Skip to content

Commit ff701d1

Browse files
committed
#87 - Make sure models are serializable
1 parent a492193 commit ff701d1

36 files changed

+572
-197
lines changed

hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexAnnotationDescriptorRegistry.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package org.hibernate.models.jandex.internal;
66

77
import java.lang.annotation.Annotation;
8+
import java.util.Map;
89

910
import org.hibernate.models.internal.AnnotationDescriptorRegistryStandard;
1011
import org.hibernate.models.spi.AnnotationDescriptor;
@@ -24,4 +25,8 @@ protected <A extends Annotation> AnnotationDescriptor<A> buildAnnotationDescript
2425
AnnotationDescriptor<? extends Annotation> containerDescriptor) {
2526
return new JandexAnnotationDescriptorImpl<>( javaType, containerDescriptor, getModelBuildingContext() );
2627
}
28+
29+
public Map<Class<? extends Annotation>, AnnotationDescriptor<? extends Annotation>> getDescriptorMap() {
30+
return descriptorMap;
31+
}
2732
}

hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexClassDetails.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
import java.util.List;
1010

1111
import org.hibernate.models.internal.ClassDetailsSupport;
12-
import org.hibernate.models.internal.SerialCassDetails;
13-
import org.hibernate.models.internal.jdk.SerialJdkCassDetails;
12+
import org.hibernate.models.internal.jdk.SerialJdkClassDetails;
1413
import org.hibernate.models.internal.util.CollectionHelper;
14+
import org.hibernate.models.serial.spi.SerialClassDetails;
1515
import org.hibernate.models.spi.ClassDetails;
1616
import org.hibernate.models.spi.FieldDetails;
1717
import org.hibernate.models.spi.MethodDetails;
@@ -280,8 +280,7 @@ private static List<TypeVariableDetails> determineTypeParameters(ClassInfo class
280280
}
281281

282282
@Override
283-
public SerialCassDetails toSerialForm(SourceModelBuildingContext context) {
284-
final Class<Object> classForName = context.getClassLoading().classForName( getClassName() );
285-
return new SerialJdkCassDetails( classForName.getName(), classForName );
283+
public SerialClassDetails toStorableForm() {
284+
return new SerialJdkClassDetails( getName(), toJavaClass() );
286285
}
287286
}

hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexClassDetailsRegistry.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
*/
55
package org.hibernate.models.jandex.internal;
66

7+
import java.util.Map;
8+
79
import org.hibernate.models.UnknownClassException;
810
import org.hibernate.models.internal.AbstractClassDetailsRegistry;
911
import org.hibernate.models.internal.jdk.JdkBuilders;
@@ -50,4 +52,8 @@ protected ClassDetails createClassDetails(String name) {
5052

5153
throw new UnknownClassException( "Unable to resolve ClassDetails for `" + name + "`" );
5254
}
55+
56+
protected Map<String, ClassDetails> getClassDetailsMap() {
57+
return classDetailsMap;
58+
}
5359
}

hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexModelBuildingContextImpl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import org.hibernate.models.jandex.spi.JandexModelBuildingContext;
1414
import org.hibernate.models.jandex.spi.JandexValueConverter;
1515
import org.hibernate.models.jandex.spi.JandexValueExtractor;
16+
import org.hibernate.models.serial.internal.StorableContextImpl;
17+
import org.hibernate.models.serial.spi.StorableContext;
1618
import org.hibernate.models.spi.ClassLoading;
1719
import org.hibernate.models.spi.RegistryPrimer;
1820
import org.hibernate.models.spi.ValueTypeDescriptor;
@@ -98,4 +100,9 @@ public <V> JandexValueExtractor<V> getJandexValueExtractor(ValueTypeDescriptor<V
98100
this
99101
);
100102
}
103+
104+
@Override
105+
public StorableContext toStorableForm() {
106+
return new StorableContextImpl( classDetailsRegistry.getClassDetailsMap(), descriptorRegistry.getDescriptorMap() );
107+
}
101108
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright: Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.models.serialization;
6+
7+
import java.lang.annotation.ElementType;
8+
import java.lang.annotation.Retention;
9+
import java.lang.annotation.RetentionPolicy;
10+
import java.lang.annotation.Target;
11+
12+
import org.hibernate.models.SerializationHelper;
13+
import org.hibernate.models.SourceModelTestHelper;
14+
import org.hibernate.models.serial.spi.StorableContext;
15+
import org.hibernate.models.spi.ClassDetails;
16+
import org.hibernate.models.spi.SourceModelBuildingContext;
17+
import org.hibernate.models.spi.SourceModelContext;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import static org.assertj.core.api.Assertions.assertThat;
22+
import static org.hibernate.models.internal.SimpleClassLoading.SIMPLE_CLASS_LOADING;
23+
24+
public class SimpleSerializationTests {
25+
protected SourceModelBuildingContext createModelContext(Class<?>... classes) {
26+
return SourceModelTestHelper.createBuildingContext( classes );
27+
}
28+
29+
@Test
30+
void serializeSimpleClass() {
31+
final SourceModelBuildingContext buildingContext = createModelContext( SimpleClass.class );
32+
33+
final ClassDetails classDetails = buildingContext.getClassDetailsRegistry().findClassDetails( SimpleClass.class.getName() );
34+
assertThat( classDetails ).isNotNull();
35+
36+
final StorableContext serialContext = buildingContext.toStorableForm();
37+
final StorableContext clonedSerialContext = SerializationHelper.clone( serialContext );
38+
assertThat( serialContext ).isNotSameAs( clonedSerialContext );
39+
40+
final SourceModelContext restored = clonedSerialContext.fromStorableForm( SIMPLE_CLASS_LOADING );
41+
assertThat( buildingContext ).isNotSameAs( restored );
42+
assertThat( buildingContext.getClassDetailsRegistry() ).isNotSameAs( restored.getClassDetailsRegistry() );
43+
assertThat( buildingContext.getAnnotationDescriptorRegistry() ).isNotSameAs( restored.getAnnotationDescriptorRegistry() );
44+
45+
final ClassDetails cloneCassDetails = restored.getClassDetailsRegistry().findClassDetails( SimpleClass.class.getName() );
46+
assertThat( cloneCassDetails ).isNotNull();
47+
assertThat( classDetails ).isNotSameAs( cloneCassDetails );
48+
}
49+
50+
@Test
51+
void serializeSimpleClassWithMembers() {
52+
final SourceModelBuildingContext buildingContext = createModelContext( SimpleClassWithMembers.class );
53+
54+
final ClassDetails classDetails = buildingContext.getClassDetailsRegistry().findClassDetails( SimpleClassWithMembers.class.getName() );
55+
assertThat( classDetails ).isNotNull();
56+
assertThat( classDetails.getFields() ).hasSize( 1 );
57+
assertThat( classDetails.getMethods() ).hasSize( 3 );
58+
59+
final StorableContext serialContext = buildingContext.toStorableForm();
60+
final StorableContext clonedSerialContext = SerializationHelper.clone( serialContext );
61+
assertThat( serialContext ).isNotSameAs( clonedSerialContext );
62+
63+
final SourceModelContext restored = clonedSerialContext.fromStorableForm( SIMPLE_CLASS_LOADING );
64+
assertThat( buildingContext ).isNotSameAs( restored );
65+
assertThat( buildingContext.getClassDetailsRegistry() ).isNotSameAs( restored.getClassDetailsRegistry() );
66+
assertThat( buildingContext.getAnnotationDescriptorRegistry() ).isNotSameAs( restored.getAnnotationDescriptorRegistry() );
67+
68+
final ClassDetails cloneCassDetails = restored.getClassDetailsRegistry().findClassDetails( SimpleClassWithMembers.class.getName() );
69+
assertThat( cloneCassDetails ).isNotNull();
70+
assertThat( classDetails ).isNotSameAs( cloneCassDetails );
71+
assertThat( cloneCassDetails.getFields() ).hasSize( 1 );
72+
assertThat( cloneCassDetails.getMethods() ).hasSize( 3 );
73+
}
74+
75+
@Test
76+
void serializeSimpleClassWithAnnotations() {
77+
final SourceModelBuildingContext buildingContext = createModelContext( SimpleClassWithAnnotations.class );
78+
79+
final ClassDetails classDetails = buildingContext.getClassDetailsRegistry().findClassDetails( SimpleClassWithAnnotations.class.getName() );
80+
assertThat( classDetails ).isNotNull();
81+
assertThat( classDetails.getDirectAnnotationUsages() ).hasSize( 1 );
82+
assertThat( classDetails.getFields() ).hasSize( 1 );
83+
assertThat( classDetails.getFields().iterator().next().getDirectAnnotationUsages() ).hasSize( 1 );
84+
assertThat( classDetails.getMethods() ).hasSize( 1 );
85+
assertThat( classDetails.getMethods().iterator().next().getDirectAnnotationUsages() ).hasSize( 1 );
86+
87+
final StorableContext serialContext = buildingContext.toStorableForm();
88+
final StorableContext clonedSerialContext = SerializationHelper.clone( serialContext );
89+
assertThat( serialContext ).isNotSameAs( clonedSerialContext );
90+
91+
final SourceModelContext restored = clonedSerialContext.fromStorableForm( SIMPLE_CLASS_LOADING );
92+
assertThat( restored ).isNotNull();
93+
assertThat( buildingContext ).isNotSameAs( restored );
94+
assertThat( buildingContext.getClassDetailsRegistry() ).isNotSameAs( restored.getClassDetailsRegistry() );
95+
assertThat( buildingContext.getAnnotationDescriptorRegistry() ).isNotSameAs( restored.getAnnotationDescriptorRegistry() );
96+
97+
final ClassDetails cloneCassDetails = restored.getClassDetailsRegistry().findClassDetails( SimpleClassWithAnnotations.class.getName() );
98+
assertThat( classDetails ).isNotSameAs( cloneCassDetails );
99+
assertThat( cloneCassDetails.getDirectAnnotationUsages() ).hasSize( 1 );
100+
assertThat( cloneCassDetails.getFields() ).hasSize( 1 );
101+
assertThat( cloneCassDetails.getFields().iterator().next().getDirectAnnotationUsages() ).hasSize( 1 );
102+
assertThat( cloneCassDetails.getMethods() ).hasSize( 1 );
103+
assertThat( cloneCassDetails.getMethods().iterator().next().getDirectAnnotationUsages() ).hasSize( 1 );
104+
105+
}
106+
107+
public static class SimpleClass {
108+
}
109+
110+
public static class SimpleClassWithMembers {
111+
public int anInt;
112+
113+
public int getAnInt() {
114+
return anInt;
115+
}
116+
117+
public void setAnInt(int anInt) {
118+
this.anInt = anInt;
119+
}
120+
121+
public void doStuff() {
122+
}
123+
}
124+
125+
@Target({ ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
126+
@Retention(RetentionPolicy.RUNTIME)
127+
public @interface AnAnnotation {
128+
}
129+
130+
@AnAnnotation
131+
public static class SimpleClassWithAnnotations {
132+
@AnAnnotation
133+
private int anInt;
134+
135+
@AnAnnotation
136+
public int getAnInt() {
137+
return anInt;
138+
}
139+
140+
}
141+
}

hibernate-models-testing/src/main/java/org/hibernate/models/SerializationHelper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
2-
* SPDX-License-Identifier: LGPL-2.1-or-later
3-
* Copyright Red Hat Inc. and Hibernate Authors
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright: Red Hat Inc. and Hibernate Authors
44
*/
55
package org.hibernate.models;
66

hibernate-models/src/main/java/org/hibernate/models/internal/AbstractAnnotationDescriptorRegistry.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
* @author Steve Ebersole
1717
*/
1818
public abstract class AbstractAnnotationDescriptorRegistry implements AnnotationDescriptorRegistry {
19-
protected final Map<Class<? extends Annotation>, AnnotationDescriptor<?>> descriptorMap;
20-
protected final Map<AnnotationDescriptor<?>, AnnotationDescriptor<?>> repeatableByContainerMap;
19+
protected final Map<Class<? extends Annotation>, AnnotationDescriptor<? extends Annotation>> descriptorMap;
20+
protected final Map<AnnotationDescriptor<? extends Annotation>, AnnotationDescriptor<? extends Annotation>> repeatableByContainerMap;
2121

2222
public AbstractAnnotationDescriptorRegistry() {
2323
this( new ConcurrentHashMap<>(), new ConcurrentHashMap<>() );

hibernate-models/src/main/java/org/hibernate/models/internal/AnnotationDescriptorRegistryStandard.java

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,8 @@
44
*/
55
package org.hibernate.models.internal;
66

7-
import java.io.IOException;
8-
import java.io.ObjectInputStream;
9-
import java.io.ObjectOutputStream;
107
import java.lang.annotation.Annotation;
118
import java.lang.annotation.Repeatable;
12-
import java.util.Map;
139

1410
import org.hibernate.models.spi.AnnotationDescriptor;
1511
import org.hibernate.models.spi.SourceModelBuildingContext;
@@ -89,20 +85,4 @@ protected <A extends Annotation> AnnotationDescriptor<A> buildAnnotationDescript
8985
modelBuildingContext
9086
);
9187
}
92-
93-
public void serialize(ObjectOutputStream outputStream, BasicModelBuildingContextImpl context) throws IOException {
94-
outputStream.writeInt( descriptorMap.size() );
95-
for ( Map.Entry<Class<? extends Annotation>, AnnotationDescriptor<?>> entry : descriptorMap.entrySet() ) {
96-
outputStream.writeObject( entry.getValue().toSerialForm( context ) );
97-
}
98-
}
99-
100-
public void deserialize(ObjectInputStream inputStream, SourceModelBuildingContext context) throws IOException, ClassNotFoundException {
101-
final int count = inputStream.readInt();
102-
for ( int i = 0; i < count; i++ ) {
103-
final SerialAnnotationDescriptor<?> serialForm = (SerialAnnotationDescriptor<?>) inputStream.readObject();
104-
register( serialForm.fromSerialForm( context ) );
105-
}
106-
}
107-
10888
}

hibernate-models/src/main/java/org/hibernate/models/internal/BasicModelBuildingContextImpl.java

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,8 @@
44
*/
55
package org.hibernate.models.internal;
66

7-
import java.io.IOException;
8-
import java.io.ObjectInputStream;
9-
import java.io.ObjectOutputStream;
10-
import java.io.Serial;
11-
12-
import org.hibernate.models.spi.ClassDetailsBuilder;
7+
import org.hibernate.models.serial.internal.StorableContextImpl;
8+
import org.hibernate.models.serial.spi.StorableContext;
139
import org.hibernate.models.spi.ClassLoading;
1410
import org.hibernate.models.spi.RegistryPrimer;
1511

@@ -19,8 +15,8 @@
1915
* @author Steve Ebersole
2016
*/
2117
public class BasicModelBuildingContextImpl extends AbstractModelBuildingContext {
22-
private transient AnnotationDescriptorRegistryStandard descriptorRegistry;
23-
private transient ClassDetailsRegistryStandard classDetailsRegistry;
18+
private final AnnotationDescriptorRegistryStandard descriptorRegistry;
19+
private final ClassDetailsRegistryStandard classDetailsRegistry;
2420

2521
public BasicModelBuildingContextImpl(ClassLoading classLoadingAccess) {
2622
this( classLoadingAccess, null );
@@ -45,23 +41,8 @@ public MutableClassDetailsRegistry getClassDetailsRegistry() {
4541
return classDetailsRegistry;
4642
}
4743

48-
@Serial
49-
private void writeObject(ObjectOutputStream outputStream) throws IOException {
50-
outputStream.writeObject( classDetailsRegistry.getClassDetailsBuilder() );
51-
52-
descriptorRegistry.serialize( outputStream, this );
53-
classDetailsRegistry.serialize( outputStream, this );
54-
55-
outputStream.flush();
56-
}
57-
58-
59-
@Serial
60-
private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
61-
descriptorRegistry = new AnnotationDescriptorRegistryStandard( this );
62-
classDetailsRegistry = new ClassDetailsRegistryStandard( (ClassDetailsBuilder) inputStream.readObject(), this );
63-
64-
descriptorRegistry.deserialize( inputStream, this );
65-
classDetailsRegistry.deserialize( inputStream, this );
44+
@Override
45+
public StorableContext toStorableForm() {
46+
return new StorableContextImpl( classDetailsRegistry.classDetailsMap, descriptorRegistry.descriptorMap );
6647
}
6748
}

hibernate-models/src/main/java/org/hibernate/models/internal/ClassDetailsRegistryStandard.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,6 @@
55
package org.hibernate.models.internal;
66

77

8-
import java.io.IOException;
9-
import java.io.ObjectInputStream;
10-
import java.io.ObjectOutputStream;
11-
import java.util.Map;
12-
138
import org.hibernate.models.internal.jdk.JdkBuilders;
149
import org.hibernate.models.spi.ClassDetails;
1510
import org.hibernate.models.spi.ClassDetailsBuilder;
@@ -42,21 +37,4 @@ public ClassDetailsRegistryStandard(ClassDetailsBuilder classDetailsBuilder, Sou
4237
protected ClassDetailsBuilder getClassDetailsBuilder() {
4338
return classDetailsBuilder;
4439
}
45-
46-
public void serialize(ObjectOutputStream outputStream, SourceModelBuildingContext context) throws IOException {
47-
outputStream.writeInt( classDetailsMap.size() );
48-
for ( Map.Entry<String, ClassDetails> entry : classDetailsMap.entrySet() ) {
49-
outputStream.writeUTF( entry.getKey() );
50-
outputStream.writeObject( entry.getValue().toSerialForm( context ) );
51-
}
52-
}
53-
54-
public void deserialize(ObjectInputStream inputStream, SourceModelBuildingContext context) throws IOException, ClassNotFoundException {
55-
final int count = inputStream.readInt();
56-
for ( int i = 0; i < count; i++ ) {
57-
final String registrationName = inputStream.readUTF();
58-
final SerialCassDetails serialForm = (SerialCassDetails) inputStream.readObject();
59-
addClassDetails( registrationName, serialForm.fromSerialForm( context ) );
60-
}
61-
}
6240
}

0 commit comments

Comments
 (0)