Skip to content

Commit 47ec4f0

Browse files
committed
Fix TypeInformation.OBJECT initialization.
We now create a decoupled instance of ClassTypeInformation to avoid initialization visibility cycle issues when TypeInformation.OBJECT (and other fields) are initialized with null because ClassTypeInformation.OBJECT hasn't been initialized yet. Closes #3340
1 parent ec792a2 commit 47ec4f0

File tree

3 files changed

+52
-25
lines changed

3 files changed

+52
-25
lines changed

src/main/java/org/springframework/data/util/ClassTypeInformation.java

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package org.springframework.data.util;
1717

18-
import java.util.Collection;
1918
import java.util.List;
2019
import java.util.Map;
2120
import java.util.Set;
@@ -40,23 +39,12 @@ class ClassTypeInformation<S> extends TypeDiscoverer<S> {
4039
private static final ConcurrentLruCache<Class<?>, ResolvableType> resolvableTypeCache = new ConcurrentLruCache<>(128,
4140
ResolvableType::forClass);
4241

43-
public static final ClassTypeInformation<Collection> COLLECTION;
44-
public static final ClassTypeInformation<List> LIST;
45-
public static final ClassTypeInformation<Set> SET;
46-
public static final ClassTypeInformation<Map> MAP;
47-
public static final ClassTypeInformation<Object> OBJECT;
48-
49-
static {
42+
private final Class<S> type;
5043

51-
OBJECT = from(Object.class);
52-
COLLECTION = from(Collection.class);
53-
LIST = from(List.class);
54-
SET = from(Set.class);
55-
MAP = from(Map.class);
44+
ClassTypeInformation(Class<?> type) {
45+
this(ResolvableType.forType(type));
5646
}
5747

58-
private final Class<S> type;
59-
6048
ClassTypeInformation(ResolvableType type) {
6149
super(type);
6250
this.type = (Class<S>) type.resolve(Object.class);
@@ -68,13 +56,34 @@ class ClassTypeInformation<S> extends TypeDiscoverer<S> {
6856
* @return
6957
*/
7058
public static <S> ClassTypeInformation<S> from(Class<S> type) {
59+
60+
if (type == Object.class) {
61+
return (ClassTypeInformation<S>) TypeInformation.OBJECT;
62+
} else if (type == List.class) {
63+
return (ClassTypeInformation<S>) TypeInformation.LIST;
64+
} else if (type == Set.class) {
65+
return (ClassTypeInformation<S>) TypeInformation.SET;
66+
} else if (type == Map.class) {
67+
return (ClassTypeInformation<S>) TypeInformation.MAP;
68+
}
69+
7170
return from(resolvableTypeCache.get(type));
7271
}
7372

7473
static <S> ClassTypeInformation<S> from(ResolvableType type) {
7574

7675
Assert.notNull(type, "Type must not be null");
7776

77+
if (type.getType() == Object.class) {
78+
return (ClassTypeInformation<S>) TypeInformation.OBJECT;
79+
} else if (type.getType() == List.class) {
80+
return (ClassTypeInformation<S>) TypeInformation.LIST;
81+
} else if (type.getType() == Set.class) {
82+
return (ClassTypeInformation<S>) TypeInformation.SET;
83+
} else if (type.getType() == Map.class) {
84+
return (ClassTypeInformation<S>) TypeInformation.MAP;
85+
}
86+
7887
return (ClassTypeInformation<S>) cache.get(type);
7988
}
8089

src/main/java/org/springframework/data/util/TypeInformation.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@
4242
*/
4343
public interface TypeInformation<S> {
4444

45-
TypeInformation<Collection> COLLECTION = ClassTypeInformation.COLLECTION;
46-
TypeInformation<List> LIST = ClassTypeInformation.LIST;
47-
TypeInformation<Set> SET = ClassTypeInformation.SET;
48-
TypeInformation<Map> MAP = ClassTypeInformation.MAP;
49-
TypeInformation<Object> OBJECT = ClassTypeInformation.OBJECT;
45+
@SuppressWarnings("rawtypes") TypeInformation<Collection> COLLECTION = new ClassTypeInformation<>(Collection.class);
46+
@SuppressWarnings("rawtypes") TypeInformation<List> LIST = new ClassTypeInformation<>(List.class);
47+
@SuppressWarnings("rawtypes") TypeInformation<Set> SET = new ClassTypeInformation<>(Set.class);
48+
@SuppressWarnings("rawtypes") TypeInformation<Map> MAP = new ClassTypeInformation<>(Map.class);
49+
TypeInformation<Object> OBJECT = new ClassTypeInformation<>(Object.class);
5050

5151
/**
5252
* Creates a new {@link TypeInformation} from the given {@link ResolvableType}.
@@ -55,7 +55,7 @@ public interface TypeInformation<S> {
5555
* @return will never be {@literal null}.
5656
* @since 3.0
5757
*/
58-
public static TypeInformation<?> of(ResolvableType type) {
58+
static TypeInformation<?> of(ResolvableType type) {
5959

6060
Assert.notNull(type, "Type must not be null");
6161

@@ -70,7 +70,7 @@ public static TypeInformation<?> of(ResolvableType type) {
7070
* @return will never be {@literal null}.
7171
* @since 3.0
7272
*/
73-
public static <S> TypeInformation<S> of(Class<S> type) {
73+
static <S> TypeInformation<S> of(Class<S> type) {
7474

7575
Assert.notNull(type, "Type must not be null");
7676

@@ -84,7 +84,7 @@ public static <S> TypeInformation<S> of(Class<S> type) {
8484
* @return will never be {@literal null}.
8585
* @since 3.0
8686
*/
87-
public static TypeInformation<?> fromReturnTypeOf(Method method) {
87+
static TypeInformation<?> fromReturnTypeOf(Method method) {
8888

8989
Assert.notNull(method, "Method must not be null");
9090

@@ -99,7 +99,7 @@ public static TypeInformation<?> fromReturnTypeOf(Method method) {
9999
* @return will never be {@literal null}.
100100
* @since 3.0
101101
*/
102-
public static TypeInformation<?> fromReturnTypeOf(Method method, @Nullable Class<?> type) {
102+
static TypeInformation<?> fromReturnTypeOf(Method method, @Nullable Class<?> type) {
103103

104104
ResolvableType intermediate = type == null ? ResolvableType.forMethodReturnType(method)
105105
: ResolvableType.forMethodReturnType(method, type);
@@ -114,7 +114,7 @@ public static TypeInformation<?> fromReturnTypeOf(Method method, @Nullable Class
114114
* @return will never be {@literal null}.
115115
* @since 3.0
116116
*/
117-
public static TypeInformation<?> fromMethodParameter(MethodParameter parameter) {
117+
static TypeInformation<?> fromMethodParameter(MethodParameter parameter) {
118118
return TypeInformation.of(ResolvableType.forMethodParameter(parameter));
119119
}
120120

src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,24 @@
4545
*/
4646
public class ClassTypeInformationUnitTests {
4747

48+
@Test // GH-3340
49+
void typeInformationConstantsShouldNotBeNull() {
50+
51+
assertThat(ClassTypeInformation.COLLECTION).isNotNull();
52+
assertThat(TypeInformation.COLLECTION).isNotNull();
53+
assertThat(TypeInformation.LIST).isNotNull();
54+
assertThat(TypeInformation.SET).isNotNull();
55+
assertThat(TypeInformation.MAP).isNotNull();
56+
assertThat(TypeInformation.OBJECT).isNotNull();
57+
assertThat(ClassTypeInformation.OBJECT).isNotNull();
58+
59+
assertThat(TypeInformation.COLLECTION).isEqualTo(ClassTypeInformation.COLLECTION);
60+
assertThat(TypeInformation.LIST).isEqualTo(ClassTypeInformation.LIST);
61+
assertThat(TypeInformation.SET).isEqualTo(ClassTypeInformation.SET);
62+
assertThat(TypeInformation.MAP).isEqualTo(ClassTypeInformation.MAP);
63+
assertThat(TypeInformation.OBJECT).isEqualTo(ClassTypeInformation.OBJECT);
64+
}
65+
4866
@Test
4967
public void discoversTypeForSimpleGenericField() {
5068

0 commit comments

Comments
 (0)