Skip to content

Commit 8ef563b

Browse files
committed
Reinstate implicit association type lookup.
We now determine the association target type from the actual property type if the property reports that it is an association and the target type is an entity. The previous change removed this behavior so we're reinstating it here. See #2344.
1 parent 0ab31bb commit 8ef563b

File tree

3 files changed

+67
-36
lines changed

3 files changed

+67
-36
lines changed

src/main/java/org/springframework/data/mapping/model/AbstractPersistentProperty.java

+16-7
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,22 @@ public AbstractPersistentProperty(Property property, PersistentEntity<?, P> owne
8989
this.usePropertyAccess = Lazy.of(() -> owner.getType().isInterface() || CAUSE_FIELD.equals(getField()));
9090

9191
this.isAssociation = Lazy.of(() -> ASSOCIATION_TYPE != null && ASSOCIATION_TYPE.isAssignableFrom(rawType));
92-
this.associationTargetType = ASSOCIATION_TYPE == null
93-
? Lazy.empty()
94-
: Lazy.of(() -> Optional.of(getTypeInformation())
95-
.map(it -> it.getSuperTypeInformation(ASSOCIATION_TYPE))
96-
.map(TypeInformation::getComponentType)
97-
.map(TypeInformation::getType)
98-
.orElse(null));
92+
93+
this.associationTargetType = Lazy.of(() -> {
94+
95+
Class<?> targetType = ASSOCIATION_TYPE == null ? null
96+
: Optional.of(getTypeInformation()) //
97+
.map(it -> it.getSuperTypeInformation(ASSOCIATION_TYPE)) //
98+
.map(TypeInformation::getComponentType) //
99+
.map(TypeInformation::getType) //
100+
.orElse(null);
101+
102+
if (targetType == null && isEntity() && isAssociation()) {
103+
return getActualType();
104+
}
105+
106+
return targetType;
107+
});
99108

100109
this.entityTypeInformation = Lazy.of(() -> Optional.ofNullable(information.getActualType())//
101110
.filter(it -> !simpleTypeHolder.isSimpleType(it.getType()))//

src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public abstract class AnnotationBasedPersistentProperty<P extends PersistentProp
8484
.map(this::findAnnotation) //
8585
.map(Reference::to) //
8686
.map(it -> !Class.class.equals(it) ? it : getActualType()) //
87-
.orElseGet(() -> super.getAssociationTargetType());
87+
.orElseGet(super::getAssociationTargetType);
8888
});
8989

9090
/**

src/test/java/org/springframework/data/mapping/model/AbstractPersistentPropertyUnitTests.java

+50-28
Original file line numberDiff line numberDiff line change
@@ -68,43 +68,43 @@ void setUp() {
6868

6969
@Test // DATACMNS-68
7070
void discoversComponentTypeCorrectly() {
71-
assertThat(getProperty(TestClassComplex.class, "testClassSet").getComponentType()).isEqualTo(Object.class);
71+
assertThat(createProperty(TestClassComplex.class, "testClassSet").getComponentType()).isEqualTo(Object.class);
7272
}
7373

7474
@Test // DATACMNS-101
7575
void returnsNestedEntityTypeCorrectly() {
76-
assertThat(getProperty(TestClassComplex.class, "testClassSet").getPersistentEntityTypes()).isEmpty();
76+
assertThat(createProperty(TestClassComplex.class, "testClassSet").getPersistentEntityTypes()).isEmpty();
7777
}
7878

7979
@Test // DATACMNS-132
8080
void isEntityWorksForUntypedMaps() {
81-
assertThat(getProperty(TestClassComplex.class, "map").isEntity()).isFalse();
81+
assertThat(createProperty(TestClassComplex.class, "map").isEntity()).isFalse();
8282
}
8383

8484
@Test // DATACMNS-132
8585
void isEntityWorksForUntypedCollection() {
86-
assertThat(getProperty(TestClassComplex.class, "collection").isEntity()).isFalse();
86+
assertThat(createProperty(TestClassComplex.class, "collection").isEntity()).isFalse();
8787
}
8888

8989
@Test // DATACMNS-121
9090
void considersPropertiesEqualIfFieldEquals() {
9191

92-
SamplePersistentProperty firstProperty = getProperty(FirstConcrete.class, "genericField");
93-
SamplePersistentProperty secondProperty = getProperty(SecondConcrete.class, "genericField");
92+
SamplePersistentProperty firstProperty = createProperty(FirstConcrete.class, "genericField");
93+
SamplePersistentProperty secondProperty = createProperty(SecondConcrete.class, "genericField");
9494

9595
assertThat(firstProperty).isEqualTo(secondProperty);
9696
assertThat(firstProperty.hashCode()).isEqualTo(secondProperty.hashCode());
9797
}
9898

9999
@Test // DATACMNS-180
100100
void doesNotConsiderJavaTransientFieldsTransient() {
101-
assertThat(getProperty(TestClassComplex.class, "transientField").isTransient()).isFalse();
101+
assertThat(createProperty(TestClassComplex.class, "transientField").isTransient()).isFalse();
102102
}
103103

104104
@Test // DATACMNS-206
105105
void findsSimpleGettersAndASetters() {
106106

107-
SamplePersistentProperty property = getProperty(AccessorTestClass.class, "id");
107+
SamplePersistentProperty property = createProperty(AccessorTestClass.class, "id");
108108

109109
assertThat(property.getGetter()).isNotNull();
110110
assertThat(property.getSetter()).isNotNull();
@@ -113,7 +113,7 @@ void findsSimpleGettersAndASetters() {
113113
@Test // DATACMNS-206
114114
void doesNotUseInvalidGettersAndASetters() {
115115

116-
SamplePersistentProperty property = getProperty(AccessorTestClass.class, "anotherId");
116+
SamplePersistentProperty property = createProperty(AccessorTestClass.class, "anotherId");
117117

118118
assertThat(property.getGetter()).isNull();
119119
assertThat(property.getSetter()).isNull();
@@ -122,7 +122,7 @@ void doesNotUseInvalidGettersAndASetters() {
122122
@Test // DATACMNS-206
123123
void usesCustomGetter() {
124124

125-
SamplePersistentProperty property = getProperty(AccessorTestClass.class, "yetAnotherId");
125+
SamplePersistentProperty property = createProperty(AccessorTestClass.class, "yetAnotherId");
126126

127127
assertThat(property.getGetter()).isNotNull();
128128
assertThat(property.getSetter()).isNull();
@@ -131,7 +131,7 @@ void usesCustomGetter() {
131131
@Test // DATACMNS-206
132132
void usesCustomSetter() {
133133

134-
SamplePersistentProperty property = getProperty(AccessorTestClass.class, "yetYetAnotherId");
134+
SamplePersistentProperty property = createProperty(AccessorTestClass.class, "yetYetAnotherId");
135135

136136
assertThat(property.getGetter()).isNull();
137137
assertThat(property.getSetter()).isNotNull();
@@ -153,83 +153,100 @@ void doesNotDiscoverGetterAndSetterIfNoPropertyDescriptorGiven() {
153153
@Test // DATACMNS-337
154154
void resolvesActualType() {
155155

156-
SamplePersistentProperty property = getProperty(Sample.class, "person");
156+
SamplePersistentProperty property = createProperty(Sample.class, "person");
157157
assertThat(property.getActualType()).isEqualTo(Person.class);
158158

159-
property = getProperty(Sample.class, "persons");
159+
property = createProperty(Sample.class, "persons");
160160
assertThat(property.getActualType()).isEqualTo(Person.class);
161161

162-
property = getProperty(Sample.class, "personArray");
162+
property = createProperty(Sample.class, "personArray");
163163
assertThat(property.getActualType()).isEqualTo(Person.class);
164164

165-
property = getProperty(Sample.class, "personMap");
165+
property = createProperty(Sample.class, "personMap");
166166
assertThat(property.getActualType()).isEqualTo(Person.class);
167167
}
168168

169169
@Test // DATACMNS-462
170170
void considersCollectionPropertyEntitiesIfComponentTypeIsEntity() {
171171

172-
SamplePersistentProperty property = getProperty(Sample.class, "persons");
172+
SamplePersistentProperty property = createProperty(Sample.class, "persons");
173173
assertThat(property.isEntity()).isTrue();
174174
}
175175

176176
@Test // DATACMNS-462
177177
void considersMapPropertyEntitiesIfValueTypeIsEntity() {
178178

179-
SamplePersistentProperty property = getProperty(Sample.class, "personMap");
179+
SamplePersistentProperty property = createProperty(Sample.class, "personMap");
180180
assertThat(property.isEntity()).isTrue();
181181
}
182182

183183
@Test // DATACMNS-462
184184
void considersArrayPropertyEntitiesIfComponentTypeIsEntity() {
185185

186-
SamplePersistentProperty property = getProperty(Sample.class, "personArray");
186+
SamplePersistentProperty property = createProperty(Sample.class, "personArray");
187187
assertThat(property.isEntity()).isTrue();
188188
}
189189

190190
@Test // DATACMNS-462
191191
void considersCollectionPropertySimpleIfComponentTypeIsSimple() {
192192

193-
SamplePersistentProperty property = getProperty(Sample.class, "strings");
193+
SamplePersistentProperty property = createProperty(Sample.class, "strings");
194194
assertThat(property.isEntity()).isFalse();
195195
}
196196

197197
@Test // DATACMNS-562
198198
void doesNotConsiderPropertyWithTreeMapMapValueAnEntity() {
199199

200-
SamplePersistentProperty property = getProperty(TreeMapWrapper.class, "map");
200+
SamplePersistentProperty property = createProperty(TreeMapWrapper.class, "map");
201201
assertThat(property.getPersistentEntityTypes()).isEmpty();
202202
assertThat(property.isEntity()).isFalse();
203203
}
204204

205205
@Test // DATACMNS-867
206206
void resolvesFieldNameWithUnderscoresCorrectly() {
207207

208-
SamplePersistentProperty property = getProperty(TestClassComplex.class, "var_name_with_underscores");
208+
SamplePersistentProperty property = createProperty(TestClassComplex.class, "var_name_with_underscores");
209209
assertThat(property.getName()).isEqualTo("var_name_with_underscores");
210210
}
211211

212212
@Test // DATACMNS-1139
213213
void resolvesGenericsForRawType() {
214214

215-
SamplePersistentProperty property = getProperty(FirstConcrete.class, "genericField");
215+
SamplePersistentProperty property = createProperty(FirstConcrete.class, "genericField");
216216

217217
assertThat(property.getRawType()).isEqualTo(String.class);
218218
}
219219

220220
@Test // DATACMNS-1180
221221
void returnsAccessorsForGenericReturnType() {
222222

223-
SamplePersistentProperty property = getProperty(ConcreteGetter.class, "genericField");
223+
SamplePersistentProperty property = createProperty(ConcreteGetter.class, "genericField");
224224

225225
assertThat(property.getSetter()).isNotNull();
226226
assertThat(property.getGetter()).isNotNull();
227227
}
228228

229+
@Test // GH-2315
230+
void detectsImplicitTargetTypeForAssociations() {
231+
232+
SamplePersistentProperty property = new SamplePersistentProperty(getProperty(Sample.class, "person"),
233+
getEntity(Sample.class), typeHolder) {
234+
@Override
235+
public boolean isAssociation() {
236+
return true;
237+
}
238+
};
239+
240+
assertThat(property.getAssociationTargetType()).isEqualTo(Person.class);
241+
242+
property = createProperty(Sample.class, "person");
243+
assertThat(property.getAssociationTargetType()).isNull();
244+
}
245+
229246
@Test // GH-2315
230247
void detectsJMoleculesAssociation() {
231248

232-
SamplePersistentProperty property = getProperty(JMolecules.class, "association");
249+
SamplePersistentProperty property = createProperty(JMolecules.class, "association");
233250

234251
assertThat(property.isAssociation()).isTrue();
235252
assertThat(property.getAssociationTargetType()).isEqualTo(JMoleculesAggregate.class);
@@ -239,19 +256,24 @@ private <T> BasicPersistentEntity<T, SamplePersistentProperty> getEntity(Class<T
239256
return new BasicPersistentEntity<>(ClassTypeInformation.from(type));
240257
}
241258

242-
private <T> SamplePersistentProperty getProperty(Class<T> type, String name) {
259+
private <T> SamplePersistentProperty createProperty(Class<T> type, String name) {
260+
261+
Property property = getProperty(type, name);
262+
263+
return new SamplePersistentProperty(property, getEntity(type), typeHolder);
264+
}
265+
266+
private <T> Property getProperty(Class<T> type, String name) {
243267

244268
TypeInformation<?> typeInformation = ClassTypeInformation.from(type);
245269
Optional<Field> field = Optional.ofNullable(ReflectionUtils.findField(type, name));
246270
Optional<PropertyDescriptor> descriptor = getPropertyDescriptor(type, name);
247271

248-
Property property = Optionals.firstNonEmpty( //
272+
return Optionals.firstNonEmpty( //
249273
() -> Optionals.mapIfAllPresent(field, descriptor, (left, right) -> Property.of(typeInformation, left, right)), //
250274
() -> field.map(it -> Property.of(typeInformation, it)), //
251275
() -> descriptor.map(it -> Property.of(typeInformation, it))) //
252276
.orElseThrow(() -> new IllegalArgumentException(String.format("Couldn't find property %s on %s!", name, type)));
253-
254-
return new SamplePersistentProperty(property, getEntity(type), typeHolder);
255277
}
256278

257279
private static Optional<PropertyDescriptor> getPropertyDescriptor(Class<?> type, String propertyName) {

0 commit comments

Comments
 (0)