diff --git a/cayenne/src/main/java/org/apache/cayenne/util/concurrentlinkedhashmap/ConcurrentLinkedHashMap.java b/cayenne/src/main/java/org/apache/cayenne/util/concurrentlinkedhashmap/ConcurrentLinkedHashMap.java index e1d98563fd..772ced0e57 100644 --- a/cayenne/src/main/java/org/apache/cayenne/util/concurrentlinkedhashmap/ConcurrentLinkedHashMap.java +++ b/cayenne/src/main/java/org/apache/cayenne/util/concurrentlinkedhashmap/ConcurrentLinkedHashMap.java @@ -788,6 +788,7 @@ else if (onlyIfAbsent) { @Override public V remove(Object key) { + if (key == null) return null; // this class does allow null to be used as a key or value (returning here prevents an NPE). final Node node = data.remove(key); if (node == null) { return null; diff --git a/cayenne/src/test/java/org/apache/cayenne/access/DataContextPrefetchMultistepIT.java b/cayenne/src/test/java/org/apache/cayenne/access/DataContextPrefetchMultistepIT.java index 7bc9eab7b9..ca3639f263 100644 --- a/cayenne/src/test/java/org/apache/cayenne/access/DataContextPrefetchMultistepIT.java +++ b/cayenne/src/test/java/org/apache/cayenne/access/DataContextPrefetchMultistepIT.java @@ -28,6 +28,7 @@ import org.apache.cayenne.query.ObjectSelect; import org.apache.cayenne.test.jdbc.DBHelper; import org.apache.cayenne.test.jdbc.TableHelper; +import org.apache.cayenne.testdo.testmap.Artist; import org.apache.cayenne.testdo.testmap.ArtistExhibit; import org.apache.cayenne.testdo.testmap.Exhibit; import org.apache.cayenne.testdo.testmap.Gallery; @@ -286,4 +287,66 @@ public void testToManyToOne_EmptyToMany_NoRootQualifier() throws Exception { assertFalse(((ValueHolder) exhibits).isFault()); assertEquals(0, exhibits.size()); } + + private Gallery createArtistWithPaintingInGallery() { + Artist artist = context.newObject(Artist.class); + artist.setArtistName("Picasso"); + + Painting painting = context.newObject(Painting.class); + painting.setPaintingTitle("Guernica"); + artist.addToPaintingArray(painting); + + Gallery gallery = context.newObject(Gallery.class); + gallery.setGalleryName("MOMA"); + painting.setToGallery(gallery); + + context.commitChanges(); + return gallery; + } + + @Test + public void testPrefetchAcross2RelationshipsKeepingBoth_Joint() { + Gallery gallery = createArtistWithPaintingInGallery(); + + assertNotNull(gallery.getPaintingArray().get(0).getToArtist()); + + // Prefetch the artist through the two relationships + ObjectSelect.query(Gallery.class) + .prefetch(Gallery.PAINTING_ARRAY.joint()) + .prefetch(Gallery.PAINTING_ARRAY.dot(Painting.TO_ARTIST).joint()) + .select(context); + + assertNotNull(gallery.getPaintingArray().get(0).getToArtist()); + } + + @Test + public void testPrefetchAcross2RelationshipsKeepingBoth_Disjoint() { + Gallery gallery = createArtistWithPaintingInGallery(); + + assertNotNull(gallery.getPaintingArray().get(0).getToArtist()); + + // Prefetch the artist through the two relationships + ObjectSelect.query(Gallery.class) + .prefetch(Gallery.PAINTING_ARRAY.joint()) + .prefetch(Gallery.PAINTING_ARRAY.dot(Painting.TO_ARTIST).disjoint()) + .select(context); + + assertNotNull(gallery.getPaintingArray().get(0).getToArtist()); + } + + @Test + public void testPrefetchAcross2RelationshipsKeepingBoth_DisjointById() { + Gallery gallery = createArtistWithPaintingInGallery(); + + assertNotNull(gallery.getPaintingArray().get(0).getToArtist()); + + // Prefetch the artist through the two relationships + ObjectSelect.query(Gallery.class) + .prefetch(Gallery.PAINTING_ARRAY.joint()) + .prefetch(Gallery.PAINTING_ARRAY.dot(Painting.TO_ARTIST).disjointById()) + .select(context); + + assertNotNull(gallery.getPaintingArray().get(0).getToArtist()); + } + }