HHH-6201 Introduce explicit maps for id-, simple- and association-attributes

This commit is contained in:
Hardy Ferentschik 2011-07-05 15:16:41 +02:00
parent d3f20f44ea
commit 546ba3c550
2 changed files with 92 additions and 68 deletions

View File

@ -110,9 +110,7 @@ public abstract class MappedAttribute implements Comparable<MappedAttribute> {
public String toString() { public String toString() {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append( "MappedAttribute" ); sb.append( "MappedAttribute" );
sb.append( "{type='" ).append( type ).append( '\'' ); sb.append( "{name='" ).append( name ).append( '\'' );
sb.append( ", typeParameters=" ).append( typeParameters );
sb.append( ", name='" ).append( name ).append( '\'' );
sb.append( '}' ); sb.append( '}' );
return sb.toString(); return sb.toString();
} }

View File

@ -32,10 +32,10 @@ import java.util.Collections;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap;
import javax.persistence.AccessType; import javax.persistence.AccessType;
import com.fasterxml.classmate.ResolvedTypeWithMembers; import com.fasterxml.classmate.ResolvedTypeWithMembers;
@ -104,9 +104,19 @@ public class ConfiguredClass {
private final List<AnnotationInstance> associationOverrides; private final List<AnnotationInstance> associationOverrides;
/** /**
* The mapped attributes for entity * The id attributes
*/ */
private final Map<String, MappedAttribute> mappedAttributes; private final Map<String, SimpleAttribute> idAttributeMap;
/**
* The mapped association attributes for this entity
*/
private final Map<String, AssociationAttribute> associationAttributeMap;
/**
* The mapped simple attributes for this entity
*/
private final Map<String, SimpleAttribute> simpleAttributeMap;
/** /**
* The embedded classes for this entity * The embedded classes for this entity
@ -132,17 +142,13 @@ public class ConfiguredClass {
this.attributeOverrides = findAttributeOverrides(); this.attributeOverrides = findAttributeOverrides();
this.associationOverrides = findAssociationOverrides(); this.associationOverrides = findAssociationOverrides();
this.simpleAttributeMap = new TreeMap<String, SimpleAttribute>();
this.idAttributeMap = new TreeMap<String, SimpleAttribute>();
this.associationAttributeMap = new TreeMap<String, AssociationAttribute>();
// find transient field and method names // find transient field and method names
findTransientFieldAndMethodNames(); findTransientFieldAndMethodNames();
collectAttributes();
List<MappedAttribute> simpleAttributes = collectAttributes();
// make sure the properties are ordered by property name
Collections.sort( simpleAttributes );
Map<String, MappedAttribute> tmpMap = new LinkedHashMap<String, MappedAttribute>();
for ( MappedAttribute property : simpleAttributes ) {
tmpMap.put( property.getName(), property );
}
this.mappedAttributes = Collections.unmodifiableMap( tmpMap );
} }
public String getName() { public String getName() {
@ -161,16 +167,20 @@ public class ConfiguredClass {
return parent; return parent;
} }
public boolean isRoot() {
return parent == null;
}
public ConfiguredClassType getConfiguredClassType() { public ConfiguredClassType getConfiguredClassType() {
return configuredClassType; return configuredClassType;
} }
public Iterable<MappedAttribute> getMappedAttributes() { public Iterable<SimpleAttribute> getSimpleAttributes() {
return mappedAttributes.values(); return simpleAttributeMap.values();
}
public Iterable<SimpleAttribute> getIdAttributes() {
return idAttributeMap.values();
}
public Iterable<AssociationAttribute> getAssociationAttributes() {
return associationAttributeMap.values();
} }
public Map<String, EmbeddableClass> getEmbeddedClasses() { public Map<String, EmbeddableClass> getEmbeddedClasses() {
@ -178,7 +188,15 @@ public class ConfiguredClass {
} }
public MappedAttribute getMappedAttribute(String propertyName) { public MappedAttribute getMappedAttribute(String propertyName) {
return mappedAttributes.get( propertyName ); MappedAttribute attribute;
attribute = simpleAttributeMap.get( propertyName );
if ( attribute == null ) {
attribute = associationAttributeMap.get( propertyName );
}
if ( attribute == null ) {
attribute = idAttributeMap.get( propertyName );
}
return attribute;
} }
@Override @Override
@ -188,7 +206,9 @@ public class ConfiguredClass {
sb.append( "{clazz=" ).append( clazz.getSimpleName() ); sb.append( "{clazz=" ).append( clazz.getSimpleName() );
sb.append( ", classAccessType=" ).append( classAccessType ); sb.append( ", classAccessType=" ).append( classAccessType );
sb.append( ", configuredClassType=" ).append( configuredClassType ); sb.append( ", configuredClassType=" ).append( configuredClassType );
sb.append( ", mappedAttributes=" ).append( mappedAttributes ); sb.append( ", idAttributeMap=" ).append( idAttributeMap );
sb.append( ", simpleAttributeMap=" ).append( simpleAttributeMap );
sb.append( ", associationAttributeMap=" ).append( associationAttributeMap );
sb.append( '}' ); sb.append( '}' );
return sb.toString(); return sb.toString();
} }
@ -221,9 +241,9 @@ public class ConfiguredClass {
} }
/** /**
* @return A list of the persistent properties of this configured class * Find all attributes for this configured class and add them to the corresponding map
*/ */
private List<MappedAttribute> collectAttributes() { private void collectAttributes() {
// use the class mate library to generic types // use the class mate library to generic types
ResolvedTypeWithMembers resolvedType = context.resolveMemberTypes( context.getResolvedType( clazz ) ); ResolvedTypeWithMembers resolvedType = context.resolveMemberTypes( context.getResolvedType( clazz ) );
for ( HierarchicType hierarchicType : resolvedType.allTypesAndOverrides() ) { for ( HierarchicType hierarchicType : resolvedType.allTypesAndOverrides() ) {
@ -237,17 +257,14 @@ public class ConfiguredClass {
throw new AssertionFailure( "Unable to resolve types for " + clazz.getName() ); throw new AssertionFailure( "Unable to resolve types for " + clazz.getName() );
} }
List<MappedAttribute> properties = new ArrayList<MappedAttribute>(); Set<String> explicitlyConfiguredMemberNames = createExplicitlyConfiguredAccessProperties( resolvedType );
Set<String> explicitlyConfiguredMemberNames = createExplicitlyConfiguredAccessProperties(
properties, resolvedType
);
if ( AccessType.FIELD.equals( classAccessType ) ) { if ( AccessType.FIELD.equals( classAccessType ) ) {
Field fields[] = clazz.getDeclaredFields(); Field fields[] = clazz.getDeclaredFields();
Field.setAccessible( fields, true ); Field.setAccessible( fields, true );
for ( Field field : fields ) { for ( Field field : fields ) {
if ( isPersistentMember( transientFieldNames, explicitlyConfiguredMemberNames, field ) ) { if ( isPersistentMember( transientFieldNames, explicitlyConfiguredMemberNames, field ) ) {
properties.add( createMappedProperty( field, resolvedType ) ); createMappedProperty( field, resolvedType );
} }
} }
} }
@ -256,11 +273,10 @@ public class ConfiguredClass {
Method.setAccessible( methods, true ); Method.setAccessible( methods, true );
for ( Method method : methods ) { for ( Method method : methods ) {
if ( isPersistentMember( transientMethodNames, explicitlyConfiguredMemberNames, method ) ) { if ( isPersistentMember( transientMethodNames, explicitlyConfiguredMemberNames, method ) ) {
properties.add( createMappedProperty( method, resolvedType ) ); createMappedProperty( method, resolvedType );
} }
} }
} }
return properties;
} }
private boolean isPersistentMember(Set<String> transientNames, Set<String> explicitlyConfiguredMemberNames, Member member) { private boolean isPersistentMember(Set<String> transientNames, Set<String> explicitlyConfiguredMemberNames, Member member) {
@ -282,12 +298,11 @@ public class ConfiguredClass {
/** /**
* Creates {@code MappedProperty} instances for the explicitly configured persistent properties * Creates {@code MappedProperty} instances for the explicitly configured persistent properties
* *
* @param mappedProperties list to which to add the explicitly configured mapped properties
* @param resolvedMembers the resolved type parameters for this class * @param resolvedMembers the resolved type parameters for this class
* *
* @return the property names of the explicitly configured class names in a set * @return the property names of the explicitly configured attribute names in a set
*/ */
private Set<String> createExplicitlyConfiguredAccessProperties(List<MappedAttribute> mappedProperties, ResolvedTypeWithMembers resolvedMembers) { private Set<String> createExplicitlyConfiguredAccessProperties(ResolvedTypeWithMembers resolvedMembers) {
Set<String> explicitAccessMembers = new HashSet<String>(); Set<String> explicitAccessMembers = new HashSet<String>();
List<AnnotationInstance> accessAnnotations = classInfo.annotations().get( JPADotNames.ACCESS ); List<AnnotationInstance> accessAnnotations = classInfo.annotations().get( JPADotNames.ACCESS );
@ -365,14 +380,14 @@ public class ConfiguredClass {
member = f; member = f;
} }
if ( ReflectionHelper.isProperty( member ) ) { if ( ReflectionHelper.isProperty( member ) ) {
mappedProperties.add( createMappedProperty( member, resolvedMembers ) ); createMappedProperty( member, resolvedMembers );
explicitAccessMembers.add( member.getName() ); explicitAccessMembers.add( member.getName() );
} }
} }
return explicitAccessMembers; return explicitAccessMembers;
} }
private MappedAttribute createMappedProperty(Member member, ResolvedTypeWithMembers resolvedType) { private void createMappedProperty(Member member, ResolvedTypeWithMembers resolvedType) {
final String attributeName = ReflectionHelper.getPropertyName( member ); final String attributeName = ReflectionHelper.getPropertyName( member );
ResolvedMember[] resolvedMembers; ResolvedMember[] resolvedMembers;
if ( member instanceof Field ) { if ( member instanceof Field ) {
@ -386,52 +401,60 @@ public class ConfiguredClass {
classInfo, member.getName() classInfo, member.getName()
); );
MappedAttribute attribute;
AttributeType attributeType = determineAttributeType( annotations ); AttributeType attributeType = determineAttributeType( annotations );
switch ( attributeType ) { switch ( attributeType ) {
case BASIC: { case BASIC: {
attribute = SimpleAttribute.createSimpleAttribute( attributeName, type.getName(), annotations ); SimpleAttribute attribute = SimpleAttribute.createSimpleAttribute(
attributeName,
type.getName(),
annotations
);
if ( attribute.isId() ) {
idAttributeMap.put( attributeName, attribute );
}
else {
simpleAttributeMap.put( attributeName, attribute );
}
break; break;
} }
case ELEMENT_COLLECTION: case ELEMENT_COLLECTION:
case EMBEDDED_ID: case EMBEDDED_ID:
case EMBEDDED: { case EMBEDDED: {
resolveEmbeddable( attributeName, type ); resolveEmbeddable( attributeName, type );
} }
// TODO handle the different association types // TODO handle the different association types
default: { default: {
attribute = AssociationAttribute.createAssociationAttribute( AssociationAttribute attribute = AssociationAttribute.createAssociationAttribute(
attributeName,type.getName(), attributeType, annotations attributeName, type.getName(), attributeType, annotations
); );
associationAttributeMap.put( attributeName, attribute );
} }
} }
return attribute;
} }
private void resolveEmbeddable(String attributeName, Class<?> type) { private void resolveEmbeddable(String attributeName, Class<?> type) {
ClassInfo embeddableClassInfo = context.getClassInfo( type.getName() ); ClassInfo embeddableClassInfo = context.getClassInfo( type.getName() );
if ( classInfo == null ) { if ( classInfo == null ) {
String msg = String.format( String msg = String.format(
"Attribute %s of entity %s is annotated with @Embedded, but no embeddable configuration for type %s can be found.", "Attribute %s of entity %s is annotated with @Embedded, but no embeddable configuration for type %s can be found.",
attributeName, attributeName,
getName(), getName(),
type.getName() type.getName()
); );
throw new AnnotationException( msg ); throw new AnnotationException( msg );
} }
context.resolveAllTypes( type.getName() ); context.resolveAllTypes( type.getName() );
ConfiguredClassHierarchy<EmbeddableClass> hierarchy = ConfiguredClassHierarchyBuilder.createEmbeddableHierarchy( ConfiguredClassHierarchy<EmbeddableClass> hierarchy = ConfiguredClassHierarchyBuilder.createEmbeddableHierarchy(
context.loadClass( embeddableClassInfo.toString() ), context.loadClass( embeddableClassInfo.toString() ),
classAccessType, classAccessType,
context context
); );
embeddedClasses.put( attributeName, hierarchy.getLeaf() ); embeddedClasses.put( attributeName, hierarchy.getLeaf() );
} }
/** /**
* Given the annotations defined on a persistent attribute this methods determines the attribute type. * Given the annotations defined on a persistent attribute this methods determines the attribute type.
* *
* @param annotations the annotations defined on the persistent attribute * @param annotations the annotations defined on the persistent attribute
@ -467,12 +490,15 @@ public class ConfiguredClass {
discoveredAttributeTypes.put( AttributeType.EMBEDDED, embedded ); discoveredAttributeTypes.put( AttributeType.EMBEDDED, embedded );
} }
AnnotationInstance embeddIded = JandexHelper.getSingleAnnotation( annotations, JPADotNames.EMBEDDED_ID ); AnnotationInstance embeddIded = JandexHelper.getSingleAnnotation( annotations, JPADotNames.EMBEDDED_ID );
if ( embeddIded != null ) { if ( embeddIded != null ) {
discoveredAttributeTypes.put( AttributeType.EMBEDDED_ID, embeddIded ); discoveredAttributeTypes.put( AttributeType.EMBEDDED_ID, embeddIded );
} }
AnnotationInstance elementCollection = JandexHelper.getSingleAnnotation( annotations, JPADotNames.ELEMENT_COLLECTION ); AnnotationInstance elementCollection = JandexHelper.getSingleAnnotation(
annotations,
JPADotNames.ELEMENT_COLLECTION
);
if ( elementCollection != null ) { if ( elementCollection != null ) {
discoveredAttributeTypes.put( AttributeType.ELEMENT_COLLECTION, elementCollection ); discoveredAttributeTypes.put( AttributeType.ELEMENT_COLLECTION, elementCollection );
} }