Embracing the Messiness in Search of Epic Solutions

java.lang.NoSuchMethodError: javax/persistence/OneToMany.orphanRemoval()Z

Posted

in

,

PROBLEM

You configure Hibernate using annotations and set orphanRemoval property in @OneToMany.

@Entity
@Table(name = "person")
public class Person implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "personId")
    private Long id;

    @OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<car> cars = new HashSet<car>();

	...
}

When you run the application, the application server throws the following exception:-

Caused by: java.lang.NoSuchMethodError: javax/persistence/OneToMany.orphanRemoval()Z
        at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1868)
        at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:767)

In my case, I’m getting this exception when I run on Websphere Application Server (WAS) 7.5.

SOLUTION

The orphanRemoval property in @OneToMany requires JPA 2.x to work. If you already have JPA 2.x in your classpath and you are still getting the error, then JPA 1.x must already been loaded either by your application or by the application server, causing your JPA 2.x to be ignored.

To fix this:-

  1. Add JPA 2.x in your classpath. For example, hibernate-jpa-2.0-api-1.0.1.Final.jar.
  2. Remove any trace of JPA 1.x from your classpath by scanning your dependency tree.
  3. If your application server uses JPA 1.x, you will need to remove or replace that jar with JPA 2.x.
  4. If you are not allowed to replace JPA 1.x jar on the application server (for example, you are not the admin of the server), you will need to invert the application class loader to PARENT_LAST to ensure the JPA 2.x from your application gets loaded first and JPA 1.x from the application server will get ignored.

Inverting class loader for application without replacing JPA 1.x from application server

Assuming you have JPA 2.x in your application classpath and your project structure looks like this:-

myproject
|- myproject-ear
|  |- pom.xml
|- myproject-war
|  |- src
|  |  |- main
|  |     |- java
|  |     |- resources
|  |     |- webapp
|  |- pom.xml
|- pom.xml

… if you are deploying your application to Websphere Application Server (WAS), create deployment.xml under src/main/application in the EAR module and instruct WAS to load parent last:-

<!--?xml version="1.0" encoding="UTF-8"?-->
<appdeployment:deployment xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:appdeployment="http://www.ibm.com/websphere/appserver/schemas/5.0/appdeployment.xmi" xmi:id="Deployment_1">


    <deployedobject xmi:type="appdeployment:ApplicationDeployment" xmi:id="ApplicationDeployment_1" startingweight="1" warclassloaderpolicy="SINGLE">
        <classloader xmi:id="Classloader_1" mode="PARENT_LAST">
    </classloader></deployedobject>
</appdeployment:deployment>

In the EAR pom.xml, extend the parent POM and configure the Maven EAR Plugin:-

<!--?xml version="1.0" encoding="UTF-8"?-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelversion>4.0.0</modelversion>

	<!-- Extend the parent POM -->
	<parent>
        <groupid>myproject</groupid>
        <artifactid>myproject</artifactid>
        <version>1.0</version>
    </parent>

    <artifactid>myproject-ear</artifactid>
    <packaging>ear</packaging>
    <name>${project.artifactId}</name>

    <build>
        <plugins>
		   <!-- Configure Maven EAR Plugin -->
            <plugin>
                <artifactid>maven-ear-plugin</artifactid>
                <version>2.4</version>
                <configuration>
                    <displayname>${project.parent.artifactId}</displayname>
                    <modules>
                        <webmodule>
                            <groupid>myproject</groupid>
                            <artifactid>myproject-war</artifactid>
                            <bundlefilename>${project.parent.artifactId}.war</bundlefilename>
                            <contextroot>${context-root}</contextroot>
                        </webmodule>
                    </modules>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
		<!--
		Expose the WAR module to allow the WAR file to be packaged
		in the EAR file by Maven EAR Plugin
		-->
        <dependency>
            <groupid>myproject</groupid>
            <artifactid>myproject-war</artifactid>
            <version>1.0</version>
            <type>war</type>
        </dependency>
    </dependencies>
</project>

Your current project structure should look like this now:-

myproject
|- myproject-ear
|  |- src
|  |  |- main
|  |     |- application
|  |        |- deployment.xml
|  |- pom.xml
|- myproject-war
|  |- src
|  |  |- main
|  |     |- java
|  |     |- resources
|  |     |- webapp
|  |- pom.xml
|- pom.xml

Configure the parent POM to be an aggregator too:-

<!--?xml version="1.0" encoding="UTF-8"?-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelversion>4.0.0</modelversion>

    <groupid>myproject</groupid>
    <artifactid>myproject</artifactid>
    <packaging>pom</packaging>
    <version>1.0</version>

	<!-- Make this parent POM to be an aggregator for both EAR and WAR modules -->
    <modules>
        <module>myproject-ear</module>
        <module>myproject-war</module>
    </modules>
</project>

When you run mvn clean package on the parent POM, the EAR file will contain the WAR file and the deployment file that inverts the class loader for this application.

Comments

2 responses to “java.lang.NoSuchMethodError: javax/persistence/OneToMany.orphanRemoval()Z”

  1. nikita Avatar

    Thank you! The apt solution to my issue. I sincerely wish this site was ranked higher in google search for key words search on JPA version issues on WAS.

  2. […] make sure you don’t have JPA 1.x in your classpath in the first place. Read java.lang.NoSuchMethodError: javax/persistence/OneToMany.orphanRemoval()Z for more […]

Leave a Reply