Skip to content

Commit d19cd4e

Browse files
Alex Nisticoodrotbohm
authored andcommitted
Use full type information for identifier and domain types exposed byRepositoryMetadata.
See #2518. $ Conflicts: $ src/test/java/org/springframework/data/repository/core/support/AbstractRepositoryMetadataUnitTests.java
1 parent 0ae04a2 commit d19cd4e

17 files changed

+154
-82
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
@@ -58,7 +61,7 @@ public AnnotationRepositoryMetadata(Class<?> repositoryInterface) {
5861
* @see org.springframework.data.repository.core.RepositoryMetadata#getIdType()
5962
*/
6063
@Override
61-
public Class<?> getIdType() {
64+
public TypeInformation<?> getIdTypeInformation() {
6265
return this.idType;
6366
}
6467

@@ -67,29 +70,29 @@ public Class<?> getIdType() {
6770
* @see org.springframework.data.repository.core.RepositoryMetadata#getDomainType()
6871
*/
6972
@Override
70-
public Class<?> getDomainType() {
73+
public TypeInformation<?> getDomainTypeInformation() {
7174
return this.domainType;
7275
}
7376

74-
private Class<?> resolveIdType(Class<?> repositoryInterface) {
77+
private TypeInformation<?> resolveIdType(Class<?> repositoryInterface) {
7578

7679
RepositoryDefinition annotation = AnnotationUtils.findAnnotation(repositoryInterface, RepositoryDefinition.class);
7780

7881
if (annotation == null || annotation.idClass() == null) {
7982
throw new IllegalArgumentException(String.format("Could not resolve id type of %s!", repositoryInterface));
8083
}
8184

82-
return annotation.idClass();
85+
return ClassTypeInformation.from(annotation.idClass());
8386
}
8487

85-
private Class<?> resolveDomainType(Class<?> repositoryInterface) {
88+
private TypeInformation<?> resolveDomainType(Class<?> repositoryInterface) {
8689

8790
RepositoryDefinition annotation = AnnotationUtils.findAnnotation(repositoryInterface, RepositoryDefinition.class);
8891

8992
if (annotation == null || annotation.domainClass() == null) {
9093
throw new IllegalArgumentException(String.format("Could not resolve domain type of %s!", repositoryInterface));
9194
}
9295

93-
return annotation.domainClass();
96+
return ClassTypeInformation.from(annotation.domainClass());
9497
}
9598
}

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

@@ -80,17 +81,17 @@ public DefaultRepositoryInformation(RepositoryMetadata metadata, Class<?> reposi
8081
* @see org.springframework.data.repository.support.RepositoryMetadata#getDomainClass()
8182
*/
8283
@Override
83-
public Class<?> getDomainType() {
84-
return metadata.getDomainType();
84+
public TypeInformation<?> getDomainTypeInformation() {
85+
return metadata.getDomainTypeInformation();
8586
}
8687

8788
/*
8889
* (non-Javadoc)
8990
* @see org.springframework.data.repository.support.RepositoryMetadata#getIdClass()
9091
*/
9192
@Override
92-
public Class<?> getIdType() {
93-
return metadata.getIdType();
93+
public TypeInformation<?> getIdTypeInformation() {
94+
return metadata.getIdTypeInformation();
9495
}
9596

9697
/*

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 {
@@ -117,6 +120,12 @@ public void setApplicationContext(ApplicationContext context) {
117120
return repositories;
118121
});
119122
}
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+
}
120129

121130
/**
122131
* Converter to create domain types from any source that can be converted into the domain types identifier type.
@@ -172,8 +181,9 @@ public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDe
172181
Class<?> domainType = targetType.getType();
173182
RepositoryInvoker invoker = repositoryInvokerFactory.getInvokerFor(domainType);
174183
RepositoryInformation information = repositories.getRequiredRepositoryInformation(domainType);
184+
TypeDescriptor idTypeDescriptor = getIdTypeDescriptor(information);
175185

176-
Object id = conversionService.convert(source, information.getIdType());
186+
Object id = conversionService.convert(source, sourceType, idTypeDescriptor);
177187

178188
return id == null ? null : invoker.invokeFindById(id).orElse(null);
179189
}
@@ -199,10 +209,10 @@ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
199209

200210
return repositoryInformation.map(it -> {
201211

202-
Class<?> rawIdType = it.getIdType();
212+
TypeDescriptor idTypeDescriptor = getIdTypeDescriptor(it);
203213

204-
return sourceType.equals(TypeDescriptor.valueOf(rawIdType))
205-
|| conversionService.canConvert(sourceType.getType(), rawIdType);
214+
return sourceType.equals(idTypeDescriptor)
215+
|| conversionService.canConvert(sourceType, idTypeDescriptor);
206216
}).orElseThrow(
207217
() -> new IllegalStateException(String.format("Couldn't find RepositoryInformation for %s!", domainType)));
208218
}
@@ -254,8 +264,8 @@ public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDe
254264
Class<?> domainType = sourceType.getType();
255265

256266
EntityInformation<Object, ?> entityInformation = repositories.getEntityInformationFor(domainType);
257-
258-
return conversionService.convert(entityInformation.getId(source), targetType.getType());
267+
Object id = entityInformation.getId(source);
268+
return conversionService.convert(id, TypeDescriptor.forObject(id), targetType);
259269
}
260270

261271
/*
@@ -279,10 +289,10 @@ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
279289

280290
return information.map(it -> {
281291

282-
Class<?> rawIdType = it.getIdType();
292+
TypeDescriptor idTypeDescriptor = getIdTypeDescriptor(it);
283293

284-
return targetType.equals(TypeDescriptor.valueOf(rawIdType))
285-
|| conversionService.canConvert(rawIdType, targetType.getType());
294+
return targetType.equals(idTypeDescriptor)
295+
|| conversionService.canConvert(idTypeDescriptor, targetType);
286296

287297
}).orElseThrow(
288298
() -> 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

@@ -285,16 +289,17 @@ private <T> Optional<T> returnAsOptional(@Nullable Object source) {
285289
protected Object convertId(Object id) {
286290

287291
Assert.notNull(id, "Id must not be null!");
292+
TypeDescriptor idDescriptor = TypeDescriptor.forObject(id);
288293

289-
if (idType.isInstance(id)) {
294+
if (idDescriptor.isAssignableTo(idTypeDescriptor)) {
290295
return id;
291296
}
292297

293-
Object result = conversionService.convert(id, idType);
298+
Object result = conversionService.convert(id, idDescriptor, idTypeDescriptor);
294299

295300
if (result == null) {
296301
throw new IllegalStateException(
297-
String.format("Identifier conversion of %s to %s unexpectedly returned null!", id, idType));
302+
String.format("Identifier conversion of %s to %s unexpectedly returned null!", id, idTypeDescriptor.getType()));
298303
}
299304

300305
return result;

0 commit comments

Comments
 (0)