Skip to content

Commit 58ed9ce

Browse files
Alex Nisticoodrotbohm
Alex Nistico
authored andcommitted
Use full type information for identifier and domain types exposed byRepositoryMetadata.
See #2518.
1 parent 21e4fd5 commit 58ed9ce

17 files changed

+161
-92
lines changed

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

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,29 +27,48 @@
2727
*
2828
* @author Oliver Gierke
2929
* @author Mark Paluch
30+
* @author Alessandro Nistico
3031
*/
3132
public interface RepositoryMetadata {
3233

3334
/**
34-
* Returns the id class the given class is declared for.
35+
* Returns the id {@link TypeInformation} the given class is declared for.
3536
*
36-
* @return the id class of the entity managed by the repository.
37+
* @return the {@link TypeInformation} class of the entity managed by the repository.
3738
*/
38-
Class<?> getIdType();
39+
TypeInformation<?> getIdTypeInformation();
3940

4041
/**
41-
* Returns the domain class the repository is declared for.
42+
* Returns the domain {@link TypeInformation} the repository is declared for.
4243
*
4344
* @return the domain class the repository is handling.
4445
*/
45-
Class<?> getDomainType();
46-
46+
TypeInformation<?> getDomainTypeInformation();
47+
4748
/**
4849
* Returns the repository interface.
4950
*
5051
* @return
5152
*/
5253
Class<?> getRepositoryInterface();
54+
55+
/**
56+
* Returns the raw id class the given class is declared for.
57+
*
58+
* @return the raw id class of the entity managed by the repository.
59+
*/
60+
default Class<?> getIdType() {
61+
return getIdTypeInformation().getType();
62+
}
63+
64+
/**
65+
* Returns the raw domain class the repository is declared for.
66+
*
67+
* @return the raw domain class the repository is handling.
68+
*/
69+
default Class<?> getDomainType() {
70+
return getDomainTypeInformation().getType();
71+
}
5372

5473
/**
5574
* Returns the type {@link Method} return type as it is declared in the repository. Considers suspended methods and

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

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import org.springframework.core.annotation.AnnotationUtils;
1919
import org.springframework.data.repository.RepositoryDefinition;
2020
import org.springframework.data.repository.core.RepositoryMetadata;
21+
import org.springframework.data.util.ClassTypeInformation;
22+
import org.springframework.data.util.TypeInformation;
2123
import org.springframework.util.Assert;
2224

2325
/**
@@ -27,14 +29,15 @@
2729
* @author Oliver Gierke
2830
* @author Thomas Darimont
2931
* @author Xeno Amess
32+
* @author Alessandro Nistico
3033
*/
3134
public class AnnotationRepositoryMetadata extends AbstractRepositoryMetadata {
3235

3336
private static final String NO_ANNOTATION_FOUND = String.format("Interface %%s must be annotated with @%s!",
3437
RepositoryDefinition.class.getName());
3538

36-
private final Class<?> idType;
37-
private final Class<?> domainType;
39+
private final TypeInformation<?> idType;
40+
private final TypeInformation<?> domainType;
3841

3942
/**
4043
* Creates a new {@link AnnotationRepositoryMetadata} instance looking up repository types from a
@@ -54,34 +57,34 @@ public AnnotationRepositoryMetadata(Class<?> repositoryInterface) {
5457
}
5558

5659
@Override
57-
public Class<?> getIdType() {
60+
public TypeInformation<?> getIdTypeInformation() {
5861
return this.idType;
5962
}
6063

6164
@Override
62-
public Class<?> getDomainType() {
65+
public TypeInformation<?> getDomainTypeInformation() {
6366
return this.domainType;
6467
}
6568

66-
private Class<?> resolveIdType(Class<?> repositoryInterface) {
69+
private TypeInformation<?> resolveIdType(Class<?> repositoryInterface) {
6770

6871
RepositoryDefinition annotation = AnnotationUtils.findAnnotation(repositoryInterface, RepositoryDefinition.class);
6972

7073
if (annotation == null || annotation.idClass() == null) {
7174
throw new IllegalArgumentException(String.format("Could not resolve id type of %s!", repositoryInterface));
7275
}
7376

74-
return annotation.idClass();
77+
return ClassTypeInformation.from(annotation.idClass());
7578
}
7679

77-
private Class<?> resolveDomainType(Class<?> repositoryInterface) {
80+
private TypeInformation<?> resolveDomainType(Class<?> repositoryInterface) {
7881

7982
RepositoryDefinition annotation = AnnotationUtils.findAnnotation(repositoryInterface, RepositoryDefinition.class);
8083

8184
if (annotation == null || annotation.domainClass() == null) {
8285
throw new IllegalArgumentException(String.format("Could not resolve domain type of %s!", repositoryInterface));
8386
}
8487

85-
return annotation.domainClass();
88+
return ClassTypeInformation.from(annotation.domainClass());
8689
}
8790
}

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
* @author Thomas Darimont
4444
* @author Mark Paluch
4545
* @author Christoph Strobl
46+
* @author Alessandro Nistico
4647
*/
4748
class DefaultRepositoryInformation implements RepositoryInformation {
4849

@@ -76,13 +77,13 @@ public DefaultRepositoryInformation(RepositoryMetadata metadata, Class<?> reposi
7677
}
7778

7879
@Override
79-
public Class<?> getDomainType() {
80-
return metadata.getDomainType();
80+
public TypeInformation<?> getDomainTypeInformation() {
81+
return metadata.getDomainTypeInformation();
8182
}
8283

8384
@Override
84-
public Class<?> getIdType() {
85-
return metadata.getIdType();
85+
public TypeInformation<?> getIdTypeInformation() {
86+
return metadata.getIdTypeInformation();
8687
}
8788

8889
@Override

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,15 @@
3030
*
3131
* @author Oliver Gierke
3232
* @author Thomas Darimont
33+
* @author Alessandro Nistico
3334
*/
3435
public class DefaultRepositoryMetadata extends AbstractRepositoryMetadata {
3536

3637
private static final String MUST_BE_A_REPOSITORY = String.format("Given type must be assignable to %s!",
3738
Repository.class);
3839

39-
private final Class<?> idType;
40-
private final Class<?> domainType;
40+
private final TypeInformation<?> idType;
41+
private final TypeInformation<?> domainType;
4142

4243
/**
4344
* Creates a new {@link DefaultRepositoryMetadata} for the given repository interface.
@@ -49,31 +50,32 @@ public DefaultRepositoryMetadata(Class<?> repositoryInterface) {
4950
super(repositoryInterface);
5051
Assert.isTrue(Repository.class.isAssignableFrom(repositoryInterface), MUST_BE_A_REPOSITORY);
5152

52-
List<TypeInformation<?>> arguments = ClassTypeInformation.from(repositoryInterface) //
53+
List<TypeInformation<?>> arguments = ClassTypeInformation.from(repositoryInterface)//
5354
.getRequiredSuperTypeInformation(Repository.class)//
5455
.getTypeArguments();
5556

5657
this.domainType = resolveTypeParameter(arguments, 0,
5758
() -> String.format("Could not resolve domain type of %s!", repositoryInterface));
59+
5860
this.idType = resolveTypeParameter(arguments, 1,
5961
() -> String.format("Could not resolve id type of %s!", repositoryInterface));
6062
}
6163

62-
private static Class<?> resolveTypeParameter(List<TypeInformation<?>> arguments, int index,
64+
private static TypeInformation<?> resolveTypeParameter(List<TypeInformation<?>> arguments, int index,
6365
Supplier<String> exceptionMessage) {
6466

6567
if (arguments.size() <= index || arguments.get(index) == null) {
6668
throw new IllegalArgumentException(exceptionMessage.get());
6769
}
6870

69-
return arguments.get(index).getType();
71+
return arguments.get(index).getGenericTypeInformation();
7072
}
7173

72-
public Class<?> getIdType() {
74+
public TypeInformation<?> getIdTypeInformation() {
7375
return this.idType;
7476
}
7577

76-
public Class<?> getDomainType() {
78+
public TypeInformation<?> getDomainTypeInformation() {
7779
return this.domainType;
7880
}
7981
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
*
4646
* @author Mark Paluch
4747
* @author Oliver Gierke
48+
* @author Alessandro Nistico
4849
* @since 2.0
4950
*/
5051
interface MethodLookups {
@@ -120,8 +121,8 @@ public RepositoryAwareMethodLookup(RepositoryMetadata repositoryMetadata) {
120121

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

123-
this.entityType = ResolvableType.forClass(repositoryMetadata.getDomainType());
124-
this.idType = ResolvableType.forClass(repositoryMetadata.getIdType());
124+
this.entityType = ResolvableType.forType(repositoryMetadata.getDomainTypeInformation().getGenericType());
125+
this.idType = ResolvableType.forType(repositoryMetadata.getIdTypeInformation().getGenericType());
125126
this.repositoryInterface = repositoryMetadata.getRepositoryInterface();
126127
}
127128

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

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

2222
import org.springframework.context.ApplicationContext;
2323
import org.springframework.context.ApplicationContextAware;
24+
import org.springframework.core.ResolvableType;
2425
import org.springframework.core.convert.ConversionService;
2526
import org.springframework.core.convert.TypeDescriptor;
2627
import org.springframework.core.convert.converter.ConditionalGenericConverter;
@@ -29,6 +30,7 @@
2930
import org.springframework.data.repository.core.EntityInformation;
3031
import org.springframework.data.repository.core.RepositoryInformation;
3132
import org.springframework.data.util.Lazy;
33+
import org.springframework.data.util.TypeInformation;
3234
import org.springframework.lang.NonNull;
3335
import org.springframework.lang.Nullable;
3436
import org.springframework.util.Assert;
@@ -42,6 +44,7 @@
4244
*
4345
* @author Oliver Gierke
4446
* @author Thomas Darimont
47+
* @author Alessandro Nistico
4548
*/
4649
public class DomainClassConverter<T extends ConversionService & ConverterRegistry>
4750
implements ConditionalGenericConverter, ApplicationContextAware {
@@ -101,6 +104,12 @@ public void setApplicationContext(ApplicationContext context) {
101104
return repositories;
102105
});
103106
}
107+
108+
109+
private static TypeDescriptor getIdTypeDescriptor(RepositoryInformation information) {
110+
TypeInformation<?> idType = information.getIdTypeInformation();
111+
return new TypeDescriptor(ResolvableType.forType(idType.getGenericType()), null, idType.getType().getAnnotations());
112+
}
104113

105114
/**
106115
* Converter to create domain types from any source that can be converted into the domain types identifier type.
@@ -148,8 +157,9 @@ public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDe
148157
Class<?> domainType = targetType.getType();
149158
RepositoryInvoker invoker = repositoryInvokerFactory.getInvokerFor(domainType);
150159
RepositoryInformation information = repositories.getRequiredRepositoryInformation(domainType);
160+
TypeDescriptor idTypeDescriptor = getIdTypeDescriptor(information);
151161

152-
Object id = conversionService.convert(source, information.getIdType());
162+
Object id = conversionService.convert(source, sourceType, idTypeDescriptor);
153163

154164
return id == null ? null : invoker.invokeFindById(id).orElse(null);
155165
}
@@ -171,10 +181,10 @@ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
171181

172182
return repositoryInformation.map(it -> {
173183

174-
Class<?> rawIdType = it.getIdType();
184+
TypeDescriptor idTypeDescriptor = getIdTypeDescriptor(it);
175185

176-
return sourceType.equals(TypeDescriptor.valueOf(rawIdType))
177-
|| conversionService.canConvert(sourceType.getType(), rawIdType);
186+
return sourceType.equals(idTypeDescriptor)
187+
|| conversionService.canConvert(sourceType, idTypeDescriptor);
178188
}).orElseThrow(
179189
() -> new IllegalStateException(String.format("Couldn't find RepositoryInformation for %s!", domainType)));
180190
}
@@ -218,8 +228,8 @@ public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDe
218228
Class<?> domainType = sourceType.getType();
219229

220230
EntityInformation<Object, ?> entityInformation = repositories.getEntityInformationFor(domainType);
221-
222-
return conversionService.convert(entityInformation.getId(source), targetType.getType());
231+
Object id = entityInformation.getId(source);
232+
return conversionService.convert(id, TypeDescriptor.forObject(id), targetType);
223233
}
224234

225235
@Override
@@ -239,10 +249,10 @@ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
239249

240250
return information.map(it -> {
241251

242-
Class<?> rawIdType = it.getIdType();
252+
TypeDescriptor idTypeDescriptor = getIdTypeDescriptor(it);
243253

244-
return targetType.equals(TypeDescriptor.valueOf(rawIdType))
245-
|| conversionService.canConvert(rawIdType, targetType.getType());
254+
return targetType.equals(idTypeDescriptor)
255+
|| conversionService.canConvert(idTypeDescriptor, targetType);
246256

247257
}).orElseThrow(
248258
() -> new IllegalStateException(String.format("Couldn't find RepositoryInformation for %s!", domainType)));

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

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

2323
import org.springframework.core.MethodParameter;
24+
import org.springframework.core.ResolvableType;
2425
import org.springframework.core.convert.ConversionException;
2526
import org.springframework.core.convert.ConversionService;
2627
import org.springframework.core.convert.TypeDescriptor;
@@ -30,6 +31,7 @@
3031
import org.springframework.data.repository.core.RepositoryMetadata;
3132
import org.springframework.data.repository.query.Param;
3233
import org.springframework.data.repository.util.QueryExecutionConverters;
34+
import org.springframework.data.util.TypeInformation;
3335
import org.springframework.lang.Nullable;
3436
import org.springframework.util.Assert;
3537
import org.springframework.util.ClassUtils;
@@ -41,6 +43,7 @@
4143
* Base {@link RepositoryInvoker} using reflection to invoke methods on Spring Data Repositories.
4244
*
4345
* @author Oliver Gierke
46+
* @author Alessandro Nistico
4447
* @since 1.10
4548
*/
4649
class ReflectionRepositoryInvoker implements RepositoryInvoker {
@@ -50,7 +53,7 @@ class ReflectionRepositoryInvoker implements RepositoryInvoker {
5053

5154
private final Object repository;
5255
private final CrudMethods methods;
53-
private final Class<?> idType;
56+
private final TypeDescriptor idTypeDescriptor;
5457
private final ConversionService conversionService;
5558

5659
/**
@@ -70,7 +73,8 @@ public ReflectionRepositoryInvoker(Object repository, RepositoryMetadata metadat
7073

7174
this.repository = repository;
7275
this.methods = metadata.getCrudMethods();
73-
this.idType = metadata.getIdType();
76+
TypeInformation<?> idType = metadata.getIdTypeInformation();
77+
this.idTypeDescriptor = new TypeDescriptor(ResolvableType.forType(idType.getGenericType()), null, idType.getType().getAnnotations());
7478
this.conversionService = conversionService;
7579
}
7680

@@ -245,16 +249,17 @@ private <T> Optional<T> returnAsOptional(@Nullable Object source) {
245249
protected Object convertId(Object id) {
246250

247251
Assert.notNull(id, "Id must not be null!");
252+
TypeDescriptor idDescriptor = TypeDescriptor.forObject(id);
248253

249-
if (idType.isInstance(id)) {
254+
if (idDescriptor.isAssignableTo(idTypeDescriptor)) {
250255
return id;
251256
}
252257

253-
Object result = conversionService.convert(id, idType);
258+
Object result = conversionService.convert(id, idDescriptor, idTypeDescriptor);
254259

255260
if (result == null) {
256261
throw new IllegalStateException(
257-
String.format("Identifier conversion of %s to %s unexpectedly returned null!", id, idType));
262+
String.format("Identifier conversion of %s to %s unexpectedly returned null!", id, idTypeDescriptor.getType()));
258263
}
259264

260265
return result;

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
* @author Thomas Darimont
4949
* @author Thomas Eizinger
5050
* @author Christoph Strobl
51+
* @author Alessandro Nistico
5152
*/
5253
public class Repositories implements Iterable<Class<?>> {
5354

@@ -102,10 +103,9 @@ private synchronized void cacheRepositoryFactory(String name) {
102103

103104
RepositoryFactoryInformation repositoryFactoryInformation = beanFactory.get().getBean(name,
104105
RepositoryFactoryInformation.class);
105-
Class<?> domainType = ClassUtils
106-
.getUserClass(repositoryFactoryInformation.getRepositoryInformation().getDomainType());
107-
108106
RepositoryInformation information = repositoryFactoryInformation.getRepositoryInformation();
107+
Class<?> domainType = ClassUtils.getUserClass(information.getDomainType());
108+
109109
Set<Class<?>> alternativeDomainTypes = information.getAlternativeDomainTypes();
110110

111111
Set<Class<?>> typesToRegister = new HashSet<>(alternativeDomainTypes.size() + 1);

0 commit comments

Comments
 (0)