From 30843d71e4e0d4647004b7500931ff18b4c34672 Mon Sep 17 00:00:00 2001 From: Ganesh Guttikonda Date: Fri, 4 Oct 2019 15:19:50 -0700 Subject: [PATCH 1/5] Allow configuration driven `maxContentLength`. This is to avoid `Max frame length of 65536 has been exceeded.` error. --- .gitignore | 7 +++++++ .../microsoft/spring/data/gremlin/common/Constants.java | 3 +++ .../spring/data/gremlin/common/GremlinConfig.java | 4 +++- .../spring/data/gremlin/common/GremlinFactory.java | 6 ++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c5e60dbb..ea66cf52 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,10 @@ target/* *.iml **/target + +#Eclipse generated files +.classpath +.project +.settings/ +/.apt_generated/ +/.apt_generated_tests/ diff --git a/src/main/java/com/microsoft/spring/data/gremlin/common/Constants.java b/src/main/java/com/microsoft/spring/data/gremlin/common/Constants.java index 268d70d2..418c1997 100644 --- a/src/main/java/com/microsoft/spring/data/gremlin/common/Constants.java +++ b/src/main/java/com/microsoft/spring/data/gremlin/common/Constants.java @@ -90,4 +90,7 @@ public class Constants { ); public static final String GREMLIN_PROPERTY_CLASSNAME = "_classname"; + + public static final int DEFAULT_MAX_CONTENT_LENGTH = 65536; + } diff --git a/src/main/java/com/microsoft/spring/data/gremlin/common/GremlinConfig.java b/src/main/java/com/microsoft/spring/data/gremlin/common/GremlinConfig.java index e76f0f8c..5a9b62b8 100644 --- a/src/main/java/com/microsoft/spring/data/gremlin/common/GremlinConfig.java +++ b/src/main/java/com/microsoft/spring/data/gremlin/common/GremlinConfig.java @@ -10,7 +10,6 @@ import lombok.Builder; import lombok.Getter; import lombok.Setter; -import org.apache.tinkerpop.gremlin.driver.ser.SerTokens; import org.apache.tinkerpop.gremlin.driver.ser.Serializers; @Getter @@ -31,6 +30,9 @@ public class GremlinConfig { private boolean telemetryAllowed; private String serializer; + + private int maxContentLength; + public static GremlinConfigBuilder builder(String endpoint, String username, String password) { return defaultBuilder() diff --git a/src/main/java/com/microsoft/spring/data/gremlin/common/GremlinFactory.java b/src/main/java/com/microsoft/spring/data/gremlin/common/GremlinFactory.java index 28f3ca07..df7357d2 100644 --- a/src/main/java/com/microsoft/spring/data/gremlin/common/GremlinFactory.java +++ b/src/main/java/com/microsoft/spring/data/gremlin/common/GremlinFactory.java @@ -25,6 +25,11 @@ public GremlinFactory(@NonNull GremlinConfig gremlinConfig) { if (port <= 0 || port > 65535) { gremlinConfig.setPort(Constants.DEFAULT_ENDPOINT_PORT); } + + final int maxContentLength = gremlinConfig.getMaxContentLength(); + if (maxContentLength <= 0) { + gremlinConfig.setMaxContentLength(Constants.DEFAULT_MAX_CONTENT_LENGTH); + } this.gremlinConfig = gremlinConfig; } @@ -37,6 +42,7 @@ private Cluster createGremlinCluster() throws GremlinIllegalConfigurationExcepti .serializer(Serializers.valueOf(this.gremlinConfig.getSerializer()).simpleInstance()) .credentials(this.gremlinConfig.getUsername(), this.gremlinConfig.getPassword()) .enableSsl(this.gremlinConfig.isSslEnabled()) + .maxContentLength(this.gremlinConfig.getMaxContentLength()) .port(this.gremlinConfig.getPort()) .create(); } catch (IllegalArgumentException e) { From 9a9db6626f412d8a9c73a5c81db43336d6333b18 Mon Sep 17 00:00:00 2001 From: Ganesh Guttikonda Date: Tue, 12 Nov 2019 17:57:37 -0800 Subject: [PATCH 2/5] Support for @Query annotation ( inspired from Neo4j Spring data implementation ) --- .../spring/data/gremlin/annotation/Query.java | 33 ++++++ .../data/gremlin/query/GremlinTemplate.java | 2 +- .../query/GraphRepositoryGremlinQuery.java | 100 ++++++++++++++++++ .../query/query/GremlinQueryMethod.java | 27 +++++ .../support/GremlinRepositoryFactory.java | 15 ++- .../common/repository/PersonRepository.java | 4 + .../repository/PersonRepositoryIT.java | 13 +++ 7 files changed, 190 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/microsoft/spring/data/gremlin/annotation/Query.java create mode 100644 src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java diff --git a/src/main/java/com/microsoft/spring/data/gremlin/annotation/Query.java b/src/main/java/com/microsoft/spring/data/gremlin/annotation/Query.java new file mode 100644 index 00000000..af5dba29 --- /dev/null +++ b/src/main/java/com/microsoft/spring/data/gremlin/annotation/Query.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for + * license information. + */ +package com.microsoft.spring.data.gremlin.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.data.annotation.QueryAnnotation; + +/** + * Annotation to declare Parameterized queries to be defined as String. + * Inspired from Spring Neo4j implementation + * + * @author Ganesh Guttikonda + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) +@QueryAnnotation +@Documented +public @interface Query { + + /** + * Defines the Gremlin query to be executed when the annotated method is called. + */ + String value() default ""; + +} diff --git a/src/main/java/com/microsoft/spring/data/gremlin/query/GremlinTemplate.java b/src/main/java/com/microsoft/spring/data/gremlin/query/GremlinTemplate.java index f84a554b..121bf91d 100644 --- a/src/main/java/com/microsoft/spring/data/gremlin/query/GremlinTemplate.java +++ b/src/main/java/com/microsoft/spring/data/gremlin/query/GremlinTemplate.java @@ -348,7 +348,7 @@ private T recoverDomain(@NonNull GremlinSource source, @NonNull List List recoverDomainList(@NonNull GremlinSource source, @NonNull List results) { + public List recoverDomainList(@NonNull GremlinSource source, @NonNull List results) { return results.stream().map(r -> recoverDomain(source, Collections.singletonList(r))).collect(toList()); } diff --git a/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java b/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java new file mode 100644 index 00000000..64abb287 --- /dev/null +++ b/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java @@ -0,0 +1,100 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for + * license information. + */ +package com.microsoft.spring.data.gremlin.query.query; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import org.apache.tinkerpop.gremlin.driver.Client; +import org.apache.tinkerpop.gremlin.driver.ResultSet; +import org.springframework.data.repository.query.Parameter; +import org.springframework.data.repository.query.Parameters; +import org.springframework.data.repository.query.ResultProcessor; +import org.springframework.lang.NonNull; + +import com.microsoft.spring.data.gremlin.common.GremlinUtils; +import com.microsoft.spring.data.gremlin.conversion.source.GremlinSource; +import com.microsoft.spring.data.gremlin.query.GremlinOperations; +import com.microsoft.spring.data.gremlin.query.GremlinTemplate; +import com.microsoft.spring.data.gremlin.query.paramerter.GremlinParameterAccessor; +import com.microsoft.spring.data.gremlin.query.paramerter.GremlinParametersParameterAccessor; + +public class GraphRepositoryGremlinQuery extends AbstractGremlinQuery { + + private final GremlinQueryMethod method; + private final GremlinOperations operations; + private final Client gremlinClient; + + public GraphRepositoryGremlinQuery(@NonNull Client gremlinClient, @NonNull GremlinQueryMethod method, + @NonNull GremlinOperations operations) { + super(method, operations); + this.gremlinClient = gremlinClient; + this.method = method; + this.operations = operations; + } + + @Override + protected GremlinQuery createQuery(GremlinParameterAccessor accessor) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + @Override + public Object execute(@NonNull Object[] parameters) { + final GremlinParameterAccessor accessor = new GremlinParametersParameterAccessor(this.method, parameters); + final String query = method.getQuery(); + final Map params = this.resolveParams(this.method.getParameters(), parameters); + + final ResultProcessor processor = method.getResultProcessor().withDynamicProjection(accessor); + final Class methodReturnType = processor.getReturnedType().getDomainType(); + final ResultSet rs = this.gremlinClient.submit(query, params); + + if (ResultSet.class.equals(methodReturnType)) { + return rs; + } + + final GremlinSource source = GremlinUtils.toGremlinSource(methodReturnType); + if (GremlinTemplate.class.equals(this.operations.getClass())) { + try { + return ((GremlinTemplate) this.operations).recoverDomainList(source, rs.all().get()); + } catch (InterruptedException e) { + throw new IllegalStateException(e); + } catch (ExecutionException e) { + throw new IllegalStateException(e); + } + } + + throw new UnsupportedOperationException(methodReturnType + " is not handled by deserializer!"); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + Map resolveParams(Parameters methodParameters, Object[] parameters) { + + final Map resolvedParameters = new HashMap<>(); + + for (final Parameter parameter : methodParameters) { + final int parameterIndex = parameter.getIndex(); + final Object parameterValue = parameters[parameterIndex]; + + //Convenience! Client can simply pass Map params, + //we automatically resolve them to individual parameters. + //this is to allow the pass through for GremlinClient + if (parameterValue instanceof Map) { + resolvedParameters.putAll((Map) parameterValue); + } + parameter.getName().ifPresent(parameterName -> resolvedParameters.put(parameterName, parameterValue)); + } + + return resolvedParameters; + } + + @Override + @NonNull + public GremlinQueryMethod getQueryMethod() { + return this.method; + } + +} diff --git a/src/main/java/com/microsoft/spring/data/gremlin/query/query/GremlinQueryMethod.java b/src/main/java/com/microsoft/spring/data/gremlin/query/query/GremlinQueryMethod.java index b38dc7b5..3c409512 100644 --- a/src/main/java/com/microsoft/spring/data/gremlin/query/query/GremlinQueryMethod.java +++ b/src/main/java/com/microsoft/spring/data/gremlin/query/query/GremlinQueryMethod.java @@ -5,21 +5,30 @@ */ package com.microsoft.spring.data.gremlin.query.query; +import com.microsoft.spring.data.gremlin.annotation.Query; import com.microsoft.spring.data.gremlin.query.GremlinEntityMetadata; import com.microsoft.spring.data.gremlin.query.SimpleGremlinEntityMetadata; + +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.repository.core.EntityMetadata; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.query.QueryMethod; +import org.springframework.util.StringUtils; import java.lang.reflect.Method; public class GremlinQueryMethod extends QueryMethod { private GremlinEntityMetadata metadata; + private final Query queryAnnotation; + private final Method method; public GremlinQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory) { super(method, metadata, factory); + this.queryAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, Query.class); + this.method = method; } @Override @@ -30,4 +39,22 @@ public EntityMetadata getEntityInformation() { return this.metadata; } + + public String getQuery() { + return queryAnnotation.value(); + } + + public boolean hasAnnotatedQuery() { + return getAnnotatedQuery() != null; + } + + private String getAnnotatedQuery() { + + final String query = (String) AnnotationUtils.getValue(getQueryAnnotation()); + return StringUtils.hasText(query) ? query : null; + } + + private Query getQueryAnnotation() { + return AnnotatedElementUtils.findMergedAnnotation(method, Query.class); + } } diff --git a/src/main/java/com/microsoft/spring/data/gremlin/repository/support/GremlinRepositoryFactory.java b/src/main/java/com/microsoft/spring/data/gremlin/repository/support/GremlinRepositoryFactory.java index 67391a0d..1ae859ed 100644 --- a/src/main/java/com/microsoft/spring/data/gremlin/repository/support/GremlinRepositoryFactory.java +++ b/src/main/java/com/microsoft/spring/data/gremlin/repository/support/GremlinRepositoryFactory.java @@ -5,7 +5,9 @@ */ package com.microsoft.spring.data.gremlin.repository.support; +import com.microsoft.spring.data.gremlin.common.GremlinFactory; import com.microsoft.spring.data.gremlin.query.GremlinOperations; +import com.microsoft.spring.data.gremlin.query.query.GraphRepositoryGremlinQuery; import com.microsoft.spring.data.gremlin.query.query.GremlinQueryMethod; import com.microsoft.spring.data.gremlin.query.query.PartTreeGremlinQuery; import org.springframework.context.ApplicationContext; @@ -55,14 +57,16 @@ public EntityInformation getEntityInformation(Class domainClas @Override protected Optional getQueryLookupStrategy( QueryLookupStrategy.Key key, QueryMethodEvaluationContextProvider provider) { - return Optional.of(new GremlinQueryLookupStrategy(this.operations)); + return Optional.of(new GremlinQueryLookupStrategy(this.context, this.operations)); } private static class GremlinQueryLookupStrategy implements QueryLookupStrategy { private final GremlinOperations operations; + private final ApplicationContext context; - public GremlinQueryLookupStrategy(@NonNull GremlinOperations operations) { + public GremlinQueryLookupStrategy(@NonNull ApplicationContext context, @NonNull GremlinOperations operations) { + this.context = context; this.operations = operations; } @@ -73,7 +77,12 @@ public RepositoryQuery resolveQuery(@NonNull Method method, RepositoryMetadata m Assert.notNull(queryMethod, "queryMethod should not be null"); Assert.notNull(this.operations, "operations should not be null"); - + if (queryMethod.hasAnnotatedQuery()) { + final GremlinFactory gremlinFactory = context.getBean(GremlinFactory.class); + Assert.notNull(gremlinFactory, "gremlinFactory bean should not be null"); + return new GraphRepositoryGremlinQuery(gremlinFactory.getGremlinClient(), queryMethod, operations); + } + return new PartTreeGremlinQuery(queryMethod, this.operations); } } diff --git a/src/test/java/com/microsoft/spring/data/gremlin/common/repository/PersonRepository.java b/src/test/java/com/microsoft/spring/data/gremlin/common/repository/PersonRepository.java index c2e7e80b..a6ff17c7 100644 --- a/src/test/java/com/microsoft/spring/data/gremlin/common/repository/PersonRepository.java +++ b/src/test/java/com/microsoft/spring/data/gremlin/common/repository/PersonRepository.java @@ -5,10 +5,14 @@ */ package com.microsoft.spring.data.gremlin.common.repository; +import com.microsoft.spring.data.gremlin.annotation.Query; import com.microsoft.spring.data.gremlin.common.domain.Person; import com.microsoft.spring.data.gremlin.repository.GremlinRepository; import org.springframework.stereotype.Repository; @Repository public interface PersonRepository extends GremlinRepository { + + @Query("g.V().hasId(id)") + public Person findPersonById(String id); } diff --git a/src/test/java/com/microsoft/spring/data/gremlin/repository/PersonRepositoryIT.java b/src/test/java/com/microsoft/spring/data/gremlin/repository/PersonRepositoryIT.java index 4b00a9bd..fb8b6341 100644 --- a/src/test/java/com/microsoft/spring/data/gremlin/repository/PersonRepositoryIT.java +++ b/src/test/java/com/microsoft/spring/data/gremlin/repository/PersonRepositoryIT.java @@ -16,6 +16,7 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -231,5 +232,17 @@ public void testFindAll() { this.repository.deleteAll(); Assert.assertFalse(this.repository.findAll().iterator().hasNext()); } + + @Ignore + @Test + public void testQueryAnnotation() { + final Person result = this.repository.save(this.person); + Assert.assertNotNull(result); + final Person foundPerson = this.repository.findPersonById(this.person.getId()); + + Assert.assertNotNull(foundPerson); + Assert.assertEquals(foundPerson.getId(), this.person.getId()); + Assert.assertEquals(foundPerson.getName(), this.person.getName()); + } } From d247ededff35e039916622bba92d55104f6756c4 Mon Sep 17 00:00:00 2001 From: Ganesh Guttikonda Date: Wed, 13 Nov 2019 13:43:46 -0800 Subject: [PATCH 3/5] * Enable the integration test case ( this is validated against Microsoft Cosmos DB ) --- .../query/GraphRepositoryGremlinQuery.java | 25 ++++++++++++------- .../common/repository/PersonRepository.java | 6 +++-- .../repository/PersonRepositoryIT.java | 11 ++++---- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java b/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java index 64abb287..b89833af 100644 --- a/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java +++ b/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java @@ -6,10 +6,12 @@ package com.microsoft.spring.data.gremlin.query.query; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import org.apache.tinkerpop.gremlin.driver.Client; +import org.apache.tinkerpop.gremlin.driver.Result; import org.apache.tinkerpop.gremlin.driver.ResultSet; import org.springframework.data.repository.query.Parameter; import org.springframework.data.repository.query.Parameters; @@ -44,10 +46,9 @@ protected GremlinQuery createQuery(GremlinParameterAccessor accessor) { @Override public Object execute(@NonNull Object[] parameters) { - final GremlinParameterAccessor accessor = new GremlinParametersParameterAccessor(this.method, parameters); final String query = method.getQuery(); final Map params = this.resolveParams(this.method.getParameters(), parameters); - + final GremlinParameterAccessor accessor = new GremlinParametersParameterAccessor(this.method, parameters); final ResultProcessor processor = method.getResultProcessor().withDynamicProjection(accessor); final Class methodReturnType = processor.getReturnedType().getDomainType(); final ResultSet rs = this.gremlinClient.submit(query, params); @@ -55,11 +56,18 @@ public Object execute(@NonNull Object[] parameters) { if (ResultSet.class.equals(methodReturnType)) { return rs; } - + final GremlinSource source = GremlinUtils.toGremlinSource(methodReturnType); if (GremlinTemplate.class.equals(this.operations.getClass())) { try { - return ((GremlinTemplate) this.operations).recoverDomainList(source, rs.all().get()); + final List gremlinResults = rs.all().get(); + final List results = ((GremlinTemplate) this.operations).recoverDomainList(source, gremlinResults); + + if (results != null && results.size() == 1) { + // return pojo instead of list + return results.get(0); + } + return results; } catch (InterruptedException e) { throw new IllegalStateException(e); } catch (ExecutionException e) { @@ -78,16 +86,15 @@ Map resolveParams(Parameters methodParameters, Object[] pa for (final Parameter parameter : methodParameters) { final int parameterIndex = parameter.getIndex(); final Object parameterValue = parameters[parameterIndex]; - - //Convenience! Client can simply pass Map params, - //we automatically resolve them to individual parameters. - //this is to allow the pass through for GremlinClient + // Convenience! Client can simply pass Map params, + // we automatically resolve them to individual parameters. + // this is to allow the pass through for GremlinClient if (parameterValue instanceof Map) { resolvedParameters.putAll((Map) parameterValue); } parameter.getName().ifPresent(parameterName -> resolvedParameters.put(parameterName, parameterValue)); - } + } return resolvedParameters; } diff --git a/src/test/java/com/microsoft/spring/data/gremlin/common/repository/PersonRepository.java b/src/test/java/com/microsoft/spring/data/gremlin/common/repository/PersonRepository.java index a6ff17c7..1f7c54b0 100644 --- a/src/test/java/com/microsoft/spring/data/gremlin/common/repository/PersonRepository.java +++ b/src/test/java/com/microsoft/spring/data/gremlin/common/repository/PersonRepository.java @@ -8,11 +8,13 @@ import com.microsoft.spring.data.gremlin.annotation.Query; import com.microsoft.spring.data.gremlin.common.domain.Person; import com.microsoft.spring.data.gremlin.repository.GremlinRepository; + +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @Repository public interface PersonRepository extends GremlinRepository { - @Query("g.V().hasId(id)") - public Person findPersonById(String id); + @Query("g.V().has('name', name)") + public Person findPersonByName(@Param("name") String name); } diff --git a/src/test/java/com/microsoft/spring/data/gremlin/repository/PersonRepositoryIT.java b/src/test/java/com/microsoft/spring/data/gremlin/repository/PersonRepositoryIT.java index fb8b6341..435c47dd 100644 --- a/src/test/java/com/microsoft/spring/data/gremlin/repository/PersonRepositoryIT.java +++ b/src/test/java/com/microsoft/spring/data/gremlin/repository/PersonRepositoryIT.java @@ -33,6 +33,7 @@ public class PersonRepositoryIT { private final Person person = new Person(TestConstants.VERTEX_PERSON_ID, TestConstants.VERTEX_PERSON_NAME); private final Person person0 = new Person(TestConstants.VERTEX_PERSON_0_ID, TestConstants.VERTEX_PERSON_0_NAME); + private final Person person1 = new Person(TestConstants.VERTEX_PERSON_1_ID, TestConstants.VERTEX_PERSON_1_NAME); private final Project project = new Project(TestConstants.VERTEX_PROJECT_ID, TestConstants.VERTEX_PROJECT_NAME, TestConstants.VERTEX_PROJECT_URI); @@ -233,16 +234,16 @@ public void testFindAll() { Assert.assertFalse(this.repository.findAll().iterator().hasNext()); } - @Ignore + @Test public void testQueryAnnotation() { - final Person result = this.repository.save(this.person); + final Person result = this.repository.save(this.person1); Assert.assertNotNull(result); - final Person foundPerson = this.repository.findPersonById(this.person.getId()); + final Person foundPerson = this.repository.findPersonByName(this.person1.getName()); Assert.assertNotNull(foundPerson); - Assert.assertEquals(foundPerson.getId(), this.person.getId()); - Assert.assertEquals(foundPerson.getName(), this.person.getName()); + Assert.assertEquals(foundPerson.getId(), this.person1.getId()); + Assert.assertEquals(foundPerson.getName(), this.person1.getName()); } } From e86c781c0a099258c00a6cfb3a753a1b56613e66 Mon Sep 17 00:00:00 2001 From: Ganesh Guttikonda Date: Sat, 18 Jan 2020 18:55:39 -0800 Subject: [PATCH 4/5] * Codacy review feedback --- .../gremlin/query/query/GraphRepositoryGremlinQuery.java | 8 ++++++-- .../data/gremlin/repository/PersonRepositoryIT.java | 1 - 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java b/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java index b89833af..70d77160 100644 --- a/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java +++ b/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java @@ -62,7 +62,11 @@ public Object execute(@NonNull Object[] parameters) { try { final List gremlinResults = rs.all().get(); final List results = ((GremlinTemplate) this.operations).recoverDomainList(source, gremlinResults); - + if (results == null || results.isEmpty()) { + //return null for not found results + return null; + } + if (results != null && results.size() == 1) { // return pojo instead of list return results.get(0); @@ -79,7 +83,7 @@ public Object execute(@NonNull Object[] parameters) { } @SuppressWarnings({ "unchecked", "rawtypes" }) - Map resolveParams(Parameters methodParameters, Object[] parameters) { + protected Map resolveParams(Parameters methodParameters, Object[] parameters) { final Map resolvedParameters = new HashMap<>(); diff --git a/src/test/java/com/microsoft/spring/data/gremlin/repository/PersonRepositoryIT.java b/src/test/java/com/microsoft/spring/data/gremlin/repository/PersonRepositoryIT.java index 435c47dd..1f63e1e5 100644 --- a/src/test/java/com/microsoft/spring/data/gremlin/repository/PersonRepositoryIT.java +++ b/src/test/java/com/microsoft/spring/data/gremlin/repository/PersonRepositoryIT.java @@ -16,7 +16,6 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; From 932a650f1e8098e73375de53e715aa57938cbb9f Mon Sep 17 00:00:00 2001 From: Ganesh Guttikonda Date: Sat, 18 Jan 2020 18:57:34 -0800 Subject: [PATCH 5/5] * Remove the null check --- .../data/gremlin/query/query/GraphRepositoryGremlinQuery.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java b/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java index 70d77160..8f4452e8 100644 --- a/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java +++ b/src/main/java/com/microsoft/spring/data/gremlin/query/query/GraphRepositoryGremlinQuery.java @@ -67,7 +67,7 @@ public Object execute(@NonNull Object[] parameters) { return null; } - if (results != null && results.size() == 1) { + if (results.size() == 1) { // return pojo instead of list return results.get(0); }