HHH-6114 Determining the default access type of a class hierarchy
This commit is contained in:
parent
4d24c16b49
commit
be7b44c2f7
|
@ -70,12 +70,12 @@ public class AnnotationBinder {
|
|||
ClassInfo classInfo = entity.getClassInfo();
|
||||
|
||||
//@Entity and @MappedSuperclass on the same class leads to a NPE down the road
|
||||
AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, ConfiguredClass.ENTITY );
|
||||
AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, JPADotNames.ENTITY );
|
||||
AnnotationInstance mappedSuperClassAnnotation = JandexHelper.getSingleAnnotation(
|
||||
classInfo, ConfiguredClass.MAPPED_SUPER_CLASS
|
||||
classInfo, JPADotNames.MAPPED_SUPER_CLASS
|
||||
);
|
||||
AnnotationInstance hibernateEntityAnnotation = JandexHelper.getSingleAnnotation(
|
||||
classInfo, ConfiguredClass.HIBERNATE_ENTITY
|
||||
classInfo, JPADotNames.HIBERNATE_ENTITY
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -38,10 +38,6 @@ import org.hibernate.AnnotationException;
|
|||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class ConfiguredClass {
|
||||
public static final DotName ENTITY = DotName.createSimple( Entity.class.getName() );
|
||||
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() );
|
||||
|
||||
private final ClassInfo classInfo;
|
||||
private final ConfiguredClassHierarchy hierarchy;
|
||||
|
||||
|
@ -53,9 +49,9 @@ public class ConfiguredClass {
|
|||
|
||||
private void init() {
|
||||
//@Entity and @MappedSuperclass on the same class leads to a NPE down the road
|
||||
AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, ENTITY );
|
||||
AnnotationInstance mappedSuperClassAnnotation = JandexHelper.getSingleAnnotation( classInfo, MAPPED_SUPER_CLASS );
|
||||
AnnotationInstance hibernateEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, HIBERNATE_ENTITY );
|
||||
AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, JPADotNames.ENTITY );
|
||||
AnnotationInstance mappedSuperClassAnnotation = JandexHelper.getSingleAnnotation( classInfo, JPADotNames.MAPPED_SUPER_CLASS );
|
||||
AnnotationInstance hibernateEntityAnnotation = JandexHelper.getSingleAnnotation( classInfo, JPADotNames.HIBERNATE_ENTITY );
|
||||
|
||||
if ( jpaEntityAnnotation != null && mappedSuperClassAnnotation != null ) {
|
||||
throw new AnnotationException(
|
||||
|
|
|
@ -26,16 +26,24 @@ package org.hibernate.metamodel.source.annotations;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.InheritanceType;
|
||||
|
||||
import org.jboss.jandex.AnnotationInstance;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.FieldInfo;
|
||||
import org.jboss.jandex.MethodInfo;
|
||||
|
||||
import org.hibernate.cfg.AccessType;
|
||||
import org.hibernate.AnnotationException;
|
||||
|
||||
/**
|
||||
* Represents the inheritance structure of the configured classes within a class hierarchy.
|
||||
*
|
||||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class ConfiguredClassHierarchy implements Iterable<ConfiguredClass> {
|
||||
private final AccessType defaultAccessType;
|
||||
private final InheritanceType inheritanceType;
|
||||
private final List<ConfiguredClass> configuredClasses;
|
||||
|
||||
ConfiguredClassHierarchy(List<ClassInfo> classes) {
|
||||
|
@ -44,19 +52,28 @@ public class ConfiguredClassHierarchy implements Iterable<ConfiguredClass> {
|
|||
configuredClasses.add( new ConfiguredClass( info, this ) );
|
||||
}
|
||||
defaultAccessType = determineDefaultAccessType();
|
||||
inheritanceType = determineInheritanceType();
|
||||
}
|
||||
|
||||
private AccessType determineDefaultAccessType() {
|
||||
return null;
|
||||
public AccessType getDefaultAccessType() {
|
||||
return defaultAccessType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ConfiguredClass> iterator() {
|
||||
public InheritanceType getInheritanceType() {
|
||||
return inheritanceType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return An iterator iterating in top down manner over the configured classes in this hierarchy.
|
||||
*/
|
||||
public Iterator<ConfiguredClass> iterator
|
||||
() {
|
||||
return configuredClasses.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
public String toString
|
||||
() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append( "ConfiguredClassHierarchy" );
|
||||
sb.append( "{defaultAccessType=" ).append( defaultAccessType );
|
||||
|
@ -64,6 +81,78 @@ public class ConfiguredClassHierarchy implements Iterable<ConfiguredClass> {
|
|||
sb.append( '}' );
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the default access type for the configured class hierarchy independent of explicit
|
||||
* {@code AccessType} annotations. The default access type is determined by the placement of the
|
||||
* annotations.
|
||||
*/
|
||||
private AccessType determineDefaultAccessType() {
|
||||
Iterator<ConfiguredClass> iter = iterator();
|
||||
AccessType accessType = null;
|
||||
while ( iter.hasNext() ) {
|
||||
ConfiguredClass configuredClass = iter.next();
|
||||
ClassInfo info = configuredClass.getClassInfo();
|
||||
List<AnnotationInstance> idAnnotations = info.annotations().get( JPADotNames.ID );
|
||||
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() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( accessType == null ) {
|
||||
return throwIdNotFoundAnnotationException();
|
||||
}
|
||||
|
||||
return accessType;
|
||||
}
|
||||
|
||||
private InheritanceType determineInheritanceType() {
|
||||
return null; //To change body of created methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
private AccessType throwIdNotFoundAnnotationException() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append( "Unable to find Id property for class hierarchy " );
|
||||
builder.append( hierarchyListString() );
|
||||
throw new AnnotationException( builder.toString() );
|
||||
}
|
||||
|
||||
private String hierarchyListString() {
|
||||
Iterator<ConfiguredClass> iter;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append( "[" );
|
||||
iter = iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
builder.append( iter.next().getClassInfo().name().toString() );
|
||||
if ( iter.hasNext() ) {
|
||||
builder.append( ", " );
|
||||
}
|
||||
}
|
||||
builder.append( "]" );
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
import org.jboss.jandex.DotName;
|
||||
|
||||
/**
|
||||
* Defines the dot names for the JPA annotations
|
||||
*
|
||||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public interface JPADotNames {
|
||||
public static final DotName ENTITY = DotName.createSimple( Entity.class.getName() );
|
||||
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() );
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
@ -19,6 +20,7 @@ import org.hibernate.AnnotationException;
|
|||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
|
@ -65,6 +67,22 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase {
|
|||
|
||||
@Test
|
||||
public void testMappedSuperClass() {
|
||||
@MappedSuperclass
|
||||
class MappedSuperClass {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private int id;
|
||||
}
|
||||
|
||||
class UnmappedSubClass extends MappedSuperClass {
|
||||
private String unmappedProperty;
|
||||
}
|
||||
|
||||
@Entity
|
||||
class MappedSubClass extends UnmappedSubClass {
|
||||
private String mappedProperty;
|
||||
}
|
||||
|
||||
Index index = indexForClass( MappedSubClass.class, MappedSuperClass.class, UnmappedSubClass.class );
|
||||
ConfiguredClassHierarchyBuilder builder = new ConfiguredClassHierarchyBuilder();
|
||||
Set<ConfiguredClassHierarchy> hierarchies = builder.createEntityHierarchies( index );
|
||||
|
@ -82,11 +100,81 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase {
|
|||
|
||||
@Test(expected = AnnotationException.class)
|
||||
public void testEntityAndMappedSuperClassAnnotations() {
|
||||
@Entity
|
||||
@MappedSuperclass
|
||||
class EntityAndMappedSuperClass {
|
||||
}
|
||||
|
||||
Index index = indexForClass( EntityAndMappedSuperClass.class );
|
||||
ConfiguredClassHierarchyBuilder builder = new ConfiguredClassHierarchyBuilder();
|
||||
builder.createEntityHierarchies( index );
|
||||
}
|
||||
|
||||
@Test(expected = AnnotationException.class)
|
||||
public void testNoIdAnnotation() {
|
||||
|
||||
@Entity
|
||||
class A {
|
||||
String id;
|
||||
}
|
||||
|
||||
@Entity
|
||||
class B extends A {
|
||||
}
|
||||
|
||||
Index index = indexForClass( B.class, A.class );
|
||||
ConfiguredClassHierarchyBuilder builder = new ConfiguredClassHierarchyBuilder();
|
||||
builder.createEntityHierarchies( index );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultFieldAccess() {
|
||||
@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 default access type", AccessType.FIELD, hierarchy.getDefaultAccessType() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultPropertyAccess() {
|
||||
@Entity
|
||||
class A {
|
||||
String id;
|
||||
|
||||
@Id
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = 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 default access type", AccessType.PROPERTY, hierarchy.getDefaultAccessType() );
|
||||
}
|
||||
|
||||
private Index indexForClass(Class<?>... classes) {
|
||||
Indexer indexer = new Indexer();
|
||||
for ( Class<?> clazz : classes ) {
|
||||
|
@ -121,27 +209,6 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase {
|
|||
public class B extends A {
|
||||
private String name;
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
public class MappedSuperClass {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private int id;
|
||||
}
|
||||
|
||||
public class UnmappedSubClass extends MappedSuperClass {
|
||||
private String unmappedProperty;
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class MappedSubClass extends UnmappedSubClass {
|
||||
private String mappedProperty;
|
||||
}
|
||||
|
||||
@Entity
|
||||
@MappedSuperclass
|
||||
public class EntityAndMappedSuperClass {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue