diff --git a/annotations/src/main/java/org/hibernate/cfg/AccessType.java b/annotations/src/main/java/org/hibernate/cfg/AccessType.java new file mode 100644 index 0000000000..6b71db3932 --- /dev/null +++ b/annotations/src/main/java/org/hibernate/cfg/AccessType.java @@ -0,0 +1,85 @@ +// $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.cfg; + +/** + * Enum defining deifferent access strategies for accessing entity values. + * + * @author Hardy Ferentschik + */ +public enum AccessType { + /** + * Default access strategy is property + */ + DEFAULT( "property" ), + + /** + * Access to value via property + */ + PROPERTY( "property" ), + + /** + * Access to value via field + */ + FIELD( "field" ); + + private final String accessType; + + AccessType(String type) { + this.accessType = type; + } + + public String getType() { + return accessType; + } + + public static AccessType getAccessStrategy(String type) { + if ( type == null ) { + return DEFAULT; + } + else if ( FIELD.getType().equals( type ) ) { + return FIELD; + } + else if ( PROPERTY.getType().equals( type ) ) { + return PROPERTY; + } + else { + // TODO historically if the type string could not be matched default access was used. Maybe this should be an exception though!? + return DEFAULT; + } + } + + public static AccessType getAccessStrategy(javax.persistence.AccessType type) { + if ( javax.persistence.AccessType.PROPERTY.equals( type ) ) { + return PROPERTY; + } + else if ( javax.persistence.AccessType.FIELD.equals( type ) ) { + return FIELD; + } + else { + return DEFAULT; + } + } +} diff --git a/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java index 59294c7024..286c79e126 100644 --- a/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -1,3 +1,4 @@ +// $Id:$ /* * Hibernate, Relational Persistence for Idiomatic Java * @@ -24,8 +25,8 @@ package org.hibernate.cfg; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; +import java.util.Arrays; +import java.util.Collection; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; @@ -34,6 +35,7 @@ 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; @@ -68,7 +70,6 @@ import javax.persistence.SqlResultSetMapping; import javax.persistence.SqlResultSetMappings; import javax.persistence.Table; import javax.persistence.TableGenerator; -import javax.persistence.Transient; import javax.persistence.Version; import javax.persistence.ElementCollection; import javax.persistence.CollectionTable; @@ -83,7 +84,6 @@ import org.hibernate.AssertionFailure; import org.hibernate.EntityMode; import org.hibernate.FetchMode; import org.hibernate.MappingException; -import org.hibernate.annotations.AccessType; import org.hibernate.annotations.BatchSize; import org.hibernate.annotations.Cache; import org.hibernate.annotations.Cascade; @@ -116,10 +116,8 @@ import org.hibernate.annotations.Parameter; import org.hibernate.annotations.Parent; import org.hibernate.annotations.Proxy; import org.hibernate.annotations.Sort; -import org.hibernate.annotations.Target; import org.hibernate.annotations.Tuplizer; import org.hibernate.annotations.Tuplizers; -import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import org.hibernate.annotations.TypeDefs; import org.hibernate.annotations.Where; @@ -424,6 +422,11 @@ public final class AnnotationBinder { /** * Bind a class having JSR175 annotations * The subclasses have to be binded after its mother class + * + * @param clazzToProcess entity to bind as {@code XClass} instance + * @param inheritanceStatePerClass Meta data about the inheritance relationships for all mapped classes + * @param mappings Mapping meta data + * @throws MappingException in case there is an configuration error */ public static void bindClass( XClass clazzToProcess, Map inheritanceStatePerClass, ExtendedMappings mappings @@ -516,12 +519,12 @@ public final class AnnotationBinder { entityBinder.setWhere( whereAnn ); entityBinder.setCache( cacheAnn ); entityBinder.setInheritanceState( inheritanceState ); - + //Filters are not allowed on subclasses if ( !inheritanceState.hasParents() ) { bindFilters(clazzToProcess, entityBinder, mappings); } - + entityBinder.bindEntity(); if ( inheritanceState.hasTable() ) { @@ -621,7 +624,7 @@ public final class AnnotationBinder { // check properties List elements = getElementsToProcess( - persistentClass, clazzToProcess, inheritanceStatePerClass, propertyHolder, entityBinder, mappings + persistentClass, clazzToProcess, inheritanceStatePerClass, entityBinder, mappings ); if ( elements == null ) { throw new AnnotationException( "No identifier specified for entity: " + propertyHolder.getEntityName() ); @@ -650,8 +653,7 @@ public final class AnnotationBinder { if ( idClass != null ) { XClass compositeClass = mappings.getReflectionManager().toXClass( idClass.value() ); boolean isComponent = true; - boolean propertyAnnotated = entityBinder.isPropertyAnnotated( compositeClass ); - String propertyAccessor = entityBinder.getPropertyAccessor( compositeClass ); + AccessType propertyAccessor = entityBinder.getPropertyAccessor( compositeClass ); String generatorType = "assigned"; String generator = BinderHelper.ANNOTATION_STRING_DEFAULT; PropertyData inferredData = new PropertyPreloadedData( @@ -672,7 +674,6 @@ public final class AnnotationBinder { propertyHolder, localGenerators, isComponent, - propertyAnnotated, propertyAccessor, entityBinder, true, false, mappings, inheritanceStatePerClass @@ -684,7 +685,6 @@ public final class AnnotationBinder { propertyHolder, inferredData, baseInferredData, - propertyAnnotated, propertyAccessor, false, entityBinder, true, true, @@ -875,11 +875,11 @@ public final class AnnotationBinder { .getName() ); } - + return true; } - /** + /* * Get the annotated elements * Guess the annotated element from @Id or @EmbeddedId presence * Change EntityBinder by side effect @@ -887,9 +887,15 @@ public final class AnnotationBinder { private static List getElementsToProcess( PersistentClass persistentClass, XClass clazzToProcess, Map inheritanceStatePerClass, - PropertyHolder propertyHolder, EntityBinder entityBinder, ExtendedMappings mappings + EntityBinder entityBinder, ExtendedMappings mappings ) { InheritanceState inheritanceState = inheritanceStatePerClass.get( clazzToProcess ); + assert !inheritanceState.isEmbeddableSuperclass(); + + AccessType accessType = determineExplicitAccessType( + clazzToProcess, inheritanceStatePerClass, mappings, inheritanceState + ); + List classesToProcess = getMappedSuperclassesTillNextEntityOrdered( persistentClass, clazzToProcess, inheritanceStatePerClass, mappings ); @@ -897,53 +903,14 @@ public final class AnnotationBinder { int deep = classesToProcess.size(); boolean hasIdentifier = false; - assert !inheritanceState.isEmbeddableSuperclass(); - Boolean isExplicitPropertyAnnotated = null; - String explicitAccessType; - if ( inheritanceState.hasParents() ) { - InheritanceState superEntityState = - InheritanceState.getInheritanceStateOfSuperEntity( - clazzToProcess, inheritanceStatePerClass, mappings.getReflectionManager() - ); - isExplicitPropertyAnnotated = superEntityState != null ? - superEntityState.isPropertyAnnotated() : - null; - explicitAccessType = superEntityState != null ? - superEntityState.getAccessType() : - null; - } - else { - //the are the root entity but we might have mapped superclasses that contain the id class - AccessType access = clazzToProcess.getAnnotation( AccessType.class ); - explicitAccessType = access != null ? - access.value() : - null; - if ( "property".equals( explicitAccessType ) ) { - isExplicitPropertyAnnotated = Boolean.TRUE; - } - else if ( "field".equals( explicitAccessType ) ) { - isExplicitPropertyAnnotated = Boolean.FALSE; - } - } - Boolean isPropertyAnnotated = isExplicitPropertyAnnotated == null ? - Boolean.TRUE : - //default to property and fallback if needed - isExplicitPropertyAnnotated; - String accessType = explicitAccessType != null ? - explicitAccessType : - "property"; /* * delay the exception in case field access is used */ AnnotationException exceptionWhileWalkingElements = null; try { for (int index = 0; index < deep; index++) { - XClass clazz = classesToProcess.get( index ); - - boolean currentHasIdentifier = addElementsOfAClass( - elements, propertyHolder, isPropertyAnnotated, - accessType, clazz, mappings - ); + PropertyContainer properyContainer = new PropertyContainer( classesToProcess.get( index ) ); + boolean currentHasIdentifier = addElementsOfClass( elements, accessType , properyContainer, mappings ); hasIdentifier = hasIdentifier || currentHasIdentifier; } } @@ -952,43 +919,85 @@ public final class AnnotationBinder { } if ( !hasIdentifier && !inheritanceState.hasParents() ) { - if ( isExplicitPropertyAnnotated != null ) { + 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 } - isPropertyAnnotated = !isPropertyAnnotated; - accessType = "field"; + accessType = AccessType.FIELD; elements.clear(); for (int index = 0; index < deep; index++) { - XClass clazz = classesToProcess.get( index ); - boolean currentHasIdentifier = addElementsOfAClass( - elements, propertyHolder, isPropertyAnnotated, - accessType, clazz, mappings - ); + PropertyContainer properyContainer = new PropertyContainer( classesToProcess.get( index ) ); + boolean currentHasIdentifier = addElementsOfClass(elements, accessType, properyContainer, mappings ); hasIdentifier = hasIdentifier || currentHasIdentifier; } } - //the field show no id, fallback tot he original exception + //the field show no id, fallback to he original exception if (!hasIdentifier && exceptionWhileWalkingElements != null) throw exceptionWhileWalkingElements; - //TODO set the access type here? - entityBinder.setPropertyAnnotated( isPropertyAnnotated ); entityBinder.setPropertyAccessor( accessType ); - inheritanceState.setPropertyAnnotated( isPropertyAnnotated ); inheritanceState.setAccessType( accessType ); return hasIdentifier || inheritanceState.hasParents() ? elements : null; } + /* + * 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(); + } + } + 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; + } + private static List getMappedSuperclassesTillNextEntityOrdered( PersistentClass persistentClass, XClass annotatedClass, Map inheritanceStatePerClass, ExtendedMappings mappings ) { - + //ordered to allow proper messages on properties subclassing List classesToProcess = new ArrayList(); XClass currentClassInHierarchy = annotatedClass; @@ -1034,17 +1043,17 @@ public final class AnnotationBinder { } return classesToProcess; } - - /** - * Process the filters defined on the given class, as well as all filters defined - * on the MappedSuperclass(s) in the inheritance hierarchy + + /* + * Process the filters defined on the given class, as well as all filters defined + * on the MappedSuperclass(s) in the inheritance hierarchy */ - private static void bindFilters(XClass annotatedClass, EntityBinder entityBinder, + private static void bindFilters(XClass annotatedClass, EntityBinder entityBinder, ExtendedMappings mappings) { - + bindFilters(annotatedClass, entityBinder); - - XClass classToProcess = annotatedClass.getSuperclass(); + + XClass classToProcess = annotatedClass.getSuperclass(); while (classToProcess != null) { AnnotatedClassType classType = mappings.getClassType( classToProcess ); if ( AnnotatedClassType.EMBEDDABLE_SUPERCLASS.equals( classType ) ) { @@ -1052,24 +1061,24 @@ public final class AnnotationBinder { } classToProcess = classToProcess.getSuperclass(); } - + } - + private static void bindFilters(XAnnotatedElement annotatedElement, EntityBinder entityBinder) { - + Filters filtersAnn = annotatedElement.getAnnotation( Filters.class ); if ( filtersAnn != null ) { for (Filter filter : filtersAnn.value()) { entityBinder.addFilter( filter.name(), filter.condition() ); } } - + Filter filterAnn = annotatedElement.getAnnotation( Filter.class ); if ( filterAnn != null ) { entityBinder.addFilter( filterAnn.name(), filterAnn.condition() ); } } - + private static void bindFilterDefs(XAnnotatedElement annotatedElement, ExtendedMappings mappings) { FilterDef defAnn = annotatedElement.getAnnotation( FilterDef.class ); FilterDefs defsAnn = annotatedElement.getAnnotation( FilterDefs.class ); @@ -1111,13 +1120,13 @@ public final class AnnotationBinder { for (Parameter param : defAnn.parameters()) { params.setProperty( param.name(), param.value() ); } - + if (BinderHelper.isDefault(defAnn.name()) && defAnn.defaultForType().equals(void.class)) { throw new AnnotationException( - "Either name or defaultForType (or both) attribute should be set in TypeDef having typeClass " + + "Either name or defaultForType (or both) attribute should be set in TypeDef having typeClass " + defAnn.typeClass().getName()); } - + if (!BinderHelper.isDefault(defAnn.name())) { log.info( "Binding type definition: {}", defAnn.name() ); mappings.addTypeDef( defAnn.name(), defAnn.typeClass().getName(), params ); @@ -1126,10 +1135,10 @@ public final class AnnotationBinder { log.info( "Binding type definition: {}", defAnn.defaultForType().getName() ); mappings.addTypeDef( defAnn.defaultForType().getName(), defAnn.typeClass().getName(), params ); } - + } - - + + private static void bindDiscriminatorToPersistentClass( RootClass rootClass, Ejb3DiscriminatorColumn discriminatorColumn, Map secondaryTables, @@ -1151,95 +1160,35 @@ public final class AnnotationBinder { } /** - * Add elements of a class + * + * @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 + * strategy is used + * @param propertyContainer Metadata about a class and its properties + * @param mappings Mapping meta data + * @return {@code true} in case an id property was found while iterating the elements of {@code annoatedClass} using + * the determined access strategy, {@code false} otherwise. */ - private static boolean addElementsOfAClass( - List elements, PropertyHolder propertyHolder, boolean isPropertyAnnotated, - String propertyAccessor, final XClass annotatedClass, ExtendedMappings mappings + private static boolean addElementsOfClass( + List elements, AccessType propertyAccessor, PropertyContainer propertyContainer, ExtendedMappings mappings ) { boolean hasIdentifier = false; - AccessType access = annotatedClass.getAnnotation( AccessType.class ); - String localPropertyAccessor = access != null ? - access.value() : - null; - String accessType; - if ( "property".equals( localPropertyAccessor ) || "field".equals( localPropertyAccessor ) ) { - accessType = localPropertyAccessor; - } - else { - if ( localPropertyAccessor == null ) { - localPropertyAccessor = propertyAccessor; - } + AccessType classDefinedAccessType = propertyContainer.getDefaultAccessStrategy(); - if ( isPropertyAnnotated ) { - accessType = "property"; - } - else { - accessType = "field"; - } + if ( classDefinedAccessType.equals( AccessType.DEFAULT ) ) { + classDefinedAccessType = propertyAccessor; } - log.debug( "Processing {} {} annotation", propertyHolder.getEntityName(), accessType ); - List properties = annotatedClass.getDeclaredProperties( accessType ); - //order so that property are used in the same order when binding native query - Collections.sort( properties, new Comparator() { - public int compare(XProperty property1, XProperty property2) { - return property1.getName().compareTo( property2.getName() ); - } - } ); - for (XProperty p : properties) { - if ( !p.isTypeResolved() && !discoverTypeWithoutReflection( p ) && !mustBeSkipped( p, mappings ) ) { - throw new AnnotationException( - "Property " + StringHelper.qualify( propertyHolder.getEntityName(), p.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" - ); - } - final boolean currentHasIdentifier = addProperty( annotatedClass, p, elements, localPropertyAccessor, mappings ); + Collection properties = propertyContainer.getProperties( classDefinedAccessType ); + for ( XProperty p : properties ) { + final boolean currentHasIdentifier = addProperty( + propertyContainer.getXClass(), p, elements, classDefinedAccessType.getType(), mappings + ); hasIdentifier = hasIdentifier || currentHasIdentifier; } return hasIdentifier; } - private static boolean discoverTypeWithoutReflection(XProperty p) { - if ( p.isAnnotationPresent( OneToOne.class ) && !p.getAnnotation( OneToOne.class ) - .targetEntity() - .equals( void.class ) ) { - return true; - } - else if ( p.isAnnotationPresent( OneToMany.class ) && !p.getAnnotation( OneToMany.class ) - .targetEntity() - .equals( void.class ) ) { - return true; - } - else if ( p.isAnnotationPresent( ManyToOne.class ) && !p.getAnnotation( ManyToOne.class ) - .targetEntity() - .equals( void.class ) ) { - return true; - } - else if ( p.isAnnotationPresent( ManyToMany.class ) && !p.getAnnotation( ManyToMany.class ) - .targetEntity() - .equals( void.class ) ) { - return true; - } - else if ( p.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) { - return true; - } - else if ( p.isAnnotationPresent( ManyToAny.class ) ) { - if ( !p.isCollection() && !p.isArray() ) { - throw new AnnotationException( "@ManyToAny used on a non collection non array property: " + p.getName() ); - } - return true; - } - else if ( p.isAnnotationPresent( Type.class ) ) { - return true; - } - else if ( p.isAnnotationPresent( Target.class ) ) { - return true; - } - return false; - } - private static boolean addProperty( XClass declaringClass, XProperty property, List annElts, String propertyAccessor, ExtendedMappings mappings @@ -1248,32 +1197,25 @@ public final class AnnotationBinder { PropertyData propertyAnnotatedElement = new PropertyInferredData( declaringClass, property, propertyAccessor, mappings.getReflectionManager() ); - if ( !mustBeSkipped( propertyAnnotatedElement.getProperty(), mappings ) ) { - /* - * put element annotated by @Id in front - * since it has to be parsed before any association by Hibernate - */ - final XAnnotatedElement element = propertyAnnotatedElement.getProperty(); - if ( element.isAnnotationPresent( Id.class ) || element.isAnnotationPresent( EmbeddedId.class ) ) { - annElts.add( 0, propertyAnnotatedElement ); - hasIdentifier = true; - } - else { - annElts.add( propertyAnnotatedElement ); - hasIdentifier = false; - } + + /* + * put element annotated by @Id in front + * since it has to be parsed before any association by Hibernate + */ + final XAnnotatedElement element = propertyAnnotatedElement.getProperty(); + if ( element.isAnnotationPresent( Id.class ) || element.isAnnotationPresent( EmbeddedId.class ) ) { + annElts.add( 0, propertyAnnotatedElement ); + hasIdentifier = true; } + else { + annElts.add( propertyAnnotatedElement ); + hasIdentifier = false; + } + return hasIdentifier; } - private static boolean mustBeSkipped(XProperty property, ExtendedMappings mappings) { - //TODO make those hardcoded tests more portable (through the bytecode provider?) - return property.isAnnotationPresent( Transient.class ) - || "net.sf.cglib.transform.impl.InterceptFieldCallback".equals( property.getType().getName() ) - || "org.hibernate.bytecode.javassist.FieldHandler".equals( property.getType().getName() ); - } - - /** + /* * Process annotation of a particular property */ private static void processElementAnnotations( @@ -1434,9 +1376,7 @@ public final class AnnotationBinder { //guess if its a component and find id data access (property, field etc) final boolean isComponent = returnedClass.isAnnotationPresent( Embeddable.class ) || property.isAnnotationPresent( EmbeddedId.class ); - boolean propertyAnnotated = entityBinder.isPropertyAnnotated( returnedClass ); - String propertyAccessor = entityBinder.getPropertyAccessor( returnedClass ); - //if ( isComponent && embeddableAnn != null && embeddableAnn.access() == AccessType.FIELD ) propertyAccess = false; + AccessType propertyAccessor = entityBinder.getPropertyAccessor( returnedClass ); GeneratedValue generatedValue = property.getAnnotation( GeneratedValue.class ); String generatorType = generatedValue != null ? @@ -1446,7 +1386,7 @@ public final class AnnotationBinder { generatedValue.generator() : BinderHelper.ANNOTATION_STRING_DEFAULT; if ( isComponent ) generatorType = "assigned"; //a component must not have any generator - + bindId( generatorType, generator, @@ -1455,14 +1395,13 @@ public final class AnnotationBinder { propertyHolder, localGenerators, isComponent, - propertyAnnotated, propertyAccessor, entityBinder, false, isIdentifierMapper, mappings, inheritanceStatePerClass ); - + log.debug( "Bind {} on {}", ( isComponent ? "@EmbeddedId" : "@Id" ), inferredData.getPropertyName() ); @@ -1491,7 +1430,7 @@ public final class AnnotationBinder { propBinder.setName( inferredData.getPropertyName() ); propBinder.setReturnedClassName( inferredData.getTypeName() ); propBinder.setLazy( false ); - propBinder.setPropertyAccessorName( inferredData.getDefaultAccess() ); + propBinder.setAccessType( inferredData.getDefaultAccess() ); propBinder.setColumns( columns ); propBinder.setHolder( propertyHolder ); //PropertyHolderBuilder.buildPropertyHolder(rootClass) propBinder.setProperty( property ); @@ -1515,7 +1454,7 @@ public final class AnnotationBinder { //we know the property is on the actual entity rootClass.setDeclaredVersion( prop ); } - + SimpleValue simpleValue = (SimpleValue) prop.getValue(); simpleValue.setNullValue( "undefined" ); rootClass.setOptimisticLockMode( Versioning.OPTIMISTIC_LOCK_VERSION ); @@ -1630,7 +1569,7 @@ public final class AnnotationBinder { if ( property.isAnnotationPresent( OrderColumn.class ) ) { indexColumn = IndexColumn.buildColumnFromAnnotation( - property.getAnnotation(OrderColumn.class), + property.getAnnotation(OrderColumn.class), propertyHolder, inferredData, entityBinder.getSecondaryTables(), @@ -1673,7 +1612,7 @@ public final class AnnotationBinder { collectionBinder.setIgnoreNotFound( ignoreNotFound ); collectionBinder.setCollectionType( inferredData.getProperty().getElementClass() ); collectionBinder.setMappings( mappings ); - collectionBinder.setPropertyAccessorName( inferredData.getDefaultAccess() ); + collectionBinder.setAccessType( inferredData.getDefaultAccess() ); Ejb3Column[] elementColumns; PropertyData virtualProperty = new WrappedInferredData( inferredData, "element" ); @@ -1732,7 +1671,7 @@ public final class AnnotationBinder { //nullify empty array keyColumns = keyColumns != null && keyColumns.length > 0 ? keyColumns : null; - + PropertyData mapKeyVirtualProperty = new WrappedInferredData( inferredData, "mapkey" ); Ejb3Column[] mapColumns = Ejb3Column.buildColumnFromAnnotation( keyColumns, @@ -1887,13 +1826,9 @@ public final class AnnotationBinder { isComponent = embeddedAnn != null || embeddableAnn != null; if ( isComponent ) { - //process component object - //boolean propertyAccess = true; - //if ( embeddableAnn != null && embeddableAnn.access() == AccessType.FIELD ) propertyAccess = false; - boolean propertyAnnotated = entityBinder.isPropertyAnnotated( property ); - String propertyAccessor = entityBinder.getPropertyAccessor( property ); + AccessType propertyAccessor = entityBinder.getPropertyAccessor( property ); bindComponent( - inferredData, propertyHolder, propertyAnnotated, propertyAccessor, entityBinder, + inferredData, propertyHolder, propertyAccessor, entityBinder, isIdentifierMapper, mappings, isComponentEmbedded, inheritanceStatePerClass ); @@ -1919,7 +1854,7 @@ public final class AnnotationBinder { propBinder.setName( inferredData.getPropertyName() ); propBinder.setReturnedClassName( inferredData.getTypeName() ); propBinder.setLazy( lazy ); - propBinder.setPropertyAccessorName( inferredData.getDefaultAccess() ); + propBinder.setAccessType( inferredData.getDefaultAccess() ); propBinder.setColumns( columns ); propBinder.setHolder( propertyHolder ); propBinder.setProperty( property ); @@ -1938,7 +1873,7 @@ public final class AnnotationBinder { Index index = property.getAnnotation( Index.class ); if ( index != null ) { if ( joinColumns != null ) { - + for (Ejb3Column column : joinColumns) { column.addIndex( index, inSecondPass ); } @@ -2038,14 +1973,13 @@ public final class AnnotationBinder { private static void bindComponent( PropertyData inferredData, PropertyHolder propertyHolder, - boolean propertyAnnotated, - String propertyAccessor, EntityBinder entityBinder, + AccessType propertyAccessor, EntityBinder entityBinder, boolean isIdentifierMapper, ExtendedMappings mappings, boolean isComponentEmbedded, Map inheritanceStatePerClass ) { Component comp = fillComponent( - propertyHolder, inferredData, propertyAnnotated, propertyAccessor, true, entityBinder, + propertyHolder, inferredData, propertyAccessor, true, entityBinder, isComponentEmbedded, isIdentifierMapper, false, mappings, inheritanceStatePerClass ); @@ -2056,32 +1990,31 @@ public final class AnnotationBinder { binder.setName( inferredData.getPropertyName() ); binder.setValue( comp ); binder.setProperty( inferredData.getProperty() ); - binder.setPropertyAccessorName( inferredData.getDefaultAccess() ); + binder.setAccessType( inferredData.getDefaultAccess() ); Property prop = binder.make(); propertyHolder.addProperty( prop, inferredData.getDeclaringClass() ); } public static Component fillComponent( PropertyHolder propertyHolder, PropertyData inferredData, - boolean propertyAnnotated, String propertyAccessor, boolean isNullable, + AccessType propertyAccessor, boolean isNullable, EntityBinder entityBinder, boolean isComponentEmbedded, boolean isIdentifierMapper, boolean inSecondPass, ExtendedMappings mappings, Map inheritanceStatePerClass ) { - - return fillComponent(propertyHolder, inferredData, null, propertyAnnotated, propertyAccessor, + + return fillComponent(propertyHolder, inferredData, null, propertyAccessor, isNullable, entityBinder, isComponentEmbedded, isIdentifierMapper, inSecondPass, mappings, inheritanceStatePerClass); } - + public static Component fillComponent( PropertyHolder propertyHolder, PropertyData inferredData, PropertyData baseInferredData, - boolean propertyAnnotated, String propertyAccessor, boolean isNullable, - EntityBinder entityBinder, + AccessType propertyAccessor, boolean isNullable, EntityBinder entityBinder, boolean isComponentEmbedded, boolean isIdentifierMapper, boolean inSecondPass, ExtendedMappings mappings, Map inheritanceStatePerClass ) { - + /** * inSecondPass can only be used to apply right away the second pass of a composite-element * Because it's a value type, there is no bidirectional association, hence second pass @@ -2104,48 +2037,33 @@ public final class AnnotationBinder { comp, subpath, inferredData, propertyHolder, mappings ); - + List classElements = new ArrayList(); XClass returnedClassOrElement = inferredData.getClassOrElement(); - + List baseClassElements = null; XClass baseReturnedClassOrElement; PropertyHolder baseSubHolder; if(baseInferredData != null) { - baseSubHolder = PropertyHolderBuilder.buildPropertyHolder( - comp, subpath, - inferredData, propertyHolder, mappings - ); baseClassElements = new ArrayList(); baseReturnedClassOrElement = baseInferredData.getClassOrElement(); bindTypeDefs(baseReturnedClassOrElement, mappings); - addElementsOfAClass( - baseClassElements, - baseSubHolder, - propertyAnnotated, - propertyAccessor, baseReturnedClassOrElement, mappings - ); + PropertyContainer propContainer = new PropertyContainer( baseReturnedClassOrElement ); + addElementsOfClass( baseClassElements, propertyAccessor, propContainer, mappings ); } //embeddable elements can have type defs bindTypeDefs(returnedClassOrElement, mappings); - addElementsOfAClass( - classElements, - subHolder, - propertyAnnotated, - propertyAccessor, returnedClassOrElement, mappings - ); + PropertyContainer propContainer = new PropertyContainer( returnedClassOrElement ); + addElementsOfClass( classElements, propertyAccessor, propContainer, mappings); + //add elements of the embeddable superclass XClass superClass = inferredData.getPropertyClass().getSuperclass(); while ( superClass != null && superClass.isAnnotationPresent( MappedSuperclass.class ) ) { //FIXME: proper support of typevariables incl var resolved at upper levels - addElementsOfAClass( - classElements, - subHolder, - entityBinder.isPropertyAnnotated( superClass ), - propertyAccessor, superClass, mappings - ); + propContainer = new PropertyContainer( superClass ); + addElementsOfClass( classElements, propertyAccessor, propContainer, mappings ); superClass = superClass.getSuperclass(); } if ( baseClassElements != null ) { @@ -2173,28 +2091,26 @@ public final class AnnotationBinder { PropertyData inferredData, Ejb3Column[] columns, PropertyHolder propertyHolder, Map localGenerators, boolean isComposite, - boolean isPropertyAnnotated, - String propertyAccessor, EntityBinder entityBinder, boolean isEmbedded, + AccessType propertyAccessor, EntityBinder entityBinder, boolean isEmbedded, boolean isIdentifierMapper, ExtendedMappings mappings, Map inheritanceStatePerClass ) { - + bindId(generatorType, generatorName, inferredData, null, columns, propertyHolder, - localGenerators, isComposite, isPropertyAnnotated, propertyAccessor, entityBinder, + localGenerators, isComposite, propertyAccessor, entityBinder, isEmbedded, isIdentifierMapper, mappings, inheritanceStatePerClass); } - + private static void bindId( String generatorType, String generatorName, PropertyData inferredData, PropertyData baseInferredData, Ejb3Column[] columns, PropertyHolder propertyHolder, Map localGenerators, boolean isComposite, - boolean isPropertyAnnotated, - String propertyAccessor, EntityBinder entityBinder, boolean isEmbedded, + AccessType propertyAccessor, EntityBinder entityBinder, boolean isEmbedded, boolean isIdentifierMapper, ExtendedMappings mappings, Map inheritanceStatePerClass ) { - + /* * Fill simple value and property since and Id is a property */ @@ -2210,7 +2126,7 @@ public final class AnnotationBinder { SimpleValue id; if ( isComposite ) { id = fillComponent( - propertyHolder, inferredData, baseInferredData, isPropertyAnnotated, propertyAccessor, + propertyHolder, inferredData, baseInferredData, propertyAccessor, false, entityBinder, isEmbedded, isIdentifierMapper, false, mappings, inheritanceStatePerClass ); Component componentId = (Component) id; @@ -2247,7 +2163,7 @@ public final class AnnotationBinder { PropertyBinder binder = new PropertyBinder(); binder.setName( inferredData.getPropertyName() ); binder.setValue( id ); - binder.setPropertyAccessorName( inferredData.getDefaultAccess() ); + binder.setAccessType( inferredData.getDefaultAccess() ); binder.setProperty( inferredData.getProperty() ); Property prop = binder.make(); rootClass.setIdentifierProperty( prop ); @@ -2345,7 +2261,7 @@ public final class AnnotationBinder { binder.setInsertable( columns[0].isInsertable() ); binder.setUpdatable( columns[0].isUpdatable() ); } - binder.setPropertyAccessorName( inferredData.getDefaultAccess() ); + binder.setAccessType( inferredData.getDefaultAccess() ); binder.setCascade( cascadeStrategy ); binder.setProperty(inferredData.getProperty()); Property prop = binder.make(); @@ -2496,7 +2412,7 @@ public final class AnnotationBinder { binder.setInsertable( columns[0].isInsertable() ); binder.setUpdatable( columns[0].isUpdatable() ); } - binder.setPropertyAccessorName( inferredData.getDefaultAccess() ); + binder.setAccessType( inferredData.getDefaultAccess() ); binder.setCascade( cascadeStrategy ); Property prop = binder.make(); //composite FK columns are in the same table so its OK @@ -2556,15 +2472,12 @@ public final class AnnotationBinder { hibernateCascadeAnnotation.value(); if ( hibernateCascades != null && hibernateCascades.length > 0 ) { - for (CascadeType cascadeType : hibernateCascades) { - hibernateCascadeSet.add( cascadeType ); - } + hibernateCascadeSet.addAll( Arrays.asList( hibernateCascades ) ); } StringBuilder cascade = new StringBuilder(); - Iterator cascadeType = hibernateCascadeSet.iterator(); - while ( cascadeType.hasNext() ) { - switch ( cascadeType.next() ) { + for ( CascadeType aHibernateCascadeSet : hibernateCascadeSet ) { + switch ( aHibernateCascadeSet ) { case ALL: cascade.append( "," ).append( "all" ); break; diff --git a/annotations/src/main/java/org/hibernate/cfg/InheritanceState.java b/annotations/src/main/java/org/hibernate/cfg/InheritanceState.java index 65cbfd03f4..658c236ed7 100644 --- a/annotations/src/main/java/org/hibernate/cfg/InheritanceState.java +++ b/annotations/src/main/java/org/hibernate/cfg/InheritanceState.java @@ -60,8 +60,7 @@ public class InheritanceState { /** * only defined on embedded superclasses */ - private String accessType = null; - private Boolean isPropertyAnnotated; + private AccessType accessType = AccessType.DEFAULT; private void extractInheritanceType() { XAnnotatedElement element = getClazz(); @@ -108,7 +107,9 @@ public class InheritanceState { do { superclass = superclass.getSuperclass(); InheritanceState currentState = states.get( superclass ); - if ( currentState != null ) return currentState; + if ( currentState != null ) { + return currentState; + } } while ( superclass != null && !reflectionManager.equals( superclass, Object.class ) ); return null; @@ -154,19 +155,11 @@ public class InheritanceState { isEmbeddableSuperclass = embeddableSuperclass; } - public String getAccessType() { + public AccessType getAccessType() { return accessType; } - public void setAccessType(String accessType) { - this.accessType = accessType; - } - - public Boolean isPropertyAnnotated() { - return isPropertyAnnotated; - } - - public void setPropertyAnnotated(Boolean propertyAnnotated) { - isPropertyAnnotated = propertyAnnotated; + public void setAccessType(AccessType type) { + this.accessType = type; } } diff --git a/annotations/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java b/annotations/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java index fab43d0245..032e282e2f 100644 --- a/annotations/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java +++ b/annotations/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java @@ -111,7 +111,7 @@ public class OneToOneSecondPass implements SecondPass { binder.setName( propertyName ); binder.setValue( value ); binder.setCascade( cascadeStrategy ); - binder.setPropertyAccessorName( inferredData.getDefaultAccess() ); + binder.setAccessType( inferredData.getDefaultAccess() ); Property prop = binder.make(); if ( BinderHelper.isDefault( mappedBy ) ) { /* diff --git a/annotations/src/main/java/org/hibernate/cfg/PropertyContainer.java b/annotations/src/main/java/org/hibernate/cfg/PropertyContainer.java new file mode 100644 index 0000000000..32a7d0aefb --- /dev/null +++ b/annotations/src/main/java/org/hibernate/cfg/PropertyContainer.java @@ -0,0 +1,233 @@ +// $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.cfg; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.TreeMap; +import javax.persistence.Access; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.Transient; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.hibernate.AnnotationException; +import org.hibernate.MappingException; +import org.hibernate.annotations.ManyToAny; +import org.hibernate.annotations.Target; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.common.reflection.XClass; +import org.hibernate.annotations.common.reflection.XProperty; + +/** + * @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; + + PropertyContainer(XClass clazz) { + this.xClass = clazz; + fieldAccessMap = initProperties( AccessType.FIELD ); + propertyAccessMap = initProperties( AccessType.PROPERTY ); + defaultAccessType = determineClassDefinedAccessStrategy(); + checkForJpaAccess(); + + + } + + public XClass getXClass() { + return xClass; + } + + public AccessType getDefaultAccessStrategy() { + return defaultAccessType; + } + + public Collection getProperties(AccessType accessType) { + if ( AccessType.DEFAULT == accessType || AccessType.PROPERTY == accessType ) { + return propertyAccessMap.values(); + } + else { + return fieldAccessMap.values(); + } + } + + private void checkForJpaAccess() { + List tmpList = new ArrayList(); + for ( XProperty property : fieldAccessMap.values() ) { + Access access = property.getAnnotation( Access.class ); + if ( access == null ) { + continue; + } + + AccessType accessType = AccessType.getAccessStrategy( access.value() ); + if ( accessType == AccessType.PROPERTY ) { + log.warn( "Placing @Access(AccessType.PROPERTY) on a field does not have any effect." ); + continue; + } + + tmpList.add( property ); + } + for ( XProperty property : tmpList ) { + fieldAccessMap.remove( property.getName() ); + propertyAccessMap.put( property.getName(), property ); + } + + + tmpList.clear(); + for ( XProperty property : propertyAccessMap.values() ) { + Access access = property.getAnnotation( Access.class ); + if ( access == null ) { + continue; + } + + AccessType accessType = AccessType.getAccessStrategy( access.value() ); + if ( accessType == AccessType.FIELD ) { + log.warn( "Placing @Access(AccessType.FIELD) on a field does not have any effect." ); + continue; + } + + tmpList.add( property ); + } + for ( XProperty property : tmpList ) { + propertyAccessMap.remove( property.getName() ); + fieldAccessMap.put( property.getName(), property ); + } + } + + private TreeMap initProperties(AccessType access) { + //order so that property are used in the same order when binding native query + 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 ); + } + } + return propertiesMap; + } + + private AccessType determineClassDefinedAccessStrategy() { + AccessType classDefinedAccessType; + + AccessType hibernateDefinedAccessType = AccessType.DEFAULT; + AccessType jpaDefinedAccessType = AccessType.DEFAULT; + + org.hibernate.annotations.AccessType accessType = xClass.getAnnotation( org.hibernate.annotations.AccessType.class ); + if ( accessType != null ) { + hibernateDefinedAccessType = AccessType.getAccessStrategy( accessType.value() ); + } + + Access access = xClass.getAnnotation( Access.class ); + if ( access != null ) { + jpaDefinedAccessType = AccessType.getAccessStrategy( access.value() ); + } + + if ( hibernateDefinedAccessType != AccessType.DEFAULT + && jpaDefinedAccessType != AccessType.DEFAULT + && hibernateDefinedAccessType != jpaDefinedAccessType ) { + throw new MappingException( + "@AccessType and @Access specified with contradicting values. Use of @Access only is recommended. " + ); + } + + if ( hibernateDefinedAccessType != AccessType.DEFAULT ) { + classDefinedAccessType = hibernateDefinedAccessType; + } + else { + classDefinedAccessType = jpaDefinedAccessType; + } + return classDefinedAccessType; + } + + private static boolean discoverTypeWithoutReflection(XProperty p) { + if ( p.isAnnotationPresent( OneToOne.class ) && !p.getAnnotation( OneToOne.class ) + .targetEntity() + .equals( void.class ) ) { + return true; + } + else if ( p.isAnnotationPresent( OneToMany.class ) && !p.getAnnotation( OneToMany.class ) + .targetEntity() + .equals( void.class ) ) { + return true; + } + else if ( p.isAnnotationPresent( ManyToOne.class ) && !p.getAnnotation( ManyToOne.class ) + .targetEntity() + .equals( void.class ) ) { + return true; + } + else if ( p.isAnnotationPresent( ManyToMany.class ) && !p.getAnnotation( ManyToMany.class ) + .targetEntity() + .equals( void.class ) ) { + return true; + } + else if ( p.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) { + return true; + } + else if ( p.isAnnotationPresent( ManyToAny.class ) ) { + if ( !p.isCollection() && !p.isArray() ) { + throw new AnnotationException( "@ManyToAny used on a non collection non array property: " + p.getName() ); + } + return true; + } + else if ( p.isAnnotationPresent( Type.class ) ) { + return true; + } + else if ( p.isAnnotationPresent( Target.class ) ) { + return true; + } + return false; + } + + private static boolean mustBeSkipped(XProperty property) { + //TODO make those hardcoded tests more portable (through the bytecode provider?) + return property.isAnnotationPresent( Transient.class ) + || "net.sf.cglib.transform.impl.InterceptFieldCallback".equals( property.getType().getName() ) + || "org.hibernate.bytecode.javassist.FieldHandler".equals( property.getType().getName() ); + } +} + + diff --git a/annotations/src/main/java/org/hibernate/cfg/PropertyData.java b/annotations/src/main/java/org/hibernate/cfg/PropertyData.java index b4a628c6d2..2dde2ca5e0 100644 --- a/annotations/src/main/java/org/hibernate/cfg/PropertyData.java +++ b/annotations/src/main/java/org/hibernate/cfg/PropertyData.java @@ -33,7 +33,7 @@ public interface PropertyData { * @return default member access (whether field or property) * @throws MappingException No getter or field found or wrong JavaBean spec usage */ - String getDefaultAccess(); + AccessType getDefaultAccess(); /** * @return property name diff --git a/annotations/src/main/java/org/hibernate/cfg/PropertyInferredData.java b/annotations/src/main/java/org/hibernate/cfg/PropertyInferredData.java index b9e2132f42..d1bb6a59fa 100644 --- a/annotations/src/main/java/org/hibernate/cfg/PropertyInferredData.java +++ b/annotations/src/main/java/org/hibernate/cfg/PropertyInferredData.java @@ -23,8 +23,9 @@ */ package org.hibernate.cfg; +import javax.persistence.Access; + import org.hibernate.MappingException; -import org.hibernate.annotations.AccessType; import org.hibernate.annotations.Target; import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.XClass; @@ -37,7 +38,7 @@ import org.hibernate.annotations.common.reflection.XProperty; * @author Paolo Perrotta */ public class PropertyInferredData implements PropertyData { - private final String defaultAccess; + private final AccessType defaultAccess; private final XProperty property; private final ReflectionManager reflectionManager; @@ -50,15 +51,45 @@ public class PropertyInferredData implements PropertyData { public PropertyInferredData(XClass declaringClass, XProperty property, String propertyAccessor, ReflectionManager reflectionManager) { this.declaringClass = declaringClass; this.property = property; - this.defaultAccess = propertyAccessor; + this.defaultAccess = AccessType.getAccessStrategy( propertyAccessor ); this.reflectionManager = reflectionManager; } - public String getDefaultAccess() throws MappingException { - // if(skip()) - // return defaultAccess; - AccessType access = property.getAnnotation( AccessType.class ); - return access != null ? access.value() : defaultAccess; + public AccessType getDefaultAccess() throws MappingException { + AccessType accessType = defaultAccess; + + AccessType hibernateAccessType = AccessType.DEFAULT; + AccessType jpaAccessType = AccessType.DEFAULT; + + org.hibernate.annotations.AccessType accessTypeAnnotation = property.getAnnotation( org.hibernate.annotations.AccessType.class ); + if ( accessTypeAnnotation != null ) { + hibernateAccessType = AccessType.getAccessStrategy( accessTypeAnnotation.value() ); + } + + Access access = property.getAnnotation( Access.class ); + if ( access != null ) { + jpaAccessType = AccessType.getAccessStrategy( access.value() ); + } + + if ( hibernateAccessType != AccessType.DEFAULT + && jpaAccessType != AccessType.DEFAULT + && hibernateAccessType != jpaAccessType ) { + + StringBuilder builder = new StringBuilder(); + builder.append( property.toString() ); + builder.append( + " defines @AccessType and @Access with contradicting values. Use of @Access only is recommended." + ); + throw new MappingException( builder.toString() ); + } + + if ( hibernateAccessType != AccessType.DEFAULT ) { + accessType = hibernateAccessType; + } + else if ( jpaAccessType != AccessType.DEFAULT ) { + accessType = jpaAccessType; + } + return accessType; } public String getPropertyName() throws MappingException { diff --git a/annotations/src/main/java/org/hibernate/cfg/PropertyPreloadedData.java b/annotations/src/main/java/org/hibernate/cfg/PropertyPreloadedData.java index cafa7aa650..1121a34be0 100644 --- a/annotations/src/main/java/org/hibernate/cfg/PropertyPreloadedData.java +++ b/annotations/src/main/java/org/hibernate/cfg/PropertyPreloadedData.java @@ -28,19 +28,19 @@ import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XProperty; public class PropertyPreloadedData implements PropertyData { - private final String defaultAccess; + private final AccessType defaultAccess; private final String propertyName; private final XClass returnedClass; - public PropertyPreloadedData(String defaultAccess, String propertyName, XClass returnedClass) { + public PropertyPreloadedData(AccessType defaultAccess, String propertyName, XClass returnedClass) { this.defaultAccess = defaultAccess; this.propertyName = propertyName; this.returnedClass = returnedClass; } - public String getDefaultAccess() throws MappingException { + public AccessType getDefaultAccess() throws MappingException { return defaultAccess; } diff --git a/annotations/src/main/java/org/hibernate/cfg/WrappedInferredData.java b/annotations/src/main/java/org/hibernate/cfg/WrappedInferredData.java index 4ff3e6d90f..82ae148637 100644 --- a/annotations/src/main/java/org/hibernate/cfg/WrappedInferredData.java +++ b/annotations/src/main/java/org/hibernate/cfg/WrappedInferredData.java @@ -43,7 +43,7 @@ public class WrappedInferredData implements PropertyData { return wrappedInferredData.getClassOrElementName(); } - public String getDefaultAccess() { + public AccessType getDefaultAccess() { return wrappedInferredData.getDefaultAccess(); } diff --git a/annotations/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java b/annotations/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java index 094f39fdb9..aa871c4bde 100644 --- a/annotations/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java +++ b/annotations/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java @@ -76,6 +76,7 @@ import org.hibernate.annotations.WhereJoinTable; import org.hibernate.annotations.common.AssertionFailure; import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XProperty; +import org.hibernate.cfg.AccessType; import org.hibernate.cfg.AnnotatedClassType; import org.hibernate.cfg.AnnotationBinder; import org.hibernate.cfg.BinderHelper; @@ -157,6 +158,7 @@ public abstract class CollectionBinder { protected Map inheritanceStatePerClass; private XClass declaringClass; private boolean declaringClassSet; + private AccessType accessType; public void setUpdatable(boolean updatable) { this.updatable = updatable; @@ -170,17 +172,14 @@ public abstract class CollectionBinder { this.insertable = insertable; } - public void setCascadeStrategy(String cascadeStrategy) { this.cascadeStrategy = cascadeStrategy; } - public void setPropertyAccessorName(String propertyAccessorName) { - this.propertyAccessorName = propertyAccessorName; + public void setAccessType(AccessType accessType) { + this.accessType = accessType; } - private String propertyAccessorName; - public void setInverseJoinColumns(Ejb3JoinColumn[] inverseJoinColumns) { this.inverseJoinColumns = inverseJoinColumns; } @@ -491,7 +490,7 @@ public abstract class CollectionBinder { if ( cascadeStrategy != null && cascadeStrategy.indexOf( "delete-orphan" ) >= 0 ) { collection.setOrphanDelete( true ); } - binder.setPropertyAccessorName( propertyAccessorName ); + binder.setAccessType( accessType ); binder.setProperty( property ); binder.setInsertable( insertable ); binder.setUpdatable( updatable ); @@ -1296,11 +1295,10 @@ public abstract class CollectionBinder { throw new AssertionFailure( "Unable to guess collection property accessor name" ); } - //boolean propertyAccess = embeddable == null || AccessType.PROPERTY.equals( embeddable.access() ); - PropertyData inferredData = new PropertyPreloadedData( "property", "element", elementClass ); + PropertyData inferredData = new PropertyPreloadedData( AccessType.PROPERTY, "element", elementClass ); //TODO be smart with isNullable Component component = AnnotationBinder.fillComponent( - holder, inferredData, isPropertyAnnotated, isPropertyAnnotated ? "property" : "field", true, + holder, inferredData, isPropertyAnnotated ? AccessType.PROPERTY : AccessType.FIELD, true, entityBinder, false, false, true, mappings, inheritanceStatePerClass ); 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 248b10a718..5b198ae63e 100644 --- a/annotations/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java +++ b/annotations/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import javax.persistence.Access; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; @@ -38,7 +39,6 @@ import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.EntityMode; import org.hibernate.MappingException; -import org.hibernate.annotations.AccessType; import org.hibernate.annotations.BatchSize; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; @@ -60,6 +60,7 @@ import org.hibernate.annotations.Tuplizers; import org.hibernate.annotations.Where; import org.hibernate.annotations.common.reflection.XAnnotatedElement; import org.hibernate.annotations.common.reflection.XClass; +import org.hibernate.cfg.AccessType; import org.hibernate.cfg.AnnotationBinder; import org.hibernate.cfg.BinderHelper; import org.hibernate.cfg.Ejb3JoinColumn; @@ -99,7 +100,6 @@ public class EntityBinder { private ExtendedMappings mappings; private Logger log = LoggerFactory.getLogger( EntityBinder.class ); private String discriminatorValue = ""; - private boolean isPropertyAnnotated = false; private boolean dynamicInsert; private boolean dynamicUpdate; private boolean explicitHibernateEntityAnnotation; @@ -118,11 +118,7 @@ public class EntityBinder { private InheritanceState inheritanceState; private boolean ignoreIdAnnotations; private boolean cacheLazyProperty; - private String propertyAccessor; - - public boolean isPropertyAnnotated() { - return isPropertyAnnotated; - } + private AccessType propertyAccessor = AccessType.DEFAULT; /** * Use as a fake one for Collection of elements @@ -847,36 +843,41 @@ public class EntityBinder { } } - public void setPropertyAnnotated(boolean propertyAnnotated) { - this.isPropertyAnnotated = propertyAnnotated; - } - - public String getPropertyAccessor() { + public AccessType getPropertyAccessor() { return propertyAccessor; } - public void setPropertyAccessor(String propertyAccessor) { + public void setPropertyAccessor(AccessType propertyAccessor) { this.propertyAccessor = propertyAccessor; } - public boolean isPropertyAnnotated(XAnnotatedElement element) { - AccessType access = element.getAnnotation( AccessType.class ); - if ( access == null ) return isPropertyAnnotated; - String propertyAccessor = access.value(); - if ( "property".equals( propertyAccessor ) ) { - return Boolean.TRUE; - } - else if ( "field".equals( propertyAccessor ) ) { - return Boolean.FALSE; - } - else { - return isPropertyAnnotated; - } - } + public AccessType getPropertyAccessor(XAnnotatedElement element) { + AccessType accessType = propertyAccessor; - public String getPropertyAccessor(XAnnotatedElement element) { - AccessType access = element.getAnnotation( AccessType.class ); - if ( access == null ) return propertyAccessor; - return access.value(); + AccessType hibernateAccessType = null; + AccessType jpaAccessType = null; + + org.hibernate.annotations.AccessType accessTypeAnnotation = element.getAnnotation( org.hibernate.annotations.AccessType.class ); + if ( accessTypeAnnotation != null ) { + hibernateAccessType = AccessType.getAccessStrategy( accessTypeAnnotation.value() ); + } + + Access access = element.getAnnotation( Access.class ); + if ( access != null ) { + jpaAccessType = AccessType.getAccessStrategy( access.value() ); + } + + if ( hibernateAccessType != null && jpaAccessType != null && hibernateAccessType != jpaAccessType ) { + throw new MappingException( " " ); + } + + if ( hibernateAccessType != null ) { + accessType = hibernateAccessType; + } + else if ( jpaAccessType != null ) { + accessType = jpaAccessType; + } + + return accessType; } } diff --git a/annotations/src/main/java/org/hibernate/cfg/annotations/MapBinder.java b/annotations/src/main/java/org/hibernate/cfg/annotations/MapBinder.java index 786e06713c..0e674cdaa1 100644 --- a/annotations/src/main/java/org/hibernate/cfg/annotations/MapBinder.java +++ b/annotations/src/main/java/org/hibernate/cfg/annotations/MapBinder.java @@ -39,6 +39,7 @@ import org.hibernate.annotations.MapKey; import org.hibernate.annotations.MapKeyManyToMany; import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XProperty; +import org.hibernate.cfg.AccessType; import org.hibernate.cfg.AnnotatedClassType; import org.hibernate.cfg.AnnotationBinder; import org.hibernate.cfg.BinderHelper; @@ -227,10 +228,10 @@ public class MapBinder extends CollectionBinder { //boolean propertyAccess = embeddable == null || AccessType.PROPERTY.equals( embeddable.access() ); //FIXME "index" is it right? - PropertyData inferredData = new PropertyPreloadedData( "property", "index", elementClass ); + PropertyData inferredData = new PropertyPreloadedData( AccessType.PROPERTY, "index", elementClass ); //TODO be smart with isNullable Component component = AnnotationBinder.fillComponent( - holder, inferredData, isPropertyAnnotated, isPropertyAnnotated ? "property" : "field", true, + holder, inferredData, isPropertyAnnotated ? AccessType.PROPERTY : AccessType.FIELD, true, entityBinder, false, false, true, mappings, inheritanceStatePerClass ); diff --git a/annotations/src/main/java/org/hibernate/cfg/annotations/PropertyBinder.java b/annotations/src/main/java/org/hibernate/cfg/annotations/PropertyBinder.java index 2439600cb5..343ee96283 100644 --- a/annotations/src/main/java/org/hibernate/cfg/annotations/PropertyBinder.java +++ b/annotations/src/main/java/org/hibernate/cfg/annotations/PropertyBinder.java @@ -35,6 +35,7 @@ import org.hibernate.annotations.OptimisticLock; import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.annotations.common.AssertionFailure; +import org.hibernate.cfg.AccessType; import org.hibernate.cfg.Ejb3Column; import org.hibernate.cfg.ExtendedMappings; import org.hibernate.cfg.PropertyHolder; @@ -54,7 +55,7 @@ public class PropertyBinder { private String name; private String returnedClassName; private boolean lazy; - private String propertyAccessorName; + private AccessType accessType; private Ejb3Column[] columns; private PropertyHolder holder; private ExtendedMappings mappings; @@ -94,8 +95,8 @@ public class PropertyBinder { this.lazy = lazy; } - public void setPropertyAccessorName(String propertyAccessorName) { - this.propertyAccessorName = propertyAccessorName; + public void setAccessType(AccessType accessType) { + this.accessType = accessType; } public void setColumns(Ejb3Column[] columns) { @@ -170,7 +171,7 @@ public class PropertyBinder { prop.setValue( value ); prop.setLazy( lazy ); prop.setCascade( cascade ); - prop.setPropertyAccessorName( propertyAccessorName ); + prop.setPropertyAccessorName( accessType.getType() ); Generated ann = property != null ? property.getAnnotation( Generated.class ) : null; @@ -231,5 +232,5 @@ public class PropertyBinder { public SimpleValueBinder getSimpleValueBinder() { return simpleValueBinder; } - + } diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/Closet.java b/annotations/src/test/java/org/hibernate/test/annotations/access/Closet.java new file mode 100644 index 0000000000..5f4ad09b69 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/Closet.java @@ -0,0 +1,30 @@ +// $Id:$ +/* +* JBoss, Home of Professional Open Source +* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors +* by the @authors tag. See the copyright.txt in the distribution for a +* full listing of individual contributors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package org.hibernate.test.annotations.access; + +import javax.persistence.Embeddable; + +/** + * @author Hardy Ferentschik + */ +@Embeddable +public class Closet extends Furniture { + int numberOfDoors; +} + + diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/Foobar.java b/annotations/src/test/java/org/hibernate/test/annotations/access/Foobar.java new file mode 100644 index 0000000000..1a7e29dd0f --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/Foobar.java @@ -0,0 +1,31 @@ +// $Id:$ +/* +* JBoss, Home of Professional Open Source +* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors +* by the @authors tag. See the copyright.txt in the distribution for a +* full listing of individual contributors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package org.hibernate.test.annotations.access; + +import javax.persistence.Entity; + + +/** + * @author Hardy Ferentschik + */ +@Entity +public class Foobar { + String foo; +} + + 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 new file mode 100644 index 0000000000..580e4b2384 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/AccessMappingTest.java @@ -0,0 +1,154 @@ +//$Id: AccessTest.java 15025 2008-08-11 09:14:39Z 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 junit.framework.TestCase; + +import org.hibernate.EntityMode; +import org.hibernate.MappingException; +import org.hibernate.cfg.AnnotationConfiguration; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.property.BasicPropertyAccessor; +import org.hibernate.property.DirectPropertyAccessor; +import org.hibernate.tuple.entity.EntityMetamodel; +import org.hibernate.tuple.entity.PojoEntityTuplizer; + + +/** + * @author Hardy Ferentschik + */ +public class AccessMappingTest extends TestCase { + + public void testInconsistentAnnotationPlacement() throws Exception { + AnnotationConfiguration cfg = new AnnotationConfiguration(); + cfg.addAnnotatedClass( Course.class ); + cfg.addAnnotatedClass( Student.class ); + try { + cfg.buildSessionFactory(); + fail( "@Id and @OneToMany are not placed consistently in test entities. SessionFactory creation should fail." ); + } + catch ( MappingException e ) { + // success + } + } + + public void testFieldAnnotationPlacement() throws Exception { + AnnotationConfiguration cfg = new AnnotationConfiguration(); + Class classUnderTest = CourseFieldAccess.class; + cfg.addAnnotatedClass( classUnderTest ); + cfg.addAnnotatedClass( Student.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.", + tuplizer.getIdentifierGetter() instanceof DirectPropertyAccessor.DirectGetter + ); + } + + public void testPropertyAnnotationPlacement() throws Exception { + AnnotationConfiguration cfg = new AnnotationConfiguration(); + Class classUnderTest = CoursePropertyAccess.class; + cfg.addAnnotatedClass( classUnderTest ); + cfg.addAnnotatedClass( Student.class ); + SessionFactoryImplementor factory = ( SessionFactoryImplementor ) cfg.buildSessionFactory(); + EntityMetamodel metaModel = factory.getEntityPersister( classUnderTest.getName() ) + .getEntityMetamodel(); + PojoEntityTuplizer tuplizer = ( PojoEntityTuplizer ) metaModel.getTuplizer( EntityMode.POJO ); + assertTrue( + "Property access should be used.", + tuplizer.getIdentifierGetter() instanceof BasicPropertyAccessor.BasicGetter + ); + } + + public void testExplicitPropertyAccessAnnotationsOnProperty() throws Exception { + AnnotationConfiguration cfg = new AnnotationConfiguration(); + Class classUnderTest = CourseExplicitPropertyAccess.class; + cfg.addAnnotatedClass( classUnderTest ); + cfg.addAnnotatedClass( Student.class ); + SessionFactoryImplementor factory = ( SessionFactoryImplementor ) cfg.buildSessionFactory(); + EntityMetamodel metaModel = factory.getEntityPersister( classUnderTest.getName() ) + .getEntityMetamodel(); + PojoEntityTuplizer tuplizer = ( PojoEntityTuplizer ) metaModel.getTuplizer( EntityMode.POJO ); + assertTrue( + "Property access should be used.", + tuplizer.getIdentifierGetter() instanceof BasicPropertyAccessor.BasicGetter + ); + } + + public void testExplicitPropertyAccessAnnotationsOnField() throws Exception { + AnnotationConfiguration cfg = new AnnotationConfiguration(); + cfg.addAnnotatedClass( CourseExplicitPropertyAccess3.class ); + cfg.addAnnotatedClass( Student.class ); + try { + cfg.buildSessionFactory(); + fail( "@Id and @OneToMany are not placed consistently in test entities. SessionFactory creation should fail." ); + } + catch ( MappingException e ) { + // success + } + } + + public void testExplicitPropertyAccessAnnotationsWithHibernateStyleOverride() throws Exception { + AnnotationConfiguration cfg = new AnnotationConfiguration(); + Class classUnderTest = CourseExplicitPropertyAccess2.class; + cfg.addAnnotatedClass( classUnderTest ); + cfg.addAnnotatedClass( Student.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.", + tuplizer.getIdentifierGetter() instanceof DirectPropertyAccessor.DirectGetter + ); + + assertTrue( + "Property access should be used.", + tuplizer.getGetter( 0 ) instanceof BasicPropertyAccessor.BasicGetter + ); + } + + public void testExplicitPropertyAccessAnnotationsWithJpaStyleOverride() throws Exception { + AnnotationConfiguration cfg = new AnnotationConfiguration(); + Class classUnderTest = CourseExplicitPropertyAccess4.class; + cfg.addAnnotatedClass( classUnderTest ); + cfg.addAnnotatedClass( Student.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.", + tuplizer.getIdentifierGetter() instanceof DirectPropertyAccessor.DirectGetter + ); + + assertTrue( + "Property access should be used.", + 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 new file mode 100644 index 0000000000..77a40796c6 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/AccessTest.java @@ -0,0 +1,184 @@ +//$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 java.util.ArrayList; +import java.util.List; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.test.annotations.TestCase; +import org.hibernate.test.annotations.access.Closet; + +/** + * @author Emmanuel Bernard + */ +public class AccessTest extends TestCase { + + public void testDefaultConfigurationModeIsInherited() throws Exception { + User john = new User(); + john.setFirstname( "John" ); + john.setLastname( "Doe" ); + List friends = new ArrayList(); + User friend = new User(); + friend.setFirstname( "Jane" ); + friend.setLastname( "Doe" ); + friends.add( friend ); + john.setFriends( friends ); + + Session s = openSession(); + s.persist( john ); + Transaction tx = s.beginTransaction(); + tx.commit(); + s.clear(); + tx = s.beginTransaction(); + 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(); + } + + public void testSuperclassOverriding() throws Exception { + Furniture fur = new Furniture(); + fur.setColor( "Black" ); + fur.setName( "Beech" ); + fur.isAlive = true; + Session s = openSession(); + s.persist( fur ); + Transaction tx = s.beginTransaction(); + tx.commit(); + s.clear(); + tx = s.beginTransaction(); + fur = (Furniture) s.get( Furniture.class, fur.getId() ); + assertFalse( fur.isAlive ); + assertNotNull( fur.getColor() ); + s.delete( fur ); + tx.commit(); + s.close(); + } + + public void testSuperclassNonOverriding() throws Exception { + Furniture fur = new Furniture(); + fur.setGod( "Buddha" ); + Session s = openSession(); + s.persist( fur ); + Transaction tx = s.beginTransaction(); + tx.commit(); + s.clear(); + tx = s.beginTransaction(); + fur = (Furniture) s.get( Furniture.class, fur.getId() ); + assertNotNull( fur.getGod() ); + s.delete( fur ); + tx.commit(); + s.close(); + } + + public void testPropertyOverriding() throws Exception { + Furniture fur = new Furniture(); + fur.weight = 3; + Session s = openSession(); + s.persist( fur ); + Transaction tx = s.beginTransaction(); + tx.commit(); + s.clear(); + tx = s.beginTransaction(); + fur = (Furniture) s.get( Furniture.class, fur.getId() ); + assertEquals( 5, fur.weight ); + s.delete( fur ); + tx.commit(); + s.close(); + + } + + public void testNonOverridenSubclass() throws Exception { + Chair chair = new Chair(); + chair.setPillow( "Blue" ); + Session s = openSession(); + s.persist( chair ); + Transaction tx = s.beginTransaction(); + tx.commit(); + s.clear(); + tx = s.beginTransaction(); + chair = (Chair) s.get( Chair.class, chair.getId() ); + assertNull( chair.getPillow() ); + s.delete( chair ); + tx.commit(); + s.close(); + + } + + public void testOverridenSubclass() throws Exception { + BigBed bed = new BigBed(); + bed.size = 5; + bed.setQuality( "good" ); + Session s = openSession(); + s.persist( bed ); + Transaction tx = s.beginTransaction(); + tx.commit(); + s.clear(); + tx = s.beginTransaction(); + bed = (BigBed) s.get( BigBed.class, bed.getId() ); + assertEquals( 5, bed.size ); + assertNull( bed.getQuality() ); + s.delete( bed ); + tx.commit(); + s.close(); + + } + + public void testFieldsOverriding() throws Exception { + Gardenshed gs = new Gardenshed(); + gs.floors = 4; + Session s = openSession(); + s.persist( gs ); + Transaction tx = s.beginTransaction(); + tx.commit(); + s.clear(); + tx = s.beginTransaction(); + gs = (Gardenshed) s.get( Gardenshed.class, gs.getId() ); + assertEquals( 4, gs.floors ); + assertEquals( 6, gs.getFloors() ); + s.delete( gs ); + tx.commit(); + s.close(); + + } + + protected Class[] getMappings() { + return new Class[] { + Bed.class, + Chair.class, + Furniture.class, + BigBed.class, + Gardenshed.class, + Closet.class, + Person.class, + User.class + }; + } +} \ No newline at end of file diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Bed.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Bed.java new file mode 100644 index 0000000000..a85d219de3 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Bed.java @@ -0,0 +1,49 @@ +//$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.Transient; + + +/** + * @author Emmanuel Bernard + */ +@Entity +@Access(AccessType.PROPERTY) +public class Bed extends Furniture { + String quality; + + @Transient + public String getQuality() { + return quality; + } + + public void setQuality(String quality) { + this.quality = quality; + } +} \ No newline at end of file diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Being.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Being.java new file mode 100644 index 0000000000..f8d3d4964a --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Being.java @@ -0,0 +1,49 @@ +//$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.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author Hardy Ferentschik + */ +@Entity +public class Being { + @Id + @GeneratedValue + private long id; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } +} + + diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/BigBed.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/BigBed.java new file mode 100644 index 0000000000..a142f9811a --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/BigBed.java @@ -0,0 +1,37 @@ +//$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.Column; +import javax.persistence.Entity; + +/** + * @author Emmanuel Bernard + */ +@Entity +public class BigBed extends Bed { + @Column(name = "bed_size") + public int size; +} \ No newline at end of file diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Chair.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Chair.java new file mode 100644 index 0000000000..c420d7048c --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Chair.java @@ -0,0 +1,46 @@ +//$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.Entity; +import javax.persistence.Transient; + +/** + * @author Emmanuel Bernard + */ +@Entity +public class Chair extends Furniture { + + @Transient + private String pillow; + + public String getPillow() { + return pillow; + } + + public void setPillow(String pillow) { + this.pillow = pillow; + } +} \ 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/Course.java new file mode 100644 index 0000000000..a3d96cf8f4 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Course.java @@ -0,0 +1,74 @@ +//$Id: AccessTest.java 15025 2008-08-11 09:14:39Z 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 java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; + + +/** + * @author Hardy Ferentschik + */ +@Entity +public class Course { + @Id + @GeneratedValue + private long id; + + private String title; + + private List students; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + @OneToMany(cascade = CascadeType.ALL) + public List getStudents() { + return students; + } + + public void setStudents(List students) { + this.students = students; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} + + 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/CourseExplicitPropertyAccess.java new file mode 100644 index 0000000000..2c48c80c66 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess.java @@ -0,0 +1,75 @@ +//$Id: AccessTest.java 15025 2008-08-11 09:14:39Z 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 java.util.List; +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; + + +/** + * @author Hardy Ferentschik + */ +@Entity +@Access(AccessType.PROPERTY) +public class CourseExplicitPropertyAccess { + private long id; + + private String title; + + private List students; + + @Id + @GeneratedValue + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + @OneToMany(cascade = CascadeType.ALL) + public List getStudents() { + return students; + } + + public void setStudents(List students) { + this.students = students; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} \ No newline at end of file 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/CourseExplicitPropertyAccess2.java new file mode 100644 index 0000000000..d3e22ed982 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess2.java @@ -0,0 +1,77 @@ +//$Id: AccessTest.java 15025 2008-08-11 09:14:39Z 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 java.util.List; +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; + + +/** + * @author Hardy Ferentschik + */ +@Entity +@Access(AccessType.PROPERTY) +public class CourseExplicitPropertyAccess2 { + private long id; + + private String title; + + + private List students; + + @Id + @GeneratedValue + @org.hibernate.annotations.AccessType("field") + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + @OneToMany(cascade = CascadeType.ALL) + public List getStudents() { + return students; + } + + public void setStudents(List students) { + this.students = students; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} \ No newline at end of file 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/CourseExplicitPropertyAccess3.java new file mode 100644 index 0000000000..b288e38cbb --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess3.java @@ -0,0 +1,75 @@ +//$Id: AccessTest.java 15025 2008-08-11 09:14:39Z 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 java.util.List; +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; + + +/** + * @author Hardy Ferentschik + */ +@Entity +@Access(AccessType.PROPERTY) +public class CourseExplicitPropertyAccess3 { + @Id + @GeneratedValue + private long id; + + private String title; + + @OneToMany(cascade = CascadeType.ALL) + private List students; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public List getStudents() { + return students; + } + + public void setStudents(List students) { + this.students = students; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} \ No newline at end of file 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/CourseExplicitPropertyAccess4.java new file mode 100644 index 0000000000..7a33476aa0 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseExplicitPropertyAccess4.java @@ -0,0 +1,77 @@ +//$Id: AccessTest.java 15025 2008-08-11 09:14:39Z 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 java.util.List; +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToMany; + + +/** + * @author Hardy Ferentschik + */ +@Entity +@Access(AccessType.PROPERTY) +public class CourseExplicitPropertyAccess4 { + + @Access(AccessType.FIELD) + @Id + @GeneratedValue + private long id; + + private String title; + + private List students; + + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + @ManyToMany + public List getStudents() { + return students; + } + + public void setStudents(List students) { + this.students = students; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} \ No newline at end of file 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/CourseFieldAccess.java new file mode 100644 index 0000000000..ab99a815e0 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CourseFieldAccess.java @@ -0,0 +1,72 @@ +//$Id: AccessTest.java 15025 2008-08-11 09:14:39Z 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 java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; + + +/** + * @author Hardy Ferentschik + */ +@Entity +public class CourseFieldAccess { + @Id + @GeneratedValue + private long id; + + private String title; + + @OneToMany(cascade = CascadeType.ALL) + private List students; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public List getStudents() { + return students; + } + + public void setStudents(List students) { + this.students = students; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} \ No newline at end of file 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/CoursePropertyAccess.java new file mode 100644 index 0000000000..943aeaa8f4 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/CoursePropertyAccess.java @@ -0,0 +1,72 @@ +//$Id: AccessTest.java 15025 2008-08-11 09:14:39Z 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 java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; + + +/** + * @author Hardy Ferentschik + */ +@Entity +public class CoursePropertyAccess { + private long id; + + private String title; + + private List students; + + @Id + @GeneratedValue + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + @OneToMany(cascade = CascadeType.ALL) + public List getStudents() { + return students; + } + + public void setStudents(List students) { + this.students = students; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} \ No newline at end of file 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 new file mode 100644 index 0000000000..3e3c63d0cf --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Furniture.java @@ -0,0 +1,72 @@ +//$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.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Transient; + +/** + * @author Emmanuel Bernard + */ +@Entity +@Access(javax.persistence.AccessType.FIELD) +public class Furniture extends Woody { + @Id + @GeneratedValue + private Integer id; + + private String brand; + + @Transient + public String getBrand() { + return brand; + } + + public void setBrand(String brand) { + this.brand = brand; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + @Access(javax.persistence.AccessType.PROPERTY) + public long weight; + + public long getWeight() { + return weight + 1; + } + + public void setWeight(long weight) { + this.weight = weight + 1; + } +} \ No newline at end of file diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Gardenshed.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Gardenshed.java new file mode 100644 index 0000000000..b3a1fd1911 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Gardenshed.java @@ -0,0 +1,78 @@ +//$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.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Transient; + +/** + * This is the opposite of the Furniture test, as this tries to override the class AccessType("property") with + * the property AccessType("field"). + * + * @author Dennis Fleurbaaij + * @since 2007-05-31 + */ +@Entity +@Access(javax.persistence.AccessType.PROPERTY) +public class Gardenshed + extends + Woody { + private Integer id; + private String brand; + public long floors; + + @Transient + public String getBrand() { + return brand; + } + + public void setBrand(String brand) { + this.brand = brand; + } + + @Id + @GeneratedValue + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + // These 2 functions should not return in Hibernate, but the value should come from the field "floors" + + @Access(javax.persistence.AccessType.FIELD) + public long getFloors() { + return this.floors + 2; + } + + public void setFloors(long floors) { + this.floors = floors + 2; + } +} \ No newline at end of file diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Person.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Person.java new file mode 100644 index 0000000000..bb6e1d3c5d --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Person.java @@ -0,0 +1,60 @@ +//$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.Entity; + + +/** + * @author Hardy Ferentschik + */ +@Entity +// explicitly override the access type to be property (default is field, see Being) +@Access(javax.persistence.AccessType.PROPERTY) +public class Person extends Being { + + String firstname; + + private String lastname; + + public String getFirstname() { + return null; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } +} + + diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Student.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Student.java new file mode 100644 index 0000000000..ad4216a841 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Student.java @@ -0,0 +1,59 @@ +//$Id: AccessTest.java 15025 2008-08-11 09:14:39Z 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; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author Hardy Ferentschik + */ +@Entity +public class Student { + @Id + @GeneratedValue + private long id; + + private String name; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} + + diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Thingy.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Thingy.java new file mode 100644 index 0000000000..33a296b267 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Thingy.java @@ -0,0 +1,45 @@ +//$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.MappedSuperclass; +import javax.persistence.Transient; + +/** + * @author Emmanuel Bernard + */ +@MappedSuperclass +public class Thingy { + private String god; + + @Transient + public String getGod() { + return god; + } + + public void setGod(String god) { + this.god = god; + } +} \ No newline at end of file diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/User.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/User.java new file mode 100644 index 0000000000..4af84a7c21 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/User.java @@ -0,0 +1,48 @@ +//$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 java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.OneToMany; + +/** + * @author Hardy Ferentschik + */ +@Entity +public class User extends Person { + + @OneToMany(cascade = CascadeType.ALL) + private List friends; + + public List getFriends() { + return friends; + } + + public void setFriends(List friends) { + this.friends = friends; + } +} \ No newline at end of file diff --git a/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Woody.java b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Woody.java new file mode 100644 index 0000000000..5e8f1a4b5c --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/access/jpa/Woody.java @@ -0,0 +1,55 @@ +//$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.MappedSuperclass; + +/** + * @author Emmanuel Bernard + */ +@MappedSuperclass +@Access(javax.persistence.AccessType.PROPERTY) +public class Woody extends Thingy { + private String color; + private String name; + public boolean isAlive; //shouldn't be persistent + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file