HHH-6393 Adding more tests and implementing nested embeddables

This commit is contained in:
Hardy Ferentschik 2011-08-02 12:00:05 +02:00
parent e875bb6004
commit b1478946db
4 changed files with 190 additions and 28 deletions

View File

@ -25,11 +25,13 @@ package org.hibernate.metamodel.source.annotations.entity;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationInstance;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.Value; import org.hibernate.internal.util.Value;
import org.hibernate.mapping.PropertyGeneration; import org.hibernate.mapping.PropertyGeneration;
import org.hibernate.metamodel.source.LocalBindingContext; import org.hibernate.metamodel.source.LocalBindingContext;
@ -53,21 +55,22 @@ import org.hibernate.metamodel.source.binder.SingularAttributeNature;
* @author Hardy Ferentschik * @author Hardy Ferentschik
*/ */
public class ComponentAttributeSourceImpl implements ComponentAttributeSource { public class ComponentAttributeSourceImpl implements ComponentAttributeSource {
private static final String PATH_SEPERATOR = ".";
private final EmbeddableClass embeddableClass; private final EmbeddableClass embeddableClass;
private final Value<Class<?>> classReference; private final Value<Class<?>> classReference;
private final Map<String, AttributeOverride> attributeOverrides; private final Map<String, AttributeOverride> attributeOverrides;
private final String path; private final String path;
public ComponentAttributeSourceImpl(EmbeddableClass embeddableClass, Map<String, AttributeOverride> attributeOverrides) { public ComponentAttributeSourceImpl(EmbeddableClass embeddableClass, String parentPath, Map<String, AttributeOverride> attributeOverrides) {
this.embeddableClass = embeddableClass; this.embeddableClass = embeddableClass;
this.classReference = new Value<Class<?>>( embeddableClass.getClass() ); this.classReference = new Value<Class<?>>( embeddableClass.getClass() );
this.attributeOverrides = attributeOverrides; this.attributeOverrides = attributeOverrides;
String tmpPath = embeddableClass.getEmbeddedAttributeName(); if ( StringHelper.isEmpty( parentPath ) ) {
ConfiguredClass parent = embeddableClass.getParent(); path = embeddableClass.getEmbeddedAttributeName();
while ( parent != null && parent instanceof EmbeddableClass ) { }
tmpPath = ( (EmbeddableClass) parent ).getEmbeddedAttributeName() + "." + tmpPath; else {
path = parentPath + "." + embeddableClass.getEmbeddedAttributeName();
} }
path = tmpPath;
} }
@Override @Override
@ -125,17 +128,18 @@ public class ComponentAttributeSourceImpl implements ComponentAttributeSource {
List<AttributeSource> attributeList = new ArrayList<AttributeSource>(); List<AttributeSource> attributeList = new ArrayList<AttributeSource>();
for ( BasicAttribute attribute : embeddableClass.getSimpleAttributes() ) { for ( BasicAttribute attribute : embeddableClass.getSimpleAttributes() ) {
AttributeOverride attributeOverride = null; AttributeOverride attributeOverride = null;
String tmp = getPath() + "." + attribute.getName(); String tmp = getPath() + PATH_SEPERATOR + attribute.getName();
if ( attributeOverrides.containsKey( tmp ) ) { if ( attributeOverrides.containsKey( tmp ) ) {
attributeOverride = attributeOverrides.get( tmp ); attributeOverride = attributeOverrides.get( tmp );
} }
attributeList.add( new SingularAttributeSourceImpl( attribute, attributeOverride ) ); attributeList.add( new SingularAttributeSourceImpl( attribute, attributeOverride ) );
} }
for ( EmbeddableClass component : embeddableClass.getEmbeddedClasses().values() ) { for ( EmbeddableClass embeddable : embeddableClass.getEmbeddedClasses().values() ) {
attributeList.add( attributeList.add(
new ComponentAttributeSourceImpl( new ComponentAttributeSourceImpl(
component, embeddable,
embeddableClass.getAttributeOverrideMap() getPath(),
createAggregatedOverrideMap()
) )
); );
} }
@ -191,13 +195,11 @@ public class ComponentAttributeSourceImpl implements ComponentAttributeSource {
@Override @Override
public boolean isLazy() { public boolean isLazy() {
// todo : implement
return false; return false;
} }
@Override @Override
public boolean isIncludedInOptimisticLocking() { public boolean isIncludedInOptimisticLocking() {
// todo : implement
return true; return true;
} }
@ -215,4 +217,29 @@ public class ComponentAttributeSourceImpl implements ComponentAttributeSource {
public boolean areValuesNullableByDefault() { public boolean areValuesNullableByDefault() {
return true; return true;
} }
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append( "ComponentAttributeSourceImpl" );
sb.append( "{embeddableClass=" ).append( embeddableClass.getConfiguredClass().getSimpleName() );
sb.append( '}' );
return sb.toString();
}
private Map<String, AttributeOverride> createAggregatedOverrideMap() {
// add all overrides passed down to this instance - they override overrides ;-) which are defined further down
// the embeddable chain
Map<String, AttributeOverride> aggregatedOverrideMap = new HashMap<String, AttributeOverride>(
attributeOverrides
);
for ( Map.Entry<String, AttributeOverride> entry : embeddableClass.getAttributeOverrideMap().entrySet() ) {
String fullPath = getPath() + PATH_SEPERATOR + entry.getKey();
if ( !aggregatedOverrideMap.containsKey( fullPath ) ) {
aggregatedOverrideMap.put( fullPath, entry.getValue() );
}
}
return aggregatedOverrideMap;
}
} }

View File

@ -608,7 +608,7 @@ public class ConfiguredClass {
JPADotNames.ATTRIBUTE_OVERRIDE JPADotNames.ATTRIBUTE_OVERRIDE
); );
if ( attributeOverrideAnnotation != null ) { if ( attributeOverrideAnnotation != null ) {
String prefix = createPathPrefix( attributeOverrideAnnotation ); String prefix = createPathPrefix( attributeOverrideAnnotation.target() );
AttributeOverride override = new AttributeOverride( prefix, attributeOverrideAnnotation ); AttributeOverride override = new AttributeOverride( prefix, attributeOverrideAnnotation );
attributeOverrideList.put( override.getAttributePath(), override ); attributeOverrideList.put( override.getAttributePath(), override );
} }
@ -620,7 +620,7 @@ public class ConfiguredClass {
if ( attributeOverridesAnnotation != null ) { if ( attributeOverridesAnnotation != null ) {
AnnotationInstance[] annotationInstances = attributeOverridesAnnotation.value().asNestedArray(); AnnotationInstance[] annotationInstances = attributeOverridesAnnotation.value().asNestedArray();
for ( AnnotationInstance annotationInstance : annotationInstances ) { for ( AnnotationInstance annotationInstance : annotationInstances ) {
String prefix = createPathPrefix( annotationInstance ); String prefix = createPathPrefix( attributeOverridesAnnotation.target() );
AttributeOverride override = new AttributeOverride( prefix, annotationInstance ); AttributeOverride override = new AttributeOverride( prefix, annotationInstance );
attributeOverrideList.put( override.getAttributePath(), override ); attributeOverrideList.put( override.getAttributePath(), override );
} }
@ -628,9 +628,8 @@ public class ConfiguredClass {
return attributeOverrideList; return attributeOverrideList;
} }
private String createPathPrefix(AnnotationInstance attributeOverrideAnnotation) { private String createPathPrefix(AnnotationTarget target) {
String prefix = null; String prefix = null;
AnnotationTarget target = attributeOverrideAnnotation.target();
if ( target instanceof FieldInfo || target instanceof MethodInfo ) { if ( target instanceof FieldInfo || target instanceof MethodInfo ) {
prefix = JandexHelper.getPropertyName( target ); prefix = JandexHelper.getPropertyName( target );
} }

View File

@ -176,7 +176,7 @@ public class EntitySourceImpl implements EntitySource {
attributeList.add( new SingularAttributeSourceImpl( attribute ) ); attributeList.add( new SingularAttributeSourceImpl( attribute ) );
} }
for ( EmbeddableClass component : entityClass.getEmbeddedClasses().values() ) { for ( EmbeddableClass component : entityClass.getEmbeddedClasses().values() ) {
attributeList.add( new ComponentAttributeSourceImpl( component, entityClass.getAttributeOverrideMap() ) ); attributeList.add( new ComponentAttributeSourceImpl( component, "", entityClass.getAttributeOverrideMap() ) );
} }
for ( AssociationAttribute associationAttribute : entityClass.getAssociationAttributes() ) { for ( AssociationAttribute associationAttribute : entityClass.getAssociationAttributes() ) {
attributeList.add( new ToOneAttributeSourceImpl( associationAttribute ) ); attributeList.add( new ToOneAttributeSourceImpl( associationAttribute ) );

View File

@ -24,6 +24,7 @@
package org.hibernate.metamodel.source.annotations.entity; package org.hibernate.metamodel.source.annotations.entity;
import javax.persistence.AttributeOverride; import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.Embedded; import javax.persistence.Embedded;
@ -52,22 +53,22 @@ public class EmbeddableBindingTest extends BaseAnnotationBindingTestCase {
private int id; private int id;
@Embedded @Embedded
private Address address; private Phone phone;
} }
@Embeddable @Embeddable
class Address { class Phone {
String street; String countryCode;
String city; String areaCode;
String postCode; String number;
} }
@Test @Test
@Resources(annotatedClasses = { User.class, Address.class }) @Resources(annotatedClasses = { User.class, Phone.class })
public void testEmbeddable() { public void testEmbeddable() {
EntityBinding binding = getEntityBinding( User.class ); EntityBinding binding = getEntityBinding( User.class );
final String componentName = "address"; final String componentName = "phone";
assertNotNull( binding.locateAttributeBinding( componentName ) ); assertNotNull( binding.locateAttributeBinding( componentName ) );
assertTrue( binding.locateAttributeBinding( componentName ) instanceof ComponentAttributeBinding ); assertTrue( binding.locateAttributeBinding( componentName ) instanceof ComponentAttributeBinding );
ComponentAttributeBinding componentBinding = (ComponentAttributeBinding) binding.locateAttributeBinding( ComponentAttributeBinding componentBinding = (ComponentAttributeBinding) binding.locateAttributeBinding(
@ -77,13 +78,13 @@ public class EmbeddableBindingTest extends BaseAnnotationBindingTestCase {
// todo - is this really correct? Does the path start w/ the class name // todo - is this really correct? Does the path start w/ the class name
assertEquals( assertEquals(
"Wrong path", "Wrong path",
"org.hibernate.metamodel.source.annotations.entity.EmbeddableBindingTest$User.address", "org.hibernate.metamodel.source.annotations.entity.EmbeddableBindingTest$User.phone",
componentBinding.getPathBase() componentBinding.getPathBase()
); );
assertNotNull( componentBinding.locateAttributeBinding( "street" ) ); assertNotNull( componentBinding.locateAttributeBinding( "countryCode" ) );
assertNotNull( componentBinding.locateAttributeBinding( "city" ) ); assertNotNull( componentBinding.locateAttributeBinding( "areaCode" ) );
assertNotNull( componentBinding.locateAttributeBinding( "postCode" ) ); assertNotNull( componentBinding.locateAttributeBinding( "number" ) );
} }
@Entity @Entity
@ -119,6 +120,141 @@ public class EmbeddableBindingTest extends BaseAnnotationBindingTestCase {
assertEquals( "Attribute override specifies a custom column name", "FUBAR", column.getColumnName().getName() ); assertEquals( "Attribute override specifies a custom column name", "FUBAR", column.getColumnName().getName() );
assertEquals( "Attribute override specifies a custom size", 42, column.getSize().getLength() ); assertEquals( "Attribute override specifies a custom size", 42, column.getSize().getLength() );
} }
@Embeddable
public class Address {
protected String street;
protected String city;
protected String state;
@Embedded
protected Zipcode zipcode;
}
@Embeddable
public class Zipcode {
protected String zip;
protected String plusFour;
}
@Entity
public class Customer {
@Id
protected Integer id;
protected String name;
@AttributeOverrides( {
@AttributeOverride(name = "state",
column = @Column(name = "ADDR_STATE")),
@AttributeOverride(name = "zipcode.zip",
column = @Column(name = "ADDR_ZIP"))
})
@Embedded
protected Address address;
}
@Test
@Resources(annotatedClasses = { Zipcode.class, Address.class, Customer.class })
public void testNestedEmbeddable() {
EntityBinding binding = getEntityBinding( Customer.class );
final String addressComponentName = "address";
assertNotNull( binding.locateAttributeBinding( addressComponentName ) );
assertTrue( binding.locateAttributeBinding( addressComponentName ) instanceof ComponentAttributeBinding );
ComponentAttributeBinding attributeComponentBinding = (ComponentAttributeBinding) binding.locateAttributeBinding(
addressComponentName
);
assertNotNull( attributeComponentBinding.locateAttributeBinding( "street" ) );
assertNotNull( attributeComponentBinding.locateAttributeBinding( "city" ) );
assertNotNull( attributeComponentBinding.locateAttributeBinding( "state" ) );
BasicAttributeBinding stateAttribute = (BasicAttributeBinding) attributeComponentBinding.locateAttributeBinding(
"state"
);
org.hibernate.metamodel.relational.Column column = (org.hibernate.metamodel.relational.Column) stateAttribute.getValue();
assertEquals(
"Attribute override specifies a custom column name",
"ADDR_STATE",
column.getColumnName().getName()
);
final String zipComponentName = "zipcode";
assertNotNull( attributeComponentBinding.locateAttributeBinding( zipComponentName ) );
assertTrue( attributeComponentBinding.locateAttributeBinding( zipComponentName ) instanceof ComponentAttributeBinding );
ComponentAttributeBinding zipComponentBinding = (ComponentAttributeBinding) attributeComponentBinding.locateAttributeBinding(
zipComponentName
);
BasicAttributeBinding nameAttribute = (BasicAttributeBinding) zipComponentBinding.locateAttributeBinding( "zip" );
column = (org.hibernate.metamodel.relational.Column) nameAttribute.getValue();
assertEquals(
"Attribute override specifies a custom column name",
"ADDR_ZIP",
column.getColumnName().getName()
);
}
@Embeddable
public class A {
@Embedded
@AttributeOverrides( {
@AttributeOverride(name = "foo", column = @Column(name = "BAR")),
@AttributeOverride(name = "fubar", column = @Column(name = "A_WINS"))
})
protected B b;
}
@Embeddable
public class B {
protected String foo;
private String fubar;
}
@Entity
public class C {
@Id
int id;
@Embedded
@AttributeOverride(name = "b.fubar", column = @Column(name = "C_WINS"))
protected A a;
}
@Test
@Resources(annotatedClasses = { A.class, B.class, C.class })
public void testAttributeOverrideInEmbeddable() {
EntityBinding binding = getEntityBinding( C.class );
final String aComponentName = "a";
assertNotNull( binding.locateAttributeBinding( aComponentName ) );
assertTrue( binding.locateAttributeBinding( aComponentName ) instanceof ComponentAttributeBinding );
ComponentAttributeBinding aComponentBinding = (ComponentAttributeBinding) binding.locateAttributeBinding(
aComponentName
);
final String bComponentName = "b";
assertNotNull( aComponentBinding.locateAttributeBinding( bComponentName ) );
assertTrue( aComponentBinding.locateAttributeBinding( bComponentName ) instanceof ComponentAttributeBinding );
ComponentAttributeBinding bComponentBinding = (ComponentAttributeBinding) aComponentBinding.locateAttributeBinding(
bComponentName
);
BasicAttributeBinding attribute = (BasicAttributeBinding) bComponentBinding.locateAttributeBinding( "foo" );
org.hibernate.metamodel.relational.Column column = (org.hibernate.metamodel.relational.Column) attribute.getValue();
assertEquals(
"Attribute override specifies a custom column name",
"BAR",
column.getColumnName().getName()
);
attribute = (BasicAttributeBinding) bComponentBinding.locateAttributeBinding( "fubar" );
column = (org.hibernate.metamodel.relational.Column) attribute.getValue();
assertEquals(
"Attribute override specifies a custom column name",
"C_WINS",
column.getColumnName().getName()
);
}
} }