Skip to content

Commit

Permalink
#56 - Collect JPA listeners on IdentifiableTypeMetadata
Browse files Browse the repository at this point in the history
  • Loading branch information
sebersole committed Oct 31, 2023
1 parent 034987d commit dc9f72d
Show file tree
Hide file tree
Showing 21 changed files with 349 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,28 @@
*/
package org.hibernate.models.orm.categorize.internal;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;

import org.hibernate.models.internal.CollectionHelper;
import org.hibernate.models.orm.JpaAnnotations;
import org.hibernate.models.orm.categorize.spi.EntityHierarchy;
import org.hibernate.models.orm.categorize.spi.IdentifiableTypeMetadata;
import org.hibernate.models.orm.categorize.spi.JpaEventListener;
import org.hibernate.models.orm.categorize.spi.JpaEventListenerStyle;
import org.hibernate.models.orm.categorize.spi.ModelCategorizationContext;
import org.hibernate.models.source.spi.AnnotationUsage;
import org.hibernate.models.source.spi.ClassDetails;
import org.hibernate.models.source.spi.ClassDetailsRegistry;

import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.ExcludeDefaultListeners;
import jakarta.persistence.ExcludeSuperclassListeners;


/**
Expand All @@ -31,7 +39,6 @@ public abstract class AbstractIdentifiableTypeMetadata
private final EntityHierarchy hierarchy;
private final AbstractIdentifiableTypeMetadata superType;
private final Set<IdentifiableTypeMetadata> subTypes = new HashSet<>();

private final AccessType accessType;

/**
Expand Down Expand Up @@ -184,4 +191,55 @@ protected void collectAttributeOverrides() {
protected void collectAssociationOverrides() {
// we only need to do this on root
}

protected List<JpaEventListener> collectHierarchyEventListeners(JpaEventListener localCallback) {
final ClassDetails classDetails = getClassDetails();

final List<JpaEventListener> combined = new ArrayList<>();

if ( classDetails.getAnnotationUsage( ExcludeSuperclassListeners.class ) == null ) {
final IdentifiableTypeMetadata superType = getSuperType();
if ( superType != null ) {
combined.addAll( superType.getHierarchyJpaEventListeners() );
}
}

applyLocalEventListeners( combined::add );

if ( localCallback != null ) {
combined.add( localCallback );
}

return combined;
}

private void applyLocalEventListeners(Consumer<JpaEventListener> consumer) {
final ClassDetails classDetails = getClassDetails();

final AnnotationUsage<EntityListeners> entityListenersAnnotation = classDetails.getAnnotationUsage( EntityListeners.class );
if ( entityListenersAnnotation == null ) {
return;
}

final List<ClassDetails> entityListenerClasses = entityListenersAnnotation.getAttributeValue( "value" );
if ( CollectionHelper.isEmpty( entityListenerClasses ) ) {
return;
}

entityListenerClasses.forEach( (listenerClass) -> {
consumer.accept( JpaEventListener.from( JpaEventListenerStyle.LISTENER, listenerClass ) );
} );
}

protected List<JpaEventListener> collectCompleteEventListeners(ModelCategorizationContext modelContext) {
final ClassDetails classDetails = getClassDetails();
if ( classDetails.getAnnotationUsage( ExcludeDefaultListeners.class ) != null ) {
return getHierarchyJpaEventListeners();
}

final List<JpaEventListener> combined = new ArrayList<>();
combined.addAll( modelContext.getDefaultEventListeners() );
combined.addAll( getHierarchyJpaEventListeners() );
return combined;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.hibernate.models.orm.HibernateAnnotations;
import org.hibernate.models.orm.JpaAnnotations;
import org.hibernate.models.orm.MultipleAttributeNaturesException;
import org.hibernate.models.orm.categorize.spi.AllMemberConsumer;
import org.hibernate.models.orm.categorize.spi.AttributeMetadata;
import org.hibernate.models.orm.categorize.spi.ManagedTypeMetadata;
import org.hibernate.models.orm.categorize.spi.ModelCategorizationContext;
Expand Down Expand Up @@ -147,10 +148,10 @@ public void forEachAttribute(IndexedConsumer<AttributeMetadata> consumer) {
}
}

protected List<AttributeMetadata> resolveAttributes() {
protected List<AttributeMetadata> resolveAttributes(AllMemberConsumer memberConsumer) {
final List<MemberDetails> backingMembers = getModelContext()
.getPersistentAttributeMemberResolver()
.resolveAttributesMembers( classDetails, getAccessType(), modelContext );
.resolveAttributesMembers( classDetails, getAccessType(), memberConsumer, modelContext );

final List<AttributeMetadata> attributeList = arrayList( backingMembers.size() );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.function.Function;

import org.hibernate.models.orm.JpaAnnotations;
import org.hibernate.models.orm.categorize.spi.AllMemberConsumer;
import org.hibernate.models.orm.categorize.spi.ModelCategorizationContext;
import org.hibernate.models.orm.categorize.spi.PersistentAttributeMemberResolver;
import org.hibernate.models.source.spi.ClassDetails;
Expand Down Expand Up @@ -57,6 +58,7 @@ protected abstract List<MemberDetails> resolveAttributesMembers(
public List<MemberDetails> resolveAttributesMembers(
ClassDetails classDetails,
AccessType classLevelAccessType,
AllMemberConsumer memberConsumer,
ModelCategorizationContext processingContext) {

final Set<FieldDetails> transientFields = new HashSet<>();
Expand All @@ -65,6 +67,7 @@ public List<MemberDetails> resolveAttributesMembers(
transientFields::add,
transientMethods::add,
classDetails,
memberConsumer,
processingContext
);

Expand All @@ -81,10 +84,12 @@ protected void collectMembersMarkedTransient(
final Consumer<FieldDetails> transientFieldConsumer,
final Consumer<MethodDetails> transientMethodConsumer,
ClassDetails classDetails,
AllMemberConsumer memberConsumer,
@SuppressWarnings("unused") ModelCategorizationContext processingContext) {
final List<FieldDetails> fields = classDetails.getFields();
for ( int i = 0; i < fields.size(); i++ ) {
final FieldDetails fieldDetails = fields.get( i );
memberConsumer.acceptMember( fieldDetails );
if ( fieldDetails.getAnnotationUsage( JpaAnnotations.TRANSIENT ) != null ) {
transientFieldConsumer.accept( fieldDetails );
}
Expand All @@ -93,6 +98,7 @@ protected void collectMembersMarkedTransient(
final List<MethodDetails> methods = classDetails.getMethods();
for ( int i = 0; i < methods.size(); i++ ) {
final MethodDetails methodDetails = methods.get( i );
memberConsumer.acceptMember( methodDetails );
if ( methodDetails.getAnnotationUsage( JpaAnnotations.TRANSIENT ) != null ) {
transientMethodConsumer.accept( methodDetails );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@
import org.hibernate.models.source.spi.AnnotationUsage;
import org.hibernate.models.source.spi.ClassDetails;

import jakarta.persistence.Entity;
import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType;
import jakarta.persistence.MappedSuperclass;

import static org.hibernate.models.orm.categorize.ModelCategorizationLogging.MODEL_CATEGORIZATION_LOGGER;

Expand All @@ -37,7 +35,7 @@
* @author Steve Ebersole
*/
public class EntityHierarchyImpl implements EntityHierarchy {
private final IdentifiableTypeMetadata rootRootTypeMetadata;
private final IdentifiableTypeMetadata absoluteRootTypeMetadata;
private final EntityTypeMetadata rootEntityTypeMetadata;

private final InheritanceType inheritanceType;
Expand All @@ -56,22 +54,22 @@ public EntityHierarchyImpl(
AccessType defaultCacheAccessType,
HierarchyTypeConsumer typeConsumer,
ModelCategorizationContext modelBuildingContext) {
final ClassDetails rootRoot = findRootRoot( rootEntityClassDetails );
final ClassDetails absoluteRootClassDetails = findRootRoot( rootEntityClassDetails );
final HierarchyMetadataCollector metadataCollector = new HierarchyMetadataCollector( this, rootEntityClassDetails, typeConsumer );

if ( CategorizationHelper.isEntity( rootRoot ) ) {
this.rootRootTypeMetadata = new EntityTypeMetadataImpl(
rootRoot,
if ( CategorizationHelper.isEntity( absoluteRootClassDetails ) ) {
this.absoluteRootTypeMetadata = new EntityTypeMetadataImpl(
absoluteRootClassDetails,
this,
defaultAccessType,
metadataCollector,
modelBuildingContext
);
}
else {
assert CategorizationHelper.isMappedSuperclass( rootRoot );
this.rootRootTypeMetadata = new MappedSuperclassTypeMetadataImpl(
rootRoot,
assert CategorizationHelper.isMappedSuperclass( absoluteRootClassDetails );
this.absoluteRootTypeMetadata = new MappedSuperclassTypeMetadataImpl(
absoluteRootClassDetails,
this,
defaultAccessType,
metadataCollector,
Expand Down Expand Up @@ -126,8 +124,8 @@ public EntityTypeMetadata getRoot() {
}

@Override
public IdentifiableTypeMetadata getRootRoot() {
return rootRootTypeMetadata;
public IdentifiableTypeMetadata getAbsoluteRoot() {
return absoluteRootTypeMetadata;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import org.hibernate.models.orm.categorize.spi.AttributeMetadata;
import org.hibernate.models.orm.categorize.spi.EntityHierarchy;
import org.hibernate.models.orm.categorize.spi.EntityTypeMetadata;
import org.hibernate.models.orm.categorize.spi.IdentifiableTypeMetadata;
import org.hibernate.models.orm.categorize.spi.JpaEventListener;
import org.hibernate.models.orm.categorize.spi.ModelCategorizationContext;
import org.hibernate.models.source.spi.AnnotationUsage;
import org.hibernate.models.source.spi.ClassDetails;
Expand Down Expand Up @@ -65,6 +65,9 @@ public class EntityTypeMetadataImpl
private final CustomSql customDelete;
private final String[] synchronizedTableNames;

private List<JpaEventListener> hierarchyEventListeners;
private List<JpaEventListener> completeEventListeners;

public EntityTypeMetadataImpl(
ClassDetails classDetails,
EntityHierarchy hierarchy,
Expand All @@ -81,7 +84,10 @@ public EntityTypeMetadataImpl(
final AnnotationUsage<Entity> entityAnnotation = classDetails.getAnnotationUsage( JpaAnnotations.ENTITY );
this.jpaEntityName = determineJpaEntityName( entityAnnotation, entityName );

this.attributeList = resolveAttributes();
final LifecycleCallbackCollector lifecycleCallbackCollector = new LifecycleCallbackCollector( classDetails, modelContext );
this.attributeList = resolveAttributes( lifecycleCallbackCollector );
this.hierarchyEventListeners = collectHierarchyEventListeners( lifecycleCallbackCollector.resolve() );
this.completeEventListeners = collectCompleteEventListeners( modelContext );

this.mutable = determineMutability( classDetails, modelContext );
this.cacheable = determineCacheability( classDetails, modelContext );
Expand Down Expand Up @@ -146,7 +152,10 @@ public EntityTypeMetadataImpl(
final AnnotationUsage<Entity> entityAnnotation = classDetails.getAnnotationUsage( JpaAnnotations.ENTITY );
this.jpaEntityName = determineJpaEntityName( entityAnnotation, entityName );

this.attributeList = resolveAttributes();
final LifecycleCallbackCollector lifecycleCallbackCollector = new LifecycleCallbackCollector( classDetails, modelContext );
this.attributeList = resolveAttributes( lifecycleCallbackCollector );
this.hierarchyEventListeners = collectHierarchyEventListeners( lifecycleCallbackCollector.resolve() );
this.completeEventListeners = collectCompleteEventListeners( modelContext );

this.mutable = determineMutability( classDetails, modelContext );
this.cacheable = determineCacheability( classDetails, modelContext );
Expand Down Expand Up @@ -277,6 +286,16 @@ public String getProxy() {
return proxy;
}

@Override
public List<JpaEventListener> getHierarchyJpaEventListeners() {
return hierarchyEventListeners;
}

@Override
public List<JpaEventListener> getCompleteJpaEventListeners() {
return completeEventListeners;
}


private String determineJpaEntityName(AnnotationUsage<Entity> entityAnnotation, String entityName) {
final String name = entityAnnotation.getAttributeValue( "name" );
Expand Down
Loading

0 comments on commit dc9f72d

Please sign in to comment.