Using Apache CXF 2.7, Struts2 2.3, and ASM 5 with Maven

In an application I work on, we recently upgraded Struts2 to 2.3.20. We then started getting exceptions at runtime with the cause of:

Caused by: java.lang.VerifyError: class
net.sf.cglib.core.DebuggingClassWriter overrides final method
visit.(IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V

The problem here is that in cglib 2.2.2, net.sf.cglib.core.DebuggingClassWriter extends the ASM class org.objectweb.asm.ClassVisitor and overrides the visit method. The only works in ASM 3, since in ASM 4 and 5 there's a different pattern of extension to follow, and the visit method is final.

So the dependencies are

  • CXF 2.7.14 depends on cglib 2.2 and ASM 3.3.1
  • Struts2 2.3.20 depends
    on cglib-nodeps 2.1 and ASM 5.0.2
  • Our webapp has a dep on cglib-nodeps 2.2.2

I first tried downgrading everything, but ran into some issues with Java 8 bytecode with ASM 3 and 4, so we had to upgrade to ASM 5. The only use of ASM is in xwork-core by com.opensymphony.xwork2.util.finder.ClassFinder, which is only used by
PackageBasedActionConfigBuilder in the "convention" plugin, which my application doesn't use, so theoretically if we were compiling to target 1.6 or 1.7 we could downgrade that to ASM 3 or 4. When struts2 2.3.22 comes out, it looks like the resolution of this issue CXF broken with upgrade of ASM 5 since Struts 2.3.20 will allow that.

Using CXF and our app with cglib 3.1 and ASM 5 seems to be working fine, at least so far. All of the CXF tests (apart from a few of the CORBA ones) passed with ASM 5.

Updated the parent pom's properties and dependencyManagement dependencies to use the right versions and exclude the wrong ones. One change was that we previously used the cglib-nodeps artifact that shadow jars the ASM classes into net.sf.cglib.asm instead of having the real ASM artifact as a transitive dependency.

Add properties for the versions, since there are a few dependencies for each one:

<properties>
    <cxf.version>2.7.14</cxf.version>
    <struts2-version>2.3.20</struts2-version>
    <asm.version>5.0.2</asm.version>
    <cglib.version>3.1</cglib.version>
</properties>

In the parent pom, set the versions to use and the transitive exclusions for the wrong ones:

<dependencyManagement>
...
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-bundle</artifactId>
            <version>${cxf.version}</version>
            <exclusions>
                <exclusion> <!-- exclude version 3 of asm -->
                    <groupId>asm</groupId>
                    <artifactId>asm</artifactId>
                </exclusion>
           ...
      </dependency>

        <dependency> 
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-core</artifactId>
            <version>${struts2-version}</version>
            <exclusions>
                <exclusion>
                    <groupId>javassist</groupId>
                    <artifactId>javassist</artifactId>
                </exclusion>
                <exclusion> <!-- exclude version 2.1-->
                    <groupId>cglib</groupId>
                    <artifactId>cglib-nodep</artifactId>
                </exclusion>
                <exclusion> <!-- we prefer our explicit version, though it should be the same -->
                    <groupId>org.ow2.asm</groupId>
                    <artifactId>asm</artifactId>
                </exclusion>
                <exclusion> <!-- we prefer our explicit version, though it should be the same -->
                    <groupId>org.ow2.asm</groupId>
                    <artifactId>asm-commons</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
...
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>${cglib.version}</version>
            <exclusions>
                <exclusion> <!-- exclude v. 4.2-->
                    <groupId>org.ow2.asm</groupId>
                    <artifactId>asm</artifactId>
                </exclusion>
                <exclusion> <!-- exclude v. 4.2 -->
                    <groupId>org.ow2.asm</groupId>
                    <artifactId>asm-util</artifactId>
                </exclusion>
                <exclusion> <!-- no ant! -->
                    <groupId>ant</groupId>
                    <artifactId>ant</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

explicitly add the asm version we want:

<dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm</artifactId>
            <version>${asm.version}</version>
        </dependency>
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm-util</artifactId>
            <version>${asm.version}</version>
        </dependency>
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm-commons</artifactId>
            <version>${asm.version}</version>
        </dependency>

and then in the dependencies section of the build pom, explicitly add cglib and asm:

<dependencies>
...
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
    </dependency>
    <dependency>
        <groupId>org.ow2.asm</groupId>
        <artifactId>asm</artifactId>
    </dependency>
    <dependency>
        <groupId>org.ow2.asm</groupId>
        <artifactId>asm-util</artifactId>
    </dependency>
    <dependency>
        <groupId>org.ow2.asm</groupId>
        <artifactId>asm-commons</artifactId>
    </dependency>
...
</dependencies>

That seems to be working, but please comment if you have any additions to this!

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">