Skip to content

Commit de90e58

Browse files
Thomas Darimontodrotbohm
authored andcommitted
DATACMNS-406 - Tighten contract for RepositoryMetadata implementations.
We now resolve the domain and id-types eagerly within the constructor of AbstractRepositoryMetadata implementations to prevent a RepositoryMetadata instance to be created in an invalid state. Pulled-up repositoryInterface property to AbstractRepositoryMetadata. Original pull request: #58.
1 parent 88c2c0e commit de90e58

File tree

6 files changed

+114
-56
lines changed

6 files changed

+114
-56
lines changed

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2011 the original author or authors.
2+
* Copyright 2011-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,10 +26,12 @@
2626
* Base class for {@link RepositoryMetadata} implementations.
2727
*
2828
* @author Oliver Gierke
29+
* @author Thomas Darimont
2930
*/
3031
public abstract class AbstractRepositoryMetadata implements RepositoryMetadata {
3132

3233
private final TypeInformation<?> typeInformation;
34+
private final Class<?> repositoryInterface;
3335

3436
/**
3537
* Creates a new {@link AbstractRepositoryMetadata}.
@@ -40,6 +42,8 @@ public AbstractRepositoryMetadata(Class<?> repositoryInterface) {
4042

4143
Assert.notNull(repositoryInterface, "Given type must not be null!");
4244
Assert.isTrue(repositoryInterface.isInterface(), "Given type must be an interface!");
45+
46+
this.repositoryInterface = repositoryInterface;
4347
this.typeInformation = ClassTypeInformation.from(repositoryInterface);
4448
}
4549

@@ -54,4 +58,11 @@ public Class<?> getReturnedDomainClass(Method method) {
5458

5559
return Iterable.class.isAssignableFrom(rawType) ? returnTypeInfo.getComponentType().getType() : rawType;
5660
}
61+
62+
/* (non-Javadoc)
63+
* @see org.springframework.data.repository.core.RepositoryMetadata#getRepositoryInterface()
64+
*/
65+
public Class<?> getRepositoryInterface() {
66+
return this.repositoryInterface;
67+
}
5768
}

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

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2011-2012 the original author or authors.
2+
* Copyright 2011-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,13 +26,15 @@
2626
* {@link RepositoryDefinition} annotation.
2727
*
2828
* @author Oliver Gierke
29+
* @author Thomas Darimont
2930
*/
3031
public class AnnotationRepositoryMetadata extends AbstractRepositoryMetadata {
3132

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

35-
private final Class<?> repositoryInterface;
36+
private final Class<? extends Serializable> idType;
37+
private final Class<?> domainType;
3638

3739
/**
3840
* Creates a new {@link AnnotationRepositoryMetadata} instance looking up repository types from a
@@ -41,34 +43,59 @@ public class AnnotationRepositoryMetadata extends AbstractRepositoryMetadata {
4143
* @param repositoryInterface must not be {@literal null}.
4244
*/
4345
public AnnotationRepositoryMetadata(Class<?> repositoryInterface) {
46+
4447
super(repositoryInterface);
4548
Assert.isTrue(repositoryInterface.isAnnotationPresent(RepositoryDefinition.class), NO_ANNOTATION_FOUND);
46-
this.repositoryInterface = repositoryInterface;
49+
50+
this.idType = resolveIdType(repositoryInterface);
51+
this.domainType = resolveDomainType(repositoryInterface);
4752
}
4853

49-
/*
54+
/*
5055
* (non-Javadoc)
51-
* @see org.springframework.data.repository.support.RepositoryMetadata#getIdClass()
56+
* @see org.springframework.data.repository.core.RepositoryMetadata#getIdType()
5257
*/
58+
@Override
5359
public Class<? extends Serializable> getIdType() {
54-
RepositoryDefinition annotation = repositoryInterface.getAnnotation(RepositoryDefinition.class);
55-
return annotation == null ? null : annotation.idClass();
60+
return this.idType;
5661
}
5762

58-
/*
63+
/*
5964
* (non-Javadoc)
60-
* @see org.springframework.data.repository.support.RepositoryMetadata#getDomainClass()
65+
* @see org.springframework.data.repository.core.RepositoryMetadata#getDomainType()
6166
*/
67+
@Override
6268
public Class<?> getDomainType() {
69+
return this.domainType;
70+
}
71+
72+
/**
73+
* @param repositoryInterface must not be {@literal null}.
74+
* @return the resolved domain type, never {@literal null}.
75+
*/
76+
private Class<? extends Serializable> resolveIdType(Class<?> repositoryInterface) {
77+
78+
Assert.notNull(repositoryInterface, "Repository interface must not be null!");
79+
6380
RepositoryDefinition annotation = repositoryInterface.getAnnotation(RepositoryDefinition.class);
64-
return annotation == null ? null : annotation.domainClass();
81+
Assert.isTrue(annotation != null && annotation.idClass() != null,
82+
String.format("Could not resolve id type of %s!", repositoryInterface));
83+
84+
return annotation.idClass();
6585
}
6686

67-
/*
68-
* (non-Javadoc)
69-
* @see org.springframework.data.repository.support.RepositoryMetadata#getRepositoryInterface()
87+
/**
88+
* @param repositoryInterface must not be {@literal null}.
89+
* @return the resolved domain type, never {@literal null}.
7090
*/
71-
public Class<?> getRepositoryInterface() {
72-
return repositoryInterface;
91+
private Class<?> resolveDomainType(Class<?> repositoryInterface) {
92+
93+
Assert.notNull(repositoryInterface, "Repository interface must not be null!");
94+
95+
RepositoryDefinition annotation = repositoryInterface.getAnnotation(RepositoryDefinition.class);
96+
Assert.isTrue(annotation != null && annotation.domainClass() != null,
97+
String.format("Could not resolve domain type of %s!", repositoryInterface));
98+
99+
return annotation.domainClass();
73100
}
74101
}

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

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
* Default implementation of {@link RepositoryInformation}.
4141
*
4242
* @author Oliver Gierke
43+
* @author Thomas Darimont
4344
*/
4445
class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements RepositoryInformation {
4546

@@ -76,15 +77,6 @@ public DefaultRepositoryInformation(RepositoryMetadata metadata, Class<?> reposi
7677
this.crudMethods = new DefaultCrudMethods(this);
7778
}
7879

79-
/*
80-
* (non-Javadoc)
81-
* @see org.springframework.data.repository.support.RepositoryMetadata#getRepositoryInterface()
82-
*/
83-
@Override
84-
public Class<?> getRepositoryInterface() {
85-
return metadata.getRepositoryInterface();
86-
}
87-
8880
/*
8981
* (non-Javadoc)
9082
* @see org.springframework.data.repository.support.RepositoryMetadata#getDomainClass()

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

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2011-2012 the original author or authors.
2+
* Copyright 2011-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,10 +28,15 @@
2828
* about domain and id class.
2929
*
3030
* @author Oliver Gierke
31+
* @author Thomas Darimont
3132
*/
3233
public class DefaultRepositoryMetadata extends AbstractRepositoryMetadata {
3334

34-
private final Class<?> repositoryInterface;
35+
private static final String MUST_BE_A_REPOSITORY = String.format("Given type must be assignable to %s!",
36+
Repository.class);
37+
38+
private final Class<? extends Serializable> idType;
39+
private final Class<?> domainType;
3540

3641
/**
3742
* Creates a new {@link DefaultRepositoryMetadata} for the given repository interface.
@@ -41,38 +46,57 @@ public class DefaultRepositoryMetadata extends AbstractRepositoryMetadata {
4146
public DefaultRepositoryMetadata(Class<?> repositoryInterface) {
4247

4348
super(repositoryInterface);
44-
Assert.isTrue(repositoryInterface.isInterface());
45-
Assert.isTrue(Repository.class.isAssignableFrom(repositoryInterface));
46-
this.repositoryInterface = repositoryInterface;
49+
Assert.isTrue(Repository.class.isAssignableFrom(repositoryInterface), MUST_BE_A_REPOSITORY);
50+
51+
this.idType = resolveIdType(repositoryInterface);
52+
this.domainType = resolveDomainType(repositoryInterface);
4753
}
4854

49-
/*
55+
/*
5056
* (non-Javadoc)
51-
* @see org.springframework.data.repository.support.RepositoryMetadata#getRepositoryInterface()
57+
* @see org.springframework.data.repository.core.RepositoryMetadata#getDomainType()
5258
*/
53-
public Class<?> getRepositoryInterface() {
54-
55-
return repositoryInterface;
59+
@Override
60+
public Class<?> getDomainType() {
61+
return this.domainType;
5662
}
5763

58-
/*
64+
/*
5965
* (non-Javadoc)
60-
* @see org.springframework.data.repository.support.RepositoryMetadata#getDomainClass()
66+
* @see org.springframework.data.repository.core.RepositoryMetadata#getIdType()
6167
*/
62-
public Class<?> getDomainType() {
68+
@Override
69+
public Class<? extends Serializable> getIdType() {
70+
return this.idType;
71+
}
72+
73+
/**
74+
* @param repositoryInterface must not be {@literal null}.
75+
* @return the resolved domain type, never {@literal null}.
76+
*/
77+
private Class<?> resolveDomainType(Class<?> repositoryInterface) {
78+
79+
Assert.notNull(repositoryInterface, "Repository interface must not be null!");
6380

6481
Class<?>[] arguments = resolveTypeArguments(repositoryInterface, Repository.class);
65-
return arguments == null ? null : arguments[0];
82+
Assert.isTrue(arguments != null && arguments[0] != null,
83+
String.format("Could not resolve domain type of %s!", repositoryInterface));
84+
85+
return arguments[0];
6686
}
6787

68-
/*
69-
* (non-Javadoc)
70-
* @see org.springframework.data.repository.support.RepositoryMetadata#getIdClass()
88+
/**
89+
* @param repositoryInterface must not be {@literal null}.
90+
* @return the resolved id type, never {@literal null}.
7191
*/
72-
@SuppressWarnings("unchecked")
73-
public Class<? extends Serializable> getIdType() {
92+
private Class<? extends Serializable> resolveIdType(Class<?> repositoryInterface) {
93+
94+
Assert.notNull(repositoryInterface, "Repository interface must not be null!");
7495

7596
Class<?>[] arguments = resolveTypeArguments(repositoryInterface, Repository.class);
76-
return (Class<? extends Serializable>) (arguments == null ? null : arguments[1]);
97+
Assert.isTrue(arguments != null && arguments[1] != null,
98+
String.format("Could not resolve id type of %s!", repositoryInterface));
99+
100+
return (Class<? extends Serializable>) arguments[1];
77101
}
78102
}

src/test/java/org/springframework/data/repository/core/support/AbstractRepositoryMetadataUnitTests.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2011-2012 the original author or authors.
2+
* Copyright 2011-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
3434
* Unit tests for {@link AbstractRepositoryMetadata}.
3535
*
3636
* @author Oliver Gierke
37+
* @author Thomas Darimont
3738
*/
3839
public class AbstractRepositoryMetadataUnitTests {
3940

@@ -118,10 +119,6 @@ public Class<? extends Serializable> getIdType() {
118119
public Class<?> getDomainType() {
119120
return null;
120121
}
121-
122-
public Class<?> getRepositoryInterface() {
123-
return null;
124-
}
125122
}
126123

127124
}

src/test/java/org/springframework/data/repository/core/support/DefaultRepositoryMetadataUnitTests.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2011-2012 the original author or authors.
2+
* Copyright 2011-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,13 +24,15 @@
2424
import org.springframework.data.domain.Page;
2525
import org.springframework.data.domain.Pageable;
2626
import org.springframework.data.repository.CrudRepository;
27+
import org.springframework.data.repository.Repository;
2728
import org.springframework.data.repository.core.RepositoryMetadata;
2829
import org.springframework.data.repository.util.ClassUtils;
2930

3031
/**
3132
* Unit tests for {@link DefaultRepositoryMetadata}.
3233
*
3334
* @author Oliver Gierke
35+
* @author Thomas Darimont
3436
*/
3537
public class DefaultRepositoryMetadataUnitTests {
3638

@@ -50,6 +52,14 @@ public void rejectsNonRepositoryInterface() {
5052
new DefaultRepositoryMetadata(Collection.class);
5153
}
5254

55+
/**
56+
* @see DATACMNS-406
57+
*/
58+
@Test(expected = IllegalArgumentException.class)
59+
public void rejectsUnparameterizedRepositoryInterface() {
60+
new DefaultRepositoryMetadata(Repository.class);
61+
}
62+
5363
@Test
5464
public void looksUpDomainClassCorrectly() throws Exception {
5565

@@ -137,10 +147,7 @@ public T findOne(ID id) {
137147
*
138148
* @author Oliver Gierke
139149
*/
140-
static class GenericEntity<T> {
141-
}
150+
static class GenericEntity<T> {}
142151

143-
static interface GenericEntityRepository extends CrudRepository<GenericEntity<String>, Long> {
144-
145-
}
152+
static interface GenericEntityRepository extends CrudRepository<GenericEntity<String>, Long> {}
146153
}

0 commit comments

Comments
 (0)