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:
Steve Ebersole 2023-12-07 09:40:04 -06:00
parent 01e3b12ae8
commit 6869dbb1f9
10 changed files with 231 additions and 191 deletions

View File

@ -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() {

View File

@ -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();

View File

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

View File

@ -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,115 +150,7 @@ 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
// @Override
// public <A extends Annotation> List<AnnotationUsage<A>> findAnnotations(AnnotationDescriptor<A> type) {
// return classDetails.getAnnotations( type );
// }

View File

@ -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 );

View File

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

View File

@ -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++ ) {

View File

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

View File

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

View File

@ -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) -> {