Skip to content

Commit

Permalink
Ignore override properties when creating PersistentEntity.
Browse files Browse the repository at this point in the history
Original pull request: #390.
Closes #1911.
  • Loading branch information
christophstrobl authored and mp911de committed Apr 21, 2021
1 parent 35b8a42 commit 85578b5
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import java.util.function.Predicate;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
Expand Down Expand Up @@ -62,6 +64,7 @@
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;
import org.springframework.util.ReflectionUtils.FieldFilter;
Expand All @@ -87,6 +90,8 @@
public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?, P>, P extends PersistentProperty<P>>
implements MappingContext<E, P>, ApplicationEventPublisherAware, ApplicationContextAware, InitializingBean {

private static final Logger LOGGER = LoggerFactory.getLogger(MappingContext.class);

private final Optional<E> NONE = Optional.empty();
private final Map<TypeInformation<?>, Optional<E>> persistentEntities = new HashMap<>();
private final PersistentPropertyAccessorFactory persistentPropertyAccessorFactory;
Expand Down Expand Up @@ -550,6 +555,10 @@ private void createAndRegisterProperty(Property input) {
return;
}

if (isKotlinOverride(property, input)) {
return;
}

entity.addPersistentProperty(property);

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

property.getPersistentEntityTypes().forEach(AbstractMappingContext.this::addPersistentEntity);
}

private boolean isKotlinOverride(P property, Property input) {

if (!KotlinDetector.isKotlinPresent() || !input.getField().isPresent()) {
return false;
}

Field field = input.getField().get();
if (!KotlinDetector.isKotlinType(field.getDeclaringClass())) {
return false;
}

for (P existingProperty : entity) {

if (!property.getName().equals(existingProperty.getName())) {
continue;
}

if (field.getDeclaringClass() != entity.getType()
&& ClassUtils.isAssignable(field.getDeclaringClass(), entity.getType())) {

if (LOGGER.isTraceEnabled()) {
LOGGER.trace(String.format("Skipping '%s.%s' property declaration shadowed by '%s %s' in '%s'. ",
field.getDeclaringClass().getName(), property.getName(), property.getType().getSimpleName(),
property.getName(), entity.getType().getSimpleName()));
}
return true;
}
}

return false;
}
}

/**
Expand Down
30 changes: 30 additions & 0 deletions src/test/java/org/springframework/data/mapping/KotlinModelTypes.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mapping

open class ShadowedPropertyType {
open val shadowedProperty: Int = 1
}

class ShadowingPropertyType : ShadowedPropertyType() {
override var shadowedProperty: Int = 10
}

open class ShadowedPropertyTypeWithCtor(open val shadowedProperty: Int)

class ShadowingPropertyTypeWithCtor(val someValue: String, override var shadowedProperty: Int = 1) : ShadowedPropertyTypeWithCtor(shadowedProperty)


Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,15 @@
import org.springframework.data.annotation.Id;
import org.springframework.data.mapping.MappingException;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.mapping.ShadowedPropertyType;
import org.springframework.data.mapping.ShadowedPropertyTypeWithCtor;
import org.springframework.data.mapping.ShadowingPropertyType;
import org.springframework.data.mapping.ShadowingPropertyTypeWithCtor;
import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.StreamUtils;
import org.springframework.data.util.TypeInformation;

/**
Expand All @@ -52,6 +58,7 @@
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
* @author Christoph Stobl
*/
class AbstractMappingContextUnitTests {

Expand Down Expand Up @@ -216,6 +223,37 @@ void cleansUpCacheForRuntimeException() {
.isThrownBy(() -> context.getPersistentEntity(Unsupported.class));
}

@Test // DATACMNS-1509
public void shouldIgnoreKotlinOverrideCtorPropertyInSuperClass() {

BasicPersistentEntity<Object, SamplePersistentProperty> entity = context
.getPersistentEntity(ClassTypeInformation.from(ShadowingPropertyTypeWithCtor.class));
entity.doWithProperties((PropertyHandler<SamplePersistentProperty>) property -> {
assertThat(property.getField().getDeclaringClass()).isNotEqualTo(ShadowedPropertyTypeWithCtor.class);
});
}

@Test // DATACMNS-1509
public void shouldIgnoreKotlinOverridePropertyInSuperClass() {

BasicPersistentEntity<Object, SamplePersistentProperty> entity = context
.getPersistentEntity(ClassTypeInformation.from(ShadowingPropertyType.class));
entity.doWithProperties((PropertyHandler<SamplePersistentProperty>) property -> {
assertThat(property.getField().getDeclaringClass()).isNotEqualTo(ShadowedPropertyType.class);
});
}

@Test // DATACMNS-1509
public void shouldStillIncludeNonKotlinShadowedPropertyInSuperClass() {

BasicPersistentEntity<Object, SamplePersistentProperty> entity = context
.getPersistentEntity(ClassTypeInformation.from(ShadowingProperty.class));

assertThat(StreamUtils.createStreamFromIterator(entity.iterator())
.filter(it -> it.getField().getDeclaringClass().equals(ShadowedProperty.class)).findFirst() //
).isNotEmpty();
}

private static void assertHasEntityFor(Class<?> type, SampleMappingContext context, boolean expected) {

boolean found = false;
Expand Down Expand Up @@ -306,4 +344,37 @@ public void verify() {
};
}
}

static class ShadowedProperty {

private final String value;

ShadowedProperty(String value) {
this.value = value;
}

public String getValue() {
return value;
}
}

static class ShadowingProperty extends ShadowedProperty {

private String value;

ShadowingProperty(String value) {
super(value);
this.value = value;
}

public void setValue(String value) {
this.value = value;
}

@Override
public String getValue() {
return value;
}
}

}

0 comments on commit 85578b5

Please sign in to comment.