Issue #2407: NullPointerException on TreeSet load

Type: Bug ReoprtVersion: 2.7.6_01Priority: NormalStatus: FixedReplies: 2
#1

I am getting a NullPointerException on an attempt to retrieve an object with a TreeSet:

SEVERE: Servlet.service() for servlet [web.TimelinesServlet] in context with path [/Timelines] threw exception
java.lang.NullPointerException
    at model.TimelineEntry.compareTo(TimelineEntry.java:257)
    at java.util.TreeMap.compare(TreeMap.java:1294)
    at java.util.TreeMap.put(TreeMap.java:538)
    at java.util.TreeSet.add(TreeSet.java:255)
    at objectdb.java.util.TreeSet.add(Unknown Source)
    at java.util.AbstractCollection.addAll(AbstractCollection.java:344)
    at java.util.TreeSet.addAll(TreeSet.java:312)
    at objectdb.java.util.TreeSet.addAll(Unknown Source)
    at com.objectdb.o.CLT.r(CLT.java:302)
    at com.objectdb.o.TYT.extractCollection(TYT.java:95)
    at com.objectdb.o.ENT.extractCollection(ENT.java:1575)
    at objectdb.java.util.TreeSet.__odbBeforeAccess(Unknown Source)
    at objectdb.java.util.TreeSet.iterator(Unknown Source)
    at model.Timeline.jsonifyItems(Timeline.java:126)
    at web.TimelinesServlet.sendTimelineData(TimelinesServlet.java:207)
    at web.TimelinesServlet.doGet(TimelinesServlet.java:71)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
#2

The following test case demonstrates using a TreeSet and no exception is thrown:

import java.util.*;

import javax.persistence.*;

public class F2407 {
    public static void main(String[] args) {

        EntityManagerFactory emf;
        emf = Persistence.createEntityManagerFactory("objectdb:./db.tmp;drop");
        EntityManager em = emf.createEntityManager();
        
        MyEntity entity = new MyEntity();

        MyElement element1 = new MyElement();
        element1.s = "a"; 
        entity.set.add(element1);

        MyElement element2 = new MyElement();
        element2.s = "b"; 
        entity.set.add(element2);
        
        em.getTransaction().begin();
        em.persist(entity);
        em.getTransaction().commit();
        
        em.clear();
        
        entity = em.find(MyEntity.class, 1);
        entity.set.iterator();

        em.close();
        emf.close();
    }

    @Entity
    public static class MyEntity {
        @OneToMany(cascade=CascadeType.PERSIST)
        Set<MyElement> set = new TreeSet();
    }
    
    @Entity
    public static class MyElement implements Comparable {
        String s;
        
        @Override
        public int compareTo(Object o) {
            return s.compareTo(((MyElement)o).s);
        }
    }
}
ObjectDB Support
#3

The test case in #2 above does throw an exception when the L2 cache is disabled, as the tree set elements are loaded lazily and not ready for comparison when the tree is built. Build 2.7.6_02 should fix the issue.

A possible workaround, if you use a previous version of ObjectDB, is to set fetch type to EAGER:

    @Entity
    public static class MyEntity {
        @OneToMany(cascade=CascadeType.PERSIST, fetch = FetchType.EAGER)
        Set<MyElement> set = new TreeSet();
    }

Thank you for this report.

ObjectDB Support

Reply