HHH-6262 bind @EmbeddedId

This commit is contained in:
Strong Liu 2011-07-01 00:31:17 +08:00
parent 88f69a135b
commit 793f317ea9
11 changed files with 174 additions and 48 deletions

View File

@ -48,8 +48,7 @@ public class EntityIdentifier {
private SimpleAttributeBinding attributeBinding; private SimpleAttributeBinding attributeBinding;
private IdentifierGenerator identifierGenerator; private IdentifierGenerator identifierGenerator;
private IdGenerator idGenerator; private IdGenerator idGenerator;
private boolean isEmbedded; private boolean isIdentifierMapper = false;
private boolean isIdentifierMapper;
// todo : mappers, etc // todo : mappers, etc
/** /**
@ -79,7 +78,7 @@ public class EntityIdentifier {
} }
public boolean isEmbedded() { public boolean isEmbedded() {
return isEmbedded; return attributeBinding.getValuesSpan()>0;
} }
public boolean isIdentifierMapper() { public boolean isIdentifierMapper() {

View File

@ -36,7 +36,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public abstract class AbstractTableSpecification implements TableSpecification, ValueContainer { public abstract class AbstractTableSpecification implements TableSpecification {
private final static AtomicInteger tableCounter = new AtomicInteger( 0 ); private final static AtomicInteger tableCounter = new AtomicInteger( 0 );
private final int tableNumber; private final int tableNumber;
private final LinkedHashMap<String,SimpleValue> values = new LinkedHashMap<String,SimpleValue>(); private final LinkedHashMap<String,SimpleValue> values = new LinkedHashMap<String,SimpleValue>();

View File

@ -32,7 +32,7 @@ import java.util.Collections;
* @author Gavin King * @author Gavin King
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class InLineView extends AbstractTableSpecification implements ValueContainer { public class InLineView extends AbstractTableSpecification {
private final Schema schema; private final Schema schema;
private final String logicalName; private final String logicalName;
private final String select; private final String select;
@ -77,7 +77,7 @@ public class InLineView extends AbstractTableSpecification implements ValueConta
} }
@Override @Override
public Iterable<String> getCheckConstraints() { public Iterable<CheckConstraint> getCheckConstraints() {
return Collections.emptyList(); return Collections.emptyList();
} }

View File

@ -29,20 +29,22 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.hibernate.internal.util.StringHelper;
/** /**
* Models the concept of a relational <tt>TABLE</tt> (or <tt>VIEW</tt>). * Models the concept of a relational <tt>TABLE</tt> (or <tt>VIEW</tt>).
* *
* @author Gavin King * @author Gavin King
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class Table extends AbstractTableSpecification implements ValueContainer, Exportable { public class Table extends AbstractTableSpecification implements Exportable {
private final Schema database; private final Schema database;
private final Identifier tableName; private final Identifier tableName;
private final String qualifiedName; private final String qualifiedName;
private LinkedHashMap<String,Index> indexes; private LinkedHashMap<String,Index> indexes;
private LinkedHashMap<String,UniqueKey> uniqueKeys; private LinkedHashMap<String,UniqueKey> uniqueKeys;
private List<String> checkConstraints; private List<CheckConstraint> checkConstraints;
private Set<String> comments; private Set<String> comments;
public Table(Schema database, String tableName) { public Table(Schema database, String tableName) {
@ -115,16 +117,18 @@ public class Table extends AbstractTableSpecification implements ValueContainer,
} }
@Override @Override
public Iterable<String> getCheckConstraints() { public Iterable<CheckConstraint> getCheckConstraints() {
return checkConstraints; return checkConstraints;
} }
@Override @Override
public void addCheckConstraint(String checkCondition) { public void addCheckConstraint(String checkCondition) {
if ( checkConstraints == null ) { if ( checkConstraints == null ) {
checkConstraints = new ArrayList<String>(); checkConstraints = new ArrayList<CheckConstraint>();
} }
checkConstraints.add( checkCondition ); //todo ? StringHelper.isEmpty( checkCondition );
//todo default name?
checkConstraints.add( new CheckConstraint( this, "", checkCondition ) );
} }
@Override @Override

View File

@ -89,7 +89,7 @@ public interface TableSpecification extends ValueContainer, Loggable {
public UniqueKey getOrCreateUniqueKey(String name); public UniqueKey getOrCreateUniqueKey(String name);
public Iterable<String> getCheckConstraints(); public Iterable<CheckConstraint> getCheckConstraints();
public void addCheckConstraint(String checkCondition); public void addCheckConstraint(String checkCondition);

View File

@ -39,6 +39,7 @@ public enum AttributeType {
MANY_TO_ONE( JPADotNames.MANY_TO_ONE ), MANY_TO_ONE( JPADotNames.MANY_TO_ONE ),
MANY_TO_MANY( JPADotNames.MANY_TO_MANY ), MANY_TO_MANY( JPADotNames.MANY_TO_MANY ),
ELEMENT_COLLECTION( JPADotNames.ELEMENT_COLLECTION ), ELEMENT_COLLECTION( JPADotNames.ELEMENT_COLLECTION ),
EMBEDDED_ID( JPADotNames.EMBEDDED_ID ),
EMBEDDED( JPADotNames.EMBEDDED ); EMBEDDED( JPADotNames.EMBEDDED );
private final DotName annotationDotName; private final DotName annotationDotName;

View File

@ -130,7 +130,8 @@ public class SimpleAttribute extends MappedAttribute {
AnnotationInstance idAnnotation = JandexHelper.getSingleAnnotation( annotations, JPADotNames.ID ); AnnotationInstance idAnnotation = JandexHelper.getSingleAnnotation( annotations, JPADotNames.ID );
isId = idAnnotation != null; AnnotationInstance embeddedIdAnnotation = JandexHelper.getSingleAnnotation( annotations, JPADotNames.EMBEDDED_ID );
isId = !(idAnnotation == null && embeddedIdAnnotation == null);
AnnotationInstance versionAnnotation = JandexHelper.getSingleAnnotation( annotations, JPADotNames.VERSION ); AnnotationInstance versionAnnotation = JandexHelper.getSingleAnnotation( annotations, JPADotNames.VERSION );
isVersioned = versionAnnotation != null; isVersioned = versionAnnotation != null;

View File

@ -393,7 +393,24 @@ public class ConfiguredClass {
attribute = SimpleAttribute.createSimpleAttribute( attributeName, type.getName(), annotations ); attribute = SimpleAttribute.createSimpleAttribute( attributeName, type.getName(), annotations );
break; break;
} }
case ELEMENT_COLLECTION:
case EMBEDDED_ID:
case EMBEDDED: { case EMBEDDED: {
resolveEmbeddable( attributeName, type );
}
// TODO handle the different association types
default: {
attribute = AssociationAttribute.createAssociationAttribute(
attributeName,type.getName(), attributeType, annotations
);
}
}
return attribute;
}
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(
@ -413,16 +430,6 @@ public class ConfiguredClass {
); );
embeddedClasses.put( attributeName, hierarchy.getLeaf() ); embeddedClasses.put( attributeName, hierarchy.getLeaf() );
} }
// TODO handle the different association types
default: {
attribute = AssociationAttribute.createAssociationAttribute(
attributeName, ( (Class) type ).getName(), attributeType, annotations
);
}
}
return attribute;
}
/** /**
* 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.
@ -460,6 +467,16 @@ public class ConfiguredClass {
discoveredAttributeTypes.put( AttributeType.EMBEDDED, embedded ); discoveredAttributeTypes.put( AttributeType.EMBEDDED, embedded );
} }
AnnotationInstance embeddIded = JandexHelper.getSingleAnnotation( annotations, JPADotNames.EMBEDDED_ID );
if ( embeddIded != null ) {
discoveredAttributeTypes.put( AttributeType.EMBEDDED_ID, embeddIded );
}
AnnotationInstance elementCollection = JandexHelper.getSingleAnnotation( annotations, JPADotNames.ELEMENT_COLLECTION );
if ( elementCollection != null ) {
discoveredAttributeTypes.put( AttributeType.ELEMENT_COLLECTION, elementCollection );
}
if ( discoveredAttributeTypes.size() == 0 ) { if ( discoveredAttributeTypes.size() == 0 ) {
return AttributeType.BASIC; return AttributeType.BASIC;
} }

View File

@ -144,20 +144,40 @@ public class ConfiguredClassHierarchy<T extends ConfiguredClass> implements Iter
* annotations. * annotations.
*/ */
private static AccessType determineDefaultAccessType(List<ClassInfo> classes) { private static AccessType determineDefaultAccessType(List<ClassInfo> classes) {
AccessType accessType = null; AccessType defaultAccessType = null;
AccessType accessTypeByIdPlacement = null;
for ( ClassInfo info : classes ) { for ( ClassInfo info : classes ) {
List<AnnotationInstance> idAnnotations = info.annotations().get( JPADotNames.ID ); List<AnnotationInstance> idAnnotations = info.annotations().get( JPADotNames.ID );
if ( idAnnotations == null || idAnnotations.size() == 0 ) { List<AnnotationInstance> accessAnnotations = info.annotations().get( JPADotNames.ACCESS );
continue;
if ( accessAnnotations != null && !accessAnnotations.isEmpty() ) {
for ( AnnotationInstance annotation : accessAnnotations ) {
if ( annotation.target() instanceof ClassInfo ) {
defaultAccessType = JandexHelper.getValueAsEnum( annotation, "value", AccessType.class );
break; //there can be only one @Access on class level.
} }
accessType = determineAccessTypeByIdPlacement( idAnnotations ); }
}
if ( idAnnotations != null && !idAnnotations.isEmpty() ) {
accessTypeByIdPlacement = determineAccessTypeByIdPlacement( idAnnotations );
}
}
if ( defaultAccessType != null ) {
return defaultAccessType;
} else if (accessTypeByIdPlacement != null ){
return accessTypeByIdPlacement;
} else {
return AccessType.PROPERTY;
} }
if ( accessType == null ) {
return throwIdNotFoundAnnotationException( classes );
}
return accessType; //
//
// if ( accessType == null ) {
// return throwIdNotFoundAnnotationException( classes );
// }
//
// return accessType;
} }
private static AccessType determineAccessTypeByIdPlacement(List<AnnotationInstance> idAnnotations) { private static AccessType determineAccessTypeByIdPlacement(List<AnnotationInstance> idAnnotations) {

View File

@ -42,6 +42,7 @@ import org.hibernate.annotations.ResultCheckStyle;
import org.hibernate.cache.spi.RegionFactory; import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.access.AccessType; import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.binding.Caching; import org.hibernate.metamodel.binding.Caching;
import org.hibernate.metamodel.binding.CustomSQL; import org.hibernate.metamodel.binding.CustomSQL;
@ -119,15 +120,15 @@ public class EntityBinder {
bindInheritance( entityBinding ); bindInheritance( entityBinding );
// take care of the id, attributes and relations
if ( entityClass.isRoot() ) {
bindId( entityBinding );
}
// bind all attributes - simple as well as associations // bind all attributes - simple as well as associations
bindAttributes( entityBinding ); bindAttributes( entityBinding );
bindEmbeddedAttributes( entityBinding ); bindEmbeddedAttributes( entityBinding );
// take care of the id, attributes and relations
if ( entityClass.isRoot() ) {
bindId( entityBinding );
}
bindTableUniqueConstraints( entityBinding ); bindTableUniqueConstraints( entityBinding );
@ -452,7 +453,7 @@ public class EntityBinder {
break; break;
} }
case EMBEDDED: { case EMBEDDED: {
// todo bindEmbeddedIdAnnotation( entityBinding );
break; break;
} }
default: { default: {
@ -475,6 +476,37 @@ public class EntityBinder {
entityBindingState.setJpaEntityName( name ); entityBindingState.setJpaEntityName( name );
} }
private void bindEmbeddedIdAnnotation(EntityBinding entityBinding) {
AnnotationInstance idAnnotation = JandexHelper.getSingleAnnotation(
entityClass.getClassInfo(), JPADotNames.EMBEDDED_ID
);
String idName = JandexHelper.getPropertyName( idAnnotation.target() );
MappedAttribute idAttribute = entityClass.getMappedAttribute( idName );
if ( !( idAttribute instanceof SimpleAttribute ) ) {
throw new AssertionFailure( "Unexpected attribute type for id attribute" );
}
SingularAttribute attribute = entityBinding.getEntity().getOrCreateComponentAttribute( idName );
SimpleAttributeBinding attributeBinding = entityBinding.makeSimpleIdAttributeBinding( attribute );
attributeBinding.initialize( new AttributeBindingStateImpl( (SimpleAttribute) idAttribute ) );
TupleRelationalStateImpl state = new TupleRelationalStateImpl();
EmbeddableClass embeddableClass = entityClass.getEmbeddedClasses().get( idName );
for ( MappedAttribute attr : embeddableClass.getMappedAttributes() ) {
state.addValueState( new ColumnRelationalStateImpl( (SimpleAttribute) attr, meta ) );
}
attributeBinding.initialize( state );
Map<String,String> parms = new HashMap<String, String>( 1 );
parms.put( IdentifierGenerator.ENTITY_NAME, entityBinding.getEntity().getName() );
IdGenerator generator = new IdGenerator( "NAME","assigned", parms);
entityBinding.getEntityIdentifier().setIdGenerator( generator );
entityBinding.getEntityIdentifier().createIdentifierGenerator( meta.getIdentifierGeneratorFactory() );
}
private void bindSingleIdAnnotation(EntityBinding entityBinding) { private void bindSingleIdAnnotation(EntityBinding entityBinding) {
AnnotationInstance idAnnotation = JandexHelper.getSingleAnnotation( AnnotationInstance idAnnotation = JandexHelper.getSingleAnnotation(
entityClass.getClassInfo(), JPADotNames.ID entityClass.getClassInfo(), JPADotNames.ID
@ -548,10 +580,11 @@ public class EntityBinder {
) )
); );
} }
else { if( idGenerator == null ) {
idGenerator = new IdGenerator( "NAME", strategy, new HashMap<String, String>() ); idGenerator = new IdGenerator( "NAME", strategy, new HashMap<String, String>() );
entityBinding.getEntityIdentifier().setIdGenerator( idGenerator ); entityBinding.getEntityIdentifier().setIdGenerator( idGenerator );
} }
entityBinding.getEntityIdentifier().createIdentifierGenerator( meta.getIdentifierGeneratorFactory() );
} }
private void bindAttributes(EntityBinding entityBinding) { private void bindAttributes(EntityBinding entityBinding) {

View File

@ -0,0 +1,51 @@
package org.hibernate.metamodel.source.annotations.entity;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import org.junit.Test;
import org.hibernate.id.Assigned;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.binding.EntityIdentifier;
import org.hibernate.metamodel.domain.Attribute;
import org.hibernate.metamodel.domain.Component;
import static junit.framework.Assert.assertTrue;
/**
* @author Strong Liu
*/
public class EmbeddedIdTests extends BaseAnnotationBindingTestCase {
@Test
public void testEmbeddable() {
buildMetadataSources( User.class, Address.class );
EntityBinding binding = getEntityBinding( User.class );
EntityIdentifier identifier = binding.getEntityIdentifier();
assertTrue( identifier.isEmbedded() );
assertTrue(
"EmbeddedId generator should be 'assigned'", identifier.getIdentifierGenerator() instanceof Assigned
);
}
@Entity
@Access( AccessType.FIELD )
class User {
private String name;
@EmbeddedId
private Address address;
}
@Embeddable
class Address {
String street;
String city;
String postCode;
}
}