QuocNg
QuocNg

Reputation: 152

Could not inject different beans with named qualifier in Micronaut

I have defined an ObjectMapper factory class like this:

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;

import io.micronaut.context.annotation.Factory;
import jakarta.inject.Named;
import jakarta.inject.Singleton;

@Factory
public class MyObjectMapper {

    @Singleton
    @Named("jsonObjectMapper")
    public ObjectMapper getJsonObjectMapper() {
        return new ObjectMapper(new JsonFactory());
    }

    @Singleton
    @Named("yamlObjectMapper")
    public ObjectMapper getYamlObjectMapper() {
        return new ObjectMapper(new YAMLFactory());
    }

}

Then, on client class, I tried to inject them like this:

import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.inject.Singleton;

@Singleton
public class MyServiceImpl implements MyService {

    private ObjectMapper jsonMapper;

    private ObjectMapper yamlMapper;

    @Inject
    @Named("jsonObjectMapper")
    public void setJsonMapper(ObjectMapper jsonMapper) {
        this.jsonMapper = jsonMapper;
    }

    @Inject
    @Named("yamlObjectMapper")
    public void setYamlMapper(ObjectMapper yamlMapper) {
        this.yamlMapper = yamlMapper;
    }
...

My goal is to have jsonMapper to be injected by the bean with @Named("jsonObjectMapper") on MyObjectMapper class, and yamlMapper with @Named("yamlObjectMapper"). But, when I tried to debug, jsonMapper and yamlMapper had the same reference, which means they are injected by the same ObjectMapper. My question is how to inject 2 different beans for json and yaml mapper on Micronaut?

Thank you!

Upvotes: 3

Views: 5705

Answers (1)

Szymon Stepniak
Szymon Stepniak

Reputation: 42272

The injection qualified by name can be done with the @Named annotation used on the method argument, and not the method itself. It means that in your case you would have to move the @Named annotation to the setJsonMapper and setYamlMapper methods arguments.

@Singleton
public class MyServiceImpl {

    private ObjectMapper jsonMapper;

    private ObjectMapper yamlMapper;

    @Inject
    public void setJsonMapper(@Named("jsonObjectMapper") ObjectMapper jsonMapper) {
        this.jsonMapper = jsonMapper;
    }

    @Inject
    public void setYamlMapper(@Named("yamlObjectMapper") ObjectMapper yamlMapper) {
        this.yamlMapper = yamlMapper;
    }

    // ...
}

Alternatively, you could use construction injection combined with the @Named annotation for each parameter. It allows you to mark both fields as private, just to make sure these objects are not re-assigned at the runtime.

@Singleton
public class MyServiceImpl {

    private final ObjectMapper jsonMapper;

    private final ObjectMapper yamlMapper;

    public MyServiceImpl(
            @Named("jsonObjectMapper") ObjectMapper jsonMapper,
            @Named("yamlObjectMapper") ObjectMapper yamlMapper) {
        this.jsonMapper = jsonMapper;
        this.yamlMapper = yamlMapper;
    }

    // ...
}

Upvotes: 4

Related Questions