Bug 494408 - Memory leak in EntityManager.createQuery
Signed-off-by: David Kral <david.k.kral@oracle.com>
Reviewed-by: Lukas Jungmann <lukas.jungmann@oracle.com>
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/criteria/AdvancedCriteriaQueryTestSuite.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/criteria/AdvancedCriteriaQueryTestSuite.java
index 858630c..06ed186 100644
--- a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/criteria/AdvancedCriteriaQueryTestSuite.java
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/criteria/AdvancedCriteriaQueryTestSuite.java
@@ -18,6 +18,7 @@
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.lang.reflect.Field;
 import java.math.BigInteger;
 import java.util.Collection;
 import java.util.HashSet;
@@ -57,6 +58,8 @@
 import org.eclipse.persistence.config.ResultSetType;
 import org.eclipse.persistence.config.ResultType;
 import org.eclipse.persistence.internal.jpa.querydef.CompoundExpressionImpl;
+import org.eclipse.persistence.internal.jpa.querydef.CriteriaQueryImpl;
+import org.eclipse.persistence.internal.jpa.querydef.FromImpl;
 import org.eclipse.persistence.internal.sessions.AbstractSession;
 import org.eclipse.persistence.jpa.JpaCriteriaBuilder;
 import org.eclipse.persistence.jpa.JpaQuery;
@@ -171,6 +174,7 @@ public static Test suite() {
         suite.addTest(new AdvancedCriteriaQueryTestSuite("testUnusedJoinDoesNotAffectFetchJoin"));
         // Bug 464833
         suite.addTest(new AdvancedCriteriaQueryTestSuite("testGetRestrictionReturningCorrectPredicate"));
+        suite.addTest(new AdvancedCriteriaQueryTestSuite("testJoinDuplication"));
 
         return suite;
     }
@@ -1869,4 +1873,33 @@ public void testGetRestrictionReturningCorrectPredicate() {
         }
     }
 
+    /**
+     * Test that checks duplicating of joins
+     */
+    public void testJoinDuplication() throws NoSuchFieldException, IllegalAccessException {
+        EntityManager em = createEntityManager();
+        beginTransaction(em);
+        try {
+            CriteriaBuilder qb = em.getCriteriaBuilder();
+            CriteriaQuery<Employee>cq = qb.createQuery(Employee.class);
+            Root<Employee> root = cq.from(Employee.class);
+            root.join("manager");
+
+            em.createQuery(cq);
+            Field field = cq.getClass().getDeclaredField("joins");
+            field.setAccessible(true);
+            Set<FromImpl> value = (Set<FromImpl>) field.get(cq);
+            assertEquals(1, value.size());
+
+            em.createQuery(cq);
+            ((CriteriaQueryImpl<Employee>)cq).translate();
+            value = (Set<FromImpl>) field.get(cq);
+            assertEquals(1, value.size());
+        } finally {
+            rollbackTransaction(em);
+            closeEntityManager(em);
+        }
+    }
+
+
 }
diff --git a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/querydef/CriteriaQueryImpl.java b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/querydef/CriteriaQueryImpl.java
index 69071d1..1373e29 100644
--- a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/querydef/CriteriaQueryImpl.java
+++ b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/querydef/CriteriaQueryImpl.java
@@ -16,9 +16,7 @@
 
 import java.lang.reflect.Constructor;
 import java.security.AccessController;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
+import java.util.*;
 
 import javax.persistence.Tuple;
 import javax.persistence.criteria.CriteriaQuery;
@@ -61,7 +59,7 @@ public class CriteriaQueryImpl<T> extends AbstractQueryImpl<T> implements Criter
     protected SelectionImpl<?> selection;
     protected List<Order> orderBy;
 
-    protected List<FromImpl> joins;
+    protected Set<FromImpl> joins;
 
     public CriteriaQueryImpl(Metamodel metamodel, ResultType queryResult, Class result, CriteriaBuilderImpl queryBuilder) {
         super(metamodel, queryResult, queryBuilder, result);
@@ -447,7 +445,7 @@ public CriteriaQuery<T> distinct(boolean distinct) {
     @Override
     public void addJoin(FromImpl from) {
         if (this.joins == null) {
-            this.joins = new ArrayList<FromImpl>();
+            this.joins = new HashSet<FromImpl>();
         }
         this.joins.add(from);
     }