Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@MockBean doesn't work with @Timed annotated components #6665

Closed
chornyi opened this issue Aug 16, 2016 · 3 comments
Closed

@MockBean doesn't work with @Timed annotated components #6665

chornyi opened this issue Aug 16, 2016 · 3 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@chornyi
Copy link

chornyi commented Aug 16, 2016

Similar to #6405

When applying @MockBean annotation to a component that has methods annotated with com.codahale.metrics.annotation.Timed, following exception is thrown on application startup:

The bean 'BeanName' could not be injected as a 'com...BeanName' because it is a JDK dynamic proxy that implements:


Action:

Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on @EnableAsync and/or @EnableCaching.


Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'BeanName' is expected to be of type [com...BeanName] but was actually of type [com.sun.proxy.$Proxy159]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.checkBeanNotOfRequiredType(DefaultListableBeanFactory.java:1423)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1402)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1057)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1019)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
    ... 67 more

This application does not use @EnableAsync or @EnableCaching. This is with Spring Boot 1.4.0.RELEASE

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Aug 16, 2016
@chornyi
Copy link
Author

chornyi commented Aug 16, 2016

Found a solution. Similar to @EnableAsync, setting proxyTargetClass = true fixes the issue:

@EnableMetrics(proxyTargetClass = true)

@chornyi chornyi closed this as completed Aug 16, 2016
@wilkinsona wilkinsona reopened this Aug 17, 2016
@wilkinsona
Copy link
Member

Reopening so that we can see if we can make this easier

wilkinsona added a commit to wilkinsona/spring-boot that referenced this issue Aug 17, 2016
Post-processing of mocked beans causes a number of problems:

 - The mock may be proxied for asynchronous processing which can cause
   problems when configuring expectations on a mock (spring-projectsgh-6573)
 - The mock may be proxied so that its return values can be cached or
   so that its methods can be transactional. This causes problems with
   verification of the expected calls to a mock (spring-projectsgh-6573, spring-projectsgh-5837)
 - If the mock is created from a class that uses field injection, the
   container will attempt to inject values into its fields. This causes
   problems if the mock is being created to avoid the use of one of
   those dependencies (spring-projectsgh-6663)
 - Proxying a mocked bean can lead to a JDK proxy being created
   (if proxyTargetClass=false) as the mock implements a Mockito
   interface. This can then cause injection failures as the types don’t
   match (spring-projectsgh-6405, spring-projectsgh-6665)

All of these problems can be avoided if a mocked bean is not
post-processed. Avoiding post-processing prevents proxies from being
created and autowiring from being performed. This commit avoids
post-processing by registering mocked beans as singletons rather than
via a bean definition.
@wilkinsona wilkinsona added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Aug 18, 2016
@wilkinsona wilkinsona added this to the 1.4.1 milestone Aug 18, 2016
snicoll pushed a commit that referenced this issue Sep 2, 2016
Post-processing of mocked beans causes a number of problems:

 - The mock may be proxied for asynchronous processing which can cause
   problems when configuring expectations on a mock (gh-6573)
 - The mock may be proxied so that its return values can be cached or
   so that its methods can be transactional. This causes problems with
   verification of the expected calls to a mock (gh-6573, gh-5837)
 - If the mock is created from a class that uses field injection, the
   container will attempt to inject values into its fields. This causes
   problems if the mock is being created to avoid the use of one of
   those dependencies (gh-6663)
 - Proxying a mocked bean can lead to a JDK proxy being created
   (if proxyTargetClass=false) as the mock implements a Mockito
   interface. This can then cause injection failures as the types don’t
   match (gh-6405, gh-6665)

All of these problems can be avoided if a mocked bean is not
post-processed. Avoiding post-processing prevents proxies from being
created and autowiring from being performed. This commit avoids
post-processing by registering mocked beans as singletons as well as
via a bean definition. The latter is still used by the context for type
matching purposes.

Closes gh-6573, gh-6663, gh-6664
@snicoll
Copy link
Member

snicoll commented Sep 12, 2016

Fixed in 0e00a49

@snicoll snicoll closed this as completed Sep 12, 2016
@snicoll snicoll self-assigned this Sep 12, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

4 participants