Search code examples
javalistnullpointerexceptionhttpsession

List<Object> is not null, but can't call .isEmpty without nullpointer exception


    Laerer laerer = (Laerer) session.getAttribute("laererInnlogget");
    List<Spoerreskjema> ss = laerer.getSkjemaliste();

    if(ss == null)
        System.out.println("1");
    if(ss != null)
        System.out.println("2");
    if(ss.isEmpty())
        System.out.println("3");
    if(!ss.isEmpty())
        System.out.println("4");

The if-loops are there to show what the problem is.

The console will show 2, and then throw a NullPointerException upon reaching ss.isEmpty()

The laerer object is not null, but contains a List which should be null (or atleast empty)

All of this is stored, and fetched in/from a postgresql database.

Any idea what the problem could be?

Btw, calling ss.size() will also cause NullPointerException

I essentially want to be able to check if the list is empty, or not.

SEVERE: Servlet.service() for servlet [no.hib.prosjekt01.controllers.laerer.LaererHjemServlet] in context with path [/prosjekt01] threw exception
java.lang.NullPointerException
    at org.apache.openjpa.enhance.no$hib$prosjekt01$models$Laerer$pcsubclass.pcReplaceField(Unknown Source)
    at org.apache.openjpa.kernel.StateManagerImpl.replaceField(StateManagerImpl.java:3254)
    at org.apache.openjpa.kernel.StateManagerImpl.storeObjectField(StateManagerImpl.java:2681)
    at org.apache.openjpa.kernel.StateManagerImpl.storeObject(StateManagerImpl.java:2671)
    at org.apache.openjpa.jdbc.meta.strats.StoreCollectionFieldStrategy.load(StoreCollectionFieldStrategy.java:596)
    at org.apache.openjpa.jdbc.meta.FieldMapping.load(FieldMapping.java:934)
    at org.apache.openjpa.jdbc.kernel.JDBCStoreManager.load(JDBCStoreManager.java:681)
    at org.apache.openjpa.kernel.DelegatingStoreManager.load(DelegatingStoreManager.java:117)
    at org.apache.openjpa.kernel.ROPStoreManager.load(ROPStoreManager.java:78)
    at org.apache.openjpa.kernel.StateManagerImpl.loadFields(StateManagerImpl.java:3146)
    at org.apache.openjpa.kernel.StateManagerImpl.loadField(StateManagerImpl.java:3226)
    at org.apache.openjpa.kernel.StateManagerImpl.fetchObjectField(StateManagerImpl.java:2468)
    at org.apache.openjpa.kernel.StateManagerImpl.fetchField(StateManagerImpl.java:890)
    at org.apache.openjpa.kernel.StateManagerImpl.fetch(StateManagerImpl.java:852)
    at org.apache.openjpa.enhance.RedefinitionHelper$1.invoke(RedefinitionHelper.java:230)
    at com.sun.proxy.$Proxy68.isEmpty(Unknown Source)
    at no.hib.prosjekt01.controllers.laerer.LaererHjemServlet.doGet(LaererHjemServlet.java:35)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
    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.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    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.tomee.catalina.OpenEJBValve.invoke(OpenEJBValve.java:44)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    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.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)

Edit1:

Creating subclass for "[class no.hib.prosjekt01.models.Spoerreskjema, class no.hib.prosjekt01.models.Laerer, class no.hib.prosjekt01.models.Svar, class no.hib.prosjekt01.models.Spoersmaal, class no.hib.prosjekt01.models.Kryptering]". This means that your application will be less efficient and will consume more memory than it would if you ran the OpenJPA enhancer. Additionally, lazy loading will not be available for one-to-one and many-to-one persistent attributes in types using field access; they will be loaded eagerly instead.

Edit2:

@Entity
@Table(name = "laerer")
public class Laerer implements Serializable {
private static final long serialVersionUID = 1L;

@Id
private String id;
private String fornavn;
private String etternavn;
@Lob
private byte[] passord;

@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "laerer")
private List<Spoerreskjema> skjemaliste;



public Laerer(String epost, String fornavn, String etternavn, byte[] passord) {
    this.id = epost;
    this.fornavn = fornavn;
    this.etternavn = etternavn;
    this.passord = passord;
    this.skjemaliste = new ArrayList<Spoerreskjema>();
}

public Laerer() {
    id = null;
    fornavn = null;
    etternavn = null;
    passord = null;
    skjemaliste = null;
}

Solution

  • OK now I have it. You are loading the Laerer Object and then placing it in the session. Somewhere later you try to access a lazy loaded collection on it. But the problem is, that the proxy inside of your list, which should call your database to get the data, needs to be in the same transaction as your call to the database when you loaded Laerer.

    There a several solutions.

    1. When you know that there are not so many objects in that list change to "EAGER" and you are happy.

    2. In your DAO after you got the Laerer Object from the entitymanager call the list to load it. Same as loading it directly "EAGER". (JPA defines that an entity can only have one EAGER Loaded list)

    3. Don't load directly the list. Instead load the list of IDs when loading Laerer Object. When you then access the list of ids over the session you can call the database again to load the required objects by IDs. For example you can place the list of IDs as a comma seperated string in a transient variable of your entity. This string can directly be use in an SELECT a FROM a.class WHERE a.id IN (:IDS) Query.