HHH-17504 - Ongoing JPA 32 work
HHH-17350 - Work on hibernate-models, XSD and JAXB HHH-16114 - Improve boot metamodel binding HHH-15996 - Develop an abstraction for Annotation in annotation processing HHH-16012 - Develop an abstraction for domain model Class refs HHH-15997 - Support for dynamic models in orm.xml HHH-15698 - Support for entity-name in mapping.xsd
This commit is contained in:
parent
01e3b12ae8
commit
6869dbb1f9
|
@ -27,6 +27,7 @@ import org.hibernate.models.ModelsException;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public abstract class IdentifiableTypeBinding extends ManagedTypeBinding {
|
public abstract class IdentifiableTypeBinding extends ManagedTypeBinding {
|
||||||
|
protected final IdentifiableTypeMetadata typeMetadata;
|
||||||
protected final IdentifiableTypeBinding superTypeBinding;
|
protected final IdentifiableTypeBinding superTypeBinding;
|
||||||
protected final IdentifiableTypeMetadata superTypeMetadata;
|
protected final IdentifiableTypeMetadata superTypeMetadata;
|
||||||
|
|
||||||
|
@ -39,7 +40,8 @@ public abstract class IdentifiableTypeBinding extends ManagedTypeBinding {
|
||||||
BindingOptions bindingOptions,
|
BindingOptions bindingOptions,
|
||||||
BindingState bindingState,
|
BindingState bindingState,
|
||||||
BindingContext bindingContext) {
|
BindingContext bindingContext) {
|
||||||
super( typeMetadata, bindingOptions, bindingState, bindingContext );
|
super( typeMetadata.getClassDetails(), bindingOptions, bindingState, bindingContext );
|
||||||
|
this.typeMetadata = typeMetadata;
|
||||||
this.superTypeBinding = superTypeBinding;
|
this.superTypeBinding = superTypeBinding;
|
||||||
this.superTypeMetadata = superTypeBinding == null ? null : superTypeBinding.getTypeMetadata();
|
this.superTypeMetadata = superTypeBinding == null ? null : superTypeBinding.getTypeMetadata();
|
||||||
|
|
||||||
|
@ -47,9 +49,8 @@ public abstract class IdentifiableTypeBinding extends ManagedTypeBinding {
|
||||||
this.attributeBindings = CollectionHelper.linkedMapOfSize( typeMetadata.getNumberOfAttributes() );
|
this.attributeBindings = CollectionHelper.linkedMapOfSize( typeMetadata.getNumberOfAttributes() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public IdentifiableTypeMetadata getTypeMetadata() {
|
public IdentifiableTypeMetadata getTypeMetadata() {
|
||||||
return (IdentifiableTypeMetadata) super.getTypeMetadata();
|
return typeMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IdentifiableTypeMetadata getSuperTypeMetadata() {
|
public IdentifiableTypeMetadata getSuperTypeMetadata() {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import java.util.Map;
|
||||||
import org.hibernate.boot.models.bind.spi.BindingContext;
|
import org.hibernate.boot.models.bind.spi.BindingContext;
|
||||||
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
import org.hibernate.boot.models.bind.spi.BindingOptions;
|
||||||
import org.hibernate.boot.models.bind.spi.BindingState;
|
import org.hibernate.boot.models.bind.spi.BindingState;
|
||||||
import org.hibernate.boot.models.categorize.spi.ManagedTypeMetadata;
|
import org.hibernate.models.spi.ClassDetails;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binding for an {@linkplain jakarta.persistence.metamodel.ManagedType managed type}
|
* Binding for an {@linkplain jakarta.persistence.metamodel.ManagedType managed type}
|
||||||
|
@ -19,19 +19,19 @@ import org.hibernate.boot.models.categorize.spi.ManagedTypeMetadata;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public abstract class ManagedTypeBinding extends Binding {
|
public abstract class ManagedTypeBinding extends Binding {
|
||||||
protected final ManagedTypeMetadata typeMetadata;
|
protected final ClassDetails classDetails;
|
||||||
|
|
||||||
public ManagedTypeBinding(
|
public ManagedTypeBinding(
|
||||||
ManagedTypeMetadata typeMetadata,
|
ClassDetails classDetails,
|
||||||
BindingOptions bindingOptions,
|
BindingOptions bindingOptions,
|
||||||
BindingState bindingState,
|
BindingState bindingState,
|
||||||
BindingContext bindingContext) {
|
BindingContext bindingContext) {
|
||||||
super( bindingOptions, bindingState, bindingContext );
|
super( bindingOptions, bindingState, bindingContext );
|
||||||
this.typeMetadata = typeMetadata;
|
this.classDetails = classDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ManagedTypeMetadata getTypeMetadata() {
|
public ClassDetails getClassDetails() {
|
||||||
return typeMetadata;
|
return classDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Map<String, AttributeBinding> getAttributeBindings();
|
public abstract Map<String, AttributeBinding> getAttributeBindings();
|
||||||
|
|
|
@ -12,7 +12,6 @@ import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.hibernate.boot.models.JpaAnnotations;
|
|
||||||
import org.hibernate.boot.models.categorize.spi.EntityHierarchy;
|
import org.hibernate.boot.models.categorize.spi.EntityHierarchy;
|
||||||
import org.hibernate.boot.models.categorize.spi.IdentifiableTypeMetadata;
|
import org.hibernate.boot.models.categorize.spi.IdentifiableTypeMetadata;
|
||||||
import org.hibernate.boot.models.categorize.spi.JpaEventListener;
|
import org.hibernate.boot.models.categorize.spi.JpaEventListener;
|
||||||
|
@ -23,7 +22,6 @@ import org.hibernate.models.spi.AnnotationUsage;
|
||||||
import org.hibernate.models.spi.ClassDetails;
|
import org.hibernate.models.spi.ClassDetails;
|
||||||
import org.hibernate.models.spi.ClassDetailsRegistry;
|
import org.hibernate.models.spi.ClassDetailsRegistry;
|
||||||
|
|
||||||
import jakarta.persistence.Access;
|
|
||||||
import jakarta.persistence.AccessType;
|
import jakarta.persistence.AccessType;
|
||||||
import jakarta.persistence.EntityListeners;
|
import jakarta.persistence.EntityListeners;
|
||||||
import jakarta.persistence.ExcludeDefaultListeners;
|
import jakarta.persistence.ExcludeDefaultListeners;
|
||||||
|
@ -56,7 +54,7 @@ public abstract class AbstractIdentifiableTypeMetadata
|
||||||
this.hierarchy = hierarchy;
|
this.hierarchy = hierarchy;
|
||||||
this.superType = null;
|
this.superType = null;
|
||||||
|
|
||||||
this.accessType = determineAccessType( accessType );
|
this.accessType = CategorizationHelper.determineAccessType( classDetails, accessType );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,7 +70,7 @@ public abstract class AbstractIdentifiableTypeMetadata
|
||||||
this.hierarchy = hierarchy;
|
this.hierarchy = hierarchy;
|
||||||
this.superType = superType;
|
this.superType = superType;
|
||||||
|
|
||||||
this.accessType = determineAccessType( superType.getAccessType() );
|
this.accessType = CategorizationHelper.determineAccessType( classDetails, superType.getAccessType() );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void postInstantiate(HierarchyTypeConsumer typeConsumer) {
|
protected void postInstantiate(HierarchyTypeConsumer typeConsumer) {
|
||||||
|
@ -124,15 +122,6 @@ public abstract class AbstractIdentifiableTypeMetadata
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private AccessType determineAccessType(AccessType defaultAccessType) {
|
|
||||||
final AnnotationUsage<Access> annotation = getClassDetails().getAnnotationUsage( JpaAnnotations.ACCESS );
|
|
||||||
if ( annotation != null ) {
|
|
||||||
return annotation.getAttributeValue( "value" );
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultAccessType;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addSubclass(IdentifiableTypeMetadata subclass) {
|
private void addSubclass(IdentifiableTypeMetadata subclass) {
|
||||||
subTypes.add( subclass );
|
subTypes.add( subclass );
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,37 +7,20 @@
|
||||||
package org.hibernate.boot.models.categorize.internal;
|
package org.hibernate.boot.models.categorize.internal;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.hibernate.annotations.Any;
|
|
||||||
import org.hibernate.annotations.ManyToAny;
|
|
||||||
import org.hibernate.boot.model.source.spi.AttributePath;
|
import org.hibernate.boot.model.source.spi.AttributePath;
|
||||||
import org.hibernate.boot.model.source.spi.AttributeRole;
|
import org.hibernate.boot.model.source.spi.AttributeRole;
|
||||||
import org.hibernate.boot.model.source.spi.NaturalIdMutability;
|
import org.hibernate.boot.model.source.spi.NaturalIdMutability;
|
||||||
import org.hibernate.boot.models.HibernateAnnotations;
|
|
||||||
import org.hibernate.boot.models.JpaAnnotations;
|
|
||||||
import org.hibernate.boot.models.MultipleAttributeNaturesException;
|
|
||||||
import org.hibernate.boot.models.categorize.ModelCategorizationLogging;
|
|
||||||
import org.hibernate.boot.models.categorize.spi.AllMemberConsumer;
|
import org.hibernate.boot.models.categorize.spi.AllMemberConsumer;
|
||||||
import org.hibernate.boot.models.categorize.spi.AttributeMetadata;
|
import org.hibernate.boot.models.categorize.spi.AttributeMetadata;
|
||||||
import org.hibernate.boot.models.categorize.spi.ManagedTypeMetadata;
|
import org.hibernate.boot.models.categorize.spi.ManagedTypeMetadata;
|
||||||
import org.hibernate.boot.models.categorize.spi.ModelCategorizationContext;
|
import org.hibernate.boot.models.categorize.spi.ModelCategorizationContext;
|
||||||
import org.hibernate.internal.util.IndexedConsumer;
|
import org.hibernate.internal.util.IndexedConsumer;
|
||||||
import org.hibernate.models.spi.AnnotationUsage;
|
|
||||||
import org.hibernate.models.spi.ClassDetails;
|
import org.hibernate.models.spi.ClassDetails;
|
||||||
import org.hibernate.models.spi.MemberDetails;
|
import org.hibernate.models.spi.MemberDetails;
|
||||||
|
|
||||||
import jakarta.persistence.Basic;
|
|
||||||
import jakarta.persistence.ElementCollection;
|
|
||||||
import jakarta.persistence.Embedded;
|
|
||||||
import jakarta.persistence.EmbeddedId;
|
|
||||||
import jakarta.persistence.ManyToMany;
|
|
||||||
import jakarta.persistence.ManyToOne;
|
|
||||||
import jakarta.persistence.OneToMany;
|
|
||||||
import jakarta.persistence.OneToOne;
|
|
||||||
|
|
||||||
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
|
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -151,14 +134,14 @@ public abstract class AbstractManagedTypeMetadata implements ManagedTypeMetadata
|
||||||
protected List<AttributeMetadata> resolveAttributes(AllMemberConsumer memberConsumer) {
|
protected List<AttributeMetadata> resolveAttributes(AllMemberConsumer memberConsumer) {
|
||||||
final List<MemberDetails> backingMembers = getModelContext()
|
final List<MemberDetails> backingMembers = getModelContext()
|
||||||
.getPersistentAttributeMemberResolver()
|
.getPersistentAttributeMemberResolver()
|
||||||
.resolveAttributesMembers( classDetails, getAccessType(), memberConsumer, modelContext );
|
.resolveAttributesMembers( classDetails, getAccessType(), memberConsumer );
|
||||||
|
|
||||||
final List<AttributeMetadata> attributeList = arrayList( backingMembers.size() );
|
final List<AttributeMetadata> attributeList = arrayList( backingMembers.size() );
|
||||||
|
|
||||||
for ( MemberDetails backingMember : backingMembers ) {
|
for ( MemberDetails backingMember : backingMembers ) {
|
||||||
final AttributeMetadata attribute = new AttributeMetadataImpl(
|
final AttributeMetadata attribute = new AttributeMetadataImpl(
|
||||||
backingMember.resolveAttributeName(),
|
backingMember.resolveAttributeName(),
|
||||||
determineAttributeNature( backingMember ),
|
CategorizationHelper.determineAttributeNature( backingMember ),
|
||||||
backingMember
|
backingMember
|
||||||
);
|
);
|
||||||
attributeList.add( attribute );
|
attributeList.add( attribute );
|
||||||
|
@ -167,114 +150,6 @@ public abstract class AbstractManagedTypeMetadata implements ManagedTypeMetadata
|
||||||
return attributeList;
|
return attributeList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine the attribute's nature - is it a basic mapping, an embeddable, ...?
|
|
||||||
*
|
|
||||||
* Also performs some simple validation around multiple natures being indicated
|
|
||||||
*/
|
|
||||||
private AttributeMetadata.AttributeNature determineAttributeNature(MemberDetails backingMember) {
|
|
||||||
final EnumSet<AttributeMetadata.AttributeNature> natures = EnumSet.noneOf( AttributeMetadata.AttributeNature.class );
|
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
// first, look for explicit nature annotations
|
|
||||||
|
|
||||||
final AnnotationUsage<Any> any = backingMember.getAnnotationUsage( HibernateAnnotations.ANY );
|
|
||||||
final AnnotationUsage<Basic> basic = backingMember.getAnnotationUsage( JpaAnnotations.BASIC );
|
|
||||||
final AnnotationUsage<ElementCollection> elementCollection = backingMember.getAnnotationUsage( JpaAnnotations.ELEMENT_COLLECTION );
|
|
||||||
final AnnotationUsage<Embedded> embedded = backingMember.getAnnotationUsage( JpaAnnotations.EMBEDDED );
|
|
||||||
final AnnotationUsage<EmbeddedId> embeddedId = backingMember.getAnnotationUsage( JpaAnnotations.EMBEDDED_ID );
|
|
||||||
final AnnotationUsage<ManyToAny> manyToAny = backingMember.getAnnotationUsage( HibernateAnnotations.MANY_TO_ANY );
|
|
||||||
final AnnotationUsage<ManyToMany> manyToMany = backingMember.getAnnotationUsage( JpaAnnotations.MANY_TO_MANY );
|
|
||||||
final AnnotationUsage<ManyToOne> manyToOne = backingMember.getAnnotationUsage( JpaAnnotations.MANY_TO_ONE );
|
|
||||||
final AnnotationUsage<OneToMany> oneToMany = backingMember.getAnnotationUsage( JpaAnnotations.ONE_TO_MANY );
|
|
||||||
final AnnotationUsage<OneToOne> oneToOne = backingMember.getAnnotationUsage( JpaAnnotations.ONE_TO_ONE );
|
|
||||||
|
|
||||||
if ( basic != null ) {
|
|
||||||
natures.add( AttributeMetadata.AttributeNature.BASIC );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( embedded != null
|
|
||||||
|| embeddedId != null
|
|
||||||
|| ( backingMember.getType() != null && backingMember.getType().getAnnotationUsage( JpaAnnotations.EMBEDDABLE ) != null ) ) {
|
|
||||||
natures.add( AttributeMetadata.AttributeNature.EMBEDDED );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( any != null ) {
|
|
||||||
natures.add( AttributeMetadata.AttributeNature.ANY );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( oneToOne != null
|
|
||||||
|| manyToOne != null ) {
|
|
||||||
natures.add( AttributeMetadata.AttributeNature.TO_ONE );
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean plural = oneToMany != null
|
|
||||||
|| manyToMany != null
|
|
||||||
|| elementCollection != null
|
|
||||||
|| manyToAny != null;
|
|
||||||
if ( plural ) {
|
|
||||||
natures.add( AttributeMetadata.AttributeNature.PLURAL );
|
|
||||||
}
|
|
||||||
|
|
||||||
// look at annotations that imply a nature
|
|
||||||
// NOTE : these could apply to the element or index of collection, so
|
|
||||||
// only do these if it is not a collection
|
|
||||||
|
|
||||||
if ( !plural ) {
|
|
||||||
// first implicit basic nature
|
|
||||||
if ( backingMember.getAnnotationUsage( JpaAnnotations.TEMPORAL ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( JpaAnnotations.LOB ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( JpaAnnotations.ENUMERATED ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( JpaAnnotations.CONVERT ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( JpaAnnotations.VERSION ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.GENERATED ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.NATIONALIZED ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.TZ_COLUMN ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.TZ_STORAGE ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.TYPE ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.TENANT_ID ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.JAVA_TYPE ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.JDBC_TYPE_CODE ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.JDBC_TYPE ) != null ) {
|
|
||||||
natures.add( AttributeMetadata.AttributeNature.BASIC );
|
|
||||||
}
|
|
||||||
|
|
||||||
// then embedded
|
|
||||||
if ( backingMember.getAnnotationUsage( HibernateAnnotations.EMBEDDABLE_INSTANTIATOR ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.COMPOSITE_TYPE ) != null ) {
|
|
||||||
natures.add( AttributeMetadata.AttributeNature.EMBEDDED );
|
|
||||||
}
|
|
||||||
|
|
||||||
// and any
|
|
||||||
if ( backingMember.getAnnotationUsage( HibernateAnnotations.ANY_DISCRIMINATOR ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.ANY_DISCRIMINATOR_VALUE ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.ANY_DISCRIMINATOR_VALUES ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.ANY_KEY_JAVA_TYPE ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.ANY_KEY_JAVA_CLASS ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.ANY_KEY_JDBC_TYPE ) != null
|
|
||||||
|| backingMember.getAnnotationUsage( HibernateAnnotations.ANY_KEY_JDBC_TYPE_CODE ) != null ) {
|
|
||||||
natures.add( AttributeMetadata.AttributeNature.ANY );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int size = natures.size();
|
|
||||||
switch ( size ) {
|
|
||||||
case 0: {
|
|
||||||
ModelCategorizationLogging.MODEL_CATEGORIZATION_LOGGER.debugf(
|
|
||||||
"Implicitly interpreting attribute `%s` as BASIC",
|
|
||||||
backingMember.resolveAttributeName()
|
|
||||||
);
|
|
||||||
return AttributeMetadata.AttributeNature.BASIC;
|
|
||||||
}
|
|
||||||
case 1: {
|
|
||||||
return natures.iterator().next();
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
throw new MultipleAttributeNaturesException( backingMember.resolveAttributeName(), natures );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
// public <A extends Annotation> List<AnnotationUsage<A>> findAnnotations(AnnotationDescriptor<A> type) {
|
// public <A extends Annotation> List<AnnotationUsage<A>> findAnnotations(AnnotationDescriptor<A> type) {
|
||||||
// return classDetails.getAnnotations( type );
|
// return classDetails.getAnnotations( type );
|
||||||
|
|
|
@ -14,7 +14,6 @@ import java.util.function.Function;
|
||||||
|
|
||||||
import org.hibernate.boot.models.JpaAnnotations;
|
import org.hibernate.boot.models.JpaAnnotations;
|
||||||
import org.hibernate.boot.models.categorize.spi.AllMemberConsumer;
|
import org.hibernate.boot.models.categorize.spi.AllMemberConsumer;
|
||||||
import org.hibernate.boot.models.categorize.spi.ModelCategorizationContext;
|
|
||||||
import org.hibernate.boot.models.categorize.spi.PersistentAttributeMemberResolver;
|
import org.hibernate.boot.models.categorize.spi.PersistentAttributeMemberResolver;
|
||||||
import org.hibernate.models.spi.ClassDetails;
|
import org.hibernate.models.spi.ClassDetails;
|
||||||
import org.hibernate.models.spi.FieldDetails;
|
import org.hibernate.models.spi.FieldDetails;
|
||||||
|
@ -45,21 +44,18 @@ public abstract class AbstractPersistentAttributeMemberResolver implements Persi
|
||||||
* @param transientMethodChecker Check whether a method is annotated as @Transient
|
* @param transientMethodChecker Check whether a method is annotated as @Transient
|
||||||
* @param classDetails The Jandex ClassInfo describing the type for which to resolve members
|
* @param classDetails The Jandex ClassInfo describing the type for which to resolve members
|
||||||
* @param classLevelAccessType The AccessType determined for the class default
|
* @param classLevelAccessType The AccessType determined for the class default
|
||||||
* @param processingContext The local context
|
|
||||||
*/
|
*/
|
||||||
protected abstract List<MemberDetails> resolveAttributesMembers(
|
protected abstract List<MemberDetails> resolveAttributesMembers(
|
||||||
Function<FieldDetails,Boolean> transientFieldChecker,
|
Function<FieldDetails,Boolean> transientFieldChecker,
|
||||||
Function<MethodDetails,Boolean> transientMethodChecker,
|
Function<MethodDetails,Boolean> transientMethodChecker,
|
||||||
ClassDetails classDetails,
|
ClassDetails classDetails,
|
||||||
AccessType classLevelAccessType,
|
AccessType classLevelAccessType);
|
||||||
ModelCategorizationContext processingContext);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<MemberDetails> resolveAttributesMembers(
|
public List<MemberDetails> resolveAttributesMembers(
|
||||||
ClassDetails classDetails,
|
ClassDetails classDetails,
|
||||||
AccessType classLevelAccessType,
|
AccessType classLevelAccessType,
|
||||||
AllMemberConsumer memberConsumer,
|
AllMemberConsumer memberConsumer) {
|
||||||
ModelCategorizationContext processingContext) {
|
|
||||||
|
|
||||||
final Set<FieldDetails> transientFields = new HashSet<>();
|
final Set<FieldDetails> transientFields = new HashSet<>();
|
||||||
final Set<MethodDetails> transientMethods = new HashSet<>();
|
final Set<MethodDetails> transientMethods = new HashSet<>();
|
||||||
|
@ -67,16 +63,14 @@ public abstract class AbstractPersistentAttributeMemberResolver implements Persi
|
||||||
transientFields::add,
|
transientFields::add,
|
||||||
transientMethods::add,
|
transientMethods::add,
|
||||||
classDetails,
|
classDetails,
|
||||||
memberConsumer,
|
memberConsumer
|
||||||
processingContext
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return resolveAttributesMembers(
|
return resolveAttributesMembers(
|
||||||
transientFields::contains,
|
transientFields::contains,
|
||||||
transientMethods::contains,
|
transientMethods::contains,
|
||||||
classDetails,
|
classDetails,
|
||||||
classLevelAccessType,
|
classLevelAccessType
|
||||||
processingContext
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,8 +78,7 @@ public abstract class AbstractPersistentAttributeMemberResolver implements Persi
|
||||||
final Consumer<FieldDetails> transientFieldConsumer,
|
final Consumer<FieldDetails> transientFieldConsumer,
|
||||||
final Consumer<MethodDetails> transientMethodConsumer,
|
final Consumer<MethodDetails> transientMethodConsumer,
|
||||||
ClassDetails classDetails,
|
ClassDetails classDetails,
|
||||||
AllMemberConsumer memberConsumer,
|
AllMemberConsumer memberConsumer) {
|
||||||
@SuppressWarnings("unused") ModelCategorizationContext processingContext) {
|
|
||||||
final List<FieldDetails> fields = classDetails.getFields();
|
final List<FieldDetails> fields = classDetails.getFields();
|
||||||
for ( int i = 0; i < fields.size(); i++ ) {
|
for ( int i = 0; i < fields.size(); i++ ) {
|
||||||
final FieldDetails fieldDetails = fields.get( i );
|
final FieldDetails fieldDetails = fields.get( i );
|
||||||
|
|
|
@ -6,8 +6,29 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.boot.models.categorize.internal;
|
package org.hibernate.boot.models.categorize.internal;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Any;
|
||||||
|
import org.hibernate.annotations.ManyToAny;
|
||||||
|
import org.hibernate.boot.models.HibernateAnnotations;
|
||||||
import org.hibernate.boot.models.JpaAnnotations;
|
import org.hibernate.boot.models.JpaAnnotations;
|
||||||
|
import org.hibernate.boot.models.MultipleAttributeNaturesException;
|
||||||
|
import org.hibernate.boot.models.categorize.ModelCategorizationLogging;
|
||||||
|
import org.hibernate.boot.models.categorize.spi.AttributeMetadata;
|
||||||
|
import org.hibernate.models.spi.AnnotationUsage;
|
||||||
import org.hibernate.models.spi.ClassDetails;
|
import org.hibernate.models.spi.ClassDetails;
|
||||||
|
import org.hibernate.models.spi.MemberDetails;
|
||||||
|
|
||||||
|
import jakarta.persistence.Access;
|
||||||
|
import jakarta.persistence.AccessType;
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.ElementCollection;
|
||||||
|
import jakarta.persistence.Embedded;
|
||||||
|
import jakarta.persistence.EmbeddedId;
|
||||||
|
import jakarta.persistence.ManyToMany;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
import jakarta.persistence.OneToOne;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -24,4 +45,117 @@ public class CategorizationHelper {
|
||||||
public static boolean isIdentifiable(ClassDetails classDetails) {
|
public static boolean isIdentifiable(ClassDetails classDetails) {
|
||||||
return isEntity( classDetails ) || isMappedSuperclass( classDetails );
|
return isEntity( classDetails ) || isMappedSuperclass( classDetails );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AccessType determineAccessType(ClassDetails classDetails, AccessType defaultAccessType) {
|
||||||
|
final AnnotationUsage<Access> annotation = classDetails.getAnnotationUsage( JpaAnnotations.ACCESS );
|
||||||
|
if ( annotation != null ) {
|
||||||
|
return annotation.getAttributeValue( "value" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultAccessType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the attribute's nature - is it a basic mapping, an embeddable, ...?
|
||||||
|
* </p>
|
||||||
|
* Also performs some simple validation around multiple natures being indicated
|
||||||
|
*/
|
||||||
|
public static AttributeMetadata.AttributeNature determineAttributeNature(MemberDetails backingMember) {
|
||||||
|
final EnumSet<AttributeMetadata.AttributeNature> natures = EnumSet.noneOf( AttributeMetadata.AttributeNature.class );
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// first, look for explicit nature annotations
|
||||||
|
|
||||||
|
final AnnotationUsage<Any> any = backingMember.getAnnotationUsage( HibernateAnnotations.ANY );
|
||||||
|
final AnnotationUsage<Basic> basic = backingMember.getAnnotationUsage( JpaAnnotations.BASIC );
|
||||||
|
final AnnotationUsage<ElementCollection> elementCollection = backingMember.getAnnotationUsage( JpaAnnotations.ELEMENT_COLLECTION );
|
||||||
|
final AnnotationUsage<Embedded> embedded = backingMember.getAnnotationUsage( JpaAnnotations.EMBEDDED );
|
||||||
|
final AnnotationUsage<EmbeddedId> embeddedId = backingMember.getAnnotationUsage( JpaAnnotations.EMBEDDED_ID );
|
||||||
|
final AnnotationUsage<ManyToAny> manyToAny = backingMember.getAnnotationUsage( HibernateAnnotations.MANY_TO_ANY );
|
||||||
|
final AnnotationUsage<ManyToMany> manyToMany = backingMember.getAnnotationUsage( JpaAnnotations.MANY_TO_MANY );
|
||||||
|
final AnnotationUsage<ManyToOne> manyToOne = backingMember.getAnnotationUsage( JpaAnnotations.MANY_TO_ONE );
|
||||||
|
final AnnotationUsage<OneToMany> oneToMany = backingMember.getAnnotationUsage( JpaAnnotations.ONE_TO_MANY );
|
||||||
|
final AnnotationUsage<OneToOne> oneToOne = backingMember.getAnnotationUsage( JpaAnnotations.ONE_TO_ONE );
|
||||||
|
|
||||||
|
if ( basic != null ) {
|
||||||
|
natures.add( AttributeMetadata.AttributeNature.BASIC );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( embedded != null
|
||||||
|
|| embeddedId != null
|
||||||
|
|| ( backingMember.getType() != null && backingMember.getType().getAnnotationUsage( JpaAnnotations.EMBEDDABLE ) != null ) ) {
|
||||||
|
natures.add( AttributeMetadata.AttributeNature.EMBEDDED );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( any != null ) {
|
||||||
|
natures.add( AttributeMetadata.AttributeNature.ANY );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( oneToOne != null
|
||||||
|
|| manyToOne != null ) {
|
||||||
|
natures.add( AttributeMetadata.AttributeNature.TO_ONE );
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean plural = oneToMany != null
|
||||||
|
|| manyToMany != null
|
||||||
|
|| elementCollection != null
|
||||||
|
|| manyToAny != null;
|
||||||
|
if ( plural ) {
|
||||||
|
natures.add( AttributeMetadata.AttributeNature.PLURAL );
|
||||||
|
}
|
||||||
|
|
||||||
|
// look at annotations that imply a nature
|
||||||
|
// NOTE : these could apply to the element or index of collection, so
|
||||||
|
// only do these if it is not a collection
|
||||||
|
|
||||||
|
if ( !plural ) {
|
||||||
|
// first implicit basic nature
|
||||||
|
if ( backingMember.getAnnotationUsage( JpaAnnotations.TEMPORAL ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( JpaAnnotations.LOB ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( JpaAnnotations.ENUMERATED ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( JpaAnnotations.CONVERT ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( JpaAnnotations.VERSION ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.GENERATED ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.NATIONALIZED ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.TZ_COLUMN ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.TZ_STORAGE ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.TYPE ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.TENANT_ID ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.JAVA_TYPE ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.JDBC_TYPE_CODE ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.JDBC_TYPE ) != null ) {
|
||||||
|
natures.add( AttributeMetadata.AttributeNature.BASIC );
|
||||||
|
}
|
||||||
|
|
||||||
|
// then embedded
|
||||||
|
if ( backingMember.getAnnotationUsage( HibernateAnnotations.EMBEDDABLE_INSTANTIATOR ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.COMPOSITE_TYPE ) != null ) {
|
||||||
|
natures.add( AttributeMetadata.AttributeNature.EMBEDDED );
|
||||||
|
}
|
||||||
|
|
||||||
|
// and any
|
||||||
|
if ( backingMember.getAnnotationUsage( HibernateAnnotations.ANY_DISCRIMINATOR ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.ANY_DISCRIMINATOR_VALUE ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.ANY_DISCRIMINATOR_VALUES ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.ANY_KEY_JAVA_TYPE ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.ANY_KEY_JAVA_CLASS ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.ANY_KEY_JDBC_TYPE ) != null
|
||||||
|
|| backingMember.getAnnotationUsage( HibernateAnnotations.ANY_KEY_JDBC_TYPE_CODE ) != null ) {
|
||||||
|
natures.add( AttributeMetadata.AttributeNature.ANY );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = natures.size();
|
||||||
|
return switch ( size ) {
|
||||||
|
case 0 -> {
|
||||||
|
ModelCategorizationLogging.MODEL_CATEGORIZATION_LOGGER.debugf(
|
||||||
|
"Implicitly interpreting attribute `%s` as BASIC",
|
||||||
|
backingMember.resolveAttributeName()
|
||||||
|
);
|
||||||
|
yield AttributeMetadata.AttributeNature.BASIC;
|
||||||
|
}
|
||||||
|
case 1 -> natures.iterator().next();
|
||||||
|
default -> throw new MultipleAttributeNaturesException( backingMember.resolveAttributeName(), natures );
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,7 @@ public class StandardPersistentAttributeMemberResolver extends AbstractPersisten
|
||||||
Function<FieldDetails,Boolean> transientFieldChecker,
|
Function<FieldDetails,Boolean> transientFieldChecker,
|
||||||
Function<MethodDetails,Boolean> transientMethodChecker,
|
Function<MethodDetails,Boolean> transientMethodChecker,
|
||||||
ClassDetails classDetails,
|
ClassDetails classDetails,
|
||||||
AccessType classLevelAccessType,
|
AccessType classLevelAccessType) {
|
||||||
ModelCategorizationContext processingContext) {
|
|
||||||
assert classLevelAccessType != null;
|
assert classLevelAccessType != null;
|
||||||
|
|
||||||
final LinkedHashMap<String,MemberDetails> results = new LinkedHashMap<>();
|
final LinkedHashMap<String,MemberDetails> results = new LinkedHashMap<>();
|
||||||
|
@ -51,8 +50,7 @@ public class StandardPersistentAttributeMemberResolver extends AbstractPersisten
|
||||||
results::put,
|
results::put,
|
||||||
transientFieldChecker,
|
transientFieldChecker,
|
||||||
transientMethodChecker,
|
transientMethodChecker,
|
||||||
classDetails,
|
classDetails
|
||||||
processingContext
|
|
||||||
);
|
);
|
||||||
|
|
||||||
processClassLevelAccess(
|
processClassLevelAccess(
|
||||||
|
@ -61,8 +59,7 @@ public class StandardPersistentAttributeMemberResolver extends AbstractPersisten
|
||||||
transientFieldChecker,
|
transientFieldChecker,
|
||||||
transientMethodChecker,
|
transientMethodChecker,
|
||||||
classDetails,
|
classDetails,
|
||||||
classLevelAccessType,
|
classLevelAccessType
|
||||||
processingContext
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return new ArrayList<>( results.values() );
|
return new ArrayList<>( results.values() );
|
||||||
|
@ -72,18 +69,17 @@ public class StandardPersistentAttributeMemberResolver extends AbstractPersisten
|
||||||
BiConsumer<String,MemberDetails> memberConsumer,
|
BiConsumer<String,MemberDetails> memberConsumer,
|
||||||
Function<FieldDetails,Boolean> transientFieldChecker,
|
Function<FieldDetails,Boolean> transientFieldChecker,
|
||||||
Function<MethodDetails,Boolean> transientMethodChecker,
|
Function<MethodDetails,Boolean> transientMethodChecker,
|
||||||
ClassDetails classDetails,
|
ClassDetails classDetails) {
|
||||||
ModelCategorizationContext processingContext) {
|
|
||||||
final List<FieldDetails> fields = classDetails.getFields();
|
final List<FieldDetails> fields = classDetails.getFields();
|
||||||
for ( int i = 0; i < fields.size(); i++ ) {
|
for ( int i = 0; i < fields.size(); i++ ) {
|
||||||
final FieldDetails fieldDetails = fields.get( i );
|
final FieldDetails fieldDetails = fields.get( i );
|
||||||
processAttributeLevelAccessMember( fieldDetails, memberConsumer, transientFieldChecker, classDetails, processingContext );
|
processAttributeLevelAccessMember( fieldDetails, memberConsumer, transientFieldChecker, classDetails );
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<MethodDetails> methods = classDetails.getMethods();
|
final List<MethodDetails> methods = classDetails.getMethods();
|
||||||
for ( int i = 0; i < methods.size(); i++ ) {
|
for ( int i = 0; i < methods.size(); i++ ) {
|
||||||
final MethodDetails methodDetails = methods.get( i );
|
final MethodDetails methodDetails = methods.get( i );
|
||||||
processAttributeLevelAccessMember( methodDetails, memberConsumer, transientMethodChecker, classDetails, processingContext );
|
processAttributeLevelAccessMember( methodDetails, memberConsumer, transientMethodChecker, classDetails );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,8 +87,7 @@ public class StandardPersistentAttributeMemberResolver extends AbstractPersisten
|
||||||
M memberDetails,
|
M memberDetails,
|
||||||
BiConsumer<String,MemberDetails> memberConsumer,
|
BiConsumer<String,MemberDetails> memberConsumer,
|
||||||
Function<M,Boolean> transiencyChecker,
|
Function<M,Boolean> transiencyChecker,
|
||||||
ClassDetails classDetails,
|
ClassDetails classDetails) {
|
||||||
ModelCategorizationContext processingContext) {
|
|
||||||
final AnnotationUsage<Access> access = memberDetails.getAnnotationUsage( JpaAnnotations.ACCESS );
|
final AnnotationUsage<Access> access = memberDetails.getAnnotationUsage( JpaAnnotations.ACCESS );
|
||||||
if ( access == null ) {
|
if ( access == null ) {
|
||||||
return;
|
return;
|
||||||
|
@ -100,12 +95,7 @@ public class StandardPersistentAttributeMemberResolver extends AbstractPersisten
|
||||||
|
|
||||||
final AccessType attributeAccessType = access.getAttributeValue( "value" );
|
final AccessType attributeAccessType = access.getAttributeValue( "value" );
|
||||||
|
|
||||||
validateAttributeLevelAccess(
|
validateAttributeLevelAccess( memberDetails, attributeAccessType, classDetails );
|
||||||
memberDetails,
|
|
||||||
attributeAccessType,
|
|
||||||
classDetails,
|
|
||||||
processingContext
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( transiencyChecker.apply( memberDetails ) ) {
|
if ( transiencyChecker.apply( memberDetails ) ) {
|
||||||
// the field is @Transient
|
// the field is @Transient
|
||||||
|
@ -118,8 +108,7 @@ public class StandardPersistentAttributeMemberResolver extends AbstractPersisten
|
||||||
private void validateAttributeLevelAccess(
|
private void validateAttributeLevelAccess(
|
||||||
MemberDetails annotationTarget,
|
MemberDetails annotationTarget,
|
||||||
AccessType attributeAccessType,
|
AccessType attributeAccessType,
|
||||||
ClassDetails classDetails,
|
ClassDetails classDetails) {
|
||||||
ModelCategorizationContext processingContext) {
|
|
||||||
// Apply the checks defined in section `2.3.2 Explicit Access Type` of the persistence specification
|
// Apply the checks defined in section `2.3.2 Explicit Access Type` of the persistence specification
|
||||||
|
|
||||||
// Mainly, it is never legal to:
|
// Mainly, it is never legal to:
|
||||||
|
@ -138,8 +127,7 @@ public class StandardPersistentAttributeMemberResolver extends AbstractPersisten
|
||||||
Function<FieldDetails,Boolean> transientFieldChecker,
|
Function<FieldDetails,Boolean> transientFieldChecker,
|
||||||
Function<MethodDetails,Boolean> transientMethodChecker,
|
Function<MethodDetails,Boolean> transientMethodChecker,
|
||||||
ClassDetails classDetails,
|
ClassDetails classDetails,
|
||||||
AccessType classLevelAccessType,
|
AccessType classLevelAccessType) {
|
||||||
@SuppressWarnings("unused") ModelCategorizationContext processingContext) {
|
|
||||||
if ( classLevelAccessType == AccessType.FIELD ) {
|
if ( classLevelAccessType == AccessType.FIELD ) {
|
||||||
final List<FieldDetails> fields = classDetails.getFields();
|
final List<FieldDetails> fields = classDetails.getFields();
|
||||||
for ( int i = 0; i < fields.size(); i++ ) {
|
for ( int i = 0; i < fields.size(); i++ ) {
|
||||||
|
|
|
@ -33,14 +33,12 @@ public interface PersistentAttributeMemberResolver {
|
||||||
* @param classDetails Descriptor of the class
|
* @param classDetails Descriptor of the class
|
||||||
* @param classLevelAccessType The implicit AccessType
|
* @param classLevelAccessType The implicit AccessType
|
||||||
* @param allMemberConsumer Optional callback for each member on the class
|
* @param allMemberConsumer Optional callback for each member on the class
|
||||||
* @param buildingContext The local context
|
|
||||||
*
|
*
|
||||||
* @return The list of "backing members"
|
* @return The list of "backing members"
|
||||||
*/
|
*/
|
||||||
List<MemberDetails> resolveAttributesMembers(
|
List<MemberDetails> resolveAttributesMembers(
|
||||||
ClassDetails classDetails,
|
ClassDetails classDetails,
|
||||||
AccessType classLevelAccessType,
|
AccessType classLevelAccessType,
|
||||||
AllMemberConsumer allMemberConsumer,
|
AllMemberConsumer allMemberConsumer);
|
||||||
ModelCategorizationContext buildingContext);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.boot.models.bind.id;
|
||||||
|
|
||||||
|
import org.hibernate.mapping.KeyValue;
|
||||||
|
import org.hibernate.mapping.PrimaryKey;
|
||||||
|
import org.hibernate.mapping.RootClass;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistryScope;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.hibernate.orm.test.boot.models.bind.BindingTestingHelper.checkDomainModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@ServiceRegistry
|
||||||
|
@SuppressWarnings("JUnitMalformedDeclaration")
|
||||||
|
public class IdBindingTests {
|
||||||
|
@Test
|
||||||
|
void testBasicId(ServiceRegistryScope scope) {
|
||||||
|
checkDomainModel(
|
||||||
|
(context) -> {
|
||||||
|
final var metadataCollector = context.getMetadataCollector();
|
||||||
|
final RootClass rootBinding = (RootClass) metadataCollector.getEntityBinding( BasicIdEntity.class.getName() );
|
||||||
|
|
||||||
|
final PrimaryKey primaryKey = rootBinding.getIdentityTable().getPrimaryKey();
|
||||||
|
final KeyValue identifier = rootBinding.getIdentifier();
|
||||||
|
|
||||||
|
assertThat( primaryKey.getColumns() ).hasSize( 1 );
|
||||||
|
assertThat( identifier.getColumns() ).hasSize( 1 );
|
||||||
|
assertThat( identifier.getColumns().get( 0 ) ).isSameAs( primaryKey.getColumns().get( 0 ) );
|
||||||
|
assertThat( identifier.getColumns().get( 0 ).getName() ).isEqualToIgnoringCase( "id" );
|
||||||
|
},
|
||||||
|
scope.getRegistry(),
|
||||||
|
BasicIdEntity.class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@FailureExpected(reason = "Embeddables not yet supported")
|
||||||
|
void testAggregatedId(ServiceRegistryScope scope) {
|
||||||
|
checkDomainModel(
|
||||||
|
(context) -> {
|
||||||
|
final var metadataCollector = context.getMetadataCollector();
|
||||||
|
final RootClass rootBinding = (RootClass) metadataCollector.getEntityBinding( AggregatedIdEntity.class.getName() );
|
||||||
|
|
||||||
|
final PrimaryKey primaryKey = rootBinding.getIdentityTable().getPrimaryKey();
|
||||||
|
final KeyValue identifier = rootBinding.getIdentifier();
|
||||||
|
|
||||||
|
assertThat( primaryKey.getColumns() ).hasSize( 2 );
|
||||||
|
assertThat( identifier.getColumns() ).hasSize( 2 );
|
||||||
|
assertThat( identifier.getColumns() ).containsAll( primaryKey.getColumns() );
|
||||||
|
},
|
||||||
|
scope.getRegistry(),
|
||||||
|
AggregatedIdEntity.class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,10 +33,6 @@ import static org.hibernate.orm.test.boot.models.bind.BindingTestingHelper.check
|
||||||
@SuppressWarnings("JUnitMalformedDeclaration")
|
@SuppressWarnings("JUnitMalformedDeclaration")
|
||||||
public class JoinedTests {
|
public class JoinedTests {
|
||||||
@Test
|
@Test
|
||||||
// @FailureExpected(
|
|
||||||
// reason = "Binding the primary key is done twice by 2 'owners' overwriting details. " +
|
|
||||||
// "Might be case for distinct, sequential root key and secondary key (secondary tables, subclass tables) table phases."
|
|
||||||
// )
|
|
||||||
void simpleTest(ServiceRegistryScope scope) {
|
void simpleTest(ServiceRegistryScope scope) {
|
||||||
checkDomainModel(
|
checkDomainModel(
|
||||||
(context) -> {
|
(context) -> {
|
||||||
|
|
Loading…
Reference in New Issue