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.

limc
  • 39,366
  • 20
  • 100
  • 145
  • 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. – Tomasz Nurkiewicz Dec 05 '11 at 21:18
  • 1
    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. – limc Dec 05 '11 at 21:27
  • @Thomasz, how exactly do I dump `writerData.getClass().getInterfaces`? Intellij basically gives me a regular compilation error. – limc Dec 05 '11 at 21:30
  • 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`. – limc Dec 05 '11 at 21:33
  • 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... – Tomasz Nurkiewicz Dec 05 '11 at 21:35
  • One more thing - do you have Cobertura enabled for `site` (reporting)? I'm pretty sure it's Cobertura's fault, not `site`. – Tomasz Nurkiewicz Dec 05 '11 at 21:43
  • 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. – limc Dec 05 '11 at 21:49
  • OK, it is a known problem. Try proxying classes instead in Spring: ``. 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. – Tomasz Nurkiewicz Dec 05 '11 at 21:54
  • `` 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. – limc Dec 05 '11 at 21:58
  • Also see my answer http://stackoverflow.com/a/8216926/1836, which is a similar question. – Matthew Farwell Dec 05 '11 at 21:59

3 Answers3

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"/>
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
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.

RSG
  • 384
  • 3
  • 7
0

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)
razvang
  • 1,055
  • 11
  • 15