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
|
||||
*/
|
||||
public abstract class IdentifiableTypeBinding extends ManagedTypeBinding {
|
||||
protected final IdentifiableTypeMetadata typeMetadata;
|
||||
protected final IdentifiableTypeBinding superTypeBinding;
|
||||
protected final IdentifiableTypeMetadata superTypeMetadata;
|
||||
|
||||
|
@ -39,7 +40,8 @@ public abstract class IdentifiableTypeBinding extends ManagedTypeBinding {
|
|||
BindingOptions bindingOptions,
|
||||
BindingState bindingState,
|
||||
BindingContext bindingContext) {
|
||||
super( typeMetadata, bindingOptions, bindingState, bindingContext );
|
||||
super( typeMetadata.getClassDetails(), bindingOptions, bindingState, bindingContext );
|
||||
this.typeMetadata = typeMetadata;
|
||||
this.superTypeBinding = superTypeBinding;
|
||||
this.superTypeMetadata = superTypeBinding == null ? null : superTypeBinding.getTypeMetadata();
|
||||
|
||||
|
@ -47,9 +49,8 @@ public abstract class IdentifiableTypeBinding extends ManagedTypeBinding {
|
|||
this.attributeBindings = CollectionHelper.linkedMapOfSize( typeMetadata.getNumberOfAttributes() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentifiableTypeMetadata getTypeMetadata() {
|
||||
return (IdentifiableTypeMetadata) super.getTypeMetadata();
|
||||
return typeMetadata;
|
||||
}
|
||||
|
||||
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.BindingOptions;
|
||||
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}
|
||||
|
@ -19,19 +19,19 @@ import org.hibernate.boot.models.categorize.spi.ManagedTypeMetadata;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class ManagedTypeBinding extends Binding {
|
||||
protected final ManagedTypeMetadata typeMetadata;
|
||||
protected final ClassDetails classDetails;
|
||||
|
||||
public ManagedTypeBinding(
|
||||
ManagedTypeMetadata typeMetadata,
|
||||
ClassDetails classDetails,
|
||||
BindingOptions bindingOptions,
|
||||
BindingState bindingState,
|
||||
BindingContext bindingContext) {
|
||||
super( bindingOptions, bindingState, bindingContext );
|
||||
this.typeMetadata = typeMetadata;
|
||||
this.classDetails = classDetails;
|
||||
}
|
||||
|
||||
public ManagedTypeMetadata getTypeMetadata() {
|
||||
return typeMetadata;
|
||||
public ClassDetails getClassDetails() {
|
||||
return classDetails;
|
||||
}
|
||||
|
||||
public abstract Map<String, AttributeBinding> getAttributeBindings();
|
||||
|
|
|
@ -12,7 +12,6 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
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.IdentifiableTypeMetadata;
|
||||
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.ClassDetailsRegistry;
|
||||
|
||||
import jakarta.persistence.Access;
|
||||
import jakarta.persistence.AccessType;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.ExcludeDefaultListeners;
|
||||
|
@ -56,7 +54,7 @@ public abstract class AbstractIdentifiableTypeMetadata
|
|||
this.hierarchy = hierarchy;
|
||||
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.superType = superType;
|
||||
|
||||
this.accessType = determineAccessType( superType.getAccessType() );
|
||||
this.accessType = CategorizationHelper.determineAccessType( classDetails, superType.getAccessType() );
|
||||
}
|
||||
|
||||
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) {
|
||||
subTypes.add( subclass );
|
||||
}
|
||||
|
|
|
@ -7,37 +7,20 @@
|
|||
package org.hibernate.boot.models.categorize.internal;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
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.AttributeRole;
|
||||
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.AttributeMetadata;
|
||||
import org.hibernate.boot.models.categorize.spi.ManagedTypeMetadata;
|
||||
import org.hibernate.boot.models.categorize.spi.ModelCategorizationContext;
|
||||
import org.hibernate.internal.util.IndexedConsumer;
|
||||
import org.hibernate.models.spi.AnnotationUsage;
|
||||
import org.hibernate.models.spi.ClassDetails;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -151,14 +134,14 @@ public abstract class AbstractManagedTypeMetadata implements ManagedTypeMetadata
|
|||
protected List<AttributeMetadata> resolveAttributes(AllMemberConsumer memberConsumer) {
|
||||
final List<MemberDetails> backingMembers = getModelContext()
|
||||
.getPersistentAttributeMemberResolver()
|
||||
.resolveAttributesMembers( classDetails, getAccessType(), memberConsumer, modelContext );
|
||||
.resolveAttributesMembers( classDetails, getAccessType(), memberConsumer );
|
||||
|
||||
final List<AttributeMetadata> attributeList = arrayList( backingMembers.size() );
|
||||
|
||||
for ( MemberDetails backingMember : backingMembers ) {
|
||||
final AttributeMetadata attribute = new AttributeMetadataImpl(
|
||||
backingMember.resolveAttributeName(),
|
||||
determineAttributeNature( backingMember ),
|
||||
CategorizationHelper.determineAttributeNature( backingMember ),
|
||||
backingMember
|
||||
);
|
||||
attributeList.add( attribute );
|
||||
|
@ -167,114 +150,6 @@ public abstract class AbstractManagedTypeMetadata implements ManagedTypeMetadata
|
|||
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
|
||||
// public <A extends Annotation> List<AnnotationUsage<A>> findAnnotations(AnnotationDescriptor<A> 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.categorize.spi.AllMemberConsumer;
|
||||
import org.hibernate.boot.models.categorize.spi.ModelCategorizationContext;
|
||||
import org.hibernate.boot.models.categorize.spi.PersistentAttributeMemberResolver;
|
||||
import org.hibernate.models.spi.ClassDetails;
|
||||
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 classDetails The Jandex ClassInfo describing the type for which to resolve members
|
||||
* @param classLevelAccessType The AccessType determined for the class default
|
||||
* @param processingContext The local context
|
||||
*/
|
||||
protected abstract List<MemberDetails> resolveAttributesMembers(
|
||||
Function<FieldDetails,Boolean> transientFieldChecker,
|
||||
Function<MethodDetails,Boolean> transientMethodChecker,
|
||||
ClassDetails classDetails,
|
||||
AccessType classLevelAccessType,
|
||||
ModelCategorizationContext processingContext);
|
||||
AccessType classLevelAccessType);
|
||||
|
||||
@Override
|
||||
public List<MemberDetails> resolveAttributesMembers(
|
||||
ClassDetails classDetails,
|
||||
AccessType classLevelAccessType,
|
||||
AllMemberConsumer memberConsumer,
|
||||
ModelCategorizationContext processingContext) {
|
||||
AllMemberConsumer memberConsumer) {
|
||||
|
||||
final Set<FieldDetails> transientFields = new HashSet<>();
|
||||
final Set<MethodDetails> transientMethods = new HashSet<>();
|
||||
|
@ -67,16 +63,14 @@ public abstract class AbstractPersistentAttributeMemberResolver implements Persi
|
|||
transientFields::add,
|
||||
transientMethods::add,
|
||||
classDetails,
|
||||
memberConsumer,
|
||||
processingContext
|
||||
memberConsumer
|
||||
);
|
||||
|
||||
return resolveAttributesMembers(
|
||||
transientFields::contains,
|
||||
transientMethods::contains,
|
||||
classDetails,
|
||||
classLevelAccessType,
|
||||
processingContext
|
||||
classLevelAccessType
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -84,8 +78,7 @@ public abstract class AbstractPersistentAttributeMemberResolver implements Persi
|
|||
final Consumer<FieldDetails> transientFieldConsumer,
|
||||
final Consumer<MethodDetails> transientMethodConsumer,
|
||||
ClassDetails classDetails,
|
||||
AllMemberConsumer memberConsumer,
|
||||
@SuppressWarnings("unused") ModelCategorizationContext processingContext) {
|
||||
AllMemberConsumer memberConsumer) {
|
||||
final List<FieldDetails> fields = classDetails.getFields();
|
||||
for ( int i = 0; i < fields.size(); i++ ) {
|
||||
final FieldDetails fieldDetails = fields.get( i );
|
||||
|
|
|
@ -6,8 +6,29 @@
|
|||
*/
|
||||
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.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.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
|
||||
|
@ -24,4 +45,117 @@ public class CategorizationHelper {
|
|||
public static boolean isIdentifiable(ClassDetails 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<MethodDetails,Boolean> transientMethodChecker,
|
||||
ClassDetails classDetails,
|
||||
AccessType classLevelAccessType,
|
||||
ModelCategorizationContext processingContext) {
|
||||
AccessType classLevelAccessType) {
|
||||
assert classLevelAccessType != null;
|
||||
|
||||
final LinkedHashMap<String,MemberDetails> results = new LinkedHashMap<>();
|
||||
|
@ -51,8 +50,7 @@ public class StandardPersistentAttributeMemberResolver extends AbstractPersisten
|
|||
results::put,
|
||||
transientFieldChecker,
|
||||
transientMethodChecker,
|
||||
classDetails,
|
||||
processingContext
|
||||
classDetails
|
||||
);
|
||||
|
||||
processClassLevelAccess(
|
||||
|
@ -61,8 +59,7 @@ public class StandardPersistentAttributeMemberResolver extends AbstractPersisten
|
|||
transientFieldChecker,
|
||||
transientMethodChecker,
|
||||
classDetails,
|
||||
classLevelAccessType,
|
||||
processingContext
|
||||
classLevelAccessType
|
||||
);
|
||||
|
||||
return new ArrayList<>( results.values() );
|
||||
|
@ -72,18 +69,17 @@ public class StandardPersistentAttributeMemberResolver extends AbstractPersisten
|
|||
BiConsumer<String,MemberDetails> memberConsumer,
|
||||
Function<FieldDetails,Boolean> transientFieldChecker,
|
||||
Function<MethodDetails,Boolean> transientMethodChecker,
|
||||
ClassDetails classDetails,
|
||||
ModelCategorizationContext processingContext) {
|
||||
ClassDetails classDetails) {
|
||||
final List<FieldDetails> fields = classDetails.getFields();
|
||||
for ( int i = 0; i < fields.size(); i++ ) {
|
||||
final FieldDetails fieldDetails = fields.get( i );
|
||||
processAttributeLevelAccessMember( fieldDetails, memberConsumer, transientFieldChecker, classDetails, processingContext );
|
||||
processAttributeLevelAccessMember( fieldDetails, memberConsumer, transientFieldChecker, classDetails );
|
||||
}
|
||||
|
||||
final List<MethodDetails> methods = classDetails.getMethods();
|
||||
for ( int i = 0; i < methods.size(); 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,
|
||||
BiConsumer<String,MemberDetails> memberConsumer,
|
||||
Function<M,Boolean> transiencyChecker,
|
||||
ClassDetails classDetails,
|
||||
ModelCategorizationContext processingContext) {
|
||||
ClassDetails classDetails) {
|
||||
final AnnotationUsage<Access> access = memberDetails.getAnnotationUsage( JpaAnnotations.ACCESS );
|
||||
if ( access == null ) {
|
||||
return;
|
||||
|
@ -100,12 +95,7 @@ public class StandardPersistentAttributeMemberResolver extends AbstractPersisten
|
|||
|
||||
final AccessType attributeAccessType = access.getAttributeValue( "value" );
|
||||
|
||||
validateAttributeLevelAccess(
|
||||
memberDetails,
|
||||
attributeAccessType,
|
||||
classDetails,
|
||||
processingContext
|
||||
);
|
||||
validateAttributeLevelAccess( memberDetails, attributeAccessType, classDetails );
|
||||
|
||||
if ( transiencyChecker.apply( memberDetails ) ) {
|
||||
// the field is @Transient
|
||||
|
@ -118,8 +108,7 @@ public class StandardPersistentAttributeMemberResolver extends AbstractPersisten
|
|||
private void validateAttributeLevelAccess(
|
||||
MemberDetails annotationTarget,
|
||||
AccessType attributeAccessType,
|
||||
ClassDetails classDetails,
|
||||
ModelCategorizationContext processingContext) {
|
||||
ClassDetails classDetails) {
|
||||
// Apply the checks defined in section `2.3.2 Explicit Access Type` of the persistence specification
|
||||
|
||||
// Mainly, it is never legal to:
|
||||
|
@ -138,8 +127,7 @@ public class StandardPersistentAttributeMemberResolver extends AbstractPersisten
|
|||
Function<FieldDetails,Boolean> transientFieldChecker,
|
||||
Function<MethodDetails,Boolean> transientMethodChecker,
|
||||
ClassDetails classDetails,
|
||||
AccessType classLevelAccessType,
|
||||
@SuppressWarnings("unused") ModelCategorizationContext processingContext) {
|
||||
AccessType classLevelAccessType) {
|
||||
if ( classLevelAccessType == AccessType.FIELD ) {
|
||||
final List<FieldDetails> fields = classDetails.getFields();
|
||||
for ( int i = 0; i < fields.size(); i++ ) {
|
||||
|
|
|
@ -33,14 +33,12 @@ public interface PersistentAttributeMemberResolver {
|
|||
* @param classDetails Descriptor of the class
|
||||
* @param classLevelAccessType The implicit AccessType
|
||||
* @param allMemberConsumer Optional callback for each member on the class
|
||||
* @param buildingContext The local context
|
||||
*
|
||||
* @return The list of "backing members"
|
||||
*/
|
||||
List<MemberDetails> resolveAttributesMembers(
|
||||
ClassDetails classDetails,
|
||||
AccessType classLevelAccessType,
|
||||
AllMemberConsumer allMemberConsumer,
|
||||
ModelCategorizationContext buildingContext);
|
||||
AllMemberConsumer allMemberConsumer);
|
||||
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
public class JoinedTests {
|
||||
@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) {
|
||||
checkDomainModel(
|
||||
(context) -> {
|
||||
|
|
Loading…
Reference in New Issue