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 Dec 7, 2023
1 parent e755c74 commit 9562b8c
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 191 deletions.
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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 9562b8c

Please sign in to comment.