Skip to content

Commit 37b072f

Browse files
committed
Polishing for full type information on RepositoryMetadata.
Avoid leaking internals from TypeInformation by exposing a ….toTypeDescriptor() method in TypeInformation directly. This causes the ResolvableType handling to become an implementation detail within ClassTypeInformation and avoid client code to manually deal with both ResolvableType and TypeDescriptor creation. Changed MethodLookups back to use the resolved domain types as the advanced generics resolutions seems not to be needed here and we can avoid Fixes #2518. $ Conflicts: $ src/main/java/org/springframework/data/util/TypeDiscoverer.java
1 parent d19cd4e commit 37b072f

File tree

12 files changed

+116
-106
lines changed

12 files changed

+116
-106
lines changed

src/main/java/org/springframework/data/repository/core/RepositoryMetadata.java

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,6 @@
3131
*/
3232
public interface RepositoryMetadata {
3333

34-
/**
35-
* Returns the id {@link TypeInformation} the given class is declared for.
36-
*
37-
* @return the {@link TypeInformation} class of the entity managed by the repository.
38-
*/
39-
TypeInformation<?> getIdTypeInformation();
40-
41-
/**
42-
* Returns the domain {@link TypeInformation} the repository is declared for.
43-
*
44-
* @return the domain class the repository is handling.
45-
*/
46-
TypeInformation<?> getDomainTypeInformation();
47-
48-
/**
49-
* Returns the repository interface.
50-
*
51-
* @return
52-
*/
53-
Class<?> getRepositoryInterface();
54-
5534
/**
5635
* Returns the raw id class the given class is declared for.
5736
*
@@ -60,7 +39,7 @@ public interface RepositoryMetadata {
6039
default Class<?> getIdType() {
6140
return getIdTypeInformation().getType();
6241
}
63-
42+
6443
/**
6544
* Returns the raw domain class the repository is declared for.
6645
*
@@ -70,6 +49,31 @@ default Class<?> getDomainType() {
7049
return getDomainTypeInformation().getType();
7150
}
7251

52+
/**
53+
* Returns the {@link TypeInformation} of the id type of the repository.
54+
*
55+
* @return the {@link TypeInformation} class of the identifier of the entity managed by the repository. Will never be
56+
* {@literal null}.
57+
* @since 2.7
58+
*/
59+
TypeInformation<?> getIdTypeInformation();
60+
61+
/**
62+
* Returns the {@link TypeInformation}of the domain type the repository is declared to manage. Will never be
63+
* {@literal null}.
64+
*
65+
* @return the domain class the repository is handling.
66+
* @since 2.7
67+
*/
68+
TypeInformation<?> getDomainTypeInformation();
69+
70+
/**
71+
* Returns the repository interface.
72+
*
73+
* @return
74+
*/
75+
Class<?> getRepositoryInterface();
76+
7377
/**
7478
* Returns the type {@link Method} return type as it is declared in the repository. Considers suspended methods and
7579
* does not unwrap component types but leaves those for further inspection.

src/main/java/org/springframework/data/repository/core/support/AnnotationRepositoryMetadata.java

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package org.springframework.data.repository.core.support;
1717

18+
import java.util.function.Function;
19+
1820
import org.springframework.core.annotation.AnnotationUtils;
1921
import org.springframework.data.repository.RepositoryDefinition;
2022
import org.springframework.data.repository.core.RepositoryMetadata;
@@ -52,8 +54,8 @@ public AnnotationRepositoryMetadata(Class<?> repositoryInterface) {
5254
Assert.isTrue(AnnotationUtils.findAnnotation(repositoryInterface, RepositoryDefinition.class) != null,
5355
() -> String.format(NO_ANNOTATION_FOUND, repositoryInterface.getName()));
5456

55-
this.idType = resolveIdType(repositoryInterface);
56-
this.domainType = resolveDomainType(repositoryInterface);
57+
this.idType = resolveType(repositoryInterface, RepositoryDefinition::idClass);
58+
this.domainType = resolveType(repositoryInterface, RepositoryDefinition::domainClass);
5759
}
5860

5961
/*
@@ -74,25 +76,15 @@ public TypeInformation<?> getDomainTypeInformation() {
7476
return this.domainType;
7577
}
7678

77-
private TypeInformation<?> resolveIdType(Class<?> repositoryInterface) {
78-
79-
RepositoryDefinition annotation = AnnotationUtils.findAnnotation(repositoryInterface, RepositoryDefinition.class);
80-
81-
if (annotation == null || annotation.idClass() == null) {
82-
throw new IllegalArgumentException(String.format("Could not resolve id type of %s!", repositoryInterface));
83-
}
84-
85-
return ClassTypeInformation.from(annotation.idClass());
86-
}
87-
88-
private TypeInformation<?> resolveDomainType(Class<?> repositoryInterface) {
79+
private static TypeInformation<?> resolveType(Class<?> repositoryInterface,
80+
Function<RepositoryDefinition, Class<?>> extractor) {
8981

9082
RepositoryDefinition annotation = AnnotationUtils.findAnnotation(repositoryInterface, RepositoryDefinition.class);
9183

92-
if (annotation == null || annotation.domainClass() == null) {
84+
if ((annotation == null) || (extractor.apply(annotation) == null)) {
9385
throw new IllegalArgumentException(String.format("Could not resolve domain type of %s!", repositoryInterface));
9486
}
9587

96-
return ClassTypeInformation.from(annotation.domainClass());
88+
return ClassTypeInformation.from(extractor.apply(annotation));
9789
}
9890
}

src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryMetadata.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,26 +56,28 @@ public DefaultRepositoryMetadata(Class<?> repositoryInterface) {
5656

5757
this.domainType = resolveTypeParameter(arguments, 0,
5858
() -> String.format("Could not resolve domain type of %s!", repositoryInterface));
59-
59+
6060
this.idType = resolveTypeParameter(arguments, 1,
6161
() -> String.format("Could not resolve id type of %s!", repositoryInterface));
6262
}
6363

64-
private static TypeInformation<?> resolveTypeParameter(List<TypeInformation<?>> arguments, int index,
65-
Supplier<String> exceptionMessage) {
66-
67-
if (arguments.size() <= index || arguments.get(index) == null) {
68-
throw new IllegalArgumentException(exceptionMessage.get());
69-
}
70-
71-
return arguments.get(index).getGenericTypeInformation();
72-
}
73-
64+
@Override
7465
public TypeInformation<?> getIdTypeInformation() {
7566
return this.idType;
7667
}
7768

69+
@Override
7870
public TypeInformation<?> getDomainTypeInformation() {
7971
return this.domainType;
8072
}
73+
74+
private static TypeInformation<?> resolveTypeParameter(List<TypeInformation<?>> arguments, int index,
75+
Supplier<String> exceptionMessage) {
76+
77+
if ((arguments.size() <= index) || (arguments.get(index) == null)) {
78+
throw new IllegalArgumentException(exceptionMessage.get());
79+
}
80+
81+
return arguments.get(index);
82+
}
8183
}

src/main/java/org/springframework/data/repository/core/support/MethodLookups.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ public RepositoryAwareMethodLookup(RepositoryMetadata repositoryMetadata) {
121121

122122
Assert.notNull(repositoryMetadata, "Repository metadata must not be null!");
123123

124-
this.entityType = ResolvableType.forType(repositoryMetadata.getDomainTypeInformation().getGenericType());
125-
this.idType = ResolvableType.forType(repositoryMetadata.getIdTypeInformation().getGenericType());
124+
this.entityType = repositoryMetadata.getDomainTypeInformation().toTypeDescriptor().getResolvableType();
125+
this.idType = repositoryMetadata.getIdTypeInformation().toTypeDescriptor().getResolvableType();
126126
this.repositoryInterface = repositoryMetadata.getRepositoryInterface();
127127
}
128128

src/main/java/org/springframework/data/repository/support/DomainClassConverter.java

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
import org.springframework.context.ApplicationContext;
2323
import org.springframework.context.ApplicationContextAware;
24-
import org.springframework.core.ResolvableType;
2524
import org.springframework.core.convert.ConversionService;
2625
import org.springframework.core.convert.TypeDescriptor;
2726
import org.springframework.core.convert.converter.ConditionalGenericConverter;
@@ -30,7 +29,6 @@
3029
import org.springframework.data.repository.core.EntityInformation;
3130
import org.springframework.data.repository.core.RepositoryInformation;
3231
import org.springframework.data.util.Lazy;
33-
import org.springframework.data.util.TypeInformation;
3432
import org.springframework.lang.NonNull;
3533
import org.springframework.lang.Nullable;
3634
import org.springframework.util.Assert;
@@ -120,12 +118,6 @@ public void setApplicationContext(ApplicationContext context) {
120118
return repositories;
121119
});
122120
}
123-
124-
125-
private static TypeDescriptor getIdTypeDescriptor(RepositoryInformation information) {
126-
TypeInformation<?> idType = information.getIdTypeInformation();
127-
return new TypeDescriptor(ResolvableType.forType(idType.getGenericType()), null, idType.getType().getAnnotations());
128-
}
129121

130122
/**
131123
* Converter to create domain types from any source that can be converted into the domain types identifier type.
@@ -181,7 +173,7 @@ public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDe
181173
Class<?> domainType = targetType.getType();
182174
RepositoryInvoker invoker = repositoryInvokerFactory.getInvokerFor(domainType);
183175
RepositoryInformation information = repositories.getRequiredRepositoryInformation(domainType);
184-
TypeDescriptor idTypeDescriptor = getIdTypeDescriptor(information);
176+
TypeDescriptor idTypeDescriptor = information.getIdTypeInformation().toTypeDescriptor();
185177

186178
Object id = conversionService.convert(source, sourceType, idTypeDescriptor);
187179

@@ -209,7 +201,7 @@ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
209201

210202
return repositoryInformation.map(it -> {
211203

212-
TypeDescriptor idTypeDescriptor = getIdTypeDescriptor(it);
204+
TypeDescriptor idTypeDescriptor = it.getIdTypeInformation().toTypeDescriptor();
213205

214206
return sourceType.equals(idTypeDescriptor)
215207
|| conversionService.canConvert(sourceType, idTypeDescriptor);
@@ -289,7 +281,7 @@ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
289281

290282
return information.map(it -> {
291283

292-
TypeDescriptor idTypeDescriptor = getIdTypeDescriptor(it);
284+
TypeDescriptor idTypeDescriptor = it.getIdTypeInformation().toTypeDescriptor();
293285

294286
return targetType.equals(idTypeDescriptor)
295287
|| conversionService.canConvert(idTypeDescriptor, targetType);

src/main/java/org/springframework/data/repository/support/ReflectionRepositoryInvoker.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import java.util.Optional;
2222

2323
import org.springframework.core.MethodParameter;
24-
import org.springframework.core.ResolvableType;
2524
import org.springframework.core.convert.ConversionException;
2625
import org.springframework.core.convert.ConversionService;
2726
import org.springframework.core.convert.TypeDescriptor;
@@ -74,7 +73,7 @@ public ReflectionRepositoryInvoker(Object repository, RepositoryMetadata metadat
7473
this.repository = repository;
7574
this.methods = metadata.getCrudMethods();
7675
TypeInformation<?> idType = metadata.getIdTypeInformation();
77-
this.idTypeDescriptor = new TypeDescriptor(ResolvableType.forType(idType.getGenericType()), null, idType.getType().getAnnotations());
76+
this.idTypeDescriptor = idType.toTypeDescriptor();
7877
this.conversionService = conversionService;
7978
}
8079

@@ -289,7 +288,7 @@ private <T> Optional<T> returnAsOptional(@Nullable Object source) {
289288
protected Object convertId(Object id) {
290289

291290
Assert.notNull(id, "Id must not be null!");
292-
TypeDescriptor idDescriptor = TypeDescriptor.forObject(id);
291+
TypeDescriptor idDescriptor = TypeDescriptor.forObject(id);
293292

294293
if (idDescriptor.isAssignableTo(idTypeDescriptor)) {
295294
return id;
@@ -299,7 +298,8 @@ protected Object convertId(Object id) {
299298

300299
if (result == null) {
301300
throw new IllegalStateException(
302-
String.format("Identifier conversion of %s to %s unexpectedly returned null!", id, idTypeDescriptor.getType()));
301+
String.format("Identifier conversion of %s to %s unexpectedly returned null!", id,
302+
idTypeDescriptor.getType()));
303303
}
304304

305305
return result;

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.Set;
3030

3131
import org.springframework.core.GenericTypeResolver;
32+
import org.springframework.core.convert.TypeDescriptor;
3233
import org.springframework.util.Assert;
3334
import org.springframework.util.ConcurrentReferenceHashMap;
3435
import org.springframework.util.ConcurrentReferenceHashMap.ReferenceType;
@@ -56,6 +57,7 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
5657
}
5758

5859
private final Class<S> type;
60+
private final Lazy<TypeDescriptor> descriptor;
5961

6062
/**
6163
* Simple factory method to easily create new instances of {@link ClassTypeInformation}.
@@ -90,8 +92,11 @@ public static <S> TypeInformation<S> fromReturnTypeOf(Method method) {
9092
* @param type
9193
*/
9294
ClassTypeInformation(Class<S> type) {
95+
9396
super(type, getTypeVariableMap(type));
97+
9498
this.type = type;
99+
this.descriptor = Lazy.of(() -> TypeDescriptor.valueOf(type));
95100
}
96101

97102
/**
@@ -173,6 +178,11 @@ public TypeInformation<? extends S> specialize(ClassTypeInformation<?> type) {
173178
* (non-Javadoc)
174179
* @see java.lang.Object#toString()
175180
*/
181+
@Override
182+
public TypeDescriptor toTypeDescriptor() {
183+
return descriptor.get();
184+
}
185+
176186
@Override
177187
public String toString() {
178188
return type.getName();

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.lang.reflect.TypeVariable;
2020
import java.util.Map;
2121

22+
import org.springframework.core.ResolvableType;
23+
import org.springframework.core.convert.TypeDescriptor;
2224
import org.springframework.lang.Nullable;
2325

2426
/**
@@ -29,6 +31,7 @@
2931
public abstract class ParentTypeAwareTypeInformation<S> extends TypeDiscoverer<S> {
3032

3133
private final TypeDiscoverer<?> parent;
34+
private final Lazy<TypeDescriptor> descriptor;
3235
private int hashCode;
3336

3437
/**
@@ -44,7 +47,14 @@ protected ParentTypeAwareTypeInformation(Type type, TypeDiscoverer<?> parent) {
4447
protected ParentTypeAwareTypeInformation(Type type, TypeDiscoverer<?> parent, Map<TypeVariable<?>, Type> map) {
4548

4649
super(type, map);
50+
4751
this.parent = parent;
52+
this.descriptor = Lazy.of(() -> new TypeDescriptor(toResolvableType(), null, null));
53+
}
54+
55+
@Override
56+
public TypeDescriptor toTypeDescriptor() {
57+
return descriptor.get();
4858
}
4959

5060
/*
@@ -65,6 +75,11 @@ protected TypeInformation<?> createInfo(Type fieldType) {
6575
* (non-Javadoc)
6676
* @see org.springframework.data.util.TypeDiscoverer#equals(java.lang.Object)
6777
*/
78+
@Override
79+
protected ResolvableType toResolvableType() {
80+
return ResolvableType.forType(getType(), parent.toResolvableType());
81+
}
82+
6883
@Override
6984
public boolean equals(@Nullable Object obj) {
7085

@@ -92,7 +107,7 @@ public boolean equals(@Nullable Object obj) {
92107
public int hashCode() {
93108

94109
if (this.hashCode == 0) {
95-
this.hashCode = super.hashCode() + 31 * parent.hashCode();
110+
this.hashCode = super.hashCode() + (31 * parent.hashCode());
96111
}
97112

98113
return this.hashCode;

0 commit comments

Comments
 (0)