In below spring bean declaration, I wonder why do we need explicit scope="singleton". Isn't it redundant?
<bean class="com.foo.blah.JerseyJacksonConfigFactory" factory-method="getProvider" scope="singleton"/>
public class JerseyJacksonConfigFactory {
public static ClientConfig getConfig() {
JacksonJsonProvider jsonProvider = getProvider();
DefaultClientConfig config = new DefaultClientConfig();
config.getSingletons().add(jsonProvider);
return config;
}
public static JacksonJsonProvider getProvider() {
ObjectMapper mapper = getObjectMapper();
JacksonJsonProvider jsonProvider = new JacksonJsonProvider();
jsonProvider.setMapper(mapper);
return jsonProvider;
}
public static ObjectMapper getObjectMapper() {
return new ObjectMapper()
.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES)
.setSerializationInclusion(JsonSerialize.Inclusion.NON_EMPTY);
}
}
Indeed, it is not necessary, as singleton is the default scope, even when using static factory methods. I guess the author used it for better verbosity of the bean definition.
Related
We're using JAX-RS (Jersey implementation) to call to external systems.
On JAX-RS Client's creation I'm registering the below context resolver to use custom ObjectMapper:
public class JacksonObjectMapperProvider implements ContextResolver<ObjectMapper>
{
#Override
public ObjectMapper getContext(Class<?> type)
{
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
mapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
mapper.configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, true);
mapper.setSerializationInclusion(Include.NON_NULL);
return mapper;
}
}
But I don't want to have the ObjectMapper defined in JacksonObjectMapperProvider. I want JacksonObjectMapperProvider to be able to retrieve it in runtime from somewhere, or have someone set the ObjectMapper on JacksonObjectMapperProvider.
I cannot do something like bellow, because the ObjectMapper is defined on some instance that creating the jax-rs Client. And here I don't have a reference to that instance:
public class JacksonObjectMapperProvider implements ContextResolver<ObjectMapper>
{
#Override
public ObjectMapper getContext(Class<?> type)
{
return someService.getObjectMapper();
}
}
Is there another way to do it?
Is there a way to pass data to JacksonObjectMapperProvider when registering on Client?
The solution is easier then I thought, instead of registering the class:
ClientConfig clConfig = new ClientConfig();
client.register(JacksonObjectMapperProvider.class);
as I did, you can register an instance of the class, and on instance creation pass whatever you want:
ClientConfig clConfig = new ClientConfig();
client.register(new JacksonObjectMapperProvider(objectMapper));
The updated provider:
public class JacksonObjectMapperProvider implements ContextResolver<ObjectMapper>
{
private ObjectMapper mapper;
public JacksonObjectMapperProvider(ObjectMapper mapper)
{
this.mapper = mapper;
}
#Override
public ObjectMapper getContext(Class<?> type)
{
return mapper;
}
}
I want to set values Spring SolrDocument Collection based on application.yml value.
#Data
#SolrDocument(collection = #Value("${solr.core}"))
public class SearchableProduct {
}
Hoi Michela,
Ok, I had the same Problem and I found a solution: SpEL
it is described in details here:Spring Data for Apache Solr
you have to add the EL-expression to the Annotation
#SolrDocument(collection = "#{#serverSolrContext.getCollectionName()}")
public class SOLREntity implements Serializable {
.....
}
you have to provide a the serverSolrContext Bean with the method getCollectionName().
#Value("${solr.core}")
private String core;
public String getCollectionName() {
return core;
}
you have to write in our application.properties the following core entry.
solr.core=myOwnCoreName
That's it actually, BUT
if you get the following Exception, so as I did:
org.springframework.expression.spel.SpelEvaluationException: EL1057E: No bean resolver registered in the context to resolve access to bean
You have to have the following in your Configuration Bean
#Configuration
#EnableSolrRepositories(basePackages = { "de.solr.db" })
#Profile("default")
#PropertySource("classpath:application.properties")
public class ServerSolrContext extends AbstractSolrConfiguration {
private static final Logger logger = LoggerFactory.getLogger(ServerSolrContext.class);
#Resource
private Environment environment;
#Value("${solr.core}")
private String core;
public String getCollectionName() {
return core;
}
#PostConstruct
public void init() {
System.out.println(core);
}
#Bean
public SolrClient solrClient() {
String url = environment.getProperty("solr.server.url");
String user = environment.getProperty("solr.server.user");
String password = environment.getProperty("solr.server.password");
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new UsernamePasswordCredentials(user, password));
SSLContext sslContext = null;
try {
sslContext = ReportConfiguration.getTrustAllContext();
}
catch (KeyManagementException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext);
HttpClient httpClient = HttpClientBuilder.create().setSSLSocketFactory(sslSocketFactory)
.addInterceptorFirst(new PreemptiveAuthInterceptor()).setDefaultCredentialsProvider(credentialsProvider)
.build();
SolrClient client = new HttpSolrClient.Builder().withHttpClient(httpClient).withBaseSolrUrl(url).build();
return client;
}
#Bean
#ConditionalOnMissingBean(name = "solrTemplate")
public SolrTemplate solrTemplate(#Qualifier("mySolrTemplate") SolrTemplate solrTemplate) {
return solrTemplate;
}
#Bean("mySolrTemplate")
public SolrTemplate mySolrTemplate(SolrClient solrClient, SolrConverter solrConverter) {
return new SolrTemplate(new HttpSolrClientFactory(solrClient), solrConverter);
}
#Override
public SolrClientFactory solrClientFactory() {
return new HttpSolrClientFactory(solrClient());
}
}
The last 3 Methods are doing the Trick, that cost me a while to find the right solution:
it is here, so actually I was lucky to find this:
Allow PropertyPlaceholders in #SolrDocument solrCoreName
i want to know why #Value property injection works on classes with #Service annotation but not on classes with #Bean within #Configuration annotated class.
Works means that the property value is not null.
This value is also injected into two other service which i see during debugging in DefaultListableBeanFactory.doResolveDependency. But i dont see the bean WebserviceEndpoint.
Configuration
#Configuration
public class WebserviceConfig {
// do some configuration stuff
#Bean
public IWebserviceEndpoint webserviceEndpoint() {
return new WebserviceEndpoint();
}
}
Webservice interface
#WebService(targetNamespace = "http://de.example/", name = "IWebservice")
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface IWebserviceEndpoint {
#WebMethod
#WebResult(name = "response", targetNamespace = "http://de.example/", partName = "parameters")
public Response callWebservice(#WebParam(partName = "parameters", name = "request", targetNamespace = "http://de.example/") Request request) throws RequestFault;
}
Webservice class
public class WebserviceEndpoint implements IWebserviceEndpoint {
#Value("${value.from.property}")
private String propertyValue;
}
application.yml
value:
from:
property: property-value
When does the injection of #Value happen in this case.
Basically propertyValue is null because Spring injects value after bean's creation.
So when you do:
#Bean
public IWebserviceEndpoint webserviceEndpoint() {
return new WebserviceEndpoint();
}
Spring creates a new instance with propertyValue=null.
You can initialize your instance attribue with #ConfigurationProperties
#Bean
#ConfigurationProperties(prefix=...)
public IWebserviceEndpoint webserviceEndpoint() {
return new WebserviceEndpoint();
}
Note that propertyValue should have a setter.
You have several ways to solve this problem, usually it's good to centralize properties in one utils class.
#Component
public class Configs {
#Value("${propery}"
String property;
String getProperty(){
return property;
}
}
And then:
#Bean
#ConfigurationProperties(prefix=...)
public IWebserviceEndpoint webserviceEndpoint() {
WebserviceEndpoint we = new WebserviceEndpoint();
we.setProperty(configs.getProperty())
return we;
}
Again there are many many different ways to solve this problem
I am struggling with a way to autowire a dependency within a converter class using spring boot. What is the most elegant solution to solve this problem?
Configuration
#Configuration
public class Config {
#Bean
public ConversionServiceFactoryBean conversionFacilitator() {
ConversionServiceFactoryBean factory = new ConversionServiceFactoryBean();
factory.setConverters(getConverters());
return factory;
}
private Set<Converter> getConverters() {
Set<Converter> converters = new HashSet<>();
converters.add(new MyConverter());
return converters;
}
}
Converter class
#Component
public class MyConverter implements Converter<Type1, Type2> {
#Autowired
private Dependency dependency; // Null here due to the component not being injected
#Override
public Type2 convert(Type1 type1) {
return dependency.something(type1);
}
}
The dependency is not being injected because you are creating MyConverter with new, instead of let Spring create it.
You do not need a method to return set of converters. Spring can do it for you, just auto wiring it. Spring is smart enough to give you a set with all the converter implementations it finds.
You should use something like:
#Configuration
public class Config {
#Bean
#Autowired
public ConversionServiceFactoryBean conversionFacilitator(Set<Converter> converters) {
ConversionServiceFactoryBean factory = new ConversionServiceFactoryBean();
factory.setConverters(converters);
return factory;
}
}
I have RepositoryConfig extending Neo4jConfiguration. The latter sets up a number of beans with #Bean annotated methods. RepositoryConfigoverrides getGraphDatabaseService which is invoked before any fields in RepositoryConfig are autowired. That is a problem since I want to use the autowired stuff inside the getGraphDatabaseServicemethod.
#ConfigurationProperties(prefix = "neo4j")
public class RepositoryProperties {
[...]
}
#Configuration
#EnableNeo4jRepositories("com.foo.bar")
#EnableConfigurationProperties(RepositoryProperties.class)
public class RepositoryConfig extends Neo4jConfiguration {
#Autowired
private RepositoryProperties properties;
#Override
#Bean(name = "graphDatabaseService", destroyMethod = "shutdown")
public GraphDatabaseService getGraphDatabaseService() {
[...] // properties is 'null' at this point
}
#PostContstruct
public void foo() {
[...] // properties is initiated OK here
}
}
Why is getGraphDatabaseServicebeing called before autowiring is complete? I guess it has to do with the inheritance... If I remove the inheritance then autowiring is complete at the time getGraphDatabaseServiceis called. I've also tried annotating the method with #DependsOn, with no luck.
Any ideas is much appreciated!
Yes, I have seen this too occasionally. I think there are two workarounds.
Option 1. Autowire the bean definition
#Override
#Bean(name = "graphDatabaseService", destroyMethod = "shutdown")
#Autowired
public GraphDatabaseService getGraphDatabaseService() {
[...] // properties is 'null' at this point
}
Option 2. Inject the bean
#Override
#Bean(name = "graphDatabaseService", destroyMethod = "shutdown")
public GraphDatabaseService getGraphDatabaseService(#Autowired RepositoryProperties properties) {
// can probably delete the Config member with this approach
[...] // properties is 'null' at this point
}