From 3e4c9ceea035450f3c33af1ae40abeb796b2a9f8 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 13 Mar 2025 23:08:11 -0500 Subject: [PATCH 1/4] #107 - hibernate-models-bytebuddy # Conflicts: # hibernate-models/src/test/java/org/hibernate/models/testing/tests/MultiDimensionalArrayTypeTests.java --- hibernate-models-bytebuddy/build.gradle | 17 + .../internal/AbstractAnnotationTarget.java | 45 ++ .../internal/AnnotationDescriptorImpl.java | 35 ++ .../AnnotationDescriptorRegistryImpl.java | 32 ++ .../internal/AnnotationUsageBuilder.java | 116 +++++ .../internal/ClassDetailsBuilderImpl.java | 26 + .../bytebuddy/internal/ClassDetailsImpl.java | 265 ++++++++++ .../internal/ClassDetailsRegistryImpl.java | 55 +++ .../bytebuddy/internal/FieldDetailsImpl.java | 151 ++++++ .../bytebuddy/internal/MethodDetailsImpl.java | 215 +++++++++ .../bytebuddy/internal/ModelBuilders.java | 453 ++++++++++++++++++ .../internal/RecordComponentDetailsImpl.java | 150 ++++++ .../SourceModelBuildingContextImpl.java | 113 +++++ .../internal/TypeSwitchStandard.java | 158 ++++++ .../values/AbstractValueExtractor.java | 31 ++ .../internal/values/ArrayValueConverter.java | 32 ++ .../internal/values/ArrayValueExtractor.java | 28 ++ .../values/BooleanValueConverter.java | 25 + .../values/BooleanValueExtractor.java | 24 + .../internal/values/ByteValueConverter.java | 25 + .../internal/values/ByteValueExtractor.java | 24 + .../values/CharacterValueConverter.java | 25 + .../values/CharacterValueExtractor.java | 24 + .../internal/values/ClassValueConverter.java | 25 + .../internal/values/ClassValueExtractor.java | 24 + .../internal/values/DoubleValueConverter.java | 24 + .../internal/values/DoubleValueExtractor.java | 24 + .../internal/values/EnumValueConverter.java | 31 ++ .../internal/values/EnumValueExtractor.java | 28 ++ .../internal/values/FloatValueConverter.java | 25 + .../internal/values/FloatValueExtractor.java | 24 + .../values/IntegerValueConverter.java | 25 + .../values/IntegerValueExtractor.java | 24 + .../internal/values/LongValueConverter.java | 25 + .../internal/values/LongValueExtractor.java | 24 + .../internal/values/NestedValueConverter.java | 32 ++ .../internal/values/NestedValueExtractor.java | 30 ++ .../internal/values/ShortValueConverter.java | 25 + .../internal/values/ShortValueExtractor.java | 24 + .../internal/values/StringValueConverter.java | 25 + .../internal/values/StringValueExtractor.java | 23 + .../models/bytebuddy/package-info.java | 6 + .../spi/ByteBuddyModelsBuildingContext.java | 20 + .../models/bytebuddy/spi/TypeSwitch.java | 33 ++ .../models/bytebuddy/spi/TypeSwitcher.java | 55 +++ .../models/bytebuddy/spi/ValueConverter.java | 21 + .../models/bytebuddy/spi/ValueExtractor.java | 32 ++ .../models/bytebuddy/SimpleTests.java | 38 ++ .../bytebuddy/SourceModelTestHelper.java | 118 +++++ .../models/bytebuddy/classes/AnEnum.java | 12 + .../models/bytebuddy/classes/BranchClass.java | 18 + .../models/bytebuddy/classes/ClassMarker.java | 20 + .../bytebuddy/classes/ClassRegistryTests.java | 93 ++++ .../models/bytebuddy/classes/Composable.java | 20 + .../models/bytebuddy/classes/EnumTests.java | 46 ++ .../bytebuddy/classes/GenericsTests.java | 192 ++++++++ .../bytebuddy/classes/InheritanceTests.java | 250 ++++++++++ .../models/bytebuddy/classes/Intf.java | 11 + .../models/bytebuddy/classes/LeafClass.java | 18 + .../bytebuddy/classes/MemberMarker.java | 20 + .../bytebuddy/classes/PrimitiveTypeTests.java | 66 +++ .../models/bytebuddy/classes/RootClass.java | 19 + .../bytebuddy/classes/SubclassableMarker.java | 21 + .../models/bytebuddy/classes/TrunkClass.java | 18 + hibernate-models-jandex/build.gradle | 2 +- settings.gradle | 1 + 66 files changed, 3680 insertions(+), 1 deletion(-) create mode 100644 hibernate-models-bytebuddy/build.gradle create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AbstractAnnotationTarget.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationDescriptorImpl.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationDescriptorRegistryImpl.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationUsageBuilder.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsBuilderImpl.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsImpl.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsRegistryImpl.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/FieldDetailsImpl.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/MethodDetailsImpl.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ModelBuilders.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/RecordComponentDetailsImpl.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/SourceModelBuildingContextImpl.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/TypeSwitchStandard.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/AbstractValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/BooleanValueConverter.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/BooleanValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ByteValueConverter.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ByteValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/CharacterValueConverter.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/CharacterValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ClassValueConverter.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ClassValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/DoubleValueConverter.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/DoubleValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/EnumValueConverter.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/EnumValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/FloatValueConverter.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/FloatValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/IntegerValueConverter.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/IntegerValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/LongValueConverter.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/LongValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/NestedValueConverter.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/NestedValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ShortValueConverter.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ShortValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/StringValueConverter.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/StringValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/package-info.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyModelsBuildingContext.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/TypeSwitch.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/TypeSwitcher.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ValueConverter.java create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ValueExtractor.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SimpleTests.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SourceModelTestHelper.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/AnEnum.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/BranchClass.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassMarker.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassRegistryTests.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Composable.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/EnumTests.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/GenericsTests.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/InheritanceTests.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Intf.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/LeafClass.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/MemberMarker.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/PrimitiveTypeTests.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/RootClass.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/SubclassableMarker.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/TrunkClass.java diff --git a/hibernate-models-bytebuddy/build.gradle b/hibernate-models-bytebuddy/build.gradle new file mode 100644 index 0000000..7c76f87 --- /dev/null +++ b/hibernate-models-bytebuddy/build.gradle @@ -0,0 +1,17 @@ +plugins { + id "published-java-module" +} + +description = "Support for hibernate-models based on ByteBuddy (isolated dependency)" + +repositories { + mavenCentral() +} + +dependencies { + api project( ":hibernate-models" ) + + implementation libs.byteBuddy + + testImplementation project( ":hibernate-models-testing" ) +} \ No newline at end of file diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AbstractAnnotationTarget.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AbstractAnnotationTarget.java new file mode 100644 index 0000000..892f275 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AbstractAnnotationTarget.java @@ -0,0 +1,45 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal; + +import java.lang.annotation.Annotation; +import java.util.Map; + +import org.hibernate.models.internal.AnnotationTargetSupport; + +import net.bytebuddy.description.annotation.AnnotationSource; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractAnnotationTarget implements AnnotationTargetSupport { + private final SourceModelBuildingContextImpl modelContext; + + private Map, ? extends Annotation> usageMap; + + public AbstractAnnotationTarget(SourceModelBuildingContextImpl modelContext) { + this.modelContext = modelContext; + } + + public SourceModelBuildingContextImpl getModelContext() { + return modelContext; + } + + protected abstract AnnotationSource getAnnotationSource(); + + @Override + public Map, ? extends Annotation> getUsageMap() { + if ( usageMap == null ) { + usageMap = AnnotationUsageBuilder.collectUsages( getAnnotationSource(), modelContext ); + } + return usageMap; + } + + @Override + public void clearAnnotationUsages() { + getUsageMap().clear(); + } + +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationDescriptorImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationDescriptorImpl.java new file mode 100644 index 0000000..a036b94 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationDescriptorImpl.java @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal; + +import java.lang.annotation.Annotation; + +import org.hibernate.models.internal.StandardAnnotationDescriptor; +import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationDescription; + +/** + * @author Steve Ebersole + */ +public class AnnotationDescriptorImpl extends StandardAnnotationDescriptor { + public AnnotationDescriptorImpl( + Class annotationType, + SourceModelBuildingContext buildingContext) { + super( annotationType, buildingContext ); + } + + public AnnotationDescriptorImpl( + Class annotationType, + AnnotationDescriptor repeatableContainer, + SourceModelBuildingContext buildingContext) { + super( annotationType, repeatableContainer, buildingContext ); + } + + public A createUsage(AnnotationDescription annotationDescription, SourceModelBuildingContextImpl context) { + return AnnotationUsageBuilder.makeUsage( annotationDescription, this, context ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationDescriptorRegistryImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationDescriptorRegistryImpl.java new file mode 100644 index 0000000..c530070 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationDescriptorRegistryImpl.java @@ -0,0 +1,32 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal; + +import java.lang.annotation.Annotation; +import java.util.Map; + +import org.hibernate.models.internal.AnnotationDescriptorRegistryStandard; +import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.SourceModelBuildingContext; + +/** + * @author Steve Ebersole + */ +public class AnnotationDescriptorRegistryImpl extends AnnotationDescriptorRegistryStandard { + public AnnotationDescriptorRegistryImpl(SourceModelBuildingContext modelBuildingContext) { + super( modelBuildingContext ); + } + + @Override + protected AnnotationDescriptor buildAnnotationDescriptor( + Class javaType, + AnnotationDescriptor containerDescriptor) { + return new AnnotationDescriptorImpl<>( javaType, containerDescriptor, getModelBuildingContext() ); + } + + public Map, AnnotationDescriptor> getDescriptorMap() { + return descriptorMap; + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationUsageBuilder.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationUsageBuilder.java new file mode 100644 index 0000000..6349382 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationUsageBuilder.java @@ -0,0 +1,116 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Documented; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiConsumer; + +import org.hibernate.models.bytebuddy.spi.ValueExtractor; +import org.hibernate.models.internal.util.CollectionHelper; +import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.AnnotationDescriptorRegistry; +import org.hibernate.models.spi.AttributeDescriptor; + +import net.bytebuddy.description.annotation.AnnotationDescription; +import net.bytebuddy.description.annotation.AnnotationList; +import net.bytebuddy.description.annotation.AnnotationSource; + +/** + * Helper for building annotation usages/instances based on + * Jandex {@linkplain AnnotationDescription} references + * + * @author Steve Ebersole + */ +public class AnnotationUsageBuilder { + public static A makeUsage( + AnnotationDescription annotationDescription, + AnnotationDescriptor annotationDescriptor, + SourceModelBuildingContextImpl modelContext) { + final Map attributeValues = extractAttributeValues( + annotationDescription, + annotationDescriptor, + modelContext + ); + return annotationDescriptor.createUsage( attributeValues, modelContext ); + } + + private static Map extractAttributeValues( + AnnotationDescription annotationDescription, + AnnotationDescriptor annotationDescriptor, + SourceModelBuildingContextImpl modelContext) { + + if ( CollectionHelper.isEmpty( annotationDescriptor.getAttributes() ) ) { + return Collections.emptyMap(); + } + + final ConcurrentHashMap valueMap = new ConcurrentHashMap<>(); + for ( int i = 0; i < annotationDescriptor.getAttributes().size(); i++ ) { + final AttributeDescriptor attributeDescriptor = annotationDescriptor.getAttributes().get( i ); + final ValueExtractor extractor = modelContext + .as( SourceModelBuildingContextImpl.class ) + .getValueExtractor( attributeDescriptor.getTypeDescriptor() ); + final Object attributeValue = extractor.extractValue( + annotationDescription, + attributeDescriptor.getName(), + modelContext + ); + valueMap.put( attributeDescriptor.getName(), attributeValue ); + } + return valueMap; + } + + public static Map, ? extends Annotation> collectUsages( + AnnotationSource annotationSource, + SourceModelBuildingContextImpl modelContext) { + if ( annotationSource == null ) { + return Collections.emptyMap(); + } + final Map, Annotation> result = new HashMap<>(); + processAnnotations( + annotationSource.getDeclaredAnnotations(), + result::put, + modelContext + ); + return result; + } + + /** + * Process annotations creating usage instances passed back to the consumer + */ + public static void processAnnotations( + AnnotationList annotations, + BiConsumer, Annotation> consumer, + SourceModelBuildingContextImpl buildingContext) { + final AnnotationDescriptorRegistry annotationDescriptorRegistry = buildingContext.getAnnotationDescriptorRegistry(); + + for ( AnnotationDescription annotation : annotations ) { + if ( annotation.getAnnotationType().represents( Documented.class ) + || annotation.getAnnotationType().represents( Repeatable.class ) + || annotation.getAnnotationType().represents( Retention.class ) + || annotation.getAnnotationType().represents( Target.class ) ) { + continue; + } + + final Class annotationType = buildingContext + .getClassLoading() + .classForName( annotation.getAnnotationType().getTypeName() ); + final AnnotationDescriptor annotationDescriptor = annotationDescriptorRegistry.getDescriptor( annotationType ); + final Annotation usage = makeUsage( + annotation, + annotationDescriptor, + buildingContext + ); + consumer.accept( annotationType, usage ); + } + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsBuilderImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsBuilderImpl.java new file mode 100644 index 0000000..3122688 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsBuilderImpl.java @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal; + +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.ClassDetailsBuilder; +import org.hibernate.models.spi.SourceModelBuildingContext; + +/** + * @author Steve Ebersole + */ +public class ClassDetailsBuilderImpl implements ClassDetailsBuilder { + private final SourceModelBuildingContextImpl modelContext; + + public ClassDetailsBuilderImpl(SourceModelBuildingContextImpl modelContext) { + this.modelContext = modelContext; + } + + @Override + public ClassDetails buildClassDetails(String name, SourceModelBuildingContext buildingContext) { + assert buildingContext == modelContext; + return ModelBuilders.buildDetails( name, modelContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsImpl.java new file mode 100644 index 0000000..5031981 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsImpl.java @@ -0,0 +1,265 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.models.internal.ClassDetailsSupport; +import org.hibernate.models.internal.jdk.SerialJdkClassDetails; +import org.hibernate.models.internal.util.CollectionHelper; +import org.hibernate.models.serial.spi.SerialClassDetails; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.FieldDetails; +import org.hibernate.models.spi.MethodDetails; +import org.hibernate.models.spi.RecordComponentDetails; +import org.hibernate.models.spi.SourceModelBuildingContext; +import org.hibernate.models.spi.TypeDetails; +import org.hibernate.models.spi.TypeVariableDetails; + +import net.bytebuddy.description.annotation.AnnotationSource; +import net.bytebuddy.description.field.FieldDescription; +import net.bytebuddy.description.field.FieldList; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.method.MethodList; +import net.bytebuddy.description.type.RecordComponentDescription; +import net.bytebuddy.description.type.RecordComponentList; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.description.type.TypeList; + +import static java.util.Collections.emptyList; +import static org.hibernate.models.internal.SimpleClassLoading.SIMPLE_CLASS_LOADING; +import static org.hibernate.models.internal.util.CollectionHelper.arrayList; +import static org.hibernate.models.internal.util.CollectionHelper.isEmpty; + +/** + * @author Steve Ebersole + */ +public class ClassDetailsImpl extends AbstractAnnotationTarget implements ClassDetailsSupport { + private final TypeDescription typeDescription; + + private final ClassDetails superClassDetails; + private TypeDetails genericSuperType; + private List implementedInterfaces; + private List typeParameters; + + private List fields; + private List methods; + private List recordComponents; + + public ClassDetailsImpl(TypeDescription typeDescription, SourceModelBuildingContextImpl modelContext) { + super( modelContext ); + this.typeDescription = typeDescription; + this.superClassDetails = determineSuperType( typeDescription, modelContext ); + } + + @Override + protected AnnotationSource getAnnotationSource() { + return typeDescription; + } + + @Override + public String getName() { + return getClassName(); + } + + @Override + public String getClassName() { + return typeDescription.getTypeName(); + } + + @Override + public boolean isResolved() { + return true; + } + + @Override + public boolean isAbstract() { + return typeDescription.isAbstract(); + } + + @Override + public boolean isInterface() { + return typeDescription.isInterface(); + } + + @Override + public boolean isEnum() { + return typeDescription.isEnum(); + } + + @Override + public boolean isRecord() { + return typeDescription.isRecord(); + } + + @Override + public ClassDetails getSuperClass() { + return superClassDetails; + } + + @Override + public TypeDetails getGenericSuperType() { + if ( genericSuperType == null && typeDescription.getSuperClass() != null ) { + genericSuperType = determineGenericSuperType( typeDescription, getModelContext() ); + } + return genericSuperType; + } + + @Override + public List getImplementedInterfaces() { + if ( implementedInterfaces == null ) { + implementedInterfaces = determineInterfaces( typeDescription, getModelContext() ); + } + return implementedInterfaces; + } + + @Override + public List getTypeParameters() { + if ( typeParameters == null ) { + this.typeParameters = determineTypeParameters( typeDescription, this, getModelContext() ); + } + return typeParameters; + } + + @Override + public boolean isImplementor(Class checkType) { + return typeDescription.isAssignableTo( checkType ); + } + + @Override + public List getFields() { + if ( fields == null ) { + fields = resolveFields(); + } + return fields; + } + + private List resolveFields() { + final FieldList declaredFields = typeDescription.getDeclaredFields(); + final List result = new ArrayList<>( declaredFields.size() ); + for ( FieldDescription.InDefinedShape declaredField : declaredFields ) { + result.add( new FieldDetailsImpl( declaredField, this, getModelContext() ) ); + } + return result; + } + + @Override + public void addField(FieldDetails fieldDetails) { + getFields().add( fieldDetails ); + } + + @Override + public List getMethods() { + if ( methods == null ) { + methods = resolveMethods(); + } + return methods; + } + + private List resolveMethods() { + final MethodList declaredMethods = typeDescription.getDeclaredMethods(); + final List result = new ArrayList<>( declaredMethods.size() ); + for ( MethodDescription.InDefinedShape declaredMethod : declaredMethods ) { + if ( declaredMethod.isConstructor() || declaredMethod.isTypeInitializer() ) { + continue; + } + result.add( ModelBuilders.buildMethodDetails( declaredMethod, this, getModelContext() ) ); + } + return result; + } + + @Override + public void addMethod(MethodDetails methodDetails) { + getMethods().add( methodDetails ); + } + + @Override + public List getRecordComponents() { + if ( recordComponents == null ) { + recordComponents = resolveRecordComponents(); + } + return recordComponents; + } + + private List resolveRecordComponents() { + final RecordComponentList recordComponents = typeDescription.getRecordComponents(); + final List result = arrayList( recordComponents.size() ); + for ( RecordComponentDescription.InDefinedShape component : recordComponents ) { + result.add( new RecordComponentDetailsImpl( component, this, getModelContext() ) ); + } + return result; + } + + @Override + public Class toJavaClass() { + return SIMPLE_CLASS_LOADING.classForName( getClassName() ); + } + + @Override + public SerialClassDetails toStorableForm() { + return new SerialJdkClassDetails( getName(), toJavaClass() ); + } + + @Override + public String toString() { + return "ClassDetails(" + typeDescription.getName() + ")"; + } + + private static ClassDetails determineSuperType( + TypeDescription typeDescription, + SourceModelBuildingContext buildingContext) { + if ( typeDescription.getSuperClass() == null ) { + return null; + } + + return buildingContext + .getClassDetailsRegistry() + .resolveClassDetails( typeDescription.getSuperClass().asRawType().getTypeName() ); + } + + private static TypeDetails determineGenericSuperType(TypeDescription typeDescription, SourceModelBuildingContext buildingContext) { + if ( typeDescription.getSuperClass() == null ) { + return null; + } + + return TypeSwitchStandard.switchType( typeDescription.getSuperClass(), buildingContext ); + } + + private static List determineInterfaces( + TypeDescription typeDescription, + SourceModelBuildingContext buildingContext) { + final TypeList.Generic interfaceTypes = typeDescription.getInterfaces(); + if ( isEmpty( interfaceTypes ) ) { + return emptyList(); + } + + final List result = arrayList( interfaceTypes.size() ); + for ( TypeDescription.Generic interfaceType : interfaceTypes ) { + final TypeDetails switchedType = TypeSwitchStandard.switchType( + interfaceType, + buildingContext + ); + result.add( switchedType ); + } + return result; + } + + private static List determineTypeParameters( + TypeDescription typeDescription, + ClassDetailsImpl current, + SourceModelBuildingContext buildingContext) { + final TypeList.Generic typeArguments = typeDescription.getTypeVariables(); + if ( CollectionHelper.isEmpty( typeArguments ) ) { + return emptyList(); + } + + final ArrayList result = arrayList( typeArguments.size() ); + for ( TypeDescription.Generic typeArgument : typeArguments ) { + result.add( (TypeVariableDetails) TypeSwitchStandard.switchType( typeArgument, current, buildingContext ) ); + } + return result; + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsRegistryImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsRegistryImpl.java new file mode 100644 index 0000000..f702ea3 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsRegistryImpl.java @@ -0,0 +1,55 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal; + +import java.util.Map; + +import org.hibernate.models.UnknownClassException; +import org.hibernate.models.internal.AbstractClassDetailsRegistry; +import org.hibernate.models.internal.jdk.JdkBuilders; +import org.hibernate.models.internal.jdk.JdkClassDetails; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.ClassDetailsBuilder; + +/** + * @author Steve Ebersole + */ +public class ClassDetailsRegistryImpl extends AbstractClassDetailsRegistry { + private final SourceModelBuildingContextImpl modelContext; + private final ClassDetailsBuilderImpl classDetailsBuilder; + + public ClassDetailsRegistryImpl(SourceModelBuildingContextImpl context) { + super( context ); + this.modelContext = context; + this.classDetailsBuilder = new ClassDetailsBuilderImpl( context ); + } + + @Override + protected ClassDetailsBuilder getClassDetailsBuilder() { + return classDetailsBuilder; + } + + @Override + protected ClassDetails createClassDetails(String name) { + final ClassDetails fromByteBuddy = classDetailsBuilder.buildClassDetails( name, context ); + if ( fromByteBuddy != null ) { + addClassDetails( name, fromByteBuddy ); + return fromByteBuddy; + } + + final JdkClassDetails jdkClassDetails = JdkBuilders.DEFAULT_BUILDER.buildClassDetails( name, context ); + if ( jdkClassDetails != null ) { + addClassDetails( name, jdkClassDetails ); + return jdkClassDetails; + } + + throw new UnknownClassException( "Unable to resolve ClassDetails for `" + name + "`" ); + } + + protected Map getClassDetailsMap() { + return classDetailsMap; + } + +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/FieldDetailsImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/FieldDetailsImpl.java new file mode 100644 index 0000000..675a0be --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/FieldDetailsImpl.java @@ -0,0 +1,151 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.util.Collection; +import java.util.Map; + +import org.hibernate.models.IllegalCastException; +import org.hibernate.models.internal.AnnotationTargetSupport; +import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.FieldDetails; +import org.hibernate.models.spi.MethodDetails; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; +import org.hibernate.models.spi.RecordComponentDetails; +import org.hibernate.models.spi.TypeDetails; + +import net.bytebuddy.description.annotation.AnnotationSource; +import net.bytebuddy.description.field.FieldDescription; + +/** + * @author Steve Ebersole + */ +public class FieldDetailsImpl + extends AbstractAnnotationTarget + implements FieldDetails, MutableMemberDetails, AnnotationTargetSupport { + private final FieldDescription.InDefinedShape underlyingField; + private final ClassDetailsImpl declaringClassDetails; + + private final TypeDetails type; + private final boolean isArray; + private final boolean isPlural; + + public FieldDetailsImpl( + FieldDescription.InDefinedShape underlyingField, + ClassDetailsImpl declaringClassDetails, + SourceModelBuildingContextImpl modelContext) { + super( modelContext ); + this.underlyingField = underlyingField; + this.declaringClassDetails = declaringClassDetails; + + this.type = TypeSwitchStandard.switchType( underlyingField.getType(), declaringClassDetails, modelContext ); + + this.isArray = underlyingField.getType().isArray(); + this.isPlural = isArray || type.isImplementor( Collection.class ) || type.isImplementor( Map.class ); + } + + @Override + protected AnnotationSource getAnnotationSource() { + return underlyingField; + } + + @Override + public String getName() { + return underlyingField.getName(); + } + + @Override + public TypeDetails getType() { + return type; + } + + @Override + public ClassDetails getDeclaringType() { + return declaringClassDetails; + } + + @Override + public boolean isPlural() { + return isPlural; + } + + @Override + public boolean isArray() { + return isArray; + } + + @Override + public int getModifiers() { + return underlyingField.getModifiers(); + } + + + private Member underlyingMember; + + @Override + public Member toJavaMember() { + if ( underlyingMember == null ) { + underlyingMember = resolveJavaMember(); + } + return underlyingMember; + } + + private Field resolveJavaMember() { + final Class declaringJavaClass = declaringClassDetails.toJavaClass(); + try { + return declaringJavaClass.getField( getName() ); + } + catch (NoSuchFieldException e) { + throw new RuntimeException( + String.format( + "Jandex FieldInfo had no corresponding Field : %s.%s", + declaringJavaClass.getName(), + getName() + ), + e + ); + } + } + + @Override + public String toString() { + return "JandexFieldDetails(" + getName() + ")"; + } + + @Override + public FieldDetails asFieldDetails() { + return this; + } + + @Override + public MutableMemberDetails asMemberDetails() { + return this; + } + + @Override + public MethodDetails asMethodDetails() { + throw new IllegalCastException( "FieldDetails cannot be cast as MethodDetails" ); + } + + @Override + public RecordComponentDetails asRecordComponentDetails() { + throw new IllegalCastException( "FieldDetails cannot be cast as RecordComponentDetails" ); + } + + @Override + public AnnotationDescriptor asAnnotationDescriptor() { + throw new IllegalCastException( "FieldDetails cannot be cast to an AnnotationDescriptor" ); + } + + @Override + public MutableClassDetails asClassDetails() { + throw new IllegalCastException( "FieldDetails cannot be cast to a ClassDetails" ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/MethodDetailsImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/MethodDetailsImpl.java new file mode 100644 index 0000000..ad17635 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/MethodDetailsImpl.java @@ -0,0 +1,215 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.hibernate.models.IllegalCastException; +import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.ClassDetailsRegistry; +import org.hibernate.models.spi.FieldDetails; +import org.hibernate.models.spi.MethodDetails; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; +import org.hibernate.models.spi.RecordComponentDetails; +import org.hibernate.models.spi.TypeDetails; + +import net.bytebuddy.description.annotation.AnnotationSource; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.method.ParameterDescription; +import net.bytebuddy.description.type.TypeDescription; + +/** + * @author Steve Ebersole + */ +public class MethodDetailsImpl extends AbstractAnnotationTarget implements MethodDetails, MutableMemberDetails { + private final MethodDescription methodDescription; + private final MethodKind methodKind; + private final TypeDetails type; + private final ClassDetails declaringType; + + private final ClassDetails returnType; + private final List argumentTypes; + + private final boolean isArray; + private final boolean isPlural; + + public MethodDetailsImpl( + MethodDescription methodDescription, + MethodKind methodKind, + TypeDetails type, + ClassDetails declaringType, + SourceModelBuildingContextImpl modelContext) { + super( modelContext ); + this.methodDescription = methodDescription; + this.methodKind = methodKind; + this.type = type; + this.declaringType = declaringType; + + final ClassDetailsRegistry classDetailsRegistry = modelContext.getClassDetailsRegistry(); + this.returnType = classDetailsRegistry.resolveClassDetails( methodDescription.getReturnType().getTypeName() ); + + this.argumentTypes = new ArrayList<>( methodDescription.getParameters().size() ); + for ( int i = 0; i < methodDescription.getParameters().size(); i++ ) { + argumentTypes.add( classDetailsRegistry.resolveClassDetails( methodDescription.getParameters().get( i ).getType().getTypeName() ) ); + } + + switch ( methodKind ) { + case GETTER -> { + this.isArray = methodDescription.getReturnType().isArray(); + this.isPlural = isArray || type.isImplementor( Collection.class ) || type.isImplementor( Map.class ); + } + case SETTER -> { + assert methodDescription.getParameters().size() == 1; + final TypeDescription.Generic argumentType = methodDescription.getParameters().asTypeList().get( 0 ); + + this.isArray = argumentType.isArray(); + this.isPlural = isArray || type.isImplementor( Collection.class ) || type.isImplementor( Map.class ); + } + default -> { + this.isArray = false; + this.isPlural = false; + } + } + } + + @Override + public String getName() { + return methodDescription.getName(); + } + + @Override + public MethodKind getMethodKind() { + return methodKind; + } + + @Override + public ClassDetails getReturnType() { + return returnType; + } + + @Override + public List getArgumentTypes() { + return argumentTypes; + } + + @Override + protected AnnotationSource getAnnotationSource() { + return methodDescription; + } + + @Override + public TypeDetails getType() { + return type; + } + + @Override + public ClassDetails getDeclaringType() { + return declaringType; + } + + @Override + public boolean isPlural() { + return isPlural; + } + + @Override + public boolean isArray() { + return isArray; + } + + @Override + public int getModifiers() { + return methodDescription.getModifiers(); + } + + private Method underlyingMethod; + + @Override + public Method toJavaMember() { + if ( underlyingMethod == null ) { + underlyingMethod = resolveJavaMember(); + } + return underlyingMethod; + } + + @Override + public MethodDetails asMethodDetails() { + return this; + } + + @Override + public MutableMemberDetails asMemberDetails() { + return this; + } + + @Override + public FieldDetails asFieldDetails() { + throw new IllegalCastException( "MethodDetails cannot be cast as FieldDetails" ); + } + + @Override + public RecordComponentDetails asRecordComponentDetails() { + throw new IllegalCastException( "MethodDetails cannot be cast as FieldDetails" ); + } + + @Override + public MutableClassDetails asClassDetails() { + throw new IllegalCastException( "MethodDetails cannot be cast as FieldDetails" ); + } + + @Override + public AnnotationDescriptor asAnnotationDescriptor() { + throw new IllegalCastException( "MethodDetails cannot be cast as AnnotationDescriptor" ); + } + + private Method resolveJavaMember() { + final Class declaringTypeClass = declaringType.toJavaClass(); + methods: for ( Method method : declaringTypeClass.getDeclaredMethods() ) { + if ( !method.getName().equals( getName() ) ) { + continue; + } + + if ( method.getParameterCount() != methodDescription.getParameters().size() ) { + continue; + } + + for ( int i = 0; i < method.getParameterTypes().length; i++ ) { + final Class methodParameterType = method.getParameterTypes()[i]; + final ParameterDescription parameterDescription = methodDescription.getParameters().get( i ); + if ( !methodParameterType.getName().equals( parameterDescription.getType().getTypeName() ) ) { + continue methods; + } + } + + // if we get here, we've found it + return method; + } + + throw new RuntimeException( + String.format( + "Jandex FieldInfo had no corresponding Field : %s.%s", + declaringType.getName(), + getName() + ) + ); + } + + @Override + public String toString() { + return String.format( + "MethodDetails( name=%s, kind=%s, type=%s )", + methodDescription.getName(), + methodKind, + type + ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ModelBuilders.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ModelBuilders.java new file mode 100644 index 0000000..db4a77d --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ModelBuilders.java @@ -0,0 +1,453 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal; + +import java.lang.annotation.Annotation; +import java.util.function.BiConsumer; + +import org.hibernate.models.bytebuddy.internal.values.ArrayValueConverter; +import org.hibernate.models.bytebuddy.internal.values.ArrayValueExtractor; +import org.hibernate.models.bytebuddy.internal.values.BooleanValueConverter; +import org.hibernate.models.bytebuddy.internal.values.BooleanValueExtractor; +import org.hibernate.models.bytebuddy.internal.values.ByteValueConverter; +import org.hibernate.models.bytebuddy.internal.values.ByteValueExtractor; +import org.hibernate.models.bytebuddy.internal.values.CharacterValueConverter; +import org.hibernate.models.bytebuddy.internal.values.CharacterValueExtractor; +import org.hibernate.models.bytebuddy.internal.values.ClassValueConverter; +import org.hibernate.models.bytebuddy.internal.values.ClassValueExtractor; +import org.hibernate.models.bytebuddy.internal.values.DoubleValueConverter; +import org.hibernate.models.bytebuddy.internal.values.DoubleValueExtractor; +import org.hibernate.models.bytebuddy.internal.values.EnumValueConverter; +import org.hibernate.models.bytebuddy.internal.values.EnumValueExtractor; +import org.hibernate.models.bytebuddy.internal.values.FloatValueConverter; +import org.hibernate.models.bytebuddy.internal.values.FloatValueExtractor; +import org.hibernate.models.bytebuddy.internal.values.IntegerValueConverter; +import org.hibernate.models.bytebuddy.internal.values.IntegerValueExtractor; +import org.hibernate.models.bytebuddy.internal.values.LongValueConverter; +import org.hibernate.models.bytebuddy.internal.values.LongValueExtractor; +import org.hibernate.models.bytebuddy.internal.values.NestedValueConverter; +import org.hibernate.models.bytebuddy.internal.values.NestedValueExtractor; +import org.hibernate.models.bytebuddy.internal.values.ShortValueConverter; +import org.hibernate.models.bytebuddy.internal.values.ShortValueExtractor; +import org.hibernate.models.bytebuddy.internal.values.StringValueConverter; +import org.hibernate.models.bytebuddy.internal.values.StringValueExtractor; +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.bytebuddy.spi.ValueExtractor; +import org.hibernate.models.internal.ArrayTypeDescriptor; +import org.hibernate.models.internal.jdk.JdkBuilders; +import org.hibernate.models.internal.util.StringHelper; +import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.MethodDetails; +import org.hibernate.models.spi.ValueTypeDescriptor; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.pool.TypePool; + +/** + * @author Steve Ebersole + */ +public class ModelBuilders { + public static ClassDetails buildDetails(String name, SourceModelBuildingContextImpl modelContext) { + if ( StringHelper.isEmpty( name ) ) { + return null; + } + + if ( "void".equals( name ) ) { + name = Void.class.getName(); + } + + // potentially handle primitives + final Class primitiveClass = resolvePrimitiveClass( name ); + if ( primitiveClass != null ) { + return JdkBuilders.buildClassDetailsStatic( primitiveClass, modelContext ); + } + + final TypePool typePool = modelContext.getTypePool(); + + try { + return new ClassDetailsImpl( typePool.describe( name ).resolve(), modelContext ); + } + catch (Exception noClass) { + // continue to the next checks + } + + try { + // potentially handle package names + final String packageInfoName = name + ".package-info"; + // just make sure it is resolvable + typePool.describe( packageInfoName ).resolve(); + // package-info is safe to load through using Class + return JdkBuilders.buildClassDetailsStatic( packageInfoName, modelContext ); + } + catch (Exception noClass) { + // continue to the next checks + } + + return null; + } + + + public static Class resolvePrimitiveClass(String className) { + if ( "boolean".equals( className ) ) { + return boolean.class; + } + + if ( Boolean.class.getSimpleName().equalsIgnoreCase( className ) || Boolean.class.getName().equals( className ) ) { + return Boolean.class; + } + + if ( "byte".equals( className ) ) { + return byte.class; + } + + if ( Byte.class.getSimpleName().equals( className ) || Byte.class.getName().equals( className ) ) { + return Byte.class; + } + + if ( "short".equals( className ) ) { + return short.class; + } + + if ( Short.class.getSimpleName().equals( className ) || Short.class.getName().equals( className ) ) { + return Short.class; + } + + if ( "int".equals( className ) ) { + return int.class; + } + + if ( Integer.class.getSimpleName().equals( className ) || Integer.class.getName().equals( className ) ) { + return Integer.class; + } + + if ( "long".equals( className ) ) { + return long.class; + } + + if ( Long.class.getSimpleName().equals( className ) || Long.class.getName().equals( className ) ) { + return Long.class; + } + + if ( "double".equals( className ) ) { + return double.class; + } + + if ( Double.class.getSimpleName().equals( className ) || Double.class.getName().equals( className ) ) { + return Double.class; + } + + if ( "float".equals( className ) ) { + return float.class; + } + + if ( Float.class.getSimpleName().equals( className ) || Float.class.getName().equals( className ) ) { + return Float.class; + } + + return null; + } + + public static MethodDetails buildMethodDetails( + MethodDescription.InDefinedShape method, + ClassDetailsImpl declaringType, + SourceModelBuildingContextImpl modelContext) { + if ( method.getParameters().isEmpty() ) { + // could be a getter + final TypeDescription.Generic returnType = method.getReturnType(); + if ( !isVoid( returnType ) ) { + final String methodName = method.getName(); + if ( methodName.startsWith( "get" ) ) { + return new MethodDetailsImpl( + method, + MethodDetails.MethodKind.GETTER, + TypeSwitchStandard.switchType( returnType, declaringType, modelContext ), + declaringType, + modelContext + ); + } + else if ( isBoolean( returnType ) && ( methodName.startsWith( "is" ) + || methodName.startsWith( "has" ) + || methodName.startsWith( "was" ) ) ) { + return new MethodDetailsImpl( + method, + MethodDetails.MethodKind.GETTER, + TypeSwitchStandard.switchType( returnType, declaringType, modelContext ), + declaringType, + modelContext + ); + } + } + } + + if ( method.getParameters().size() == 1 + && isVoid( method.getReturnType() ) + && method.getName().startsWith( "set" ) ) { + return new MethodDetailsImpl( + method, + MethodDetails.MethodKind.SETTER, + TypeSwitchStandard.switchType( method.getParameters().get( 0 ).getType(), declaringType, modelContext ), + declaringType, + modelContext + ); + } + + return new MethodDetailsImpl( + method, + MethodDetails.MethodKind.OTHER, + null, + declaringType, + modelContext + ); + } + + public static boolean isVoid(TypeDescription.Generic type) { + return type.represents( Void.class ) || type.represents( void.class ); + } + + public static boolean isBoolean(TypeDescription.Generic type) { + return type.represents( Boolean.class ) || type.represents( boolean.class ); + } + + @SuppressWarnings("unchecked") + public static ValueConverter buildValueHandlersReturnConverter( + ValueTypeDescriptor valueTypeDescriptor, + BiConsumer,ValueConverter> converterCollector, + BiConsumer, ValueExtractor> extractorCollector, + SourceModelBuildingContextImpl sourceModelBuildingContext) { + if ( valueTypeDescriptor.getValueType().isArray() ) { + final ValueTypeDescriptor elementTypeDescriptor = ( (ArrayTypeDescriptor) valueTypeDescriptor ).getElementTypeDescriptor(); + final ArrayValueConverter valueConverter = new ArrayValueConverter<>( elementTypeDescriptor ); + final ArrayValueExtractor valueExtractor = new ArrayValueExtractor<>( valueConverter ); + converterCollector.accept( valueTypeDescriptor, (ValueConverter) valueConverter ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) valueExtractor ); + return (ValueConverter) valueConverter; + } + + if ( isBoolean( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) BooleanValueConverter.BOOLEAN_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) BooleanValueExtractor.BOOLEAN_EXTRACTOR ); + return (ValueConverter) BooleanValueConverter.BOOLEAN_VALUE_WRAPPER; + } + + if ( isByte( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) ByteValueConverter.BYTE_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) ByteValueExtractor.BYTE_EXTRACTOR ); + return (ValueConverter) ByteValueConverter.BYTE_VALUE_WRAPPER; + } + + if ( isChar( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) CharacterValueConverter.CHARACTER_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) CharacterValueExtractor.CHARACTER_EXTRACTOR ); + return (ValueConverter) CharacterValueConverter.CHARACTER_VALUE_WRAPPER; + } + + if ( isDouble( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) DoubleValueConverter.DOUBLE_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) DoubleValueExtractor.DOUBLE_EXTRACTOR ); + return (ValueConverter) DoubleValueConverter.DOUBLE_VALUE_WRAPPER; + } + + if ( isFloat( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) FloatValueConverter.FLOAT_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) FloatValueExtractor.FLOAT_EXTRACTOR ); + return (ValueConverter) FloatValueConverter.FLOAT_VALUE_WRAPPER; + } + + if ( isInt( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) IntegerValueConverter.INTEGER_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) IntegerValueExtractor.INTEGER_EXTRACTOR ); + return (ValueConverter) IntegerValueConverter.INTEGER_VALUE_WRAPPER; + } + + if ( isLong( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) LongValueConverter.LONG_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) LongValueExtractor.LONG_EXTRACTOR ); + return (ValueConverter) LongValueConverter.LONG_VALUE_WRAPPER; + } + + if ( isShort( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) ShortValueConverter.SHORT_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) ShortValueExtractor.SHORT_EXTRACTOR ); + return (ValueConverter) ShortValueConverter.SHORT_VALUE_WRAPPER; + } + + if ( valueTypeDescriptor.getValueType() == String.class ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) StringValueConverter.STRING_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) StringValueExtractor.STRING_EXTRACTOR ); + return (ValueConverter) StringValueConverter.STRING_VALUE_WRAPPER; + } + + if ( valueTypeDescriptor.getValueType().isAnnotation() ) { + final AnnotationDescriptor annotationDescriptor = sourceModelBuildingContext + .getAnnotationDescriptorRegistry() + .getDescriptor( (Class) valueTypeDescriptor.getValueType() ); + final NestedValueConverter jandexNestedValueConverter = new NestedValueConverter<>( annotationDescriptor ); + final NestedValueExtractor jandexNestedValueExtractor = new NestedValueExtractor<>( jandexNestedValueConverter ); + + converterCollector.accept( valueTypeDescriptor, (ValueConverter) jandexNestedValueConverter ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) jandexNestedValueExtractor ); + return (ValueConverter) jandexNestedValueConverter; + } + + if ( valueTypeDescriptor.getValueType().isEnum() ) { + //noinspection rawtypes + final EnumValueConverter converter = new EnumValueConverter( valueTypeDescriptor.getValueType() ); + converterCollector.accept( valueTypeDescriptor, (ValueConverter) converter ); + //noinspection rawtypes + extractorCollector.accept( valueTypeDescriptor, new EnumValueExtractor( converter ) ); + return (ValueConverter) converter; + } + + if ( valueTypeDescriptor.getValueType() == Class.class ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) ClassValueConverter.CLASS_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) ClassValueExtractor.CLASS_EXTRACTOR ); + return (ValueConverter) ClassValueConverter.CLASS_VALUE_WRAPPER; + } + + throw new UnsupportedOperationException( "Unhandled value type : " + valueTypeDescriptor ); + } + + @SuppressWarnings("unchecked") + public static ValueExtractor buildValueHandlersReturnExtractor( + ValueTypeDescriptor valueTypeDescriptor, + BiConsumer,ValueConverter> converterCollector, + BiConsumer, ValueExtractor> extractorCollector, + SourceModelBuildingContextImpl sourceModelBuildingContext) { + if ( valueTypeDescriptor.getValueType().isArray() ) { + final ValueTypeDescriptor elementTypeDescriptor = ( (ArrayTypeDescriptor) valueTypeDescriptor ).getElementTypeDescriptor(); + final ArrayValueConverter valueConverter = new ArrayValueConverter<>( elementTypeDescriptor ); + final ArrayValueExtractor valueExtractor = new ArrayValueExtractor<>( valueConverter ); + converterCollector.accept( valueTypeDescriptor, (ValueConverter) valueConverter ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) valueExtractor ); + return (ValueExtractor) valueExtractor; + } + + if ( isBoolean( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) BooleanValueConverter.BOOLEAN_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) BooleanValueExtractor.BOOLEAN_EXTRACTOR ); + return (ValueExtractor) BooleanValueExtractor.BOOLEAN_EXTRACTOR; + } + + if ( isByte( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) ByteValueConverter.BYTE_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) ByteValueExtractor.BYTE_EXTRACTOR ); + return (ValueExtractor) ByteValueExtractor.BYTE_EXTRACTOR; + } + + if ( isChar( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) CharacterValueConverter.CHARACTER_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) CharacterValueExtractor.CHARACTER_EXTRACTOR ); + return (ValueExtractor) CharacterValueExtractor.CHARACTER_EXTRACTOR; + } + + if ( isDouble( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) DoubleValueConverter.DOUBLE_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) DoubleValueExtractor.DOUBLE_EXTRACTOR ); + return (ValueExtractor) DoubleValueExtractor.DOUBLE_EXTRACTOR; + } + + if ( isFloat( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) FloatValueConverter.FLOAT_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) FloatValueExtractor.FLOAT_EXTRACTOR ); + return (ValueExtractor) FloatValueExtractor.FLOAT_EXTRACTOR; + } + + if ( isInt( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) IntegerValueConverter.INTEGER_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) IntegerValueExtractor.INTEGER_EXTRACTOR ); + return (ValueExtractor) IntegerValueExtractor.INTEGER_EXTRACTOR; + } + + if ( isLong( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) LongValueConverter.LONG_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) LongValueExtractor.LONG_EXTRACTOR ); + return (ValueExtractor) LongValueExtractor.LONG_EXTRACTOR; + } + + if ( isShort( valueTypeDescriptor ) ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) ShortValueConverter.SHORT_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) ShortValueExtractor.SHORT_EXTRACTOR ); + return (ValueExtractor) ShortValueExtractor.SHORT_EXTRACTOR; + } + + if ( valueTypeDescriptor.getValueType() == String.class ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) StringValueConverter.STRING_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) StringValueExtractor.STRING_EXTRACTOR ); + return (ValueExtractor) StringValueExtractor.STRING_EXTRACTOR; + } + + if ( valueTypeDescriptor.getValueType().isAnnotation() ) { + final AnnotationDescriptor annotationDescriptor = sourceModelBuildingContext + .getAnnotationDescriptorRegistry() + .getDescriptor( (Class) valueTypeDescriptor.getValueType() ); + final NestedValueConverter jandexNestedValueConverter = new NestedValueConverter<>( annotationDescriptor ); + final NestedValueExtractor jandexNestedValueExtractor = new NestedValueExtractor<>( jandexNestedValueConverter ); + + converterCollector.accept( valueTypeDescriptor, (ValueConverter) jandexNestedValueConverter ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) jandexNestedValueExtractor ); + return (ValueExtractor) jandexNestedValueExtractor; + } + + if ( valueTypeDescriptor.getValueType().isEnum() ) { + //noinspection rawtypes + final EnumValueConverter converter = new EnumValueConverter( valueTypeDescriptor.getValueType() ); + //noinspection rawtypes + final EnumValueExtractor extractor = new EnumValueExtractor<>( converter ); + converterCollector.accept( valueTypeDescriptor, (ValueConverter) converter ); + extractorCollector.accept( valueTypeDescriptor, extractor ); + return (ValueExtractor) extractor; + } + + if ( valueTypeDescriptor.getValueType() == Class.class ) { + converterCollector.accept( valueTypeDescriptor, (ValueConverter) ClassValueConverter.CLASS_VALUE_WRAPPER ); + extractorCollector.accept( valueTypeDescriptor, (ValueExtractor) ClassValueExtractor.CLASS_EXTRACTOR ); + return (ValueExtractor) ClassValueExtractor.CLASS_EXTRACTOR; + } + + throw new UnsupportedOperationException( "Unhandled value type : " + valueTypeDescriptor ); + } + + private static boolean isBoolean(ValueTypeDescriptor valueTypeDescriptor) { + return valueTypeDescriptor.getValueType() == boolean.class + || valueTypeDescriptor.getValueType() == Boolean.class; + } + + private static boolean isByte(ValueTypeDescriptor valueTypeDescriptor) { + return valueTypeDescriptor.getValueType() == byte.class + || valueTypeDescriptor.getValueType() == Byte.class; + } + + private static boolean isChar(ValueTypeDescriptor valueTypeDescriptor) { + return valueTypeDescriptor.getValueType() == char.class + || valueTypeDescriptor.getValueType() == Character.class; + } + + private static boolean isDouble(ValueTypeDescriptor valueTypeDescriptor) { + return valueTypeDescriptor.getValueType() == double.class + || valueTypeDescriptor.getValueType() == Double.class; + } + + private static boolean isFloat(ValueTypeDescriptor valueTypeDescriptor) { + return valueTypeDescriptor.getValueType() == float.class + || valueTypeDescriptor.getValueType() == Float.class; + } + + private static boolean isShort(ValueTypeDescriptor valueTypeDescriptor) { + return valueTypeDescriptor.getValueType() == short.class + || valueTypeDescriptor.getValueType() == Short.class; + } + + private static boolean isInt(ValueTypeDescriptor valueTypeDescriptor) { + return valueTypeDescriptor.getValueType() == int.class + || valueTypeDescriptor.getValueType() == Integer.class; + } + + private static boolean isLong(ValueTypeDescriptor valueTypeDescriptor) { + return valueTypeDescriptor.getValueType() == long.class + || valueTypeDescriptor.getValueType() == Long.class; + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/RecordComponentDetailsImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/RecordComponentDetailsImpl.java new file mode 100644 index 0000000..498e6d5 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/RecordComponentDetailsImpl.java @@ -0,0 +1,150 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.util.Collection; +import java.util.Map; + +import org.hibernate.models.IllegalCastException; +import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.FieldDetails; +import org.hibernate.models.spi.MethodDetails; +import org.hibernate.models.spi.MutableClassDetails; +import org.hibernate.models.spi.MutableMemberDetails; +import org.hibernate.models.spi.RecordComponentDetails; +import org.hibernate.models.spi.TypeDetails; + +import net.bytebuddy.description.annotation.AnnotationSource; +import net.bytebuddy.description.type.RecordComponentDescription; + +/** + * @author Steve Ebersole + */ +public class RecordComponentDetailsImpl + extends AbstractAnnotationTarget + implements RecordComponentDetails, MutableMemberDetails { + private final RecordComponentDescription.InDefinedShape underlyingComponent; + private final ClassDetails declaringClassDetails; + private final TypeDetails type; + + private final boolean isArray; + private final boolean isPlural; + + public RecordComponentDetailsImpl( + RecordComponentDescription.InDefinedShape underlyingComponent, + ClassDetailsImpl declaringClassDetails, + SourceModelBuildingContextImpl modelContext) { + super( modelContext ); + this.underlyingComponent = underlyingComponent; + this.declaringClassDetails = declaringClassDetails; + + this.type = TypeSwitchStandard.switchType( underlyingComponent.getType(), declaringClassDetails, modelContext ); + + this.isArray = underlyingComponent.getType().isArray(); + this.isPlural = isArray || type.isImplementor( Collection.class ) || type.isImplementor( Map.class ); + } + + @Override + protected AnnotationSource getAnnotationSource() { + return underlyingComponent; + } + + @Override + public String getName() { + return underlyingComponent.getActualName(); + } + + @Override + public TypeDetails getType() { + return type; + } + + @Override + public ClassDetails getDeclaringType() { + return declaringClassDetails; + } + + @Override + public boolean isPlural() { + return isPlural; + } + + @Override + public boolean isArray() { + return isArray; + } + + @Override + public int getModifiers() { + return underlyingComponent.getAccessor().getModifiers(); + } + + + private Member underlyingMember; + + @Override + public Member toJavaMember() { + if ( underlyingMember == null ) { + underlyingMember = resolveJavaMember(); + } + return underlyingMember; + } + + private Field resolveJavaMember() { + final Class declaringJavaClass = declaringClassDetails.toJavaClass(); + try { + return declaringJavaClass.getField( getName() ); + } + catch (NoSuchFieldException e) { + throw new RuntimeException( + String.format( + "Has no corresponding record-component : %s.%s", + declaringJavaClass.getName(), + getName() + ), + e + ); + } + } + + @Override + public String toString() { + return "RecordComponentDetails(" + getName() + ")"; + } + + @Override + public RecordComponentDetails asRecordComponentDetails() { + return this; + } + + @Override + public MutableMemberDetails asMemberDetails() { + return this; + } + + @Override + public FieldDetails asFieldDetails() { + throw new IllegalCastException( "RecordComponentDetails cannot be cast as FieldDetails" ); + } + + @Override + public MethodDetails asMethodDetails() { + throw new IllegalCastException( "FieldDetails cannot be cast as MethodDetails" ); + } + + @Override + public AnnotationDescriptor asAnnotationDescriptor() { + throw new IllegalCastException( "FieldDetails cannot be cast to an AnnotationDescriptor" ); + } + + @Override + public MutableClassDetails asClassDetails() { + throw new IllegalCastException( "FieldDetails cannot be cast to a ClassDetails" ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/SourceModelBuildingContextImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/SourceModelBuildingContextImpl.java new file mode 100644 index 0000000..22c516d --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/SourceModelBuildingContextImpl.java @@ -0,0 +1,113 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal; + +import java.util.HashMap; +import java.util.Map; + +import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsBuildingContext; +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.bytebuddy.spi.ValueExtractor; +import org.hibernate.models.internal.AbstractModelBuildingContext; +import org.hibernate.models.internal.MutableAnnotationDescriptorRegistry; +import org.hibernate.models.internal.MutableClassDetailsRegistry; +import org.hibernate.models.internal.SimpleClassLoading; +import org.hibernate.models.serial.internal.StorableContextImpl; +import org.hibernate.models.serial.spi.StorableContext; +import org.hibernate.models.spi.ClassLoading; +import org.hibernate.models.spi.RegistryPrimer; +import org.hibernate.models.spi.ValueTypeDescriptor; + +import net.bytebuddy.pool.TypePool; + +/** + * SourceModelBuildingContext implementation based on ByteBuddy, leveraging a + * {@linkplain TypePool} to inspect + * + * @author Steve Ebersole + */ +public class SourceModelBuildingContextImpl + extends AbstractModelBuildingContext + implements ByteBuddyModelsBuildingContext { + private final TypePool typePool; + + private final ClassDetailsRegistryImpl classDetailsRegistry; + private final AnnotationDescriptorRegistryImpl descriptorRegistry; + + private final Map valueConverters = new HashMap<>(); + private final Map valueExtractors = new HashMap<>(); + + public SourceModelBuildingContextImpl( + TypePool typePool, + RegistryPrimer registryPrimer) { + this( typePool, SimpleClassLoading.SIMPLE_CLASS_LOADING, registryPrimer ); + } + + public SourceModelBuildingContextImpl( + TypePool typePool, + ClassLoading classLoading, + RegistryPrimer registryPrimer) { + super( classLoading ); + + this.typePool = typePool; + + this.classDetailsRegistry = new ClassDetailsRegistryImpl( this ); + this.descriptorRegistry = new AnnotationDescriptorRegistryImpl( this ); + + primeRegistries( registryPrimer ); + } + + @Override + public TypePool getTypePool() { + return typePool; + } + + @Override + public MutableClassDetailsRegistry getClassDetailsRegistry() { + return classDetailsRegistry; + } + + @Override + public MutableAnnotationDescriptorRegistry getAnnotationDescriptorRegistry() { + return descriptorRegistry; + } + + @Override + public StorableContext toStorableForm() { + return new StorableContextImpl( classDetailsRegistry.getClassDetailsMap(), descriptorRegistry.getDescriptorMap() ); + } + + @Override + public ValueConverter getValueConverter(ValueTypeDescriptor valueTypeDescriptor) { + //noinspection unchecked + final ValueConverter existing = valueConverters.get( valueTypeDescriptor ); + if ( existing != null ) { + return existing; + } + + return ModelBuilders.buildValueHandlersReturnConverter( + valueTypeDescriptor, + valueConverters::put, + valueExtractors::put, + this + ); + } + + @Override + public ValueExtractor getValueExtractor(ValueTypeDescriptor valueTypeDescriptor) { + //noinspection unchecked + final ValueExtractor existing = valueExtractors.get( valueTypeDescriptor ); + if ( existing != null ) { + return existing; + } + + return ModelBuilders.buildValueHandlersReturnExtractor( + valueTypeDescriptor, + valueConverters::put, + valueExtractors::put, + this + ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/TypeSwitchStandard.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/TypeSwitchStandard.java new file mode 100644 index 0000000..cf7f3e0 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/TypeSwitchStandard.java @@ -0,0 +1,158 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.hibernate.models.bytebuddy.spi.TypeSwitch; +import org.hibernate.models.bytebuddy.spi.TypeSwitcher; +import org.hibernate.models.internal.ClassTypeDetailsImpl; +import org.hibernate.models.internal.ParameterizedTypeDetailsImpl; +import org.hibernate.models.internal.PrimitiveTypeDetailsImpl; +import org.hibernate.models.internal.TypeVariableDetailsImpl; +import org.hibernate.models.internal.TypeVariableReferenceDetailsImpl; +import org.hibernate.models.internal.VoidTypeDetailsImpl; +import org.hibernate.models.internal.WildcardTypeDetailsImpl; +import org.hibernate.models.internal.util.CollectionHelper; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.SourceModelBuildingContext; +import org.hibernate.models.spi.TypeDetails; +import org.hibernate.models.spi.TypeDetailsHelper; + +import net.bytebuddy.description.type.TypeDefinition; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.description.type.TypeList; + +import static org.hibernate.models.internal.util.CollectionHelper.arrayList; + +/** + * @author Steve Ebersole + */ +public class TypeSwitchStandard implements TypeSwitch { + + public static TypeDetails switchType(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext) { + return switchType( typeDescription, null, buildingContext ); + } + + public static TypeDetails switchType(TypeDefinition typeDescription, ClassDetails declaringType, SourceModelBuildingContext buildingContext) { + final TypeSwitchStandard switchImpl = new TypeSwitchStandard( declaringType ); + return TypeSwitcher.switchType( typeDescription, switchImpl, buildingContext ); + } + + + private final ClassDetails declaringType; + + public TypeSwitchStandard(ClassDetails declaringType) { + this.declaringType = declaringType; + } + + @Override + public TypeDetails caseClass(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext) { + final ClassDetails classDetails = buildingContext + .getClassDetailsRegistry() + .resolveClassDetails( typeDescription.getTypeName() ); + return new ClassTypeDetailsImpl( classDetails, TypeDetails.Kind.CLASS ); + } + + @Override + public TypeDetails casePrimitive(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext) { + final ClassDetails classDetails = buildingContext + .getClassDetailsRegistry() + .resolveClassDetails( typeDescription.getTypeName() ); + return new PrimitiveTypeDetailsImpl( classDetails ); + } + + @Override + public TypeDetails caseVoid(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext) { + final ClassDetails classDetails = buildingContext + .getClassDetailsRegistry() + // allows for void or Void + .resolveClassDetails( typeDescription.getTypeName() ); + return new VoidTypeDetailsImpl( classDetails ); + } + + @Override + public TypeDetails caseParameterizedType( + TypeDefinition typeDescription, + SourceModelBuildingContext buildingContext) { + final ClassDetails classDetails = buildingContext + .getClassDetailsRegistry() + .resolveClassDetails( typeDescription.asErasure().getName() ); + return new ParameterizedTypeDetailsImpl( + classDetails, + resolveTypes( typeDescription.asGenericType().getTypeArguments(), this, buildingContext ), + null + ); + } + + @Override + public TypeDetails caseWildcardType(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext) { + final TypeList.Generic upperBounds = typeDescription.asGenericType().getUpperBounds(); + final TypeList.Generic lowerBounds = typeDescription.asGenericType().getLowerBounds(); + + final TypeList.Generic bound; + final boolean isExtends; + + if ( ! (upperBounds instanceof TypeList.Generic.Empty) ) { + bound = upperBounds; + isExtends = true; + } + else if ( ! (lowerBounds instanceof TypeList.Generic.Empty) ) { + bound = lowerBounds; + isExtends = false; + } + else { + throw new IllegalArgumentException( "What?" ); + } + + return new WildcardTypeDetailsImpl( TypeSwitcher.switchType( bound.get( 0 ), this, buildingContext ), isExtends ); + } + + @Override + public TypeDetails caseTypeVariable(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext) { + return new TypeVariableDetailsImpl( + typeDescription.getActualName(), + declaringType, + resolveTypes( typeDescription.asGenericType().getUpperBounds(), this, buildingContext ) + ); + } + + @Override + public TypeDetails caseTypeVariableReference( + TypeDefinition typeDescription, + SourceModelBuildingContext buildingContext) { + return new TypeVariableReferenceDetailsImpl( typeDescription.getActualName() ); + } + + @Override + public TypeDetails caseArrayType(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext) { + final TypeDetails constituentType = TypeSwitcher.switchType( typeDescription.getComponentType(), this, buildingContext ); + return TypeDetailsHelper.arrayOf( constituentType, buildingContext ); + } + + @Override + public TypeDetails defaultCase(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext) { + throw new UnsupportedOperationException( "Unexpected Type kind - " + typeDescription ); + } + + public static List resolveTypes( + TypeList.Generic generics, + TypeSwitchStandard typeSwitch, + SourceModelBuildingContext buildingContext) { + if ( CollectionHelper.isEmpty( generics ) ) { + return Collections.emptyList(); + } + + final ArrayList result = arrayList( generics.size() ); + for ( TypeDescription.Generic bound : generics ) { + final TypeDetails switchedType = TypeSwitcher.switchType( bound, typeSwitch, buildingContext ); + result.add( switchedType ); + } + + return result; + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/AbstractValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/AbstractValueExtractor.java new file mode 100644 index 0000000..11df79d --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/AbstractValueExtractor.java @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.bytebuddy.spi.ValueExtractor; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationDescription; +import net.bytebuddy.description.annotation.AnnotationValue; + + +/** + * Support for ByteBuddy-based extractors + * + * @author Steve Ebersole + */ +public abstract class AbstractValueExtractor implements ValueExtractor { + + protected abstract W extractAndWrap(AnnotationValue byteBuddyValue, SourceModelBuildingContext buildingContext); + + @Override + public W extractValue( + AnnotationDescription annotation, + String attributeName, + SourceModelBuildingContext buildingContext) { + final AnnotationValue value = annotation.getValue( attributeName ); + return extractAndWrap( value, buildingContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java new file mode 100644 index 0000000..75792c7 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java @@ -0,0 +1,32 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.SourceModelBuildingContext; +import org.hibernate.models.spi.ValueTypeDescriptor; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for converting array values + * + * @author Steve Ebersole + */ +public class ArrayValueConverter implements ValueConverter { + private final ValueTypeDescriptor elementTypeDescriptor; + + public ArrayValueConverter(ValueTypeDescriptor elementTypeDescriptor) { + this.elementTypeDescriptor = elementTypeDescriptor; + } + + @Override + public V[] convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { + assert byteBuddyValue != null; + + //noinspection unchecked + return (V[]) byteBuddyValue.resolve(); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueExtractor.java new file mode 100644 index 0000000..257aa28 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueExtractor.java @@ -0,0 +1,28 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for extracting array values + * + * @author Steve Ebersole + */ +public class ArrayValueExtractor extends AbstractValueExtractor { + private final ValueConverter wrapper; + + public ArrayValueExtractor(ValueConverter wrapper) { + this.wrapper = wrapper; + } + + @Override + protected V[] extractAndWrap(AnnotationValue byteBuddyValue, SourceModelBuildingContext buildingContext) { + return wrapper.convert( byteBuddyValue, buildingContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/BooleanValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/BooleanValueConverter.java new file mode 100644 index 0000000..db868f3 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/BooleanValueConverter.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for converting boolean values + * + * @author Steve Ebersole + */ +public class BooleanValueConverter implements ValueConverter { + public static final BooleanValueConverter BOOLEAN_VALUE_WRAPPER = new BooleanValueConverter(); + + @Override + public Boolean convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { + assert byteBuddyValue != null; + return byteBuddyValue.resolve( Boolean.class ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/BooleanValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/BooleanValueExtractor.java new file mode 100644 index 0000000..20c6481 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/BooleanValueExtractor.java @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for extracting boolean values + * + * @author Steve Ebersole + */ +public class BooleanValueExtractor extends AbstractValueExtractor { + public static final BooleanValueExtractor BOOLEAN_EXTRACTOR = new BooleanValueExtractor(); + + @Override + protected Boolean extractAndWrap(AnnotationValue byteBuddyValue, SourceModelBuildingContext buildingContext) { + assert byteBuddyValue != null; + return BooleanValueConverter.BOOLEAN_VALUE_WRAPPER.convert( byteBuddyValue, buildingContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ByteValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ByteValueConverter.java new file mode 100644 index 0000000..6ba6c16 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ByteValueConverter.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for converting byte values + * + * @author Steve Ebersole + */ +public class ByteValueConverter implements ValueConverter { + public static final ByteValueConverter BYTE_VALUE_WRAPPER = new ByteValueConverter(); + + @Override + public Byte convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { + assert byteBuddyValue != null; + return byteBuddyValue.resolve( Byte.class ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ByteValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ByteValueExtractor.java new file mode 100644 index 0000000..fcbb9bd --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ByteValueExtractor.java @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for extracting byte values + * + * @author Steve Ebersole + */ +public class ByteValueExtractor extends AbstractValueExtractor { + public static final ByteValueExtractor BYTE_EXTRACTOR = new ByteValueExtractor(); + + @Override + protected Byte extractAndWrap(AnnotationValue byteBuddyValue, SourceModelBuildingContext buildingContext) { + assert byteBuddyValue != null; + return ByteValueConverter.BYTE_VALUE_WRAPPER.convert( byteBuddyValue, buildingContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/CharacterValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/CharacterValueConverter.java new file mode 100644 index 0000000..79218a5 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/CharacterValueConverter.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for converting char values + * + * @author Steve Ebersole + */ +public class CharacterValueConverter implements ValueConverter { + public static final CharacterValueConverter CHARACTER_VALUE_WRAPPER = new CharacterValueConverter(); + + @Override + public Character convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { + assert byteBuddyValue != null; + return byteBuddyValue.resolve( Character.class ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/CharacterValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/CharacterValueExtractor.java new file mode 100644 index 0000000..67f5d93 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/CharacterValueExtractor.java @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for extracting char values + * + * @author Steve Ebersole + */ +public class CharacterValueExtractor extends AbstractValueExtractor { + public static final CharacterValueExtractor CHARACTER_EXTRACTOR = new CharacterValueExtractor(); + + @Override + protected Character extractAndWrap(AnnotationValue byteBuddyValue, SourceModelBuildingContext buildingContext) { + assert byteBuddyValue != null; + return CharacterValueConverter.CHARACTER_VALUE_WRAPPER.convert( byteBuddyValue, buildingContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ClassValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ClassValueConverter.java new file mode 100644 index 0000000..d17e137 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ClassValueConverter.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + + +/** + * Support for converting Class values + * + * @author Steve Ebersole + */ +public class ClassValueConverter implements ValueConverter> { + public static final ClassValueConverter CLASS_VALUE_WRAPPER = new ClassValueConverter(); + + @Override + public Class convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { + return byteBuddyValue.resolve( Class.class ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ClassValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ClassValueExtractor.java new file mode 100644 index 0000000..0e59a18 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ClassValueExtractor.java @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for extracting Class values + * + * @author Steve Ebersole + */ +public class ClassValueExtractor extends AbstractValueExtractor> { + public static final ClassValueExtractor CLASS_EXTRACTOR = new ClassValueExtractor(); + + @Override + protected Class extractAndWrap(AnnotationValue byteBuddyValue, SourceModelBuildingContext buildingContext) { + assert byteBuddyValue != null; + return ClassValueConverter.CLASS_VALUE_WRAPPER.convert( byteBuddyValue, buildingContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/DoubleValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/DoubleValueConverter.java new file mode 100644 index 0000000..875da39 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/DoubleValueConverter.java @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.SourceModelBuildingContext; +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for converting double values + * + * @author Steve Ebersole + */ +public class DoubleValueConverter implements ValueConverter { + public static final DoubleValueConverter DOUBLE_VALUE_WRAPPER = new DoubleValueConverter(); + + @Override + public Double convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { + assert byteBuddyValue != null; + return byteBuddyValue.resolve( Double.class ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/DoubleValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/DoubleValueExtractor.java new file mode 100644 index 0000000..8a02961 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/DoubleValueExtractor.java @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for extracting double values + * + * @author Steve Ebersole + */ +public class DoubleValueExtractor extends AbstractValueExtractor { + public static final DoubleValueExtractor DOUBLE_EXTRACTOR = new DoubleValueExtractor(); + + @Override + protected Double extractAndWrap(AnnotationValue byteBuddyValue, SourceModelBuildingContext buildingContext) { + assert byteBuddyValue != null; + return DoubleValueConverter.DOUBLE_VALUE_WRAPPER.convert( byteBuddyValue, buildingContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/EnumValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/EnumValueConverter.java new file mode 100644 index 0000000..e94fe35 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/EnumValueConverter.java @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; +import net.bytebuddy.description.enumeration.EnumerationDescription; + +/** + * Support for converting enum values + * + * @author Steve Ebersole + */ +public class EnumValueConverter> implements ValueConverter { + private final Class enumClass; + + public EnumValueConverter(Class enumClass) { + this.enumClass = enumClass; + } + + @Override + public E convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { + assert byteBuddyValue != null; + final EnumerationDescription resolved = byteBuddyValue.resolve( EnumerationDescription.class ); + return resolved.load( enumClass ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/EnumValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/EnumValueExtractor.java new file mode 100644 index 0000000..5f55e98 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/EnumValueExtractor.java @@ -0,0 +1,28 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for extracting enum values + * + * @author Steve Ebersole + */ +public class EnumValueExtractor> extends AbstractValueExtractor { + private final EnumValueConverter wrapper; + + public EnumValueExtractor(EnumValueConverter wrapper) { + this.wrapper = wrapper; + } + + @Override + protected E extractAndWrap(AnnotationValue byteBuddyValue, SourceModelBuildingContext buildingContext) { + assert byteBuddyValue != null; + return wrapper.convert( byteBuddyValue, buildingContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/FloatValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/FloatValueConverter.java new file mode 100644 index 0000000..73218ca --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/FloatValueConverter.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for converting float values + * + * @author Steve Ebersole + */ +public class FloatValueConverter implements ValueConverter { + public static final FloatValueConverter FLOAT_VALUE_WRAPPER = new FloatValueConverter(); + + @Override + public Float convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { + assert byteBuddyValue != null; + return byteBuddyValue.resolve( Float.class ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/FloatValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/FloatValueExtractor.java new file mode 100644 index 0000000..4edd756 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/FloatValueExtractor.java @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for extracting float values + * + * @author Steve Ebersole + */ +public class FloatValueExtractor extends AbstractValueExtractor { + public static final FloatValueExtractor FLOAT_EXTRACTOR = new FloatValueExtractor(); + + @Override + protected Float extractAndWrap(AnnotationValue byteBuddyValue, SourceModelBuildingContext buildingContext) { + assert byteBuddyValue != null; + return FloatValueConverter.FLOAT_VALUE_WRAPPER.convert( byteBuddyValue, buildingContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/IntegerValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/IntegerValueConverter.java new file mode 100644 index 0000000..85ea62e --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/IntegerValueConverter.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for converting int values + * + * @author Steve Ebersole + */ +public class IntegerValueConverter implements ValueConverter { + public static final IntegerValueConverter INTEGER_VALUE_WRAPPER = new IntegerValueConverter(); + + @Override + public Integer convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { + assert byteBuddyValue != null; + return byteBuddyValue.resolve( Integer.class ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/IntegerValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/IntegerValueExtractor.java new file mode 100644 index 0000000..dc9faa0 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/IntegerValueExtractor.java @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for extracting int values + * + * @author Steve Ebersole + */ +public class IntegerValueExtractor extends AbstractValueExtractor { + public static final IntegerValueExtractor INTEGER_EXTRACTOR = new IntegerValueExtractor(); + + @Override + protected Integer extractAndWrap(AnnotationValue byteBuddyValue, SourceModelBuildingContext buildingContext) { + assert byteBuddyValue != null; + return IntegerValueConverter.INTEGER_VALUE_WRAPPER.convert( byteBuddyValue, buildingContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/LongValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/LongValueConverter.java new file mode 100644 index 0000000..c3b2ac8 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/LongValueConverter.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for converting long values + * + * @author Steve Ebersole + */ +public class LongValueConverter implements ValueConverter { + public static final LongValueConverter LONG_VALUE_WRAPPER = new LongValueConverter(); + + @Override + public Long convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { + assert byteBuddyValue != null; + return byteBuddyValue.resolve( Long.class ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/LongValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/LongValueExtractor.java new file mode 100644 index 0000000..8df78d5 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/LongValueExtractor.java @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for extracting long values + * + * @author Steve Ebersole + */ +public class LongValueExtractor extends AbstractValueExtractor { + public static final LongValueExtractor LONG_EXTRACTOR = new LongValueExtractor(); + + @Override + protected Long extractAndWrap(AnnotationValue byteBuddyValue, SourceModelBuildingContext buildingContext) { + assert byteBuddyValue != null; + return LongValueConverter.LONG_VALUE_WRAPPER.convert( byteBuddyValue, buildingContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/NestedValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/NestedValueConverter.java new file mode 100644 index 0000000..6cccb55 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/NestedValueConverter.java @@ -0,0 +1,32 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import java.lang.annotation.Annotation; + +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for converting nested annotation values + * + * @author Steve Ebersole + */ +public class NestedValueConverter implements ValueConverter { + private final AnnotationDescriptor descriptor; + + public NestedValueConverter(AnnotationDescriptor descriptor) { + assert descriptor != null : "AnnotationDescriptor was null"; + this.descriptor = descriptor; + } + + @Override + public A convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { + return byteBuddyValue.resolve( descriptor.getAnnotationType() ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/NestedValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/NestedValueExtractor.java new file mode 100644 index 0000000..3a083ba --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/NestedValueExtractor.java @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import java.lang.annotation.Annotation; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + + +/** + * Support for extracting nested annotation values + * + * @author Steve Ebersole + */ +public class NestedValueExtractor extends AbstractValueExtractor { + private final NestedValueConverter wrapper; + + public NestedValueExtractor(NestedValueConverter wrapper) { + this.wrapper = wrapper; + } + + @Override + protected A extractAndWrap(AnnotationValue byteBuddyValue, SourceModelBuildingContext buildingContext) { + return wrapper.convert( byteBuddyValue, buildingContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ShortValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ShortValueConverter.java new file mode 100644 index 0000000..ebcd7a9 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ShortValueConverter.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for converting short values + * + * @author Steve Ebersole + */ +public class ShortValueConverter implements ValueConverter { + public static final ShortValueConverter SHORT_VALUE_WRAPPER = new ShortValueConverter(); + + @Override + public Short convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { + assert byteBuddyValue != null; + return byteBuddyValue.resolve( Short.class ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ShortValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ShortValueExtractor.java new file mode 100644 index 0000000..7b8f6e0 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ShortValueExtractor.java @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for extracting short values + * + * @author Steve Ebersole + */ +public class ShortValueExtractor extends AbstractValueExtractor { + public static final ShortValueExtractor SHORT_EXTRACTOR = new ShortValueExtractor(); + + protected Short extractAndWrap(AnnotationValue byteBuddyValue, SourceModelBuildingContext buildingContext) { + assert byteBuddyValue != null; + return ShortValueConverter.SHORT_VALUE_WRAPPER.convert( byteBuddyValue, buildingContext ); + } + +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/StringValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/StringValueConverter.java new file mode 100644 index 0000000..fd417a6 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/StringValueConverter.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for converting string values + * + * @author Steve Ebersole + */ +public class StringValueConverter implements ValueConverter { + public static final StringValueConverter STRING_VALUE_WRAPPER = new StringValueConverter(); + + @Override + public String convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { + assert byteBuddyValue != null; + return byteBuddyValue.resolve( String.class ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/StringValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/StringValueExtractor.java new file mode 100644 index 0000000..7a6553b --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/StringValueExtractor.java @@ -0,0 +1,23 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.internal.values; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Support for extracting string values + * + * @author Steve Ebersole + */ +public class StringValueExtractor extends AbstractValueExtractor { + public static final StringValueExtractor STRING_EXTRACTOR = new StringValueExtractor(); + + @Override + protected String extractAndWrap(AnnotationValue byteBuddyValue, SourceModelBuildingContext buildingContext) { + return StringValueConverter.STRING_VALUE_WRAPPER.convert( byteBuddyValue, buildingContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/package-info.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/package-info.java new file mode 100644 index 0000000..4681e59 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/package-info.java @@ -0,0 +1,6 @@ +/** + * Implementation of {@code hibernate-models} contracts using Byte Buddy. + * + * @author Steve Ebersole + */ +package org.hibernate.models.bytebuddy; diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyModelsBuildingContext.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyModelsBuildingContext.java new file mode 100644 index 0000000..4ae17e8 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyModelsBuildingContext.java @@ -0,0 +1,20 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.spi; + +import org.hibernate.models.spi.SourceModelBuildingContext; +import org.hibernate.models.spi.ValueTypeDescriptor; + +import net.bytebuddy.pool.TypePool; + +/** + * @author Steve Ebersole + */ +public interface ByteBuddyModelsBuildingContext extends SourceModelBuildingContext { + TypePool getTypePool(); + + ValueConverter getValueConverter(ValueTypeDescriptor valueTypeDescriptor); + ValueExtractor getValueExtractor(ValueTypeDescriptor valueTypeDescriptor); +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/TypeSwitch.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/TypeSwitch.java new file mode 100644 index 0000000..32d8da8 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/TypeSwitch.java @@ -0,0 +1,33 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.spi; + +import org.hibernate.models.spi.SourceModelBuildingContext; + + +import net.bytebuddy.description.type.TypeDefinition; + +/** + * @author Steve Ebersole + */ +public interface TypeSwitch { + T caseClass(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext); + + T casePrimitive(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext); + + T caseVoid(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext); + + T caseParameterizedType(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext); + + T caseWildcardType(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext); + + T caseTypeVariable(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext); + + T caseTypeVariableReference(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext); + + T caseArrayType(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext); + + T defaultCase(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext); +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/TypeSwitcher.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/TypeSwitcher.java new file mode 100644 index 0000000..d6677d1 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/TypeSwitcher.java @@ -0,0 +1,55 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.spi; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.type.TypeDefinition; +import net.bytebuddy.description.type.TypeDescription; + +/** + * @author Steve Ebersole + */ +public class TypeSwitcher { + private static final TypeDescription VOID = TypeDescription.ForLoadedType.of( void.class ); + + public static T switchType(TypeDefinition typeDescription, TypeSwitch typeSwitch, SourceModelBuildingContext buildingContext) { + if ( VOID.equals( typeDescription ) ) { + return typeSwitch.caseVoid( typeDescription, buildingContext ); + } + + if ( typeDescription.isPrimitive() ) { + return typeSwitch.casePrimitive( typeDescription, buildingContext ); + } + + if ( typeDescription.isArray() ) { + return typeSwitch.caseArrayType( typeDescription, buildingContext ); + } + + switch( typeDescription.getSort() ) { + case NON_GENERIC -> { + return typeSwitch.caseClass( typeDescription, buildingContext ); + } + case GENERIC_ARRAY -> { + return typeSwitch.caseArrayType( typeDescription, buildingContext ); + } + case PARAMETERIZED -> { + return typeSwitch.caseParameterizedType( typeDescription, buildingContext ); + } + case WILDCARD -> { + return typeSwitch.caseWildcardType( typeDescription, buildingContext ); + } + case VARIABLE -> { + return typeSwitch.caseTypeVariable( typeDescription, buildingContext ); + } + case VARIABLE_SYMBOLIC -> { + return typeSwitch.caseTypeVariableReference( typeDescription, buildingContext ); + } + default -> { + return typeSwitch.defaultCase( typeDescription, buildingContext ); + } + } + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ValueConverter.java new file mode 100644 index 0000000..8a8b177 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ValueConverter.java @@ -0,0 +1,21 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.spi; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationValue; + +/** + * Used in processing ByteBuddy references. + * Given a ByteBuddy {@linkplain AnnotationValue}, converts to the corresponding "value type". + * + * @param The value type. + * + * @author Steve Ebersole + */ +public interface ValueConverter { + V convert(AnnotationValue attributeValue, SourceModelBuildingContext modelContext); +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ValueExtractor.java new file mode 100644 index 0000000..c3efa3e --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ValueExtractor.java @@ -0,0 +1,32 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.spi; + +import org.hibernate.models.spi.AttributeDescriptor; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.description.annotation.AnnotationDescription; + +/** + * Contract to extract a named attribute value from an {@linkplain AnnotationDescription annotation}. + * + * @author Steve Ebersole + */ +public interface ValueExtractor { + /** + * Extract the value of the named attribute from the given annotation + */ + V extractValue(AnnotationDescription annotation, String attributeName, SourceModelBuildingContext modelContext); + + /** + * Extract the value of the described attribute from the given annotation + */ + default V extractValue( + AnnotationDescription annotation, + AttributeDescriptor attributeDescriptor, + SourceModelBuildingContext modelContext) { + return extractValue( annotation, attributeDescriptor.getName(), modelContext ); + } +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SimpleTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SimpleTests.java new file mode 100644 index 0000000..f1e18af --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SimpleTests.java @@ -0,0 +1,38 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy; + +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.ClassDetailsRegistry; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import org.junit.jupiter.api.Test; + + +/** + * @author Steve Ebersole + */ +public class SimpleTests { + @Test + void testSimple1() { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( + Base.class, + Thing.class + ); + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + final ClassDetails classDetails = classDetailsRegistry.getClassDetails( Base.class.getName() ); + classDetails.getFields(); + classDetails.getMethods(); + } + + public static class Base { + private String[] strings; + private I[] generics; + } + + public static class Thing extends Base { + } +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SourceModelTestHelper.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SourceModelTestHelper.java new file mode 100644 index 0000000..3a075d8 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SourceModelTestHelper.java @@ -0,0 +1,118 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import org.hibernate.models.ModelsException; +import org.hibernate.models.bytebuddy.internal.SourceModelBuildingContextImpl; +import org.hibernate.models.internal.BasicModelBuildingContextImpl; +import org.hibernate.models.internal.util.CollectionHelper; +import org.hibernate.models.orm.OrmAnnotationHelper; +import org.hibernate.models.spi.ClassLoading; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import net.bytebuddy.dynamic.ClassFileLocator; +import net.bytebuddy.pool.TypePool; + +import static org.hibernate.models.internal.SimpleClassLoading.SIMPLE_CLASS_LOADING; + +/** + * @author Steve Ebersole + */ +public class SourceModelTestHelper { + + public static SourceModelBuildingContext createBuildingContext(Class modelClass) { + return createBuildingContext( SIMPLE_CLASS_LOADING, modelClass ); + } + + public static SourceModelBuildingContext createBuildingContext(Class... modelClasses) { + return createBuildingContext( SIMPLE_CLASS_LOADING, modelClasses ); + } + + public static SourceModelBuildingContext createBuildingContext(ClassLoading classLoadingAccess, Class... modelClasses) { + final TypePool typePool = buildByteBuddyTypePool( classLoadingAccess, modelClasses ); + return createBuildingContext( typePool, modelClasses ); + } + + public static SourceModelBuildingContext createBuildingContext(TypePool typePool, Class modelClass) { + return createBuildingContext( typePool, SIMPLE_CLASS_LOADING, modelClass ); + } + + public static SourceModelBuildingContext createBuildingContext(TypePool typePool, Class... modelClasses) { + return createBuildingContext( typePool, SIMPLE_CLASS_LOADING, modelClasses ); + } + + public static SourceModelBuildingContext createBuildingContext( + TypePool typePool, + ClassLoading classLoadingAccess, + Class... modelClasses) { + final SourceModelBuildingContext ctx; + if ( typePool == null ) { + ctx = new BasicModelBuildingContextImpl( + classLoadingAccess, + (contributions, buildingContext1) -> OrmAnnotationHelper.forEachOrmAnnotation( contributions::registerAnnotation ) + ); + } + else { + ctx = new SourceModelBuildingContextImpl( + typePool, + classLoadingAccess, + (contributions, buildingContext1) -> OrmAnnotationHelper.forEachOrmAnnotation( contributions::registerAnnotation ) + ); + } + + if ( CollectionHelper.isNotEmpty( modelClasses ) ) { + for ( Class modelClass : modelClasses ) { + ctx.getClassDetailsRegistry().resolveClassDetails( modelClass.getName() ); + } + } + + return ctx; + } + + public static TypePool buildByteBuddyTypePool(Class... modelClasses) { + return buildByteBuddyTypePool( SIMPLE_CLASS_LOADING, modelClasses ); + } + + public static TypePool buildByteBuddyTypePool(ClassLoading classLoadingAccess, Class... modelClasses) { + final TypePool typePool = TypePool.Default.of( new ClassLoadingBridge( classLoadingAccess ) ); + for ( Class modelClass : modelClasses ) { + typePool.describe( modelClass.getName() ).resolve(); + } + return typePool; + } + + private static class ClassLoadingBridge implements ClassFileLocator { + private final ClassLoading classLoading; + + public ClassLoadingBridge(ClassLoading classLoading) { + this.classLoading = classLoading; + } + + @Override + public Resolution locate(String name) throws IOException { + final String classFileName = toClassFileName( name ); + final URL locatedResource = classLoading.locateResource( classFileName ); + if ( locatedResource == null ) { + throw new ModelsException( "Unable to locate resource : " + name + " (" + classFileName + ")" ); + } + try (InputStream stream = locatedResource.openStream()) { + return new Resolution.Explicit( stream.readAllBytes() ); + } + } + + private String toClassFileName(String className) { + return className.replace( '.', '/' ) + ".class"; + } + + @Override + public void close() throws IOException { + + } + } +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/AnEnum.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/AnEnum.java new file mode 100644 index 0000000..7165838 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/AnEnum.java @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +/** + * @author Steve Ebersole + */ +public enum AnEnum { + A,B,C +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/BranchClass.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/BranchClass.java new file mode 100644 index 0000000..08a8053 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/BranchClass.java @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +import jakarta.persistence.Transient; + +/** + * @author Steve Ebersole + */ +@ClassMarker +public class BranchClass extends TrunkClass implements Intf { + @MemberMarker + private Integer value5; + @Transient + private Integer value6; +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassMarker.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassMarker.java new file mode 100644 index 0000000..910affe --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassMarker.java @@ -0,0 +1,20 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Silly annotation we can put on a type + * + * @author Steve Ebersole + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface ClassMarker { +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassRegistryTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassRegistryTests.java new file mode 100644 index 0000000..9a59b94 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassRegistryTests.java @@ -0,0 +1,93 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +import java.util.HashSet; +import java.util.Set; + +import org.hibernate.models.bytebuddy.SourceModelTestHelper; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.ClassDetailsRegistry; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +/** + * @author Steve Ebersole + */ +public class ClassRegistryTests { + + @Test + void testResolveClassDetails() { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( + RootClass.class, + TrunkClass.class, + BranchClass.class, + LeafClass.class + ); + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + final ClassDetails rootClassDetails = classDetailsRegistry.resolveClassDetails( RootClass.class.getName() ); + assertThat( rootClassDetails ).isNotNull(); + + final ClassDetails trunkClassDetails = classDetailsRegistry.resolveClassDetails( TrunkClass.class.getName() ); + assertThat( trunkClassDetails ).isNotNull(); + } + + @Test + void testResolveClassDetailsVoid() { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( + RootClass.class, + TrunkClass.class, + BranchClass.class, + LeafClass.class + ); + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + final ClassDetails voidClassDetails = classDetailsRegistry.resolveClassDetails( void.class.getName() ); + assertThat( voidClassDetails ).isNotNull(); + + final ClassDetails bigVoidClassDetails = classDetailsRegistry.resolveClassDetails( Void.class.getName() ); + assertThat( bigVoidClassDetails ).isNotNull(); + } + + @Test + void testResolveClassDetailsNull() { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( + RootClass.class, + TrunkClass.class, + BranchClass.class, + LeafClass.class + ); + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + try { + classDetailsRegistry.resolveClassDetails( null ); + fail( "Expecting a failure" ); + } + catch (IllegalArgumentException expected) { + } + } + + @Test + void testForEachClassDetails() { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( + RootClass.class, + TrunkClass.class, + BranchClass.class, + LeafClass.class + ); + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + final Set names = new HashSet<>(); + classDetailsRegistry.forEachClassDetails( (classDetails) -> { + names.add( classDetails.getName() ); + } ); + assertThat( names ).contains( RootClass.class.getName() ); + } +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Composable.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Composable.java new file mode 100644 index 0000000..4271acb --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Composable.java @@ -0,0 +1,20 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Silly annotation which can be a "meta annotation" + * + * @author Steve Ebersole + */ +@Target(ElementType.ANNOTATION_TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface Composable { +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/EnumTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/EnumTests.java new file mode 100644 index 0000000..992789a --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/EnumTests.java @@ -0,0 +1,46 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +import org.hibernate.models.bytebuddy.SourceModelTestHelper; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.ClassDetailsRegistry; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import org.junit.jupiter.api.Test; + +import net.bytebuddy.pool.TypePool; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +public class EnumTests { + @Test + void basicEnumTestWithJandex() { + final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( AnEnum.class ); + basicEnumTest( typePool ); + } + + @Test + void basicRootTestWithoutJandex() { + basicEnumTest( null ); + } + + private void basicEnumTest(TypePool typePool) { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( + typePool, + AnEnum.class + ); + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + final ClassDetails enumClassDetails = classDetailsRegistry.getClassDetails( AnEnum.class.getName() ); + assertThat( enumClassDetails.isEnum() ).isTrue(); + assertThat( enumClassDetails.isRecord() ).isFalse(); + assertThat( enumClassDetails.isInterface() ).isFalse(); + assertThat( enumClassDetails.isAbstract() ).isFalse(); + } +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/GenericsTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/GenericsTests.java new file mode 100644 index 0000000..1e11738 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/GenericsTests.java @@ -0,0 +1,192 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +import org.hibernate.models.bytebuddy.SourceModelTestHelper; +import org.hibernate.models.spi.ClassBasedTypeDetails; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.ClassDetailsRegistry; +import org.hibernate.models.spi.SourceModelBuildingContext; +import org.hibernate.models.spi.TypeDetails; + +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.MappedSuperclass; +import net.bytebuddy.pool.TypePool; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +public class GenericsTests { + @Test + void testWrappedIdWithJandex() { + final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( + Base.class, + Thing1.class, + Thing2.class + ); + testWrappedId( typePool ); + } + + @Test + void testWrappedIdWithoutJandex() { + testWrappedId( null ); + } + + void testWrappedId(TypePool typePool) { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( + typePool, + Base.class, + Thing1.class, + Thing2.class + ); + + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + final ClassDetails baseClassDetails = classDetailsRegistry.getClassDetails( Base.class.getName() ); + + final TypeDetails idType = baseClassDetails.findFieldByName( "id" ).getType(); + assertThat( idType.isResolved() ).isFalse(); + assertThat( idType.determineRawClass().isResolved() ).isTrue(); + assertThat( idType.getName() ).isEqualTo( IdWrapper.class.getName() ); + + final TypeDetails wrappedType = idType.asParameterizedType().getRawClassDetails().findFieldByName( "value" ).getType(); + assertThat( wrappedType.getTypeKind() ).isEqualTo( TypeDetails.Kind.TYPE_VARIABLE ); + assertThat( wrappedType.asTypeVariable().getIdentifier() ).isEqualTo( "T" ); + assertThat( wrappedType.asTypeVariable().getBounds() ).hasSize( 1 ); + assertThat( wrappedType.asTypeVariable().getBounds() ).contains( ClassBasedTypeDetails.OBJECT_TYPE_DETAILS ); + assertThat( wrappedType.isResolved() ).isFalse(); + assertThat( wrappedType.determineRawClass().isResolved() ).isTrue(); + + final ClassDetails thing1ClassDetails = classDetailsRegistry.resolveClassDetails( Thing1.class.getName() ); + final TypeDetails thing1IdType = idType.determineRelativeType( thing1ClassDetails ); + assertThat( thing1IdType.isResolved() ).isTrue(); + + final ClassDetails thing2ClassDetails = classDetailsRegistry.resolveClassDetails( Thing2.class.getName() ); + final TypeDetails thing2IdType = idType.determineRelativeType( thing2ClassDetails ); + assertThat( thing2IdType.isResolved() ).isTrue(); + } + + @Test + void testIdWithJandex() { + final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( Base2.class, Thing3.class, Thing4.class ); + testId( typePool ); + } + + @Test + void testIdWithoutJandex() { + testId( null ); + } + + void testId(TypePool typePool) { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( + typePool, + Base2.class, + Thing3.class, + Thing4.class + ); + + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + final ClassDetails baseClassDetails = classDetailsRegistry.getClassDetails( Base2.class.getName() ); + assertThat( baseClassDetails.getFields() ).hasSize( 2 ); + final TypeDetails idType = baseClassDetails.findFieldByName( "id" ).getType(); + assertThat( idType.isResolved() ).isFalse(); + assertThat( idType.determineRawClass().isResolved() ).isTrue(); + + final ClassDetails thing3ClassDetails = classDetailsRegistry.resolveClassDetails( Thing3.class.getName() ); + final TypeDetails thing3IdType = idType.determineRelativeType( thing3ClassDetails ); + assertThat( thing3IdType.isResolved() ).isTrue(); + + final ClassDetails thing4ClassDetails = classDetailsRegistry.resolveClassDetails( Thing4.class.getName() ); + final TypeDetails thing4IdType = idType.determineRelativeType( thing4ClassDetails ); + assertThat( thing4IdType.isResolved() ).isTrue(); + } + + @Test + void testArraysWithJandex() { + final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( Base3.class, Thing5.class ); + testArrays( typePool ); + } + + @Test + void testArraysWithoutJandex() { + testArrays( null ); + } + + void testArrays(TypePool typePool) { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( + typePool, + Base3.class, + Thing5.class + ); + + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + final ClassDetails baseClassDetails = classDetailsRegistry.getClassDetails( Base3.class.getName() ); + assertThat( baseClassDetails.getFields() ).hasSize( 2 ); + + final TypeDetails stringArrayType = baseClassDetails.findFieldByName( "strings" ).getType(); + assertThat( stringArrayType.isResolved() ).isTrue(); + assertThat( stringArrayType.determineRawClass().isResolved() ).isTrue(); + + final TypeDetails genericArrayType = baseClassDetails.findFieldByName( "generics" ).getType(); + assertThat( genericArrayType.isResolved() ).isFalse(); + assertThat( genericArrayType.determineRawClass().isResolved() ).isTrue(); + + final ClassDetails thing5ClassDetails = classDetailsRegistry.getClassDetails( Thing5.class.getName() ); + final TypeDetails thing5GenericArrayType = genericArrayType.determineRelativeType( thing5ClassDetails ); + assertThat( thing5GenericArrayType.isResolved() ).isTrue(); + assertThat( thing5GenericArrayType.determineRawClass().isResolved() ).isTrue(); + + assertThat( stringArrayType.determineRawClass().isResolved() ).isTrue(); + assertThat( genericArrayType.determineRawClass().isResolved() ).isTrue(); + } + + public static class IdWrapper { + T value; + } + + @MappedSuperclass + public static class Base { + @Id + private IdWrapper id; + private String name; + } + + @Entity + public static class Thing1 extends Base { + } + + @Entity + public static class Thing2 extends Base { + } + + @MappedSuperclass + public static class Base2 { + @Id + private I id; + private String name; + } + + @Entity + public static class Thing3 extends Base2 { + } + + @Entity + public static class Thing4 extends Base2 { + } + + public static class Base3 { + private String[] strings; + private I[] generics; + } + + public static class Thing5 extends Base3 { + } +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/InheritanceTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/InheritanceTests.java new file mode 100644 index 0000000..c62aa27 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/InheritanceTests.java @@ -0,0 +1,250 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.models.bytebuddy.SourceModelTestHelper; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.ClassDetailsRegistry; +import org.hibernate.models.spi.FieldDetails; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Transient; +import net.bytebuddy.pool.TypePool; +import org.assertj.core.api.Assertions; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +public class InheritanceTests { + @Test + void basicRootTestWithJandex() { + final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( + RootClass.class, + TrunkClass.class, + BranchClass.class, + LeafClass.class + ); + basicRootTest( typePool ); + } + + @Test + void basicRootTestWithoutJandex() { + basicRootTest( null ); + } + + private void basicRootTest(TypePool typePool) { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( + typePool, + RootClass.class, + TrunkClass.class, + BranchClass.class, + LeafClass.class + ); + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + final ClassDetails rootClassDetails = classDetailsRegistry.getClassDetails( RootClass.class.getName() ); + assertThat( rootClassDetails.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNotNull(); + assertThat( rootClassDetails.getAnnotationUsage( SubclassableMarker.class, buildingContext ) ).isNotNull(); + assertThat( rootClassDetails.getAnnotationUsage( Composable.class, buildingContext ) ).isNull(); + Assertions.assertThat( rootClassDetails.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNull(); + + assertThat( rootClassDetails.getFields() ).hasSize( 2 ); + final FieldDetails value1 = rootClassDetails.findFieldByName( "value1" ); + assertThat( value1 ).isNotNull(); + assertThat( value1.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNotNull(); + assertThat( value1.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNull(); + assertThat( value1.getAnnotationUsage( Transient.class, buildingContext ) ).isNull(); + final FieldDetails value2 = rootClassDetails.findFieldByName( "value2" ); + assertThat( value2.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNull(); + assertThat( value2.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNull(); + assertThat( value2.getAnnotationUsage( Transient.class, buildingContext ) ).isNotNull(); + + assertThat( rootClassDetails.getSuperClass() ).isNotNull(); + assertThat( rootClassDetails.getSuperClass().toJavaClass() ).isEqualTo( Object.class ); + } + + @Test + void basicTrunkTestWithJandex() { + final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( + RootClass.class, + TrunkClass.class, + BranchClass.class, + LeafClass.class + ); + basicTrunkTest( typePool ); + } + + @Test + void basicTrunkTestWithoutJandex() { + basicTrunkTest( null ); + } + + private void basicTrunkTest(TypePool typePool) { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( + typePool, + RootClass.class, + TrunkClass.class, + BranchClass.class, + LeafClass.class + ); + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + final ClassDetails trunkClassDetails = classDetailsRegistry.getClassDetails( TrunkClass.class.getName() ); + assertThat( trunkClassDetails.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNotNull(); + // NOTE : SubclassableMarker is @Inherited, so we should see it here too + assertThat( trunkClassDetails.getAnnotationUsage( SubclassableMarker.class, buildingContext ) ).isNotNull(); + assertThat( trunkClassDetails.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNull(); + + assertThat( trunkClassDetails.getFields() ).hasSize( 2 ); + final FieldDetails value3 = trunkClassDetails.findFieldByName( "value3" ); + assertThat( value3 ).isNotNull(); + assertThat( value3.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNotNull(); + assertThat( value3.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNull(); + assertThat( value3.getAnnotationUsage( Transient.class, buildingContext ) ).isNull(); + + final FieldDetails value4 = trunkClassDetails.findFieldByName( "value4" ); + assertThat( value4.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNull(); + assertThat( value4.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNull(); + assertThat( value4.getAnnotationUsage( Transient.class, buildingContext ) ).isNotNull(); + + assertThat( trunkClassDetails.getSuperClass() ).isNotNull(); + assertThat( trunkClassDetails.getSuperClass().toJavaClass() ).isEqualTo( RootClass.class ); + } + + @Test + void basicLeafTestWithJandex() { + final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( + RootClass.class, + TrunkClass.class, + BranchClass.class, + LeafClass.class + ); + basicLeafTest( typePool ); + } + + @Test + void basicLeafTestWithoutJandex() { + basicLeafTest( null ); + } + + private void basicLeafTest(TypePool typePool) { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( + typePool, + RootClass.class, + TrunkClass.class, + BranchClass.class, + LeafClass.class + ); + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + final ClassDetails leafClassDetails = classDetailsRegistry.getClassDetails( LeafClass.class.getName() ); + assertThat( leafClassDetails.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNotNull(); + // NOTE : SubclassableMarker is @Inherited, so we should see it here too + assertThat( leafClassDetails.getAnnotationUsage( SubclassableMarker.class, buildingContext ) ).isNotNull(); + assertThat( leafClassDetails.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNull(); + + assertThat( leafClassDetails.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNotNull(); + // NOTE : SubclassableMarker is @Inherited, so we should see it even way down here too + assertThat( leafClassDetails.getAnnotationUsage( SubclassableMarker.class, buildingContext ) ).isNotNull(); + assertThat( leafClassDetails.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNull(); + } + + @Test + void testIsImplementorWithJandex() { + final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( + Intf.class, + RootClass.class, + TrunkClass.class, + BranchClass.class, + LeafClass.class + ); + testIsImplementor( typePool ); + } + + @Test + void testIsImplementorWithoutJandex() { + testIsImplementor( null ); + } + + private void testIsImplementor(TypePool typePool) { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( + typePool, + Intf.class, + RootClass.class, + TrunkClass.class, + BranchClass.class, + LeafClass.class + ); + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + final ClassDetails rootClassDetails = classDetailsRegistry.getClassDetails( RootClass.class.getName() ); + assertThat( rootClassDetails.isImplementor( Intf.class ) ).isFalse(); + assertThat( rootClassDetails.getSuperClass() ).isSameAs( ClassDetails.OBJECT_CLASS_DETAILS ); + assertThat( rootClassDetails.isInterface() ).isFalse(); + + final ClassDetails branchClassDetails = classDetailsRegistry.getClassDetails( BranchClass.class.getName() ); + assertThat( branchClassDetails.isImplementor( Intf.class ) ).isTrue(); + assertThat( branchClassDetails.isInterface() ).isFalse(); + + final ClassDetails leafClassDetails = classDetailsRegistry.getClassDetails( LeafClass.class.getName() ); + assertThat( leafClassDetails.isImplementor( Intf.class ) ).isTrue(); + assertThat( leafClassDetails.isInterface() ).isFalse(); + + final ClassDetails interfaceDetails = classDetailsRegistry.getClassDetails( Intf.class.getName() ); + assertThat( interfaceDetails.isInterface() ).isTrue(); + } + + @Test + void testForEachDirectSubTypeWithJandex() { + final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( + Intf.class, + RootClass.class, + TrunkClass.class, + BranchClass.class, + LeafClass.class + ); + testForEachDirectSubType( typePool ); + } + + @Test + void testForEachDirectSubTypeWithoutJandex() { + testForEachDirectSubType( null ); + } + + private void testForEachDirectSubType(TypePool typePool) { + final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( + typePool, + RootClass.class, + TrunkClass.class, + BranchClass.class, + LeafClass.class + ); + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + final List subTypes = new ArrayList<>(); + classDetailsRegistry.forEachDirectSubType( RootClass.class.getName(), subTypes::add ); + assertThat( subTypes ).hasSize( 1 ); + subTypes.clear(); + + classDetailsRegistry.forEachDirectSubType( TrunkClass.class.getName(), subTypes::add ); + assertThat( subTypes ).hasSize( 1 ); + subTypes.clear(); + + classDetailsRegistry.forEachDirectSubType( BranchClass.class.getName(), subTypes::add ); + assertThat( subTypes ).hasSize( 1 ); + subTypes.clear(); + + classDetailsRegistry.forEachDirectSubType( LeafClass.class.getName(), subTypes::add ); + assertThat( subTypes ).hasSize( 0 ); + } + +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Intf.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Intf.java new file mode 100644 index 0000000..cf3df9e --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Intf.java @@ -0,0 +1,11 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +/** + * @author Steve Ebersole + */ +interface Intf { +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/LeafClass.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/LeafClass.java new file mode 100644 index 0000000..cbeefc0 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/LeafClass.java @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +import jakarta.persistence.Transient; + +/** + * @author Steve Ebersole + */ +@ClassMarker +public class LeafClass extends BranchClass { + @MemberMarker + private Integer value7; + @Transient + private Integer value8; +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/MemberMarker.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/MemberMarker.java new file mode 100644 index 0000000..143bd53 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/MemberMarker.java @@ -0,0 +1,20 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Silly annotation we can put on a field/method + * + * @author Steve Ebersole + */ +@Target({ElementType.FIELD,ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface MemberMarker { +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/PrimitiveTypeTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/PrimitiveTypeTests.java new file mode 100644 index 0000000..0db7b73 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/PrimitiveTypeTests.java @@ -0,0 +1,66 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +import org.hibernate.models.internal.jdk.JdkClassDetails; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.ClassDetailsRegistry; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import org.junit.jupiter.api.Test; + +import net.bytebuddy.pool.TypePool; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.models.bytebuddy.SourceModelTestHelper.buildByteBuddyTypePool; +import static org.hibernate.models.bytebuddy.SourceModelTestHelper.createBuildingContext; + +/** + * @author Steve Ebersole + */ +public class PrimitiveTypeTests { + @Test + void testWithJandex() { + final TypePool typePool = buildByteBuddyTypePool(); + final SourceModelBuildingContext buildingContext = createBuildingContext( typePool ); + verify( buildingContext.getClassDetailsRegistry() ); + } + + @Test + void testWithoutJandex() { + final SourceModelBuildingContext buildingContext = createBuildingContext( (TypePool) null ); + verify( buildingContext.getClassDetailsRegistry() ); + } + + void verify(ClassDetailsRegistry classDetailsRegistry) { + final ClassDetails booleanDetails = classDetailsRegistry.resolveClassDetails( "boolean" ); + assertThat( booleanDetails ).isNotNull(); + assertThat( booleanDetails ).isInstanceOf( JdkClassDetails.class ); + + final ClassDetails byteDetails = classDetailsRegistry.resolveClassDetails( "byte" ); + assertThat( byteDetails ).isNotNull(); + assertThat( byteDetails ).isInstanceOf( JdkClassDetails.class ); + + final ClassDetails shortDetails = classDetailsRegistry.resolveClassDetails( "short" ); + assertThat( shortDetails ).isNotNull(); + assertThat( shortDetails ).isInstanceOf( JdkClassDetails.class ); + + final ClassDetails intDetails = classDetailsRegistry.resolveClassDetails( "int" ); + assertThat( intDetails ).isNotNull(); + assertThat( intDetails ).isInstanceOf( JdkClassDetails.class ); + + final ClassDetails longDetails = classDetailsRegistry.resolveClassDetails( "long" ); + assertThat( longDetails ).isNotNull(); + assertThat( longDetails ).isInstanceOf( JdkClassDetails.class ); + + final ClassDetails doubleDetails = classDetailsRegistry.resolveClassDetails( "double" ); + assertThat( doubleDetails ).isNotNull(); + assertThat( doubleDetails ).isInstanceOf( JdkClassDetails.class ); + + final ClassDetails floatDetails = classDetailsRegistry.resolveClassDetails( "float" ); + assertThat( floatDetails ).isNotNull(); + assertThat( floatDetails ).isInstanceOf( JdkClassDetails.class ); + } +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/RootClass.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/RootClass.java new file mode 100644 index 0000000..bf96130 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/RootClass.java @@ -0,0 +1,19 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +import jakarta.persistence.Transient; + +/** + * @author Steve Ebersole + */ +@ClassMarker +@SubclassableMarker +public class RootClass { + @MemberMarker + private Integer value1; + @Transient + private Integer value2; +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/SubclassableMarker.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/SubclassableMarker.java new file mode 100644 index 0000000..cc5a007 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/SubclassableMarker.java @@ -0,0 +1,21 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Steve Ebersole + */ +@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Composable +public @interface SubclassableMarker { +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/TrunkClass.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/TrunkClass.java new file mode 100644 index 0000000..8122059 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/TrunkClass.java @@ -0,0 +1,18 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.classes; + +import jakarta.persistence.Transient; + +/** + * @author Steve Ebersole + */ +@ClassMarker +public class TrunkClass extends RootClass { + @MemberMarker + private Integer value3; + @Transient + private Integer value4; +} diff --git a/hibernate-models-jandex/build.gradle b/hibernate-models-jandex/build.gradle index f4f6d51..e2644d8 100644 --- a/hibernate-models-jandex/build.gradle +++ b/hibernate-models-jandex/build.gradle @@ -3,7 +3,7 @@ plugins { id "shared-testing" } -description = "Jandex support for hibernate-models (isolated dependency)" +description = "Support for hibernate-models based on Jandex (isolated dependency)" dependencies { api project( ":hibernate-models" ) diff --git a/settings.gradle b/settings.gradle index abe981d..3ee0392 100644 --- a/settings.gradle +++ b/settings.gradle @@ -129,5 +129,6 @@ dependencyResolutionManagement { include "hibernate-models" include "hibernate-models-jandex" +include 'hibernate-models-bytebuddy' include 'hibernate-models-testing' From 08f29703f031e24c2ee2b95855862d2953ed00cd Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Tue, 18 Mar 2025 12:11:45 -0500 Subject: [PATCH 2/4] #107 - hibernate-models-bytebuddy # Conflicts: # hibernate-models/src/main/java/org/hibernate/models/spi/ModelsConfiguration.java --- hibernate-models-bytebuddy/build.gradle | 3 +- .../hibernate/models/bytebuddy/Settings.java | 17 ++ .../internal/AbstractAnnotationTarget.java | 7 +- .../internal/AnnotationDescriptorImpl.java | 3 +- .../internal/AnnotationUsageBuilder.java | 12 +- ...pl.java => ByteBuddyModelContextImpl.java} | 10 +- .../internal/ClassDetailsBuilderImpl.java | 5 +- .../bytebuddy/internal/ClassDetailsImpl.java | 3 +- .../internal/ClassDetailsRegistryImpl.java | 4 +- .../bytebuddy/internal/FieldDetailsImpl.java | 3 +- .../bytebuddy/internal/MethodDetailsImpl.java | 3 +- .../bytebuddy/internal/ModelBuilders.java | 9 +- .../internal/RecordComponentDetailsImpl.java | 3 +- .../internal/values/ArrayValueConverter.java | 46 +++- .../internal/values/NestedValueConverter.java | 5 +- .../spi/ByteBuddyContextProvider.java | 44 +++ ...ntext.java => ByteBuddyModelsContext.java} | 2 +- ...els.spi.SourceModelBuildingContextProvider | 1 + .../models/bytebuddy/SimpleTests.java | 38 --- .../bytebuddy/SourceModelTestHelper.java | 118 --------- .../models/bytebuddy/classes/AnEnum.java | 12 - .../models/bytebuddy/classes/BranchClass.java | 18 -- .../models/bytebuddy/classes/ClassMarker.java | 20 -- .../bytebuddy/classes/ClassRegistryTests.java | 93 ------- .../models/bytebuddy/classes/Composable.java | 20 -- .../models/bytebuddy/classes/EnumTests.java | 46 ---- .../bytebuddy/classes/GenericsTests.java | 192 -------------- .../bytebuddy/classes/InheritanceTests.java | 250 ------------------ .../models/bytebuddy/classes/Intf.java | 11 - .../models/bytebuddy/classes/LeafClass.java | 18 -- .../bytebuddy/classes/MemberMarker.java | 20 -- .../bytebuddy/classes/PrimitiveTypeTests.java | 66 ----- .../models/bytebuddy/classes/RootClass.java | 19 -- .../bytebuddy/classes/SubclassableMarker.java | 21 -- .../models/bytebuddy/classes/TrunkClass.java | 18 -- .../intg/ByteBuddyModelContextFactory.java | 79 ++++++ .../tests/AnnotationHandlingTests.java | 65 +++++ .../models/testing/tests/ProviderTests.java | 53 ++++ ...te.models.testing.intg.ModelContextFactory | 5 + .../org/hibernate/models/jandex/Settings.java | 14 + .../spi/JandexBuildingContextProvider.java | 5 +- .../models/testing/tests/ProviderTests.java | 53 ++++ 42 files changed, 419 insertions(+), 1015 deletions(-) create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/Settings.java rename hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/{SourceModelBuildingContextImpl.java => ByteBuddyModelContextImpl.java} (92%) create mode 100644 hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyContextProvider.java rename hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/{ByteBuddyModelsBuildingContext.java => ByteBuddyModelsContext.java} (86%) create mode 100644 hibernate-models-bytebuddy/src/main/resources/META-INF/services/org.hibernate.models.spi.SourceModelBuildingContextProvider delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SimpleTests.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SourceModelTestHelper.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/AnEnum.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/BranchClass.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassMarker.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassRegistryTests.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Composable.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/EnumTests.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/GenericsTests.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/InheritanceTests.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Intf.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/LeafClass.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/MemberMarker.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/PrimitiveTypeTests.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/RootClass.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/SubclassableMarker.java delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/TrunkClass.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/shared/intg/ByteBuddyModelContextFactory.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/tests/AnnotationHandlingTests.java create mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/tests/ProviderTests.java create mode 100644 hibernate-models-bytebuddy/src/test/resources/META-INF/services/org.hibernate.models.testing.intg.ModelContextFactory create mode 100644 hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/Settings.java create mode 100644 hibernate-models-jandex/src/test/java/org/hibernate/models/testing/tests/ProviderTests.java diff --git a/hibernate-models-bytebuddy/build.gradle b/hibernate-models-bytebuddy/build.gradle index 7c76f87..edcb1e8 100644 --- a/hibernate-models-bytebuddy/build.gradle +++ b/hibernate-models-bytebuddy/build.gradle @@ -1,5 +1,6 @@ plugins { id "published-java-module" + id "shared-testing" } description = "Support for hibernate-models based on ByteBuddy (isolated dependency)" @@ -12,6 +13,4 @@ dependencies { api project( ":hibernate-models" ) implementation libs.byteBuddy - - testImplementation project( ":hibernate-models-testing" ) } \ No newline at end of file diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/Settings.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/Settings.java new file mode 100644 index 0000000..49296fd --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/Settings.java @@ -0,0 +1,17 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy; + +/** + * Settings for hibernate-models ByteBuddy support + * + * @author Steve Ebersole + */ +public interface Settings { + /** + * Used to pass the ByteBuddy {@linkplain net.bytebuddy.pool.TypePool}. + */ + String TYPE_POOL_PARAM = "hibernate.models.bytebuddy.typePool"; +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AbstractAnnotationTarget.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AbstractAnnotationTarget.java index 892f275..41cd587 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AbstractAnnotationTarget.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AbstractAnnotationTarget.java @@ -7,6 +7,7 @@ import java.lang.annotation.Annotation; import java.util.Map; +import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext; import org.hibernate.models.internal.AnnotationTargetSupport; import net.bytebuddy.description.annotation.AnnotationSource; @@ -15,15 +16,15 @@ * @author Steve Ebersole */ public abstract class AbstractAnnotationTarget implements AnnotationTargetSupport { - private final SourceModelBuildingContextImpl modelContext; + private final ByteBuddyModelsContext modelContext; private Map, ? extends Annotation> usageMap; - public AbstractAnnotationTarget(SourceModelBuildingContextImpl modelContext) { + public AbstractAnnotationTarget(ByteBuddyModelsContext modelContext) { this.modelContext = modelContext; } - public SourceModelBuildingContextImpl getModelContext() { + public ByteBuddyModelsContext getModelContext() { return modelContext; } diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationDescriptorImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationDescriptorImpl.java index a036b94..4411634 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationDescriptorImpl.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationDescriptorImpl.java @@ -6,6 +6,7 @@ import java.lang.annotation.Annotation; +import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext; import org.hibernate.models.internal.StandardAnnotationDescriptor; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.SourceModelBuildingContext; @@ -29,7 +30,7 @@ public AnnotationDescriptorImpl( super( annotationType, repeatableContainer, buildingContext ); } - public A createUsage(AnnotationDescription annotationDescription, SourceModelBuildingContextImpl context) { + public A createUsage(AnnotationDescription annotationDescription, ByteBuddyModelsContext context) { return AnnotationUsageBuilder.makeUsage( annotationDescription, this, context ); } } diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationUsageBuilder.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationUsageBuilder.java index 6349382..67feeef 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationUsageBuilder.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationUsageBuilder.java @@ -15,11 +15,13 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiConsumer; +import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext; import org.hibernate.models.bytebuddy.spi.ValueExtractor; import org.hibernate.models.internal.util.CollectionHelper; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.AnnotationDescriptorRegistry; import org.hibernate.models.spi.AttributeDescriptor; +import org.hibernate.models.spi.SourceModelBuildingContext; import net.bytebuddy.description.annotation.AnnotationDescription; import net.bytebuddy.description.annotation.AnnotationList; @@ -35,7 +37,7 @@ public class AnnotationUsageBuilder { public static A makeUsage( AnnotationDescription annotationDescription, AnnotationDescriptor annotationDescriptor, - SourceModelBuildingContextImpl modelContext) { + SourceModelBuildingContext modelContext) { final Map attributeValues = extractAttributeValues( annotationDescription, annotationDescriptor, @@ -47,7 +49,7 @@ public static A makeUsage( private static Map extractAttributeValues( AnnotationDescription annotationDescription, AnnotationDescriptor annotationDescriptor, - SourceModelBuildingContextImpl modelContext) { + SourceModelBuildingContext modelContext) { if ( CollectionHelper.isEmpty( annotationDescriptor.getAttributes() ) ) { return Collections.emptyMap(); @@ -57,7 +59,7 @@ private static Map extractAttributeValues for ( int i = 0; i < annotationDescriptor.getAttributes().size(); i++ ) { final AttributeDescriptor attributeDescriptor = annotationDescriptor.getAttributes().get( i ); final ValueExtractor extractor = modelContext - .as( SourceModelBuildingContextImpl.class ) + .as( ByteBuddyModelContextImpl.class ) .getValueExtractor( attributeDescriptor.getTypeDescriptor() ); final Object attributeValue = extractor.extractValue( annotationDescription, @@ -71,7 +73,7 @@ private static Map extractAttributeValues public static Map, ? extends Annotation> collectUsages( AnnotationSource annotationSource, - SourceModelBuildingContextImpl modelContext) { + ByteBuddyModelsContext modelContext) { if ( annotationSource == null ) { return Collections.emptyMap(); } @@ -90,7 +92,7 @@ private static Map extractAttributeValues public static void processAnnotations( AnnotationList annotations, BiConsumer, Annotation> consumer, - SourceModelBuildingContextImpl buildingContext) { + ByteBuddyModelsContext buildingContext) { final AnnotationDescriptorRegistry annotationDescriptorRegistry = buildingContext.getAnnotationDescriptorRegistry(); for ( AnnotationDescription annotation : annotations ) { diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/SourceModelBuildingContextImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ByteBuddyModelContextImpl.java similarity index 92% rename from hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/SourceModelBuildingContextImpl.java rename to hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ByteBuddyModelContextImpl.java index 22c516d..bd45a41 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/SourceModelBuildingContextImpl.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ByteBuddyModelContextImpl.java @@ -7,7 +7,7 @@ import java.util.HashMap; import java.util.Map; -import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsBuildingContext; +import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext; import org.hibernate.models.bytebuddy.spi.ValueConverter; import org.hibernate.models.bytebuddy.spi.ValueExtractor; import org.hibernate.models.internal.AbstractModelBuildingContext; @@ -28,9 +28,9 @@ * * @author Steve Ebersole */ -public class SourceModelBuildingContextImpl +public class ByteBuddyModelContextImpl extends AbstractModelBuildingContext - implements ByteBuddyModelsBuildingContext { + implements ByteBuddyModelsContext { private final TypePool typePool; private final ClassDetailsRegistryImpl classDetailsRegistry; @@ -39,13 +39,13 @@ public class SourceModelBuildingContextImpl private final Map valueConverters = new HashMap<>(); private final Map valueExtractors = new HashMap<>(); - public SourceModelBuildingContextImpl( + public ByteBuddyModelContextImpl( TypePool typePool, RegistryPrimer registryPrimer) { this( typePool, SimpleClassLoading.SIMPLE_CLASS_LOADING, registryPrimer ); } - public SourceModelBuildingContextImpl( + public ByteBuddyModelContextImpl( TypePool typePool, ClassLoading classLoading, RegistryPrimer registryPrimer) { diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsBuilderImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsBuilderImpl.java index 3122688..4dbb9c2 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsBuilderImpl.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsBuilderImpl.java @@ -4,6 +4,7 @@ */ package org.hibernate.models.bytebuddy.internal; +import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetailsBuilder; import org.hibernate.models.spi.SourceModelBuildingContext; @@ -12,9 +13,9 @@ * @author Steve Ebersole */ public class ClassDetailsBuilderImpl implements ClassDetailsBuilder { - private final SourceModelBuildingContextImpl modelContext; + private final ByteBuddyModelsContext modelContext; - public ClassDetailsBuilderImpl(SourceModelBuildingContextImpl modelContext) { + public ClassDetailsBuilderImpl(ByteBuddyModelsContext modelContext) { this.modelContext = modelContext; } diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsImpl.java index 5031981..08259fc 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsImpl.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsImpl.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.List; +import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext; import org.hibernate.models.internal.ClassDetailsSupport; import org.hibernate.models.internal.jdk.SerialJdkClassDetails; import org.hibernate.models.internal.util.CollectionHelper; @@ -49,7 +50,7 @@ public class ClassDetailsImpl extends AbstractAnnotationTarget implements ClassD private List methods; private List recordComponents; - public ClassDetailsImpl(TypeDescription typeDescription, SourceModelBuildingContextImpl modelContext) { + public ClassDetailsImpl(TypeDescription typeDescription, ByteBuddyModelsContext modelContext) { super( modelContext ); this.typeDescription = typeDescription; this.superClassDetails = determineSuperType( typeDescription, modelContext ); diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsRegistryImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsRegistryImpl.java index f702ea3..26651a6 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsRegistryImpl.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsRegistryImpl.java @@ -17,12 +17,10 @@ * @author Steve Ebersole */ public class ClassDetailsRegistryImpl extends AbstractClassDetailsRegistry { - private final SourceModelBuildingContextImpl modelContext; private final ClassDetailsBuilderImpl classDetailsBuilder; - public ClassDetailsRegistryImpl(SourceModelBuildingContextImpl context) { + public ClassDetailsRegistryImpl(ByteBuddyModelContextImpl context) { super( context ); - this.modelContext = context; this.classDetailsBuilder = new ClassDetailsBuilderImpl( context ); } diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/FieldDetailsImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/FieldDetailsImpl.java index 675a0be..a31582c 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/FieldDetailsImpl.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/FieldDetailsImpl.java @@ -11,6 +11,7 @@ import java.util.Map; import org.hibernate.models.IllegalCastException; +import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext; import org.hibernate.models.internal.AnnotationTargetSupport; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.ClassDetails; @@ -40,7 +41,7 @@ public class FieldDetailsImpl public FieldDetailsImpl( FieldDescription.InDefinedShape underlyingField, ClassDetailsImpl declaringClassDetails, - SourceModelBuildingContextImpl modelContext) { + ByteBuddyModelsContext modelContext) { super( modelContext ); this.underlyingField = underlyingField; this.declaringClassDetails = declaringClassDetails; diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/MethodDetailsImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/MethodDetailsImpl.java index ad17635..0607aee 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/MethodDetailsImpl.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/MethodDetailsImpl.java @@ -12,6 +12,7 @@ import java.util.Map; import org.hibernate.models.IllegalCastException; +import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetailsRegistry; @@ -47,7 +48,7 @@ public MethodDetailsImpl( MethodKind methodKind, TypeDetails type, ClassDetails declaringType, - SourceModelBuildingContextImpl modelContext) { + ByteBuddyModelsContext modelContext) { super( modelContext ); this.methodDescription = methodDescription; this.methodKind = methodKind; diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ModelBuilders.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ModelBuilders.java index db4a77d..9a6e7e1 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ModelBuilders.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ModelBuilders.java @@ -33,6 +33,7 @@ import org.hibernate.models.bytebuddy.internal.values.ShortValueExtractor; import org.hibernate.models.bytebuddy.internal.values.StringValueConverter; import org.hibernate.models.bytebuddy.internal.values.StringValueExtractor; +import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext; import org.hibernate.models.bytebuddy.spi.ValueConverter; import org.hibernate.models.bytebuddy.spi.ValueExtractor; import org.hibernate.models.internal.ArrayTypeDescriptor; @@ -51,7 +52,7 @@ * @author Steve Ebersole */ public class ModelBuilders { - public static ClassDetails buildDetails(String name, SourceModelBuildingContextImpl modelContext) { + public static ClassDetails buildDetails(String name, ByteBuddyModelsContext modelContext) { if ( StringHelper.isEmpty( name ) ) { return null; } @@ -154,7 +155,7 @@ public static Class resolvePrimitiveClass(String className) { public static MethodDetails buildMethodDetails( MethodDescription.InDefinedShape method, ClassDetailsImpl declaringType, - SourceModelBuildingContextImpl modelContext) { + ByteBuddyModelsContext modelContext) { if ( method.getParameters().isEmpty() ) { // could be a getter final TypeDescription.Generic returnType = method.getReturnType(); @@ -217,7 +218,7 @@ public static ValueConverter buildValueHandlersReturnConverter( ValueTypeDescriptor valueTypeDescriptor, BiConsumer,ValueConverter> converterCollector, BiConsumer, ValueExtractor> extractorCollector, - SourceModelBuildingContextImpl sourceModelBuildingContext) { + ByteBuddyModelContextImpl sourceModelBuildingContext) { if ( valueTypeDescriptor.getValueType().isArray() ) { final ValueTypeDescriptor elementTypeDescriptor = ( (ArrayTypeDescriptor) valueTypeDescriptor ).getElementTypeDescriptor(); final ArrayValueConverter valueConverter = new ArrayValueConverter<>( elementTypeDescriptor ); @@ -316,7 +317,7 @@ public static ValueExtractor buildValueHandlersReturnExtractor( ValueTypeDescriptor valueTypeDescriptor, BiConsumer,ValueConverter> converterCollector, BiConsumer, ValueExtractor> extractorCollector, - SourceModelBuildingContextImpl sourceModelBuildingContext) { + ByteBuddyModelContextImpl sourceModelBuildingContext) { if ( valueTypeDescriptor.getValueType().isArray() ) { final ValueTypeDescriptor elementTypeDescriptor = ( (ArrayTypeDescriptor) valueTypeDescriptor ).getElementTypeDescriptor(); final ArrayValueConverter valueConverter = new ArrayValueConverter<>( elementTypeDescriptor ); diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/RecordComponentDetailsImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/RecordComponentDetailsImpl.java index 498e6d5..b781797 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/RecordComponentDetailsImpl.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/RecordComponentDetailsImpl.java @@ -11,6 +11,7 @@ import java.util.Map; import org.hibernate.models.IllegalCastException; +import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.FieldDetails; @@ -39,7 +40,7 @@ public class RecordComponentDetailsImpl public RecordComponentDetailsImpl( RecordComponentDescription.InDefinedShape underlyingComponent, ClassDetailsImpl declaringClassDetails, - SourceModelBuildingContextImpl modelContext) { + ByteBuddyModelsContext modelContext) { super( modelContext ); this.underlyingComponent = underlyingComponent; this.declaringClassDetails = declaringClassDetails; diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java index 75792c7..88fa3c5 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java @@ -4,11 +4,17 @@ */ package org.hibernate.models.bytebuddy.internal.values; +import java.lang.reflect.Field; +import java.util.List; + +import org.hibernate.models.ModelsException; +import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext; import org.hibernate.models.bytebuddy.spi.ValueConverter; import org.hibernate.models.spi.SourceModelBuildingContext; import org.hibernate.models.spi.ValueTypeDescriptor; import net.bytebuddy.description.annotation.AnnotationValue; +import net.bytebuddy.pool.TypePool; /** * Support for converting array values @@ -26,7 +32,43 @@ public ArrayValueConverter(ValueTypeDescriptor elementTypeDescriptor) { public V[] convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { assert byteBuddyValue != null; - //noinspection unchecked - return (V[]) byteBuddyValue.resolve(); + // UGH... + final List> byteBuddyValues = extractValueValues( byteBuddyValue, modelContext ); + + final V[] result = elementTypeDescriptor.makeArray( byteBuddyValues.size(), modelContext ); + final ValueConverter elementWrapper = modelContext.as( ByteBuddyModelsContext.class ).getValueConverter( elementTypeDescriptor ); + + for ( int i = 0; i < byteBuddyValues.size(); i++ ) { + result[i] = elementWrapper.convert( byteBuddyValues.get(i), modelContext ); + } + return result; + } + + private List> extractValueValues( + AnnotationValue byteBuddyValue, + SourceModelBuildingContext modelContext) { + try { + //noinspection unchecked + return (List>) getValuesField( modelContext ).get( byteBuddyValue ); + } + catch (IllegalAccessException e) { + throw new ModelsException( "Could not access Byte Buddy's `AnnotationValue.ForDescriptionArray#values` field", e ); + } + } + + private Field getValuesField(SourceModelBuildingContext modelContext) { + return ARRRRGGGGHHHHH; + } + + private static Field ARRRRGGGGHHHHH; + + static { + try { + ARRRRGGGGHHHHH = AnnotationValue.ForDescriptionArray.class.getDeclaredField( "values" ); + ARRRRGGGGHHHHH.setAccessible( true ); + } + catch (Exception e) { + throw new ModelsException( "Could not access Byte Buddy's `AnnotationValue.ForDescriptionArray#values` field", e ); + } } } diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/NestedValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/NestedValueConverter.java index 6cccb55..2f2ecf1 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/NestedValueConverter.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/NestedValueConverter.java @@ -6,10 +6,12 @@ import java.lang.annotation.Annotation; +import org.hibernate.models.bytebuddy.internal.AnnotationUsageBuilder; import org.hibernate.models.bytebuddy.spi.ValueConverter; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.SourceModelBuildingContext; +import net.bytebuddy.description.annotation.AnnotationDescription; import net.bytebuddy.description.annotation.AnnotationValue; /** @@ -27,6 +29,7 @@ public NestedValueConverter(AnnotationDescriptor descriptor) { @Override public A convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { - return byteBuddyValue.resolve( descriptor.getAnnotationType() ); + final AnnotationDescription resolved = byteBuddyValue.resolve( AnnotationDescription.class ); + return AnnotationUsageBuilder.makeUsage( resolved, descriptor, modelContext ); } } diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyContextProvider.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyContextProvider.java new file mode 100644 index 0000000..3aedc8e --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyContextProvider.java @@ -0,0 +1,44 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.bytebuddy.spi; + +import java.util.Map; + +import org.hibernate.models.bytebuddy.Settings; +import org.hibernate.models.bytebuddy.internal.ByteBuddyModelContextImpl; +import org.hibernate.models.internal.BasicModelBuildingContextImpl; +import org.hibernate.models.spi.ClassLoading; +import org.hibernate.models.spi.RegistryPrimer; +import org.hibernate.models.spi.SourceModelBuildingContext; +import org.hibernate.models.spi.SourceModelBuildingContextProvider; + +import net.bytebuddy.pool.TypePool; + +/** + * @author Steve Ebersole + */ +public class ByteBuddyContextProvider implements SourceModelBuildingContextProvider { + public static final ByteBuddyContextProvider BYTEBUDDY_PROVIDER = new ByteBuddyContextProvider(); + + @Override + public SourceModelBuildingContext produceContext( + ClassLoading classLoading, + RegistryPrimer registryPrimer, + Map configProperties) { + final TypePool typePool = resolveTypePool( configProperties ); + + if ( typePool != null ) { + return new ByteBuddyModelContextImpl( typePool, classLoading, registryPrimer ); + } + + return new BasicModelBuildingContextImpl( classLoading, registryPrimer ); + } + + private TypePool resolveTypePool(Map configProperties) { + // todo : do we want to have the ability to create the TypePool or resolve one from another source? + // - note: if building, be sure to apply BaseLineJavaTypes + return (TypePool) configProperties.get( Settings.TYPE_POOL_PARAM ); + } +} diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyModelsBuildingContext.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyModelsContext.java similarity index 86% rename from hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyModelsBuildingContext.java rename to hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyModelsContext.java index 4ae17e8..f51c479 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyModelsBuildingContext.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyModelsContext.java @@ -12,7 +12,7 @@ /** * @author Steve Ebersole */ -public interface ByteBuddyModelsBuildingContext extends SourceModelBuildingContext { +public interface ByteBuddyModelsContext extends SourceModelBuildingContext { TypePool getTypePool(); ValueConverter getValueConverter(ValueTypeDescriptor valueTypeDescriptor); diff --git a/hibernate-models-bytebuddy/src/main/resources/META-INF/services/org.hibernate.models.spi.SourceModelBuildingContextProvider b/hibernate-models-bytebuddy/src/main/resources/META-INF/services/org.hibernate.models.spi.SourceModelBuildingContextProvider new file mode 100644 index 0000000..0cbfc66 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/resources/META-INF/services/org.hibernate.models.spi.SourceModelBuildingContextProvider @@ -0,0 +1 @@ +org.hibernate.models.bytebuddy.spi.ByteBuddyContextProvider \ No newline at end of file diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SimpleTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SimpleTests.java deleted file mode 100644 index f1e18af..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SimpleTests.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy; - -import org.hibernate.models.spi.ClassDetails; -import org.hibernate.models.spi.ClassDetailsRegistry; -import org.hibernate.models.spi.SourceModelBuildingContext; - -import org.junit.jupiter.api.Test; - - -/** - * @author Steve Ebersole - */ -public class SimpleTests { - @Test - void testSimple1() { - final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( - Base.class, - Thing.class - ); - final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); - - final ClassDetails classDetails = classDetailsRegistry.getClassDetails( Base.class.getName() ); - classDetails.getFields(); - classDetails.getMethods(); - } - - public static class Base { - private String[] strings; - private I[] generics; - } - - public static class Thing extends Base { - } -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SourceModelTestHelper.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SourceModelTestHelper.java deleted file mode 100644 index 3a075d8..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/SourceModelTestHelper.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - -import org.hibernate.models.ModelsException; -import org.hibernate.models.bytebuddy.internal.SourceModelBuildingContextImpl; -import org.hibernate.models.internal.BasicModelBuildingContextImpl; -import org.hibernate.models.internal.util.CollectionHelper; -import org.hibernate.models.orm.OrmAnnotationHelper; -import org.hibernate.models.spi.ClassLoading; -import org.hibernate.models.spi.SourceModelBuildingContext; - -import net.bytebuddy.dynamic.ClassFileLocator; -import net.bytebuddy.pool.TypePool; - -import static org.hibernate.models.internal.SimpleClassLoading.SIMPLE_CLASS_LOADING; - -/** - * @author Steve Ebersole - */ -public class SourceModelTestHelper { - - public static SourceModelBuildingContext createBuildingContext(Class modelClass) { - return createBuildingContext( SIMPLE_CLASS_LOADING, modelClass ); - } - - public static SourceModelBuildingContext createBuildingContext(Class... modelClasses) { - return createBuildingContext( SIMPLE_CLASS_LOADING, modelClasses ); - } - - public static SourceModelBuildingContext createBuildingContext(ClassLoading classLoadingAccess, Class... modelClasses) { - final TypePool typePool = buildByteBuddyTypePool( classLoadingAccess, modelClasses ); - return createBuildingContext( typePool, modelClasses ); - } - - public static SourceModelBuildingContext createBuildingContext(TypePool typePool, Class modelClass) { - return createBuildingContext( typePool, SIMPLE_CLASS_LOADING, modelClass ); - } - - public static SourceModelBuildingContext createBuildingContext(TypePool typePool, Class... modelClasses) { - return createBuildingContext( typePool, SIMPLE_CLASS_LOADING, modelClasses ); - } - - public static SourceModelBuildingContext createBuildingContext( - TypePool typePool, - ClassLoading classLoadingAccess, - Class... modelClasses) { - final SourceModelBuildingContext ctx; - if ( typePool == null ) { - ctx = new BasicModelBuildingContextImpl( - classLoadingAccess, - (contributions, buildingContext1) -> OrmAnnotationHelper.forEachOrmAnnotation( contributions::registerAnnotation ) - ); - } - else { - ctx = new SourceModelBuildingContextImpl( - typePool, - classLoadingAccess, - (contributions, buildingContext1) -> OrmAnnotationHelper.forEachOrmAnnotation( contributions::registerAnnotation ) - ); - } - - if ( CollectionHelper.isNotEmpty( modelClasses ) ) { - for ( Class modelClass : modelClasses ) { - ctx.getClassDetailsRegistry().resolveClassDetails( modelClass.getName() ); - } - } - - return ctx; - } - - public static TypePool buildByteBuddyTypePool(Class... modelClasses) { - return buildByteBuddyTypePool( SIMPLE_CLASS_LOADING, modelClasses ); - } - - public static TypePool buildByteBuddyTypePool(ClassLoading classLoadingAccess, Class... modelClasses) { - final TypePool typePool = TypePool.Default.of( new ClassLoadingBridge( classLoadingAccess ) ); - for ( Class modelClass : modelClasses ) { - typePool.describe( modelClass.getName() ).resolve(); - } - return typePool; - } - - private static class ClassLoadingBridge implements ClassFileLocator { - private final ClassLoading classLoading; - - public ClassLoadingBridge(ClassLoading classLoading) { - this.classLoading = classLoading; - } - - @Override - public Resolution locate(String name) throws IOException { - final String classFileName = toClassFileName( name ); - final URL locatedResource = classLoading.locateResource( classFileName ); - if ( locatedResource == null ) { - throw new ModelsException( "Unable to locate resource : " + name + " (" + classFileName + ")" ); - } - try (InputStream stream = locatedResource.openStream()) { - return new Resolution.Explicit( stream.readAllBytes() ); - } - } - - private String toClassFileName(String className) { - return className.replace( '.', '/' ) + ".class"; - } - - @Override - public void close() throws IOException { - - } - } -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/AnEnum.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/AnEnum.java deleted file mode 100644 index 7165838..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/AnEnum.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -/** - * @author Steve Ebersole - */ -public enum AnEnum { - A,B,C -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/BranchClass.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/BranchClass.java deleted file mode 100644 index 08a8053..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/BranchClass.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -import jakarta.persistence.Transient; - -/** - * @author Steve Ebersole - */ -@ClassMarker -public class BranchClass extends TrunkClass implements Intf { - @MemberMarker - private Integer value5; - @Transient - private Integer value6; -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassMarker.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassMarker.java deleted file mode 100644 index 910affe..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassMarker.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Silly annotation we can put on a type - * - * @author Steve Ebersole - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface ClassMarker { -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassRegistryTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassRegistryTests.java deleted file mode 100644 index 9a59b94..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/ClassRegistryTests.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -import java.util.HashSet; -import java.util.Set; - -import org.hibernate.models.bytebuddy.SourceModelTestHelper; -import org.hibernate.models.spi.ClassDetails; -import org.hibernate.models.spi.ClassDetailsRegistry; -import org.hibernate.models.spi.SourceModelBuildingContext; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; - -/** - * @author Steve Ebersole - */ -public class ClassRegistryTests { - - @Test - void testResolveClassDetails() { - final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( - RootClass.class, - TrunkClass.class, - BranchClass.class, - LeafClass.class - ); - final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); - - final ClassDetails rootClassDetails = classDetailsRegistry.resolveClassDetails( RootClass.class.getName() ); - assertThat( rootClassDetails ).isNotNull(); - - final ClassDetails trunkClassDetails = classDetailsRegistry.resolveClassDetails( TrunkClass.class.getName() ); - assertThat( trunkClassDetails ).isNotNull(); - } - - @Test - void testResolveClassDetailsVoid() { - final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( - RootClass.class, - TrunkClass.class, - BranchClass.class, - LeafClass.class - ); - final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); - - final ClassDetails voidClassDetails = classDetailsRegistry.resolveClassDetails( void.class.getName() ); - assertThat( voidClassDetails ).isNotNull(); - - final ClassDetails bigVoidClassDetails = classDetailsRegistry.resolveClassDetails( Void.class.getName() ); - assertThat( bigVoidClassDetails ).isNotNull(); - } - - @Test - void testResolveClassDetailsNull() { - final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( - RootClass.class, - TrunkClass.class, - BranchClass.class, - LeafClass.class - ); - final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); - - try { - classDetailsRegistry.resolveClassDetails( null ); - fail( "Expecting a failure" ); - } - catch (IllegalArgumentException expected) { - } - } - - @Test - void testForEachClassDetails() { - final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( - RootClass.class, - TrunkClass.class, - BranchClass.class, - LeafClass.class - ); - final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); - - final Set names = new HashSet<>(); - classDetailsRegistry.forEachClassDetails( (classDetails) -> { - names.add( classDetails.getName() ); - } ); - assertThat( names ).contains( RootClass.class.getName() ); - } -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Composable.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Composable.java deleted file mode 100644 index 4271acb..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Composable.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Silly annotation which can be a "meta annotation" - * - * @author Steve Ebersole - */ -@Target(ElementType.ANNOTATION_TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface Composable { -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/EnumTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/EnumTests.java deleted file mode 100644 index 992789a..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/EnumTests.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -import org.hibernate.models.bytebuddy.SourceModelTestHelper; -import org.hibernate.models.spi.ClassDetails; -import org.hibernate.models.spi.ClassDetailsRegistry; -import org.hibernate.models.spi.SourceModelBuildingContext; - -import org.junit.jupiter.api.Test; - -import net.bytebuddy.pool.TypePool; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Steve Ebersole - */ -public class EnumTests { - @Test - void basicEnumTestWithJandex() { - final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( AnEnum.class ); - basicEnumTest( typePool ); - } - - @Test - void basicRootTestWithoutJandex() { - basicEnumTest( null ); - } - - private void basicEnumTest(TypePool typePool) { - final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( - typePool, - AnEnum.class - ); - final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); - - final ClassDetails enumClassDetails = classDetailsRegistry.getClassDetails( AnEnum.class.getName() ); - assertThat( enumClassDetails.isEnum() ).isTrue(); - assertThat( enumClassDetails.isRecord() ).isFalse(); - assertThat( enumClassDetails.isInterface() ).isFalse(); - assertThat( enumClassDetails.isAbstract() ).isFalse(); - } -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/GenericsTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/GenericsTests.java deleted file mode 100644 index 1e11738..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/GenericsTests.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -import org.hibernate.models.bytebuddy.SourceModelTestHelper; -import org.hibernate.models.spi.ClassBasedTypeDetails; -import org.hibernate.models.spi.ClassDetails; -import org.hibernate.models.spi.ClassDetailsRegistry; -import org.hibernate.models.spi.SourceModelBuildingContext; -import org.hibernate.models.spi.TypeDetails; - -import org.junit.jupiter.api.Test; - -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.MappedSuperclass; -import net.bytebuddy.pool.TypePool; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Steve Ebersole - */ -public class GenericsTests { - @Test - void testWrappedIdWithJandex() { - final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( - Base.class, - Thing1.class, - Thing2.class - ); - testWrappedId( typePool ); - } - - @Test - void testWrappedIdWithoutJandex() { - testWrappedId( null ); - } - - void testWrappedId(TypePool typePool) { - final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( - typePool, - Base.class, - Thing1.class, - Thing2.class - ); - - final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); - - final ClassDetails baseClassDetails = classDetailsRegistry.getClassDetails( Base.class.getName() ); - - final TypeDetails idType = baseClassDetails.findFieldByName( "id" ).getType(); - assertThat( idType.isResolved() ).isFalse(); - assertThat( idType.determineRawClass().isResolved() ).isTrue(); - assertThat( idType.getName() ).isEqualTo( IdWrapper.class.getName() ); - - final TypeDetails wrappedType = idType.asParameterizedType().getRawClassDetails().findFieldByName( "value" ).getType(); - assertThat( wrappedType.getTypeKind() ).isEqualTo( TypeDetails.Kind.TYPE_VARIABLE ); - assertThat( wrappedType.asTypeVariable().getIdentifier() ).isEqualTo( "T" ); - assertThat( wrappedType.asTypeVariable().getBounds() ).hasSize( 1 ); - assertThat( wrappedType.asTypeVariable().getBounds() ).contains( ClassBasedTypeDetails.OBJECT_TYPE_DETAILS ); - assertThat( wrappedType.isResolved() ).isFalse(); - assertThat( wrappedType.determineRawClass().isResolved() ).isTrue(); - - final ClassDetails thing1ClassDetails = classDetailsRegistry.resolveClassDetails( Thing1.class.getName() ); - final TypeDetails thing1IdType = idType.determineRelativeType( thing1ClassDetails ); - assertThat( thing1IdType.isResolved() ).isTrue(); - - final ClassDetails thing2ClassDetails = classDetailsRegistry.resolveClassDetails( Thing2.class.getName() ); - final TypeDetails thing2IdType = idType.determineRelativeType( thing2ClassDetails ); - assertThat( thing2IdType.isResolved() ).isTrue(); - } - - @Test - void testIdWithJandex() { - final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( Base2.class, Thing3.class, Thing4.class ); - testId( typePool ); - } - - @Test - void testIdWithoutJandex() { - testId( null ); - } - - void testId(TypePool typePool) { - final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( - typePool, - Base2.class, - Thing3.class, - Thing4.class - ); - - final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); - - final ClassDetails baseClassDetails = classDetailsRegistry.getClassDetails( Base2.class.getName() ); - assertThat( baseClassDetails.getFields() ).hasSize( 2 ); - final TypeDetails idType = baseClassDetails.findFieldByName( "id" ).getType(); - assertThat( idType.isResolved() ).isFalse(); - assertThat( idType.determineRawClass().isResolved() ).isTrue(); - - final ClassDetails thing3ClassDetails = classDetailsRegistry.resolveClassDetails( Thing3.class.getName() ); - final TypeDetails thing3IdType = idType.determineRelativeType( thing3ClassDetails ); - assertThat( thing3IdType.isResolved() ).isTrue(); - - final ClassDetails thing4ClassDetails = classDetailsRegistry.resolveClassDetails( Thing4.class.getName() ); - final TypeDetails thing4IdType = idType.determineRelativeType( thing4ClassDetails ); - assertThat( thing4IdType.isResolved() ).isTrue(); - } - - @Test - void testArraysWithJandex() { - final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( Base3.class, Thing5.class ); - testArrays( typePool ); - } - - @Test - void testArraysWithoutJandex() { - testArrays( null ); - } - - void testArrays(TypePool typePool) { - final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( - typePool, - Base3.class, - Thing5.class - ); - - final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); - final ClassDetails baseClassDetails = classDetailsRegistry.getClassDetails( Base3.class.getName() ); - assertThat( baseClassDetails.getFields() ).hasSize( 2 ); - - final TypeDetails stringArrayType = baseClassDetails.findFieldByName( "strings" ).getType(); - assertThat( stringArrayType.isResolved() ).isTrue(); - assertThat( stringArrayType.determineRawClass().isResolved() ).isTrue(); - - final TypeDetails genericArrayType = baseClassDetails.findFieldByName( "generics" ).getType(); - assertThat( genericArrayType.isResolved() ).isFalse(); - assertThat( genericArrayType.determineRawClass().isResolved() ).isTrue(); - - final ClassDetails thing5ClassDetails = classDetailsRegistry.getClassDetails( Thing5.class.getName() ); - final TypeDetails thing5GenericArrayType = genericArrayType.determineRelativeType( thing5ClassDetails ); - assertThat( thing5GenericArrayType.isResolved() ).isTrue(); - assertThat( thing5GenericArrayType.determineRawClass().isResolved() ).isTrue(); - - assertThat( stringArrayType.determineRawClass().isResolved() ).isTrue(); - assertThat( genericArrayType.determineRawClass().isResolved() ).isTrue(); - } - - public static class IdWrapper { - T value; - } - - @MappedSuperclass - public static class Base { - @Id - private IdWrapper id; - private String name; - } - - @Entity - public static class Thing1 extends Base { - } - - @Entity - public static class Thing2 extends Base { - } - - @MappedSuperclass - public static class Base2 { - @Id - private I id; - private String name; - } - - @Entity - public static class Thing3 extends Base2 { - } - - @Entity - public static class Thing4 extends Base2 { - } - - public static class Base3 { - private String[] strings; - private I[] generics; - } - - public static class Thing5 extends Base3 { - } -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/InheritanceTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/InheritanceTests.java deleted file mode 100644 index c62aa27..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/InheritanceTests.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -import java.util.ArrayList; -import java.util.List; - -import org.hibernate.models.bytebuddy.SourceModelTestHelper; -import org.hibernate.models.spi.ClassDetails; -import org.hibernate.models.spi.ClassDetailsRegistry; -import org.hibernate.models.spi.FieldDetails; -import org.hibernate.models.spi.SourceModelBuildingContext; - -import org.junit.jupiter.api.Test; - -import jakarta.persistence.Transient; -import net.bytebuddy.pool.TypePool; -import org.assertj.core.api.Assertions; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Steve Ebersole - */ -public class InheritanceTests { - @Test - void basicRootTestWithJandex() { - final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( - RootClass.class, - TrunkClass.class, - BranchClass.class, - LeafClass.class - ); - basicRootTest( typePool ); - } - - @Test - void basicRootTestWithoutJandex() { - basicRootTest( null ); - } - - private void basicRootTest(TypePool typePool) { - final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( - typePool, - RootClass.class, - TrunkClass.class, - BranchClass.class, - LeafClass.class - ); - final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); - - final ClassDetails rootClassDetails = classDetailsRegistry.getClassDetails( RootClass.class.getName() ); - assertThat( rootClassDetails.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNotNull(); - assertThat( rootClassDetails.getAnnotationUsage( SubclassableMarker.class, buildingContext ) ).isNotNull(); - assertThat( rootClassDetails.getAnnotationUsage( Composable.class, buildingContext ) ).isNull(); - Assertions.assertThat( rootClassDetails.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNull(); - - assertThat( rootClassDetails.getFields() ).hasSize( 2 ); - final FieldDetails value1 = rootClassDetails.findFieldByName( "value1" ); - assertThat( value1 ).isNotNull(); - assertThat( value1.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNotNull(); - assertThat( value1.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNull(); - assertThat( value1.getAnnotationUsage( Transient.class, buildingContext ) ).isNull(); - final FieldDetails value2 = rootClassDetails.findFieldByName( "value2" ); - assertThat( value2.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNull(); - assertThat( value2.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNull(); - assertThat( value2.getAnnotationUsage( Transient.class, buildingContext ) ).isNotNull(); - - assertThat( rootClassDetails.getSuperClass() ).isNotNull(); - assertThat( rootClassDetails.getSuperClass().toJavaClass() ).isEqualTo( Object.class ); - } - - @Test - void basicTrunkTestWithJandex() { - final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( - RootClass.class, - TrunkClass.class, - BranchClass.class, - LeafClass.class - ); - basicTrunkTest( typePool ); - } - - @Test - void basicTrunkTestWithoutJandex() { - basicTrunkTest( null ); - } - - private void basicTrunkTest(TypePool typePool) { - final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( - typePool, - RootClass.class, - TrunkClass.class, - BranchClass.class, - LeafClass.class - ); - final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); - - final ClassDetails trunkClassDetails = classDetailsRegistry.getClassDetails( TrunkClass.class.getName() ); - assertThat( trunkClassDetails.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNotNull(); - // NOTE : SubclassableMarker is @Inherited, so we should see it here too - assertThat( trunkClassDetails.getAnnotationUsage( SubclassableMarker.class, buildingContext ) ).isNotNull(); - assertThat( trunkClassDetails.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNull(); - - assertThat( trunkClassDetails.getFields() ).hasSize( 2 ); - final FieldDetails value3 = trunkClassDetails.findFieldByName( "value3" ); - assertThat( value3 ).isNotNull(); - assertThat( value3.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNotNull(); - assertThat( value3.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNull(); - assertThat( value3.getAnnotationUsage( Transient.class, buildingContext ) ).isNull(); - - final FieldDetails value4 = trunkClassDetails.findFieldByName( "value4" ); - assertThat( value4.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNull(); - assertThat( value4.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNull(); - assertThat( value4.getAnnotationUsage( Transient.class, buildingContext ) ).isNotNull(); - - assertThat( trunkClassDetails.getSuperClass() ).isNotNull(); - assertThat( trunkClassDetails.getSuperClass().toJavaClass() ).isEqualTo( RootClass.class ); - } - - @Test - void basicLeafTestWithJandex() { - final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( - RootClass.class, - TrunkClass.class, - BranchClass.class, - LeafClass.class - ); - basicLeafTest( typePool ); - } - - @Test - void basicLeafTestWithoutJandex() { - basicLeafTest( null ); - } - - private void basicLeafTest(TypePool typePool) { - final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( - typePool, - RootClass.class, - TrunkClass.class, - BranchClass.class, - LeafClass.class - ); - final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); - - final ClassDetails leafClassDetails = classDetailsRegistry.getClassDetails( LeafClass.class.getName() ); - assertThat( leafClassDetails.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNotNull(); - // NOTE : SubclassableMarker is @Inherited, so we should see it here too - assertThat( leafClassDetails.getAnnotationUsage( SubclassableMarker.class, buildingContext ) ).isNotNull(); - assertThat( leafClassDetails.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNull(); - - assertThat( leafClassDetails.getAnnotationUsage( ClassMarker.class, buildingContext ) ).isNotNull(); - // NOTE : SubclassableMarker is @Inherited, so we should see it even way down here too - assertThat( leafClassDetails.getAnnotationUsage( SubclassableMarker.class, buildingContext ) ).isNotNull(); - assertThat( leafClassDetails.getAnnotationUsage( MemberMarker.class, buildingContext ) ).isNull(); - } - - @Test - void testIsImplementorWithJandex() { - final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( - Intf.class, - RootClass.class, - TrunkClass.class, - BranchClass.class, - LeafClass.class - ); - testIsImplementor( typePool ); - } - - @Test - void testIsImplementorWithoutJandex() { - testIsImplementor( null ); - } - - private void testIsImplementor(TypePool typePool) { - final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( - typePool, - Intf.class, - RootClass.class, - TrunkClass.class, - BranchClass.class, - LeafClass.class - ); - final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); - - final ClassDetails rootClassDetails = classDetailsRegistry.getClassDetails( RootClass.class.getName() ); - assertThat( rootClassDetails.isImplementor( Intf.class ) ).isFalse(); - assertThat( rootClassDetails.getSuperClass() ).isSameAs( ClassDetails.OBJECT_CLASS_DETAILS ); - assertThat( rootClassDetails.isInterface() ).isFalse(); - - final ClassDetails branchClassDetails = classDetailsRegistry.getClassDetails( BranchClass.class.getName() ); - assertThat( branchClassDetails.isImplementor( Intf.class ) ).isTrue(); - assertThat( branchClassDetails.isInterface() ).isFalse(); - - final ClassDetails leafClassDetails = classDetailsRegistry.getClassDetails( LeafClass.class.getName() ); - assertThat( leafClassDetails.isImplementor( Intf.class ) ).isTrue(); - assertThat( leafClassDetails.isInterface() ).isFalse(); - - final ClassDetails interfaceDetails = classDetailsRegistry.getClassDetails( Intf.class.getName() ); - assertThat( interfaceDetails.isInterface() ).isTrue(); - } - - @Test - void testForEachDirectSubTypeWithJandex() { - final TypePool typePool = SourceModelTestHelper.buildByteBuddyTypePool( - Intf.class, - RootClass.class, - TrunkClass.class, - BranchClass.class, - LeafClass.class - ); - testForEachDirectSubType( typePool ); - } - - @Test - void testForEachDirectSubTypeWithoutJandex() { - testForEachDirectSubType( null ); - } - - private void testForEachDirectSubType(TypePool typePool) { - final SourceModelBuildingContext buildingContext = SourceModelTestHelper.createBuildingContext( - typePool, - RootClass.class, - TrunkClass.class, - BranchClass.class, - LeafClass.class - ); - final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); - - final List subTypes = new ArrayList<>(); - classDetailsRegistry.forEachDirectSubType( RootClass.class.getName(), subTypes::add ); - assertThat( subTypes ).hasSize( 1 ); - subTypes.clear(); - - classDetailsRegistry.forEachDirectSubType( TrunkClass.class.getName(), subTypes::add ); - assertThat( subTypes ).hasSize( 1 ); - subTypes.clear(); - - classDetailsRegistry.forEachDirectSubType( BranchClass.class.getName(), subTypes::add ); - assertThat( subTypes ).hasSize( 1 ); - subTypes.clear(); - - classDetailsRegistry.forEachDirectSubType( LeafClass.class.getName(), subTypes::add ); - assertThat( subTypes ).hasSize( 0 ); - } - -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Intf.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Intf.java deleted file mode 100644 index cf3df9e..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/Intf.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -/** - * @author Steve Ebersole - */ -interface Intf { -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/LeafClass.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/LeafClass.java deleted file mode 100644 index cbeefc0..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/LeafClass.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -import jakarta.persistence.Transient; - -/** - * @author Steve Ebersole - */ -@ClassMarker -public class LeafClass extends BranchClass { - @MemberMarker - private Integer value7; - @Transient - private Integer value8; -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/MemberMarker.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/MemberMarker.java deleted file mode 100644 index 143bd53..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/MemberMarker.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Silly annotation we can put on a field/method - * - * @author Steve Ebersole - */ -@Target({ElementType.FIELD,ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -public @interface MemberMarker { -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/PrimitiveTypeTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/PrimitiveTypeTests.java deleted file mode 100644 index 0db7b73..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/PrimitiveTypeTests.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -import org.hibernate.models.internal.jdk.JdkClassDetails; -import org.hibernate.models.spi.ClassDetails; -import org.hibernate.models.spi.ClassDetailsRegistry; -import org.hibernate.models.spi.SourceModelBuildingContext; - -import org.junit.jupiter.api.Test; - -import net.bytebuddy.pool.TypePool; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hibernate.models.bytebuddy.SourceModelTestHelper.buildByteBuddyTypePool; -import static org.hibernate.models.bytebuddy.SourceModelTestHelper.createBuildingContext; - -/** - * @author Steve Ebersole - */ -public class PrimitiveTypeTests { - @Test - void testWithJandex() { - final TypePool typePool = buildByteBuddyTypePool(); - final SourceModelBuildingContext buildingContext = createBuildingContext( typePool ); - verify( buildingContext.getClassDetailsRegistry() ); - } - - @Test - void testWithoutJandex() { - final SourceModelBuildingContext buildingContext = createBuildingContext( (TypePool) null ); - verify( buildingContext.getClassDetailsRegistry() ); - } - - void verify(ClassDetailsRegistry classDetailsRegistry) { - final ClassDetails booleanDetails = classDetailsRegistry.resolveClassDetails( "boolean" ); - assertThat( booleanDetails ).isNotNull(); - assertThat( booleanDetails ).isInstanceOf( JdkClassDetails.class ); - - final ClassDetails byteDetails = classDetailsRegistry.resolveClassDetails( "byte" ); - assertThat( byteDetails ).isNotNull(); - assertThat( byteDetails ).isInstanceOf( JdkClassDetails.class ); - - final ClassDetails shortDetails = classDetailsRegistry.resolveClassDetails( "short" ); - assertThat( shortDetails ).isNotNull(); - assertThat( shortDetails ).isInstanceOf( JdkClassDetails.class ); - - final ClassDetails intDetails = classDetailsRegistry.resolveClassDetails( "int" ); - assertThat( intDetails ).isNotNull(); - assertThat( intDetails ).isInstanceOf( JdkClassDetails.class ); - - final ClassDetails longDetails = classDetailsRegistry.resolveClassDetails( "long" ); - assertThat( longDetails ).isNotNull(); - assertThat( longDetails ).isInstanceOf( JdkClassDetails.class ); - - final ClassDetails doubleDetails = classDetailsRegistry.resolveClassDetails( "double" ); - assertThat( doubleDetails ).isNotNull(); - assertThat( doubleDetails ).isInstanceOf( JdkClassDetails.class ); - - final ClassDetails floatDetails = classDetailsRegistry.resolveClassDetails( "float" ); - assertThat( floatDetails ).isNotNull(); - assertThat( floatDetails ).isInstanceOf( JdkClassDetails.class ); - } -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/RootClass.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/RootClass.java deleted file mode 100644 index bf96130..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/RootClass.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -import jakarta.persistence.Transient; - -/** - * @author Steve Ebersole - */ -@ClassMarker -@SubclassableMarker -public class RootClass { - @MemberMarker - private Integer value1; - @Transient - private Integer value2; -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/SubclassableMarker.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/SubclassableMarker.java deleted file mode 100644 index cc5a007..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/SubclassableMarker.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @author Steve Ebersole - */ -@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -@Composable -public @interface SubclassableMarker { -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/TrunkClass.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/TrunkClass.java deleted file mode 100644 index 8122059..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/bytebuddy/classes/TrunkClass.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.bytebuddy.classes; - -import jakarta.persistence.Transient; - -/** - * @author Steve Ebersole - */ -@ClassMarker -public class TrunkClass extends RootClass { - @MemberMarker - private Integer value3; - @Transient - private Integer value4; -} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/shared/intg/ByteBuddyModelContextFactory.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/shared/intg/ByteBuddyModelContextFactory.java new file mode 100644 index 0000000..41723b8 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/shared/intg/ByteBuddyModelContextFactory.java @@ -0,0 +1,79 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.testing.shared.intg; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import org.hibernate.models.ModelsException; +import org.hibernate.models.bytebuddy.internal.ByteBuddyModelContextImpl; +import org.hibernate.models.spi.ClassLoading; +import org.hibernate.models.spi.RegistryPrimer; +import org.hibernate.models.spi.SourceModelBuildingContext; +import org.hibernate.models.testing.intg.ModelContextFactory; + +import net.bytebuddy.dynamic.ClassFileLocator; +import net.bytebuddy.pool.TypePool; + +import static org.hibernate.models.internal.SimpleClassLoading.SIMPLE_CLASS_LOADING; + +/** + * @author Steve Ebersole + */ +public class ByteBuddyModelContextFactory implements ModelContextFactory { + public static final ByteBuddyModelContextFactory CONTEXT_FACTORY = new ByteBuddyModelContextFactory(); + + @Override + public SourceModelBuildingContext createModelContext( + RegistryPrimer registryPrimer, + Class... modelClasses) { + final TypePool byteBuddyTypePool = buildTypePool( modelClasses ); + return new ByteBuddyModelContextImpl( byteBuddyTypePool, SIMPLE_CLASS_LOADING, registryPrimer ); + } + + public static TypePool buildTypePool(Class... modelClasses) { + return buildTypePool( SIMPLE_CLASS_LOADING, modelClasses ); + } + + public static TypePool buildTypePool(ClassLoading classLoadingAccess, Class... modelClasses) { + final TypePool typePool = TypePool.Default.of( new ClassLoadingBridge( classLoadingAccess ) ); + for ( Class modelClass : modelClasses ) { + // load each modelClass into the TypePool + typePool.describe( modelClass.getName() ).resolve(); + } + return typePool; + } + + private static class ClassLoadingBridge implements ClassFileLocator { + private final ClassLoading classLoading; + + public ClassLoadingBridge(ClassLoading classLoading) { + this.classLoading = classLoading; + } + + @Override + @SuppressWarnings("NullableProblems") + public Resolution locate(String name) throws IOException { + final String classFileName = toClassFileName( name ); + final URL locatedResource = classLoading.locateResource( classFileName ); + if ( locatedResource == null ) { + throw new ModelsException( "Unable to locate resource : " + name + " (" + classFileName + ")" ); + } + try (InputStream stream = locatedResource.openStream()) { + return new Resolution.Explicit( stream.readAllBytes() ); + } + } + + private String toClassFileName(String className) { + return className.replace( '.', '/' ) + ".class"; + } + + @Override + public void close() { + + } + } +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/tests/AnnotationHandlingTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/tests/AnnotationHandlingTests.java new file mode 100644 index 0000000..0001254 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/tests/AnnotationHandlingTests.java @@ -0,0 +1,65 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.testing.tests; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.SourceModelBuildingContext; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.models.testing.shared.intg.ByteBuddyModelContextFactory.CONTEXT_FACTORY; + +/** + * @author Steve Ebersole + */ +public class AnnotationHandlingTests { + @Test + void testSimpleUsages() { + final SourceModelBuildingContext buildingContext = CONTEXT_FACTORY.createModelContext( null, SimpleClass.class ); + final ClassDetails classDetails = buildingContext.getClassDetailsRegistry().resolveClassDetails( SimpleClass.class.getName() ); + assertThat( classDetails ).isNotNull(); + + final MyOtherAnnotation annotationUsage = classDetails.getDirectAnnotationUsage( MyOtherAnnotation.class ); + assertThat( annotationUsage ).isNotNull(); + assertThat( annotationUsage.theNested().value() ).isEqualTo( "nested" ); + assertThat( annotationUsage.theNesteds() ).hasSize( 1 ); + assertThat( annotationUsage.theNesteds()[0].value() ).isEqualTo( "nesteds[0]" ); + + } + + public enum MyEnum {FIRST,SECOND,THIRD} + + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + public @interface MyAnnotation { + String value(); + } + + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + public @interface MyOtherAnnotation { + MyEnum theEnum(); + int theInt(); + String theString(); + MyAnnotation theNested(); + MyAnnotation[] theNesteds(); + } + + @MyOtherAnnotation( + theEnum = MyEnum.SECOND, + theInt = Integer.MAX_VALUE, + theString = "Some string", + theNested = @MyAnnotation( "nested" ), + theNesteds = @MyAnnotation( "nesteds[0]" ) + ) + public static class SimpleClass { + } +} diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/tests/ProviderTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/tests/ProviderTests.java new file mode 100644 index 0000000..9207e45 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/tests/ProviderTests.java @@ -0,0 +1,53 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.testing.tests; + +import org.hibernate.models.bytebuddy.Settings; +import org.hibernate.models.bytebuddy.internal.ByteBuddyModelContextImpl; +import org.hibernate.models.internal.BasicModelBuildingContextImpl; +import org.hibernate.models.spi.ModelsConfiguration; +import org.hibernate.models.spi.SourceModelBuildingContext; +import org.hibernate.models.testing.shared.intg.ByteBuddyModelContextFactory; + +import org.junit.jupiter.api.Test; + +import net.bytebuddy.pool.TypePool; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.models.bytebuddy.spi.ByteBuddyContextProvider.BYTEBUDDY_PROVIDER; +import static org.hibernate.models.internal.SimpleClassLoading.SIMPLE_CLASS_LOADING; + +/** + * @author Steve Ebersole + */ +public class ProviderTests { + @Test + void testBasicBootstrap() { + final SourceModelBuildingContext context = new ModelsConfiguration() + .bootstrap(); + assertThat( context ).isNotNull(); + assertThat( context ).isInstanceOf( BasicModelBuildingContextImpl.class ); + } + + @Test + void testExplicitProvider() { + final SourceModelBuildingContext context = new ModelsConfiguration() + .setExplicitContextProvider( BYTEBUDDY_PROVIDER ) + .bootstrap(); + assertThat( context ).isNotNull(); + // without passing the TypePool, the basic one is used + assertThat( context ).isInstanceOf( BasicModelBuildingContextImpl.class ); + } + + @Test + void testPassingJandexIndex() { + final TypePool typePool = ByteBuddyModelContextFactory.buildTypePool( SIMPLE_CLASS_LOADING ); + final SourceModelBuildingContext context = new ModelsConfiguration() + .configValue( Settings.TYPE_POOL_PARAM, typePool ) + .bootstrap(); + assertThat( context ).isNotNull(); + assertThat( context ).isInstanceOf( ByteBuddyModelContextImpl.class ); + } +} diff --git a/hibernate-models-bytebuddy/src/test/resources/META-INF/services/org.hibernate.models.testing.intg.ModelContextFactory b/hibernate-models-bytebuddy/src/test/resources/META-INF/services/org.hibernate.models.testing.intg.ModelContextFactory new file mode 100644 index 0000000..02fdb40 --- /dev/null +++ b/hibernate-models-bytebuddy/src/test/resources/META-INF/services/org.hibernate.models.testing.intg.ModelContextFactory @@ -0,0 +1,5 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# Copyright: Red Hat Inc. and Hibernate Authors +# +org.hibernate.models.testing.shared.intg.ByteBuddyModelContextFactory \ No newline at end of file diff --git a/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/Settings.java b/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/Settings.java new file mode 100644 index 0000000..a89ae65 --- /dev/null +++ b/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/Settings.java @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.jandex; + +/** + * Settings for hibernate-models Jandex support + * + * @author Steve Ebersole + */ +public interface Settings { + String INDEX_PARAM = "hibernate.models.jandex.index"; +} diff --git a/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/spi/JandexBuildingContextProvider.java b/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/spi/JandexBuildingContextProvider.java index 7733403..84d021b 100644 --- a/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/spi/JandexBuildingContextProvider.java +++ b/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/spi/JandexBuildingContextProvider.java @@ -7,6 +7,7 @@ import java.util.Map; import org.hibernate.models.internal.BasicModelBuildingContextImpl; +import org.hibernate.models.jandex.Settings; import org.hibernate.models.spi.ClassLoading; import org.hibernate.models.spi.RegistryPrimer; import org.hibernate.models.spi.SourceModelBuildingContext; @@ -20,7 +21,7 @@ * @author Steve Ebersole */ public class JandexBuildingContextProvider implements SourceModelBuildingContextProvider { - public static final String INDEX_PARAM = "hibernate.models.jandex.index"; + public static final JandexBuildingContextProvider JANDEX_PROVIDER = new JandexBuildingContextProvider(); @Override public SourceModelBuildingContext produceContext( @@ -40,6 +41,6 @@ public SourceModelBuildingContext produceContext( private IndexView resolveJandexIndex(Map configProperties) { // todo : do we want to have the ability to create the Jandex index or resolve one from another source? // - note: if building, be sure to apply BaseLineJavaTypes - return (IndexView) configProperties.get( INDEX_PARAM ); + return (IndexView) configProperties.get( Settings.INDEX_PARAM ); } } diff --git a/hibernate-models-jandex/src/test/java/org/hibernate/models/testing/tests/ProviderTests.java b/hibernate-models-jandex/src/test/java/org/hibernate/models/testing/tests/ProviderTests.java new file mode 100644 index 0000000..7d7da3f --- /dev/null +++ b/hibernate-models-jandex/src/test/java/org/hibernate/models/testing/tests/ProviderTests.java @@ -0,0 +1,53 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.testing.tests; + +import org.hibernate.models.internal.BasicModelBuildingContextImpl; +import org.hibernate.models.jandex.Settings; +import org.hibernate.models.jandex.internal.JandexModelBuildingContextImpl; +import org.hibernate.models.spi.ModelsConfiguration; +import org.hibernate.models.spi.SourceModelBuildingContext; +import org.hibernate.models.testing.shared.intg.JandexModelContextFactoryImpl; + +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; +import static org.hibernate.models.jandex.spi.JandexBuildingContextProvider.JANDEX_PROVIDER; + +/** + * @author Steve Ebersole + */ +public class ProviderTests { + @Test + void testBasicBootstrap() { + final SourceModelBuildingContext context = new ModelsConfiguration() + .bootstrap(); + assertThat( context ).isNotNull(); + assertThat( context ).isInstanceOf( BasicModelBuildingContextImpl.class ); + } + + @Test + void testExplicitProvider() { + final SourceModelBuildingContext context = new ModelsConfiguration() + .setExplicitContextProvider( JANDEX_PROVIDER ) + .bootstrap(); + assertThat( context ).isNotNull(); + // without passing the Index, the basic one is used + assertThat( context ).isInstanceOf( BasicModelBuildingContextImpl.class ); + } + + @Test + void testPassingJandexIndex() { + final Index index = JandexModelContextFactoryImpl.buildJandexIndex( SIMPLE_CLASS_LOADING ); + final SourceModelBuildingContext context = new ModelsConfiguration() + .configValue( Settings.INDEX_PARAM, index ) + .bootstrap(); + assertThat( context ).isNotNull(); + assertThat( context ).isInstanceOf( JandexModelBuildingContextImpl.class ); + } +} From 8ba7162b105b946d6f77c8c2772f75b3ab7637f8 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Mon, 24 Mar 2025 08:27:22 -0500 Subject: [PATCH 3/4] #107 - hibernate-models-bytebuddy --- .../models/bytebuddy/internal/values/ArrayValueConverter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java index 88fa3c5..2342261 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java @@ -14,7 +14,6 @@ import org.hibernate.models.spi.ValueTypeDescriptor; import net.bytebuddy.description.annotation.AnnotationValue; -import net.bytebuddy.pool.TypePool; /** * Support for converting array values From 72776d7f05b7f8bccd23d291548cb0a79b4b1e40 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Tue, 25 Mar 2025 11:31:53 -0500 Subject: [PATCH 4/4] #107 - hibernate-models-bytebuddy --- .../src/main/groovy/shared-testing.gradle | 11 +- .../bytebuddy/internal/ClassDetailsImpl.java | 1 + .../internal/ClassDetailsRegistryImpl.java | 2 +- .../bytebuddy/internal/ModelBuilders.java | 13 ++ .../internal/TypeSwitchStandard.java | 39 +++- .../internal/values/ArrayValueConverter.java | 185 +++++++++++++++--- .../internal/values/ArrayValueExtractor.java | 2 +- .../internal/values/ClassValueConverter.java | 9 +- .../intg/ByteBuddyModelContextFactory.java | 4 +- .../tests/AnnotationHandlingTests.java | 65 ------ .../internal/JandexClassDetailsRegistry.java | 6 +- .../JandexModelBuildingContextImpl.java | 3 +- .../intg/JandexModelContextFactoryImpl.java | 5 +- hibernate-models/build.gradle | 13 +- .../AbstractClassDetailsRegistry.java | 3 - .../ClassDetailsRegistryStandard.java | 2 +- .../internal/WildcardTypeDetailsImpl.java | 6 +- .../models/spi/ClassDetailsRegistry.java | 5 + 18 files changed, 245 insertions(+), 129 deletions(-) delete mode 100644 hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/tests/AnnotationHandlingTests.java diff --git a/buildSrc/src/main/groovy/shared-testing.gradle b/buildSrc/src/main/groovy/shared-testing.gradle index 76896a4..bf1e34f 100644 --- a/buildSrc/src/main/groovy/shared-testing.gradle +++ b/buildSrc/src/main/groovy/shared-testing.gradle @@ -11,7 +11,6 @@ plugins { // Wire in the shared-tests // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// link the configurations { sharedTestClasses { canBeConsumed = false @@ -24,22 +23,20 @@ configurations { sharedTestRuntimeClasspath { canBeConsumed = false canBeResolved = true - extendsFrom testRuntimeClasspath } } dependencies { testImplementation project( ":hibernate-models-testing" ) - sharedTestClasses project(path: ':hibernate-models', configuration: 'exposedTestClasses') - sharedTestResources project(path: ':hibernate-models', configuration: 'exposedTestResources') - sharedTestRuntimeClasspath project(path: ':hibernate-models', configuration: 'exposedTestRuntimeClasspath') + sharedTestClasses project(path: ':hibernate-models', configuration: 'exportedTestClasses') + sharedTestResources project(path: ':hibernate-models', configuration: 'exportedTestResources') + + sharedTestRuntimeClasspath project(path: ':hibernate-models', configuration: 'exportedTestRuntimeClasspath') } tasks.named( "test", Test ) { - // use the configurations defined above, which depends on the configurations in `:architecture-tests` testClassesDirs += configurations.sharedTestClasses - classpath += configurations.sharedTestResources classpath += configurations.sharedTestRuntimeClasspath } diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsImpl.java index 08259fc..13fd426 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsImpl.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsImpl.java @@ -52,6 +52,7 @@ public class ClassDetailsImpl extends AbstractAnnotationTarget implements ClassD public ClassDetailsImpl(TypeDescription typeDescription, ByteBuddyModelsContext modelContext) { super( modelContext ); + assert !typeDescription.isPrimitive(); this.typeDescription = typeDescription; this.superClassDetails = determineSuperType( typeDescription, modelContext ); } diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsRegistryImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsRegistryImpl.java index 26651a6..f9edd79 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsRegistryImpl.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsRegistryImpl.java @@ -25,7 +25,7 @@ public ClassDetailsRegistryImpl(ByteBuddyModelContextImpl context) { } @Override - protected ClassDetailsBuilder getClassDetailsBuilder() { + public ClassDetailsBuilder getClassDetailsBuilder() { return classDetailsBuilder; } diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ModelBuilders.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ModelBuilders.java index 9a6e7e1..48add91 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ModelBuilders.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ModelBuilders.java @@ -57,6 +57,11 @@ public static ClassDetails buildDetails(String name, ByteBuddyModelsContext mode return null; } + if ( name.startsWith( "[" ) ) { + // always handle arrays via the JDK builder + return null; + } + if ( "void".equals( name ) ) { name = Void.class.getName(); } @@ -149,6 +154,14 @@ public static Class resolvePrimitiveClass(String className) { return Float.class; } + if ( "char".equals( className ) ) { + return char.class; + } + + if ( Character.class.getSimpleName().equals( className ) || Character.class.getName().equals( className ) ) { + return Character.class; + } + return null; } diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/TypeSwitchStandard.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/TypeSwitchStandard.java index cf7f3e0..dcead71 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/TypeSwitchStandard.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/TypeSwitchStandard.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; import org.hibernate.models.bytebuddy.spi.TypeSwitch; @@ -97,23 +98,45 @@ public TypeDetails caseWildcardType(TypeDefinition typeDescription, SourceModelB final TypeList.Generic bound; final boolean isExtends; - if ( ! (upperBounds instanceof TypeList.Generic.Empty) ) { + if ( isExtends( upperBounds, lowerBounds ) ) { bound = upperBounds; isExtends = true; } - else if ( ! (lowerBounds instanceof TypeList.Generic.Empty) ) { + else { bound = lowerBounds; isExtends = false; } - else { - throw new IllegalArgumentException( "What?" ); - } return new WildcardTypeDetailsImpl( TypeSwitcher.switchType( bound.get( 0 ), this, buildingContext ), isExtends ); } + private boolean isExtends(TypeList.Generic upperBounds, TypeList.Generic lowerBounds) { + if ( lowerBounds.isEmpty() ) { + return true; + } + + return upperBounds.isEmpty(); + } + + private HashSet typeVariableIdentifiers; + @Override public TypeDetails caseTypeVariable(TypeDefinition typeDescription, SourceModelBuildingContext buildingContext) { + final boolean isTypeVariableRef; + if ( typeVariableIdentifiers == null ) { + typeVariableIdentifiers = new HashSet<>(); + typeVariableIdentifiers.add( typeDescription.getActualName() ); + isTypeVariableRef = false; + } + else { + final boolean newlyAdded = typeVariableIdentifiers.add( typeDescription.getActualName() ); + isTypeVariableRef = !newlyAdded; + } + + if ( isTypeVariableRef ) { + return new TypeVariableReferenceDetailsImpl( typeDescription.getActualName() ); + } + return new TypeVariableDetailsImpl( typeDescription.getActualName(), declaringType, @@ -125,6 +148,12 @@ public TypeDetails caseTypeVariable(TypeDefinition typeDescription, SourceModelB public TypeDetails caseTypeVariableReference( TypeDefinition typeDescription, SourceModelBuildingContext buildingContext) { + // todo : This is not actually correct I think. From the Byte Buddy javadocs: + // > Represents a type variable that is merely symbolic and is not + // > attached to a net.bytebuddy.description.TypeVariableSource and does + // > not defined bounds. + // - but I am unsure of an actual scenario this is attempting to describe + // to be able to test it out return new TypeVariableReferenceDetailsImpl( typeDescription.getActualName() ); } diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java index 2342261..2b1e911 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java @@ -4,15 +4,17 @@ */ package org.hibernate.models.bytebuddy.internal.values; -import java.lang.reflect.Field; -import java.util.List; -import org.hibernate.models.ModelsException; -import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext; +import java.lang.annotation.Annotation; + +import org.hibernate.models.bytebuddy.internal.AnnotationUsageBuilder; import org.hibernate.models.bytebuddy.spi.ValueConverter; +import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.AnnotationDescriptorRegistry; import org.hibernate.models.spi.SourceModelBuildingContext; import org.hibernate.models.spi.ValueTypeDescriptor; +import net.bytebuddy.description.annotation.AnnotationDescription; import net.bytebuddy.description.annotation.AnnotationValue; /** @@ -28,46 +30,171 @@ public ArrayValueConverter(ValueTypeDescriptor elementTypeDescriptor) { } @Override - public V[] convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { - assert byteBuddyValue != null; + public V[] convert(AnnotationValue annotationValue, SourceModelBuildingContext modelContext) { + assert annotationValue != null; + + final Class elementValueType = elementTypeDescriptor.getValueType(); + + if ( Boolean.class == elementValueType ) { + return convertBooleanArray( annotationValue, modelContext ); + } + + if ( Byte.class == elementValueType ) { + return convertByteArray( annotationValue, modelContext ); + } - // UGH... - final List> byteBuddyValues = extractValueValues( byteBuddyValue, modelContext ); + if ( Short.class == elementValueType ) { + return convertShortArray( annotationValue, modelContext ); + } + + if ( Integer.class == elementValueType ) { + return convertIntArray( annotationValue, modelContext ); + } - final V[] result = elementTypeDescriptor.makeArray( byteBuddyValues.size(), modelContext ); - final ValueConverter elementWrapper = modelContext.as( ByteBuddyModelsContext.class ).getValueConverter( elementTypeDescriptor ); + if ( Long.class == elementValueType ) { + return convertLongArray( annotationValue, modelContext ); + } + + if ( double.class == elementValueType ) { + return convertDoubleArray( annotationValue, modelContext ); + } - for ( int i = 0; i < byteBuddyValues.size(); i++ ) { - result[i] = elementWrapper.convert( byteBuddyValues.get(i), modelContext ); + if ( float.class == elementValueType ) { + return convertFloatArray( annotationValue, modelContext ); } - return result; + + if ( Character.class == elementValueType ) { + return convertCharacterArray( annotationValue, modelContext ); + } + + if ( elementValueType.isAnnotation() ) { + return convertNestedAnnotationArray( annotationValue, modelContext ); + } + + final Class arrayType = elementValueType.arrayType(); + //noinspection unchecked + return (V[]) annotationValue.resolve( arrayType ); } - private List> extractValueValues( - AnnotationValue byteBuddyValue, + private V[] convertBooleanArray( + AnnotationValue annotationValue, SourceModelBuildingContext modelContext) { - try { - //noinspection unchecked - return (List>) getValuesField( modelContext ).get( byteBuddyValue ); + final boolean[] resolved = annotationValue.resolve( boolean[].class ); + final Boolean[] result = (Boolean[]) elementTypeDescriptor.makeArray( resolved.length, modelContext ); + for ( int i = 0; i < resolved.length; i++ ) { + result[i] = resolved[i]; } - catch (IllegalAccessException e) { - throw new ModelsException( "Could not access Byte Buddy's `AnnotationValue.ForDescriptionArray#values` field", e ); + //noinspection unchecked + return (V[]) result; + } + + private V[] convertByteArray( + AnnotationValue annotationValue, + SourceModelBuildingContext modelContext) { + final byte[] resolved = annotationValue.resolve( byte[].class ); + final Byte[] result = (Byte[]) elementTypeDescriptor.makeArray( resolved.length, modelContext ); + for ( int i = 0; i < resolved.length; i++ ) { + result[i] = resolved[i]; } + //noinspection unchecked + return (V[]) result; } - private Field getValuesField(SourceModelBuildingContext modelContext) { - return ARRRRGGGGHHHHH; + private V[] convertShortArray( + AnnotationValue annotationValue, + SourceModelBuildingContext modelContext) { + final short[] resolved = annotationValue.resolve( short[].class ); + final Short[] result = (Short[]) elementTypeDescriptor.makeArray( resolved.length, modelContext ); + for ( int i = 0; i < resolved.length; i++ ) { + result[i] = resolved[i]; + } + //noinspection unchecked + return (V[]) result; } - private static Field ARRRRGGGGHHHHH; + private V[] convertIntArray( + AnnotationValue annotationValue, + SourceModelBuildingContext modelContext) { + final int[] resolved = annotationValue.resolve( int[].class ); + final Integer[] result = (Integer[]) elementTypeDescriptor.makeArray( resolved.length, modelContext ); + for ( int i = 0; i < resolved.length; i++ ) { + result[i] = resolved[i]; + } + //noinspection unchecked + return (V[]) result; + } + + private V[] convertLongArray( + AnnotationValue annotationValue, + SourceModelBuildingContext modelContext) { + final long[] resolved = annotationValue.resolve( long[].class ); + final Long[] result = (Long[]) elementTypeDescriptor.makeArray( resolved.length, modelContext ); + for ( int i = 0; i < resolved.length; i++ ) { + result[i] = resolved[i]; + } + //noinspection unchecked + return (V[]) result; + } + + private V[] convertDoubleArray( + AnnotationValue annotationValue, + SourceModelBuildingContext modelContext) { + final double[] resolved = annotationValue.resolve( double[].class ); + final Double[] result = (Double[]) elementTypeDescriptor.makeArray( resolved.length, modelContext ); + for ( int i = 0; i < resolved.length; i++ ) { + result[i] = resolved[i]; + } + //noinspection unchecked + return (V[]) result; + } + + private V[] convertFloatArray( + AnnotationValue annotationValue, + SourceModelBuildingContext modelContext) { + final float[] resolved = annotationValue.resolve( float[].class ); + final Float[] result = (Float[]) elementTypeDescriptor.makeArray( resolved.length, modelContext ); + for ( int i = 0; i < resolved.length; i++ ) { + result[i] = resolved[i]; + } + //noinspection unchecked + return (V[]) result; + } - static { - try { - ARRRRGGGGHHHHH = AnnotationValue.ForDescriptionArray.class.getDeclaredField( "values" ); - ARRRRGGGGHHHHH.setAccessible( true ); + private V[] convertCharacterArray( + AnnotationValue annotationValue, + SourceModelBuildingContext modelContext) { + final char[] resolved = annotationValue.resolve( char[].class ); + final Character[] result = (Character[]) elementTypeDescriptor.makeArray( resolved.length, modelContext ); + for ( int i = 0; i < resolved.length; i++ ) { + result[i] = resolved[i]; } - catch (Exception e) { - throw new ModelsException( "Could not access Byte Buddy's `AnnotationValue.ForDescriptionArray#values` field", e ); + //noinspection unchecked + return (V[]) result; + } + + private V[] convertNestedAnnotationArray( + AnnotationValue annotationValue, + SourceModelBuildingContext modelContext) { + final AnnotationDescriptorRegistry descriptorRegistry = modelContext.getAnnotationDescriptorRegistry(); + + //noinspection unchecked + final Class annotationType = (Class) elementTypeDescriptor.getValueType(); + final AnnotationDescriptor annotationDescriptor = descriptorRegistry.getDescriptor( annotationType ); + + final AnnotationDescription[] resolved = annotationValue.resolve( AnnotationDescription[].class ); + final Annotation[] result = (Annotation[]) elementTypeDescriptor.makeArray( resolved.length, modelContext ); + + for ( int i = 0; i < resolved.length; i++ ) { + final AnnotationDescription annotationDescription = resolved[i]; + final Annotation usage = AnnotationUsageBuilder.makeUsage( + annotationDescription, + annotationDescriptor, + modelContext + ); + result[i] = usage; } + + //noinspection unchecked + return (V[]) result; } } diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueExtractor.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueExtractor.java index 257aa28..0984caf 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueExtractor.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueExtractor.java @@ -17,7 +17,7 @@ public class ArrayValueExtractor extends AbstractValueExtractor { private final ValueConverter wrapper; - public ArrayValueExtractor(ValueConverter wrapper) { + public ArrayValueExtractor(ValueConverter wrapper) { this.wrapper = wrapper; } diff --git a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ClassValueConverter.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ClassValueConverter.java index d17e137..7d3be97 100644 --- a/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ClassValueConverter.java +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ClassValueConverter.java @@ -8,6 +8,7 @@ import org.hibernate.models.spi.SourceModelBuildingContext; import net.bytebuddy.description.annotation.AnnotationValue; +import net.bytebuddy.description.type.TypeDescription; /** @@ -20,6 +21,12 @@ public class ClassValueConverter implements ValueConverter> { @Override public Class convert(AnnotationValue byteBuddyValue, SourceModelBuildingContext modelContext) { - return byteBuddyValue.resolve( Class.class ); + final TypeDescription typeDescription = byteBuddyValue.resolve( TypeDescription.class ); + final String typeName = typeDescription.getName(); + if ( "void".equals( typeName ) ) { + return void.class; + } + return modelContext.getClassLoading().classForName( typeDescription.getTypeName() ); +// return byteBuddyValue.resolve( Class.class ); } } diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/shared/intg/ByteBuddyModelContextFactory.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/shared/intg/ByteBuddyModelContextFactory.java index 41723b8..f4337f6 100644 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/shared/intg/ByteBuddyModelContextFactory.java +++ b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/shared/intg/ByteBuddyModelContextFactory.java @@ -10,9 +10,9 @@ import org.hibernate.models.ModelsException; import org.hibernate.models.bytebuddy.internal.ByteBuddyModelContextImpl; +import org.hibernate.models.bytebuddy.spi.ByteBuddyModelsContext; import org.hibernate.models.spi.ClassLoading; import org.hibernate.models.spi.RegistryPrimer; -import org.hibernate.models.spi.SourceModelBuildingContext; import org.hibernate.models.testing.intg.ModelContextFactory; import net.bytebuddy.dynamic.ClassFileLocator; @@ -27,7 +27,7 @@ public class ByteBuddyModelContextFactory implements ModelContextFactory { public static final ByteBuddyModelContextFactory CONTEXT_FACTORY = new ByteBuddyModelContextFactory(); @Override - public SourceModelBuildingContext createModelContext( + public ByteBuddyModelsContext createModelContext( RegistryPrimer registryPrimer, Class... modelClasses) { final TypePool byteBuddyTypePool = buildTypePool( modelClasses ); diff --git a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/tests/AnnotationHandlingTests.java b/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/tests/AnnotationHandlingTests.java deleted file mode 100644 index 0001254..0000000 --- a/hibernate-models-bytebuddy/src/test/java/org/hibernate/models/testing/tests/AnnotationHandlingTests.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.models.testing.tests; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.hibernate.models.spi.ClassDetails; -import org.hibernate.models.spi.SourceModelBuildingContext; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hibernate.models.testing.shared.intg.ByteBuddyModelContextFactory.CONTEXT_FACTORY; - -/** - * @author Steve Ebersole - */ -public class AnnotationHandlingTests { - @Test - void testSimpleUsages() { - final SourceModelBuildingContext buildingContext = CONTEXT_FACTORY.createModelContext( null, SimpleClass.class ); - final ClassDetails classDetails = buildingContext.getClassDetailsRegistry().resolveClassDetails( SimpleClass.class.getName() ); - assertThat( classDetails ).isNotNull(); - - final MyOtherAnnotation annotationUsage = classDetails.getDirectAnnotationUsage( MyOtherAnnotation.class ); - assertThat( annotationUsage ).isNotNull(); - assertThat( annotationUsage.theNested().value() ).isEqualTo( "nested" ); - assertThat( annotationUsage.theNesteds() ).hasSize( 1 ); - assertThat( annotationUsage.theNesteds()[0].value() ).isEqualTo( "nesteds[0]" ); - - } - - public enum MyEnum {FIRST,SECOND,THIRD} - - @Target(ElementType.TYPE) - @Retention(RetentionPolicy.RUNTIME) - public @interface MyAnnotation { - String value(); - } - - @Target(ElementType.TYPE) - @Retention(RetentionPolicy.RUNTIME) - public @interface MyOtherAnnotation { - MyEnum theEnum(); - int theInt(); - String theString(); - MyAnnotation theNested(); - MyAnnotation[] theNesteds(); - } - - @MyOtherAnnotation( - theEnum = MyEnum.SECOND, - theInt = Integer.MAX_VALUE, - theString = "Some string", - theNested = @MyAnnotation( "nested" ), - theNesteds = @MyAnnotation( "nesteds[0]" ) - ) - public static class SimpleClass { - } -} diff --git a/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexClassDetailsRegistry.java b/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexClassDetailsRegistry.java index 0704b69..f8c1316 100644 --- a/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexClassDetailsRegistry.java +++ b/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexClassDetailsRegistry.java @@ -31,8 +31,12 @@ public JandexClassDetailsRegistry(IndexView jandexIndex, SourceModelBuildingCont this.classDetailsBuilder = new JandexClassDetailsBuilderImpl( jandexIndex, context ); } + public IndexView getJandexIndex() { + return jandexIndex; + } + @Override - protected ClassDetailsBuilder getClassDetailsBuilder() { + public ClassDetailsBuilder getClassDetailsBuilder() { return classDetailsBuilder; } diff --git a/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexModelBuildingContextImpl.java b/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexModelBuildingContextImpl.java index 677e657..3db0d2f 100644 --- a/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexModelBuildingContextImpl.java +++ b/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexModelBuildingContextImpl.java @@ -9,7 +9,6 @@ import org.hibernate.models.internal.AbstractModelBuildingContext; import org.hibernate.models.internal.MutableAnnotationDescriptorRegistry; -import org.hibernate.models.internal.MutableClassDetailsRegistry; import org.hibernate.models.jandex.spi.JandexModelBuildingContext; import org.hibernate.models.jandex.spi.JandexValueConverter; import org.hibernate.models.jandex.spi.JandexValueExtractor; @@ -60,7 +59,7 @@ public MutableAnnotationDescriptorRegistry getAnnotationDescriptorRegistry() { } @Override - public MutableClassDetailsRegistry getClassDetailsRegistry() { + public JandexClassDetailsRegistry getClassDetailsRegistry() { return classDetailsRegistry; } diff --git a/hibernate-models-jandex/src/test/java/org/hibernate/models/testing/shared/intg/JandexModelContextFactoryImpl.java b/hibernate-models-jandex/src/test/java/org/hibernate/models/testing/shared/intg/JandexModelContextFactoryImpl.java index 9ac7428..0679c86 100644 --- a/hibernate-models-jandex/src/test/java/org/hibernate/models/testing/shared/intg/JandexModelContextFactoryImpl.java +++ b/hibernate-models-jandex/src/test/java/org/hibernate/models/testing/shared/intg/JandexModelContextFactoryImpl.java @@ -12,7 +12,6 @@ import org.hibernate.models.jandex.internal.JandexModelBuildingContextImpl; import org.hibernate.models.spi.ClassLoading; import org.hibernate.models.spi.RegistryPrimer; -import org.hibernate.models.spi.SourceModelBuildingContext; import org.hibernate.models.testing.intg.ModelContextFactory; import org.hibernate.models.testing.orm.JpaAnnotations; @@ -25,8 +24,10 @@ * @author Steve Ebersole */ public class JandexModelContextFactoryImpl implements ModelContextFactory { + public static final JandexModelContextFactoryImpl CONTEXT_FACTORY = new JandexModelContextFactoryImpl(); + @Override - public SourceModelBuildingContext createModelContext( + public JandexModelBuildingContextImpl createModelContext( RegistryPrimer registryPrimer, Class... modelClasses) { final Index jandexIndex = buildJandexIndex( SIMPLE_CLASS_LOADING, modelClasses ); diff --git a/hibernate-models/build.gradle b/hibernate-models/build.gradle index aef69a2..4c1e7c8 100644 --- a/hibernate-models/build.gradle +++ b/hibernate-models/build.gradle @@ -13,27 +13,26 @@ dependencies { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ configurations { - exposedTestClasses { + exportedTestClasses { canBeConsumed = true canBeResolved = false } - exposedTestResources { + exportedTestResources { canBeConsumed = true canBeResolved = false } - exposedTestRuntimeClasspath { + exportedTestRuntimeClasspath { canBeConsumed = true canBeResolved = false } } artifacts { - exposedTestClasses(sourceSets.test.output.classesDirs.files) { + exportedTestClasses(sourceSets.test.output.classesDirs.files) { builtBy(compileTestJava) } - exposedTestResources(sourceSets.test.output.resourcesDir) { + exportedTestResources(sourceSets.test.output.resourcesDir) { builtBy(processTestResources) - } - exposedTestRuntimeClasspath sourceSets.test.runtimeClasspath.files + exportedTestRuntimeClasspath sourceSets.test.runtimeClasspath.files } \ No newline at end of file diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/AbstractClassDetailsRegistry.java b/hibernate-models/src/main/java/org/hibernate/models/internal/AbstractClassDetailsRegistry.java index df11538..6031ceb 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/AbstractClassDetailsRegistry.java +++ b/hibernate-models/src/main/java/org/hibernate/models/internal/AbstractClassDetailsRegistry.java @@ -11,7 +11,6 @@ import org.hibernate.models.UnknownClassException; import org.hibernate.models.spi.ClassDetails; -import org.hibernate.models.spi.ClassDetailsBuilder; import org.hibernate.models.spi.SourceModelBuildingContext; /** @@ -43,8 +42,6 @@ protected AbstractClassDetailsRegistry( classDetailsMap.put( ClassDetails.VOID_OBJECT_CLASS_DETAILS.getName(), ClassDetails.VOID_OBJECT_CLASS_DETAILS ); } - protected abstract ClassDetailsBuilder getClassDetailsBuilder(); - @Override public List getDirectSubTypes(String superTypeName) { return subTypeClassDetailsMap.get( superTypeName ); diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/ClassDetailsRegistryStandard.java b/hibernate-models/src/main/java/org/hibernate/models/internal/ClassDetailsRegistryStandard.java index 27a3ecb..1c436ed 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/ClassDetailsRegistryStandard.java +++ b/hibernate-models/src/main/java/org/hibernate/models/internal/ClassDetailsRegistryStandard.java @@ -34,7 +34,7 @@ public ClassDetailsRegistryStandard(ClassDetailsBuilder classDetailsBuilder, Sou } @Override - protected ClassDetailsBuilder getClassDetailsBuilder() { + public ClassDetailsBuilder getClassDetailsBuilder() { return classDetailsBuilder; } } diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/WildcardTypeDetailsImpl.java b/hibernate-models/src/main/java/org/hibernate/models/internal/WildcardTypeDetailsImpl.java index 77e6634..8c4efcb 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/WildcardTypeDetailsImpl.java +++ b/hibernate-models/src/main/java/org/hibernate/models/internal/WildcardTypeDetailsImpl.java @@ -23,8 +23,10 @@ public TypeDetails getBound() { } /** - * Whether the {@linkplain #bound() bound} is an extends - i.e. {@code ? extends Something}. - * False would imply a super - i.e. {@code ? super Something}. + * Indicates the type of {@linkplain #bound() bound} -
    + *
  1. {@code true} -> {@code ? extends Something}
  2. + *
  3. {@code false} -> {@code ? super Something}
  4. + *
*/ @Override public boolean isExtends() { diff --git a/hibernate-models/src/main/java/org/hibernate/models/spi/ClassDetailsRegistry.java b/hibernate-models/src/main/java/org/hibernate/models/spi/ClassDetailsRegistry.java index fea600b..b3ca6af 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/spi/ClassDetailsRegistry.java +++ b/hibernate-models/src/main/java/org/hibernate/models/spi/ClassDetailsRegistry.java @@ -70,6 +70,11 @@ default S as(Class type) { return (S) this; } + /** + * Access to the ClassDetailsBuilder used in this registry + */ + ClassDetailsBuilder getClassDetailsBuilder(); + @FunctionalInterface interface ClassDetailsConsumer { void consume(ClassDetails classDetails);