HHH-6114 Determining inheritance strategy and starting to process mapped properties

This commit is contained in:
Hardy Ferentschik 2011-04-13 17:56:32 +02:00
parent f27695b680
commit 78ad67cff6
6 changed files with 232 additions and 36 deletions

View File

@ -23,12 +23,11 @@
*/
package org.hibernate.metamodel.source.annotations;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import java.util.List;
import javax.persistence.AccessType;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.hibernate.AnnotationException;
@ -39,19 +38,20 @@ import org.hibernate.AnnotationException;
*/
public class ConfiguredClass {
private final ClassInfo classInfo;
private final AccessType classAccessType;
private final ConfiguredClassHierarchy hierarchy;
private final boolean isMappedSuperClass;
private final List<MappedProperty> mappedProperties;
public ConfiguredClass(ClassInfo info, ConfiguredClassHierarchy hierarchy) {
this.classInfo = info;
this.hierarchy = hierarchy;
init();
}
private void init() {
//@Entity and @MappedSuperclass on the same class leads to a NPE down the road
AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, JPADotNames.ENTITY );
AnnotationInstance mappedSuperClassAnnotation = JandexHelper.getSingleAnnotation( classInfo, JPADotNames.MAPPED_SUPER_CLASS );
AnnotationInstance hibernateEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, JPADotNames.HIBERNATE_ENTITY );
AnnotationInstance mappedSuperClassAnnotation = JandexHelper.getSingleAnnotation(
classInfo, JPADotNames.MAPPED_SUPER_CLASS
);
if ( jpaEntityAnnotation != null && mappedSuperClassAnnotation != null ) {
throw new AnnotationException(
@ -60,13 +60,19 @@ public class ConfiguredClass {
);
}
isMappedSuperClass = mappedSuperClassAnnotation != null;
classAccessType = determineClassAccessType( hierarchy.getDefaultAccessType() );
mappedProperties = collectMappedProperties();
}
public ClassInfo getClassInfo() {
return classInfo;
}
public boolean isMappedSuperClass() {
return isMappedSuperClass;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
@ -75,6 +81,22 @@ public class ConfiguredClass {
sb.append( '}' );
return sb.toString();
}
private AccessType determineClassAccessType(AccessType hierarchyAccessType) {
// default to the hierarchy access type to start with
AccessType accessType = hierarchyAccessType;
AnnotationInstance accessAnnotation = JandexHelper.getSingleAnnotation( classInfo, JPADotNames.ACCESS );
if ( accessAnnotation != null ) {
accessType = Enum.valueOf( AccessType.class, accessAnnotation.value( "value" ).asEnum() );
}
return accessType;
}
private List<MappedProperty> collectMappedProperties() {
return null; //To change body of created methods use File | Settings | File Templates.
}
}

View File

@ -66,8 +66,7 @@ public class ConfiguredClassHierarchy implements Iterable<ConfiguredClass> {
/**
* @return An iterator iterating in top down manner over the configured classes in this hierarchy.
*/
public Iterator<ConfiguredClass> iterator
() {
public Iterator<ConfiguredClass> iterator() {
return configuredClasses.iterator();
}
@ -97,28 +96,7 @@ public class ConfiguredClassHierarchy implements Iterable<ConfiguredClass> {
if ( idAnnotations == null || idAnnotations.size() == 0 ) {
continue;
}
for ( AnnotationInstance annotation : idAnnotations ) {
AccessType tmpAccessType;
if ( annotation.target() instanceof FieldInfo ) {
tmpAccessType = AccessType.FIELD;
}
else if ( annotation.target() instanceof MethodInfo ) {
tmpAccessType = AccessType.PROPERTY;
}
else {
throw new AnnotationException( "Invalid placement of @Id annotation" );
}
if ( accessType == null ) {
accessType = tmpAccessType;
}
else {
if ( !accessType.equals( tmpAccessType ) ) {
throw new AnnotationException( "Inconsistent placement of @Id annotation within hierarchy " + hierarchyListString() );
}
}
}
accessType = processIdAnnotations( idAnnotations );
}
if ( accessType == null ) {
@ -128,8 +106,71 @@ public class ConfiguredClassHierarchy implements Iterable<ConfiguredClass> {
return accessType;
}
private AccessType processIdAnnotations(List<AnnotationInstance> idAnnotations) {
AccessType accessType = null;
for ( AnnotationInstance annotation : idAnnotations ) {
AccessType tmpAccessType;
if ( annotation.target() instanceof FieldInfo ) {
tmpAccessType = AccessType.FIELD;
}
else if ( annotation.target() instanceof MethodInfo ) {
tmpAccessType = AccessType.PROPERTY;
}
else {
throw new AnnotationException( "Invalid placement of @Id annotation" );
}
if ( accessType == null ) {
accessType = tmpAccessType;
}
else {
if ( !accessType.equals( tmpAccessType ) ) {
throw new AnnotationException( "Inconsistent placement of @Id annotation within hierarchy " + hierarchyListString() );
}
}
}
return accessType;
}
private InheritanceType determineInheritanceType() {
return null; //To change body of created methods use File | Settings | File Templates.
Iterator<ConfiguredClass> iter = iterator();
InheritanceType inheritanceType = null;
while ( iter.hasNext() ) {
ConfiguredClass configuredClass = iter.next();
ClassInfo info = configuredClass.getClassInfo();
AnnotationInstance inheritanceAnnotation = JandexHelper.getSingleAnnotation(
info, JPADotNames.INHERITANCE
);
if ( inheritanceAnnotation == null ) {
continue;
}
InheritanceType tmpInheritanceType = Enum.valueOf(
InheritanceType.class, inheritanceAnnotation.value( "strategy" ).asEnum()
);
if ( tmpInheritanceType == null ) {
// default inheritance type is single table
inheritanceType = InheritanceType.SINGLE_TABLE;
}
if ( inheritanceType == null ) {
inheritanceType = tmpInheritanceType;
}
else {
if ( !inheritanceType.equals( tmpInheritanceType ) ) {
throw new AnnotationException(
"Multiple incompatible instances of @Inheritance specified within hierarchy " + hierarchyListString()
);
}
}
}
if ( inheritanceType == null ) {
// default inheritance type is single table
inheritanceType = InheritanceType.SINGLE_TABLE;
}
return inheritanceType;
}
private AccessType throwIdNotFoundAnnotationException() {

View File

@ -23,8 +23,10 @@
*/
package org.hibernate.metamodel.source.annotations;
import javax.persistence.Access;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.MappedSuperclass;
import org.jboss.jandex.DotName;
@ -39,8 +41,10 @@ public interface JPADotNames {
public static final DotName HIBERNATE_ENTITY = DotName.createSimple( org.hibernate.annotations.Entity.class.getName() );
public static final DotName MAPPED_SUPER_CLASS = DotName.createSimple( MappedSuperclass.class.getName() );
public static final DotName ID = DotName.createSimple( Id.class.getName() );
public static final DotName INHERITANCE = DotName.createSimple( Inheritance.class.getName() );
public static final DotName ACCESS = DotName.createSimple( Access.class.getName() );
public static final DotName ID = DotName.createSimple( Id.class.getName() );
}

View File

@ -1,3 +1,26 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.metamodel.source.annotations;
import java.util.List;
@ -9,6 +32,8 @@ import org.jboss.jandex.DotName;
import org.hibernate.AssertionFailure;
/**
* Utility methods for working with the jandex annotation index.
*
* @author Hardy Ferentschik
*/
public class JandexHelper {
@ -34,7 +59,9 @@ public class JandexHelper {
}
else {
throw new AssertionFailure(
"There should be only one annotation of type " + annotationName + " defined on" + classInfo.name()
"Found more than one instance of the annotation "
+ annotationList.get( 0 ).name().toString()
+ ". Expected was one."
);
}
}

View File

@ -0,0 +1,34 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.metamodel.source.annotations;
/**
* Represent a mapped property (explicitly or implicitly mapped).
*
* @author Hardy Ferentschik
*/
public class MappedProperty {
}

View File

@ -8,6 +8,8 @@ import javax.persistence.AccessType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.MappedSuperclass;
import org.jboss.jandex.ClassInfo;
@ -175,6 +177,72 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase {
assertEquals( "Wrong default access type", AccessType.PROPERTY, hierarchy.getDefaultAccessType() );
}
@Test
public void testDefaultInheritanceStrategy() {
@Entity
class A {
@Id
String id;
}
@Entity
class B extends A {
}
Index index = indexForClass( B.class, A.class );
ConfiguredClassHierarchyBuilder builder = new ConfiguredClassHierarchyBuilder();
Set<ConfiguredClassHierarchy> hierarchies = builder.createEntityHierarchies( index );
assertTrue( hierarchies.size() == 1 );
ConfiguredClassHierarchy hierarchy = hierarchies.iterator().next();
assertEquals( "Wrong inheritance type", InheritanceType.SINGLE_TABLE, hierarchy.getInheritanceType() );
}
@Test
public void testExplicitInheritanceStrategy() {
@MappedSuperclass
class MappedSuperClass {
}
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
class A extends MappedSuperClass {
@Id
String id;
}
@Entity
class B extends A {
}
Index index = indexForClass( B.class, MappedSuperClass.class, A.class );
ConfiguredClassHierarchyBuilder builder = new ConfiguredClassHierarchyBuilder();
Set<ConfiguredClassHierarchy> hierarchies = builder.createEntityHierarchies( index );
assertTrue( hierarchies.size() == 1 );
ConfiguredClassHierarchy hierarchy = hierarchies.iterator().next();
assertEquals( "Wrong inheritance type", InheritanceType.JOINED, hierarchy.getInheritanceType() );
}
@Test(expected = AnnotationException.class)
public void testMultipleConflictingInheritanceDefinitions() {
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
class A {
String id;
}
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
class B extends A {
}
Index index = indexForClass( B.class, A.class );
ConfiguredClassHierarchyBuilder builder = new ConfiguredClassHierarchyBuilder();
builder.createEntityHierarchies( index );
}
private Index indexForClass(Class<?>... classes) {
Indexer indexer = new Indexer();
for ( Class<?> clazz : classes ) {