Search code examples
javaspringspring-data-neo4jneo4j-ogmspring-data-neo4j-5

Spring-framework Neo4jRepository function, findById, causes a Cypher Error


Background

My spring data neo4j application is giving out cypher errors.

This is odd because I am using neo ogm to manage all of my cyper statements, I have not written any cypher myself.

Here are my errors:

Cypher Error in CLI output

Error executing Cypher "Neo.ClientError.Statement.SyntaxError"; Code: Neo.ClientError.Statement.SyntaxError; Description: Invalid input '|': expected whitespace, comment, a relationship pattern, '.', node labels, '[', "=~", IN, STARTS, ENDS, CONTAINS, IS, '^', '*', '/', '%', '+', '-', '=', "<>", "!=", '<', '>', "<=", ">=", AND, XOR, OR, ',' or ']...

OGM error in CLI output after the cypher error

...nested exception is org.neo4j.ogm.exception.CypherException: Error executing Cypher \"Neo.ClientError.Statement.SyntaxError\"; Code: Neo.ClientError.Statement.SyntaxError; Description: Invalid input '|': expected whitespace, comment, a relationship pattern, '...

Error locating the spot in my code where the error originates (GenericService)

...myproject.service.GenericService.find(GenericService.java:39) ~[classes/:na]...

Line 39 of GenericService

Optional<T> object = getRepository().findById(id, depth);

Where I'm stuck

findById is declared in the springframework.data.neo4j.repository.Neo4jRepository.java as Optional<T> findById(ID id, int depth);

I have recently started using neo4jrepository instead of graphrepository since I switched to the Spring data neo4j 5.0.0.

So, I think I have located the issue in the code, but its not my code, its the library, but I cant' believe that a the most recent neo4j ogm was released with a bug in the findById function.

Question

How do I get past this Cypher Error? Where could this problem be originating from?

UPDATE 1

I am using neo4j-ogm-version 3.0.0, spring-boot 2.0.0.M3, Neo4J is 3.2.3 and spring-data-neo4j 5.0.0.RELEASE,

UPDATE 2

Could it be that my id is instantiated as a Long whereas Neo4jRepository.java has is instantiated as an ID?

MORE CONTEXT in GenericService.java

public T find(Long id) {
    Optional<T> object = getRepository().findById(id, DEPTH_ENTITY);
    if(object.isPresent())
            return object.get();
    return null;
}

UPDATE 3

springframework.data.neo4j.repository.Neo4jRepository.java contains

@NoRepositoryBean
public interface Neo4jRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {

    <S extends T> S save(S s, int depth);

    <S extends T> Iterable<S> save(Iterable<S> entities, int depth);

    Optional<T> findById(ID id, int depth);

    Iterable<T> findAll();

    Iterable<T> findAll(int depth);

    Iterable<T> findAll(Sort sort);

    Iterable<T> findAll(Sort sort, int depth);

    Iterable<T> findAllById(Iterable<ID> ids);

    Iterable<T> findAllById(Iterable<ID> ids, int depth);

    Iterable<T> findAllById(Iterable<ID> ids, Sort sort);

    Iterable<T> findAllById(Iterable<ID> ids, Sort sort, int depth);

    /**
     * Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
     * {@link Page#getTotalPages()} returns an estimation of the total number of pages and should not be relied upon for accuracy.
     *
     * @param pageable
     * @return a page of entities
     */
    Page<T> findAll(Pageable pageable);

    /**
     * Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
     * {@link Page#getTotalPages()} returns an estimation of the total number of pages and should not be relied upon for accuracy.
     *
     * @param pageable
     * @param depth
     * @return a page of entities
     */
    Page<T> findAll(Pageable pageable, int depth);
}

Solution

  • Looks like you are not very familiar with Java and its generics type.

    Let's take it step by step :

    1. You need to define an entity, for example

      @NodeEntity
      public class User {
          @Id @GeneratedValue
          private Long id;
          ...
      
    2. Then define a repository extending Neo4jRepository from SDN

      public interface UserRepository extends Neo4jRepository<User, Long> {
      }
      

    This way you specialize Neo4jRepository by indicating you want a repository to manage User whose identity is defined by a Long. The method defined in Neo4jRepository :

    Optional<T> findById(ID id, int depth);
    

    Becomes this specialized version in your repository

    Optional<User> findById(Long id, int depth);
    

    You never use Neo4jRepository directly, only the sub-interfaces you define.

    For much more details please check the Spring Data commons reference. Also consider having a look at java generic types.

    Update

    Besides the fact the use of SDN is incorrect, I think the cause of the error is that you use a Neo4j version < 3.1

    I highly doubt you are using 3.2.3 as specified in your comment. Please double check.