- Created a QueryMapResultConverter that can take a map produced by Cypher/Gremlin and produce a proxy object to use for subgraph extraction
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright 2011 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
|
||||
*
|
||||
* http://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.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
public @interface ResultColumn {
|
||||
String value() default "";
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright 2011 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
|
||||
*
|
||||
* http://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.conversion;
|
||||
|
||||
import org.springframework.data.neo4j.annotation.ResultColumn;
|
||||
import org.springframework.data.neo4j.template.Neo4jOperations;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Map;
|
||||
|
||||
public class QueryMapResulConverter<T> implements ResultConverter<Map<String, Object>, T> {
|
||||
private final Neo4jOperations template;
|
||||
|
||||
public QueryMapResulConverter(Neo4jOperations template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T convert(Map<String, Object> value, Class<T> type) {
|
||||
final Map<String, Object> valueCopy = value;
|
||||
|
||||
|
||||
T resultProxy = (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{type}, new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
|
||||
ResultColumn column = method.getAnnotation(ResultColumn.class);
|
||||
TypeInformation<Object> returnType = ClassTypeInformation.fromReturnTypeOf(method);
|
||||
Object columnValue = valueCopy.get(column.value());
|
||||
|
||||
Object result;
|
||||
if (returnType.isCollectionLike())
|
||||
result = template.convert((Iterable) columnValue).to(returnType.getActualType().getType());
|
||||
else
|
||||
result = template.convert(columnValue, returnType.getType());
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
return resultProxy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Copyright 2011 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
|
||||
*
|
||||
* http://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.conversion;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.neo4j.annotation.ResultColumn;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jPersistentTestBase;
|
||||
import org.springframework.data.neo4j.model.Friendship;
|
||||
import org.springframework.data.neo4j.model.Person;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.matchers.JUnitMatchers.hasItems;
|
||||
import static org.neo4j.helpers.collection.MapUtil.map;
|
||||
|
||||
|
||||
public class QueryMapResultConverterTest extends Neo4jPersistentTestBase {
|
||||
|
||||
private Map<String, Object> simpleMap;
|
||||
private List<String> friends;
|
||||
private Map<String, Object> advancedMap;
|
||||
|
||||
public interface PersonAndFriendsData {
|
||||
@ResultColumn("person")
|
||||
Person getPerson();
|
||||
|
||||
@ResultColumn("collect(r)")
|
||||
Iterable<Friendship> getFriends();
|
||||
}
|
||||
|
||||
public interface SimplestQuery {
|
||||
@ResultColumn("name")
|
||||
String getName();
|
||||
|
||||
@ResultColumn("age")
|
||||
Integer getAge();
|
||||
|
||||
@ResultColumn("friends")
|
||||
Iterable<String> getFriendNames();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
storeInGraph(michael);
|
||||
storeInGraph(andres);
|
||||
storeInGraph(emil);
|
||||
|
||||
friends = asList("Michael", "Emil", "Anders");
|
||||
simpleMap = map("name", "Andres", "age", 36L, "friends", friends);
|
||||
advancedMap = map("person", michaelNode(), "collect(r)", michaelNode().getRelationships(KNOWS));
|
||||
|
||||
makeFriends(michaelNode(), andresNode(), 19);
|
||||
makeFriends(michaelNode(), emilNode(), 6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToGetAStringFromAResultMap() throws Exception {
|
||||
QueryMapResulConverter<SimplestQuery> converter = getConverter();
|
||||
SimplestQuery query = converter.convert(simpleMap, SimplestQuery.class);
|
||||
|
||||
assertThat(query.getName(), equalTo("Andres"));
|
||||
assertThat(query.getAge(), equalTo(36));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToHandleAnIterableOfString() throws Exception {
|
||||
QueryMapResulConverter<SimplestQuery> converter = getConverter();
|
||||
SimplestQuery query = converter.convert(simpleMap, SimplestQuery.class);
|
||||
|
||||
assertThat(query.getFriendNames(), hasItems("Michael", "Emil", "Anders"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHandleANodeBackedEntity() throws Exception {
|
||||
QueryMapResulConverter<PersonAndFriendsData> converter = new QueryMapResulConverter<PersonAndFriendsData>(template);
|
||||
PersonAndFriendsData result = converter.convert(advancedMap, PersonAndFriendsData.class);
|
||||
|
||||
assertThat(result.getPerson(), equalTo(michael));
|
||||
assertThat(result.getFriends(), equalTo(michael.getFriendships()));
|
||||
}
|
||||
|
||||
private QueryMapResulConverter<SimplestQuery> getConverter() {
|
||||
return new QueryMapResulConverter<SimplestQuery>(template);
|
||||
}
|
||||
}
|
||||
@@ -298,8 +298,7 @@ public class Neo4jEntityConverterTest extends Neo4jPersistentTestBase {
|
||||
storeInGraph(michael);
|
||||
storeInGraph(andres);
|
||||
|
||||
Relationship friendshipRelationship = michaelNode().createRelationshipTo(andresNode(), KNOWS);
|
||||
friendshipRelationship.setProperty("Friendship.years", 19);
|
||||
Relationship friendshipRelationship = makeFriends(michaelNode(), andresNode(), 19);
|
||||
|
||||
Person m = readPerson(michaelNode());
|
||||
Friendship friendship = IteratorUtil.first(m.getFriendships());
|
||||
|
||||
@@ -30,7 +30,9 @@ import org.springframework.data.neo4j.fieldaccess.NodeDelegatingFieldAccessorFac
|
||||
import org.springframework.data.neo4j.fieldaccess.RelationshipDelegatingFieldAccessorFactory;
|
||||
import org.springframework.data.neo4j.model.Group;
|
||||
import org.springframework.data.neo4j.model.Person;
|
||||
import org.springframework.data.neo4j.support.*;
|
||||
import org.springframework.data.neo4j.support.DelegatingGraphDatabase;
|
||||
import org.springframework.data.neo4j.support.MappingInfrastructure;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.data.neo4j.support.mapping.*;
|
||||
import org.springframework.data.neo4j.support.node.NodeEntityInstantiator;
|
||||
import org.springframework.data.neo4j.support.node.NodeEntityStateFactory;
|
||||
@@ -100,7 +102,7 @@ public class Neo4jPersistentTestBase {
|
||||
|
||||
nodeEntityInstantiator = new NodeEntityInstantiator(entityStateHandler);
|
||||
relationshipEntityInstantiator = new RelationshipEntityInstantiator(entityStateHandler);
|
||||
nodeTypeMapper = new DefaultTypeMapper<Node>(new TRSTypeAliasAccessor<Node>(infrastructure.getNodeTypeRepresentationStrategy()),asList(new ClassValueTypeInformationMapper()));
|
||||
nodeTypeMapper = new DefaultTypeMapper<Node>(new TRSTypeAliasAccessor<Node>(infrastructure.getNodeTypeRepresentationStrategy()), asList(new ClassValueTypeInformationMapper()));
|
||||
nodeStateTransmitter = new SourceStateTransmitter<Node>(nodeEntityStateFactory);
|
||||
relationshipStateTransmitter = new SourceStateTransmitter<Relationship>(relationshipEntityStateFactory);
|
||||
conversionService = template.getConversionService();
|
||||
@@ -135,7 +137,7 @@ public class Neo4jPersistentTestBase {
|
||||
}
|
||||
|
||||
private MappingInfrastructure createInfrastructure(Neo4jMappingContext mappingContext) throws Exception {
|
||||
MappingInfrastructure infrastructure=new MappingInfrastructure();
|
||||
MappingInfrastructure infrastructure = new MappingInfrastructure();
|
||||
final ImpermanentGraphDatabase gdb = new ImpermanentGraphDatabase();
|
||||
infrastructure.setGraphDatabaseService(gdb);
|
||||
final DelegatingGraphDatabase graphDatabase = new DelegatingGraphDatabase(gdb);
|
||||
@@ -187,7 +189,7 @@ public class Neo4jPersistentTestBase {
|
||||
if (id != null) {
|
||||
write(p, template.getNode(id));
|
||||
} else {
|
||||
write(p,null);
|
||||
write(p, null);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
@@ -199,7 +201,7 @@ public class Neo4jPersistentTestBase {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T storeInGraph(T obj) {
|
||||
return (T) write(obj,null);
|
||||
return (T) write(obj, null);
|
||||
}
|
||||
|
||||
protected Node groupNode() {
|
||||
@@ -225,6 +227,13 @@ public class Neo4jPersistentTestBase {
|
||||
public Person readPerson(Node node) {
|
||||
return entityPersister.read(Person.class, node);
|
||||
}
|
||||
|
||||
protected Relationship makeFriends(Node from, Node to, int years) {
|
||||
Relationship friendship = from.createRelationshipTo(to, KNOWS);
|
||||
friendship.setProperty("Friendship.years", years);
|
||||
return friendship;
|
||||
}
|
||||
|
||||
public Group readGroup(Node node) {
|
||||
return entityPersister.read(Group.class, node);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user