From ff701d1e1ae71bdf4d7a25a394f12349d14c3161 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Mon, 14 Oct 2024 16:53:48 -0500 Subject: [PATCH] #87 - Make sure models are serializable --- .../JandexAnnotationDescriptorRegistry.java | 5 + .../jandex/internal/JandexClassDetails.java | 9 +- .../internal/JandexClassDetailsRegistry.java | 6 + .../JandexModelBuildingContextImpl.java | 7 + .../SimpleSerializationTests.java | 141 ++++++++++++++++++ .../hibernate/models/SerializationHelper.java | 4 +- .../AbstractAnnotationDescriptorRegistry.java | 4 +- .../AnnotationDescriptorRegistryStandard.java | 20 --- .../BasicModelBuildingContextImpl.java | 33 +--- .../ClassDetailsRegistryStandard.java | 22 --- .../internal/MissingPackageInfoDetails.java | 17 ++- .../models/internal/SerialCassDetails.java | 11 -- .../hibernate/models/internal/SerialForm.java | 14 -- .../models/internal/SimpleClassDetails.java | 7 +- .../internal/dynamic/DynamicClassDetails.java | 4 +- .../dynamic/SerialDynamicClassDetails.java | 17 --- .../models/internal/jdk/JdkClassDetails.java | 12 +- ...etails.java => SerialJdkClassDetails.java} | 25 ++-- .../internal/util/CollectionHelper.java | 29 ++++ .../internal/ClassDetailsBuilderImpl.java | 35 +++++ .../serial/internal/RestoredModelContext.java | 80 ++++++++++ .../SerialAnnotationDescriptorImpl.java} | 14 +- .../serial/internal/StorableContextImpl.java | 56 +++++++ .../hibernate/models/serial/package-info.java | 11 ++ .../spi/SerialAnnotationDescriptor.java | 16 ++ .../models/serial/spi/SerialClassDetails.java | 16 ++ .../hibernate/models/serial/spi/Storable.java | 16 ++ .../models/serial/spi/StorableContext.java | 25 ++++ .../models/serial/spi/StorableForm.java | 19 +++ .../models/spi/AnnotationDescriptor.java | 11 +- .../hibernate/models/spi/ClassDetails.java | 6 +- .../spi/SourceModelBuildingContext.java | 4 + .../models/spi/SourceModelContext.java | 4 +- .../org/hibernate/models/spi/Storable.java | 14 -- .../models/SimpleSerializationTests.java | 54 ++++--- .../models/SourceModelTestHelper.java | 1 - 36 files changed, 572 insertions(+), 197 deletions(-) create mode 100644 hibernate-models-jandex/src/test/java/org/hibernate/models/serialization/SimpleSerializationTests.java delete mode 100644 hibernate-models/src/main/java/org/hibernate/models/internal/SerialCassDetails.java delete mode 100644 hibernate-models/src/main/java/org/hibernate/models/internal/SerialForm.java delete mode 100644 hibernate-models/src/main/java/org/hibernate/models/internal/dynamic/SerialDynamicClassDetails.java rename hibernate-models/src/main/java/org/hibernate/models/internal/jdk/{SerialJdkCassDetails.java => SerialJdkClassDetails.java} (50%) create mode 100644 hibernate-models/src/main/java/org/hibernate/models/serial/internal/ClassDetailsBuilderImpl.java create mode 100644 hibernate-models/src/main/java/org/hibernate/models/serial/internal/RestoredModelContext.java rename hibernate-models/src/main/java/org/hibernate/models/{internal/SerialAnnotationDescriptor.java => serial/internal/SerialAnnotationDescriptorImpl.java} (50%) create mode 100644 hibernate-models/src/main/java/org/hibernate/models/serial/internal/StorableContextImpl.java create mode 100644 hibernate-models/src/main/java/org/hibernate/models/serial/package-info.java create mode 100644 hibernate-models/src/main/java/org/hibernate/models/serial/spi/SerialAnnotationDescriptor.java create mode 100644 hibernate-models/src/main/java/org/hibernate/models/serial/spi/SerialClassDetails.java create mode 100644 hibernate-models/src/main/java/org/hibernate/models/serial/spi/Storable.java create mode 100644 hibernate-models/src/main/java/org/hibernate/models/serial/spi/StorableContext.java create mode 100644 hibernate-models/src/main/java/org/hibernate/models/serial/spi/StorableForm.java delete mode 100644 hibernate-models/src/main/java/org/hibernate/models/spi/Storable.java diff --git a/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexAnnotationDescriptorRegistry.java b/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexAnnotationDescriptorRegistry.java index 468a132..7a51226 100644 --- a/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexAnnotationDescriptorRegistry.java +++ b/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexAnnotationDescriptorRegistry.java @@ -5,6 +5,7 @@ package org.hibernate.models.jandex.internal; import java.lang.annotation.Annotation; +import java.util.Map; import org.hibernate.models.internal.AnnotationDescriptorRegistryStandard; import org.hibernate.models.spi.AnnotationDescriptor; @@ -24,4 +25,8 @@ protected AnnotationDescriptor buildAnnotationDescript AnnotationDescriptor containerDescriptor) { return new JandexAnnotationDescriptorImpl<>( javaType, containerDescriptor, getModelBuildingContext() ); } + + public Map, AnnotationDescriptor> getDescriptorMap() { + return descriptorMap; + } } diff --git a/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexClassDetails.java b/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexClassDetails.java index 5f53ed1..990cca4 100644 --- a/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexClassDetails.java +++ b/hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexClassDetails.java @@ -9,9 +9,9 @@ import java.util.List; import org.hibernate.models.internal.ClassDetailsSupport; -import org.hibernate.models.internal.SerialCassDetails; -import org.hibernate.models.internal.jdk.SerialJdkCassDetails; +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; @@ -280,8 +280,7 @@ private static List determineTypeParameters(ClassInfo class } @Override - public SerialCassDetails toSerialForm(SourceModelBuildingContext context) { - final Class classForName = context.getClassLoading().classForName( getClassName() ); - return new SerialJdkCassDetails( classForName.getName(), classForName ); + public SerialClassDetails toStorableForm() { + return new SerialJdkClassDetails( getName(), toJavaClass() ); } } 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 5f94013..0704b69 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 @@ -4,6 +4,8 @@ */ package org.hibernate.models.jandex.internal; +import java.util.Map; + import org.hibernate.models.UnknownClassException; import org.hibernate.models.internal.AbstractClassDetailsRegistry; import org.hibernate.models.internal.jdk.JdkBuilders; @@ -50,4 +52,8 @@ protected ClassDetails createClassDetails(String name) { throw new UnknownClassException( "Unable to resolve ClassDetails for `" + name + "`" ); } + + protected Map getClassDetailsMap() { + return classDetailsMap; + } } 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 fa4b8b1..677e657 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 @@ -13,6 +13,8 @@ import org.hibernate.models.jandex.spi.JandexModelBuildingContext; import org.hibernate.models.jandex.spi.JandexValueConverter; import org.hibernate.models.jandex.spi.JandexValueExtractor; +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; @@ -98,4 +100,9 @@ public JandexValueExtractor getJandexValueExtractor(ValueTypeDescriptor... classes) { + return SourceModelTestHelper.createBuildingContext( classes ); + } + + @Test + void serializeSimpleClass() { + final SourceModelBuildingContext buildingContext = createModelContext( SimpleClass.class ); + + final ClassDetails classDetails = buildingContext.getClassDetailsRegistry().findClassDetails( SimpleClass.class.getName() ); + assertThat( classDetails ).isNotNull(); + + final StorableContext serialContext = buildingContext.toStorableForm(); + final StorableContext clonedSerialContext = SerializationHelper.clone( serialContext ); + assertThat( serialContext ).isNotSameAs( clonedSerialContext ); + + final SourceModelContext restored = clonedSerialContext.fromStorableForm( SIMPLE_CLASS_LOADING ); + assertThat( buildingContext ).isNotSameAs( restored ); + assertThat( buildingContext.getClassDetailsRegistry() ).isNotSameAs( restored.getClassDetailsRegistry() ); + assertThat( buildingContext.getAnnotationDescriptorRegistry() ).isNotSameAs( restored.getAnnotationDescriptorRegistry() ); + + final ClassDetails cloneCassDetails = restored.getClassDetailsRegistry().findClassDetails( SimpleClass.class.getName() ); + assertThat( cloneCassDetails ).isNotNull(); + assertThat( classDetails ).isNotSameAs( cloneCassDetails ); + } + + @Test + void serializeSimpleClassWithMembers() { + final SourceModelBuildingContext buildingContext = createModelContext( SimpleClassWithMembers.class ); + + final ClassDetails classDetails = buildingContext.getClassDetailsRegistry().findClassDetails( SimpleClassWithMembers.class.getName() ); + assertThat( classDetails ).isNotNull(); + assertThat( classDetails.getFields() ).hasSize( 1 ); + assertThat( classDetails.getMethods() ).hasSize( 3 ); + + final StorableContext serialContext = buildingContext.toStorableForm(); + final StorableContext clonedSerialContext = SerializationHelper.clone( serialContext ); + assertThat( serialContext ).isNotSameAs( clonedSerialContext ); + + final SourceModelContext restored = clonedSerialContext.fromStorableForm( SIMPLE_CLASS_LOADING ); + assertThat( buildingContext ).isNotSameAs( restored ); + assertThat( buildingContext.getClassDetailsRegistry() ).isNotSameAs( restored.getClassDetailsRegistry() ); + assertThat( buildingContext.getAnnotationDescriptorRegistry() ).isNotSameAs( restored.getAnnotationDescriptorRegistry() ); + + final ClassDetails cloneCassDetails = restored.getClassDetailsRegistry().findClassDetails( SimpleClassWithMembers.class.getName() ); + assertThat( cloneCassDetails ).isNotNull(); + assertThat( classDetails ).isNotSameAs( cloneCassDetails ); + assertThat( cloneCassDetails.getFields() ).hasSize( 1 ); + assertThat( cloneCassDetails.getMethods() ).hasSize( 3 ); + } + + @Test + void serializeSimpleClassWithAnnotations() { + final SourceModelBuildingContext buildingContext = createModelContext( SimpleClassWithAnnotations.class ); + + final ClassDetails classDetails = buildingContext.getClassDetailsRegistry().findClassDetails( SimpleClassWithAnnotations.class.getName() ); + assertThat( classDetails ).isNotNull(); + assertThat( classDetails.getDirectAnnotationUsages() ).hasSize( 1 ); + assertThat( classDetails.getFields() ).hasSize( 1 ); + assertThat( classDetails.getFields().iterator().next().getDirectAnnotationUsages() ).hasSize( 1 ); + assertThat( classDetails.getMethods() ).hasSize( 1 ); + assertThat( classDetails.getMethods().iterator().next().getDirectAnnotationUsages() ).hasSize( 1 ); + + final StorableContext serialContext = buildingContext.toStorableForm(); + final StorableContext clonedSerialContext = SerializationHelper.clone( serialContext ); + assertThat( serialContext ).isNotSameAs( clonedSerialContext ); + + final SourceModelContext restored = clonedSerialContext.fromStorableForm( SIMPLE_CLASS_LOADING ); + assertThat( restored ).isNotNull(); + assertThat( buildingContext ).isNotSameAs( restored ); + assertThat( buildingContext.getClassDetailsRegistry() ).isNotSameAs( restored.getClassDetailsRegistry() ); + assertThat( buildingContext.getAnnotationDescriptorRegistry() ).isNotSameAs( restored.getAnnotationDescriptorRegistry() ); + + final ClassDetails cloneCassDetails = restored.getClassDetailsRegistry().findClassDetails( SimpleClassWithAnnotations.class.getName() ); + assertThat( classDetails ).isNotSameAs( cloneCassDetails ); + assertThat( cloneCassDetails.getDirectAnnotationUsages() ).hasSize( 1 ); + assertThat( cloneCassDetails.getFields() ).hasSize( 1 ); + assertThat( cloneCassDetails.getFields().iterator().next().getDirectAnnotationUsages() ).hasSize( 1 ); + assertThat( cloneCassDetails.getMethods() ).hasSize( 1 ); + assertThat( cloneCassDetails.getMethods().iterator().next().getDirectAnnotationUsages() ).hasSize( 1 ); + + } + + public static class SimpleClass { + } + + public static class SimpleClassWithMembers { + public int anInt; + + public int getAnInt() { + return anInt; + } + + public void setAnInt(int anInt) { + this.anInt = anInt; + } + + public void doStuff() { + } + } + + @Target({ ElementType.FIELD,ElementType.METHOD,ElementType.TYPE}) + @Retention(RetentionPolicy.RUNTIME) + public @interface AnAnnotation { + } + + @AnAnnotation + public static class SimpleClassWithAnnotations { + @AnAnnotation + private int anInt; + + @AnAnnotation + public int getAnInt() { + return anInt; + } + + } +} diff --git a/hibernate-models-testing/src/main/java/org/hibernate/models/SerializationHelper.java b/hibernate-models-testing/src/main/java/org/hibernate/models/SerializationHelper.java index 6b60df7..f42de4c 100644 --- a/hibernate-models-testing/src/main/java/org/hibernate/models/SerializationHelper.java +++ b/hibernate-models-testing/src/main/java/org/hibernate/models/SerializationHelper.java @@ -1,6 +1,6 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors */ package org.hibernate.models; diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/AbstractAnnotationDescriptorRegistry.java b/hibernate-models/src/main/java/org/hibernate/models/internal/AbstractAnnotationDescriptorRegistry.java index 975a0ed..d6e4179 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/AbstractAnnotationDescriptorRegistry.java +++ b/hibernate-models/src/main/java/org/hibernate/models/internal/AbstractAnnotationDescriptorRegistry.java @@ -16,8 +16,8 @@ * @author Steve Ebersole */ public abstract class AbstractAnnotationDescriptorRegistry implements AnnotationDescriptorRegistry { - protected final Map, AnnotationDescriptor> descriptorMap; - protected final Map, AnnotationDescriptor> repeatableByContainerMap; + protected final Map, AnnotationDescriptor> descriptorMap; + protected final Map, AnnotationDescriptor> repeatableByContainerMap; public AbstractAnnotationDescriptorRegistry() { this( new ConcurrentHashMap<>(), new ConcurrentHashMap<>() ); diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/AnnotationDescriptorRegistryStandard.java b/hibernate-models/src/main/java/org/hibernate/models/internal/AnnotationDescriptorRegistryStandard.java index 76c66dc..1efdc81 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/AnnotationDescriptorRegistryStandard.java +++ b/hibernate-models/src/main/java/org/hibernate/models/internal/AnnotationDescriptorRegistryStandard.java @@ -4,12 +4,8 @@ */ package org.hibernate.models.internal; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.lang.annotation.Annotation; import java.lang.annotation.Repeatable; -import java.util.Map; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.SourceModelBuildingContext; @@ -89,20 +85,4 @@ protected AnnotationDescriptor buildAnnotationDescript modelBuildingContext ); } - - public void serialize(ObjectOutputStream outputStream, BasicModelBuildingContextImpl context) throws IOException { - outputStream.writeInt( descriptorMap.size() ); - for ( Map.Entry, AnnotationDescriptor> entry : descriptorMap.entrySet() ) { - outputStream.writeObject( entry.getValue().toSerialForm( context ) ); - } - } - - public void deserialize(ObjectInputStream inputStream, SourceModelBuildingContext context) throws IOException, ClassNotFoundException { - final int count = inputStream.readInt(); - for ( int i = 0; i < count; i++ ) { - final SerialAnnotationDescriptor serialForm = (SerialAnnotationDescriptor) inputStream.readObject(); - register( serialForm.fromSerialForm( context ) ); - } - } - } diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/BasicModelBuildingContextImpl.java b/hibernate-models/src/main/java/org/hibernate/models/internal/BasicModelBuildingContextImpl.java index ff3d7fb..d3a24f2 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/BasicModelBuildingContextImpl.java +++ b/hibernate-models/src/main/java/org/hibernate/models/internal/BasicModelBuildingContextImpl.java @@ -4,12 +4,8 @@ */ package org.hibernate.models.internal; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serial; - -import org.hibernate.models.spi.ClassDetailsBuilder; +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; @@ -19,8 +15,8 @@ * @author Steve Ebersole */ public class BasicModelBuildingContextImpl extends AbstractModelBuildingContext { - private transient AnnotationDescriptorRegistryStandard descriptorRegistry; - private transient ClassDetailsRegistryStandard classDetailsRegistry; + private final AnnotationDescriptorRegistryStandard descriptorRegistry; + private final ClassDetailsRegistryStandard classDetailsRegistry; public BasicModelBuildingContextImpl(ClassLoading classLoadingAccess) { this( classLoadingAccess, null ); @@ -45,23 +41,8 @@ public MutableClassDetailsRegistry getClassDetailsRegistry() { return classDetailsRegistry; } - @Serial - private void writeObject(ObjectOutputStream outputStream) throws IOException { - outputStream.writeObject( classDetailsRegistry.getClassDetailsBuilder() ); - - descriptorRegistry.serialize( outputStream, this ); - classDetailsRegistry.serialize( outputStream, this ); - - outputStream.flush(); - } - - - @Serial - private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { - descriptorRegistry = new AnnotationDescriptorRegistryStandard( this ); - classDetailsRegistry = new ClassDetailsRegistryStandard( (ClassDetailsBuilder) inputStream.readObject(), this ); - - descriptorRegistry.deserialize( inputStream, this ); - classDetailsRegistry.deserialize( inputStream, this ); + @Override + public StorableContext toStorableForm() { + return new StorableContextImpl( classDetailsRegistry.classDetailsMap, descriptorRegistry.descriptorMap ); } } 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 88a6b27..27a3ecb 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 @@ -5,11 +5,6 @@ package org.hibernate.models.internal; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.Map; - import org.hibernate.models.internal.jdk.JdkBuilders; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetailsBuilder; @@ -42,21 +37,4 @@ public ClassDetailsRegistryStandard(ClassDetailsBuilder classDetailsBuilder, Sou protected ClassDetailsBuilder getClassDetailsBuilder() { return classDetailsBuilder; } - - public void serialize(ObjectOutputStream outputStream, SourceModelBuildingContext context) throws IOException { - outputStream.writeInt( classDetailsMap.size() ); - for ( Map.Entry entry : classDetailsMap.entrySet() ) { - outputStream.writeUTF( entry.getKey() ); - outputStream.writeObject( entry.getValue().toSerialForm( context ) ); - } - } - - public void deserialize(ObjectInputStream inputStream, SourceModelBuildingContext context) throws IOException, ClassNotFoundException { - final int count = inputStream.readInt(); - for ( int i = 0; i < count; i++ ) { - final String registrationName = inputStream.readUTF(); - final SerialCassDetails serialForm = (SerialCassDetails) inputStream.readObject(); - addClassDetails( registrationName, serialForm.fromSerialForm( context ) ); - } - } } diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/MissingPackageInfoDetails.java b/hibernate-models/src/main/java/org/hibernate/models/internal/MissingPackageInfoDetails.java index 4b68427..62465ce 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/MissingPackageInfoDetails.java +++ b/hibernate-models/src/main/java/org/hibernate/models/internal/MissingPackageInfoDetails.java @@ -10,6 +10,7 @@ import java.util.function.Consumer; import org.hibernate.models.internal.util.IndexedConsumer; +import org.hibernate.models.serial.spi.SerialClassDetails; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.FieldDetails; @@ -198,11 +199,11 @@ public Class toJavaClass() { } @Override - public SerialCassDetails toSerialForm(SourceModelBuildingContext context) { + public SerialClassDetails toStorableForm() { return new SerialFormImpl( packageName, packageInfoClassName ); } - private static class SerialFormImpl implements SerialCassDetails { + private static class SerialFormImpl implements SerialClassDetails { private final String packageName; private final String packageInfoClassName; @@ -212,7 +213,17 @@ public SerialFormImpl(String packageName, String packageInfoClassName) { } @Override - public ClassDetails fromSerialForm(SourceModelBuildingContext context) { + public String getName() { + return packageName; + } + + @Override + public String getClassName() { + return packageInfoClassName; + } + + @Override + public ClassDetails fromStorableForm(SourceModelBuildingContext context) { return new MissingPackageInfoDetails( packageName, packageInfoClassName ); } } diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/SerialCassDetails.java b/hibernate-models/src/main/java/org/hibernate/models/internal/SerialCassDetails.java deleted file mode 100644 index 44976c9..0000000 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/SerialCassDetails.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ - -package org.hibernate.models.internal; - -import org.hibernate.models.spi.ClassDetails; - -public interface SerialCassDetails extends SerialForm { -} diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/SerialForm.java b/hibernate-models/src/main/java/org/hibernate/models/internal/SerialForm.java deleted file mode 100644 index a3d3745..0000000 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/SerialForm.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ - -package org.hibernate.models.internal; - -import java.io.Serializable; - -import org.hibernate.models.spi.SourceModelBuildingContext; - -public interface SerialForm extends Serializable { - T fromSerialForm(SourceModelBuildingContext context); -} diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/SimpleClassDetails.java b/hibernate-models/src/main/java/org/hibernate/models/internal/SimpleClassDetails.java index cafeb51..3bf4d06 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/SimpleClassDetails.java +++ b/hibernate-models/src/main/java/org/hibernate/models/internal/SimpleClassDetails.java @@ -10,8 +10,9 @@ import java.util.List; import java.util.function.Consumer; -import org.hibernate.models.internal.jdk.SerialJdkCassDetails; +import org.hibernate.models.internal.jdk.SerialJdkClassDetails; import org.hibernate.models.internal.util.IndexedConsumer; +import org.hibernate.models.serial.spi.SerialClassDetails; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.FieldDetails; @@ -231,7 +232,7 @@ public X getNamedAnnotationUsage( } @Override - public SerialCassDetails toSerialForm(SourceModelBuildingContext context) { - return new SerialJdkCassDetails( null, clazz ); + public SerialClassDetails toStorableForm() { + return new SerialJdkClassDetails( clazz.getName(), clazz ); } } diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/dynamic/DynamicClassDetails.java b/hibernate-models/src/main/java/org/hibernate/models/internal/dynamic/DynamicClassDetails.java index 1890f54..eae133b 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/dynamic/DynamicClassDetails.java +++ b/hibernate-models/src/main/java/org/hibernate/models/internal/dynamic/DynamicClassDetails.java @@ -10,7 +10,7 @@ import org.hibernate.models.internal.ClassDetailsSupport; import org.hibernate.models.internal.ClassTypeDetailsImpl; -import org.hibernate.models.internal.SerialCassDetails; +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; @@ -236,7 +236,7 @@ public String toString() { } @Override - public SerialCassDetails toSerialForm(SourceModelBuildingContext context) { + public SerialClassDetails toStorableForm() { throw new UnsupportedOperationException( "Not implemented yet" ); } } diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/dynamic/SerialDynamicClassDetails.java b/hibernate-models/src/main/java/org/hibernate/models/internal/dynamic/SerialDynamicClassDetails.java deleted file mode 100644 index 9a7b020..0000000 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/dynamic/SerialDynamicClassDetails.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ - -package org.hibernate.models.internal.dynamic; - -import org.hibernate.models.internal.SerialCassDetails; -import org.hibernate.models.spi.ClassDetails; -import org.hibernate.models.spi.SourceModelBuildingContext; - -public class SerialDynamicClassDetails implements SerialCassDetails { - @Override - public ClassDetails fromSerialForm(SourceModelBuildingContext context) { - throw new UnsupportedOperationException( "Not implemented yet" ); - } -} diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/jdk/JdkClassDetails.java b/hibernate-models/src/main/java/org/hibernate/models/internal/jdk/JdkClassDetails.java index 76728ad..914fc31 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/jdk/JdkClassDetails.java +++ b/hibernate-models/src/main/java/org/hibernate/models/internal/jdk/JdkClassDetails.java @@ -15,8 +15,8 @@ import java.util.List; import org.hibernate.models.internal.ClassDetailsSupport; -import org.hibernate.models.internal.SerialCassDetails; 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.ClassDetailsRegistry; import org.hibernate.models.spi.FieldDetails; @@ -184,6 +184,9 @@ public List getFields() { this.fields = arrayList( reflectionFields.length ); for ( int i = 0; i < reflectionFields.length; i++ ) { final Field reflectionField = reflectionFields[i]; + if ( reflectionField.isSynthetic() ) { + continue; + } fields.add( new JdkFieldDetails( reflectionField, this, getModelContext() ) ); } } @@ -201,6 +204,9 @@ public List getMethods() { final Method[] reflectionMethods = managedClass.getDeclaredMethods(); this.methods = arrayList( reflectionMethods.length ); for ( int i = 0; i < reflectionMethods.length; i++ ) { + if ( reflectionMethods[i].isSynthetic() ) { + continue; + } this.methods.add( buildMethodDetails( reflectionMethods[i], this, getModelContext() ) ); } } @@ -233,7 +239,7 @@ public String toString() { } @Override - public SerialCassDetails toSerialForm(SourceModelBuildingContext context) { - return new SerialJdkCassDetails( name, managedClass ); + public SerialClassDetails toStorableForm() { + return new SerialJdkClassDetails( name, managedClass ); } } diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/jdk/SerialJdkCassDetails.java b/hibernate-models/src/main/java/org/hibernate/models/internal/jdk/SerialJdkClassDetails.java similarity index 50% rename from hibernate-models/src/main/java/org/hibernate/models/internal/jdk/SerialJdkCassDetails.java rename to hibernate-models/src/main/java/org/hibernate/models/internal/jdk/SerialJdkClassDetails.java index 8c9fdb9..0cc20e0 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/jdk/SerialJdkCassDetails.java +++ b/hibernate-models/src/main/java/org/hibernate/models/internal/jdk/SerialJdkClassDetails.java @@ -2,30 +2,33 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright: Red Hat Inc. and Hibernate Authors */ - -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ - package org.hibernate.models.internal.jdk; -import org.hibernate.models.internal.SerialCassDetails; -import org.hibernate.models.internal.SerialForm; +import org.hibernate.models.serial.spi.SerialClassDetails; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.SourceModelBuildingContext; -public class SerialJdkCassDetails implements SerialForm, SerialCassDetails { +public class SerialJdkClassDetails implements SerialClassDetails { private final String name; private final Class javaType; - public SerialJdkCassDetails(String name, Class javaType) { + public SerialJdkClassDetails(String name, Class javaType) { this.name = name; this.javaType = javaType; } @Override - public ClassDetails fromSerialForm(SourceModelBuildingContext context) { + public String getName() { + return name; + } + + @Override + public String getClassName() { + return javaType.getName(); + } + + @Override + public ClassDetails fromStorableForm(SourceModelBuildingContext context) { return new JdkClassDetails( name, javaType, context ); } } diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/util/CollectionHelper.java b/hibernate-models/src/main/java/org/hibernate/models/internal/util/CollectionHelper.java index 202c36c..832e355 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/util/CollectionHelper.java +++ b/hibernate-models/src/main/java/org/hibernate/models/internal/util/CollectionHelper.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -16,6 +17,8 @@ */ public class CollectionHelper { public static final int DEFAULT_LIST_CAPACITY = 10; + public static final int MINIMUM_INITIAL_CAPACITY = 16; + public static final float LOAD_FACTOR = 0.75f; public static boolean isEmpty(@SuppressWarnings("rawtypes") Collection collection) { return collection == null || collection.isEmpty(); @@ -86,4 +89,30 @@ public static void forEach(T[] values, Consumer consumer) { } } } + + /** + * Determine the proper initial size for a new collection in order for it to hold the given a number of elements. + * Specifically we want to account for load size and load factor to prevent immediate resizing. + * + * @param numberOfElements The number of elements to be stored. + * + * @return The proper size. + */ + public static int determineProperSizing(int numberOfElements) { + int actual = ( (int) ( numberOfElements / LOAD_FACTOR ) ) + 1; + return Math.max( actual, MINIMUM_INITIAL_CAPACITY ); + } + + /** + * Build a properly sized linked map, especially handling load size and load factor to prevent immediate resizing. + *

+ * Especially helpful for copy map contents. + * + * @param size The size to make the map. + * + * @return The sized linked map. + */ + public static LinkedHashMap linkedMapOfSize(int size) { + return new LinkedHashMap<>( determineProperSizing( size ), LOAD_FACTOR ); + } } diff --git a/hibernate-models/src/main/java/org/hibernate/models/serial/internal/ClassDetailsBuilderImpl.java b/hibernate-models/src/main/java/org/hibernate/models/serial/internal/ClassDetailsBuilderImpl.java new file mode 100644 index 0000000..e04f5ec --- /dev/null +++ b/hibernate-models/src/main/java/org/hibernate/models/serial/internal/ClassDetailsBuilderImpl.java @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.serial.internal; + +import org.hibernate.models.serial.spi.SerialClassDetails; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.ClassDetailsBuilder; +import org.hibernate.models.spi.ClassLoading; +import org.hibernate.models.spi.SourceModelBuildingContext; + +/** + * @author Steve Ebersole + */ +public class ClassDetailsBuilderImpl implements ClassDetailsBuilder { + private StorableContextImpl serialContext; + + public ClassDetailsBuilderImpl(StorableContextImpl serialContext, ClassLoading classLoading) { + this.serialContext = serialContext; + } + + @Override + public ClassDetails buildClassDetails(String name, SourceModelBuildingContext buildingContext) { + if ( serialContext == null ) { + throw new IllegalStateException( "Building context is now immutable" ); + } + final SerialClassDetails serialClassDetails = serialContext.getSerialClassDetailsMap().get( name ); + return serialClassDetails.fromStorableForm( buildingContext ); + } + + public void invalidate() { + serialContext = null; + } +} diff --git a/hibernate-models/src/main/java/org/hibernate/models/serial/internal/RestoredModelContext.java b/hibernate-models/src/main/java/org/hibernate/models/serial/internal/RestoredModelContext.java new file mode 100644 index 0000000..4653fbe --- /dev/null +++ b/hibernate-models/src/main/java/org/hibernate/models/serial/internal/RestoredModelContext.java @@ -0,0 +1,80 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.serial.internal; + +import java.lang.annotation.Annotation; +import java.util.Map; + +import org.hibernate.models.internal.AnnotationDescriptorRegistryStandard; +import org.hibernate.models.internal.ClassDetailsRegistryStandard; +import org.hibernate.models.internal.MutableAnnotationDescriptorRegistry; +import org.hibernate.models.internal.MutableClassDetailsRegistry; +import org.hibernate.models.serial.spi.SerialAnnotationDescriptor; +import org.hibernate.models.serial.spi.SerialClassDetails; +import org.hibernate.models.serial.spi.StorableContext; +import org.hibernate.models.spi.AnnotationDescriptorRegistry; +import org.hibernate.models.spi.ClassDetailsRegistry; +import org.hibernate.models.spi.ClassLoading; +import org.hibernate.models.spi.SourceModelBuildingContext; +import org.hibernate.models.spi.SourceModelContext; + +/** + * SourceModelBuildingContext implementation used with serialization support. + * + * @implNote This implementation is considered immutable after construction. It implements + * {@linkplain SourceModelBuildingContext} instead of just {@linkplain SourceModelContext} + * simply for ease of coding. From the API point of view, via {@linkplain StorableContext#fromStorableForm}, + * this implementation is always treated as an immutable {@linkplain SourceModelContext}. + * + * @author Steve Ebersole + */ +public class RestoredModelContext implements SourceModelBuildingContext { + private final MutableAnnotationDescriptorRegistry annotationDescriptorRegistry; + private final MutableClassDetailsRegistry classDetailsRegistry; + + private ClassLoading classLoading; + + public RestoredModelContext(StorableContextImpl serialContext, ClassLoading classLoading) { + this.classLoading = classLoading; + + final ClassDetailsBuilderImpl classDetailsBuilder = new ClassDetailsBuilderImpl( serialContext, classLoading ); + + this.annotationDescriptorRegistry = new AnnotationDescriptorRegistryStandard( this ); + this.classDetailsRegistry = new ClassDetailsRegistryStandard( classDetailsBuilder, this ); + + for ( Map.Entry classDetailsEntry : serialContext.getSerialClassDetailsMap().entrySet() ) { + classDetailsRegistry.resolveClassDetails( classDetailsEntry.getKey() ); + } + + for ( Map.Entry, SerialAnnotationDescriptor> annotationDescriptorEntry + : serialContext.getSerialAnnotationDescriptorMap().entrySet() ) { + final SerialAnnotationDescriptor serialDescriptor = annotationDescriptorEntry.getValue(); + annotationDescriptorRegistry.register( serialDescriptor.fromStorableForm( this ) ); + } + + classLoading = null; + classDetailsBuilder.invalidate(); + } + + @Override + public ClassLoading getClassLoading() { + return classLoading; + } + + @Override + public AnnotationDescriptorRegistry getAnnotationDescriptorRegistry() { + return annotationDescriptorRegistry; + } + + @Override + public ClassDetailsRegistry getClassDetailsRegistry() { + return classDetailsRegistry; + } + + @Override + public StorableContext toStorableForm() { + throw new UnsupportedOperationException( ); + } +} diff --git a/hibernate-models/src/main/java/org/hibernate/models/internal/SerialAnnotationDescriptor.java b/hibernate-models/src/main/java/org/hibernate/models/serial/internal/SerialAnnotationDescriptorImpl.java similarity index 50% rename from hibernate-models/src/main/java/org/hibernate/models/internal/SerialAnnotationDescriptor.java rename to hibernate-models/src/main/java/org/hibernate/models/serial/internal/SerialAnnotationDescriptorImpl.java index 12d2892..cdbe6be 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/internal/SerialAnnotationDescriptor.java +++ b/hibernate-models/src/main/java/org/hibernate/models/serial/internal/SerialAnnotationDescriptorImpl.java @@ -2,29 +2,27 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright: Red Hat Inc. and Hibernate Authors */ +package org.hibernate.models.serial.internal; -package org.hibernate.models.internal; - -import java.io.Serializable; import java.lang.annotation.Annotation; +import org.hibernate.models.internal.StandardAnnotationDescriptor; +import org.hibernate.models.serial.spi.SerialAnnotationDescriptor; import org.hibernate.models.spi.AnnotationDescriptor; import org.hibernate.models.spi.SourceModelBuildingContext; /** - * Serial form of a AnnotationDescriptor - * * @author Steve Ebersole */ -public class SerialAnnotationDescriptor implements SerialForm> { +public class SerialAnnotationDescriptorImpl implements SerialAnnotationDescriptor { private final Class annotationType; - public SerialAnnotationDescriptor(Class annotationType) { + public SerialAnnotationDescriptorImpl(Class annotationType) { this.annotationType = annotationType; } @Override - public AnnotationDescriptor fromSerialForm(SourceModelBuildingContext context) { + public AnnotationDescriptor fromStorableForm(SourceModelBuildingContext context) { return new StandardAnnotationDescriptor<>( annotationType, context ); } } diff --git a/hibernate-models/src/main/java/org/hibernate/models/serial/internal/StorableContextImpl.java b/hibernate-models/src/main/java/org/hibernate/models/serial/internal/StorableContextImpl.java new file mode 100644 index 0000000..5911d88 --- /dev/null +++ b/hibernate-models/src/main/java/org/hibernate/models/serial/internal/StorableContextImpl.java @@ -0,0 +1,56 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.serial.internal; + +import java.lang.annotation.Annotation; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.hibernate.models.serial.spi.SerialAnnotationDescriptor; +import org.hibernate.models.serial.spi.SerialClassDetails; +import org.hibernate.models.serial.spi.StorableContext; +import org.hibernate.models.spi.AnnotationDescriptor; +import org.hibernate.models.spi.ClassDetails; +import org.hibernate.models.spi.ClassLoading; +import org.hibernate.models.spi.SourceModelContext; + +import static org.hibernate.models.internal.util.CollectionHelper.linkedMapOfSize; + +/** + * Standard implementation of {@linkplain StorableContext} representing a serializable {@linkplain SourceModelContext} + * + * @author Steve Ebersole + */ +public class StorableContextImpl implements StorableContext { + private final LinkedHashMap serialClassDetailsMap; + private final LinkedHashMap, SerialAnnotationDescriptor> serialAnnotationDescriptorMap; + + public StorableContextImpl( + Map classDetailsMap, + Map, AnnotationDescriptor> annotationDescriptorMap) { + serialClassDetailsMap = linkedMapOfSize( classDetailsMap.size() ); + serialAnnotationDescriptorMap = linkedMapOfSize( annotationDescriptorMap.size() ); + + for ( Map.Entry classDetailsEntry : classDetailsMap.entrySet() ) { + serialClassDetailsMap.put( classDetailsEntry.getKey(), classDetailsEntry.getValue().toStorableForm() ); + } + for ( Map.Entry, AnnotationDescriptor> descriptorEntry : annotationDescriptorMap.entrySet() ) { + serialAnnotationDescriptorMap.put( descriptorEntry.getKey(), descriptorEntry.getValue().toStorableForm() ); + } + } + + @Override + public SourceModelContext fromStorableForm(ClassLoading classLoading) { + return new RestoredModelContext( this, classLoading ); + } + + public LinkedHashMap getSerialClassDetailsMap() { + return serialClassDetailsMap; + } + + public LinkedHashMap, SerialAnnotationDescriptor> getSerialAnnotationDescriptorMap() { + return serialAnnotationDescriptorMap; + } +} diff --git a/hibernate-models/src/main/java/org/hibernate/models/serial/package-info.java b/hibernate-models/src/main/java/org/hibernate/models/serial/package-info.java new file mode 100644 index 0000000..ea61aab --- /dev/null +++ b/hibernate-models/src/main/java/org/hibernate/models/serial/package-info.java @@ -0,0 +1,11 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ + +/** + * Support for serializing and deserializing {@linkplain org.hibernate.models.spi.SourceModelBuildingContext}, + * {@linkplain org.hibernate.models.spi.ClassDetailsRegistry}, + * {@linkplain org.hibernate.models.spi.AnnotationDescriptorRegistry}, etc. + */ +package org.hibernate.models.serial; diff --git a/hibernate-models/src/main/java/org/hibernate/models/serial/spi/SerialAnnotationDescriptor.java b/hibernate-models/src/main/java/org/hibernate/models/serial/spi/SerialAnnotationDescriptor.java new file mode 100644 index 0000000..88de46c --- /dev/null +++ b/hibernate-models/src/main/java/org/hibernate/models/serial/spi/SerialAnnotationDescriptor.java @@ -0,0 +1,16 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.serial.spi; + +import java.lang.annotation.Annotation; + +import org.hibernate.models.spi.AnnotationDescriptor; + +/** + * @author Steve Ebersole + */ +public interface SerialAnnotationDescriptor extends StorableForm> { + +} diff --git a/hibernate-models/src/main/java/org/hibernate/models/serial/spi/SerialClassDetails.java b/hibernate-models/src/main/java/org/hibernate/models/serial/spi/SerialClassDetails.java new file mode 100644 index 0000000..63d6f23 --- /dev/null +++ b/hibernate-models/src/main/java/org/hibernate/models/serial/spi/SerialClassDetails.java @@ -0,0 +1,16 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.serial.spi; + +import org.hibernate.models.spi.ClassDetails; + +/** + * @author Steve Ebersole + */ +public interface SerialClassDetails extends StorableForm { + String getName(); + + String getClassName(); +} diff --git a/hibernate-models/src/main/java/org/hibernate/models/serial/spi/Storable.java b/hibernate-models/src/main/java/org/hibernate/models/serial/spi/Storable.java new file mode 100644 index 0000000..d5505eb --- /dev/null +++ b/hibernate-models/src/main/java/org/hibernate/models/serial/spi/Storable.java @@ -0,0 +1,16 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.serial.spi; + +/** + * A part of the {@linkplain org.hibernate.models.spi.SourceModelContext model context} which can + * be stored in the context's {@linkplain StorableContext serial form}. + * + * @param The storable's type + * @param The storable's serial-type's type + */ +public interface Storable> { + S toStorableForm(); +} diff --git a/hibernate-models/src/main/java/org/hibernate/models/serial/spi/StorableContext.java b/hibernate-models/src/main/java/org/hibernate/models/serial/spi/StorableContext.java new file mode 100644 index 0000000..f4761af --- /dev/null +++ b/hibernate-models/src/main/java/org/hibernate/models/serial/spi/StorableContext.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.serial.spi; + +import java.io.Serializable; + +import org.hibernate.models.spi.ClassLoading; +import org.hibernate.models.spi.SourceModelBuildingContext; +import org.hibernate.models.spi.SourceModelContext; + +/** + * Form of {@linkplain SourceModelContext} which is serializable. + * + * @see SourceModelBuildingContext#toStorableForm() + * + * @author Steve Ebersole + */ +public interface StorableContext extends Serializable { + /** + * "Re-construct" the model context from the serial form + */ + SourceModelContext fromStorableForm(ClassLoading classLoading); +} diff --git a/hibernate-models/src/main/java/org/hibernate/models/serial/spi/StorableForm.java b/hibernate-models/src/main/java/org/hibernate/models/serial/spi/StorableForm.java new file mode 100644 index 0000000..b3a573f --- /dev/null +++ b/hibernate-models/src/main/java/org/hibernate/models/serial/spi/StorableForm.java @@ -0,0 +1,19 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.serial.spi; + +import java.io.Serializable; + +import org.hibernate.models.spi.SourceModelBuildingContext; + +/** + * Serial form for various parts of a {@linkplain SourceModelBuildingContext context} + * included in its {@linkplain StorableContext serial form}. + * + * @author Steve Ebersole + */ +public interface StorableForm extends Serializable { + T fromStorableForm(SourceModelBuildingContext context); +} diff --git a/hibernate-models/src/main/java/org/hibernate/models/spi/AnnotationDescriptor.java b/hibernate-models/src/main/java/org/hibernate/models/spi/AnnotationDescriptor.java index 4c4206b..df84301 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/spi/AnnotationDescriptor.java +++ b/hibernate-models/src/main/java/org/hibernate/models/spi/AnnotationDescriptor.java @@ -4,9 +4,6 @@ */ package org.hibernate.models.spi; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.lang.annotation.Annotation; import java.lang.annotation.Repeatable; import java.util.EnumSet; @@ -16,7 +13,9 @@ import org.hibernate.models.IllegalCastException; import org.hibernate.models.UnknownAnnotationAttributeException; import org.hibernate.models.internal.AnnotationProxy; -import org.hibernate.models.internal.SerialAnnotationDescriptor; +import org.hibernate.models.serial.internal.SerialAnnotationDescriptorImpl; +import org.hibernate.models.serial.spi.SerialAnnotationDescriptor; +import org.hibernate.models.serial.spi.Storable; /** * Describes an annotation type (the Class) @@ -158,7 +157,7 @@ default RecordComponentDetails asRecordComponentDetails() { } @Override - default SerialAnnotationDescriptor toSerialForm(SourceModelBuildingContext context) { - return new SerialAnnotationDescriptor<>( getAnnotationType() ); + default SerialAnnotationDescriptor toStorableForm() { + return new SerialAnnotationDescriptorImpl<>( getAnnotationType() ); } } diff --git a/hibernate-models/src/main/java/org/hibernate/models/spi/ClassDetails.java b/hibernate-models/src/main/java/org/hibernate/models/spi/ClassDetails.java index dd1a8bf..cb91904 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/spi/ClassDetails.java +++ b/hibernate-models/src/main/java/org/hibernate/models/spi/ClassDetails.java @@ -4,7 +4,6 @@ */ package org.hibernate.models.spi; -import java.io.IOException; import java.lang.annotation.Annotation; import java.util.List; import java.util.function.Consumer; @@ -12,9 +11,10 @@ import org.hibernate.models.IllegalCastException; import org.hibernate.models.internal.AnnotationTargetHelper; -import org.hibernate.models.internal.SerialCassDetails; import org.hibernate.models.internal.SimpleClassDetails; import org.hibernate.models.internal.util.IndexedConsumer; +import org.hibernate.models.serial.spi.SerialClassDetails; +import org.hibernate.models.serial.spi.Storable; /** * Abstraction for what Hibernate understands about a "class", generally before it has access to @@ -23,7 +23,7 @@ * @author Steve Ebersole * @see ClassDetailsRegistry */ -public interface ClassDetails extends AnnotationTarget, TypeVariableScope, Storable { +public interface ClassDetails extends AnnotationTarget, TypeVariableScope, Storable { /** * Details for {@code Object.class} */ diff --git a/hibernate-models/src/main/java/org/hibernate/models/spi/SourceModelBuildingContext.java b/hibernate-models/src/main/java/org/hibernate/models/spi/SourceModelBuildingContext.java index 0e0e648..a310035 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/spi/SourceModelBuildingContext.java +++ b/hibernate-models/src/main/java/org/hibernate/models/spi/SourceModelBuildingContext.java @@ -4,6 +4,8 @@ */ package org.hibernate.models.spi; +import org.hibernate.models.serial.spi.StorableContext; + /** * Context object used while building references for {@link AnnotationDescriptor}, * {@link ClassDetails} and friends. @@ -22,4 +24,6 @@ default S as(Class type) { //noinspection unchecked return (S) this; } + + StorableContext toStorableForm(); } diff --git a/hibernate-models/src/main/java/org/hibernate/models/spi/SourceModelContext.java b/hibernate-models/src/main/java/org/hibernate/models/spi/SourceModelContext.java index c8b2bb9..9b9b642 100644 --- a/hibernate-models/src/main/java/org/hibernate/models/spi/SourceModelContext.java +++ b/hibernate-models/src/main/java/org/hibernate/models/spi/SourceModelContext.java @@ -4,12 +4,10 @@ */ package org.hibernate.models.spi; -import java.io.Serializable; - /** * @author Steve Ebersole */ -public interface SourceModelContext extends Serializable { +public interface SourceModelContext { /** * The registry of annotation descriptors */ diff --git a/hibernate-models/src/main/java/org/hibernate/models/spi/Storable.java b/hibernate-models/src/main/java/org/hibernate/models/spi/Storable.java deleted file mode 100644 index 6798172..0000000 --- a/hibernate-models/src/main/java/org/hibernate/models/spi/Storable.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ - -package org.hibernate.models.spi; - -import java.io.IOException; - -import org.hibernate.models.internal.SerialForm; - -public interface Storable> { - S toSerialForm(SourceModelBuildingContext context); -} diff --git a/hibernate-models/src/test/java/org/hibernate/models/SimpleSerializationTests.java b/hibernate-models/src/test/java/org/hibernate/models/SimpleSerializationTests.java index de1fca9..26cb1e9 100644 --- a/hibernate-models/src/test/java/org/hibernate/models/SimpleSerializationTests.java +++ b/hibernate-models/src/test/java/org/hibernate/models/SimpleSerializationTests.java @@ -2,7 +2,6 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright: Red Hat Inc. and Hibernate Authors */ - package org.hibernate.models; import java.lang.annotation.ElementType; @@ -10,12 +9,15 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.hibernate.models.serial.spi.StorableContext; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.SourceModelBuildingContext; +import org.hibernate.models.spi.SourceModelContext; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.models.internal.SimpleClassLoading.SIMPLE_CLASS_LOADING; public class SimpleSerializationTests { protected SourceModelBuildingContext createModelContext(Class... classes) { @@ -25,19 +27,20 @@ protected SourceModelBuildingContext createModelContext(Class... classes) { @Test void serializeSimpleClass() { final SourceModelBuildingContext buildingContext = createModelContext( SimpleClass.class ); - final ClassDetails classDetails = buildingContext.getClassDetailsRegistry().findClassDetails( SimpleClass.class.getName() ); assertThat( classDetails ).isNotNull(); - final SourceModelBuildingContext clone = SerializationHelper.clone( buildingContext ); - assertThat( buildingContext ).isNotSameAs( clone ); + final StorableContext serialContext = buildingContext.toStorableForm(); + final StorableContext clonedSerialContext = SerializationHelper.clone( serialContext ); + assertThat( serialContext ).isNotSameAs( clonedSerialContext ); - final ClassDetails cloneCassDetails = clone.getClassDetailsRegistry().findClassDetails( SimpleClass.class.getName() ); - assertThat( cloneCassDetails ).isNotNull(); + final SourceModelContext restored = clonedSerialContext.fromStorableForm( SIMPLE_CLASS_LOADING ); + assertThat( buildingContext.getClassDetailsRegistry() ).isNotSameAs( restored.getClassDetailsRegistry() ); + assertThat( buildingContext.getAnnotationDescriptorRegistry() ).isNotSameAs( restored.getAnnotationDescriptorRegistry() ); - assertThat( classDetails ).isNotSameAs( cloneCassDetails ); - assertThat( buildingContext.getClassDetailsRegistry() ).isNotSameAs( clone.getClassDetailsRegistry() ); - assertThat( buildingContext.getAnnotationDescriptorRegistry() ).isNotSameAs( clone.getAnnotationDescriptorRegistry() ); + final ClassDetails restoredClassDetails = restored.getClassDetailsRegistry().findClassDetails( SimpleClass.class.getName() ); + assertThat( restoredClassDetails ).isNotNull(); + assertThat( classDetails ).isNotSameAs( restoredClassDetails ); } @Test @@ -49,16 +52,21 @@ void serializeSimpleClassWithMembers() { assertThat( classDetails.getFields() ).hasSize( 1 ); assertThat( classDetails.getMethods() ).hasSize( 3 ); - final SourceModelBuildingContext clone = SerializationHelper.clone( buildingContext ); - final ClassDetails cloneCassDetails = clone.getClassDetailsRegistry().findClassDetails( SimpleClassWithMembers.class.getName() ); + final StorableContext serialContext = buildingContext.toStorableForm(); + final StorableContext clonedSerialContext = SerializationHelper.clone( serialContext ); + assertThat( serialContext ).isNotSameAs( clonedSerialContext ); + + final SourceModelContext restored = clonedSerialContext.fromStorableForm( SIMPLE_CLASS_LOADING ); + assertThat( buildingContext ).isNotSameAs( restored ); + assertThat( buildingContext.getClassDetailsRegistry() ).isNotSameAs( restored.getClassDetailsRegistry() ); + assertThat( buildingContext.getAnnotationDescriptorRegistry() ).isNotSameAs( restored.getAnnotationDescriptorRegistry() ); + + final ClassDetails cloneCassDetails = restored.getClassDetailsRegistry().findClassDetails( SimpleClassWithMembers.class.getName() ); assertThat( cloneCassDetails ).isNotNull(); assertThat( cloneCassDetails.getFields() ).hasSize( 1 ); assertThat( cloneCassDetails.getMethods() ).hasSize( 3 ); - assertThat( buildingContext ).isNotSameAs( clone ); assertThat( classDetails ).isNotSameAs( cloneCassDetails ); - assertThat( buildingContext.getClassDetailsRegistry() ).isNotSameAs( clone.getClassDetailsRegistry() ); - assertThat( buildingContext.getAnnotationDescriptorRegistry() ).isNotSameAs( clone.getAnnotationDescriptorRegistry() ); } @Test @@ -73,18 +81,22 @@ void serializeSimpleClassWithAnnotations() { assertThat( classDetails.getMethods() ).hasSize( 1 ); assertThat( classDetails.getMethods().iterator().next().getDirectAnnotationUsages() ).hasSize( 1 ); - final SourceModelBuildingContext clone = SerializationHelper.clone( buildingContext ); - final ClassDetails cloneCassDetails = clone.getClassDetailsRegistry().findClassDetails( SimpleClassWithAnnotations.class.getName() ); + final StorableContext serialContext = buildingContext.toStorableForm(); + final StorableContext clonedSerialContext = SerializationHelper.clone( serialContext ); + assertThat( serialContext ).isNotSameAs( clonedSerialContext ); + + final SourceModelContext restored = clonedSerialContext.fromStorableForm( SIMPLE_CLASS_LOADING ); + assertThat( buildingContext ).isNotSameAs( restored ); + assertThat( buildingContext.getClassDetailsRegistry() ).isNotSameAs( restored.getClassDetailsRegistry() ); + assertThat( buildingContext.getAnnotationDescriptorRegistry() ).isNotSameAs( restored.getAnnotationDescriptorRegistry() ); + + final ClassDetails cloneCassDetails = restored.getClassDetailsRegistry().findClassDetails( SimpleClassWithAnnotations.class.getName() ); + assertThat( classDetails ).isNotSameAs( cloneCassDetails ); assertThat( cloneCassDetails.getDirectAnnotationUsages() ).hasSize( 1 ); assertThat( cloneCassDetails.getFields() ).hasSize( 1 ); assertThat( cloneCassDetails.getFields().iterator().next().getDirectAnnotationUsages() ).hasSize( 1 ); assertThat( cloneCassDetails.getMethods() ).hasSize( 1 ); assertThat( cloneCassDetails.getMethods().iterator().next().getDirectAnnotationUsages() ).hasSize( 1 ); - - assertThat( buildingContext ).isNotSameAs( clone ); - assertThat( classDetails ).isNotSameAs( cloneCassDetails ); - assertThat( buildingContext.getClassDetailsRegistry() ).isNotSameAs( clone.getClassDetailsRegistry() ); - assertThat( buildingContext.getAnnotationDescriptorRegistry() ).isNotSameAs( clone.getAnnotationDescriptorRegistry() ); } public static class SimpleClass { diff --git a/hibernate-models/src/test/java/org/hibernate/models/SourceModelTestHelper.java b/hibernate-models/src/test/java/org/hibernate/models/SourceModelTestHelper.java index f72c54b..b36c43d 100644 --- a/hibernate-models/src/test/java/org/hibernate/models/SourceModelTestHelper.java +++ b/hibernate-models/src/test/java/org/hibernate/models/SourceModelTestHelper.java @@ -2,7 +2,6 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright: Red Hat Inc. and Hibernate Authors */ - package org.hibernate.models; import org.hibernate.models.internal.BasicModelBuildingContextImpl;