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!
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;
}
// ...
}