6

I want to create two Hibernate aware object mapper bean in my Spring boot project.

One bean to force lazy loading and another to force lazy loading set as false. My bean definition as below :

I created a HibernateAwareObjectMapper class

public class HibernateAwareObjectMapper extends ObjectMapper {
}

and

@Configuration
public class CrewuiserCorebeans extends WebMvcConfigurerAdapter {

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

@Bean
public ObjectMapper defaultObjectMapper() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    Hibernate5Module hibernate5Module = new Hibernate5Module();
    hibernate5Module.configure(Hibernate5Module.Feature.FORCE_LAZY_LOADING, true);
    objectMapper.registerModule(hibernate5Module);
    return objectMapper;
}

@Bean
public HibernateAwareObjectMapper hibernateAwareObjectMapper() {
    HibernateAwareObjectMapper objectMapper = new HibernateAwareObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    Hibernate5Module hibernate5Module = new Hibernate5Module();
    hibernate5Module.configure(Hibernate5Module.Feature.FORCE_LAZY_LOADING, false);
    objectMapper.registerModule(hibernate5Module);
    return objectMapper;
}


@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    argumentResolvers.add(new UserContextResolver());
}

}

When I run the application, I am getting below error:

Parameter 0 of method mappingJackson2HttpMessageConverter in org.springframework.boot.autoconfigure.web.JacksonHttpMessageConvertersConfiguration$MappingJackson2HttpMessageConverterConfiguration required a single bean, but 2 were found:
- defaultObjectMapper: defined by method 'defaultObjectMapper' in class path resource [com/crewuiser/core/configuration/CrewuiserCorebeans.class]
- hibernateAwareObjectMapper: defined by method 'hibernateAwareObjectMapper' in class path resource [com/crewuiser/core/configuration/CrewuiserCorebeans.class]

org.springframework.boot.autoconfigure.web.JacksonHttpMessageConvertersConfiguration is in jar, so I can't add @Qualifier annotation.

Please help, if I am missing anything here.How I can make it work?

Nicomedes E.
  • 1,326
  • 5
  • 18
  • 27
anunaki
  • 989
  • 9
  • 16

3 Answers3

11

I found a solution.

I added @Primary to one of the bean and used @Qualifier in my other classes where non-primary bean need to @Autowired.

@Bean
@Primary
public ObjectMapper defaultObjectMapper() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    return objectMapper;
}

and in my service class.

@Autowired
public OrganisationService(OrganisationValidator organisationValidator, OrganisationAuthority organisationAuthority,
                           OrganisationHelper organisationHelper, OrganisationRepository organisationRepository,
                           @Qualifier("hibernateAwareObjectMapper") ObjectMapper hibernateAwareObjectMapper) {}
Nicomedes E.
  • 1,326
  • 5
  • 18
  • 27
anunaki
  • 989
  • 9
  • 16
  • 1
    Worth noting that by default, Spring will use the method name that returns the bean as the qualifier, but you can also customize that qualifier by annotating the `@Bean` method with `@Qualifier` and then specifying the qualifier you want to use as a parameter to the annotation. – Chris Thompson Oct 03 '17 at 20:27
0

Another way to use different parameters / configuration in different situations is to create an ObjectReader from the ObjectMapper, with customizations that override the ObjectMapper configuration. For example, objectMapper.readerFor(YourClass.class).with(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)

Got this idea from here: https://stackoverflow.com/a/58294093/345648

This isn't necessarily the best way, depending on your use case. Check out anunaki's answer too.

Alexander Taylor
  • 16,574
  • 14
  • 62
  • 83
-2

You can give name to the bean as below:

@Bean("bean1")
public ObjectMapper defaultObjectMapper() {
.......
}

@Bean("bean2")
public HibernateAwareObjectMapper hibernateAwareObjectMapper() {
.....    
}

and where you want to autowire it use @Qualifier("bean1") for bean1 or @Qualifier("bean2") for bean2.

Roberto Russo
  • 834
  • 10
  • 22
  • At first, this annotation redefines the name (not to give). In your case from "defaultObjectMapper" to "bean1" At second, the author of question can't use the `@Qualifier` annotation. – foal Aug 03 '19 at 09:13