單元測試報錯javax.persistence.Table.indexes()[Ljavax/persistence/Index;

          今天在寫WEB項目的時候tomcat上都能跑,但是唯獨在junit單元測試的時報錯。Caused by: java.lang.NoSuchMethodError: javax.persistence.Table.indexes()[Ljavax/persistence/Index;

          見了鬼了,明明我在tomcat跑的時候都好的,爲什麼偏偏在junit時候報錯呢?

         先來看看我自己的代碼:

package com.bsoft.entry;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name="pmis_user")
public class User {

	@Id  
    @GeneratedValue(generator = "system-uuid")  //使用uuid生成主鍵的方式  
    @GenericGenerator(name = "system-uuid", strategy = "uuid")   
    @Column(length=32)  
	private String UserId;
	
	@Column(length=100)
	private String userName;
	
	@Column(length=100)
	private String loginname;
	
	@Column(length=100)
	private String password;
	
	@Column(length=100)
	private String phoneNumber;
	
	@Column(length=100)
	private String email;
	
	@Column(length=100)
	private String authority;
	
	@Column(length=20)
	private String JGID;
	
	public String getJGID() {
		return JGID;
	}

	public void setJGID(String jGID) {
		JGID = jGID;
	}

	public String getUserId() {
		return UserId;
	}

	public void setUserId(String userId) {
		UserId = userId;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getLoginname() {
		return loginname;
	}

	public void setLoginname(String loginname) {
		this.loginname = loginname;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getPhoneNumber() {
		return phoneNumber;
	}

	public void setPhoneNumber(String phoneNumber) {
		this.phoneNumber = phoneNumber;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getAuthority() {
		return authority;
	}

	public void setAuthority(String authority) {
		this.authority = authority;
	}
	
	
	
}

網上搜了一下說是去掉@Table註釋,改成@Entity(TABLEName)。乍一試,沒問題。但是當我們用到HQL查詢的時候  比如 from User where xxxxxxxx 發現User  is not mapping.只能改成和表名一樣的pmis_user 才能繼續。明顯不合理。

         解決思路:

          既然報錯,我們就接着報錯的地方找下去。建議各位碰到問題可以多看看想想,我們的切入點是官網。

         本系統中用的是javaee5.0 對應官網地址:http://docs.oracle.com/javaee/5/api/

         找到javax.persistence.Table :

javax.persistence
Annotation Type Table


@Target(value=TYPE)
@Retention(value=RUNTIME)
public @interface Table

This annotation specifies the primary table for the annotated entity. Additional tables may be specified using SecondaryTable or SecondaryTables annotation.

If no Table annotation is specified for an entity class, the default values apply.

    Example:

    @Entity
    @Table(name="CUST", schema="RECORDS")
    public class Customer { ... }
 
Since:
Java Persistence 1.0

Optional Element Summary
 String catalog
          (Optional) The catalog of the table.
 String name
          (Optional) The name of the table.
 String schema
          (Optional) The schema of the table.
 UniqueConstraint[] uniqueConstraints
          (Optional) Unique constraints that are to be placed on the table.


    我了個乖乖  發現根本就沒Index這個屬性麼。難怪會報錯

    我們再繼續看6.0 也是沒有

    再查7.0:

javax.persistence

Annotation Type Table



  • @Target(value=TYPE)
     @Retention(value=RUNTIME)
    public @interface Table
    Specifies the primary table for the annotated entity. Additional tables may be specified using SecondaryTable or SecondaryTables annotation.

    If no Table annotation is specified for an entity class, the default values apply.

        Example:
    
        @Entity
        @Table(name="CUST", schema="RECORDS")
        public class Customer { ... }
     
    Since:
    Java Persistence 1.0

Optional Element Summary

Optional Elements
Modifier and Type Optional Element and Description
String catalog
(Optional) The catalog of the table.
Index[] indexes
(Optional) Indexes for the table.
String name
(Optional) The name of the table.
String schema
(Optional) The schema of the table.
UniqueConstraint[] uniqueConstraints
(Optional) Unique constraints that are to be placed on the table.

   總算找到了 我們替換javaee 7.0:

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


 OK 果然可以了。

深度分析:

   那爲什麼會出現這種問題呢? 根據hibernate返回的報錯

public static void bindClass(XClass clazzToProcess, Map<XClass, InheritanceState> inheritanceStatePerClass, Mappings mappings)
    throws MappingException
{
    //此處省略N行代碼
    
    mappings.addClass(persistentClass);
    
    mappings.addSecondPass(new SecondaryTableSecondPass(entityBinder, propertyHolder, clazzToProcess));
    
    entityBinder.processComplementaryTableDefinitions((org.hibernate.annotations.Table)clazzToProcess.getAnnotation(org.hibernate.annotations.Table.class));
    entityBinder.processComplementaryTableDefinitions((Tables)clazzToProcess.getAnnotation(Tables.class));
    entityBinder.processComplementaryTableDefinitions(tabAnn);
}
發現都是調用 processComplementaryTableDefinitions 這個方法

前面兩個都是org.hibernate.annotations.Tables  最後一個tabAnn:

javax.persistence.Table tabAnn = null;
		if ( clazzToProcess.isAnnotationPresent( javax.persistence.Table.class ) ) {
			tabAnn = clazzToProcess.getAnnotation( javax.persistence.Table.class );
			table = tabAnn.name();
			schema = tabAnn.schema();
			catalog = tabAnn.catalog();
			uniqueConstraints = TableBinder.buildUniqueConstraintHolders( tabAnn.uniqueConstraints() );
		}

發現是javax.persistence.Table javaEE中 好的那我們繼續往下找:

找到EntityBinder 的processComplementaryTableDefinitions()

public void processComplementaryTableDefinitions(javax.persistence.Table table) {
    if (table == null) return;
    TableBinder.addIndexes(this.persistentClass.getTable(), table.indexes(), this.mappings);
}

public void processComplementaryTableDefinitions(org.hibernate.annotations.Table table) {
		//comment and index are processed here
		if ( table == null ) return;
		String appliedTable = table.appliesTo();
		Iterator tables = persistentClass.getTableClosureIterator();
		Table hibTable = null;
		while ( tables.hasNext() ) {
			Table pcTable = (Table) tables.next();
			if ( pcTable.getQuotedName().equals( appliedTable ) ) {
				//we are in the correct table to find columns
				hibTable = pcTable;
				break;
			}
			hibTable = null;
		}
		if ( hibTable == null ) {
			//maybe a join/secondary table
			for ( Join join : secondaryTables.values() ) {
				if ( join.getTable().getQuotedName().equals( appliedTable ) ) {
					hibTable = join.getTable();
					break;
				}
			}
		}
		if ( hibTable == null ) {
			throw new AnnotationException(
					"@org.hibernate.annotations.Table references an unknown table: " + appliedTable
			);
		}
		if ( !BinderHelper.isEmptyAnnotationValue( table.comment() ) ) hibTable.setComment( table.comment() );
		TableBinder.addIndexes( hibTable, table.indexes(), mappings );
	}
OK找到。再發現:
Java EE 5平臺引入了Java持久化API(Java Persistence API,JPA),它爲Java EE和Java SE應用程序提供了一個基於POJO的持久化模塊。JPA處理關係數據與Java對象之間的映射,它使對象/關係(O/R)映射標準化,JPA已經被廣泛採用,已經成爲事實上的O/R持久化企業標準。

  Java EE 6帶來了JPA的最新版本 — JSR 317:Java持久化2.0,JPA 2.0帶來了許多新特性和增強,包括

  1、對象/關係映射增強;

  2、Java持久化查詢語言增強;

  3、一種新的基於標準的查詢API;

  4、支持悲觀鎖定。

但是在javax.persistence.Table中(javaee7.0)發現

  • indexes

    public abstract Index[] indexes
    (Optional) Indexes for the table. These are only used if table generation is in effect. Note that it is not necessary to specify an index for a primary key, as the primary key index will be created automatically.
    Since:
    Java Persistence 2.1
    Default:
    {}
JPA 2.1開始啓用。所以要在搭配hibernate-core-4.3.5 時候又想能用junit做單元測試的,我們要跟上節奏,儘快更新javaee 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章