@Tested/@Injectable does not support custom annotations when also using standard DI annotations #124

Closed
henryken opened this Issue Jan 10, 2015 · 5 comments

Comments

2 participants
@henryken

Hi,

When upgrading from v1.9 to v1.14, the @Injectable is not working for non-javax annotated field.
This issue seems have been found few months ago (http://stackoverflow.com/questions/26683962/why-is-there-a-npe-on-injectable-class)

In the code below, the "clock" can be injected properly.
However, trialReadyTemplate and trialReadyTimer are not injected.

I'm using TestNG and Java 8.
The current workaround is to use reflection at the beginning of the test method.

@Service
public class TrialServerServiceImpl implements TrialServerService {

    @Resource
    private Clock clock;

    @Produce(uri = "direct:trial-ready")
    private ProducerTemplate trialReadyTemplate;

    @Metric(name = "trial.ready")
    private Timer trialReadyTimer;
}



public class TrialServerServiceImplTest {

    @Tested
    private TrialServerServiceImpl trialServerService;

    @Injectable
    private Clock clock;

    @Injectable
    private ProducerTemplate trialReadyTemplate;

    @Injectable
    private Timer trialReadyTimer;
}
@rliesenfeld

This comment has been minimized.

Show comment
Hide comment
@rliesenfeld

rliesenfeld Jan 11, 2015

Member

It will work if @resource is not used here. Is there a reason why it was used, without a name being provided?

Member

rliesenfeld commented Jan 11, 2015

It will work if @resource is not used here. Is there a reason why it was used, without a name being provided?

@henryken

This comment has been minimized.

Show comment
Hide comment
@henryken

henryken Jan 12, 2015

It's used for dependency injection.
It doesn't have a "name" because it follows the name of the attribute.

Also, @produce and @Metric will inject Spring beans.

It's used for dependency injection.
It doesn't have a "name" because it follows the name of the attribute.

Also, @produce and @Metric will inject Spring beans.

@rliesenfeld

This comment has been minimized.

Show comment
Hide comment
@rliesenfeld

rliesenfeld Jan 12, 2015

Member

Ok. The problem here is that the presence of @resource (one of the "standard" DI annotations, together with @Inject and @Autowired) put JMockit in "annotations-only" mode, where only fields that use the standard annotations are regarded as injection points. I thought that Spring would not accept other annotations on their own (ie, without also using @Inject, @resource, or @Autowired).

Do you happen to know where this behavior is mentioned in the Spring framework documentation?

Member

rliesenfeld commented Jan 12, 2015

Ok. The problem here is that the presence of @resource (one of the "standard" DI annotations, together with @Inject and @Autowired) put JMockit in "annotations-only" mode, where only fields that use the standard annotations are regarded as injection points. I thought that Spring would not accept other annotations on their own (ie, without also using @Inject, @resource, or @Autowired).

Do you happen to know where this behavior is mentioned in the Spring framework documentation?

@henryken

This comment has been minimized.

Show comment
Hide comment
@henryken

henryken Jan 12, 2015

I don't think that limiting the injection to those 3 annotations is the correct approach.
There are lots of other third party libraries and annotations which rely on Spring injection to provide the correct dependencies, e.g. in my case
http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/Produce.html
https://github.com/ryantenney/metrics-spring

Those libraries are supposed to work with Spring, so there is no reason to limit the presence of the injection annotations.

I don't think that limiting the injection to those 3 annotations is the correct approach.
There are lots of other third party libraries and annotations which rely on Spring injection to provide the correct dependencies, e.g. in my case
http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/Produce.html
https://github.com/ryantenney/metrics-spring

Those libraries are supposed to work with Spring, so there is no reason to limit the presence of the injection annotations.

@rliesenfeld rliesenfeld self-assigned this Jan 12, 2015

@rliesenfeld

This comment has been minimized.

Show comment
Hide comment
@rliesenfeld

rliesenfeld Jan 12, 2015

Member

Hmm, actually, those other libraries which integrate with Spring and do their own injection are doing it the wrong way. All DI frameworks (Spring, Guice, CDI/JavaEE) adopted the rule (when using annotation-driven DI) that all injection points must use one of a set of standardized DI annotations (@javax.inject.Inject in the official Java standard for DI; one of @Inject, @resource, @PersistenceContext, or @PersistenceUnit in Java EE; @Inject, @Autowired, or @value in Spring).

The correct way would be to require use of @Inject together with a custom @qualifier annotation. They would still have their own annotations (such as @produce), the only difference being that @Inject (or @Autowired) would also be applied to each field. This would comply with the rule adopted by javax.inject, Spring, etc., and which JMockit attempts to follow.

That said, given the fact that other libraries decided to not support standardized DI, I will try and regard any runtime field annotation as marking an injection point. This should work well in practice.

Member

rliesenfeld commented Jan 12, 2015

Hmm, actually, those other libraries which integrate with Spring and do their own injection are doing it the wrong way. All DI frameworks (Spring, Guice, CDI/JavaEE) adopted the rule (when using annotation-driven DI) that all injection points must use one of a set of standardized DI annotations (@javax.inject.Inject in the official Java standard for DI; one of @Inject, @resource, @PersistenceContext, or @PersistenceUnit in Java EE; @Inject, @Autowired, or @value in Spring).

The correct way would be to require use of @Inject together with a custom @qualifier annotation. They would still have their own annotations (such as @produce), the only difference being that @Inject (or @Autowired) would also be applied to each field. This would comply with the rule adopted by javax.inject, Spring, etc., and which JMockit attempts to follow.

That said, given the fact that other libraries decided to not support standardized DI, I will try and regard any runtime field annotation as marking an injection point. This should work well in practice.

@rliesenfeld rliesenfeld changed the title from @Injectable not working to @Tested/@Injectable does not support custom annotations when also using standard DI annotations Jan 12, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment