From 187060882648169d2afe3054b633da4c19334a59 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Mon, 22 Jan 2024 15:36:28 -0600 Subject: [PATCH] #20 - Add AnnotationUsage#toAnnotation --- .../models/internal/AnnotationProxy.java | 50 +++++++++++++++++++ .../models/internal/ArrayTypeDescriptor.java | 9 ++++ .../internal/BooleanTypeDescriptor.java | 5 ++ .../models/internal/ByteTypeDescriptor.java | 5 ++ .../internal/CharacterTypeDescriptor.java | 5 ++ .../models/internal/ClassTypeDescriptor.java | 5 ++ .../models/internal/DoubleTypeDescriptor.java | 5 ++ .../models/internal/EnumTypeDescriptor.java | 5 ++ .../models/internal/FloatTypeDescriptor.java | 5 ++ .../internal/IntegerTypeDescriptor.java | 5 ++ .../models/internal/LongTypeDescriptor.java | 5 ++ .../models/internal/NestedTypeDescriptor.java | 5 ++ .../models/internal/ShortTypeDescriptor.java | 5 ++ .../models/internal/StringTypeDescriptor.java | 5 ++ .../dynamic/DynamicAnnotationUsage.java | 6 +++ .../jandex/JandexAnnotationUsage.java | 6 +++ .../internal/jdk/JdkAnnotationUsage.java | 7 +++ .../hibernate/models/spi/AnnotationUsage.java | 5 ++ .../models/spi/ValueTypeDescriptor.java | 2 + .../annotations/AnnotationUsageTests.java | 38 ++++++++++++++ 20 files changed, 183 insertions(+) create mode 100644 src/main/java/org/hibernate/models/internal/AnnotationProxy.java diff --git a/src/main/java/org/hibernate/models/internal/AnnotationProxy.java b/src/main/java/org/hibernate/models/internal/AnnotationProxy.java new file mode 100644 index 0000000..3217fad --- /dev/null +++ b/src/main/java/org/hibernate/models/internal/AnnotationProxy.java @@ -0,0 +1,50 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ + +package org.hibernate.models.internal; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Map; + +import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.AttributeDescriptor; + +/** + * @author Steve Ebersole + */ +public class AnnotationProxy implements InvocationHandler { + private final AnnotationDescriptor annotationDescriptor; + private final Map valueMap; + + public AnnotationProxy(AnnotationDescriptor annotationDescriptor, Map valueMap) { + this.annotationDescriptor = annotationDescriptor; + this.valueMap = valueMap; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) { + final AttributeDescriptor attributeDescriptor = annotationDescriptor.getAttribute( method.getName() ); + return attributeDescriptor.getTypeDescriptor().unwrap( valueMap.get( method.getName() ) ); + } + + + public static A makeProxy( + AnnotationDescriptor descriptor, + Map valueMap) { + final AnnotationProxy handler = new AnnotationProxy<>( descriptor, valueMap ); + //noinspection unchecked + return (A) Proxy.newProxyInstance( + AnnotationProxy.class.getClassLoader(), + new Class[] { descriptor.getAnnotationType() }, + handler + ); + } + +} diff --git a/src/main/java/org/hibernate/models/internal/ArrayTypeDescriptor.java b/src/main/java/org/hibernate/models/internal/ArrayTypeDescriptor.java index c526611..00ec197 100644 --- a/src/main/java/org/hibernate/models/internal/ArrayTypeDescriptor.java +++ b/src/main/java/org/hibernate/models/internal/ArrayTypeDescriptor.java @@ -120,4 +120,13 @@ public ValueWrapper,Object[]> resolveJkWrapper(SourceModelBuildingContex } return jdkValueWrapper; } + + @Override + public Object unwrap(List value) { + final Object[] result = new Object[value.size()]; + for ( int i = 0; i < value.size(); i++ ) { + result[i] = elementTypeDescriptor.unwrap( value.get(i) ); + } + return result; + } } diff --git a/src/main/java/org/hibernate/models/internal/BooleanTypeDescriptor.java b/src/main/java/org/hibernate/models/internal/BooleanTypeDescriptor.java index cbfe59d..8551b37 100644 --- a/src/main/java/org/hibernate/models/internal/BooleanTypeDescriptor.java +++ b/src/main/java/org/hibernate/models/internal/BooleanTypeDescriptor.java @@ -54,4 +54,9 @@ public ValueExtractor createJdkExtractor(SourceModelBuildin //noinspection unchecked return PassThruExtractor.PASS_THRU_EXTRACTOR; } + + @Override + public Object unwrap(Boolean value) { + return value; + } } diff --git a/src/main/java/org/hibernate/models/internal/ByteTypeDescriptor.java b/src/main/java/org/hibernate/models/internal/ByteTypeDescriptor.java index a3d3334..9cb673f 100644 --- a/src/main/java/org/hibernate/models/internal/ByteTypeDescriptor.java +++ b/src/main/java/org/hibernate/models/internal/ByteTypeDescriptor.java @@ -54,4 +54,9 @@ public ValueExtractor createJdkExtractor(SourceModelBuildingCo //noinspection unchecked return PassThruExtractor.PASS_THRU_EXTRACTOR; } + + @Override + public Object unwrap(Byte value) { + return value; + } } diff --git a/src/main/java/org/hibernate/models/internal/CharacterTypeDescriptor.java b/src/main/java/org/hibernate/models/internal/CharacterTypeDescriptor.java index 5a6af7d..54c003d 100644 --- a/src/main/java/org/hibernate/models/internal/CharacterTypeDescriptor.java +++ b/src/main/java/org/hibernate/models/internal/CharacterTypeDescriptor.java @@ -54,4 +54,9 @@ public ValueExtractor createJdkExtractor(SourceModelBuild //noinspection unchecked return PassThruExtractor.PASS_THRU_EXTRACTOR; } + + @Override + public Object unwrap(Character value) { + return value; + } } diff --git a/src/main/java/org/hibernate/models/internal/ClassTypeDescriptor.java b/src/main/java/org/hibernate/models/internal/ClassTypeDescriptor.java index 2435016..873f976 100644 --- a/src/main/java/org/hibernate/models/internal/ClassTypeDescriptor.java +++ b/src/main/java/org/hibernate/models/internal/ClassTypeDescriptor.java @@ -50,4 +50,9 @@ public ValueExtractor createJandexExtractor(So public ValueExtractor createJdkExtractor(SourceModelBuildingContext buildingContext) { return org.hibernate.models.internal.jdk.ClassValueExtractor.JDK_CLASS_EXTRACTOR; } + + @Override + public Object unwrap(ClassDetails value) { + return value.toJavaClass(); + } } diff --git a/src/main/java/org/hibernate/models/internal/DoubleTypeDescriptor.java b/src/main/java/org/hibernate/models/internal/DoubleTypeDescriptor.java index b9970c7..546652b 100644 --- a/src/main/java/org/hibernate/models/internal/DoubleTypeDescriptor.java +++ b/src/main/java/org/hibernate/models/internal/DoubleTypeDescriptor.java @@ -54,4 +54,9 @@ public ValueExtractor createJdkExtractor(SourceModelBuilding //noinspection unchecked return PassThruExtractor.PASS_THRU_EXTRACTOR; } + + @Override + public Object unwrap(Double value) { + return value; + } } diff --git a/src/main/java/org/hibernate/models/internal/EnumTypeDescriptor.java b/src/main/java/org/hibernate/models/internal/EnumTypeDescriptor.java index 5ff497e..9827da8 100644 --- a/src/main/java/org/hibernate/models/internal/EnumTypeDescriptor.java +++ b/src/main/java/org/hibernate/models/internal/EnumTypeDescriptor.java @@ -63,4 +63,9 @@ public ValueExtractor createJdkExtractor(SourceModelBuildingConte //noinspection unchecked return PassThruExtractor.PASS_THRU_EXTRACTOR; } + + @Override + public Object unwrap(E value) { + return value; + } } diff --git a/src/main/java/org/hibernate/models/internal/FloatTypeDescriptor.java b/src/main/java/org/hibernate/models/internal/FloatTypeDescriptor.java index 9244c9d..b007d8d 100644 --- a/src/main/java/org/hibernate/models/internal/FloatTypeDescriptor.java +++ b/src/main/java/org/hibernate/models/internal/FloatTypeDescriptor.java @@ -54,4 +54,9 @@ public ValueExtractor createJdkExtractor(SourceModelBuildingC //noinspection unchecked return PassThruExtractor.PASS_THRU_EXTRACTOR; } + + @Override + public Object unwrap(Float value) { + return value; + } } diff --git a/src/main/java/org/hibernate/models/internal/IntegerTypeDescriptor.java b/src/main/java/org/hibernate/models/internal/IntegerTypeDescriptor.java index 01e89f5..4dcc545 100644 --- a/src/main/java/org/hibernate/models/internal/IntegerTypeDescriptor.java +++ b/src/main/java/org/hibernate/models/internal/IntegerTypeDescriptor.java @@ -54,4 +54,9 @@ public ValueExtractor createJdkExtractor(SourceModelBuildin //noinspection unchecked return PassThruExtractor.PASS_THRU_EXTRACTOR; } + + @Override + public Object unwrap(Integer value) { + return value; + } } diff --git a/src/main/java/org/hibernate/models/internal/LongTypeDescriptor.java b/src/main/java/org/hibernate/models/internal/LongTypeDescriptor.java index be0b8a1..f0ef170 100644 --- a/src/main/java/org/hibernate/models/internal/LongTypeDescriptor.java +++ b/src/main/java/org/hibernate/models/internal/LongTypeDescriptor.java @@ -54,4 +54,9 @@ public ValueExtractor createJdkExtractor(SourceModelBuildingCo //noinspection unchecked return PassThruExtractor.PASS_THRU_EXTRACTOR; } + + @Override + public Object unwrap(Long value) { + return value; + } } diff --git a/src/main/java/org/hibernate/models/internal/NestedTypeDescriptor.java b/src/main/java/org/hibernate/models/internal/NestedTypeDescriptor.java index ab114bb..44b6f5e 100644 --- a/src/main/java/org/hibernate/models/internal/NestedTypeDescriptor.java +++ b/src/main/java/org/hibernate/models/internal/NestedTypeDescriptor.java @@ -97,6 +97,11 @@ public ValueExtractor> createJdkExtractor(SourceM return resolveJdkExtractor( buildingContext ); } + @Override + public Object unwrap(AnnotationUsage value) { + return value.toAnnotation(); + } + public ValueExtractor> resolveJdkExtractor(SourceModelBuildingContext buildingContext) { if ( jdkExtractor == null ) { jdkExtractor = new org.hibernate.models.internal.jdk.NestedValueExtractor<>( resolveJdkWrapper( buildingContext ) ); diff --git a/src/main/java/org/hibernate/models/internal/ShortTypeDescriptor.java b/src/main/java/org/hibernate/models/internal/ShortTypeDescriptor.java index 018c36a..2da8501 100644 --- a/src/main/java/org/hibernate/models/internal/ShortTypeDescriptor.java +++ b/src/main/java/org/hibernate/models/internal/ShortTypeDescriptor.java @@ -54,4 +54,9 @@ public ValueExtractor createJdkExtractor(SourceModelBuildingC //noinspection unchecked return PassThruExtractor.PASS_THRU_EXTRACTOR; } + + @Override + public Object unwrap(Short value) { + return value; + } } diff --git a/src/main/java/org/hibernate/models/internal/StringTypeDescriptor.java b/src/main/java/org/hibernate/models/internal/StringTypeDescriptor.java index 1b0837c..dabc2f2 100644 --- a/src/main/java/org/hibernate/models/internal/StringTypeDescriptor.java +++ b/src/main/java/org/hibernate/models/internal/StringTypeDescriptor.java @@ -54,4 +54,9 @@ public ValueExtractor createJdkExtractor(SourceModelBuilding //noinspection unchecked return PassThruExtractor.PASS_THRU_EXTRACTOR; } + + @Override + public Object unwrap(String value) { + return value; + } } diff --git a/src/main/java/org/hibernate/models/internal/dynamic/DynamicAnnotationUsage.java b/src/main/java/org/hibernate/models/internal/dynamic/DynamicAnnotationUsage.java index 4092fd7..d53799d 100644 --- a/src/main/java/org/hibernate/models/internal/dynamic/DynamicAnnotationUsage.java +++ b/src/main/java/org/hibernate/models/internal/dynamic/DynamicAnnotationUsage.java @@ -12,6 +12,7 @@ import java.util.Map; import org.hibernate.models.UnknownAnnotationAttributeException; +import org.hibernate.models.internal.AnnotationProxy; import org.hibernate.models.spi.MutableAnnotationUsage; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.AnnotationTarget; @@ -44,6 +45,11 @@ public AnnotationTarget getAnnotationTarget() { return target; } + @Override + public A toAnnotation() { + return AnnotationProxy.makeProxy( annotationDescriptor, values ); + } + @Override public V findAttributeValue(String name) { if ( values != null ) { diff --git a/src/main/java/org/hibernate/models/internal/jandex/JandexAnnotationUsage.java b/src/main/java/org/hibernate/models/internal/jandex/JandexAnnotationUsage.java index c1fae7b..45a4602 100644 --- a/src/main/java/org/hibernate/models/internal/jandex/JandexAnnotationUsage.java +++ b/src/main/java/org/hibernate/models/internal/jandex/JandexAnnotationUsage.java @@ -9,6 +9,7 @@ import java.lang.annotation.Annotation; import java.util.Map; +import org.hibernate.models.internal.AnnotationProxy; import org.hibernate.models.spi.MutableAnnotationUsage; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.AnnotationTarget; @@ -56,6 +57,11 @@ public AnnotationTarget getAnnotationTarget() { return annotationTarget; } + @Override + public A toAnnotation() { + return AnnotationProxy.makeProxy( annotationDescriptor, attributeValueMap ); + } + @Override public W findAttributeValue(String name) { //noinspection unchecked diff --git a/src/main/java/org/hibernate/models/internal/jdk/JdkAnnotationUsage.java b/src/main/java/org/hibernate/models/internal/jdk/JdkAnnotationUsage.java index 848acd2..018caf4 100644 --- a/src/main/java/org/hibernate/models/internal/jdk/JdkAnnotationUsage.java +++ b/src/main/java/org/hibernate/models/internal/jdk/JdkAnnotationUsage.java @@ -18,6 +18,7 @@ * @author Steve Ebersole */ public class JdkAnnotationUsage implements MutableAnnotationUsage { + private final A annotation; private final AnnotationDescriptor annotationDescriptor; private final AnnotationTarget location; @@ -28,6 +29,7 @@ public JdkAnnotationUsage( AnnotationDescriptor annotationDescriptor, AnnotationTarget location, SourceModelBuildingContext buildingContext) { + this.annotation = annotation; this.annotationDescriptor = annotationDescriptor; this.location = location; @@ -44,6 +46,11 @@ public AnnotationTarget getAnnotationTarget() { return location; } + @Override + public A toAnnotation() { + return annotation; + } + @Override public W findAttributeValue(String name) { //noinspection unchecked diff --git a/src/main/java/org/hibernate/models/spi/AnnotationUsage.java b/src/main/java/org/hibernate/models/spi/AnnotationUsage.java index b512898..8844077 100644 --- a/src/main/java/org/hibernate/models/spi/AnnotationUsage.java +++ b/src/main/java/org/hibernate/models/spi/AnnotationUsage.java @@ -53,6 +53,11 @@ default Class getAnnotationType() { */ AnnotationTarget getAnnotationTarget(); + /** + * Create the Annotation representation of this usage + */ + A toAnnotation(); + /** * The value of the named annotation attribute */ diff --git a/src/main/java/org/hibernate/models/spi/ValueTypeDescriptor.java b/src/main/java/org/hibernate/models/spi/ValueTypeDescriptor.java index db3328f..6976efe 100644 --- a/src/main/java/org/hibernate/models/spi/ValueTypeDescriptor.java +++ b/src/main/java/org/hibernate/models/spi/ValueTypeDescriptor.java @@ -40,4 +40,6 @@ public interface ValueTypeDescriptor { ValueWrapper createJdkWrapper(SourceModelBuildingContext buildingContext); ValueExtractor createJdkExtractor(SourceModelBuildingContext buildingContext); + + Object unwrap(V value); } diff --git a/src/test/java/org/hibernate/models/annotations/AnnotationUsageTests.java b/src/test/java/org/hibernate/models/annotations/AnnotationUsageTests.java index 3eca4e4..a616e8b 100644 --- a/src/test/java/org/hibernate/models/annotations/AnnotationUsageTests.java +++ b/src/test/java/org/hibernate/models/annotations/AnnotationUsageTests.java @@ -224,4 +224,42 @@ void badAttributeNamesChecks(Index index) { catch (UnknownAnnotationAttributeException expected) { } } + + @Test + void testToAnnotationJandex() { + toAnnotationChecks( buildJandexIndex( SimpleEntity.class ) ); + } + + @Test + void testToAnnotationWithoutJandex() { + toAnnotationChecks( null ); + } + + private void toAnnotationChecks(Index index) { + final SourceModelBuildingContextImpl buildingContext = createBuildingContext( index, SimpleEntity.class ); + final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry(); + + final ClassDetails classDetails = classDetailsRegistry.getClassDetails( SimpleEntity.class.getName() ); + + { + final AnnotationUsage annotationUsage = classDetails.getAnnotationUsage( CustomAnnotation.class ); + final CustomAnnotation annotation = annotationUsage.toAnnotation(); + assertThat( annotation ).isNotNull(); + } + + { + final AnnotationUsage annotationUsage = classDetails.getAnnotationUsage( Entity.class ); + final Entity annotation = annotationUsage.toAnnotation(); + assertThat( annotation.name() ).isEqualTo( "SimpleColumnEntity" ); + } + + { + final AnnotationUsage annotationUsage = classDetails.findFieldByName( "name" ).getAnnotationUsage( Column.class ); + final Column annotation = annotationUsage.toAnnotation(); + assertThat( annotation.name() ).isEqualTo( "description" ); + assertThat( annotation.table() ).isEqualTo( "" ); + assertThat( annotation.nullable() ).isFalse(); + assertThat( annotation.unique() ).isTrue(); + } + } }