ASM version incompatibilities, using Spring @Autowired with Hibernate

Alef Arendsen

I was working on Spring 2.1 stuff this week with Joris. We were preparing a sample using all three ways of doing dependency injection. The sample does not only highlight dependency injection, but also features a back-end based on Hibernate.

Several features in Spring 2.1 require the ASM byte code manipulation framework. Hibernate also uses ASM, through CGLIB. There is a binary incompatibility between ASM 1.5.3 and 2.2.3. The former is used by Hibernate, the latter is used by Spring in various scenarios; specifically in some of the AOP functionality and the new @Autowired features.

UPDATE: read solution number 3 first!

Solution no. 1

The first solution is to explicitly replace the CGLIB jar for Hibernate with a nodep version (one is available from the Spring distribution) which contains a re-packaged version of ASM version 1.5.3. With Maven, this requires you to put in a few exclusions alongside your Hibernate dependency and to explicitly put in the ASM 2.2.3 dependency in your pom.

<dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate</artifactId>
        <version>3.2.1.ga</version>
        <exclusions>
                <exclusion>
                        <groupId>asm</groupId>
                        <artifactId>asm</artifactId>
                </exclusion>
                <exclusion>
                        <groupId>asm</groupId>
                        <artifactId>asm-attrs</artifactId>
                </exclusion>               
        </exclusions>
</dependency>
<dependency>
        <groupId>asm</groupId>
        <artifactId>asm</artifactId>
        <version>2.2.3</version>                       
</dependency>

Solution no. 2

I haven't tried this, but according to the Hibernate JIRA you can change the byte code provider for Hibernate to Javassist, as commented by Max Rydahl Andersen in the bug report.

Solution no.3 (added October 18 2007)

As of Spring 2.5rc1, spring.jar contains ASM 2.2.3 (repackaged using Jar Jar Links (that name!!!!! :) ). This means all incompatibilities with other projects using ASM should from now on be a thing of the past. I haven't tried this out yet, so you should figure this one out for yourself.

 

9 responses


  1. Thanks for doing a prominent write-up on this. This issue has existed for a couple of years with the AOP stuff, and is always challenging for people who are hitting it for the first time.


  2. For what I've seen in other projects, they usually create a fork with the specific version of ASM they use, and add it to their own codebase, probably to avoid this instability of the API. Why don't you do the same?


  3. Guice gets around this by using jarjar to repackage ASM inside of our jar at build time. That does suck that ASM broke backward compatibility like that. Why not create a new package named "asm2"?


  4. I was talking to Eugene Kuleshov (one of the ASM committers) about this, and he said that basically it's a given that ASM has to change on a regular basis to support new JDK features, so the expectation is in fact that you will basically fork a specific version into your package structure, ala cglib_nodep…

    So this basically means that the idea of versioning ASM in a simple fashion with Maven, where 3.0 can replace 2.0, is completely unrealistic. It also means 2.0 and 3.0 can not live side by side. Realistically, unless you assume no other app/lib than yours will ever use ASM, it means you have to fork it into your own app/lib.

    I don't really think this is a great strategy. I think it would have been realistic to change the base asm package each time it changed in an incompatible fashion. So we'd be up to ASM 33 by now, but so what?


  5. Hi,
    I am having problems running a very basic JUnit test case via Maven2. The application uses spring-framework-2.1-m1 release, and test case extends from org.springframework.test.jpa.AbstractJpaTests, uses org.springframework.orm.jpa.LocalContainerEntityMa nagerFactoryBean as entityManagerFactory, and uses
    org.springframework.orm.jpa.vendor.HibernateJpaVen dorAdapter as jpaVendorAdapter propery for entityManagerFactory. Complete issue is here http://forum.springframework.org/showthread.php?p=127012#poststop. I have tried your outlined solution, but the exception is same. Any help would be great!

    Below are few lines from stack trace,
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [META-INF/applicationContext-jpaCommon.xml]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: javassist.bytecode.ClassFile.getName()Ljava/lang/String;
    Caused by: java.lang.NoSuchMethodError: javassist.bytecode.ClassFile.getName()Ljava/lang/String;
    at org.hibernate.ejb.Ejb3Configuration.scanForClasses(Ejb3Configuration.java:652)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:350)
    at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:126)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:218)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:251)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1201)


  6. Hi, i have tried soln # 1 but it does not resolve my problem. My detailed problem is here on spring forum http://forum.springframework.org/showthread.php?p=127012#poststop and someone from there refereed me here. Any help would be great!

    On difference is that I had to include dependency on javaassist as I was getting error that its not inclasspath. After adding it get the exception (details on above URL, summary is here). Here are first few lines from the exception stack trace.
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [META-INF/applicationContext-jpaCommon.xml]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: javassist.bytecode.ClassFile.getName()Ljava/lang/String;
    Caused by: java.lang.NoSuchMethodError: javassist.bytecode.ClassFile.getName()Ljava/lang/String;
    at org.hibernate.ejb.Ejb3Configuration.scanForClasses(Ejb3Configuration.java:652)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:350)
    at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:126)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:218)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:251)


  7. I tried solution No 1 but cglib (which is used by hibernate) uses old classes and methods from asm which are not present in asm-2.2.3. So i got an java.lang.NoClassDefFoundError: org/objectweb/asm/CodeVisitor from hibernate initialisation.

    I solved this by using cglib-nodep-2.1_3 from maven repository, instead of cglib from the hibernate dependencies, see: http://mvnrepository.com/artifact/cglib/cglib-nodep/2.1_3

    org.hibernate
    hibernate
    [3.2.2.ga]

    asm
    asm

    asm
    asm-attrs

    cglib
    cglib

    cglib
    cglib-nodep
    2.1_3

    cglib-nodep contains asm classes but they are in different packages as in the asm jars.


  8. Hmm, you can not post XML here. Here is my XML code from the end of the posting:

    [dependency]
    [groupId]org.hibernate[/groupId]
    [artifactId]hibernate[/artifactId]
    [version][3.2.2.ga][/version]
    [exclusions]
    [exclusion]
    [groupId]asm[/groupId]
    [artifactId]asm[/artifactId]
    [/exclusion]
    [exclusion]
    [groupId]asm[/groupId]
    [artifactId]asm-attrs[/artifactId]
    [/exclusion]
    [exclusion]
    [groupId]cglib[/groupId]
    [artifactId]cglib[/artifactId]
    [/exclusion]
    [/exclusions]
    [/dependency]
    [dependency]
    [groupId]cglib[/groupId]
    [artifactId]cglib-nodep[/artifactId]
    [version]2.1_3[/version]
    [/dependency]
    [dependency]


  9. Just a FYI

    Unfortunately, solution 3 won't work for me, and my guess would be most people, if you are using dynamic languages, as GroovyScriptFactory uses the GroovyClassLoader, which comes in a different jar (groovy jar of course), which still uses the old org.objectweb.asm pagkage, rather than the new spring org.springframework.asm package

One trackback

Leave a Reply

Quote selected text