1

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);
Danne
  • 11
  • 2

1 Answers1

2

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

František Hartman
  • 14,436
  • 2
  • 40
  • 60
  • I Already tried that..., then I get an "NullPointerException" at TransactionRollback something... When using '' I at least get {} back... - Any other suggestions ? – Danne Dec 09 '14 at 11:23
  • Can you post whole stack trace of that exception and code that is calling findByUsername method? – František Hartman Dec 09 '14 at 11:43
  • curl -i http://localhost:8080/data/search/findByUsername?username=danne I bet he is, but there must be something around transaction management that is missing... – Danne Dec 10 '14 at 06:03
  • Did you change the query to what Frant suggested? – Michael Hunger Dec 10 '14 at 07:56
  • Can you change Iterable to List and/or add @Transactional to the repository method? – Michael Hunger Dec 10 '14 at 07:57
  • After struggeling for quite a while with \@EnableTransactionManagement and \@Transactional, which I just could occasionally get to work a while before failing again, I made a simple example that worked. Then when trying to figure out why it worked I managed to nail it down to the fact that Iterable<> does not work in my case. At least if I do not know how to get transactions in place properly. But Collection<> did the trick :-), so the solution is to change "public Iterable find..." to "public Collection find..." – Danne Dec 11 '14 at 06:42