Alex Kras
Alex Kras

Reputation: 23

Micronaut: problem with getting bean from context

I have a class that contain injections and mandatory(final) fields. For common I can use MicronautBeanFactory.getBean(type) OR BeanContext.getBean(type) to get bean from context, but in this situation I must pass type and args.

I've created simple test for this

@MicronautTest
public class ETLExecutorTest {

    @Inject
    private MicronautBeanFactory micronautBeanFactory;

    @Test
    void testGetBean() {
        Object[] args = new Object[] {"name", "spec", 1L};
        ObjectInstance instance = micronautBeanFactory.getBean(ObjectInstance.class, args);
    }
}

Object(bean) code

@Prototype
public class ObjectInstance {

    @Inject
    private ObjectStorage objectStorage;

    private final String name;
    private final String spec;
    private final Long id;

    public ObjectInstance(String name, String spec, Long id) {
        this.name = name;
        this.spec = spec;
        this.id = id;
    }
}

When I run it I receive exception

io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter [name] of class: com.ObjectInstance Message: Multiple possible bean candidates found: [java.lang.String, java.lang.String, java.lang.String] Path Taken: new ObjectInstance([String name],String specName,Long accountId) at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1016) at com.$TableInstanceDefinition.build(Unknown Source) at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1598) at io.micronaut.context.DefaultBeanContext.getScopedBeanForDefinition(DefaultBeanContext.java:2076) at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1991) at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1963) at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:610) at io.micronaut.spring.context.factory.MicronautBeanFactory.getBean(MicronautBeanFactory.java:264) Caused by: io.micronaut.context.exceptions.NonUniqueBeanException: Multiple possible bean candidates found: [java.lang.String, java.lang.String, java.lang.String] at io.micronaut.context.DefaultBeanContext.findConcreteCandidate(DefaultBeanContext.java:1701) at io.micronaut.context.DefaultApplicationContext.findConcreteCandidate(DefaultApplicationContext.java:395) at io.micronaut.context.DefaultBeanContext.lastChanceResolve(DefaultBeanContext.java:2289) at io.micronaut.context.DefaultBeanContext.findConcreteCandidateNoCache(DefaultBeanContext.java:2212) at io.micronaut.context.DefaultBeanContext.lambda$findConcreteCandidate$57(DefaultBeanContext.java:2155) at io.micronaut.core.util.clhm.ConcurrentLinkedHashMap.lambda$compute$0(ConcurrentLinkedHashMap.java:721) at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) at io.micronaut.core.util.clhm.ConcurrentLinkedHashMap.compute(ConcurrentLinkedHashMap.java:733) at io.micronaut.core.util.clhm.ConcurrentLinkedHashMap.computeIfAbsent(ConcurrentLinkedHashMap.java:710) at io.micronaut.context.DefaultBeanContext.findConcreteCandidate(DefaultBeanContext.java:2154) at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1943) at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1082) at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1007)

Also I tried to do another test, but in this case I receive object without injected fields

@MicronautTest
public class ETLExecutorTest {

    @Inject
    private BeanContext beanContext;

    @Test
    void testGetBean() {
        Object[] args = new Object[] {"name", "spec", 1L};
        BeanDefinition<ObjectInstance> definition = beanContext.getBeanDefinition(ObjectInstance.class);
        ObjectInstance instance =  definition.getConstructor().invoke(args); // there are no injections here: ObjectStorage of instance = null.
    }
}

Could you tell me, please, what I do wrong ???

Upvotes: 1

Views: 9131

Answers (1)

tsarenkotxt
tsarenkotxt

Reputation: 3489

micronaut trying to create bean ObjectInstance through the constructor but can't find String name to inject, looks like it’s just a simple field for the ObjectInstance and in this case, it works as expected:

io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for parameter [name]

if you add a default constructor, then the ObjectInstance will be created and you can get bean via beanContext.getBean(ObjectInstance.class):

@Prototype
public class ObjectInstance {

    @Inject
    private ObjectStorage objectStorage;

    private String name;
    private String spec;
    private Long id;


    public ObjectInstance() {}

    public ObjectInstance(String name, String spec, Long id) {
        this.name = name;
        this.spec = spec;
        this.id = id;
    }

}

Also pay attention to MicronautBeanFactory implements ListableBeanFactory, this is for integration with Spring

P.S. I would recommend you change your code structure, POJO should not contain beans

Upvotes: 1

Related Questions