Skip to content

Commit

Permalink
HHH-17504 - Ongoing JPA 32 work
Browse files Browse the repository at this point in the history
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
  • Loading branch information
sebersole committed Mar 28, 2024
1 parent 0b8c08a commit 5993495
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 191 deletions.
Expand Up @@ -27,6 +27,7 @@
* @author Steve Ebersole
*/
public abstract class IdentifiableTypeBinding extends ManagedTypeBinding {
protected final IdentifiableTypeMetadata typeMetadata;
protected final IdentifiableTypeBinding superTypeBinding;
protected final IdentifiableTypeMetadata superTypeMetadata;

Expand All @@ -39,17 +40,17 @@ public IdentifiableTypeBinding(
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();

// NOTE: slightly over-sized (id, version, ...), but that's ok
this.attributeBindings = CollectionHelper.linkedMapOfSize( typeMetadata.getNumberOfAttributes() );
}

@Override
public IdentifiableTypeMetadata getTypeMetadata() {
return (IdentifiableTypeMetadata) super.getTypeMetadata();
return typeMetadata;
}

public IdentifiableTypeMetadata getSuperTypeMetadata() {
Expand Down
Expand Up @@ -11,27 +11,27 @@
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}
*
* @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();
Expand Down
Expand Up @@ -12,7 +12,6 @@
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;
Expand All @@ -23,7 +22,6 @@
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;
Expand Down Expand Up @@ -56,7 +54,7 @@ public AbstractIdentifiableTypeMetadata(
this.hierarchy = hierarchy;
this.superType = null;

this.accessType = determineAccessType( accessType );
this.accessType = CategorizationHelper.determineAccessType( classDetails, accessType );
}


Expand All @@ -72,7 +70,7 @@ public AbstractIdentifiableTypeMetadata(
this.hierarchy = hierarchy;
this.superType = superType;

this.accessType = determineAccessType( superType.getAccessType() );
this.accessType = CategorizationHelper.determineAccessType( classDetails, superType.getAccessType() );
}

protected void postInstantiate(HierarchyTypeConsumer typeConsumer) {
Expand Down Expand Up @@ -124,15 +122,6 @@ else if ( CategorizationHelper.isMappedSuperclass( subClassDetails ) ) {

}

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 );
}
Expand Down
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -151,14 +134,14 @@ public void forEachAttribute(IndexedConsumer<AttributeMetadata> consumer) {
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 );
Expand All @@ -167,115 +150,7 @@ protected List<AttributeMetadata> resolveAttributes(AllMemberConsumer memberCons
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) {
// return classDetails.getAnnotations( type );
// }
Expand Down
Expand Up @@ -14,7 +14,6 @@

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;
Expand Down Expand Up @@ -45,47 +44,41 @@ 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<>();
collectMembersMarkedTransient(
transientFields::add,
transientMethods::add,
classDetails,
memberConsumer,
processingContext
memberConsumer
);

return resolveAttributesMembers(
transientFields::contains,
transientMethods::contains,
classDetails,
classLevelAccessType,
processingContext
classLevelAccessType
);
}

protected void collectMembersMarkedTransient(
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 );
Expand Down

0 comments on commit 5993495

Please sign in to comment.