Search code examples
neo4jneo4j-ogm

MappingException with root cause NullpointerException


Context

I have a neo4j 2.3.X running on localhost, connected to an API using:

  • Neo4j-OGM
  • Spring boot
  • Spring security
  • Spring hateoas
  • Spring logging

All of this running on a java-8-oracle JVM

I tested this on windows and linux, same issue.

Problem summary

When I do a GET request on my api, with every endpoint (I tested them all), neo4j-ogm is raising a MappingException:

2016-02-24 09:52:59.821 ERROR 7496 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.neo4j.ogm.exception.MappingException: Error mapping GraphModel to instance of com.bnstips.api.database.model.BnSClass] with root cause

java.lang.NullPointerException: null
    at org.neo4j.ogm.session.Utils.coerceTypes(Utils.java:80) ~[neo4j-ogm-core-2.0.0-M02.jar:na]
    at org.neo4j.ogm.annotations.FieldWriter.write(FieldWriter.java:69) ~[neo4j-ogm-core-2.0.0-M02.jar:na]
    at org.neo4j.ogm.context.GraphEntityMapper.tryMappingAsSingleton(GraphEntityMapper.java:221) ~[neo4j-ogm-core-2.0.0-M02.jar:na]
    at org.neo4j.ogm.context.GraphEntityMapper.mapRelationship(GraphEntityMapper.java:258) ~[neo4j-ogm-core-2.0.0-M02.jar:na]
    at org.neo4j.ogm.context.GraphEntityMapper.mapRelationships(GraphEntityMapper.java:245) ~[neo4j-ogm-core-2.0.0-M02.jar:na]
    at org.neo4j.ogm.context.GraphEntityMapper.mapEntities(GraphEntityMapper.java:143) ~[neo4j-ogm-core-2.0.0-M02.jar:na]
    at org.neo4j.ogm.context.GraphEntityMapper.map(GraphEntityMapper.java:117) ~[neo4j-ogm-core-2.0.0-M02.jar:na]
    at org.neo4j.ogm.context.GraphEntityMapper.map(GraphEntityMapper.java:81) ~[neo4j-ogm-core-2.0.0-M02.jar:na]
    at org.neo4j.ogm.session.delegates.LoadByTypeDelegate.loadAll(LoadByTypeDelegate.java:73) ~[neo4j-ogm-core-2.0.0-M02.jar:na]
    at org.neo4j.ogm.session.delegates.LoadByTypeDelegate.loadAll(LoadByTypeDelegate.java:110) ~[neo4j-ogm-core-2.0.0-M02.jar:na]
    at org.neo4j.ogm.session.Neo4jSession.loadAll(Neo4jSession.java:97) ~[neo4j-ogm-core-2.0.0-M02.jar:na]
    at com.bnstips.api.database.GenericService.findAll(GenericService.java:18) ~[classes/:na]
    at com.bnstips.api.endpoint.ClassEndpoint.getClasses(ClassEndpoint.java:54) ~[classes/:na]
...

I stopped the stack trace copy at the first line where my own code is, but if needed, I can copy the whole trace.

My project is done like the first example here: http://neo4j.com/docs/ogm/java/stable/

So I have a GenericService<T> extended by all my Services with CRUD operations.

Here is ClassEndpoint.getClasses(long id) implementation:

@RequestMapping(method=RequestMethod.GET)
@ResponseBody
public Iterable<BnSClass> getClasses(){

    Iterable<BnSClass> classes = this.service.findAll();
    classes.forEach((c) -> {
        c.createLinks();
    });
    return classes;
}

and findAll method:

 @Override
 public Iterable<T> findAll() {
     return session.loadAll(getEntityType(), DEPTH_LIST);//DEPTH_LIST is -1
 }

and finally, Class model:

@NodeEntity(label="Class")
public class BnSClass extends Entity<BnSClass>{

    private String name;

    @Relationship(type="TIP_FOR", direction="INCOMING")
    @JsonIgnore private Set<Tip> tips = new HashSet<Tip>(); 

    @Relationship(type="USED_BY", direction="INCOMING")
    @JsonIgnore private Set<Build> builds = new HashSet<Build>();

    ...Getters and Setters ommited
}

Database

My database is so simple that I can show it to you by a simple screenshot:

Database structure

:Class nodes are using only one property: name.

EDIT:

pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.2.RELEASE</version>
</parent>

<properties>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-hateoas</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-logging</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.6.0</version>
    </dependency>        
    <dependency>
        <groupId>org.neo4j</groupId>
        <artifactId>neo4j-ogm-api</artifactId>
        <version>2.0.0-M02</version>
    </dependency>
    <dependency>
        <groupId>org.neo4j</groupId>
        <artifactId>neo4j-ogm-core</artifactId>
        <version>2.0.0-M02</version>
    </dependency>
</dependencies>

EDIT 2: After some tries I managed to get rid of the bug, but for that I have to set DEPTH_ENTITY to 1 but it only fixes findAll() queries, so this is not a solution, but it might give a way to find a solution.


Solution

  • Ok I found where it was from, let me explain:

    BnSClass extends Commentable<T>, Here is Commentable<T>:

    @NodeEntity
    public abstract class Commentable<T> extends Rateable<T>{
    
        @Relationship(type="COMMENTED", direction="INCOMING")
        @JsonIgnore private Set<Comment> comments = new HashSet<Comment>(); 
    
        public Set<Comment> getComments(){
            return this.comments;
        }
    }
    

    As you can see, Commentable<T> adds a set of Comment to my object, and the problem was coming from Comment:

    @NodeEntity
    @JsonPropertyOrder({"id", "content", "score"})
    public class Comment extends Commentable<Comment> implements CreationDate{
    
        @Relationship(type="COMMENTED", direction="OUTGOING")
        @JsonIgnore private Entity<?> subject;
    
        private String content;
    
        private long edited;
    
        private boolean deleted = false;
    
        @JsonIgnore private Authored authored;
    }
    

    If I set subject type to Entity rawtype, it works like a charm, but if I let Entity<?> as type, it produces this error. Since almost every resources in my api are commentable or have a Set, this error occured everytime I was fetching from the database.

    N.B: Every node entity inherits from Entity<T>, which is the Entity<T> class provided in neo4j-ogm guide.