3

This is not a duplicate question. As is explained in the body of this question, I have had to return to an old Spring and Hibernate project for various reasons. This project uses the two frameworks to connect to an Apache Derby database using Apache Tomcat and suffered a dependencies issue last year described at:

Error: javax.persistence.JoinColumn.foreignKey()Ljavax/persistence/ForeignKey with Spring controller

But the same problem has occurred again in the same project but where the fix from last year has been applied.

So again, this is not a duplicate question. It is asking why a previously solved problem in a project has happened again after that problem was previously fixed and where the version of the project being used now and suffering the same problem includes last year's fix. I can't understand why.

When I try to build the fixed project from last year, I am getting exception:

used by: java.lang.NoSuchMethodError: javax.persistence.JoinColumn.foreignKey()Ljavax/persistence/ForeignKey;

Because of a one to many relationship between two database tables. The exception seems to point at the dispatcher servlet repository bean reference:

<bean id="bookDAOImpl" class="library.dao.BookDAOImpl" />

As indicated by:

Could not autowire field: private org.hibernate.SessionFactory library.dao.BookDAOImpl.sessionFactory; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/classes/library-servlet.xml]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: javax.persistence.JoinColumn.foreignKey()Ljavax/persistence/ForeignKey;

In the stack trace.

In the dispatcher servlet I am using where the bean can't be created.

The servlet is as follows:

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:mvc="http://www.springframework.org/schema/mvc" 
   xmlns:tx="http://www.springframework.org/schema/tx"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       
   xsi:schemaLocation="http://www.springframework.org/schema/beans 
                       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
                       http://www.springframework.org/schema/context 
                       http://www.springframework.org/schema/context/spring-context-4.0.xsd 
                       http://www.springframework.org/schema/mvc                            
                       http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd                           
                       http://www.springframework.org/schema/tx    
                       http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
                       http://www.springframework.org/schema/aop
                       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">

<!-- Uses annotations in classes for JavaBeans. XML is an alternative. -->
<mvc:annotation-driven />   

<!-- Base package of Library. -->
<context:component-scan base-package="library" />    

<!-- Model. -->
<bean id="person" class="library.model.Person" />
<bean id="book" class="library.model.Book" />        

<!-- Spring Controllers. -->
<bean id="adminController" class="library.controller.admin.AdminController" />    
<bean id="personController" class="library.controller.PersonController" />      
<bean id="bookController" class="library.controller.BookController" /> 
<bean id="exceptionController" class="library.controller.ExceptionController" />     

<!-- Spring Interceptors. -->
<mvc:interceptors>
    <bean id="clientInterceptor" class="library.interceptor.ClientInterceptor" />
</mvc:interceptors>

<!-- Spring Services. -->
<bean id="personService" class="library.service.PersonService" />    
<bean id="bookService" class="library.service.BookService" />  

<!-- Spring Repositories. -->
<bean id="personDAOImpl" class="library.dao.PersonDAOImpl" />    
<bean id="bookDAOImpl" class="library.dao.BookDAOImpl" />       

<!-- Spring Validators. -->
<bean id="personValidator" class="library.validator.PersonValidator" />    
<bean id="bookValidator" class="library.validator.BookValidator" />     

<!-- Spring ViewResolver. -->               
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix">
         <value>/WEB-INF/jsp/</value>
    </property>
    <property name="suffix">
        <value>.jsp</value>
    </property>
</bean>   

<!-- Spring MesssageSource. -->         
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename"> 
        <value>/WEB-INF/classes/messages</value>    
    </property>    
</bean>

<!-- Spring Properties file for Library. -->      
<bean id="propertiesFactory" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    <property name="location">  
         <value>classpath:library.properties</value>             
    </property>
</bean>      

<!-- Hibernate DataSource. -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">        
    <property name="driverClassName" value="org.apache.derby.jdbc.ClientDriver" />
    <property name="url" value="jdbc:derby://localhost:1527/Library" />
    <property name="username" value="username" />
    <property name="password" value="password" />            
</bean>   

<!-- Hibernate Interceptors. -->
<bean id="serverInterceptor" class="library.interceptor.ServerInterceptor" />

<!-- Hibernate SessionFactory. -->    
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">    
    <property name="dataSource" ref="dataSource"></property>                  
    <property name="hibernateProperties">
        <props>               
           <prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop>
           <prop key="hibernate.show_sql">false</prop>
           <prop key="hibernate.current_session_context_class">thread</prop>

           <!-- What to do with the database schema. -->
           <prop key="hbm2ddl.auto">update</prop>    
           <!-- validate:    validate the schema, makes no changes to the database.
                update:      update the schema.
                create:      creates the schema, destroying previous data.
                create-drop: drop the schema at the end of the session. -->                 
        </props>            
    </property>                                                                                                                                
    <property name="entityInterceptor">
        <ref bean="serverInterceptor" />            
    </property>                                                                                                                                             
    <property name="packagesToScan">
        <list>
            <value>library.model</value>                
        </list>
    </property>          
</bean>

<!-- Hibernate TransactionManagment. -->
<tx:annotation-driven />                
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
   <property name="sessionFactory" ref="sessionFactory" />
</bean>  

I had this problem last year and it was solved by changing dependencies as described here:

Error: javax.persistence.JoinColumn.foreignKey()Ljavax/persistence/ForeignKey with Spring controller ` However, the project's dependencies have not changed since, nor has any of its configuration so I do not understand why I am getting this problem.

As with last year, the project uses Spring 4.0.2 and Hibernate 4.3.5 running in NetBeans 8 using Apache Tomcat 8.0.3.0.

In the Java classes there is a 1:M relationship from a class called Person to another class called Book. The database tables are declared for these as well.

Class Person is as follows:

package library.model;

import com.fasterxml.jackson.annotation.JsonManagedReference;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

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

// Attributes.    
@Id
@Column(name="PERSON_ID", unique=true, nullable=false)    
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer personId;

@Column(name="NAME", nullable=false, length=50)      
private String name;

@Column(name="ADDRESS", nullable=false, length=100)
private String address;

@Column(name="TELEPHONE", nullable=false, length=10)
private String telephone;

@Column(name="EMAIL", nullable=false, length=50)
private String email;

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="person") 
@JsonManagedReference
private List<Book> books;

// Constructors.
public Person() {
    this.personId = 0;
    this.name = ("");
    this.address = ("");
    this.telephone = ("");
    this.email = ("");
    this.books = null;
}

public Person(Integer personId, String name, String address, String telephone, String email, ArrayList<Book> books) {
    this.personId = personId;
    this.name = name;
    this.address = address;
    this.telephone = telephone;
    this.email = email;
    this.books = books;
}

With getters and setters.

Book has:

package library.model;

import com.fasterxml.jackson.annotation.JsonBackReference;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="BOOK")
public class Book implements Serializable {

// Attributes.
@Id
@Column(name="BOOK_ID", unique=true, nullable=false)
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer bookId;

@Column(name="AUTHOR", nullable=false, length=50)
private String author;

@Column(name="TITLE", nullable=false, length=50)
private String title;

@Column(name="DESCRIPTION", nullable=false, length=500)
private String description;

@Column(name="ONLOAN", nullable=false, length=5)
private String onLoan;

@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="person_id")
@JsonBackReference
private Person person;

// Constructors.
public Book() {
    this.bookId= 0;
    this.author = ("");
    this.title = ("");
    this.description = ("");  
    this.onLoan = "false";
}

public Book(Integer bookId, String author, String title, String description, String onLoan) {
    this.bookId = 0;
    this.author = author;
    this.title = title;
    this.description = description;     
    this.onLoan = onLoan;
}

The BookDAOImpl class is set like this:

package library.dao;

import java.util.List;
import library.model.Book;
import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository("bookDAOImpl")
public class BookDAOImpl implements GenericDAO<Book> {

@Autowired
private SessionFactory sessionFactory;

static final Logger logger = Logger.getLogger(BookDAOImpl.class.getName());

public BookDAOImpl() {
}

@Override
public void delete(Integer bookId) {
    logger.info(BookDAOImpl.class.getName() + ".delete() method called.");

    Session session = sessionFactory.openSession();
    Transaction transaction = session.getTransaction();        
    try {
        transaction.begin();
        session.delete((Book) session.get(Book.class, bookId));
        transaction.commit();            
    }
    catch(RuntimeException e) {
        transaction.rollback();
        throw e;
    }
    finally {
        session.close();
    }
}

But why, with all the configuration unchanged, do I get this now?

The libraries in the project are as follows:

24 Jun 2015  23 35           445,288 antlr-2.7.7.jar
24 Jun 2015  23 35             4,467 aopalliance-1.0.jar
24 Jun 2015  23 35           160,519 commons-dbcp-1.4.jar
24 Jun 2015  23 35            62,050 commons-logging-1.1.3.jar
24 Jun 2015  23 35         2,703,892 derby-10.9.1.0.jar
24 Jun 2015  23 35           535,985 derbyclient-10.9.1.0.jar
24 Jun 2015  23 35           313,898 dom4j-1.6.1.jar
24 Jun 2015  23 35            75,311 hibernate-commons-annotations-4.0.4.Final.jar
24 Jun 2015  23 35         5,230,007 hibernate-core-4.3.5.Final.jar
24 Jun 2015  23 35           113,371 hibernate-jpa-2.1-api-1.0.0.Final.jar
24 Jun 2015  23 35            38,605 jackson-annotations-2.4.0.jar
24 Jun 2015  23 35           225,306 jackson-core-2.4.1.jar
24 Jun 2015  23 36           228,552 jackson-core-asl-1.9.7.jar
24 Jun 2015  23 35         1,074,275 jackson-databind-2.4.1.jar
24 Jun 2015  23 35           786,084 jackson-mapper-lgpl-1.9.13.jar
24 Jun 2015  23 35            76,551 jandex-1.1.0.Final.jar
24 Jun 2015  23 35           714,194 javassist-3.18.1-GA.jar
24 Jun 2015  23 35           162,126 javax.persistence-2.1.0.jar
24 Jun 2015  23 35            57,183 jboss-logging-3.1.3.GA.jar
24 Jun 2015  23 35            11,558 jboss-logging-annotations-1.2.0.Beta1.jar
24 Jun 2015  23 35            27,717 jboss-transaction-api_1.2_spec-1.0.0.Final.jar
24 Jun 2015  23 35            20,682 jstl-1.1.2.jar
24 Jun 2015  23 35            15,071 jta-1.1.jar
24 Jun 2015  23 35           367,444 log4j-1.2.14.jar
24 Jun 2015  23 35            52,150 persistence-api-1.0.jar
24 Jun 2015  23 36            36,364 spring-annotation-base-1.0.2.jar
24 Jun 2015  23 35           352,730 spring-aop-4.0.2.RELEASE.jar
24 Jun 2015  23 35           669,044 spring-beans-4.0.2.RELEASE.jar
24 Jun 2015  23 35           974,272 spring-context-4.0.2.RELEASE.jar
24 Jun 2015  23 35           960,994 spring-core-4.0.2.RELEASE.jar
24 Jun 2015  23 35           204,780 spring-expression-4.0.2.RELEASE.jar
24 Jun 2015  23 35           419,614 spring-jdbc-4.0.2.RELEASE.jar
24 Jun 2015  23 35           366,844 spring-orm-4.0.2.RELEASE.jar
24 Jun 2015  23 35           248,204 spring-tx-4.0.2.RELEASE.jar
24 Jun 2015  23 35           665,015 spring-web-4.0.2.RELEASE.jar
24 Jun 2015  23 35           660,329 spring-webmvc-4.0.2.RELEASE.jar
24 Jun 2015  23 35           393,259 standard-1.1.2.jar
Community
  • 1
  • 1
Mr Morgan
  • 2,215
  • 15
  • 48
  • 78
  • You are still using Hibernate 4.0.4 while the earlier resolution suggest upgrading to 4.3.x? – Uday Shankar Jun 24 '15 at 14:58
  • Seems like you have this error because of hibernate library. Are you using maven? Try to add [this](http://mvnrepository.com/artifact/org.hibernate.javax.persistence/hibernate-jpa-2.1-api/1.0.0.Final) dependency: – andriy Jun 24 '15 at 14:59
  • Sorry. I am using 4.3.5. The question has been corrected. – Mr Morgan Jun 24 '15 at 15:00
  • The project has `javax-persistence-2.1.0.jar` in its libraries. – Mr Morgan Jun 24 '15 at 15:02
  • Something must have changed. Either j2ee, tomcat or something else. Please check the dependencies and mention the libraries changed. – Uday Shankar Jun 24 '15 at 15:06
  • I will provide a full dependencies list later. – Mr Morgan Jun 24 '15 at 15:11
  • possible duplicate of [Error: javax.persistence.JoinColumn.foreignKey()Ljavax/persistence/ForeignKey with Spring controller](http://stackoverflow.com/questions/24588860/error-javax-persistence-joincolumn-foreignkeyljavax-persistence-foreignkey-wi) – andriy Jun 24 '15 at 15:16
  • Not a duplicate. The problem has happened again in the same project used last year but after the fix was made. Why? – Mr Morgan Jun 24 '15 at 16:47

2 Answers2

2

You're getting this exception because there is an older version of the javax.persistence API somewhere upper in the classpath.

Remove the older version from the classpath and you'll be fine.

WeMakeSoftware
  • 9,039
  • 5
  • 34
  • 52
1

Have same issue. It is due to old Java EE 6 API in classpath:

    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>6.0</version>
        <scope>provided</scope>
    </dependency>

Change this to:

    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>

If you have such issue in a future debug with:

$ mvn dependency:tree
[INFO] +- javax:javaee-web-api:jar:6.0:provided

[INFO] +- org.hibernate:hibernate-entitymanager:jar:4.3.11.Final:compile
[INFO] |  +- org.jboss.logging:jboss-logging:jar:3.1.3.GA:compile
[INFO] |  +- org.jboss.logging:jboss-logging-annotations:jar:1.2.0.Beta1:compile
[INFO] |  +- org.hibernate:hibernate-core:jar:4.3.11.Final:compile
[INFO] |  |  +- antlr:antlr:jar:2.7.7:compile
[INFO] |  |  \- org.jboss:jandex:jar:1.1.0.Final:compile
[INFO] |  +- dom4j:dom4j:jar:1.6.1:compile
[INFO] |  |  \- xml-apis:xml-apis:jar:1.0.b2:compile
[INFO] |  +- org.hibernate.common:hibernate-commons-annotations:jar:4.0.5.Final:compile

[INFO] |  +- org.hibernate.javax.persistence:hibernate-jpa-2.1-api:jar:1.0.0.Final:compile

[INFO] |  +- org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:jar:1.0.0.Final:compile
[INFO] |  \- org.javassist:javassist:jar:3.18.1-GA:compile
gavenkoa
  • 45,285
  • 19
  • 251
  • 303