I am using a customized ObjectMapper in my spring boot app. I also use the JPA converters for several fields which are stored as JSON strings in the DB. I am not sure how to autowire my custom object mapper into my converter.
#Convert(converter=AddressConverter.class)
private Address address;
And my AddressConverter is
class AddressConverter implements AttributeConverter<Address, String> {
#Autowire
ObjectMapper objectMapper; //How to do this?
.....
.....
}
How to autowire ObjectMapper into AddressConverter? Is there a way to do this with Spring AOP?
Maybe you can do it by changing it to a static property, like this:
#Component
class AddressConverter implements AttributeConverter<Address, String> {
private static ObjectMapper objectMapper;
#Autowired
public void setObjectMapper(ObjectMapper objectMapper){
AddressConverter.objectMapper = objectMapper;
}
.....
.....
}
Related
I am trying to autowire a component into a custom JsonDeserializer but cannot get it right even with the following suggestions I found:
Autowiring in JsonDeserializer: SpringBeanAutowiringSupport vs HandlerInstantiator
Right way to write JSON deserializer in Spring or extend it
How to customise the Jackson JSON mapper implicitly used by Spring Boot?
Spring Boot Autowiring of JsonDeserializer in Integration test
My final goal is to accept URLs to resources in different microservices and store only the ID of the resource locally. But I don't want to just extract the ID from the URL but also verify that the rest of the URL is correct.
I have tried many things and lost track a bit of what I tried but I believe I tried everything mentioned in the links above. I created tons of beans for SpringHandlerInstantiator, Jackson2ObjectMapperBuilder, MappingJackson2HttpMessageConverter, RestTemplate and others and also tried with setting the SpringHandlerInstantiator in RepositoryRestConfigurer#configureJacksonObjectMapper.
I am using Spring Boot 2.1.6.RELEASE which makes me think something might have changed since some of the linked threads are quite old.
Here's my last attempt:
#Configuration
public class JacksonConfig {
#Bean
public HandlerInstantiator handlerInstantiator(ApplicationContext applicationContext) {
return new SpringHandlerInstantiator(applicationContext.getAutowireCapableBeanFactory());
}
}
#Configuration
public class RestConfiguration implements RepositoryRestConfigurer {
#Autowired
private Validator validator;
#Autowired
private HandlerInstantiator handlerInstantiator;
#Override
public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
validatingListener.addValidator("beforeCreate", validator);
validatingListener.addValidator("beforeSave", validator);
}
#Override
public void configureJacksonObjectMapper(ObjectMapper objectMapper) {
objectMapper.setHandlerInstantiator(handlerInstantiator);
}
}
#Component
public class RestResourceURLSerializer extends JsonDeserializer<Long> {
#Autowired
private MyConfig config;
#Override
public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
ServiceConfig serviceConfig = config.getServices().get("identity");
URI serviceUri = serviceConfig.getExternalUrl();
String servicePath = serviceUri.getPath();
URL givenUrl = p.readValueAs(URL.class);
String givenPath = givenUrl.getPath();
if (servicePath.equals(givenPath)) {
return Long.parseLong(givenPath.substring(givenPath.lastIndexOf('/') + 1));
}
return null;
}
}
I keep getting a NullPointerException POSTing something to the API endpoint that is deserialized with the JsonDeserializer above.
I was able to solve a similar problem by marking my deserializer constructor accept a parameter (and therefore removing the empty constructor) and marking constructor as #Autowired.
public class MyDeserializer extends JsonDeserializer<MyEntity> {
private final MyBean bean;
// no default constructor
#Autowired
public MyDeserializer(MyBean bean){
this.bean = bean
}
...
}
#JsonDeserialize(using = MyDeserializer.class)
public class MyEntity{...}
My entity is marked with annotation #JsonDeserialize so I don't have to explicitly register it with ObjectMapper.
I came across a strange behaviour with respect to #Bean and #Autowired in my #Configuration class. My web project structure is like
Controller → Service → Repository
In my Service I have a dependency on ObjectMapper
#Autowired
public ServiceClass(final ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
Since I want to use a Java 8 optional class while deserializing, I wanted to register Jdk8Module. So I created a configuration class like this:
#Configuration
public class JacksonConfig {
#Bean
public ObjectMapper objectMapper(final ObjectMapper objectMapper) {
objectMapper.registerModule(new Jdk8Module());
return objectMapper;
}
}
I initially thought that Spring will inject the objectMapper instance which it has, which I can manipulate and return it, so that when I autowire it in my service class, I get the updated instance of ObjectMapper.
But I get a cyclic dependency error. This is understandable because, my bean configuration depends on objectmapper and returns an objectmapper.
But it is surprising, if I change the method to have #Autowired instead of #Bean, Spring doesn't complain and works as expected.
#Autowired
public ObjectMapper objectMapper(final ObjectMapper objectMapper) {
objectMapper.registerModule(new Jdk8Module());
return objectMapper;
}
Why is that?
The #Bean annotation goal is to provide beans from the Spring BeanFactory. When a method is annotated #Bean, it is supposed to return a new instance of an object. It can use paramaters if Spring is able to instantiate them too.
In your example, when you declare
#Bean
public ObjectMapper objectMapper(final ObjectMapper objectMapper) {
objectMapper.registerModule(new Jdk8Module());
return objectMapper;
}
It means your ObjectMapper is a bean (of course) that takes a parameter which is an instance of ObjectMapper and Spring knows ObjectMapper so it can instantiate it using... the very same method. Here is your cyclic dependency.
In the case of #Autowired, Spring uses an ObjectMapper as a parameter of your method that is already in the BeanFactory. That's why it removes the cyclic dependency.
I hope I'm clear enough.
Little reference here : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html
In
#Autowired
public ObjectMapper objectMapper(final ObjectMapper objectMapper) {
objectMapper.registerModule(new Jdk8Module());
return objectMapper;
}
Someone else is injecting an ObjectMapper (maybe Spring) to this method. I think the Autowired annotation is not necessary in this case, Spring knows you want to inject a bean here.
You aren't creating new beans in this case so you will not have a cyclic dependency error here.
If you want to create a new one, maybe you should play with #Qualifier.
More info: https://dzone.com/articles/spring-configuration-and
I have an application with 2 Contexts. Parent for web agnostic business logic and ChildContext (implicitly created by dispatcher servlet) for web logic.
My setup loks like
#Configuration
public class BusinessConfig {
#Bean
public ObjectMapper jacksonMapper() { return new ObjectMapper() }
}
and
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
private ObjectMapper objectMapper; // <- is null for some reason
#Override
public configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper); // <- bang!
messageConverters.add(converter);
}
}
I need the the object mapper in the parent context, as I use it also in security configuration. But can someone explain me, why the #Autowired objectMapper is null? Its created in the parent context (the fact that the parent exists is even logged by spring at startup). Also #Autowired has required=true by default, so it should not blow up in the configure method (it should have blown up in construction of the context, if the bean wasn't there for some reason).
It seems to me that there might be some lifecycle problem in spring - in a sense that it calls the overridden methods first, and then #Autowires the dependencies... I have also tried to #Autowire the BusinessConfig (should be perfectly legal according to documentation - the result was the same (null)).
What should I do to make this working?
Thanks in advance!
EDIT - ISSUE FOUND
I found the issue. Unfortunately it had nothing to do with WebMvcConfigurerAdapter nor #Configuration. It was caused by premature initialization of context triggered by missing static modifier for propertyPlaceholderConfigurer... I have created issue in Spring core jira (https://jira.spring.io/browse/SPR-14382)
What about simply renaming the bean declaration method to match with the autowired bean?
#Configuration
public class BusinessConfig {
#Bean
public ObjectMapper objectMapper() { return new ObjectMapper() }
}
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
private ObjectMapper objectMapper;
[...]
}
I am trying to autowire java.util.concurrent.ConcurrentHashMap to enforce a singleton implementation without using any spring-config.xml file. I'm fairly certain there is a way to do this via some spring annotation directly at the Java side of things, is this possible?
#Component
public class MyClass{
//Some annotation goes here?
private ConcurrentHashMap<String, String> myMap;
}
Actualy, you can not inject MAP.
But you can wrap your map in another class then inject it.
#Component
Public class MapWrapper {
public Map<String, String> map = newConcurrentHashMap<String, String>();
}
...
#Inject
private MapWrapper wrapper;
...
I have the following Dao class defined:
#Repository
public class MyDao {
private JdbcTemplate jdbcTemplate;
private String myString;
#Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
I'm using component scanning over the package where MyDao is defined so I do not have a bean definition for MyDao in my Spring configuration file. Is there a way to inject a String into myString without using autowiring? What are my alternatives for this?
Spring comes with the #Value annotation that you can use to inject a string.
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/annotation/Value.html
http://chrislovecnm.com/2010/03/08/spring-3-java-based-configuration-with-value/
There is also a configuration framework called Constretto that allows nested configurations (like json) to be injected.