HHH-8533 - Add tests of JPA Metamodel handling for MappedSuperclass and mixed @Id/@IdClass declaration
This commit is contained in:
parent
bfb05f5694
commit
9360f4d9d4
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.jpa.internal.metamodel;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
@ -45,6 +46,7 @@ public abstract class AbstractIdentifiableType<X>
|
|||
extends AbstractManagedType<X>
|
||||
implements IdentifiableType<X>, Serializable {
|
||||
|
||||
private final boolean hasIdClass;
|
||||
private final boolean hasIdentifierProperty;
|
||||
private final boolean isVersioned;
|
||||
|
||||
|
@ -56,169 +58,157 @@ public abstract class AbstractIdentifiableType<X>
|
|||
Class<X> javaType,
|
||||
String typeName,
|
||||
AbstractIdentifiableType<? super X> superType,
|
||||
boolean hasIdClass,
|
||||
boolean hasIdentifierProperty,
|
||||
boolean versioned) {
|
||||
super( javaType, typeName, superType );
|
||||
this.hasIdClass = hasIdClass;
|
||||
this.hasIdentifierProperty = hasIdentifierProperty;
|
||||
isVersioned = versioned;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean hasIdClass() {
|
||||
return hasIdClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSingleIdAttribute() {
|
||||
return !hasIdClass && hasIdentifierProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public AbstractIdentifiableType<? super X> getSupertype() {
|
||||
// overridden simply to perform the cast
|
||||
return (AbstractIdentifiableType<? super X>) super.getSupertype();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if a non-null super type is required to provide the
|
||||
* identifier attribute(s) if this object does not have a declared
|
||||
* identifier.
|
||||
* .
|
||||
* @return true, if a non-null super type is required to provide
|
||||
* the identifier attribute(s) if this object does not have a
|
||||
* declared identifier; false, otherwise.
|
||||
*/
|
||||
protected abstract boolean requiresSupertypeForNonDeclaredIdentifier();
|
||||
|
||||
protected AbstractIdentifiableType<? super X> requireSupertype() {
|
||||
if ( getSupertype() == null ) {
|
||||
throw new IllegalStateException( "No supertype found" );
|
||||
}
|
||||
return getSupertype();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean hasSingleIdAttribute() {
|
||||
return hasIdentifierProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public <Y> SingularAttribute<? super X, Y> getId(Class<Y> javaType) {
|
||||
final SingularAttribute<? super X, Y> id_;
|
||||
ensureNoIdClass();
|
||||
SingularAttributeImpl id = locateIdAttribute();
|
||||
if ( id != null ) {
|
||||
checkSimpleId();
|
||||
id_ = ( SingularAttribute<? super X, Y> ) id;
|
||||
if ( javaType != id.getJavaType() ) {
|
||||
throw new IllegalArgumentException( "Id attribute was not of specified type : " + javaType.getName() );
|
||||
checkType( id, javaType );
|
||||
}
|
||||
}
|
||||
else {
|
||||
//yuk yuk bad me
|
||||
if ( ! requiresSupertypeForNonDeclaredIdentifier()) {
|
||||
final AbstractIdentifiableType<? super X> supertype = getSupertype();
|
||||
if (supertype != null) {
|
||||
id_ = supertype.getId( javaType );
|
||||
}
|
||||
else {
|
||||
id_ = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
id_ = requireSupertype().getId( javaType );
|
||||
}
|
||||
}
|
||||
return id_;
|
||||
return ( SingularAttribute<? super X, Y> ) id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Centralized check to ensure the id for this hierarchy is a simple one (i.e., does not use
|
||||
* an id-class).
|
||||
*
|
||||
* @see #checkIdClass()
|
||||
*/
|
||||
protected void checkSimpleId() {
|
||||
if ( ! hasIdentifierProperty ) {
|
||||
throw new IllegalStateException( "This class uses an @IdClass" );
|
||||
private void ensureNoIdClass() {
|
||||
if ( hasIdClass ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal call to IdentifiableType#getId for class [" + getTypeName() + "] defined with @IdClass"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private SingularAttributeImpl locateIdAttribute() {
|
||||
if ( id != null ) {
|
||||
return id;
|
||||
}
|
||||
else {
|
||||
if ( getSupertype() != null ) {
|
||||
SingularAttributeImpl id = getSupertype().internalGetId();
|
||||
if ( id != null ) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
return null;
|
||||
}
|
||||
|
||||
protected SingularAttributeImpl internalGetId() {
|
||||
if ( id != null ) {
|
||||
return id;
|
||||
}
|
||||
else {
|
||||
if ( getSupertype() != null ) {
|
||||
return getSupertype().internalGetId();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void checkType(SingularAttributeImpl attribute, Class javaType) {
|
||||
if ( ! javaType.isAssignableFrom( attribute.getType().getJavaType() ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Attribute [%s#%s : %s] not castable to requested type [%s]",
|
||||
getTypeName(),
|
||||
attribute.getName(),
|
||||
attribute.getType().getJavaType().getName(),
|
||||
javaType.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public <Y> SingularAttribute<X, Y> getDeclaredId(Class<Y> javaType) {
|
||||
checkDeclaredId();
|
||||
checkSimpleId();
|
||||
if ( javaType != id.getJavaType() ) {
|
||||
throw new IllegalArgumentException( "Id attribute was not of specified type : " + javaType.getName() );
|
||||
ensureNoIdClass();
|
||||
if ( id == null ) {
|
||||
throw new IllegalArgumentException( "The id attribute is not declared on this type [" + getTypeName() + "]" );
|
||||
}
|
||||
checkType( id, javaType );
|
||||
return (SingularAttribute<X, Y>) id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Centralized check to ensure the id is actually declared on the class mapped here, as opposed to a
|
||||
* super class.
|
||||
*/
|
||||
protected void checkDeclaredId() {
|
||||
if ( id == null ) {
|
||||
throw new IllegalArgumentException( "The id attribute is not declared on this type" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Type<?> getIdType() {
|
||||
if ( id != null ) {
|
||||
checkSimpleId();
|
||||
return id.getType();
|
||||
}
|
||||
else {
|
||||
return requireSupertype().getIdType();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasIdClassAttributesDefined() {
|
||||
return idClassAttributes != null ||
|
||||
( getSupertype() != null && getSupertype().hasIdClassAttributesDefined() );
|
||||
SingularAttributeImpl id = locateIdAttribute();
|
||||
return id == null ? null : id.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Set<SingularAttribute<? super X, ?>> getIdClassAttributes() {
|
||||
if ( idClassAttributes != null ) {
|
||||
checkIdClass();
|
||||
}
|
||||
else {
|
||||
// Java does not allow casting requireSupertype().getIdClassAttributes()
|
||||
// to Set<SingularAttribute<? super X, ?>> because the
|
||||
// superclass X is a different Java type from this X
|
||||
// (i.e, getSupertype().getJavaType() != getJavaType()).
|
||||
// It will, however, allow a Set<SingularAttribute<? super X, ?>>
|
||||
// to be initialized with requireSupertype().getIdClassAttributes(),
|
||||
// since getSupertype().getJavaType() is a superclass of getJavaType()
|
||||
if ( requiresSupertypeForNonDeclaredIdentifier() ) {
|
||||
idClassAttributes = new HashSet<SingularAttribute<? super X, ?>>( requireSupertype().getIdClassAttributes() );
|
||||
}
|
||||
else if ( getSupertype() != null && hasIdClassAttributesDefined() ) {
|
||||
idClassAttributes = new HashSet<SingularAttribute<? super X, ?>>( getSupertype().getIdClassAttributes() );
|
||||
}
|
||||
}
|
||||
return idClassAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Centralized check to ensure the id for this hierarchy uses an id-class.
|
||||
* A form of {@link #getIdClassAttributes} which prefers to return {@code null} rather than throw exceptions
|
||||
*
|
||||
* @see #checkSimpleId()
|
||||
* @return IdClass attributes or {@code null}
|
||||
*/
|
||||
private void checkIdClass() {
|
||||
if ( hasIdentifierProperty ) {
|
||||
throw new IllegalArgumentException( "This class does not use @IdClass" );
|
||||
public Set<SingularAttribute<? super X, ?>> getIdClassAttributesSafely() {
|
||||
if ( !hasIdClass ) {
|
||||
return null;
|
||||
}
|
||||
final Set<SingularAttribute<? super X, ?>> attributes = new HashSet<SingularAttribute<? super X, ?>>();
|
||||
internalCollectIdClassAttributes( attributes );
|
||||
|
||||
if ( attributes.isEmpty() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SingularAttribute<? super X, ?>> getIdClassAttributes() {
|
||||
if ( !hasIdClass ) {
|
||||
throw new IllegalArgumentException( "This class [" + getJavaType() + "] does not define an IdClass" );
|
||||
}
|
||||
|
||||
final Set<SingularAttribute<? super X, ?>> attributes = new HashSet<SingularAttribute<? super X, ?>>();
|
||||
internalCollectIdClassAttributes( attributes );
|
||||
|
||||
if ( attributes.isEmpty() ) {
|
||||
throw new IllegalArgumentException( "Unable to locate IdClass attributes [" + getJavaType() + "]" );
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void internalCollectIdClassAttributes(Set attributes) {
|
||||
if ( idClassAttributes != null ) {
|
||||
attributes.addAll( idClassAttributes );
|
||||
}
|
||||
else if ( getSupertype() != null ) {
|
||||
getSupertype().internalCollectIdClassAttributes( attributes );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean hasVersionAttribute() {
|
||||
return isVersioned;
|
||||
}
|
||||
|
@ -227,39 +217,67 @@ public abstract class AbstractIdentifiableType<X>
|
|||
return isVersioned && version != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public <Y> SingularAttribute<? super X, Y> getVersion(Class<Y> javaType) {
|
||||
// todo : is return null allowed?
|
||||
if ( ! hasVersionAttribute() ) {
|
||||
return null;
|
||||
}
|
||||
final SingularAttribute<? super X, Y> version_;
|
||||
|
||||
SingularAttributeImpl version = locateVersionAttribute();
|
||||
if ( version != null ) {
|
||||
version_ = ( SingularAttribute<? super X, Y> ) version;
|
||||
if ( javaType != version.getJavaType() ) {
|
||||
throw new IllegalArgumentException( "Version attribute was not of specified type : " + javaType.getName() );
|
||||
checkType( version, javaType );
|
||||
}
|
||||
}
|
||||
else {
|
||||
version_ = requireSupertype().getVersion( javaType );
|
||||
}
|
||||
return version_;
|
||||
return ( SingularAttribute<? super X, Y> ) version;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
private SingularAttributeImpl locateVersionAttribute() {
|
||||
if ( version != null ) {
|
||||
return version;
|
||||
}
|
||||
else {
|
||||
if ( getSupertype() != null ) {
|
||||
SingularAttributeImpl version = getSupertype().internalGetVersion();
|
||||
if ( version != null ) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected SingularAttributeImpl internalGetVersion() {
|
||||
if ( version != null ) {
|
||||
return version;
|
||||
}
|
||||
else {
|
||||
if ( getSupertype() != null ) {
|
||||
return getSupertype().internalGetVersion();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public <Y> SingularAttribute<X, Y> getDeclaredVersion(Class<Y> javaType) {
|
||||
checkDeclaredVersion();
|
||||
if ( javaType != version.getJavaType() ) {
|
||||
throw new IllegalArgumentException( "Version attribute was not of specified type : " + javaType.getName() );
|
||||
}
|
||||
checkType( version, javaType );
|
||||
return ( SingularAttribute<X, Y> ) version;
|
||||
}
|
||||
|
||||
private void checkDeclaredVersion() {
|
||||
if ( version == null || ( getSupertype() != null && getSupertype().hasVersionAttribute() )) {
|
||||
throw new IllegalArgumentException(
|
||||
"The version attribute is not declared by this type [" + getJavaType() + "]"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For used to retrieve the declared version when populating the static metamodel.
|
||||
*
|
||||
|
@ -270,16 +288,6 @@ public abstract class AbstractIdentifiableType<X>
|
|||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Centralized check to ensure the version (if one) is actually declared on the class mapped here, as opposed to a
|
||||
* super class.
|
||||
*/
|
||||
protected void checkDeclaredVersion() {
|
||||
if ( version == null || ( getSupertype() != null && getSupertype().hasVersionAttribute() )) {
|
||||
throw new IllegalArgumentException( "The version attribute is not declared on this type" );
|
||||
}
|
||||
}
|
||||
|
||||
public Builder<X> getBuilder() {
|
||||
final AbstractManagedType.Builder<X> managedBuilder = super.getBuilder();
|
||||
return new Builder<X>() {
|
||||
|
|
|
@ -34,40 +34,39 @@ import org.hibernate.mapping.PersistentClass;
|
|||
* @author Steve Ebersole
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public class EntityTypeImpl<X>
|
||||
extends AbstractIdentifiableType<X>
|
||||
implements EntityType<X>, Serializable {
|
||||
public class EntityTypeImpl<X> extends AbstractIdentifiableType<X> implements EntityType<X>, Serializable {
|
||||
private final String jpaEntityName;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public EntityTypeImpl(Class javaType, AbstractIdentifiableType<? super X> superType, PersistentClass persistentClass) {
|
||||
super(
|
||||
javaType,
|
||||
persistentClass.getEntityName(),
|
||||
superType,
|
||||
persistentClass.getDeclaredIdentifierMapper() != null || ( superType != null && superType.hasIdClass() ),
|
||||
persistentClass.hasIdentifierProperty(),
|
||||
persistentClass.isVersioned()
|
||||
);
|
||||
this.jpaEntityName = persistentClass.getJpaEntityName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return jpaEntityName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BindableType getBindableType() {
|
||||
return BindableType.ENTITY_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<X> getBindableJavaType() {
|
||||
return getJavaType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistenceType getPersistenceType() {
|
||||
return PersistenceType.ENTITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean requiresSupertypeForNonDeclaredIdentifier() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,15 +36,18 @@ public class MappedSuperclassTypeImpl<X> extends AbstractIdentifiableType<X> imp
|
|||
Class<X> javaType,
|
||||
MappedSuperclass mappedSuperclass,
|
||||
AbstractIdentifiableType<? super X> superType) {
|
||||
super( javaType, null, superType, mappedSuperclass.hasIdentifierProperty(), mappedSuperclass.isVersioned() );
|
||||
}
|
||||
|
||||
public PersistenceType getPersistenceType() {
|
||||
return PersistenceType.MAPPED_SUPERCLASS;
|
||||
super(
|
||||
javaType,
|
||||
null,
|
||||
superType,
|
||||
mappedSuperclass.getDeclaredIdentifierMapper() != null || ( superType != null && superType.hasIdClass() ),
|
||||
mappedSuperclass.hasIdentifierProperty(),
|
||||
mappedSuperclass.isVersioned()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean requiresSupertypeForNonDeclaredIdentifier() {
|
||||
return false;
|
||||
public PersistenceType getPersistenceType() {
|
||||
return PersistenceType.MAPPED_SUPERCLASS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -393,8 +393,8 @@ class MetadataContext {
|
|||
}
|
||||
|
||||
// handle id-class mappings specially
|
||||
if ( ! entityType.hasSingleIdAttribute() ) {
|
||||
final Set<SingularAttribute<? super X, ?>> attributes = entityType.getIdClassAttributes();
|
||||
if ( entityType.hasIdClass() ) {
|
||||
final Set<SingularAttribute<? super X, ?>> attributes = entityType.getIdClassAttributesSafely();
|
||||
if ( attributes != null ) {
|
||||
for ( SingularAttribute<? super X, ?> attribute : attributes ) {
|
||||
registerAttribute( metamodelClass, attribute );
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
*/
|
||||
package org.hibernate.jpa.test.metamodel;
|
||||
|
||||
import javax.persistence.metamodel.EntityType;
|
||||
import javax.persistence.metamodel.IdentifiableType;
|
||||
import javax.persistence.metamodel.ManagedType;
|
||||
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
@ -32,6 +34,7 @@ import org.junit.Test;
|
|||
import org.hibernate.testing.TestForIssue;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -49,4 +52,23 @@ public class MappedSuperclassTypeTest extends BaseEntityManagerFunctionalTestCas
|
|||
// the issue was in regards to throwing an exception, but also check for nullness
|
||||
assertNotNull( type );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-8533" )
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testAttributeAccess() {
|
||||
final EntityType<SomeMappedSuperclassSubclass> entityType = entityManagerFactory().getMetamodel().entity( SomeMappedSuperclassSubclass.class );
|
||||
final IdentifiableType<SomeMappedSuperclass> mappedSuperclassType = (IdentifiableType<SomeMappedSuperclass>) entityType.getSupertype();
|
||||
|
||||
assertNotNull( entityType.getId( Long.class ) );
|
||||
try {
|
||||
entityType.getDeclaredId( Long.class );
|
||||
fail();
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
|
||||
assertNotNull( mappedSuperclassType.getId( Long.class ) );
|
||||
assertNotNull( mappedSuperclassType.getDeclaredId( Long.class ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.jpa.test.metamodel;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.metamodel.EntityType;
|
||||
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* Ugh
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MixedIdAndIdClassHandling extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { FullTimeEmployee.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-8533" )
|
||||
public void testAccess() {
|
||||
EntityType<FullTimeEmployee> entityType = entityManagerFactory().getMetamodel().entity( FullTimeEmployee.class );
|
||||
try {
|
||||
entityType.getId( String.class );
|
||||
fail( "getId on entity defining @IdClass should cause IAE" );
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
|
||||
assertFalse( entityType.hasSingleIdAttribute() );
|
||||
|
||||
// this is questionable...
|
||||
//assertEquals( String.class, entityType.getIdType().getJavaType() );
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
@IdClass( EmployeeId.class )
|
||||
public static abstract class Employee {
|
||||
@Id
|
||||
private String id;
|
||||
private String name;
|
||||
}
|
||||
|
||||
@Entity( name = "FullTimeEmployee" )
|
||||
@Table( name="EMPLOYEE" )
|
||||
public static class FullTimeEmployee extends Employee {
|
||||
@Column(name="SALARY")
|
||||
private float salary;
|
||||
|
||||
public FullTimeEmployee() {
|
||||
}
|
||||
}
|
||||
|
||||
public static class EmployeeId implements java.io.Serializable {
|
||||
String id;
|
||||
|
||||
public EmployeeId() {
|
||||
}
|
||||
|
||||
public EmployeeId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final EmployeeId other = (EmployeeId) obj;
|
||||
if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 5;
|
||||
hash = 29 * hash + (this.id != null ? this.id.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue