I have two @NodeEntity classes:
@NodeEntity
class User {
@GraphId
Long id;
String username;
}
@NodeEntity
class Data {
@GraphId
Long id;
String data;
@RelatedTo(direction=Direction.BOTH)
User user;
}
And one repository:
@RepositoryRestResource(collectionResourceRel="data", itemResourceRel="data", path="data")
public interface DataRepository extends GraphRepository<Data> {
// @Query("MATCH (u:User{username:'danne'}) -- (n:Data) RETURN n")
// This works in CLI but not here...
@Query("MATCH (u:User{username:'{username}'}) -- (n:Data) RETURN n")
public Iterable<Data> findByUsername(@Param("username") String username);
}
And for total clarity, spring-boot main...
@ComponentScan
@EnableAutoConfiguration
@EnableNeo4jRepositories
@Configuration
public class SpringBootMain extends Neo4jConfiguration {
public SpringBootMain() {
setBasePackage("org.example");
}
@Bean
GraphDatabaseService graphDatabaseService() {
return new GraphDatabaseFactory().newEmbeddedDatabase("build/test/dataneo4j.db");
}
@Autowired
GraphDatabase graphDatabase;
public static void main(String[] args) {
SpringApplication.run(SpringBootMain.class, args);
}
}
And of course there is a UserRepository exactly like above, but with no search functions.
I tried adding a User node and 1 Data Node connecting to it using REST interface curl.
$ curl -i -H "Content-Type: application/json" -d '{ "username" : "danne" }' -X POST http://localhost:8080/users
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: http://localhost:8080/users/1
Content-Length: 0
Date: Tue, 09 Dec 2014 19:34:39 GMT
$ curl -i -H "Content-Type: application/json" -d '{ "data" : "dataA", "user":"http://localhost:8080/users/1"}' -X POST http://localhost:8080/data
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: http://localhost:8080/data/2
Content-Length: 0
Date: Tue, 09 Dec 2014 19:36:59 GMT
That works just fine. Inspecting everything through REST also looks okey.
$ curl -i http://localhost:8080/data
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/hal+json
Transfer-Encoding: chunked
Date: Tue, 09 Dec 2014 19:37:32 GMT
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/data{?page,size,sort}",
"templated" : true
},
"search" : {
"href" : "http://localhost:8080/data/search"
}
},
"_embedded" : {
"data" : [ {
"data" : "dataA",
"_links" : {
"self" : {
"href" : "http://localhost:8080/data/2"
},
"user" : {
"href" : "http://localhost:8080/data/2/user"
}
}
} ]
},
"page" : {
"size" : 20,
"totalElements" : 1,
"totalPages" : 1,
"number" : 0
}
}
I can also go into neo4jshell and execute the commented out query above, that works just fine. But, when accessing the search method findByUsername on the REST interface result set is empty.
What is wrong with the Query, what do I have to alter to get the REST interface to accept it properly ?
Frant Artm suggested removing the quotes, but that does not make spring-boot happy...
java.lang.NullPointerException: null
at org.neo4j.kernel.TopLevelTransaction.markAsRollbackOnly(TopLevelTransaction.java:93)
at org.neo4j.kernel.TopLevelTransaction.failure(TopLevelTransaction.java:86)
at org.neo4j.cypher.internal.spi.v2_1.TransactionBoundQueryContext.close(TransactionBoundQueryContext.scala:64)
at org.neo4j.cypher.internal.compiler.v2_1.spi.DelegatingQueryContext.close(DelegatingQueryContext.scala:40)
at org.neo4j.cypher.internal.compiler.v2_1.spi.ExceptionTranslatingQueryContext.org$neo4j$cypher$internal$compiler$v2_1$spi$ExceptionTranslatingQueryContext$$super$close(ExceptionTranslatingQueryContext.scala:34)
at org.neo4j.cypher.internal.compiler.v2_1.spi.ExceptionTranslatingQueryContext$$anonfun$close$1.apply$mcV$sp(ExceptionTranslatingQueryContext.scala:34)
at org.neo4j.cypher.internal.compiler.v2_1.spi.ExceptionTranslatingQueryContext$$anonfun$close$1.apply(ExceptionTranslatingQueryContext.scala:34)
at org.neo4j.cypher.internal.compiler.v2_1.spi.ExceptionTranslatingQueryContext$$anonfun$close$1.apply(ExceptionTranslatingQueryContext.scala:34)
at org.neo4j.cypher.internal.compiler.v2_1.spi.ExceptionTranslatingQueryContext.org$neo4j$cypher$internal$compiler$v2_1$spi$ExceptionTranslatingQueryContext$$translateException(ExceptionTranslatingQueryContext.scala:149)
at org.neo4j.cypher.internal.compiler.v2_1.spi.ExceptionTranslatingQueryContext.close(ExceptionTranslatingQueryContext.scala:34)
at org.neo4j.cypher.internal.compiler.v2_1.spi.DelegatingQueryContext.close(DelegatingQueryContext.scala:40)
at org.neo4j.cypher.internal.compiler.v2_1.executionplan.ExecutionWorkflowBuilder$$anonfun$runWithQueryState$1.apply(ExecutionPlanBuilder.scala:165)
at org.neo4j.cypher.internal.compiler.v2_1.executionplan.ExecutionWorkflowBuilder$$anonfun$runWithQueryState$1.apply(ExecutionPlanBuilder.scala:165)
at org.neo4j.cypher.internal.compiler.v2_1.TaskCloser$$anonfun$1.apply(TaskCloser.scala:43)
at org.neo4j.cypher.internal.compiler.v2_1.TaskCloser$$anonfun$1.apply(TaskCloser.scala:41)
at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251)
at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251)
at scala.collection.immutable.List.foreach(List.scala:318)
at scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:251)
at scala.collection.AbstractTraversable.flatMap(Traversable.scala:105)
at org.neo4j.cypher.internal.compiler.v2_1.TaskCloser.close(TaskCloser.scala:40)
at org.neo4j.cypher.internal.compiler.v2_1.ClosingIterator$$anonfun$close$1.apply$mcV$sp(ClosingIterator.scala:67)
at org.neo4j.cypher.internal.compiler.v2_1.ClosingIterator$$anonfun$close$1.apply(ClosingIterator.scala:67)
at org.neo4j.cypher.internal.compiler.v2_1.ClosingIterator$$anonfun$close$1.apply(ClosingIterator.scala:67)
at org.neo4j.cypher.internal.compiler.v2_1.ClosingIterator$$anonfun$translateException$1.apply(ClosingIterator.scala:72)
at org.neo4j.cypher.internal.compiler.v2_1.ClosingIterator.decoratedCypherException(ClosingIterator.scala:102)
at org.neo4j.cypher.internal.compiler.v2_1.ClosingIterator.translateException(ClosingIterator.scala:70)
at org.neo4j.cypher.internal.compiler.v2_1.ClosingIterator.close(ClosingIterator.scala:66)
at org.neo4j.cypher.internal.compiler.v2_1.ClosingIterator$$anonfun$failIfThrows$1.apply(ClosingIterator.scala:96)
at org.neo4j.cypher.internal.compiler.v2_1.ClosingIterator.decoratedCypherException(ClosingIterator.scala:102)
at org.neo4j.cypher.internal.compiler.v2_1.ClosingIterator.failIfThrows(ClosingIterator.scala:91)
at org.neo4j.cypher.internal.compiler.v2_1.ClosingIterator.hasNext(ClosingIterator.scala:34)
at org.neo4j.cypher.internal.compiler.v2_1.PipeExecutionResult.hasNext(PipeExecutionResult.scala:166)
at scala.collection.Iterator$$anon$11.hasNext(Iterator.scala:327)
at scala.collection.convert.Wrappers$IteratorWrapper.hasNext(Wrappers.scala:29)
at org.neo4j.cypher.internal.compiler.v2_1.PipeExecutionResult$$anon$1.hasNext(PipeExecutionResult.scala:74)
at org.neo4j.helpers.collection.IteratorWrapper.hasNext(IteratorWrapper.java:42)
at org.springframework.data.rest.webmvc.AbstractRepositoryRestController.entitiesToResources(AbstractRepositoryRestController.java:222)
at org.springframework.data.rest.webmvc.AbstractRepositoryRestController.resultToResources(AbstractRepositoryRestController.java:203)
at org.springframework.data.rest.webmvc.RepositorySearchController.executeQueryMethod(RepositorySearchController.java:242)
at org.springframework.data.rest.webmvc.RepositorySearchController.executeSearch(RepositorySearchController.java:146)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1736)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1695)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
SOLUTION:
The suggestions in the comments were correct, the quotes should not be there, and Iterable<> requires transaction handling, which is a separate problem I will not address here.
Change
@Query("MATCH (u:User{username:'{username}'}) -- (n:Data) RETURN n")
public Iterable<Data> findByUsername(@Param("username") String username);
to
@Query("MATCH (u:User{username:{username}}) -- (n:Data) RETURN n")
public Collection<Data> findByUsername(@Param("username") String username);
@EnableNeo4jRepositories("org.example.repositories")
– Michael Hunger