HHH-7628: Modified ConfiguredClass to also process @AccessType annotations

This commit is contained in:
John Verhaeg 2012-09-20 08:20:44 -05:00
parent 07405e0f00
commit 78060d8eac
4 changed files with 83 additions and 86 deletions

View File

@ -1596,18 +1596,33 @@ public interface CoreMessageLogger extends BasicLogger {
)
void tooManyInExpressions(String dialectName, int limit, String paramName, int size);
// moved from hibernate-entitymanager ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@LogMessage( level = ERROR )
@Message( value = "Illegal argument on static metamodel field injection : %s#%s; expected type : %s; encountered type : %s", id = 15007 )
@Message( value = "Illegal argument on static metamodel field injection : %s#%s; expected type : %s; encountered type : %s", id = 448 )
void illegalArgumentOnStaticMetamodelFieldInjection( String metamodelClassName,
String attributeName,
String attributeJavaType,
String metamodelFieldJavaType );
@LogMessage( level = ERROR )
@Message( value = "Unable to locate static metamodel field : %s#%s", id = 15011 )
@Message( value = "Unable to locate static metamodel field : %s#%s", id = 449 )
void unableToLocateStaticMetamodelField( String metamodelClassName,
String attributeName );
@Message(value = "The access type of class %s is AccessType.FIELD. To override the access for an attribute " +
"@Access has to be placed on the property (getter)", id = 450)
String accessTypeOverrideShouldBeAnnotatedOnProperty( String className );
@Message(value = "The access type of class %s is AccessType.FIELD. To override the access for an attribute " +
"@Access has to be placed on the property (getter) with an access type of AccessType.PROPERTY. " +
"Using AccessType.FIELD on the property has no effect", id = 451)
String accessTypeOverrideShouldBeProperty( String className );
@Message(value = "The access type of class %s is AccessType.PROPERTY. To override the access for a field " +
"@Access has to be placed on the field ", id = 452)
String accessTypeOverrideShouldBeAnnotatedOnField( String className );
@Message(value = "The access type of class %s is AccessType.PROPERTY. To override the access for a field " +
"@Access has to be placed on the field with an access type of AccessType.FIELD. " +
"Using AccessType.PROPERTY on the field has no effect", id = 453)
String accessTypeOverrideShouldBeField( String className );
}

View File

@ -27,7 +27,6 @@ import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
@ -37,23 +36,14 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import javax.persistence.AccessType;
import com.fasterxml.classmate.ResolvedTypeWithMembers;
import com.fasterxml.classmate.members.HierarchicType;
import com.fasterxml.classmate.members.ResolvedMember;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.MethodInfo;
import org.jboss.logging.Logger;
import javax.persistence.AccessType;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.metamodel.internal.source.annotations.AnnotationBindingContext;
import org.hibernate.metamodel.internal.source.annotations.attribute.AssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.AttributeOverride;
@ -66,6 +56,17 @@ import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper;
import org.hibernate.metamodel.internal.source.annotations.util.ReflectionHelper;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.source.MappingException;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.MethodInfo;
import org.jboss.logging.Logger;
import com.fasterxml.classmate.ResolvedTypeWithMembers;
import com.fasterxml.classmate.members.HierarchicType;
import com.fasterxml.classmate.members.ResolvedMember;
/**
* Base class for a configured entity, mapped super class or embeddable
@ -73,7 +74,7 @@ import org.hibernate.metamodel.spi.source.MappingException;
* @author Hardy Ferentschik
*/
public class ConfiguredClass {
public static final Logger LOG = Logger.getLogger( ConfiguredClass.class.getName() );
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, AssertionFailure.class.getName());
/**
* The parent of this configured class or {@code null} in case this configured class is the root of a hierarchy.
@ -233,8 +234,13 @@ public class ConfiguredClass {
AccessType accessType = defaultAccessType;
AnnotationInstance accessAnnotation = JandexHelper.getSingleAnnotation( classInfo, JPADotNames.ACCESS, ClassInfo.class );
if ( accessAnnotation != null && accessAnnotation.target().getClass().equals( ClassInfo.class ) ) {
if ( accessAnnotation != null ) {
accessType = JandexHelper.getEnumValue( accessAnnotation, "value", AccessType.class );
} else {
accessAnnotation = JandexHelper.getSingleAnnotation( classInfo, HibernateDotNames.ACCESS_TYPE, ClassInfo.class );
if ( accessAnnotation != null ) {
accessType = AccessType.valueOf( accessAnnotation.value().asString().toUpperCase() );
}
}
return accessType;
@ -321,9 +327,15 @@ public class ConfiguredClass {
Set<String> explicitAccessPropertyNames = new HashSet<String>();
List<AnnotationInstance> accessAnnotations = classInfo.annotations().get( JPADotNames.ACCESS );
List<AnnotationInstance> hibernateAccessAnnotations = classInfo.annotations().get( HibernateDotNames.ACCESS_TYPE );
if ( accessAnnotations == null ) {
accessAnnotations = hibernateAccessAnnotations;
if ( accessAnnotations == null ) {
return explicitAccessPropertyNames;
}
} else if ( hibernateAccessAnnotations != null ) {
accessAnnotations.addAll( hibernateAccessAnnotations );
}
// iterate over all @Access annotations defined on the current class
for ( AnnotationInstance accessAnnotation : accessAnnotations ) {
@ -334,18 +346,19 @@ public class ConfiguredClass {
continue;
}
AccessType accessType = JandexHelper.getEnumValue( accessAnnotation, "value", AccessType.class );
if ( !isExplicitAttributeAccessAnnotationPlacedCorrectly( annotationTarget, accessType ) ) {
continue;
AccessType accessType;
if ( JPADotNames.ACCESS.equals( accessAnnotation.name() ) ) {
accessType = JandexHelper.getEnumValue( accessAnnotation, "value", AccessType.class );
checkExplicitJpaAttributeAccessAnnotationPlacedCorrectly( annotationTarget, accessType );
} else {
accessType = AccessType.valueOf( accessAnnotation.value().asString().toUpperCase() );
}
// the placement is correct, get the member
Member member;
if ( annotationTarget instanceof MethodInfo ) {
Method m;
try {
m = clazz.getMethod( ( ( MethodInfo ) annotationTarget ).name() );
member = clazz.getMethod( ( ( MethodInfo ) annotationTarget ).name() );
}
catch ( NoSuchMethodException e ) {
throw new HibernateException(
@ -354,13 +367,10 @@ public class ConfiguredClass {
+ " of class " + clazz.getName()
);
}
member = m;
accessType = AccessType.PROPERTY;
}
else {
Field f;
try {
f = clazz.getField( ( ( FieldInfo ) annotationTarget ).name() );
member = clazz.getField( ( ( FieldInfo ) annotationTarget ).name() );
}
catch ( NoSuchFieldException e ) {
throw new HibernateException(
@ -369,8 +379,6 @@ public class ConfiguredClass {
+ " of class " + clazz.getName()
);
}
member = f;
accessType = AccessType.FIELD;
}
if ( ReflectionHelper.isProperty( member ) ) {
createMappedAttribute( member, resolvedMembers, accessType );
@ -380,26 +388,20 @@ public class ConfiguredClass {
return explicitAccessPropertyNames;
}
private boolean isExplicitAttributeAccessAnnotationPlacedCorrectly(AnnotationTarget annotationTarget, AccessType accessType) {
private void checkExplicitJpaAttributeAccessAnnotationPlacedCorrectly(AnnotationTarget annotationTarget, AccessType accessType) {
// when the access type of the class is FIELD
// overriding access annotations must be placed on properties AND have the access type PROPERTY
if ( AccessType.FIELD.equals( classAccessType ) ) {
if ( !MethodInfo.class.isInstance( annotationTarget ) ) {
LOG.tracef(
"The access type of class %s is AccessType.FIELD. To override the access for an attribute " +
"@Access has to be placed on the property (getter)", classInfo.name().toString()
);
return false;
String msg = LOG.accessTypeOverrideShouldBeAnnotatedOnProperty( classInfo.name().toString() );
LOG.trace( msg );
throw new AnnotationException( msg );
}
if ( !AccessType.PROPERTY.equals( accessType ) ) {
LOG.tracef(
"The access type of class %s is AccessType.FIELD. To override the access for an attribute " +
"@Access has to be placed on the property (getter) with an access type of AccessType.PROPERTY. " +
"Using AccessType.FIELD on the property has no effect",
classInfo.name().toString()
);
return false;
String msg = LOG.accessTypeOverrideShouldBeProperty( classInfo.name().toString() );
LOG.trace( msg );
throw new AnnotationException( msg );
}
}
@ -407,24 +409,17 @@ public class ConfiguredClass {
// overriding access annotations must be placed on fields and have the access type FIELD
if ( AccessType.PROPERTY.equals( classAccessType ) ) {
if ( !FieldInfo.class.isInstance( annotationTarget ) ) {
LOG.tracef(
"The access type of class %s is AccessType.PROPERTY. To override the access for a field " +
"@Access has to be placed on the field ", classInfo.name().toString()
);
return false;
String msg = LOG.accessTypeOverrideShouldBeAnnotatedOnField( classInfo.name().toString() );
LOG.trace( msg );
throw new AnnotationException( msg );
}
if ( !AccessType.FIELD.equals( accessType ) ) {
LOG.tracef(
"The access type of class %s is AccessType.PROPERTY. To override the access for a field " +
"@Access has to be placed on the field with an access type of AccessType.FIELD. " +
"Using AccessType.PROPERTY on the field has no effect",
classInfo.name().toString()
);
return false;
String msg = LOG.accessTypeOverrideShouldBeField( classInfo.name().toString() );
LOG.trace( msg );
throw new AnnotationException( msg );
}
}
return true;
}
private void createMappedAttribute(Member member, ResolvedTypeWithMembers resolvedType, AccessType accessType) {
@ -476,6 +471,7 @@ public class ConfiguredClass {
);
idAttributeMap.put( attributeName, attribute );
}
//$FALL-THROUGH$
case EMBEDDED: {
final AnnotationInstance targetAnnotation = JandexHelper.getSingleAnnotation(
getClassInfo(),
@ -520,7 +516,7 @@ public class ConfiguredClass {
associationAttributeMap.put( attributeName, attribute );
break;
}
case MANY_TO_ANY: {}
}
}
@ -722,29 +718,6 @@ public class ConfiguredClass {
return prefix;
}
private List<AnnotationInstance> findAssociationOverrides() {
List<AnnotationInstance> associationOverrideList = new ArrayList<AnnotationInstance>();
AnnotationInstance associationOverrideAnnotation = JandexHelper.getSingleAnnotation(
classInfo,
JPADotNames.ASSOCIATION_OVERRIDE
);
if ( associationOverrideAnnotation != null ) {
associationOverrideList.add( associationOverrideAnnotation );
}
AnnotationInstance associationOverridesAnnotation = JandexHelper.getSingleAnnotation(
classInfo,
JPADotNames.ASSOCIATION_OVERRIDES
);
if ( associationOverrideAnnotation != null ) {
AnnotationInstance[] attributeOverride = associationOverridesAnnotation.value().asNestedArray();
Collections.addAll( associationOverrideList, attributeOverride );
}
return associationOverrideList;
}
private String determineCustomTuplizer() {
final AnnotationInstance tuplizersAnnotation = JandexHelper.getSingleAnnotation(
classInfo, HibernateDotNames.TUPLIZERS

View File

@ -38,9 +38,10 @@ import static org.junit.Assert.assertNull;
/**
* @author Emmanuel Bernard
*/
@FailureExpectedWithNewMetamodel
public class AccessTest extends BaseCoreFunctionalTestCase {
@Test
@FailureExpectedWithNewMetamodel
public void testSuperclassOverriding() throws Exception {
Furniture fur = new Furniture();
fur.setColor( "Black" );
@ -61,6 +62,7 @@ public class AccessTest extends BaseCoreFunctionalTestCase {
}
@Test
@FailureExpectedWithNewMetamodel
public void testSuperclassNonOverriding() throws Exception {
Furniture fur = new Furniture();
fur.setGod( "Buddha" );
@ -76,7 +78,9 @@ public class AccessTest extends BaseCoreFunctionalTestCase {
tx.commit();
s.close();
}
@Test
@FailureExpectedWithNewMetamodel
public void testPropertyOverriding() throws Exception {
Furniture fur = new Furniture();
fur.weight = 3;
@ -92,7 +96,9 @@ public class AccessTest extends BaseCoreFunctionalTestCase {
tx.commit();
s.close();
}
@Test
@FailureExpectedWithNewMetamodel
public void testNonOverridenSubclass() throws Exception {
Chair chair = new Chair();
chair.setPillow( "Blue" );
@ -108,7 +114,9 @@ public class AccessTest extends BaseCoreFunctionalTestCase {
tx.commit();
s.close();
}
@Test
@FailureExpectedWithNewMetamodel
public void testOverridenSubclass() throws Exception {
BigBed bed = new BigBed();
bed.size = 5;
@ -126,6 +134,7 @@ public class AccessTest extends BaseCoreFunctionalTestCase {
tx.commit();
s.close();
}
@Test
public void testFieldsOverriding() throws Exception {
Gardenshed gs = new Gardenshed();
@ -143,6 +152,7 @@ public class AccessTest extends BaseCoreFunctionalTestCase {
tx.commit();
s.close();
}
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] {

View File

@ -50,7 +50,6 @@ public class EagerKeyManyToOneTest extends BaseCoreFunctionalTestCase {
@Test
@TestForIssue( jiraKey = "HHH-4147" )
@FailureExpectedWithNewMetamodel
public void testLoadEntityWithEagerFetchingToKeyManyToOneReferenceBackToSelf() {
// based on the core testsuite test of same name in org.hibernate.test.keymanytoone.bidir.component.EagerKeyManyToOneTest
// meant to test against regression relating to http://opensource.atlassian.com/projects/hibernate/browse/HHH-2277