fix: Take generic field type into account for @RelationshipProperties.
This falls back to checking the field type, so that generic relationship properties can be used instead of a concrete implementation. Closes #2911.
This commit is contained in:
@@ -16,8 +16,10 @@
|
||||
package org.springframework.data.neo4j.core.mapping;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
@@ -116,8 +118,8 @@ final class DefaultNeo4jPersistentProperty extends AnnotationBasedPersistentProp
|
||||
Neo4jPersistentEntity<?> relationshipPropertiesClass = null;
|
||||
|
||||
if (this.hasActualTypeAnnotation(RelationshipProperties.class)) {
|
||||
Class<?> type = getRelationshipPropertiesTargetType(getActualType());
|
||||
obverseOwner = this.mappingContext.addPersistentEntity(TypeInformation.of(type)).get();
|
||||
TypeInformation<?> typeInformation = getRelationshipPropertiesTargetType(getActualType());
|
||||
obverseOwner = this.mappingContext.addPersistentEntity(typeInformation).get();
|
||||
relationshipPropertiesClass = this.mappingContext.addPersistentEntity(TypeInformation.of(getActualType())).get();
|
||||
} else {
|
||||
Class<?> associationTargetType = this.getAssociationTargetType();
|
||||
@@ -135,8 +137,8 @@ final class DefaultNeo4jPersistentProperty extends AnnotationBasedPersistentProp
|
||||
mapValueType.getType().isAnnotationPresent(RelationshipProperties.class);
|
||||
|
||||
if (relationshipPropertiesCollection) {
|
||||
Class<?> type = getRelationshipPropertiesTargetType(mapValueType.getActualType().getType());
|
||||
obverseOwner = this.mappingContext.addPersistentEntity(TypeInformation.of(type)).get();
|
||||
TypeInformation<?> typeInformation = getRelationshipPropertiesTargetType(mapValueType.getActualType().getType());
|
||||
obverseOwner = this.mappingContext.addPersistentEntity(typeInformation).get();
|
||||
relationshipPropertiesClass = this.mappingContext
|
||||
.addPersistentEntity(mapValueType.getComponentType()).get();
|
||||
|
||||
@@ -178,7 +180,7 @@ final class DefaultNeo4jPersistentProperty extends AnnotationBasedPersistentProp
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Class<?> getRelationshipPropertiesTargetType(Class<?> relationshipPropertiesType) {
|
||||
private TypeInformation<?> getRelationshipPropertiesTargetType(Class<?> relationshipPropertiesType) {
|
||||
|
||||
Field targetNodeField = ReflectionUtils.findField(relationshipPropertiesType,
|
||||
field -> field.isAnnotationPresent(TargetNode.class));
|
||||
@@ -187,7 +189,11 @@ final class DefaultNeo4jPersistentProperty extends AnnotationBasedPersistentProp
|
||||
throw new MappingException("Missing @TargetNode declaration in " + relationshipPropertiesType);
|
||||
}
|
||||
TypeInformation<?> relationshipPropertiesTypeInformation = TypeInformation.of(relationshipPropertiesType);
|
||||
return relationshipPropertiesTypeInformation.getProperty(targetNodeField.getName()).getType();
|
||||
Class<?> type = relationshipPropertiesTypeInformation.getProperty(targetNodeField.getName()).getType();
|
||||
if (Object.class == type && this.getField().getGenericType() instanceof ParameterizedType pt && pt.getActualTypeArguments().length == 1) {
|
||||
return TypeInformation.of(ResolvableType.forType(pt.getActualTypeArguments()[0]));
|
||||
}
|
||||
return TypeInformation.of(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -59,6 +59,8 @@ import org.springframework.data.neo4j.core.mapping.datagraph1446.R1;
|
||||
import org.springframework.data.neo4j.core.mapping.datagraph1446.R2;
|
||||
import org.springframework.data.neo4j.core.mapping.datagraph1448.A_S3;
|
||||
import org.springframework.data.neo4j.core.mapping.datagraph1448.RelatedThing;
|
||||
import org.springframework.data.neo4j.core.mapping.genericRelProperties.Source;
|
||||
import org.springframework.data.neo4j.core.mapping.genericRelProperties.Target;
|
||||
import org.springframework.data.neo4j.core.mapping.gh2574.Model;
|
||||
import org.springframework.data.neo4j.core.schema.CompositeProperty;
|
||||
import org.springframework.data.neo4j.core.schema.GeneratedValue;
|
||||
@@ -682,6 +684,16 @@ class Neo4jMappingContextTest {
|
||||
assertThat(children).containsExactly("A2", "A3", "A4");
|
||||
}
|
||||
|
||||
@Test // GH-2911
|
||||
void shouldDealWithGenericRelationshipProperties() {
|
||||
Neo4jMappingContext schema = new Neo4jMappingContext();
|
||||
Neo4jPersistentEntity<?> persistentEntity = schema.getPersistentEntity(Source.class);
|
||||
assertThat(persistentEntity.getRelationships()).hasSize(1).first().satisfies(r -> {
|
||||
var target = r.getTarget();
|
||||
assertThat(target.getUnderlyingClass()).isEqualTo(Target.class);
|
||||
});
|
||||
}
|
||||
|
||||
static class EntityWithPostLoadMethods {
|
||||
|
||||
String m1;
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2011-2024 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.neo4j.core.mapping.genericRelProperties;
|
||||
|
||||
import org.springframework.data.neo4j.core.schema.GeneratedValue;
|
||||
import org.springframework.data.neo4j.core.schema.Id;
|
||||
import org.springframework.data.neo4j.core.schema.RelationshipProperties;
|
||||
import org.springframework.data.neo4j.core.schema.TargetNode;
|
||||
|
||||
/**
|
||||
* @author Michael J. Simons
|
||||
* @param <T> The crux of this class
|
||||
*/
|
||||
@RelationshipProperties
|
||||
public class Properties<T> {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
@TargetNode
|
||||
T target;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2011-2024 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.neo4j.core.mapping.genericRelProperties;
|
||||
|
||||
import org.springframework.data.neo4j.core.schema.Relationship;
|
||||
|
||||
/**
|
||||
* @author Michael J. Simons
|
||||
*/
|
||||
public class Source {
|
||||
|
||||
@Relationship("IS_RELATED_TO")
|
||||
private Properties<Target> target;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2011-2024 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.neo4j.core.mapping.genericRelProperties;
|
||||
|
||||
/**
|
||||
* @author Michael J. Simons
|
||||
*/
|
||||
public class Target {
|
||||
}
|
||||
Reference in New Issue
Block a user