Skip to content

Commit 85578b5

Browse files
christophstroblmp911de
authored andcommitted
Ignore override properties when creating PersistentEntity.
Original pull request: #390. Closes #1911.
1 parent 35b8a42 commit 85578b5

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed

src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java

+41
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import java.util.function.Predicate;
3131
import java.util.stream.Collectors;
3232

33+
import org.slf4j.Logger;
34+
import org.slf4j.LoggerFactory;
3335
import org.springframework.beans.BeanUtils;
3436
import org.springframework.beans.BeansException;
3537
import org.springframework.beans.factory.InitializingBean;
@@ -62,6 +64,7 @@
6264
import org.springframework.data.util.TypeInformation;
6365
import org.springframework.lang.Nullable;
6466
import org.springframework.util.Assert;
67+
import org.springframework.util.ClassUtils;
6568
import org.springframework.util.ReflectionUtils;
6669
import org.springframework.util.ReflectionUtils.FieldCallback;
6770
import org.springframework.util.ReflectionUtils.FieldFilter;
@@ -87,6 +90,8 @@
8790
public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?, P>, P extends PersistentProperty<P>>
8891
implements MappingContext<E, P>, ApplicationEventPublisherAware, ApplicationContextAware, InitializingBean {
8992

93+
private static final Logger LOGGER = LoggerFactory.getLogger(MappingContext.class);
94+
9095
private final Optional<E> NONE = Optional.empty();
9196
private final Map<TypeInformation<?>, Optional<E>> persistentEntities = new HashMap<>();
9297
private final PersistentPropertyAccessorFactory persistentPropertyAccessorFactory;
@@ -550,6 +555,10 @@ private void createAndRegisterProperty(Property input) {
550555
return;
551556
}
552557

558+
if (isKotlinOverride(property, input)) {
559+
return;
560+
}
561+
553562
entity.addPersistentProperty(property);
554563

555564
if (property.isAssociation()) {
@@ -562,6 +571,38 @@ private void createAndRegisterProperty(Property input) {
562571

563572
property.getPersistentEntityTypes().forEach(AbstractMappingContext.this::addPersistentEntity);
564573
}
574+
575+
private boolean isKotlinOverride(P property, Property input) {
576+
577+
if (!KotlinDetector.isKotlinPresent() || !input.getField().isPresent()) {
578+
return false;
579+
}
580+
581+
Field field = input.getField().get();
582+
if (!KotlinDetector.isKotlinType(field.getDeclaringClass())) {
583+
return false;
584+
}
585+
586+
for (P existingProperty : entity) {
587+
588+
if (!property.getName().equals(existingProperty.getName())) {
589+
continue;
590+
}
591+
592+
if (field.getDeclaringClass() != entity.getType()
593+
&& ClassUtils.isAssignable(field.getDeclaringClass(), entity.getType())) {
594+
595+
if (LOGGER.isTraceEnabled()) {
596+
LOGGER.trace(String.format("Skipping '%s.%s' property declaration shadowed by '%s %s' in '%s'. ",
597+
field.getDeclaringClass().getName(), property.getName(), property.getType().getSimpleName(),
598+
property.getName(), entity.getType().getSimpleName()));
599+
}
600+
return true;
601+
}
602+
}
603+
604+
return false;
605+
}
565606
}
566607

567608
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.mapping
17+
18+
open class ShadowedPropertyType {
19+
open val shadowedProperty: Int = 1
20+
}
21+
22+
class ShadowingPropertyType : ShadowedPropertyType() {
23+
override var shadowedProperty: Int = 10
24+
}
25+
26+
open class ShadowedPropertyTypeWithCtor(open val shadowedProperty: Int)
27+
28+
class ShadowingPropertyTypeWithCtor(val someValue: String, override var shadowedProperty: Int = 1) : ShadowedPropertyTypeWithCtor(shadowedProperty)
29+
30+

src/test/java/org/springframework/data/mapping/context/AbstractMappingContextUnitTests.java

+71
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,15 @@
4141
import org.springframework.data.annotation.Id;
4242
import org.springframework.data.mapping.MappingException;
4343
import org.springframework.data.mapping.PersistentEntity;
44+
import org.springframework.data.mapping.PropertyHandler;
45+
import org.springframework.data.mapping.ShadowedPropertyType;
46+
import org.springframework.data.mapping.ShadowedPropertyTypeWithCtor;
47+
import org.springframework.data.mapping.ShadowingPropertyType;
48+
import org.springframework.data.mapping.ShadowingPropertyTypeWithCtor;
4449
import org.springframework.data.mapping.model.BasicPersistentEntity;
4550
import org.springframework.data.mapping.model.SimpleTypeHolder;
4651
import org.springframework.data.util.ClassTypeInformation;
52+
import org.springframework.data.util.StreamUtils;
4753
import org.springframework.data.util.TypeInformation;
4854

4955
/**
@@ -52,6 +58,7 @@
5258
* @author Oliver Gierke
5359
* @author Thomas Darimont
5460
* @author Mark Paluch
61+
* @author Christoph Stobl
5562
*/
5663
class AbstractMappingContextUnitTests {
5764

@@ -216,6 +223,37 @@ void cleansUpCacheForRuntimeException() {
216223
.isThrownBy(() -> context.getPersistentEntity(Unsupported.class));
217224
}
218225

226+
@Test // DATACMNS-1509
227+
public void shouldIgnoreKotlinOverrideCtorPropertyInSuperClass() {
228+
229+
BasicPersistentEntity<Object, SamplePersistentProperty> entity = context
230+
.getPersistentEntity(ClassTypeInformation.from(ShadowingPropertyTypeWithCtor.class));
231+
entity.doWithProperties((PropertyHandler<SamplePersistentProperty>) property -> {
232+
assertThat(property.getField().getDeclaringClass()).isNotEqualTo(ShadowedPropertyTypeWithCtor.class);
233+
});
234+
}
235+
236+
@Test // DATACMNS-1509
237+
public void shouldIgnoreKotlinOverridePropertyInSuperClass() {
238+
239+
BasicPersistentEntity<Object, SamplePersistentProperty> entity = context
240+
.getPersistentEntity(ClassTypeInformation.from(ShadowingPropertyType.class));
241+
entity.doWithProperties((PropertyHandler<SamplePersistentProperty>) property -> {
242+
assertThat(property.getField().getDeclaringClass()).isNotEqualTo(ShadowedPropertyType.class);
243+
});
244+
}
245+
246+
@Test // DATACMNS-1509
247+
public void shouldStillIncludeNonKotlinShadowedPropertyInSuperClass() {
248+
249+
BasicPersistentEntity<Object, SamplePersistentProperty> entity = context
250+
.getPersistentEntity(ClassTypeInformation.from(ShadowingProperty.class));
251+
252+
assertThat(StreamUtils.createStreamFromIterator(entity.iterator())
253+
.filter(it -> it.getField().getDeclaringClass().equals(ShadowedProperty.class)).findFirst() //
254+
).isNotEmpty();
255+
}
256+
219257
private static void assertHasEntityFor(Class<?> type, SampleMappingContext context, boolean expected) {
220258

221259
boolean found = false;
@@ -306,4 +344,37 @@ public void verify() {
306344
};
307345
}
308346
}
347+
348+
static class ShadowedProperty {
349+
350+
private final String value;
351+
352+
ShadowedProperty(String value) {
353+
this.value = value;
354+
}
355+
356+
public String getValue() {
357+
return value;
358+
}
359+
}
360+
361+
static class ShadowingProperty extends ShadowedProperty {
362+
363+
private String value;
364+
365+
ShadowingProperty(String value) {
366+
super(value);
367+
this.value = value;
368+
}
369+
370+
public void setValue(String value) {
371+
this.value = value;
372+
}
373+
374+
@Override
375+
public String getValue() {
376+
return value;
377+
}
378+
}
379+
309380
}

0 commit comments

Comments
 (0)