DATAGRAPH-487 - Handle unique fields that have to be converted correctly
This commit is contained in:
@@ -152,7 +152,7 @@ public abstract class Neo4jConfiguration {
|
||||
|
||||
@Bean
|
||||
public EntityStateHandler entityStateHandler() throws Exception {
|
||||
return new EntityStateHandler(neo4jMappingContext(),graphDatabase());
|
||||
return new EntityStateHandler(neo4jMappingContext(),graphDatabase(),neo4jConversionService());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -63,18 +63,14 @@ public class ConvertingNodePropertyFieldAccessorFactory implements FieldAccessor
|
||||
|
||||
@Override
|
||||
public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) {
|
||||
Object value = propertyConverter.isObjectOrSupportedType(newVal, this.property) ? newVal : propertyConverter.serializePropertyValue(newVal);
|
||||
Object value = propertyConverter.serializeIfNotBuiltIn(newVal);
|
||||
super.setValue(entity, value, mappingPolicy);
|
||||
return newVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object doGetValue(final Object entity) {
|
||||
Object ret = super.doGetValue(entity);
|
||||
if (propertyConverter.isObjectOrSupportedType(ret, this.property)) {
|
||||
return ret;
|
||||
}
|
||||
return propertyConverter.deserializePropertyValue(ret);
|
||||
return propertyConverter.deserializeIfNotBuiltIn(super.doGetValue(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.data.neo4j.fieldaccess;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Configurable;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.data.neo4j.mapping.MappingPolicy;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
|
||||
@@ -61,7 +60,7 @@ public class GenericNodePropertyFieldAccessorFactory implements FieldAccessorFac
|
||||
|
||||
@Override
|
||||
public Object setValue(final Object entity, final Object newVal, MappingPolicy mappingPolicy) {
|
||||
Object value = propertyConverter.isObjectOrSupportedType(newVal, this.property) ? newVal : propertyConverter.serializePropertyValue(newVal);
|
||||
Object value = propertyConverter.isObjectOrSupportedType(newVal) ? newVal : propertyConverter.serializePropertyValue(newVal);
|
||||
super.setValue(entity, value, mappingPolicy);
|
||||
return newVal;
|
||||
}
|
||||
@@ -69,7 +68,7 @@ public class GenericNodePropertyFieldAccessorFactory implements FieldAccessorFac
|
||||
@Override
|
||||
public Object doGetValue(final Object entity) {
|
||||
Object ret = super.doGetValue(entity);
|
||||
if (propertyConverter.isObjectOrSupportedType(ret, this.property)) {
|
||||
if (propertyConverter.isObjectOrSupportedType(ret)) {
|
||||
return ret;
|
||||
}
|
||||
return propertyConverter.deserializePropertyValue(ret);
|
||||
|
||||
@@ -95,7 +95,18 @@ public class PropertyConverter {
|
||||
}
|
||||
}
|
||||
|
||||
boolean isObjectOrSupportedType(final Object value, Neo4jPersistentProperty property) {
|
||||
boolean isObjectOrSupportedType(final Object value) {
|
||||
return property.getType().equals(Object.class) && property.isNeo4jPropertyValue(value);
|
||||
}
|
||||
|
||||
public Object deserializeIfNotBuiltIn(Object ret) {
|
||||
if (isObjectOrSupportedType(ret)) {
|
||||
return ret;
|
||||
}
|
||||
return deserializePropertyValue(ret);
|
||||
}
|
||||
|
||||
public Object serializeIfNotBuiltIn(Object newVal) {
|
||||
return isObjectOrSupportedType(newVal) ? newVal : serializePropertyValue(newVal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ public class MappingInfrastructureFactoryBean implements FactoryBean<Infrastruct
|
||||
this.conversionService=new Neo4jConversionServiceFactoryBean().getObject();
|
||||
}
|
||||
if (entityStateHandler == null) {
|
||||
entityStateHandler = new EntityStateHandler(mappingContext,graphDatabase);
|
||||
entityStateHandler = new EntityStateHandler(mappingContext,graphDatabase, conversionService);
|
||||
}
|
||||
if (nodeEntityInstantiator == null) {
|
||||
nodeEntityInstantiator = new NodeEntityInstantiator(entityStateHandler);
|
||||
@@ -148,7 +148,7 @@ public class MappingInfrastructureFactoryBean implements FactoryBean<Infrastruct
|
||||
}
|
||||
this.typeRepresentationStrategies = new TypeRepresentationStrategies(mappingContext, nodeTypeRepresentationStrategy, relationshipTypeRepresentationStrategy);
|
||||
|
||||
final EntityStateHandler entityStateHandler = new EntityStateHandler(mappingContext, graphDatabase);
|
||||
final EntityStateHandler entityStateHandler = new EntityStateHandler(mappingContext, graphDatabase, conversionService);
|
||||
EntityTools<Node> nodeEntityTools = new EntityTools<Node>(nodeTypeRepresentationStrategy, nodeEntityStateFactory, nodeEntityInstantiator, mappingContext);
|
||||
EntityTools<Relationship> relationshipEntityTools = new EntityTools<Relationship>(relationshipTypeRepresentationStrategy, relationshipEntityStateFactory, relationshipEntityInstantiator, mappingContext);
|
||||
this.entityPersister = new Neo4jEntityPersister(conversionService, nodeEntityTools, relationshipEntityTools, mappingContext, entityStateHandler);
|
||||
|
||||
@@ -21,8 +21,10 @@ import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.neo4j.graphdb.Relationship;
|
||||
import org.neo4j.graphdb.RelationshipType;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.neo4j.core.GraphDatabase;
|
||||
import org.springframework.data.neo4j.fieldaccess.PropertyConverter;
|
||||
import org.springframework.data.neo4j.mapping.IndexInfo;
|
||||
import org.springframework.data.neo4j.mapping.ManagedEntity;
|
||||
import org.springframework.data.neo4j.mapping.MappingPolicy;
|
||||
@@ -43,12 +45,14 @@ import static org.neo4j.helpers.collection.MapUtil.map;
|
||||
*/
|
||||
public class EntityStateHandler {
|
||||
|
||||
private Neo4jMappingContext mappingContext;
|
||||
private final Neo4jMappingContext mappingContext;
|
||||
private final GraphDatabase graphDatabase;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
public EntityStateHandler(Neo4jMappingContext mappingContext, GraphDatabase graphDatabase) {
|
||||
public EntityStateHandler(Neo4jMappingContext mappingContext, GraphDatabase graphDatabase, ConversionService conversionService) {
|
||||
this.mappingContext = mappingContext;
|
||||
this.graphDatabase = graphDatabase;
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -149,9 +153,9 @@ public class EntityStateHandler {
|
||||
|
||||
private Node createUniqueNode(Neo4jPersistentEntityImpl<?> persistentEntity, Object entity) {
|
||||
Neo4jPersistentProperty uniqueProperty = persistentEntity.getUniqueProperty();
|
||||
final IndexInfo indexInfo = uniqueProperty.getIndexInfo();
|
||||
final Object value = uniqueProperty.getValueFromEntity(entity, MappingPolicy.MAP_FIELD_DIRECT_POLICY);
|
||||
final Object value = getSerializedUniqueValue(entity, uniqueProperty);
|
||||
if (value==null) throw new MappingException("Error creating "+uniqueProperty.getOwner().getName()+" with "+entity+" unique property "+uniqueProperty.getName()+" has null value");
|
||||
final IndexInfo indexInfo = uniqueProperty.getIndexInfo();
|
||||
if (indexInfo.isLabelBased()) {
|
||||
return (indexInfo.isFailOnDuplicate())
|
||||
? graphDatabase.createNode(map(uniqueProperty.getName(),value),persistentEntity.getAllLabels())
|
||||
@@ -161,6 +165,13 @@ public class EntityStateHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private Object getSerializedUniqueValue(Object entity, Neo4jPersistentProperty uniqueProperty) {
|
||||
final Object value = uniqueProperty.getValueFromEntity(entity, MappingPolicy.MAP_FIELD_DIRECT_POLICY);
|
||||
if (uniqueProperty.isSerializablePropertyField(conversionService))
|
||||
return new PropertyConverter(conversionService,uniqueProperty).serializeIfNotBuiltIn(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S extends PropertyContainer> S getOrCreateRelationship( Object entity, Neo4jPersistentEntity<?> persistentEntity, RelationshipType annotationProvidedRelationshipType ) {
|
||||
final RelationshipProperties relationshipProperties = persistentEntity.getRelationshipProperties();
|
||||
|
||||
@@ -112,7 +112,7 @@ public class Neo4jPersistentTestBase {
|
||||
final DelegatingGraphDatabase graphDatabase = new DelegatingGraphDatabase(gdb);
|
||||
factoryBean.setGraphDatabase(graphDatabase);
|
||||
factoryBean.setMappingContext(mappingContext);
|
||||
final EntityStateHandler entityStateHandler = new EntityStateHandler(mappingContext, graphDatabase);
|
||||
final EntityStateHandler entityStateHandler = new EntityStateHandler(mappingContext, graphDatabase, conversionService);
|
||||
final NoopNodeTypeRepresentationStrategy nodeTypeRepresentationStrategy = new NoopNodeTypeRepresentationStrategy();
|
||||
factoryBean.setNodeTypeRepresentationStrategy(nodeTypeRepresentationStrategy);
|
||||
final NoopRelationshipTypeRepresentationStrategy relationshipTypeRepresentationStrategy = new NoopRelationshipTypeRepresentationStrategy();
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package org.springframework.data.neo4j.unique;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.test.TestGraphDatabaseFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.neo4j.annotation.GraphId;
|
||||
import org.springframework.data.neo4j.annotation.Indexed;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
|
||||
import org.springframework.data.neo4j.config.Neo4jConfiguration;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.data.neo4j.support.index.IndexType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 30.06.14
|
||||
*/
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class UniqueConvertedValueTests {
|
||||
|
||||
@Configuration
|
||||
@EnableNeo4jRepositories
|
||||
static class TestConfig extends Neo4jConfiguration {
|
||||
TestConfig() {
|
||||
setBasePackage("org.springframework.data.neo4j.unique");
|
||||
}
|
||||
|
||||
@Bean
|
||||
GraphDatabaseService graphDatabaseService() {
|
||||
return new TestGraphDatabaseFactory().newImpermanentDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
Neo4jTemplate template;
|
||||
|
||||
static enum Letter {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
@NodeEntity
|
||||
static class Word {
|
||||
@GraphId
|
||||
Long id;
|
||||
@Indexed(unique = true, indexType = IndexType.LABEL)
|
||||
Letter letter;
|
||||
String word;
|
||||
|
||||
Word() { }
|
||||
|
||||
Word(Letter letter, String word) {
|
||||
this.letter = letter;
|
||||
this.word = word;
|
||||
}
|
||||
}
|
||||
@NodeEntity
|
||||
static class Word2 {
|
||||
@GraphId
|
||||
Long id;
|
||||
@Indexed(unique = true, indexType = IndexType.SIMPLE)
|
||||
Letter letter;
|
||||
String word;
|
||||
|
||||
Word2() { }
|
||||
|
||||
Word2(Letter letter, String word) {
|
||||
this.letter = letter;
|
||||
this.word = word;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public void testPersistUniqueEnumValue() throws Exception {
|
||||
Word word = template.save(new Word(Letter.A, "Afternoon"));
|
||||
assertEquals(Letter.A, word.letter);
|
||||
assertEquals("Afternoon", word.word);
|
||||
}
|
||||
@Test
|
||||
@Transactional
|
||||
public void testPersistUniqueEnumValueLegacyIndex() throws Exception {
|
||||
Word word = template.save(new Word(Letter.A, "Afternoon"));
|
||||
assertEquals(Letter.A, word.letter);
|
||||
assertEquals("Afternoon", word.word);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user