CAY-2358 NPE when callbacks invoked on null objects
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/65ebda99 Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/65ebda99 Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/65ebda99 Branch: refs/heads/master Commit: 65ebda996b5dff7b9887a45fc1d5c5759192f8e3 Parents: 8452d41 Author: Nikita Timofeev <stari...@gmail.com> Authored: Thu Aug 31 12:20:49 2017 +0300 Committer: Nikita Timofeev <stari...@gmail.com> Committed: Thu Aug 31 12:20:49 2017 +0300 ---------------------------------------------------------------------- .../reflect/LifecycleCallbackEventHandler.java | 16 +++++------ .../org/apache/cayenne/query/EJBQLQueryIT.java | 29 ++++++++++++++++++++ docs/doc/src/main/resources/RELEASE-NOTES.txt | 1 + 3 files changed, 37 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/65ebda99/cayenne-server/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackEventHandler.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackEventHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackEventHandler.java index db596bb..fd044a6 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackEventHandler.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/reflect/LifecycleCallbackEventHandler.java @@ -20,7 +20,6 @@ package org.apache.cayenne.reflect; import org.apache.cayenne.Persistent; import org.apache.cayenne.map.EntityResolver; -import org.apache.cayenne.map.ObjEntity; import java.lang.reflect.Method; import java.util.ArrayList; @@ -111,14 +110,8 @@ class LifecycleCallbackEventHandler { * Registers a callback object to be invoked when a lifecycle event occurs. */ private void addCallback(Class<?> entityClass, AbstractCallback callback) { - Collection<AbstractCallback> entityListeners = listeners.get(entityClass - .getName()); - - if (entityListeners == null) { - entityListeners = new ArrayList<>(3); - listeners.put(entityClass.getName(), entityListeners); - } - + Collection<AbstractCallback> entityListeners = listeners + .computeIfAbsent(entityClass.getName(), k -> new ArrayList<>(3)); entityListeners.add(callback); } @@ -126,6 +119,11 @@ class LifecycleCallbackEventHandler { * Invokes callbacks for a given entity object. */ void performCallbacks(Persistent object) { + if(object == null) { + // this can happen if object resolved to null from some query with outer join + // (e.g. in EJBQL or SQLTemplate) + return; + } // default listeners are invoked first if (!defaultListeners.isEmpty()) { http://git-wip-us.apache.org/repos/asf/cayenne/blob/65ebda99/cayenne-server/src/test/java/org/apache/cayenne/query/EJBQLQueryIT.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/query/EJBQLQueryIT.java b/cayenne-server/src/test/java/org/apache/cayenne/query/EJBQLQueryIT.java index 2e148ef..a760f3c 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/query/EJBQLQueryIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/query/EJBQLQueryIT.java @@ -28,6 +28,8 @@ import org.apache.cayenne.ejbql.EJBQLException; import org.apache.cayenne.exp.Expression; import org.apache.cayenne.map.EJBQLQueryDescriptor; import org.apache.cayenne.map.EntityResolver; +import org.apache.cayenne.map.LifecycleEvent; +import org.apache.cayenne.reflect.LifecycleCallbackRegistry; import org.apache.cayenne.test.jdbc.DBHelper; import org.apache.cayenne.test.jdbc.TableHelper; import org.apache.cayenne.testdo.testmap.Artist; @@ -645,4 +647,31 @@ public class EJBQLQueryIT extends ServerCase { } } + @Test + public void testNullObjectsCallback() throws Exception { + tArtist.insert(1, "a1"); + tArtist.insert(2, "a2"); + tArtist.insert(3, "a3"); + + tPainting.insert(1, 2, "title1"); + tPainting.insert(2, 1, "title2"); + tPainting.insert(3, 1, "title3"); + + // set callback to be called + LifecycleCallbackRegistry registry = runtime + .getDataDomain() + .getEntityResolver() + .getCallbackRegistry(); + registry.addCallback(LifecycleEvent.POST_LOAD, Painting.class, "postAddCallback"); + + // select Paintings, where one of it will be null + EJBQLQuery queryFullProduct = new EJBQLQuery("select a.paintingArray+ from Artist a order by a.artistName"); + List<Painting> result1 = context.performQuery(queryFullProduct); + assertEquals(4, result1.size()); + assertNull(result1.get(3)); + for(int i=0; i<3; i++) { + assertNotNull(result1.get(i)); + assertTrue(result1.get(i).isPostAdded()); + } + } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/65ebda99/docs/doc/src/main/resources/RELEASE-NOTES.txt ---------------------------------------------------------------------- diff --git a/docs/doc/src/main/resources/RELEASE-NOTES.txt b/docs/doc/src/main/resources/RELEASE-NOTES.txt index 77e14a3..d80050a 100644 --- a/docs/doc/src/main/resources/RELEASE-NOTES.txt +++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt @@ -38,6 +38,7 @@ CAY-2353 Broken paginated column select with only one entity in the result CAY-2354 DbGenerator.runGenerator must commit its connection CAY-2356 EJBQL: Incorrect COUNT() on outer joined table CAY-2357 Generic select queries silently convert result to nulls if no PK column found +CAY-2358 NPE when callbacks invoked on null objects ---------------------------------- Release: 4.0.B1