单元测试报错javax.persistence.Table.indexes()[Ljavax/persistence/Index;

本文探讨了在使用Hibernate框架进行开发时遇到的问题,在Tomcat环境下正常运行的应用在JUnit单元测试下出现NoSuchMethodError错误。通过深入分析,发现是由于Java Persistence API (JPA) 版本不匹配导致。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

          今天在写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
 Stringcatalog
          (Optional) The catalog of the table.
 Stringname
          (Optional) The name of the table.
 Stringschema
          (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 TypeOptional Element and Description
Stringcatalog
(Optional) The catalog of the table.
Index[]indexes
(Optional) Indexes for the table.
Stringname
(Optional) The name of the table.
Stringschema
(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 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值