0

I know I'm not the first to have this problem, but I'm struggling to create multiple beans of the same type in Spring Boot 2.5.4.

My config:

@Configuration
public class MapperConfig {

    @Bean("yamlMapper")
    public ObjectMapper yamlMapper() {
        return new ObjectMapper(new YAMLFactory());
    }

    @Bean("jsonMapper")
    public ObjectMapper jsonMapper() {
        return new ObjectMapper();
    }

}

And my service class:

@Service
@RequiredArgsConstructor
public class MapperService {

    @Qualifier("jsonMapper")
    private final ObjectMapper jsonMapper;

    @Qualifier("yamlMapper")
    private final ObjectMapper yamlMapper;

}

The error is as follows:

No qualifying bean of type 'com.fasterxml.jackson.databind.ObjectMapper' available: expected single matching bean but found 2: yamlMapper,jsonMapper

I've tried the various combinations of @Bean, @Qualifier, etc. suggested in other SO posts and the docs, but I can't seem to find a way of making Spring autowire by name instead of type. Any help would be greatly appreciated!

SOLUTION:

As pointed out by Youssef, it's not the MapperService which is failing to find the right bean, it's Spring Boot's MappingJackson2HttpMessageConverterConfiguration class. We can't add annotations to that class, so need to resort to using @Primary in our config.

The context loads okay as follows:

@Configuration
public class MapperConfig {

    @Bean
    public ObjectMapper yamlMapper() {
        return new ObjectMapper(new YAMLFactory());
    }

    @Bean
    @Primary
    public ObjectMapper jsonMapper() {
        return new ObjectMapper();
    }

}
@Service
@RequiredArgsConstructor
public class MapperService {

    @Autowired
    @Qualifier("jsonMapper")
    private final ObjectMapper jsonMapper;

    @Autowired
    @Qualifier("yamlMapper")
    private final ObjectMapper yamlMapper;

}
Liam
  • 109
  • 3
  • 11
  • Do you have the wrong `@Qualifier` imported maybe? – daniu Nov 18 '21 at 12:50
  • 1
    Ditch lombok, write a constructor yourself, which has the `@Qualifier` on the constructor arguments. Next the `ObjectMapper` is also used by Spring (Boot) itself, so you need to mark the JSON one as Primary (which could also break stuff as this will also (partially) disable auto configuration for the `ObjectMapper`). – M. Deinum Nov 18 '21 at 13:32
  • @sotiriosdelimanolis you have linked the wrong answer it is about issue like that https://stackoverflow.com/questions/46548750/spring-boot-two-object-mapper-bean – Hayi Nov 18 '21 at 14:00
  • @Youssef Indeed, the question did not contain the necessary details. Replaced the duplicates. – Sotirios Delimanolis Nov 18 '21 at 15:19

2 Answers2

1

Use the annotation:

@Resource

https://www.baeldung.com/spring-annotations-resource-inject-autowire

Your service:

@Service
public class MapperService {

    @Resource(name = "jsonMapper")
    private final ObjectMapper jsonMapper;

    @Resource(name = "yamlMapper")
    private final ObjectMapper yamlMapper;

}
morsor
  • 1,263
  • 14
  • 29
  • Thanks for the suggestion - still getting the same error unfortunately, really weird... – Liam Nov 18 '21 at 12:20
  • @Liam: Is this helpful: https://stackoverflow.com/questions/18711924/required-multiple-beans-of-same-type-in-spring – morsor Nov 18 '21 at 12:38
  • Yeah, I looked at that one and it seems like the same use case, yet when I use the solution from that post it still doesn't work – Liam Nov 18 '21 at 12:42
0

You need to add @Primary annotation to one of your ObjectMapper beans like that

@Primary
@Bean("jsonMapper")

Because if you are using Spring Boot, it is needed by Jackson when trying auto configuration:

Parameter 0 of method mappingJackson2HttpMessageConverter in org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration$MappingJackson2HttpMessageConverterConfiguration required a single bean, but 2 were found:

But be careful also to as @M.Deinum comment: could also break stuff as this will also (partially) disable auto configuration for the ObjectMapper

Hayi
  • 6,972
  • 26
  • 80
  • 139