Skip to content

Commit

Permalink
HHH-17460 - Ongoing JPA 32 work
Browse files Browse the repository at this point in the history
  • Loading branch information
sebersole committed Apr 3, 2024
1 parent 36ea140 commit d1d8148
Show file tree
Hide file tree
Showing 15 changed files with 971 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,11 @@ public static class MetadataBuildingOptionsImpl
private final boolean xmlMappingEnabled;
private final boolean allowExtensionsInCdi;

public MetadataBuildingOptionsImpl(BootstrapContext bootstrapContext) {
this( bootstrapContext.getServiceRegistry() );
setBootstrapContext( bootstrapContext );
}

public MetadataBuildingOptionsImpl(StandardServiceRegistry serviceRegistry) {
this.serviceRegistry = serviceRegistry;
this.identifierGeneratorFactory = serviceRegistry.getService( IdentifierGeneratorFactory.class );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
package org.hibernate.boot.model.process.spi;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.function.Consumer;

import org.hibernate.boot.jaxb.spi.JaxbBindableMappingDescriptor;
import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
import org.hibernate.models.spi.ClassDetails;

/**
* Represents the result of the first step of the process of building {@link org.hibernate.boot.MetadataSources}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import org.hibernate.boot.model.source.spi.MetadataSourceProcessor;
import org.hibernate.boot.models.categorize.internal.DomainModelCategorizationCollector;
import org.hibernate.boot.models.categorize.internal.OrmAnnotationHelper;
import org.hibernate.boot.models.categorize.spi.ManagedResourcesProcessor;
import org.hibernate.boot.models.xml.spi.XmlPreProcessingResult;
import org.hibernate.boot.models.xml.spi.XmlPreProcessor;
import org.hibernate.boot.models.xml.spi.XmlProcessingResult;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ protected void collectMembersMarkedTransient(
final List<FieldDetails> fields = classDetails.getFields();
for ( int i = 0; i < fields.size(); i++ ) {
final FieldDetails fieldDetails = fields.get( i );
memberConsumer.acceptMember( fieldDetails );
if ( memberConsumer != null ) {
memberConsumer.acceptMember( fieldDetails );
}
if ( fieldDetails.getAnnotationUsage( JpaAnnotations.TRANSIENT ) != null ) {
transientFieldConsumer.accept( fieldDetails );
}
Expand All @@ -90,7 +92,9 @@ 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 ( memberConsumer != null ) {
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 @@ -128,4 +128,32 @@ public JpaEventListener resolve() {
}
return null;
}

public MethodDetails getPrePersist() {
return prePersist;
}

public MethodDetails getPostPersist() {
return postPersist;
}

public MethodDetails getPreUpdate() {
return preUpdate;
}

public MethodDetails getPostUpdate() {
return postUpdate;
}

public MethodDetails getPreRemove() {
return preRemove;
}

public MethodDetails getPostRemove() {
return postRemove;
}

public MethodDetails getPostLoad() {
return postLoad;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,15 @@ default void forEachEmbeddable(KeyedConsumer<String, ClassDetails> consumer) {

embeddables.forEach( consumer::accept );
}

default void forEachManagedType(KeyedConsumer<String, ClassDetails> consumer) {
forEachEntityHierarchy( (index, entityHierarchy) -> {
entityHierarchy.forEachType( (type, superType, hierarchy, relation) -> {
final ClassDetails classDetails = type.getClassDetails();
consumer.accept( classDetails.getName(), classDetails );
} );
} );
forEachMappedSuperclass( consumer );
forEachEmbeddable( consumer );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
import java.util.Set;
import java.util.stream.Collectors;

import org.hibernate.Incubating;
import org.hibernate.Internal;
import org.hibernate.annotations.TenantId;
import org.hibernate.boot.internal.MetadataBuilderImpl;
import org.hibernate.boot.internal.MetadataBuilderImpl.MetadataBuildingOptionsImpl;
import org.hibernate.boot.internal.RootMappingDefaults;
import org.hibernate.boot.model.process.spi.ManagedResources;
import org.hibernate.boot.models.categorize.ModelCategorizationLogging;
Expand Down Expand Up @@ -57,6 +58,7 @@
*
* @author Steve Ebersole
*/
@Incubating
public class ManagedResourcesProcessor {
public static CategorizedDomainModel processManagedResources(
ManagedResources managedResources,
Expand All @@ -76,7 +78,7 @@ public static CategorizedDomainModel processManagedResources(
//
// OUTPUTS:
// - xmlPreProcessingResult
// - allKnownClassNames (technically could be included in xmlPreProcessingResult)
// - allKnownClassNames
// - sourceModelBuildingContext

final ClassLoaderService classLoaderService = bootstrapContext.getServiceRegistry().getService( ClassLoaderService.class );
Expand Down Expand Up @@ -304,9 +306,10 @@ public static void preFillRegistries(RegistryPrimer.Contributions contributions,
public static CategorizedDomainModel processManagedResources(
ManagedResources managedResources,
BootstrapContext bootstrapContext) {
final MetadataBuildingOptionsImpl metadataBuildingOptions = new MetadataBuildingOptionsImpl( bootstrapContext );
return processManagedResources(
managedResources,
new MetadataBuilderImpl.MetadataBuildingOptionsImpl( bootstrapContext.getServiceRegistry() ),
metadataBuildingOptions,
bootstrapContext
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* 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.categorize;

import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.internal.BootstrapContextImpl;
import org.hibernate.boot.internal.MetadataBuilderImpl;
import org.hibernate.boot.model.process.spi.ManagedResources;
import org.hibernate.boot.model.process.spi.MetadataBuildingProcess;
import org.hibernate.boot.models.categorize.spi.CategorizedDomainModel;
import org.hibernate.boot.models.categorize.spi.ManagedResourcesProcessor;
import org.hibernate.boot.registry.StandardServiceRegistry;

import org.hibernate.testing.orm.junit.ServiceRegistryScope;

/**
* @author Steve Ebersole
*/
public class CategorizationTestsHelper {
public static CategorizedDomainModel buildCategorizedDomainModel(ServiceRegistryScope scope, Class<?>... managedClasses) {
final StandardServiceRegistry serviceRegistry = scope.getRegistry();
final MetadataSources metadataSources = new MetadataSources( serviceRegistry ).addAnnotatedClasses( managedClasses );
final MetadataBuilderImpl.MetadataBuildingOptionsImpl metadataBuildingOptions = new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry );
final BootstrapContextImpl bootstrapContext = new BootstrapContextImpl( serviceRegistry, metadataBuildingOptions );
metadataBuildingOptions.setBootstrapContext( bootstrapContext );
final ManagedResources managedResources = MetadataBuildingProcess.prepare( metadataSources, bootstrapContext );

//noinspection UnnecessaryLocalVariable
final CategorizedDomainModel categorizedDomainModel = ManagedResourcesProcessor.processManagedResources(
managedResources,
bootstrapContext
);
return categorizedDomainModel;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* 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.categorize;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Basic;
import jakarta.persistence.PostLoad;
import jakarta.persistence.PostPersist;
import jakarta.persistence.PrePersist;

/**
* @author Steve Ebersole
*/
@Entity
public class SimpleEntity {
@Id
private Integer id;
@Basic
private String name;

protected SimpleEntity() {
// for Hibernate use
}

public SimpleEntity(Integer id, String name) {
this.id = id;
this.name = name;
}

public Integer getId() {
return id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@PostLoad
public void afterLoad() {}

@PrePersist
public void beforePersist() {}

@PostPersist
public void afterPersist() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* 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.categorize;

import java.util.List;

import org.hibernate.boot.internal.InFlightMetadataCollectorImpl;
import org.hibernate.boot.internal.MetadataBuilderImpl;
import org.hibernate.boot.internal.RootMappingDefaults;
import org.hibernate.boot.model.process.spi.ManagedResources;
import org.hibernate.boot.model.source.internal.annotations.AdditionalManagedResourcesImpl;
import org.hibernate.boot.models.categorize.internal.DomainModelCategorizationCollector;
import org.hibernate.boot.models.categorize.internal.LifecycleCallbackCollector;
import org.hibernate.boot.models.categorize.internal.StandardPersistentAttributeMemberResolver;
import org.hibernate.boot.models.categorize.spi.ClassAttributeAccessType;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.models.spi.ClassDetails;
import org.hibernate.models.spi.ClassDetailsRegistry;
import org.hibernate.models.spi.MemberDetails;
import org.hibernate.models.spi.SourceModelBuildingContext;
import org.hibernate.orm.test.boot.models.BootstrapContextTesting;
import org.hibernate.orm.test.boot.models.MyStringConverter;
import org.hibernate.orm.test.boot.models.MyUuidConverter;
import org.hibernate.orm.test.boot.models.SourceModelTestHelper;
import org.hibernate.orm.test.boot.models.process.Person;
import org.hibernate.orm.test.boot.models.process.Root;
import org.hibernate.orm.test.boot.models.process.Sub;

import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.ServiceRegistryScope;
import org.junit.jupiter.api.Test;

import org.jboss.jandex.Index;

import static org.assertj.core.api.Assertions.assertThat;
import static org.hibernate.models.internal.SimpleClassLoading.SIMPLE_CLASS_LOADING;

/**
* Simple smoke-test showing how to possibly move forward with the "categorization" consumption of
* hibernate-models (replacing all the binder stuff)
*
* @author Steve Ebersole
*/
@SuppressWarnings("JUnitMalformedDeclaration")
public class SimpleProcessingSmokeTest {
@Test
@ServiceRegistry
void testSimpleUsage(ServiceRegistryScope scope) {
final StandardServiceRegistry serviceRegistry = scope.getRegistry();

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ManagedResources is built by scanning and from explicit resources
// during ORM bootstrap.
// Here we build one manually for testing
final AdditionalManagedResourcesImpl.Builder managedResourcesBuilder = new AdditionalManagedResourcesImpl.Builder();
managedResourcesBuilder
.addLoadedClasses( Person.class, Root.class, Sub.class, MyStringConverter.class, MyUuidConverter.class )
.addPackages( "org.hibernate.models.orm.process" );
final ManagedResources managedResources = managedResourcesBuilder.build();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// The Jandex index would generally (1) be built by WF and passed
// to ORM or (2) be built by ORM.
// Again, here we build one manually for testing
final Index jandexIndex = SourceModelTestHelper.buildJandexIndex(
SIMPLE_CLASS_LOADING,
SimpleEntity.class
);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This is also all internal set up stuff done as part of bootstrapping
// Again, here we do this all manually for testing
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final MetadataBuilderImpl.MetadataBuildingOptionsImpl metadataBuildingOptions = new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry );
final BootstrapContextTesting bootstrapContext = new BootstrapContextTesting( jandexIndex, serviceRegistry, metadataBuildingOptions );
metadataBuildingOptions.setBootstrapContext( bootstrapContext );
final InFlightMetadataCollectorImpl metadataCollector = new InFlightMetadataCollectorImpl( bootstrapContext, metadataBuildingOptions );
final SourceModelBuildingContext sourceModelBuildingContext = metadataCollector.getSourceModelBuildingContext();
final ClassDetailsRegistry classDetailsRegistry = sourceModelBuildingContext.getClassDetailsRegistry();

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

final ClassDetails simpleEntityClassDetails = classDetailsRegistry.resolveClassDetails( SimpleEntity.class.getName() );


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Now we get to the meat and potatoes...
//
// At a high level we want to iterate over class members just once. During
// this process we -
// 1. collect "attribute members"
// 2. collect "call back" methods
//
// This would be triggered for each "managed class" (entity, mapped-super
// and embeddable)
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final LifecycleCallbackCollector lifecycleCallbackCollector = new LifecycleCallbackCollector( simpleEntityClassDetails, null );
final List<MemberDetails> attributeMembers = StandardPersistentAttributeMemberResolver.INSTANCE.resolveAttributesMembers(
simpleEntityClassDetails,
ClassAttributeAccessType.IMPLICIT_FIELD,
lifecycleCallbackCollector
);

assertThat( attributeMembers ).hasSize( 2 );
assertThat( attributeMembers ).containsExactly(
simpleEntityClassDetails.findFieldByName( "id" ),
simpleEntityClassDetails.findFieldByName( "name" )
);

assertThat( lifecycleCallbackCollector.getPostLoad() ).isNotNull();

assertThat( lifecycleCallbackCollector.getPrePersist() ).isNotNull();
assertThat( lifecycleCallbackCollector.getPostPersist() ).isNotNull();

assertThat( lifecycleCallbackCollector.getPreUpdate() ).isNull();
assertThat( lifecycleCallbackCollector.getPostUpdate() ).isNull();

assertThat( lifecycleCallbackCollector.getPreRemove() ).isNull();
assertThat( lifecycleCallbackCollector.getPostRemove() ).isNull();
}
}

0 comments on commit d1d8148

Please sign in to comment.