HHH-6262 bind @EmbeddedId
This commit is contained in:
parent
88f69a135b
commit
793f317ea9
|
@ -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() {
|
||||||
|
|
|
@ -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>();
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue