Getting Spring Error "Bean named 'x' must be of type [y], but was actually of type [$Proxy]" in Jenkins
Asked Answered
W

3

21

I have been debugging this for awhile now, and I'm hoping someone could shed some light here.

I have a Maven project that is added into Jenkins, using JDK 1.6. I'm using AOP in this project to handle the database transaction.

When I run the build in Jenkins, my testcase fails with the following exceptions:-

Caused by: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'dataHandlerClassificationImpl': 
Injection of resource dependencies failed; nested exception is 
org.springframework.beans.factory.BeanNotOfRequiredTypeException: 
Bean named 'writerDataLocationImpl' must be of type [xxx.script.WriterData], 
but was actually of type [$Proxy17]
    ...
    ...
Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: 
Bean named 'writerDataLocationImpl' must be of type [xxx.script.WriterData], 
but was actually of type [$Proxy17]
    ...
    ...

The DataHandlerClassificationImpl class looks something like this:-

@Service
public class DataHandlerClassificationImpl extends DataHandler {

    @Resource(name="writerDataLocationImpl")
    private WriterData writerData;

    ...
}       

WriterData is an interface with multiple implementations.

I am able to execute the code without problem from the IDE. To determine whether it is a Maven problem or Jenkins problem, I navigated to the Jenkins' project job folder using command line and I'm able to run mvn test without any errors.

I know the proxy error has something to do with AOP, and that I can only autowire to an interface instead of a concrete class... but that's not the case here since I'm able to run my code fine outside Jenkins.

Any ideas? Thanks.

Waybill answered 5/12, 2011 at 21:12 Comment(10)
Are you running Cobertura, Sonar or other code-instrumenting tool on Jenkins? What is the exact mvn build command? Can you try replacing injected filed to private Object writerData and dump writerData.getClass().getInterfaces after dealing with compilation errors? This might give us a clue what is the nature of this unwanted and strange proxy.Calends
Under Jenkins' "Goals and Options", I had clean cobertura:cobertura site. Just for my curiosity sake, I changed it to clean test and it worked fine. When I changed it to clean site, I'm getting the same exception again. It looks like it has something to do with site. Any ideas? Thanks.Waybill
@Thomasz, how exactly do I dump writerData.getClass().getInterfaces? Intellij basically gives me a regular compilation error.Waybill
It is definitely something to do with mvn site. I ran that command from the command line, and I'm getting the exact exception. I'm not sure why this is behaving differently from test.Waybill
Try this: Arrays.asList(new Object().getClass().getInterfaces()) within afterPropertiesSet or @PostConstruct. I am a bit surprised that site is causing this problem to appear as I know Cobertura/Sonar tend to introduce this bug. Can you try mvn cobertura:cobertura alone? Should fail as well...Calends
One more thing - do you have Cobertura enabled for site (reporting)? I'm pretty sure it's Cobertura's fault, not site.Calends
I think you are right about Cobertura being the problem. I tried mvn cobertura:cobertura test and I get the exception. Yes, the reporting contains cobertura-maven-plugin (version 2.5.1). I'm going to try removing that to see if the problem goes away for now.Waybill
OK, it is a known problem. Try proxying classes instead in Spring: <aop:config proxy-target-class="true">. If it works for you let me know, I will form an answer from these comments for future readers. Also try googling "cobertura spring proxy" - you'll find plenty people having the same issue.Calends
<aop:config proxy-target-class="true"> indeed fixed the problem! Thanks much. If you could post your last comment as an answer below, I'll upvote it and mark it as completed. Thanks again.Waybill
Also see my answer https://mcmap.net/q/659227/-classcastexception-when-using-embedded-glassfish-for-unit-tests, which is a similar question.Brookes
C
47

Excerpt from question comments above:

Are you running Cobertura, Sonar or other code-instrumenting tool on Jenkins? Note that mvn site might also be configured to include Cobertura report in generated site.

The problem with Cobertura is that it performs pretty heavy byte-code instrumentation including the addition of some custom interfaces. When Spring starts up it generates proxies for beans. If bean has at least one interface, it uses standard Java proxy. Otherwise it tries to create class-based proxy.

I guess in your case the CGLIB class proxy was used but after Cobertura instrumentation Spring fall back to java proxies. This caused startup error because dependency injection expected class (or CGLIB subclass).

To cut long story short, force CGLIB class proxies and you'll be fine:

<aop:config proxy-target-class="true"/>
Calends answered 5/12, 2011 at 22:27 Comment(3)
You are awesome Tomasz :-) Your explanation helped me.Lisette
What's the namespace for aop?Tertia
This property in Spring boot is spring.aop.proxy-target-class=trueWedded
O
2

I've had this issue in JUnit tests. I complained about a @Component which was using Cacheable

Please see this link: https://github.com/spring-projects/spring-boot/issues/12194#issuecomment-368027766

For me the fix was to add this into the JUnit

@SpringBootTest
@EnableCaching(proxyTargetClass = true)
Out answered 16/3, 2023 at 15:17 Comment(0)
A
0

Got the same problem using AspectJ.

There was a bean w

@Configuration public class MyConfig{

@Value("classpath:some.properties")
private Resource theResource;

@Bean
public  SomeResource getSomeResource()
{
    return  SomeResource.getOne(theResource);
}
/******/
 
  @Component
public class SomeResource{
   public SomeResource(Resource r) {...}
   public static getOne(Resource r} { return new SomeResource(r); }

This works fine until AOP/AspectJ is enabled. The injection validates that the SomeResource bean is from class SomeResource, but since it is a Proxy it crashes.

SOlution: use GLIBC proxy for that Bean instead of AspectJ proxies.

@EnableAspectJAutoProxy(proxyTargetClass=false)
public class SomeResource{...}

Makes no sense, but now got a clearer message

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.springframework.cglib.core.ReflectUtils
 (file:/path/spring-core/5.2.10.RELEASE/spring-core-5.2.10.RELEASE.jar) to method
java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of org.springframework.cglib.core.ReflectUtils

Meaning Java prevent reflection on this method.Either Spring or Java needs to fix that.

Alienor answered 17/11, 2020 at 3:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.