1
votes

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);
1
You forgot to set the base package for the repositories @EnableNeo4jRepositories("org.example.repositories")Michael Hunger
Nowdays done with "setBasePackage" above, right?Danne

1 Answers

2
votes

You shouldn't put '' around the parameter. SDN will do that for you. Use just

@Query("MATCH (u:User{username:{username}}) -- (n:Data) RETURN n")
public Iterable<Data> findByUsername(@Param("username") String username);

Update:

You also need to set basePackages for @EnableNeo4jRepositories to a package with your repositories

@EnableNeo4jRepositories(basePackages = {"org.example.repositories"})

And call setBasePackage with a a package with your entities

public SpringBootMain() {
    setBasePackage("org.example.entities");
}

Source:

http://docs.spring.io/spring-data/data-neo4j/docs/current/reference/html/

Example 92. Java-based configuration