diff --git a/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java index a9886a9d75..ea25daf3d7 100644 --- a/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -35,7 +35,6 @@ import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; -import javax.persistence.Access; import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.DiscriminatorType; @@ -191,8 +190,6 @@ public final class AnnotationBinder { * bindSomething usually create the mapping container and is accessed by one of the 2 first level method * makeSomething usually create the mapping container and is accessed by bindSomething[else] * fillSomething take the container into parameter and fill it. - * - * */ private AnnotationBinder() { } @@ -618,7 +615,7 @@ public final class AnnotationBinder { ); } - //try to find class level generators + // try to find class level generators HashMap classGenerators = buildLocalGenerators( clazzToProcess, mappings ); // check properties @@ -626,9 +623,6 @@ public final class AnnotationBinder { getElementsToProcess( persistentClass, clazzToProcess, inheritanceStatePerClass, entityBinder, mappings ); - if ( elements == null ) { - throw new AnnotationException( "No identifier specified for entity: " + propertyHolder.getEntityName() ); - } final boolean subclassAndSingleTableStrategy = inheritanceState.getType() == InheritanceType.SINGLE_TABLE && inheritanceState.hasParents(); //process idclass if any @@ -644,9 +638,7 @@ public final class AnnotationBinder { idClass = current.getAnnotation( IdClass.class ); break; } - state = InheritanceState.getSuperclassInheritanceState( - current, inheritanceStatePerClass, mappings.getReflectionManager() - ); + state = InheritanceState.getSuperclassInheritanceState( current, inheritanceStatePerClass ); } while ( state != null ); } @@ -657,10 +649,10 @@ public final class AnnotationBinder { String generatorType = "assigned"; String generator = BinderHelper.ANNOTATION_STRING_DEFAULT; PropertyData inferredData = new PropertyPreloadedData( - entityBinder.getPropertyAccessor(), "id", compositeClass + entityBinder.getPropertyAccessType(), "id", compositeClass ); PropertyData baseInferredData = new PropertyPreloadedData( - entityBinder.getPropertyAccessor(), "id", current + entityBinder.getPropertyAccessType(), "id", current ); HashMap localGenerators = new HashMap(); boolean ignoreIdAnnotations = entityBinder.isIgnoreIdAnnotations(); @@ -834,11 +826,7 @@ public final class AnnotationBinder { } private static PersistentClass getSuperEntity(XClass clazzToProcess, Map inheritanceStatePerClass, ExtendedMappings mappings, InheritanceState inheritanceState) { - final ReflectionManager reflectionManager = mappings.getReflectionManager(); - InheritanceState superEntityState = - InheritanceState.getInheritanceStateOfSuperEntity( - clazzToProcess, inheritanceStatePerClass, reflectionManager - ); + InheritanceState superEntityState = InheritanceState.getInheritanceStateOfSuperEntity( clazzToProcess, inheritanceStatePerClass ); PersistentClass superEntity = superEntityState != null ? mappings.getClass( superEntityState.getClazz().getName() @@ -880,8 +868,7 @@ public final class AnnotationBinder { } /* - * Get the annotated elements - * Guess the annotated element from @Id or @EmbeddedId presence + * Get the annotated elements, guessing the access type from @Id or @EmbeddedId presence. * Change EntityBinder by side effect */ private static List getElementsToProcess( @@ -892,104 +879,50 @@ public final class AnnotationBinder { InheritanceState inheritanceState = inheritanceStatePerClass.get( clazzToProcess ); assert !inheritanceState.isEmbeddableSuperclass(); - AccessType accessType = determineExplicitAccessType( - clazzToProcess, inheritanceStatePerClass, mappings, inheritanceState - ); List classesToProcess = getMappedSuperclassesTillNextEntityOrdered( persistentClass, clazzToProcess, inheritanceStatePerClass, mappings ); + + AccessType accessType = determineDefaultAccessType( clazzToProcess, inheritanceStatePerClass ); + List elements = new ArrayList(); int deep = classesToProcess.size(); boolean hasIdentifier = false; - /* - * delay the exception in case field access is used - */ - AnnotationException exceptionWhileWalkingElements = null; - try { - for (int index = 0; index < deep; index++) { - PropertyContainer properyContainer = new PropertyContainer( classesToProcess.get( index ) ); - boolean currentHasIdentifier = addElementsOfClass( elements, accessType , properyContainer, mappings ); - hasIdentifier = hasIdentifier || currentHasIdentifier; - } - } - catch ( AnnotationException e ) { - exceptionWhileWalkingElements = e; + for ( int index = 0; index < deep; index++ ) { + PropertyContainer properyContainer = new PropertyContainer( classesToProcess.get( index ) ); + boolean currentHasIdentifier = addElementsOfClass( elements, accessType, properyContainer, mappings ); + hasIdentifier = hasIdentifier || currentHasIdentifier; } + entityBinder.setPropertyAccessType( accessType ); + if ( !hasIdentifier && !inheritanceState.hasParents() ) { - if ( AccessType.PROPERTY.equals( accessType ) ) { - //the original exception is legitimate - if ( exceptionWhileWalkingElements != null) throw exceptionWhileWalkingElements; - return null; //explicit but no @Id: the upper layer will raise an exception - } - accessType = AccessType.FIELD; - elements.clear(); - for (int index = 0; index < deep; index++) { - PropertyContainer properyContainer = new PropertyContainer( classesToProcess.get( index ) ); - boolean currentHasIdentifier = addElementsOfClass(elements, accessType, properyContainer, mappings ); - hasIdentifier = hasIdentifier || currentHasIdentifier; - } + throw new AnnotationException( "No identifier specified for entity: " + clazzToProcess.getName() ); } - //the field show no id, fallback to he original exception - if (!hasIdentifier && exceptionWhileWalkingElements != null) throw exceptionWhileWalkingElements; - - entityBinder.setPropertyAccessor( accessType ); - inheritanceState.setAccessType( accessType ); - return hasIdentifier || inheritanceState.hasParents() ? - elements : - null; + return elements; } - /* - * Check whether either the class itself or any of its super classes explicitly defines a value access strategy. - * - * @return {@code AccessType.FIELD} or {@code AccessType.PROPERTY} in case there is an explicit value, - * {@code AccessType.DEFAULT} otherwise. - */ - private static AccessType determineExplicitAccessType(XClass clazzToProcess, Map inheritanceStatePerClass, ExtendedMappings mappings, InheritanceState inheritanceState) { - AccessType explicitAccessType = AccessType.DEFAULT; - - // check whether any of the super classes or the class itself - if ( inheritanceState.hasParents() ) { - InheritanceState superEntityState = - InheritanceState.getInheritanceStateOfSuperEntity( - clazzToProcess, inheritanceStatePerClass, mappings.getReflectionManager() - ); - if ( superEntityState != null ) { - explicitAccessType = superEntityState.getAccessType(); + private static AccessType determineDefaultAccessType(XClass annotatedClass, Map inheritanceStatePerClass) { + XClass xclass = annotatedClass; + while ( xclass != null && !Object.class.getName().equals( xclass.getName() ) ) { + if ( xclass.isAnnotationPresent( Entity.class ) || xclass.isAnnotationPresent( MappedSuperclass.class ) ) { + for ( XProperty prop : xclass.getDeclaredProperties( AccessType.PROPERTY.getType() ) ) { + if ( prop.isAnnotationPresent( Id.class ) || prop.isAnnotationPresent( EmbeddedId.class ) ) { + return AccessType.PROPERTY; + } + } + for ( XProperty prop : xclass.getDeclaredProperties( AccessType.FIELD.getType() ) ) { + if ( prop.isAnnotationPresent( Id.class ) || prop.isAnnotationPresent( EmbeddedId.class ) ) { + return AccessType.FIELD; + } + } } + xclass = xclass.getSuperclass(); } - else { - AccessType hibernateExplicitAccessType = AccessType.DEFAULT; - AccessType jpaExplicitAccessType = AccessType.DEFAULT; - - //the are the root entity but we might have mapped superclasses that contain the id class - org.hibernate.annotations.AccessType accessType = clazzToProcess.getAnnotation( org.hibernate.annotations.AccessType.class ); - if ( accessType != null ) { - hibernateExplicitAccessType = AccessType.getAccessStrategy( accessType.value() ); - } - - Access access = clazzToProcess.getAnnotation( Access.class ); - if( access != null ) { - jpaExplicitAccessType = AccessType.getAccessStrategy( access.value() ); - } - - if ( hibernateExplicitAccessType != AccessType.DEFAULT - && jpaExplicitAccessType != AccessType.DEFAULT - && hibernateExplicitAccessType != jpaExplicitAccessType ) { - throw new MappingException( "@AccessType and @Access specified with contradicting values. Use of @Access only is recommended. " ); - } - - if(hibernateExplicitAccessType != AccessType.DEFAULT) { - explicitAccessType = hibernateExplicitAccessType; - } else { - explicitAccessType = jpaExplicitAccessType; - } - } - return explicitAccessType; + throw new AnnotationException( "No identifier specified for entity: " + annotatedClass.getName() ); } private static List getMappedSuperclassesTillNextEntityOrdered( @@ -1021,7 +954,7 @@ public final class AnnotationBinder { // classes from 0 to n-1 are @MappedSuperclass and should be linked org.hibernate.mapping.MappedSuperclass mappedSuperclass = null; final InheritanceState superEntityState = - InheritanceState.getInheritanceStateOfSuperEntity(annotatedClass, inheritanceStatePerClass, reflectionManager); + InheritanceState.getInheritanceStateOfSuperEntity( annotatedClass, inheritanceStatePerClass ); PersistentClass superEntity = superEntityState != null ? mappings.getClass( superEntityState.getClazz().getName() ) : @@ -1162,7 +1095,7 @@ public final class AnnotationBinder { /** * * @param elements List of {@code ProperyData} instances - * @param propertyAccessor The default value access strategy which has to be used in case no explicit local access + * @param defaultAccessType The default value access strategy which has to be used in case no explicit local access * strategy is used * @param propertyContainer Metadata about a class and its properties * @param mappings Mapping meta data @@ -1170,19 +1103,20 @@ public final class AnnotationBinder { * the determined access strategy, {@code false} otherwise. */ private static boolean addElementsOfClass( - List elements, AccessType propertyAccessor, PropertyContainer propertyContainer, ExtendedMappings mappings + List elements, AccessType defaultAccessType, PropertyContainer propertyContainer, ExtendedMappings mappings ) { boolean hasIdentifier = false; - AccessType classDefinedAccessType = propertyContainer.getDefaultAccessStrategy(); + AccessType accessType = defaultAccessType; - if ( classDefinedAccessType.equals( AccessType.DEFAULT ) ) { - classDefinedAccessType = propertyAccessor; + if ( propertyContainer.hasExplicitAccessStrategy() ) { + accessType = propertyContainer.getExplicitAccessStrategy(); } - Collection properties = propertyContainer.getProperties( classDefinedAccessType ); + propertyContainer.assertTypesAreResolvable( accessType ); + Collection properties = propertyContainer.getProperties( accessType ); for ( XProperty p : properties ) { final boolean currentHasIdentifier = addProperty( - propertyContainer.getXClass(), p, elements, classDefinedAccessType.getType(), mappings + propertyContainer.getXClass(), p, elements, accessType.getType(), mappings ); hasIdentifier = hasIdentifier || currentHasIdentifier; } @@ -1193,7 +1127,7 @@ public final class AnnotationBinder { XClass declaringClass, XProperty property, List annElts, String propertyAccessor, ExtendedMappings mappings ) { - boolean hasIdentifier = false; + boolean hasIdentifier; PropertyData propertyAnnotatedElement = new PropertyInferredData( declaringClass, property, propertyAccessor, mappings.getReflectionManager() ); @@ -2048,7 +1982,6 @@ public final class AnnotationBinder { List baseClassElements = null; XClass baseReturnedClassOrElement; - PropertyHolder baseSubHolder; if(baseInferredData != null) { baseClassElements = new ArrayList(); @@ -2567,29 +2500,22 @@ public final class AnnotationBinder { * inheritance status of a class. * * @param orderedClasses Order list of all annotated entities and their mapped superclasses - * @param reflectionManager Reference to the reflection manager (commons-annotations) * @return A map of {@code InheritanceState}s keyed against their {@code XClass}. */ - public static Map buildInheritanceStates( - List orderedClasses, ReflectionManager reflectionManager - ) { + public static Map buildInheritanceStates(List orderedClasses) { Map inheritanceStatePerClass = new HashMap( orderedClasses.size() ); for (XClass clazz : orderedClasses) { InheritanceState superclassState = InheritanceState.getSuperclassInheritanceState( - clazz, inheritanceStatePerClass, - reflectionManager - ); + clazz, inheritanceStatePerClass ); InheritanceState state = new InheritanceState( clazz ); if ( superclassState != null ) { //the classes are ordered thus preventing an NPE //FIXME if an entity has subclasses annotated @MappedSperclass wo sub @Entity this is wrong superclassState.setHasSiblings( true ); InheritanceState superEntityState = InheritanceState.getInheritanceStateOfSuperEntity( - clazz, inheritanceStatePerClass, - reflectionManager - ); + clazz, inheritanceStatePerClass ); state.setHasParents( superEntityState != null ); final boolean nonDefault = state.getType() != null && !InheritanceType.SINGLE_TABLE.equals( state.getType() ); if ( superclassState.getType() != null ) { diff --git a/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java b/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java index 9d87e07278..29d2e81416 100644 --- a/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java +++ b/annotations/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java @@ -611,7 +611,7 @@ public class AnnotationConfiguration extends Configuration { //bind classes in the correct order calculating some inheritance state List orderedClasses = orderAndFillHierarchy( annotatedClasses ); Map inheritanceStatePerClass = AnnotationBinder.buildInheritanceStates( - orderedClasses, reflectionManager + orderedClasses ); ExtendedMappings mappings = createExtendedMappings(); diff --git a/annotations/src/main/java/org/hibernate/cfg/InheritanceState.java b/annotations/src/main/java/org/hibernate/cfg/InheritanceState.java index 658c236ed7..aa98dd9d34 100644 --- a/annotations/src/main/java/org/hibernate/cfg/InheritanceState.java +++ b/annotations/src/main/java/org/hibernate/cfg/InheritanceState.java @@ -28,7 +28,6 @@ import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.MappedSuperclass; -import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.XAnnotatedElement; import org.hibernate.annotations.common.reflection.XClass; @@ -57,11 +56,6 @@ public class InheritanceState { private InheritanceType type; private boolean isEmbeddableSuperclass = false; - /** - * only defined on embedded superclasses - */ - private AccessType accessType = AccessType.DEFAULT; - private void extractInheritanceType() { XAnnotatedElement element = getClazz(); Inheritance inhAnn = element.getAnnotation( Inheritance.class ); @@ -84,8 +78,7 @@ public class InheritanceState { } public static InheritanceState getInheritanceStateOfSuperEntity( - XClass clazz, Map states, - ReflectionManager reflectionManager + XClass clazz, Map states ) { XClass superclass = clazz; do { @@ -95,14 +88,11 @@ public class InheritanceState { return currentState; } } - while ( superclass != null && !reflectionManager.equals( superclass, Object.class ) ); + while ( superclass != null && !Object.class.getName().equals( superclass.getName() ) ); return null; } - public static InheritanceState getSuperclassInheritanceState( - XClass clazz, Map states, - ReflectionManager reflectionManager - ) { + public static InheritanceState getSuperclassInheritanceState( XClass clazz, Map states) { XClass superclass = clazz; do { superclass = superclass.getSuperclass(); @@ -111,7 +101,7 @@ public class InheritanceState { return currentState; } } - while ( superclass != null && !reflectionManager.equals( superclass, Object.class ) ); + while ( superclass != null && !Object.class.getName().equals( superclass.getName() ) ); return null; } @@ -154,12 +144,4 @@ public class InheritanceState { public void setEmbeddableSuperclass(boolean embeddableSuperclass) { isEmbeddableSuperclass = embeddableSuperclass; } - - public AccessType getAccessType() { - return accessType; - } - - public void setAccessType(AccessType type) { - this.accessType = type; - } } diff --git a/annotations/src/main/java/org/hibernate/cfg/PropertyContainer.java b/annotations/src/main/java/org/hibernate/cfg/PropertyContainer.java index 32a7d0aefb..8b622d2a2b 100644 --- a/annotations/src/main/java/org/hibernate/cfg/PropertyContainer.java +++ b/annotations/src/main/java/org/hibernate/cfg/PropertyContainer.java @@ -45,38 +45,39 @@ import org.hibernate.annotations.Target; import org.hibernate.annotations.Type; import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XProperty; +import org.hibernate.util.StringHelper; /** + * A helper class to keep the {@code XProperty}s of a class ordered by access type. + * * @author Hardy Ferentschik */ - -/** - * A temporary class where we keep the {@code XProperty}s of a class ordered by access type. - */ class PropertyContainer { private static final Logger log = LoggerFactory.getLogger( AnnotationBinder.class ); private final TreeMap fieldAccessMap; private final TreeMap propertyAccessMap; private final XClass xClass; - private final AccessType defaultAccessType; + private final AccessType explicitClassDefinedAccessType; PropertyContainer(XClass clazz) { this.xClass = clazz; fieldAccessMap = initProperties( AccessType.FIELD ); propertyAccessMap = initProperties( AccessType.PROPERTY ); - defaultAccessType = determineClassDefinedAccessStrategy(); + explicitClassDefinedAccessType = determineClassDefinedAccessStrategy(); checkForJpaAccess(); - - } public XClass getXClass() { return xClass; } - public AccessType getDefaultAccessStrategy() { - return defaultAccessType; + public AccessType getExplicitAccessStrategy() { + return explicitClassDefinedAccessType; + } + + public boolean hasExplicitAccessStrategy() { + return !explicitClassDefinedAccessType.equals( AccessType.DEFAULT ); } public Collection getProperties(AccessType accessType) { @@ -88,6 +89,24 @@ class PropertyContainer { } } + public void assertTypesAreResolvable(AccessType access) { + TreeMap xprops; + if ( AccessType.PROPERTY.equals( access ) || AccessType.DEFAULT.equals( access ) ) { + xprops = propertyAccessMap; + } + else { + xprops = fieldAccessMap; + } + for ( XProperty property : xprops.values() ) { + if ( !property.isTypeResolved() && !discoverTypeWithoutReflection( property ) ) { + String msg = "Property " + StringHelper.qualify( xClass.getName(), property.getName() ) + + " has an unbound type and no explicit target entity. Resolve this Generic usage issue" + + " or set an explicit target attribute (eg @OneToMany(target=) or use an explicit @Type"; + throw new AnnotationException( msg ); + } + } + } + private void checkForJpaAccess() { List tmpList = new ArrayList(); for ( XProperty property : fieldAccessMap.values() ) { @@ -136,16 +155,10 @@ class PropertyContainer { TreeMap propertiesMap = new TreeMap(); List properties = xClass.getDeclaredProperties( access.getType() ); for ( XProperty property : properties ) { -// if ( !property.isTypeResolved() && !discoverTypeWithoutReflection( property ) -// && !mustBeSkipped( property ) ) { -// String msg = "Property " + StringHelper.qualify( xClass.getName(), property.getName() ) + -// " has an unbound type and no explicit target entity. Resolve this Generic usage issue" + -// " or set an explicit target attribute (eg @OneToMany(target=) or use an explicit @Type"; -// throw new AnnotationException( msg ); -// } - if ( !mustBeSkipped( property ) ) { - propertiesMap.put( property.getName(), property ); + if ( mustBeSkipped( property ) ) { + continue; } + propertiesMap.put( property.getName(), property ); } return propertiesMap; } diff --git a/annotations/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java b/annotations/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java index 5b198ae63e..88fec5b7a9 100644 --- a/annotations/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java +++ b/annotations/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java @@ -118,7 +118,7 @@ public class EntityBinder { private InheritanceState inheritanceState; private boolean ignoreIdAnnotations; private boolean cacheLazyProperty; - private AccessType propertyAccessor = AccessType.DEFAULT; + private AccessType propertyAccessType = AccessType.DEFAULT; /** * Use as a fake one for Collection of elements @@ -843,16 +843,28 @@ public class EntityBinder { } } - public AccessType getPropertyAccessor() { - return propertyAccessor; + public AccessType getPropertyAccessType() { + return propertyAccessType; } - public void setPropertyAccessor(AccessType propertyAccessor) { - this.propertyAccessor = propertyAccessor; + public void setPropertyAccessType(AccessType propertyAccessor) { + this.propertyAccessType = getExplicitAccessType( annotatedClass ); + // only set the access type if there is no explicit access type for this class + if( this.propertyAccessType == null ) { + this.propertyAccessType = propertyAccessor; + } } public AccessType getPropertyAccessor(XAnnotatedElement element) { - AccessType accessType = propertyAccessor; + AccessType accessType = getExplicitAccessType( element ); + if ( accessType == null ) { + accessType = propertyAccessType; + } + return accessType; + } + + public AccessType getExplicitAccessType(XAnnotatedElement element) { + AccessType accessType = null; AccessType hibernateAccessType = null; AccessType jpaAccessType = null; @@ -868,7 +880,9 @@ public class EntityBinder { } if ( hibernateAccessType != null && jpaAccessType != null && hibernateAccessType != jpaAccessType ) { - throw new MappingException( " " ); + throw new MappingException( + "Found @Access and @AccessType with conflicting values on a property in class " + annotatedClass.toString() + ); } if ( hibernateAccessType != null ) { diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/AccessMappingTest.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/AccessMappingTest.java index 580e4b2384..1d59a22e8d 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/AccessMappingTest.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/AccessMappingTest.java @@ -43,7 +43,7 @@ public class AccessMappingTest extends TestCase { public void testInconsistentAnnotationPlacement() throws Exception { AnnotationConfiguration cfg = new AnnotationConfiguration(); - cfg.addAnnotatedClass( Course.class ); + cfg.addAnnotatedClass( Course1.class ); cfg.addAnnotatedClass( Student.class ); try { cfg.buildSessionFactory(); @@ -56,7 +56,7 @@ public class AccessMappingTest extends TestCase { public void testFieldAnnotationPlacement() throws Exception { AnnotationConfiguration cfg = new AnnotationConfiguration(); - Class classUnderTest = CourseFieldAccess.class; + Class classUnderTest = Course6.class; cfg.addAnnotatedClass( classUnderTest ); cfg.addAnnotatedClass( Student.class ); SessionFactoryImplementor factory = ( SessionFactoryImplementor ) cfg.buildSessionFactory(); @@ -71,7 +71,7 @@ public class AccessMappingTest extends TestCase { public void testPropertyAnnotationPlacement() throws Exception { AnnotationConfiguration cfg = new AnnotationConfiguration(); - Class classUnderTest = CoursePropertyAccess.class; + Class classUnderTest = Course7.class; cfg.addAnnotatedClass( classUnderTest ); cfg.addAnnotatedClass( Student.class ); SessionFactoryImplementor factory = ( SessionFactoryImplementor ) cfg.buildSessionFactory(); @@ -86,7 +86,7 @@ public class AccessMappingTest extends TestCase { public void testExplicitPropertyAccessAnnotationsOnProperty() throws Exception { AnnotationConfiguration cfg = new AnnotationConfiguration(); - Class classUnderTest = CourseExplicitPropertyAccess.class; + Class classUnderTest = Course2.class; cfg.addAnnotatedClass( classUnderTest ); cfg.addAnnotatedClass( Student.class ); SessionFactoryImplementor factory = ( SessionFactoryImplementor ) cfg.buildSessionFactory(); @@ -101,7 +101,7 @@ public class AccessMappingTest extends TestCase { public void testExplicitPropertyAccessAnnotationsOnField() throws Exception { AnnotationConfiguration cfg = new AnnotationConfiguration(); - cfg.addAnnotatedClass( CourseExplicitPropertyAccess3.class ); + cfg.addAnnotatedClass( Course4.class ); cfg.addAnnotatedClass( Student.class ); try { cfg.buildSessionFactory(); @@ -114,7 +114,7 @@ public class AccessMappingTest extends TestCase { public void testExplicitPropertyAccessAnnotationsWithHibernateStyleOverride() throws Exception { AnnotationConfiguration cfg = new AnnotationConfiguration(); - Class classUnderTest = CourseExplicitPropertyAccess2.class; + Class classUnderTest = Course3.class; cfg.addAnnotatedClass( classUnderTest ); cfg.addAnnotatedClass( Student.class ); SessionFactoryImplementor factory = ( SessionFactoryImplementor ) cfg.buildSessionFactory(); @@ -134,7 +134,7 @@ public class AccessMappingTest extends TestCase { public void testExplicitPropertyAccessAnnotationsWithJpaStyleOverride() throws Exception { AnnotationConfiguration cfg = new AnnotationConfiguration(); - Class classUnderTest = CourseExplicitPropertyAccess4.class; + Class classUnderTest = Course5.class; cfg.addAnnotatedClass( classUnderTest ); cfg.addAnnotatedClass( Student.class ); SessionFactoryImplementor factory = ( SessionFactoryImplementor ) cfg.buildSessionFactory(); @@ -151,4 +151,43 @@ public class AccessMappingTest extends TestCase { tuplizer.getGetter( 0 ) instanceof BasicPropertyAccessor.BasicGetter ); } + + public void testDefaultFieldAccessIsInherited() throws Exception { + AnnotationConfiguration cfg = new AnnotationConfiguration(); + Class classUnderTest = User.class; + cfg.addAnnotatedClass( classUnderTest ); + cfg.addAnnotatedClass( Person.class ); + cfg.addAnnotatedClass( Being.class ); + SessionFactoryImplementor factory = ( SessionFactoryImplementor ) cfg.buildSessionFactory(); + EntityMetamodel metaModel = factory.getEntityPersister( classUnderTest.getName() ) + .getEntityMetamodel(); + PojoEntityTuplizer tuplizer = ( PojoEntityTuplizer ) metaModel.getTuplizer( EntityMode.POJO ); + assertTrue( + "Field access should be used since the default access mode gets inherited", + tuplizer.getIdentifierGetter() instanceof DirectPropertyAccessor.DirectGetter + ); + } + + public void testDefaultPropertyAccessIsInherited() throws Exception { + AnnotationConfiguration cfg = new AnnotationConfiguration(); + cfg.addAnnotatedClass( Horse.class ); + cfg.addAnnotatedClass( Animal.class ); + + SessionFactoryImplementor factory = ( SessionFactoryImplementor ) cfg.buildSessionFactory(); + EntityMetamodel metaModel = factory.getEntityPersister( Animal.class.getName() ) + .getEntityMetamodel(); + PojoEntityTuplizer tuplizer = ( PojoEntityTuplizer ) metaModel.getTuplizer( EntityMode.POJO ); + assertTrue( + "Property access should be used since explicity configured via @Access", + tuplizer.getIdentifierGetter() instanceof BasicPropertyAccessor.BasicGetter + ); + + metaModel = factory.getEntityPersister( Horse.class.getName() ) + .getEntityMetamodel(); + tuplizer = ( PojoEntityTuplizer ) metaModel.getTuplizer( EntityMode.POJO ); + assertTrue( + "Property access should be used since the default access mode gets inherited", + tuplizer.getGetter( 0 ) instanceof BasicPropertyAccessor.BasicGetter + ); + } } \ No newline at end of file diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/AccessTest.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/AccessTest.java index 77a40796c6..4eb354c61b 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/AccessTest.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/AccessTest.java @@ -54,10 +54,10 @@ public class AccessTest extends TestCase { tx.commit(); s.clear(); tx = s.beginTransaction(); - john = (User) s.get( User.class, john.getId() ); - assertEquals("Wrong number of friends", 1, john.getFriends().size() ); + john = ( User ) s.get( User.class, john.getId() ); + assertEquals( "Wrong number of friends", 1, john.getFriends().size() ); assertNull( john.firstname ); - + s.delete( john ); tx.commit(); s.close(); @@ -74,7 +74,7 @@ public class AccessTest extends TestCase { tx.commit(); s.clear(); tx = s.beginTransaction(); - fur = (Furniture) s.get( Furniture.class, fur.getId() ); + fur = ( Furniture ) s.get( Furniture.class, fur.getId() ); assertFalse( fur.isAlive ); assertNotNull( fur.getColor() ); s.delete( fur ); @@ -91,7 +91,7 @@ public class AccessTest extends TestCase { tx.commit(); s.clear(); tx = s.beginTransaction(); - fur = (Furniture) s.get( Furniture.class, fur.getId() ); + fur = ( Furniture ) s.get( Furniture.class, fur.getId() ); assertNotNull( fur.getGod() ); s.delete( fur ); tx.commit(); @@ -107,7 +107,7 @@ public class AccessTest extends TestCase { tx.commit(); s.clear(); tx = s.beginTransaction(); - fur = (Furniture) s.get( Furniture.class, fur.getId() ); + fur = ( Furniture ) s.get( Furniture.class, fur.getId() ); assertEquals( 5, fur.weight ); s.delete( fur ); tx.commit(); @@ -124,7 +124,7 @@ public class AccessTest extends TestCase { tx.commit(); s.clear(); tx = s.beginTransaction(); - chair = (Chair) s.get( Chair.class, chair.getId() ); + chair = ( Chair ) s.get( Chair.class, chair.getId() ); assertNull( chair.getPillow() ); s.delete( chair ); tx.commit(); @@ -142,7 +142,7 @@ public class AccessTest extends TestCase { tx.commit(); s.clear(); tx = s.beginTransaction(); - bed = (BigBed) s.get( BigBed.class, bed.getId() ); + bed = ( BigBed ) s.get( BigBed.class, bed.getId() ); assertEquals( 5, bed.size ); assertNull( bed.getQuality() ); s.delete( bed ); @@ -160,7 +160,7 @@ public class AccessTest extends TestCase { tx.commit(); s.clear(); tx = s.beginTransaction(); - gs = (Gardenshed) s.get( Gardenshed.class, gs.getId() ); + gs = ( Gardenshed ) s.get( Gardenshed.class, gs.getId() ); assertEquals( 4, gs.floors ); assertEquals( 6, gs.getFloors() ); s.delete( gs ); @@ -169,6 +169,29 @@ public class AccessTest extends TestCase { } + public void testEmbeddableUsesAccessStrategyOfContainingClass() throws Exception { + Circle circle = new Circle(); + Color color = new Color( 5, 10, 15 ); + circle.setColor( color ); + Session s = openSession(); + s.persist( circle ); + Transaction tx = s.beginTransaction(); + tx.commit(); + s.clear(); + tx = s.beginTransaction(); + circle = ( Circle ) s.get( Circle.class, circle.getId() ); + assertEquals( 5, circle.getColor().r ); + try { + circle.getColor().getR(); + fail(); + } catch (RuntimeException e) { + // success + } + s.delete( circle ); + tx.commit(); + s.close(); + } + protected Class[] getMappings() { return new Class[] { Bed.class, @@ -178,7 +201,10 @@ public class AccessTest extends TestCase { Gardenshed.class, Closet.class, Person.class, - User.class + User.class, + Shape.class, + Circle.class, + Color.class }; } } \ No newline at end of file diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Animal.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Animal.java new file mode 100644 index 0000000000..268930b25b --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Animal.java @@ -0,0 +1,53 @@ +//$Id$ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.test.annotations.access.jpa; + +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + + +/** + * @author Hardy Ferentschik + */ +@Entity +@Access(AccessType.FIELD) +public class Animal { + + private long id; + + @Access( AccessType.PROPERTY) + @Id + @GeneratedValue + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } +} \ No newline at end of file diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Circle.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Circle.java new file mode 100644 index 0000000000..7c1597c8f9 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Circle.java @@ -0,0 +1,49 @@ +//$Id: Being.java 18260 2009-12-17 21:14:07Z hardy.ferentschik $ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.test.annotations.access.jpa; + +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.Embedded; +import javax.persistence.Entity; + + +/** + * @author Hardy Ferentschik + */ +@Entity +@Access(AccessType.FIELD) +public class Circle extends Shape { + @Embedded + private Color color; + + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } +} \ No newline at end of file diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Color.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Color.java new file mode 100644 index 0000000000..97e3e5966a --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Color.java @@ -0,0 +1,71 @@ +//$Id: Being.java 18260 2009-12-17 21:14:07Z hardy.ferentschik $ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.test.annotations.access.jpa; + +import javax.persistence.Embeddable; + + +/** + * @author Hardy Ferentschik + */ +@Embeddable +public class Color { + public int r; + public int g; + public int b; + + public Color() { + } + + public Color(int r, int g, int b) { + this.r = r; + this.g = g; + this.b = b; + } + + public int getB() { + throw new RuntimeException(); + } + + public void setB(int b) { + this.b = b; + } + + public int getG() { + throw new RuntimeException(); + } + + public void setG(int g) { + this.g = g; + } + + public int getR() { + throw new RuntimeException(); + } + + public void setR(int r) { + this.r = r; + } +} \ No newline at end of file diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course1.java similarity index 98% rename from annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course.java rename to annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course1.java index a3d96cf8f4..fcf5138954 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course1.java @@ -36,7 +36,7 @@ import javax.persistence.OneToMany; * @author Hardy Ferentschik */ @Entity -public class Course { +public class Course1 { @Id @GeneratedValue private long id; diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course2.java similarity index 97% rename from annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess.java rename to annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course2.java index 2c48c80c66..d931e6602a 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course2.java @@ -39,7 +39,7 @@ import javax.persistence.OneToMany; */ @Entity @Access(AccessType.PROPERTY) -public class CourseExplicitPropertyAccess { +public class Course2 { private long id; private String title; diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess2.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course3.java similarity index 97% rename from annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess2.java rename to annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course3.java index d3e22ed982..d0f5046297 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess2.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course3.java @@ -39,7 +39,7 @@ import javax.persistence.OneToMany; */ @Entity @Access(AccessType.PROPERTY) -public class CourseExplicitPropertyAccess2 { +public class Course3 { private long id; private String title; diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess3.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course4.java similarity index 97% rename from annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess3.java rename to annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course4.java index b288e38cbb..030acbf1d0 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess3.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course4.java @@ -39,7 +39,7 @@ import javax.persistence.OneToMany; */ @Entity @Access(AccessType.PROPERTY) -public class CourseExplicitPropertyAccess3 { +public class Course4 { @Id @GeneratedValue private long id; diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess4.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course5.java similarity index 97% rename from annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess4.java rename to annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course5.java index 7a33476aa0..dee73d96f7 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess4.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course5.java @@ -38,7 +38,7 @@ import javax.persistence.ManyToMany; */ @Entity @Access(AccessType.PROPERTY) -public class CourseExplicitPropertyAccess4 { +public class Course5 { @Access(AccessType.FIELD) @Id diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseFieldAccess.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course6.java similarity index 98% rename from annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseFieldAccess.java rename to annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course6.java index ab99a815e0..f9897a888e 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseFieldAccess.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course6.java @@ -36,7 +36,7 @@ import javax.persistence.OneToMany; * @author Hardy Ferentschik */ @Entity -public class CourseFieldAccess { +public class Course6 { @Id @GeneratedValue private long id; diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CoursePropertyAccess.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course7.java similarity index 98% rename from annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CoursePropertyAccess.java rename to annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course7.java index 943aeaa8f4..4000efa43a 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CoursePropertyAccess.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course7.java @@ -36,7 +36,7 @@ import javax.persistence.OneToMany; * @author Hardy Ferentschik */ @Entity -public class CoursePropertyAccess { +public class Course7 { private long id; private String title; diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Furniture.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Furniture.java index 3e3c63d0cf..d9f9de8311 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Furniture.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Furniture.java @@ -1,4 +1,4 @@ -//$Id:$ +//$Id$ /* * Hibernate, Relational Persistence for Idiomatic Java * @@ -59,9 +59,9 @@ public class Furniture extends Woody { this.id = id; } - @Access(javax.persistence.AccessType.PROPERTY) public long weight; + @Access(javax.persistence.AccessType.PROPERTY) public long getWeight() { return weight + 1; } diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Horse.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Horse.java new file mode 100644 index 0000000000..db7340f252 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Horse.java @@ -0,0 +1,45 @@ +//$Id: Being.java 18260 2009-12-17 21:14:07Z hardy.ferentschik $ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.test.annotations.access.jpa; + +import javax.persistence.Entity; + + +/** + * @author Hardy Ferentschik + */ +@Entity +public class Horse extends Animal { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Shape.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Shape.java new file mode 100644 index 0000000000..512ec07e4f --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Shape.java @@ -0,0 +1,50 @@ +//$Id: Being.java 18260 2009-12-17 21:14:07Z hardy.ferentschik $ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC. + * + * 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.test.annotations.access.jpa; + +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + + +/** + * @author Hardy Ferentschik + */ +@Entity +public class Shape { + private long id; + + @Id + @GeneratedValue + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } +} \ No newline at end of file