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/build.gradle b/hibernate-models-bytebuddy/build.gradle new file mode 100644 index 0000000..edcb1e8 --- /dev/null +++ b/hibernate-models-bytebuddy/build.gradle @@ -0,0 +1,16 @@ +plugins { + id "published-java-module" + id "shared-testing" +} + +description = "Support for hibernate-models based on ByteBuddy (isolated dependency)" + +repositories { + mavenCentral() +} + +dependencies { + api project( ":hibernate-models" ) + + implementation libs.byteBuddy +} \ 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 new file mode 100644 index 0000000..41cd587 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AbstractAnnotationTarget.java @@ -0,0 +1,46 @@ +/* + * 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.bytebuddy.spi.ByteBuddyModelsContext; +import org.hibernate.models.internal.AnnotationTargetSupport; + +import net.bytebuddy.description.annotation.AnnotationSource; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractAnnotationTarget implements AnnotationTargetSupport { + private final ByteBuddyModelsContext modelContext; + + private Map, ? extends Annotation> usageMap; + + public AbstractAnnotationTarget(ByteBuddyModelsContext modelContext) { + this.modelContext = modelContext; + } + + public ByteBuddyModelsContext 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..4411634 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationDescriptorImpl.java @@ -0,0 +1,36 @@ +/* + * 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.bytebuddy.spi.ByteBuddyModelsContext; +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, ByteBuddyModelsContext 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..67feeef --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/AnnotationUsageBuilder.java @@ -0,0 +1,118 @@ +/* + * 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.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; +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, + SourceModelBuildingContext modelContext) { + final Map attributeValues = extractAttributeValues( + annotationDescription, + annotationDescriptor, + modelContext + ); + return annotationDescriptor.createUsage( attributeValues, modelContext ); + } + + private static Map extractAttributeValues( + AnnotationDescription annotationDescription, + AnnotationDescriptor annotationDescriptor, + SourceModelBuildingContext 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( ByteBuddyModelContextImpl.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, + ByteBuddyModelsContext 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, + ByteBuddyModelsContext 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/ByteBuddyModelContextImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ByteBuddyModelContextImpl.java new file mode 100644 index 0000000..bd45a41 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ByteBuddyModelContextImpl.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.ByteBuddyModelsContext; +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 ByteBuddyModelContextImpl + extends AbstractModelBuildingContext + implements ByteBuddyModelsContext { + 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 ByteBuddyModelContextImpl( + TypePool typePool, + RegistryPrimer registryPrimer) { + this( typePool, SimpleClassLoading.SIMPLE_CLASS_LOADING, registryPrimer ); + } + + public ByteBuddyModelContextImpl( + 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/ClassDetailsBuilderImpl.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsBuilderImpl.java new file mode 100644 index 0000000..4dbb9c2 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsBuilderImpl.java @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +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; + +/** + * @author Steve Ebersole + */ +public class ClassDetailsBuilderImpl implements ClassDetailsBuilder { + private final ByteBuddyModelsContext modelContext; + + public ClassDetailsBuilderImpl(ByteBuddyModelsContext 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..13fd426 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsImpl.java @@ -0,0 +1,267 @@ +/* + * 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.bytebuddy.spi.ByteBuddyModelsContext; +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, ByteBuddyModelsContext modelContext) { + super( modelContext ); + assert !typeDescription.isPrimitive(); + 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..f9edd79 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ClassDetailsRegistryImpl.java @@ -0,0 +1,53 @@ +/* + * 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 ClassDetailsBuilderImpl classDetailsBuilder; + + public ClassDetailsRegistryImpl(ByteBuddyModelContextImpl context) { + super( context ); + this.classDetailsBuilder = new ClassDetailsBuilderImpl( context ); + } + + @Override + public 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..a31582c --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/FieldDetailsImpl.java @@ -0,0 +1,152 @@ +/* + * 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.bytebuddy.spi.ByteBuddyModelsContext; +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, + ByteBuddyModelsContext 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..0607aee --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/MethodDetailsImpl.java @@ -0,0 +1,216 @@ +/* + * 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.bytebuddy.spi.ByteBuddyModelsContext; +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, + ByteBuddyModelsContext 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..48add91 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/ModelBuilders.java @@ -0,0 +1,467 @@ +/* + * 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.ByteBuddyModelsContext; +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, ByteBuddyModelsContext modelContext) { + if ( StringHelper.isEmpty( name ) ) { + return null; + } + + if ( name.startsWith( "[" ) ) { + // always handle arrays via the JDK builder + 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; + } + + if ( "char".equals( className ) ) { + return char.class; + } + + if ( Character.class.getSimpleName().equals( className ) || Character.class.getName().equals( className ) ) { + return Character.class; + } + + return null; + } + + public static MethodDetails buildMethodDetails( + MethodDescription.InDefinedShape method, + ClassDetailsImpl declaringType, + ByteBuddyModelsContext 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, + ByteBuddyModelContextImpl 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, + ByteBuddyModelContextImpl 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..b781797 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/RecordComponentDetailsImpl.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.bytebuddy.spi.ByteBuddyModelsContext; +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, + ByteBuddyModelsContext 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/TypeSwitchStandard.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/TypeSwitchStandard.java new file mode 100644 index 0000000..dcead71 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/TypeSwitchStandard.java @@ -0,0 +1,187 @@ +/* + * 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.HashSet; +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 ( isExtends( upperBounds, lowerBounds ) ) { + bound = upperBounds; + isExtends = true; + } + else { + bound = lowerBounds; + isExtends = false; + } + + 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, + resolveTypes( typeDescription.asGenericType().getUpperBounds(), this, buildingContext ) + ); + } + + @Override + 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() ); + } + + @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..2b1e911 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ArrayValueConverter.java @@ -0,0 +1,200 @@ +/* + * 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.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; + +/** + * 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 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 ); + } + + if ( Short.class == elementValueType ) { + return convertShortArray( annotationValue, modelContext ); + } + + if ( Integer.class == elementValueType ) { + return convertIntArray( annotationValue, modelContext ); + } + + if ( Long.class == elementValueType ) { + return convertLongArray( annotationValue, modelContext ); + } + + if ( double.class == elementValueType ) { + return convertDoubleArray( annotationValue, modelContext ); + } + + if ( float.class == elementValueType ) { + return convertFloatArray( annotationValue, modelContext ); + } + + 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 V[] convertBooleanArray( + AnnotationValue annotationValue, + SourceModelBuildingContext modelContext) { + 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]; + } + //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 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 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; + } + + 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]; + } + //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 new file mode 100644 index 0000000..0984caf --- /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..7d3be97 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/ClassValueConverter.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 net.bytebuddy.description.annotation.AnnotationValue; +import net.bytebuddy.description.type.TypeDescription; + + +/** + * 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) { + 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/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..2f2ecf1 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/internal/values/NestedValueConverter.java @@ -0,0 +1,35 @@ +/* + * 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.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; + +/** + * 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) { + 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/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/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/ByteBuddyModelsContext.java b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyModelsContext.java new file mode 100644 index 0000000..f51c479 --- /dev/null +++ b/hibernate-models-bytebuddy/src/main/java/org/hibernate/models/bytebuddy/spi/ByteBuddyModelsContext.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 ByteBuddyModelsContext 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/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/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..f4337f6 --- /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.bytebuddy.spi.ByteBuddyModelsContext; +import org.hibernate.models.spi.ClassLoading; +import org.hibernate.models.spi.RegistryPrimer; +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 ByteBuddyModelsContext 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/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/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/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/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/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/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-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 ); + } +} 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); 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'