Bug 433075: Stream API gets no results

Signed-off-by: Lukas Jungmann <lukas.jungmann@oracle.com>
Reviewed-by: Martin Grebac
diff --git a/.gitignore b/.gitignore
index e13867d..6a05065 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
 .DS_Store
 *.class
+!**/org.eclipse.persistence.core/resource/**/jdk8/**
 *test.jar
 *model.jar
 eclipselink*.jar
diff --git a/antbuild.xml b/antbuild.xml
index 290210d..5d7a824 100644
--- a/antbuild.xml
+++ b/antbuild.xml
@@ -588,6 +588,46 @@
         <ant antfile="antbuild.xml" dir="${eclipselink.util.jaxb}"              target="build"/>
     </target>
 
+    <target name="build-jdk8" description="compile JDK 8+ specific sources">
+        <!--
+            helper target to compile JDK 8 specific sources
+            expected flow:
+            - build eclipselink.jar on JDK 7
+            - switch to JDK 8
+            - run 'ant -f antbuild.xml build-jdk8'
+               -> this creates *.class files under resources
+                  and they should be commited into the repo
+            - switch back to JDK 7
+            - run regular build
+               -> tycho takes *.class files from resources
+                  and puts them into final jar files
+        -->
+        <fail message="This target requires JDK 8">
+            <condition>
+                <not>
+                    <equals arg1="${ant.java.version}" arg2="1.8"/>
+                </not>
+            </condition>
+        </fail>
+        <property name="jdk8.tmp.dir" value="${java.io.tmpdir}/el-jdk8-compilation"/>
+        <mkdir dir="${jdk8.tmp.dir}"/>
+        <javac srcdir="${eclipselink.core}/src"
+               destdir="${jdk8.tmp.dir}"
+               includes="**/jdk8/**"
+               debug="${javac.debug}"
+               debuglevel="${javac.debuglevel}"
+               encoding="UTF-8"
+               optimize="${javac.optimize}"
+               deprecation="${javac.deprecation}"
+               failonerror="true"
+               memoryMaximumSize="512m"
+               fork="true"
+               classpath="${eclipselink.jar}"
+        />
+        <copy todir="${eclipselink.core}/resource" includeemptydirs="false" verbose="true">
+            <fileset dir="${jdk8.tmp.dir}" includes="**/jdk8/**"/>
+        </copy>
+    </target>
     <!--      *** intended for dev use only ***
     *    Create runtime components (excluding Tests) from existing classes in project heirarchy.
     *    note: oracle extension tries to be tricksy and either jars from classes like others,
diff --git a/buildsystem/org.eclipse.persistence.parent/pom.xml b/buildsystem/org.eclipse.persistence.parent/pom.xml
index a5f79c0..897f2cc 100644
--- a/buildsystem/org.eclipse.persistence.parent/pom.xml
+++ b/buildsystem/org.eclipse.persistence.parent/pom.xml
@@ -200,6 +200,11 @@
                 <artifactId>tycho-compiler-plugin</artifactId>
                 <version>${tycho.version}</version>
                 <configuration>
+                    <excludes>
+                        <!-- some sources here require JDK 8 for compilation
+                             so exclude them from the tycho build -->
+                        <exclude>**/jdk8/**</exclude>
+                    </excludes>
                     <!-- Set to force OSGi Compatability settings (defaults to "false") (Only available as of Tycho 0.16.0) -->
                     <!-- requireJREPackageImports>true</requireJREPackageImports -->
                     <!-- compilerArgument>-nowarn</compilerArgument> <disable all warnings -->
diff --git a/foundation/eclipselink.core.test/antbuild.xml b/foundation/eclipselink.core.test/antbuild.xml
index 37a5ce4..87bf01d 100644
--- a/foundation/eclipselink.core.test/antbuild.xml
+++ b/foundation/eclipselink.core.test/antbuild.xml
@@ -111,6 +111,19 @@
         </delete>
     </target>
 
+    <target name="valid-junit-java">
+        <available property="valid.junit.java.home" file="${junit.java.home}/bin/java"/>
+    </target>
+
+    <target name="check-jdk8" description="Check availability of JDK 8" if="${valid.junit.java.home}" depends="valid-junit-java">
+        <exec outputproperty="jdk.detection.output" executable="${junit.java.home}/bin/java">
+            <arg line="-version"/>
+        </exec>
+        <condition property="compat.jdk8" value="true">
+            <matches string="${jdk.detection.output}" pattern="1.(?:[8-9]|[1-9]\d)(?:.\d+)*.*"/>
+        </condition>
+    </target>
+
     <target name="init">
         <!-- Give this a default value if not set in a user.home or test property file -->
         <property name="extensions.depend.dir" value="../${core_test.2.base.dir}/extension.lib.external"/>
@@ -187,6 +200,9 @@
             </and>
         </condition>
 
+        <!-- java tests should run with -->
+        <property name="junit.java.home" value="${java.home}"/>
+
         <!-- Can be set e.g. in test.properties to add VM options for a particular platform/driver  -->
         <property name="additional.jvmargs" value="-Ddummy2=dummy"/>
     </target>
@@ -336,6 +352,9 @@
         <antcall target="run-test" inheritRefs="true">
             <param name="TEST_CLASS" value="org.eclipse.persistence.testing.tests.security.SecurityTestModel"/>
         </antcall>
+        <ant target="test-jdk8" antfile="${ant.file}">
+            <property name="junit.java.home" value="${env.JAVA8_HOME}"/>
+        </ant>
         <antcall target="generate-report" inheritRefs="true"/>
     </target>
 
@@ -412,9 +431,18 @@
         <antcall target="run-test" inheritRefs="true">
             <param name="TEST_CLASS" value="org.eclipse.persistence.testing.tests.TestRunModel"/>
         </antcall>
+        <ant target="test-jdk8" antfile="${ant.file}">
+            <property name="junit.java.home" value="${env.JAVA8_HOME}"/>
+        </ant>
         <antcall target="generate-report" inheritRefs="true"/>
     </target>
 
+    <target name="test-jdk8" depends="check-jdk8" if="${compat.jdk8}">
+        <antcall target="run-test" inheritRefs="true">
+            <param name="TEST_CLASS" value="org.eclipse.persistence.testing.tests.transparentindirection.TransparentIndirectionModel"/>
+        </antcall>
+    </target>
+
     <!-- Prompt runner test target, runs test.class from test.properties (default is LRG). -->
     <target name="test-prompt">
         <antcall target="run-test-prompt" inheritRefs="true">
@@ -464,7 +492,7 @@
         <mkdir dir="${core_test.report.dir}"/>
         <!-- 282012: On a 64-bit JVM - The XML processing at the end of the testing requires at least 1536 -->
         <!-- Note: on a legacy XP OS with 4GB ram - the max is 1536 - use of 2048 will cause [junit] [WARN ] Unable to acquire some virtual address space - reduced from 2048 to 1908MB. -->
-        <junit printsummary="yes" failureproperty="junit.failed" fork="yes" forkmode="once" showoutput="true" maxmemory="${max.heap.memory}" dir="${core_test.run.dir}">
+        <junit printsummary="yes" failureproperty="junit.failed" fork="yes" forkmode="once" showoutput="true" maxmemory="${max.heap.memory}" dir="${core_test.run.dir}" jvm="${junit.java.home}/bin/java">
             <jvmarg value="-Declipselink.logging.level=${logging.level}"/>
             <jvmarg value="-Ddb.driver=${db.driver}"/>
             <jvmarg value="-Ddb.url=${db.url}"/>
diff --git a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/models/relationshipmaintenance/Customer.java b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/models/relationshipmaintenance/Customer.java
index f838a7a..ed02b23 100644
--- a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/models/relationshipmaintenance/Customer.java
+++ b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/models/relationshipmaintenance/Customer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.

+ * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the 

  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 

  * which accompanies this distribution. 

@@ -12,8 +12,9 @@
  ******************************************************************************/  

 package org.eclipse.persistence.testing.models.relationshipmaintenance;

 

-import java.util.*;

-import org.eclipse.persistence.indirection.*;

+import java.util.Collection;
+
+import org.eclipse.persistence.indirection.IndirectCollectionsFactory;
 

 public class Customer {

     public java.util.Collection salespeople;

@@ -24,7 +25,7 @@
      * Customer constructor comment.

      */

     public Customer() {

-        salespeople = new IndirectSet();

+        salespeople = IndirectCollectionsFactory.createIndirectSet();
     }

 

     public void addSalesPerson(SalesPerson aSalesPerson) {

diff --git a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/models/relationshipmaintenance/SalesPerson.java b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/models/relationshipmaintenance/SalesPerson.java
index 78e9b88..e029c57 100644
--- a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/models/relationshipmaintenance/SalesPerson.java
+++ b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/models/relationshipmaintenance/SalesPerson.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.

+ * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the 

  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 

  * which accompanies this distribution. 

@@ -13,7 +13,10 @@
 package org.eclipse.persistence.testing.models.relationshipmaintenance;

 

 import java.util.*;

-import org.eclipse.persistence.indirection.*;

+
+import org.eclipse.persistence.indirection.IndirectCollectionsFactory;
+import org.eclipse.persistence.indirection.ValueHolder;
+import org.eclipse.persistence.indirection.ValueHolderInterface;
 

 public class SalesPerson {

     public int id;

@@ -26,7 +29,7 @@
      */

     public SalesPerson() {

         fieldOffice = new ValueHolder();

-        customers = new IndirectSet();

+        customers = IndirectCollectionsFactory.createIndirectSet();
     }

 

     public void addCustomer(Customer aCustomer) {

diff --git a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/IndirectListTestAPI.java b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/IndirectListTestAPI.java
index 36d47e3..e4c5d02 100644
--- a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/IndirectListTestAPI.java
+++ b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/IndirectListTestAPI.java
@@ -1,442 +1,463 @@
 /*******************************************************************************
- * Copyright (c) 1998, 2014 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
  * which accompanies this distribution.
- * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html

- * and the Eclipse Distribution License is available at 

- * http://www.eclipse.org/org/documents/edl-v10.php.

- *

- * Contributors:

- *     Oracle - initial API and implementation from Oracle TopLink

- ******************************************************************************/  

+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation from Oracle TopLink
+ ******************************************************************************/
 package org.eclipse.persistence.testing.tests.transparentindirection;
 
-import java.util.*;
-
-import org.eclipse.persistence.indirection.*;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Vector;
+import org.eclipse.persistence.indirection.IndirectCollectionsFactory;
+import org.eclipse.persistence.indirection.IndirectList;
+import org.eclipse.persistence.indirection.ValueHolderInterface;
 import org.eclipse.persistence.internal.helper.JavaSEPlatform;
-import org.eclipse.persistence.sessions.*;
-import org.eclipse.persistence.queries.*;
+import org.eclipse.persistence.internal.indirection.QueryBasedValueHolder;
+import org.eclipse.persistence.queries.ReadAllQuery;
+import org.eclipse.persistence.sessions.DatabaseRecord;
 
-/**

- * Test a simple IndirectList.

+/**
+ * Test a simple IndirectList.
  * @author: Big Country
  */
 public class IndirectListTestAPI extends ZTestCase {
 
+    private Vector<String> list;
+    private IndirectList<String> testList;
+
     /**
-     * Vector with sort method to verify sorting with JDK < 1.8.
-     * @param <E> Object type stored inside.
+     * Constructor
+     * @param name java.lang.String
      */
-    public static final class VectorWithSort<E> extends Vector<E> {
-
-        /**
-         * Creates an instance of Vector with sort method with provided initial
-         * elements.
-         * @param collection The collection whose elements are to be placed into
-         *                   this vector.
-         */
-        private VectorWithSort(final Collection<? extends E> collection) {
-            super(collection);
-        }
-
-        /**
-         * Creates an instance of Vector.
-         */
-        private VectorWithSort() {
-            super();
-        }
-
-        /**
-         * JDK 1.8 sort implemented in Vector to verify sorting on JDK < 1.8
-         * @param c Comparator to define sorting order.
-         */
-        public synchronized void sort(final Comparator<? super E> c) {
-            final int expectedModCount = modCount;
-            Arrays.sort((E[]) elementData, 0, elementCount, c);
-            if (modCount != expectedModCount) {
-                throw new ConcurrentModificationException();
-            }
-            modCount++;
-        }
+    public IndirectListTestAPI(String name) {
+        super(name);
     }
 
     /**
-     * Indirect list with delegate {@see Vector} setter.
-     * @param <E> Object type stored inside.
+     * set up the test fixture:
+     * 1. an IndirectList based on a Vector
      */
-    private static final class IndirectListWrapper<E> extends IndirectList<E> {
+    protected void setUp() {
+        super.setUp();
+        list = this.setUpList();
+        Object temp = new Vector<>(list);
 
-        /**
-         * Creates an instance of IndirectList with provided initial capacity.
-         * @param initialCapacity Internal initial capacity.
-         */
-        private IndirectListWrapper(final int initialCapacity) {
-            super(0);
-        }
+        ValueHolderInterface vh = new QueryBasedValueHolder(new ReadAllQuery(), new DatabaseRecord(), new TestSession(temp));
+        testList = IndirectCollectionsFactory.createIndirectList();
+        testList.setValueHolder(vh);
+    }
 
-        /**
-         * Allow to set delegate object from outside.
-         * @param delegate Delegate object to be set.
-         */
-        private final void setDelegate(final Vector<E> delegate) {
-            this.delegate = delegate;
-        }
+    protected Vector setUpList() {
+        Vector<String> result = new Vector<>();
+        result.addElement("zero");
+        result.addElement("one");
+        result.addElement("two");
+        result.addElement("three");
+        result.addElement("four");
+        result.addElement("five");
+        result.addElement("six");
+        result.addElement("seven");
+        result.addElement("eight");
+        result.addElement("nine");
+        return result;
     }
 
     /**
-     * Do we run with at least Java SE 1.8?
-     * @return Value of {@code true} when we run with Java SE 1.8 or higher
-     *         or {@code false} otherwise.
+     * nothing for now...
      */
-    private static final boolean atLeastJava8() {
-        return JavaSEPlatform.CURRENT.atLeast(JavaSEPlatform.v1_8);
+    @Override
+    protected void tearDown() {
+        super.tearDown();
     }
 
-    Vector list;
-    IndirectList testList;
+    public void testAdd1() {
+        String temp = "foo";
 
-    /**

-     * Constructor

-     * @param name java.lang.String

-     */

-    public IndirectListTestAPI(String name) {

-        super(name);

-    }

-

-    /**

-     * set up the test fixture:

-     * 1. an IndirectList based on a Vector

-     */

-    protected void setUp() {

-        super.setUp();

-        list = this.setUpList();

-        Object temp = new Vector(list);

-

-        org.eclipse.persistence.indirection.ValueHolderInterface vh = new org.eclipse.persistence.internal.indirection.QueryBasedValueHolder(new ReadAllQuery(), new DatabaseRecord(), new TestSession(temp));

-        testList = new IndirectList();

-        testList.setValueHolder(vh);

-    }

-

-    protected Vector setUpList() {

-        Vector result = new Vector();

-        result.addElement("zero");

-        result.addElement("one");

-        result.addElement("two");

-        result.addElement("three");

-        result.addElement("four");

-        result.addElement("five");

-        result.addElement("six");

-        result.addElement("seven");

-        result.addElement("eight");

-        result.addElement("nine");

-        return result;

-    }

-

-    /**

-     * nothing for now...

-     */

-    protected void tearDown() {

-        super.tearDown();

-    }

-

-    public void testAdd1() {

-        Object temp = "foo";

-

-        list.add(3, temp);

-        testList.add(3, temp);

-        this.assertEquals(list, testList);

-        this.assertTrue(testList.contains(temp));

-    }

-

-    public void testAdd2() {

-        Object temp = "foo";

-

-        list.add(temp);

-        testList.add(temp);

-        this.assertEquals(list, testList);

-        this.assertTrue(testList.contains(temp));

-    }

-

-    public void testAddAll1() {

-        Vector temp = new Vector();

-        temp.addElement("foo");

-        temp.addElement("bar");

-

-        list.addAll(temp);

-        testList.addAll(temp);

-        this.assertEquals(list, testList);

-        this.assertTrue(testList.containsAll(temp));

-    }

-

-    public void testAddAll2() {

-        Vector temp = new Vector();

-        temp.addElement("foo");

-        temp.addElement("bar");

-

-        list.addAll(3, temp);

-        testList.addAll(3, temp);

-        this.assertEquals(list, testList);

-        this.assertTrue(testList.containsAll(temp));

-    }

-

-    public void testAddElement() {

-        Object temp = "foo";

-        list.addElement(temp);

-        testList.addElement(temp);

-        this.assertEquals(list, testList);

-        this.assertTrue(testList.contains(temp));

-    }

-

-    public void testClear() {

-        list.clear();

-        testList.clear();

-        this.assertEquals(list, testList);

-        this.assertTrue(testList.size() == 0);

-    }

-

-    public void testContains() {

-        this.assertTrue(testList.contains(list.elementAt(1)));

-    }

-

-    public void testContainsAll() {

-        this.assertTrue(testList.containsAll(list.subList(1, 5)));

-    }

-

-    public void testElementAt() {

-        this.assertEquals(list.elementAt(1), testList.elementAt(1));

-    }

-

-    public void testElements() {

-        this.assertEquals(list.elements().nextElement(), testList.elements().nextElement());

-    }

-

-    public void testEquals() {

-        this.assertTrue(testList.equals(list));

-    }

-

-    public void testFirstElement() {

-        this.assertEquals(list.firstElement(), testList.firstElement());

-    }

-

-    public void testGet() {

-        this.assertEquals(list.get(1), testList.get(1));

-    }

-

-    public void testHashCode() {

-        this.assertEquals(list.hashCode(), testList.hashCode());

-    }

-

-    public void testIndexOf1() {

-        String temp = "one";

-        this.assertEquals(list.indexOf(temp), testList.indexOf(temp));

-    }

-

-    public void testIndexOf2() {

-        String temp = "seven";

-        this.assertEquals(list.indexOf(temp, 3), testList.indexOf(temp, 3));

-    }

-

-    public void testInsertElementAt() {

-        Object temp = "foo";

-        list.insertElementAt(temp, 3);

-        testList.insertElementAt(temp, 3);

-        this.assertEquals(list, testList);

-        this.assertTrue(testList.contains(temp));

-    }

-

-    public void testIsEmpty() {

-        this.assertTrue(!testList.isEmpty());

-    }

-

-    public void testIterator() {

-        int i = 0;

-

-        for (Iterator stream = testList.iterator(); stream.hasNext(); i++) {

-            stream.next();

-        }

-        this.assertEquals(list.size(), i);

-    }

-

-    public void testLastElement() {

-        this.assertEquals(list.lastElement(), testList.lastElement());

-    }

-

-    public void testLastIndexOf1() {

-        String temp = "one";

-        this.assertEquals(list.lastIndexOf(temp), testList.lastIndexOf(temp));

-    }

-

-    public void testLastIndexOf2() {

-        String temp = "one";

-        this.assertEquals(list.lastIndexOf(temp, 7), testList.lastIndexOf(temp, 7));

-    }

-

-    public void testListIterator1() {

-        int i = 0;

-

-        for (ListIterator stream = testList.listIterator(); stream.hasNext(); i++) {

-            stream.next();

-        }

-        this.assertEquals(list.size(), i);

-    }

-

-    public void testListIterator2() {

-        int i = 0;

-

-        for (ListIterator stream = testList.listIterator(2); stream.hasNext(); i++) {

-            stream.next();

-        }

-        this.assertEquals(list.size(), i + 2);

-    }

-

-    public void testRemove1() {

-        Object temp = list.remove(1);

-        this.assertEquals(temp, testList.remove(1));

-        this.assertEquals(list, testList);

-        this.assertTrue(!testList.contains(temp));

-    }

-

-    public void testRemove2() {

-        Object temp = "one";

-

-        this.assertTrue(list.remove(temp));

-        this.assertTrue(testList.remove(temp));

-        this.assertEquals(list, testList);

-        this.assertTrue(!testList.contains(temp));

-    }

-

-    public void testRemoveAll() {

-        Vector temp = new Vector();

-        temp.addElement("one");

-        temp.addElement("two");

-

-        this.assertTrue(list.removeAll(temp));

-        this.assertTrue(testList.removeAll(temp));

-        this.assertEquals(list, testList);

-        this.assertTrue(!testList.containsAll(temp));

-    }

-

-    public void testRemoveAllElements() {

-        list.removeAllElements();

-        testList.removeAllElements();

-        this.assertEquals(list, testList);

-        this.assertTrue(testList.size() == 0);

-    }

-

-    public void testRemoveElement() {

-        Object temp = "one";

-        this.assertTrue(list.removeElement(temp));

-        this.assertTrue(testList.removeElement(temp));

-        this.assertEquals(list, testList);

-        this.assertTrue(!testList.contains(temp));

-    }

-

-    public void testRemoveElementAt() {

-        Object temp = testList.elementAt(1);

-        list.removeElementAt(1);

-        testList.removeElementAt(1);

-        this.assertEquals(list, testList);

-        this.assertTrue(!testList.contains(temp));

-    }

-

-    public void testRetainAll() {

-        Vector temp = new Vector();

-        temp.addElement("one");

-        temp.addElement("two");

-

-        this.assertTrue(list.retainAll(temp));

-        this.assertTrue(testList.retainAll(temp));

-        this.assertEquals(list, testList);

-        this.assertTrue(testList.containsAll(temp));

-        this.assertEquals(temp.size(), testList.size());

-    }

-

-    public void testSet() {

-        Object temp = "foo";

-

-        list.set(3, temp);

-        testList.set(3, temp);

-        this.assertEquals(list, testList);

-        this.assertTrue(testList.contains(temp));

-    }

-

-    public void testSetElementAt() {

-        Object temp = "foo";

-        list.setElementAt(temp, 3);

-        testList.setElementAt(temp, 3);

-        this.assertEquals(list, testList);

-        this.assertTrue(testList.contains(temp));

-    }

-

-    public void testSize() {

-        this.assertEquals(list.size(), testList.size());

-    }

-

-    public void testSubList() {

-        this.assertEquals(list.subList(2, 5), testList.subList(2, 5));

-    }

-

-    public void testToArray1() {

-        Object[] temp = list.toArray();

-        Vector v1 = new Vector(temp.length);

-        for (int i = 0; i < temp.length; i++) {

-            v1.addElement(temp[i]);

-        }

-        temp = testList.toArray();

-        Vector v2 = new Vector(temp.length);

-        for (int i = 0; i < temp.length; i++) {

-            v2.addElement(temp[i]);

-        }

-

-        this.assertEquals(v1, v2);

-    }

-

-    public void testToArray2() {

-        String[] temp = (String[])list.toArray(new String[0]);

-        Vector v1 = new Vector(temp.length);

-        for (int i = 0; i < temp.length; i++) {

-            v1.addElement(temp[i]);

-        }

-        temp = (String[])testList.toArray(new String[0]);

-        Vector v2 = new Vector(temp.length);

-        for (int i = 0; i < temp.length; i++) {

-            v2.addElement(temp[i]);

-        }

+        list.add(3, temp);
+        testList.add(3, temp);
+        this.assertEquals(list, testList);
+        this.assertTrue(testList.contains(temp));
+    }
+
+    public void testAdd2() {
+        String temp = "foo";
+
+        list.add(temp);
+        testList.add(temp);
+        this.assertEquals(list, testList);
+        this.assertTrue(testList.contains(temp));
+    }
+
+    public void testAddAll1() {
+        Vector temp = new Vector();
+        temp.addElement("foo");
+        temp.addElement("bar");
+
+        list.addAll(temp);
+        testList.addAll(temp);
+        this.assertEquals(list, testList);
+        this.assertTrue(testList.containsAll(temp));
+    }
+
+    public void testAddAll2() {
+        Vector temp = new Vector();
+        temp.addElement("foo");
+        temp.addElement("bar");
+
+        list.addAll(3, temp);
+        testList.addAll(3, temp);
+        this.assertEquals(list, testList);
+        this.assertTrue(testList.containsAll(temp));
+    }
+
+    public void testAddElement() {
+        String temp = "foo";
+        list.addElement(temp);
+        testList.addElement(temp);
+        this.assertEquals(list, testList);
+        this.assertTrue(testList.contains(temp));
+    }
+
+    public void testClear() {
+        list.clear();
+        testList.clear();
+        this.assertEquals(list, testList);
+        this.assertTrue(testList.size() == 0);
+    }
+
+    public void testContains() {
+        this.assertTrue(testList.contains(list.elementAt(1)));
+    }
+
+    public void testContainsAll() {
+        this.assertTrue(testList.containsAll(list.subList(1, 5)));
+    }
+
+    public void testElementAt() {
+        this.assertEquals(list.elementAt(1), testList.elementAt(1));
+    }
+
+    public void testElements() {
+        this.assertEquals(list.elements().nextElement(), testList.elements().nextElement());
+    }
+
+    public void testEquals() {
+        this.assertTrue(testList.equals(list));
+    }
+
+    public void testFirstElement() {
+        this.assertEquals(list.firstElement(), testList.firstElement());
+    }
+
+    public void testGet() {
+        this.assertEquals(list.get(1), testList.get(1));
+    }
+
+    public void testHashCode() {
+        this.assertEquals(list.hashCode(), testList.hashCode());
+    }
+
+    public void testIndexOf1() {
+        String temp = "one";
+        this.assertEquals(list.indexOf(temp), testList.indexOf(temp));
+    }
+
+    public void testIndexOf2() {
+        String temp = "seven";
+        this.assertEquals(list.indexOf(temp, 3), testList.indexOf(temp, 3));
+    }
+
+    public void testInsertElementAt() {
+        String temp = "foo";
+        list.insertElementAt(temp, 3);
+        testList.insertElementAt(temp, 3);
+        this.assertEquals(list, testList);
+        this.assertTrue(testList.contains(temp));
+    }
+
+    public void testIsEmpty() {
+        this.assertTrue(!testList.isEmpty());
+    }
+
+    public void testIterator() {
+        int i = 0;
+
+        for (Iterator stream = testList.iterator(); stream.hasNext(); i++) {
+            stream.next();
+        }
+        this.assertEquals(list.size(), i);
+    }
+
+    public void testLastElement() {
+        this.assertEquals(list.lastElement(), testList.lastElement());
+    }
+
+    public void testLastIndexOf1() {
+        String temp = "one";
+        this.assertEquals(list.lastIndexOf(temp), testList.lastIndexOf(temp));
+    }
+
+    public void testLastIndexOf2() {
+        String temp = "one";
+        this.assertEquals(list.lastIndexOf(temp, 7), testList.lastIndexOf(temp, 7));
+    }
+
+    public void testListIterator1() {
+        int i = 0;
+
+        for (ListIterator stream = testList.listIterator(); stream.hasNext(); i++) {
+            stream.next();
+        }
+        this.assertEquals(list.size(), i);
+    }
+
+    public void testListIterator2() {
+        int i = 0;
+
+        for (ListIterator stream = testList.listIterator(2); stream.hasNext(); i++) {
+            stream.next();
+        }
+        this.assertEquals(list.size(), i + 2);
+    }
+
+    public void testRemove1() {
+        Object temp = list.remove(1);
+        this.assertEquals(temp, testList.remove(1));
+        this.assertEquals(list, testList);
+        this.assertTrue(!testList.contains(temp));
+    }
+
+    public void testRemove2() {
+        Object temp = "one";
+
+        this.assertTrue(list.remove(temp));
+        this.assertTrue(testList.remove(temp));
+        this.assertEquals(list, testList);
+        this.assertTrue(!testList.contains(temp));
+    }
+
+    public void testRemoveAll() {
+        Vector temp = new Vector();
+        temp.addElement("one");
+        temp.addElement("two");
+
+        this.assertTrue(list.removeAll(temp));
+        this.assertTrue(testList.removeAll(temp));
+        this.assertEquals(list, testList);
+        this.assertTrue(!testList.containsAll(temp));
+    }
+
+    public void testRemoveAllElements() {
+        list.removeAllElements();
+        testList.removeAllElements();
+        this.assertEquals(list, testList);
+        this.assertTrue(testList.size() == 0);
+    }
+
+    public void testRemoveElement() {
+        Object temp = "one";
+        this.assertTrue(list.removeElement(temp));
+        this.assertTrue(testList.removeElement(temp));
+        this.assertEquals(list, testList);
+        this.assertTrue(!testList.contains(temp));
+    }
+
+    public void testRemoveElementAt() {
+        Object temp = testList.elementAt(1);
+        list.removeElementAt(1);
+        testList.removeElementAt(1);
+        this.assertEquals(list, testList);
+        this.assertTrue(!testList.contains(temp));
+    }
+
+    public void testRetainAll() {
+        Vector temp = new Vector();
+        temp.addElement("one");
+        temp.addElement("two");
+
+        this.assertTrue(list.retainAll(temp));
+        this.assertTrue(testList.retainAll(temp));
+        this.assertEquals(list, testList);
+        this.assertTrue(testList.containsAll(temp));
+        this.assertEquals(temp.size(), testList.size());
+    }
+
+    public void testSet() {
+        String temp = "foo";
+
+        list.set(3, temp);
+        testList.set(3, temp);
+        this.assertEquals(list, testList);
+        this.assertTrue(testList.contains(temp));
+    }
+
+    public void testSetElementAt() {
+        String temp = "foo";
+        list.setElementAt(temp, 3);
+        testList.setElementAt(temp, 3);
+        this.assertEquals(list, testList);
+        this.assertTrue(testList.contains(temp));
+    }
+
+    public void testSize() {
+        this.assertEquals(list.size(), testList.size());
+    }
+
+    public void testSubList() {
+        this.assertEquals(list.subList(2, 5), testList.subList(2, 5));
+    }
+
+    public void testToArray1() {
+        Object[] temp = list.toArray();
+        Vector v1 = new Vector(temp.length);
+        for (int i = 0; i < temp.length; i++) {
+            v1.addElement(temp[i]);
+        }
+        temp = testList.toArray();
+        Vector v2 = new Vector(temp.length);
+        for (int i = 0; i < temp.length; i++) {
+            v2.addElement(temp[i]);
+        }
 
         this.assertEquals(v1, v2);
     }
 
-    // TODO: Rewrite to work directly with Vector#sort(Comparator) when source level will be at least 1.8
+    public void testToArray2() {
+        String[] temp = list.toArray(new String[0]);
+        Vector v1 = new Vector(temp.length);
+        for (int i = 0; i < temp.length; i++) {
+            v1.addElement(temp[i]);
+        }
+        temp = testList.toArray(new String[0]);
+        Vector v2 = new Vector(temp.length);
+        for (int i = 0; i < temp.length; i++) {
+            v2.addElement(temp[i]);
+        }
+
+        this.assertEquals(v1, v2);
+    }
+
+    //Java SE 8 API
     public void testSort() {
-        final Vector<String> data = atLeastJava8() ? new Vector<String>(list) : new VectorWithSort<String>(list);
-        final VectorWithSort<String> sortedData = new VectorWithSort<String>(list);
-        final IndirectListWrapper<String> list = new IndirectListWrapper<String>(data.size());
-        sortedData.sort(null);
-        list.setDelegate(data);
-        list.sort(null);
-        assertEquals(data.size(), sortedData.size());
-        for (int i = 0; i < sortedData.size(); i++) {
-            this.assertEquals(data.get(i), sortedData.get(i));
-        }
-    }
+        assertElementsEqual(list, testList);
+        Comparator c = new Comparator<String>() {
 
-    // TODO: Rewrite to work directly with Vector#sort(Comparator) when source level will be at least 1.8
-    public void testSortOnCommonVector() {
-        final Vector<String> data = new Vector<String>(list);
-        final IndirectListWrapper<String> list = new IndirectListWrapper<String>(data.size());
-        list.setDelegate(data);
+            @Override
+            public int compare(String o1, String o2) {
+                return o1.compareTo(o2);
+            }
+        };
         try {
-            list.sort(null);
-            if (!atLeastJava8()) {
-                fail("Sort shall throw an exception on JDK < 1.8.");
-            }
+            callMethod(testList, "sort", new Class[]{Comparator.class}, new Object[]{c});
         } catch (UnsupportedOperationException e) {
-            if (atLeastJava8()) {
-                fail("Sort shall work since JDK 1.8.");
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
             }
         }
+        list = new Vector<>();
+        list.addElement("eight");
+        list.addElement("five");
+        list.addElement("four");
+        list.addElement("nine");
+        list.addElement("one");
+        list.addElement("seven");
+        list.addElement("six");
+        list.addElement("three");
+        list.addElement("two");
+        list.addElement("zero");
+        assertElementsEqual(list, testList);
     }
 
+    public void testSpliterator() {
+        Object o = null;
+        try {
+            o = callMethod(testList, "spliterator", new Class[0], new Object[0]);
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertNotNull("Should get an instance of java.util.Spliterator", o);
+        boolean streamFound = false;
+        for (Class c: o.getClass().getInterfaces()) {
+            if ("java.util.Spliterator".equals(c.getName())) {
+                streamFound = true;
+                break;
+            }
+        }
+        assertTrue("not implementing java.util.Spliterator", streamFound);
+    }
+
+    public void testStream() {
+        Object o = null;
+        try {
+            o = callMethod(testList, "stream", new Class[0], new Object[0]);
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertNotNull("Should get an instance of java.util.stream.Stream", o);
+        boolean streamFound = false;
+        if (o.getClass().getEnclosingClass() != null) {
+            for (Class c: o.getClass().getEnclosingClass().getInterfaces()) {
+                if ("java.util.stream.Stream".equals(c.getName())) {
+                    streamFound = true;
+                    break;
+                }
+            }
+        }
+        assertTrue("not implementing java.util.stream.Stream", streamFound);
+    }
+
+    public void testParallelStream() {
+        Object o = null;
+        try {
+            o = callMethod(testList, "parallelStream", new Class[0], new Object[0]);
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertNotNull("Should get an instance of java.util.stream.Stream", o);
+        boolean streamFound = false;
+        if (o.getClass().getEnclosingClass() != null) {
+            for (Class c: o.getClass().getEnclosingClass().getInterfaces()) {
+                if ("java.util.stream.Stream".equals(c.getName())) {
+                    streamFound = true;
+                    break;
+                }
+            }
+        }
+        assertTrue("not implementing java.util.stream.Stream", streamFound);
+    }
+
+    private Object callMethod(List list, String method, Class[] params, Object[] args) {
+        try {
+            Method m = list.getClass().getMethod(method, params);
+            return m.invoke(list, args);
+        } catch (NoSuchMethodException | SecurityException | IllegalArgumentException | IllegalAccessException | InvocationTargetException ex) {
+            if (JavaSEPlatform.CURRENT.atLeast(JavaSEPlatform.v1_8)) {
+                fail("cannot call method '" + method + "' " + ex.getMessage());
+            } else {
+                throw new UnsupportedOperationException();
+            }
+        }
+        return null;
+    }
 }
diff --git a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/IndirectMapTestAPI.java b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/IndirectMapTestAPI.java
index 60fd49b..5de3113 100644
--- a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/IndirectMapTestAPI.java
+++ b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/IndirectMapTestAPI.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.

+ * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the 

  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 

  * which accompanies this distribution. 

@@ -12,18 +12,29 @@
  ******************************************************************************/  

 package org.eclipse.persistence.testing.tests.transparentindirection;

 

-import java.util.*;

-import org.eclipse.persistence.indirection.*;

-import org.eclipse.persistence.sessions.*;

-import org.eclipse.persistence.queries.*;

+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.fail;
+import org.eclipse.persistence.indirection.IndirectCollectionsFactory;
+import org.eclipse.persistence.indirection.IndirectMap;
+import org.eclipse.persistence.indirection.ValueHolderInterface;
+import org.eclipse.persistence.internal.helper.JavaSEPlatform;
+import org.eclipse.persistence.internal.indirection.QueryBasedValueHolder;
+import org.eclipse.persistence.queries.ReadAllQuery;
+import org.eclipse.persistence.sessions.DatabaseRecord;
 

 /**

  * Test a simple IndirectMap.

  * @author: Big Country

  */

 public class IndirectMapTestAPI extends ZTestCase {

-    Hashtable map;

-    IndirectMap testMap;

+    private Hashtable<String, String> map;
+    private IndirectMap<String, String> testMap;
 

     public IndirectMapTestAPI(String name) {

         super(name);

@@ -70,13 +81,13 @@
         map = this.setUpMap();

         Object temp = new Hashtable(map);

 

-        org.eclipse.persistence.indirection.ValueHolderInterface vh = new org.eclipse.persistence.internal.indirection.QueryBasedValueHolder(new ReadAllQuery(), new DatabaseRecord(), new TestSession(temp));

-        testMap = new IndirectMap();

+        ValueHolderInterface vh = new QueryBasedValueHolder(new ReadAllQuery(), new DatabaseRecord(), new TestSession(temp));
+        testMap = IndirectCollectionsFactory.createIndirectMap();
         testMap.setValueHolder(vh);

     }

 

-    protected Hashtable setUpMap() {

-        Hashtable result = new Hashtable();

+    protected Hashtable<String, String> setUpMap() {
+        Hashtable<String, String> result = new Hashtable<>();
         result.put("zero", "000");

         result.put("one", "111");

         result.put("two", "222");

@@ -154,8 +165,8 @@
     }

 

     public void testPut() {

-        Object key = "foo";

-        Object value = "bar";

+        String key = "foo";
+        String value = "bar";
         map.put(key, value);

         testMap.put(key, value);

 

@@ -165,7 +176,7 @@
     }

 

     public void testPutAll() {

-        Hashtable temp = new Hashtable();

+        Hashtable<String, String> temp = new Hashtable<>();
         temp.put("foo", "bar");

         temp.put("sna", "fu");

 

@@ -181,7 +192,7 @@
     }

 

     public void testRemove() {

-        Object temp = "one";

+        String temp = "one";
         this.assertTrue(map.remove(temp) != null);

         this.assertTrue(testMap.remove(temp) != null);

         this.assertEquals(map, testMap);

@@ -201,4 +212,140 @@
         map.values().removeAll(testMap.values());

         this.assertTrue(map.values().isEmpty());

     }

+
+    public void testReplace() {
+        assertEquals(map, testMap);
+        Object o = null;
+        try {
+            o = callMethod(testMap, "replace", new Class[] {Object.class, Object.class}, new Object[] {"one", "1"});
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertNotNull("Should return value", o);
+        assertEquals("111", o);
+        assertEquals("1", testMap.get("one"));
+    }
+
+    public void testReplaceWithDefault() {
+        assertEquals("111", testMap.get("one"));
+        Object o = null;
+        try {
+            o = callMethod(testMap, "replace", new Class[] {Object.class, Object.class, Object.class}, new Object[] {"one", "1", "1234"});
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertFalse("Should return false", (boolean) o);
+        assertFalse("Should not have '1234'", testMap.containsValue("1234"));
+
+        assertEquals("111", testMap.get("one"));
+        try {
+            o = callMethod(testMap, "replace", new Class[] {Object.class, Object.class, Object.class}, new Object[] {"one", "111", "1234"});
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertTrue("Should return true", (boolean) o);
+        assertEquals("1234", testMap.get("one"));
+    }
+
+    public void testGetOrDefault() {
+        Object o = null;
+        assertFalse(testMap.containsKey("temp"));
+        try {
+            o = callMethod(testMap, "getOrDefault", new Class[] {Object.class, Object.class}, new Object[] {"temp", "1234"});
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertNotNull("Should return value", o);
+        assertEquals("1234", o);
+
+        assertTrue(testMap.containsKey("one"));
+        try {
+            o = callMethod(testMap, "getOrDefault", new Class[] {Object.class, Object.class}, new Object[] {"one", "5678"});
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertNotNull("Should return value", o);
+        assertEquals("111", o);
+    }
+
+    public void testPutIfAbsent() {
+        Object o = null;
+        assertFalse(testMap.containsKey("temp"));
+        try {
+            o = callMethod(testMap, "putIfAbsent", new Class[] {Object.class, Object.class}, new Object[] {"temp", "1234"});
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertNull("Should return null", o);
+
+        assertTrue(testMap.containsKey("temp"));
+        try {
+            o = callMethod(testMap, "putIfAbsent", new Class[] {Object.class, Object.class}, new Object[] {"temp", "5678"});
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertNotNull("Should return value", o);
+        assertEquals("1234", o);
+    }
+
+    public void testRemoveTwoArgs() {
+        Object o = null;
+        assertEquals("111", testMap.get("one"));
+        try {
+            o = callMethod(testMap, "remove", new Class[] {Object.class, Object.class}, new Object[] {"one", "1234"});
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertFalse("Should return false", (boolean) o);
+
+        assertEquals("111", testMap.get("one"));
+        try {
+            o = callMethod(testMap, "remove", new Class[] {Object.class, Object.class}, new Object[] {"one", "111"});
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertTrue("Should return true", (boolean) o);
+        assertNull(testMap.get("one"));
+    }
+
+    private Object callMethod(Map map, String method, Class[] params, Object[] args) {
+        try {
+            Method m = map.getClass().getMethod(method, params);
+            return m.invoke(map, args);
+        } catch (NoSuchMethodException | SecurityException | IllegalArgumentException | IllegalAccessException | InvocationTargetException ex) {
+            if (JavaSEPlatform.CURRENT.atLeast(JavaSEPlatform.v1_8)) {
+                fail("cannot call method '" + method + "' " + ex.getMessage());
+            } else {
+                throw new UnsupportedOperationException();
+            }
+        }
+        return null;
+    }
 }

diff --git a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/IndirectSetTestAPI.java b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/IndirectSetTestAPI.java
index 8e91382..1164cd5 100644
--- a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/IndirectSetTestAPI.java
+++ b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/IndirectSetTestAPI.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.

+ * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the 

  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 

  * which accompanies this distribution. 

@@ -12,10 +12,22 @@
  ******************************************************************************/  

 package org.eclipse.persistence.testing.tests.transparentindirection;

 

-import java.util.*;

-import org.eclipse.persistence.sessions.*;

+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Vector;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+import org.eclipse.persistence.indirection.IndirectCollectionsFactory;
 import org.eclipse.persistence.indirection.IndirectSet;

-import org.eclipse.persistence.queries.*;

+import org.eclipse.persistence.indirection.ValueHolderInterface;
+import org.eclipse.persistence.internal.helper.JavaSEPlatform;
+import org.eclipse.persistence.internal.indirection.QueryBasedValueHolder;
+import org.eclipse.persistence.queries.ReadAllQuery;
+import org.eclipse.persistence.sessions.DatabaseRecord;
 

 /**

  * Test a simple IndirectSet.

@@ -23,8 +35,8 @@
  * @author: Big Country

  */

 public class IndirectSetTestAPI extends ZTestCase {

-    Vector list;

-    IndirectSet testList;

+    Vector<String> list;
+    IndirectSet<String> testList;
 

     /**

      * Constructor

@@ -40,15 +52,15 @@
     protected void setUp() {

         super.setUp();

         list = this.setUpList();

-        Object temp = new HashSet(list);

+        Object temp = new HashSet<>(list);
 

-        org.eclipse.persistence.indirection.ValueHolderInterface vh = new org.eclipse.persistence.internal.indirection.QueryBasedValueHolder(new ReadAllQuery(), new DatabaseRecord(), new TestSession(temp));

-        testList = new IndirectSet();

+        ValueHolderInterface vh = new QueryBasedValueHolder(new ReadAllQuery(), new DatabaseRecord(), new TestSession(temp));
+        testList = IndirectCollectionsFactory.createIndirectSet();
         testList.setValueHolder(vh);

     }

 

     protected Vector setUpList() {

-        Vector result = new Vector();

+        Vector<String> result = new Vector<>();
         result.addElement("zero");

         result.addElement("one");

         result.addElement("two");

@@ -70,7 +82,7 @@
     }

 

     public void testAdd() {

-        Object temp = "foo";

+        String temp = "foo";
         list.add(temp);

         testList.add(temp);

         this.assertUnorderedElementsEqual(list, new Vector(testList));

@@ -78,7 +90,7 @@
     }

 

     public void testAddAll() {

-        Vector temp = new Vector();

+        Vector<String> temp = new Vector<>();
         temp.addElement("foo");

         temp.addElement("bar");

 

@@ -121,7 +133,7 @@
     }

 

     public void testRemove() {

-        Object temp = "one";

+        String temp = "one";
         this.assertTrue(list.remove(temp));

         this.assertTrue(testList.remove(temp));

         this.assertUnorderedElementsEqual(list, new Vector(testList));

@@ -129,7 +141,7 @@
     }

 

     public void testRemoveAll() {

-        Vector temp = new Vector();

+        Vector<String> temp = new Vector<>();
         temp.addElement("one");

         temp.addElement("two");

 

@@ -140,7 +152,7 @@
     }

 

     public void testRetainAll() {

-        Vector temp = new Vector();

+        Vector<String> temp = new Vector<>();
         temp.addElement("one");

         temp.addElement("two");

 

@@ -184,4 +196,85 @@
         }

         this.assertUnorderedElementsEqual(v1, v2);

     }

+
+    public void testSpliterator() {
+        Object o = null;
+        try {
+            o = callMethod(testList, "spliterator", new Class[0], new Object[0]);
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertNotNull("Should get an instance of java.util.Spliterator", o);
+        boolean streamFound = false;
+        for (Class c: o.getClass().getInterfaces()) {
+            if ("java.util.Spliterator".equals(c.getName())) {
+                streamFound = true;
+                break;
+            }
+        }
+        assertTrue("not implementing java.util.Spliterator", streamFound);
+    }
+
+    public void testStream() {
+        Object o = null;
+        try {
+            o = callMethod(testList, "stream", new Class[0], new Object[0]);
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertNotNull("Should get an instance of java.util.stream.Stream", o);
+        boolean streamFound = false;
+        if (o.getClass().getEnclosingClass() != null) {
+            for (Class c: o.getClass().getEnclosingClass().getInterfaces()) {
+                if ("java.util.stream.Stream".equals(c.getName())) {
+                    streamFound = true;
+                    break;
+                }
+            }
+        }
+        assertTrue("not implementing java.util.stream.Stream", streamFound);
+    }
+
+    public void testParallelStream() {
+        Object o = null;
+        try {
+            o = callMethod(testList, "parallelStream", new Class[0], new Object[0]);
+        } catch (UnsupportedOperationException e) {
+            if (JavaSEPlatform.CURRENT.compareTo(JavaSEPlatform.v1_8) < 0) {
+                //nothing to check on JDK 7 and lower
+                return;
+            }
+        }
+        assertNotNull("Should get an instance of java.util.stream.Stream", o);
+        boolean streamFound = false;
+        if (o.getClass().getEnclosingClass() != null) {
+            for (Class c: o.getClass().getEnclosingClass().getInterfaces()) {
+                if ("java.util.stream.Stream".equals(c.getName())) {
+                    streamFound = true;
+                    break;
+                }
+            }
+        }
+        assertTrue("not implementing java.util.stream.Stream", streamFound);
+    }
+
+    private Object callMethod(Set set, String method, Class[] params, Object[] args) {
+        try {
+            Method m = set.getClass().getMethod(method, params);
+            return m.invoke(set, args);
+        } catch (NoSuchMethodException | SecurityException | IllegalArgumentException | IllegalAccessException | InvocationTargetException ex) {
+            if (JavaSEPlatform.CURRENT.atLeast(JavaSEPlatform.v1_8)) {
+                fail("cannot call method '" + method + "' " + ex.getMessage());
+            } else {
+                throw new UnsupportedOperationException();
+            }
+        }
+        return null;
+    }
 }

diff --git a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/TransparentIndirectionModel.java b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/TransparentIndirectionModel.java
index f66a35c..ccf6105 100644
--- a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/TransparentIndirectionModel.java
+++ b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/transparentindirection/TransparentIndirectionModel.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.

+ * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the 

  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 

  * which accompanies this distribution. 

@@ -86,4 +86,10 @@
         return suite;

     }

     

+    /**
+     * Return the JUnit suite to allow JUnit runner to find it.
+     */
+    public static junit.framework.TestSuite suite() {
+        return new TransparentIndirectionModel();
+    }
 }

diff --git a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/unitofwork/DeepMergeCloneIndirectionTest.java b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/unitofwork/DeepMergeCloneIndirectionTest.java
index b7bb6ef..09fc1b4 100644
--- a/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/unitofwork/DeepMergeCloneIndirectionTest.java
+++ b/foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/tests/unitofwork/DeepMergeCloneIndirectionTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.

+ * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the 

  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 

  * which accompanies this distribution. 

@@ -17,10 +17,9 @@
 import java.io.IOException;

 import java.io.ObjectInputStream;

 import java.io.ObjectOutputStream;

-

 import java.util.Collection;

 

-import org.eclipse.persistence.indirection.IndirectList;

+import org.eclipse.persistence.indirection.IndirectCollectionsFactory;
 import org.eclipse.persistence.sessions.Session;

 import org.eclipse.persistence.sessions.UnitOfWork;

 import org.eclipse.persistence.testing.framework.TestErrorException;

@@ -51,8 +50,8 @@
         }

         getAbstractSession().beginTransaction();

         this.orderObject = new Order();

-        this.orderObject.contacts = new IndirectList();

-        this.orderObject.lines = new IndirectList();

+        this.orderObject.contacts = IndirectCollectionsFactory.createIndirectList();
+        this.orderObject.lines = IndirectCollectionsFactory.createIndirectList();
         this.orderObject.setTotal(56789);

         this.orderObject.customerName = "henry";

         //Using a unit of work here becuase this test is used in the clientSession Tests

diff --git a/foundation/org.eclipse.persistence.core/META-INF/MANIFEST.MF b/foundation/org.eclipse.persistence.core/META-INF/MANIFEST.MF
index 19ed675..b34238f 100644
--- a/foundation/org.eclipse.persistence.core/META-INF/MANIFEST.MF
+++ b/foundation/org.eclipse.persistence.core/META-INF/MANIFEST.MF
@@ -40,6 +40,7 @@
  org.eclipse.persistence.internal.history;version="2.6.0",

  org.eclipse.persistence.internal.identitymaps;version="2.6.0",

  org.eclipse.persistence.internal.indirection;version="2.6.0",

+ org.eclipse.persistence.internal.indirection.jdk8;version="2.6.0",
  org.eclipse.persistence.internal.jpa.jpql;version="2.6.0",

  org.eclipse.persistence.internal.jpa.parsing;version="2.6.0",

  org.eclipse.persistence.internal.jpa.parsing.jpql;version="2.6.0",

diff --git a/foundation/org.eclipse.persistence.core/pom.xml b/foundation/org.eclipse.persistence.core/pom.xml
index 96f143a..f911bd9 100644
--- a/foundation/org.eclipse.persistence.core/pom.xml
+++ b/foundation/org.eclipse.persistence.core/pom.xml
@@ -84,6 +84,5 @@
       </dependency>
     </dependencies>
 
-
 </project>
 
diff --git a/foundation/org.eclipse.persistence.core/resource/org/eclipse/persistence/internal/indirection/jdk8/IndirectCollectionsProvider.class b/foundation/org.eclipse.persistence.core/resource/org/eclipse/persistence/internal/indirection/jdk8/IndirectCollectionsProvider.class
new file mode 100644
index 0000000..933a373
--- /dev/null
+++ b/foundation/org.eclipse.persistence.core/resource/org/eclipse/persistence/internal/indirection/jdk8/IndirectCollectionsProvider.class
Binary files differ
diff --git a/foundation/org.eclipse.persistence.core/resource/org/eclipse/persistence/internal/indirection/jdk8/IndirectList.class b/foundation/org.eclipse.persistence.core/resource/org/eclipse/persistence/internal/indirection/jdk8/IndirectList.class
new file mode 100644
index 0000000..234d719
--- /dev/null
+++ b/foundation/org.eclipse.persistence.core/resource/org/eclipse/persistence/internal/indirection/jdk8/IndirectList.class
Binary files differ
diff --git a/foundation/org.eclipse.persistence.core/resource/org/eclipse/persistence/internal/indirection/jdk8/IndirectMap.class b/foundation/org.eclipse.persistence.core/resource/org/eclipse/persistence/internal/indirection/jdk8/IndirectMap.class
new file mode 100644
index 0000000..0d833b2
--- /dev/null
+++ b/foundation/org.eclipse.persistence.core/resource/org/eclipse/persistence/internal/indirection/jdk8/IndirectMap.class
Binary files differ
diff --git a/foundation/org.eclipse.persistence.core/resource/org/eclipse/persistence/internal/indirection/jdk8/IndirectSet.class b/foundation/org.eclipse.persistence.core/resource/org/eclipse/persistence/internal/indirection/jdk8/IndirectSet.class
new file mode 100644
index 0000000..864661e
--- /dev/null
+++ b/foundation/org.eclipse.persistence.core/resource/org/eclipse/persistence/internal/indirection/jdk8/IndirectSet.class
Binary files differ
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectCollectionsFactory.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectCollectionsFactory.java
new file mode 100644
index 0000000..ed825f5
--- /dev/null
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectCollectionsFactory.java
@@ -0,0 +1,368 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.persistence.indirection;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collection;
+import java.util.Map;
+import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
+import org.eclipse.persistence.internal.security.PrivilegedClassForName;
+import org.eclipse.persistence.logging.AbstractSessionLog;
+import org.eclipse.persistence.logging.SessionLog;
+
+/**
+ * Provides factory methods to create JDK specific implementation
+ * of particular type of {@link IndirectCollection}.
+ *
+ * @author Lukas Jungmann
+ * @see IndirectCollection
+ * @see IndirectList
+ * @see IndirectMap
+ * @see IndirectSet
+ * @since EclipseLink 2.6.0
+ */
+public final class IndirectCollectionsFactory {
+
+    //loaded using reflection to avoid runtime (and compile time) dependency on JDK 8
+    private static final String JDK8_SUPPORT_PROVIDER = "org.eclipse.persistence.internal.indirection.jdk8.IndirectCollectionsProvider";
+
+    private static final IndirectCollectionsProvider provider = getProvider();
+
+    /**
+     * Class implementing {@link IndirectList}.
+     */
+    public static final Class IndirectList_Class = provider.getListClass();
+
+    /**
+     * Class implementing {@link IndirectSet}.
+     */
+    public static final Class IndirectSet_Class = provider.getSetClass();
+
+    /**
+     * Class implementing {@link IndirectMap}.
+     */
+    public static final Class IndirectMap_Class = provider.getMapClass();
+
+    /**
+     * Construct an empty {@link IndirectList} with the default initial capacity (10)
+     * and default capacity increment (0).
+     *
+     * @param <E> the class of the objects in the list
+     * @return an empty {@link IndirectList} with the default initial capacity
+     *      and default capacity increment
+     */
+    public static <E> IndirectList<E> createIndirectList() {
+        return provider.createIndirectList(10, 0);
+    }
+
+    /**
+     * Construct an empty {@link IndirectList} with the specified initial capacity
+     * and default capacity increment (0).
+     *
+     * @param <E> the class of the objects in the list
+     * @param initialCapacity the initial capacity of the vector
+     *
+     * @return an empty {@link IndirectList} with the specified initial capacity
+     *      and default capacity increment
+     * @throws IllegalArgumentException if the specified initial capacity
+     *      is negative
+     */
+    public static <E> IndirectList<E> createIndirectList(int initialCapacity) {
+        return provider.createIndirectList(initialCapacity, 0);
+    }
+
+    /**
+     * Construct an {@link IndirectList} containing the elements of the specified
+     * collection, in the order they are returned by the collection's iterator.
+     *
+     * @param <E> the class of the objects in the list
+     * @param collection a collection containing the elements to construct
+     *      the {@link IndirectList} with.
+     * @return an {@link IndirectList} containing the elements of the specified
+     *      collection
+     */
+    public static <E> IndirectList<E> createIndirectList(Collection<? extends E> collection) {
+        return  provider.createIndirectList(collection);
+    }
+
+    /**
+     * Construct an empty {@link IndirectSet} with the default initial capacity (10)
+     * and the default load factor (0.75).
+     *
+     * @return an empty {@link IndirectSet} with the default initial capacity
+     *      and the default load factor
+     */
+    public static <E> IndirectSet<E> createIndirectSet() {
+        return provider.createIndirectSet(10, 0.75f);
+    }
+
+    /**
+     * Construct an empty {@link IndirectSet} with the specified initial capacity
+     * and the default load factor (0.75).
+     *
+     * @param initialCapacity the initial capacity of the set
+     *
+     * @return an empty {@link IndirectSet} with the specified initial capacity
+     *      and the default load factor
+     * @throws IllegalArgumentException if the specified initial capacity is negative
+     */
+    public static <E> IndirectSet<E> createIndirectSet(int initialCapacity) {
+        return provider.createIndirectSet(initialCapacity, 0.75f);
+    }
+
+    /**
+     * Constructs an {@link IndirectSet} containing the elements of the specified
+     * collection.
+     *
+     * @param collection a collection containing the elements to construct
+     *      the {@link IndirectSet} with
+     *
+     * @return an {@link IndirectSet} containing the elements of the specified collection
+     * @throws NullPointerException if the specified collection is null
+     */
+    public static <E> IndirectSet<E> createIndirectSet(Collection<? extends E> collection) {
+        return provider.createIndirectSet(collection);
+    }
+
+    /**
+     * Construct a new, empty {@link IndirectMap} with the default initial
+     * capacity (11) and the default load factor (0.75).
+     *
+     * @return a new, empty {@link IndirectMap} with the default initial
+     *      capacity and the default load factor
+     */
+    public static <K, V> IndirectMap<K, V> createIndirectMap() {
+        return provider.createIndirectMap(11, 0.75f);
+    }
+
+    /**
+     * Construct a new, empty {@link IndirectMap} with the specified initial
+     * capacity and the default load factor (0.75).
+     *
+     * @param initialCapacity the initial capacity of the {@link IndirectMap}
+     *
+     * @return a new, empty {@link IndirectMap} with the specified initial
+     *      capacity and the default load factor
+     * @throws  IllegalArgumentException  if the initial capacity is less than
+     *      or equal to zero
+     */
+    public static <K, V> IndirectMap<K, V> createIndirectMap(int initialCapacity) {
+        return provider.createIndirectMap(initialCapacity, 0.75f);
+    }
+
+    /**
+     * Construct a new {@link IndirectMap} with the same mappings as the given Map.
+     * The {@link IndirectMap} is created with a capacity of twice the number of entries
+     * in the given Map or 11 (whichever is greater), and a default load factor, which is 0.75.
+     *
+     * @param map the map whose mappings are to be placed into created {@link IndirectMap}
+     *
+     * @return a new {@link IndirectMap} with the same mappings as the given Map
+     * @throws NullPointerException if the specified map is null
+     */
+    public static <K, V> IndirectMap<K, V> createIndirectMap(Map<? extends K, ? extends V> map) {
+        return provider.createIndirectMap(map);
+    }
+
+    /**
+     * As of EclipseLink 2.6.0 this returns Java SE 7- compatible provider by default
+     * on Java SE 7 and Java SE 8+ compatible provider if Java SE 8+ is detected.
+     *
+     * @return default provider responsible for creating Java SE specific implementations
+     * of {@link IndirectCollection}s
+     */
+    private static IndirectCollectionsProvider getProvider() {
+        try {
+            if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
+                final Class support = (Class) AccessController.doPrivileged(new PrivilegedClassForName(JDK8_SUPPORT_PROVIDER, true, IndirectCollectionsFactory.class.getClassLoader()));
+                return AccessController.doPrivileged(new PrivilegedAction<IndirectCollectionsProvider>() {
+
+                    @Override
+                    public IndirectCollectionsProvider run() {
+                        try {
+                            return (IndirectCollectionsProvider) support.newInstance();
+                        } catch (InstantiationException | IllegalAccessException ex) {
+                            throw new RuntimeException(ex);
+                        }
+                    }
+                });
+            } else {
+                Class support = PrivilegedAccessHelper.getClassForName(JDK8_SUPPORT_PROVIDER, true, IndirectCollectionsFactory.class.getClassLoader());
+                return (IndirectCollectionsProvider) PrivilegedAccessHelper.newInstanceFromClass(support);
+            }
+        } catch (Throwable t) {
+            AbstractSessionLog.getLog().logThrowable(SessionLog.FINEST, SessionLog.MISC, t);
+        }
+
+        return new DefaultProvider();
+    }
+
+    /**
+     * Define API providers of {@link IndirectCollection} implementations must conform to.
+     */
+    public static interface IndirectCollectionsProvider {
+
+        /**
+         * Class implementing {@link IndirectList}.
+         *
+         * @return class implementing {@link IndirectList}
+         */
+        Class getListClass();
+
+        /**
+         * Construct an empty {@link IndirectList} with the specified initial capacity
+         * and capacity increment.
+         *
+         * @param <E> the class of the objects in the list
+         * @param initialCapacity the initial capacity of the list
+         * @param capacityIncrement the amount by which the capacity is increased
+         *      when the list overflows
+         *
+         * @return an empty {@link IndirectList} with the specified initial capacity
+         *      and capacity increment
+         * @throws IllegalArgumentException if the specified initial capacity is negative
+         */
+        <E> IndirectList<E> createIndirectList(int initialCapacity, int capacityIncrement);
+
+        /**
+         * Constructs an {@link IndirectList} containing the elements of the specified
+         * collection, in the order they are returned by the collection's iterator.
+         *
+         * @param <E> the class of the objects in the list
+         * @param collection a collection containing the elements to construct
+         *      the {@link IndirectList} with
+         *
+         * @return an {@link IndirectList} containing the elements of the specified collection
+         * @throws NullPointerException if the specified collection is null
+         */
+        <E> IndirectList<E> createIndirectList(Collection<? extends E> collection);
+
+        /**
+         * Class implementing {@link IndirectSet}.
+         *
+         * @return class implementing {@link IndirectSet}
+         */
+        Class getSetClass();
+
+        /**
+         * Construct an empty {@link IndirectSet} with the specified initial capacity
+         * and the specified load factor.
+         *
+         * @param initialCapacity the initial capacity of the set
+         * @param loadFactor the load factor of the set
+         *
+         * @return an empty {@link IndirectSet} with the specified initial capacity
+         *      and the specified load factor
+         * @throws IllegalArgumentException if the specified initial capacity is negative
+         */
+        <E> IndirectSet<E> createIndirectSet(int initialCapacity, float loadFactor);
+
+        /**
+         * Constructs an {@link IndirectSet} containing the elements of the specified
+         * collection.
+         *
+         * @param collection a collection containing the elements to construct
+         *      the {@link IndirectSet} with
+         *
+         * @return an {@link IndirectSet} containing the elements of the specified collection
+         * @throws NullPointerException if the specified collection is null
+         */
+        <E> IndirectSet<E> createIndirectSet(Collection<? extends E> collection);
+
+        /**
+         * Class implementing {@link IndirectMap}.
+         *
+         * @return class implementing {@link IndirectMap}
+         */
+        Class getMapClass();
+
+        /**
+         * Construct a new, empty {@link IndirectMap} with the specified initial
+         * capacity and the specified load factor.
+         *
+         * @param initialCapacity the initial capacity of the {@link IndirectMap}
+         * @param loadFactor a number between 0.0 and 1.0
+         *
+         * @return a new, empty {@link IndirectMap} with the specified initial
+         *      capacity and the specified load factor
+         * @throws  IllegalArgumentException  if the initial capacity is less than
+         *      or equal to zero, or if the load factor is less than or equal to zero
+         */
+        <K, V> IndirectMap<K, V> createIndirectMap(int initialCapacity, float loadFactor);
+
+        /**
+         * Construct a new {@link IndirectMap} with the same mappings as the given Map.
+         * The {@link IndirectMap} is created with a capacity of twice the number of entries
+         * in the given Map or 11 (whichever is greater), and a default load factor, which is 0.75.
+         *
+         * @param map the map whose mappings are to be placed into created {@link IndirectMap}
+         *
+         * @return a new {@link IndirectMap} with the same mappings as the given Map
+         * @throws NullPointerException if the specified map is null
+         */
+        <K, V> IndirectMap<K, V> createIndirectMap(Map<? extends K, ? extends V> map);
+    }
+
+    /**
+     * Provider for creating Java SE 7 (and older) compatible
+     * {@link IndirectCollection} implementations.
+     */
+    private static final class DefaultProvider implements IndirectCollectionsProvider {
+
+        @Override
+        public Class getListClass() {
+            return IndirectList.class;
+        }
+
+        @Override
+        public <E> IndirectList<E> createIndirectList(int initialCapacity, int capacityIncrement) {
+            return new IndirectList<>(initialCapacity, capacityIncrement);
+        }
+
+        @Override
+        public <E> IndirectList<E> createIndirectList(Collection<? extends E> collection) {
+            return new IndirectList<>(collection);
+        }
+
+        @Override
+        public Class getSetClass() {
+            return IndirectSet.class;
+        }
+
+        @Override
+        public <E> IndirectSet<E> createIndirectSet(int initialCapacity, float loadFactor) {
+            return new IndirectSet<>(initialCapacity, loadFactor);
+        }
+
+        @Override
+        public <E> IndirectSet<E> createIndirectSet(Collection<? extends E> collection) {
+            return new IndirectSet<>(collection);
+        }
+
+        @Override
+        public Class getMapClass() {
+            return IndirectMap.class;
+        }
+
+        @Override
+        public <K, V> IndirectMap<K, V> createIndirectMap(int initialCapacity, float loadFactor) {
+            return new IndirectMap<>(initialCapacity, loadFactor);
+        }
+
+        @Override
+        public <K, V> IndirectMap<K, V> createIndirectMap(Map<? extends K, ? extends V> map) {
+            return new IndirectMap<>(map);
+        }
+    }
+}
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectList.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectList.java
index 3f52ede..f56fcd6 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectList.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectList.java
@@ -1,43 +1,50 @@
 /*******************************************************************************
- * Copyright (c) 1998, 2014 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
  * which accompanies this distribution.
- * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html

- * and the Eclipse Distribution License is available at 

- * http://www.eclipse.org/org/documents/edl-v10.php.

- *

- * Contributors:

- *     Oracle - initial API and implementation from Oracle TopLink

+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation from Oracle TopLink
  ******************************************************************************/
 package org.eclipse.persistence.indirection;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.*;
 import java.beans.PropertyChangeListener;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Vector;
 
+import org.eclipse.persistence.descriptors.changetracking.CollectionChangeEvent;
+import org.eclipse.persistence.descriptors.changetracking.CollectionChangeTracker;
 import org.eclipse.persistence.internal.descriptors.changetracking.AttributeChangeListener;
-import org.eclipse.persistence.internal.indirection.*;
+import org.eclipse.persistence.internal.indirection.UnitOfWorkQueryValueHolder;
+import org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder;
 import org.eclipse.persistence.mappings.CollectionMapping;
-import org.eclipse.persistence.mappings.DatabaseMapping;

-import org.eclipse.persistence.descriptors.changetracking.*;

-

-/**

- * IndirectList allows a domain class to take advantage of TopLink indirection

- * without having to declare its instance variable as a ValueHolderInterface.

- * <p>To use an IndirectList:<ul>

- * <li> Declare the appropriate instance variable with type Collection/List/Vector (jdk1.2).

- * <li> Send the message #useTransparentCollection() to the appropriate

- * CollectionMapping.

- * </ul>

- * EclipseLink will place an

- * IndirectList in the instance variable when the containing domain object is read from

- * the datatabase. With the first message sent to the IndirectList, the contents

- * are fetched from the database and normal Collection/List/Vector behavior is resumed.

- *

- * @see org.eclipse.persistence.mappings.CollectionMapping

- * @see org.eclipse.persistence.indirection.IndirectMap

+import org.eclipse.persistence.mappings.DatabaseMapping;
+
+/**
+ * IndirectList allows a domain class to take advantage of TopLink indirection
+ * without having to declare its instance variable as a ValueHolderInterface.
+ * <p>To use an IndirectList:<ul>
+ * <li> Declare the appropriate instance variable with type Collection/List/Vector (jdk1.2).
+ * <li> Send the message #useTransparentCollection() to the appropriate
+ * CollectionMapping.
+ * </ul>
+ * EclipseLink will place an
+ * IndirectList in the instance variable when the containing domain object is read from
+ * the datatabase. With the first message sent to the IndirectList, the contents
+ * are fetched from the database and normal Collection/List/Vector behavior is resumed.
+ *
+ * @param <E> the type of elements maintained by this list
+ * @see org.eclipse.persistence.mappings.CollectionMapping
+ * @see org.eclipse.persistence.indirection.IndirectMap
  * @author Big Country
  * @since TOPLink/Java 2.5
  */
@@ -48,185 +55,189 @@
 
     /** Delegate indirection behavior to a value holder. */
     protected ValueHolderInterface valueHolder;
-

-    /** Change tracking listener. */

-    private transient PropertyChangeListener changeListener;

-    

-    /** The mapping attribute name, used to raise change events. */

-    private transient String attributeName;

-    

-    /** Store added elements to avoid instantiation on add. */

-    private transient List addedElements;

-    

-    /** Store removed elements to avoid instantiation on remove. */

-    private transient List removedElements;

-

-    /** Store initial size for lazy init. */

-    protected int initialCapacity;

-    

-    /** PERF: Quick check flag if has been registered in a unit of work. */

-    protected boolean isRegistered;

-    

-    /** 

-     * If the mapping using IndirectList has listOrderfield != null then this flag indicates

-     * whether the list in the db has invalid order:

-     * either row(s) with null order value(s) or/and "holes" in order.

-     * The flag may be set to true when the objects are read from the db.

-     * When collection is updated the flag set to true causes updating of listOrderField of all rows in the db.

-     * After update is complete the flag is set back to false. 

-     **/

-    private boolean isListOrderBrokenInDb;

-

-    /**

-     * This value is used to determine if we should attempt to do adds and removes from the list without

-     * actually instantiating the list from the database.  By default this is set to true.

-     */

-    private boolean useLazyInstantiation = true;

-    

-    /**

-     * PUBLIC:

-     * Construct an empty IndirectList so that its internal data array

-     * has size <tt>10</tt> and its standard capacity increment is zero.

-     */

-    public IndirectList() {

-        super(0, 0);

-        this.initialCapacity = 10;

-    }

-

-    /**

-     * PUBLIC:

-     * Construct an empty IndirectList with the specified initial capacity and

-     * with its capacity increment equal to zero.

-     *

-     * @param   initialCapacity   the initial capacity of the vector

-     * @exception IllegalArgumentException if the specified initial capacity

-     *               is negative

-     */

-    public IndirectList(int initialCapacity) {

-        super(0, 0);

-        this.initialCapacity = initialCapacity;

-    }

-

-    /**

-     * PUBLIC:

-     * Construct an empty IndirectList with the specified initial capacity and

-     * capacity increment.

-     *

-     * @param   initialCapacity     the initial capacity of the vector

-     * @param   capacityIncrement   the amount by which the capacity is

-     *                              increased when the vector overflows

-     * @exception IllegalArgumentException if the specified initial capacity

-     *               is negative

-     */

-    public IndirectList(int initialCapacity, int capacityIncrement) {

-        super(0, capacityIncrement);

-        this.initialCapacity = initialCapacity;

-    }

-

-    /**

-     * PUBLIC:

-     * Construct an IndirectList containing the elements of the specified

-     * collection, in the order they are returned by the collection's

-     * iterator.

-     * @param collection a collection containing the elements to construct this IndirectList with.

-     */

-    public IndirectList(Collection collection) {

-        super(0);

-        this.valueHolder = new ValueHolder(new Vector(collection));

-    }

-

+
+    /** Change tracking listener. */
+    private transient PropertyChangeListener changeListener;
+    
+    /** The mapping attribute name, used to raise change events. */
+    private transient String attributeName;
+    
+    /** Store added elements to avoid instantiation on add. */
+    private transient List addedElements;
+    
+    /** Store removed elements to avoid instantiation on remove. */
+    private transient List removedElements;
+
+    /** Store initial size for lazy init. */
+    protected int initialCapacity;
+    
+    /** PERF: Quick check flag if has been registered in a unit of work. */
+    protected boolean isRegistered;
+    
+    /** 
+     * If the mapping using IndirectList has listOrderfield != null then this flag indicates
+     * whether the list in the db has invalid order:
+     * either row(s) with null order value(s) or/and "holes" in order.
+     * The flag may be set to true when the objects are read from the db.
+     * When collection is updated the flag set to true causes updating of listOrderField of all rows in the db.
+     * After update is complete the flag is set back to false. 
+     **/
+    private boolean isListOrderBrokenInDb;
+
+    /**
+     * This value is used to determine if we should attempt to do adds and removes from the list without
+     * actually instantiating the list from the database.  By default this is set to true.
+     */
+    private boolean useLazyInstantiation = true;
+    
+    /**
+     * PUBLIC:
+     * Construct an empty IndirectList so that its internal data array
+     * has size <tt>10</tt> and its standard capacity increment is zero.
+     */
+    public IndirectList() {
+        super(0, 0);
+        this.initialCapacity = 10;
+    }
+
+    /**
+     * PUBLIC:
+     * Construct an empty IndirectList with the specified initial capacity and
+     * with its capacity increment equal to zero.
+     *
+     * @param   initialCapacity   the initial capacity of the vector
+     * @exception IllegalArgumentException if the specified initial capacity
+     *               is negative
+     */
+    public IndirectList(int initialCapacity) {
+        super(0, 0);
+        this.initialCapacity = initialCapacity;
+    }
+
+    /**
+     * PUBLIC:
+     * Construct an empty IndirectList with the specified initial capacity and
+     * capacity increment.
+     *
+     * @param   initialCapacity     the initial capacity of the vector
+     * @param   capacityIncrement   the amount by which the capacity is
+     *                              increased when the vector overflows
+     * @exception IllegalArgumentException if the specified initial capacity
+     *               is negative
+     */
+    public IndirectList(int initialCapacity, int capacityIncrement) {
+        super(0, capacityIncrement);
+        this.initialCapacity = initialCapacity;
+    }
+
+    /**
+     * PUBLIC:
+     * Construct an IndirectList containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.
+     * @param collection a collection containing the elements to construct this IndirectList with.
+     */
+    public IndirectList(Collection<? extends E> collection) {
+        super(0);
+        this.valueHolder = new ValueHolder(new Vector(collection));
+    }
+
     /**
      * @see java.util.Vector#add(int, java.lang.Object)
      */
+    @Override
     public void add(int index, E element) {
         getDelegate().add(index, element);
         raiseAddChangeEvent(element, index);
     }
-    

-    /**

-     * Raise the add change event and relationship maintenance.

-     */

-    protected void raiseAddChangeEvent(Object element, Integer index) {

-        raiseAddChangeEvent(element, index, false);

-    }    

-    protected void raiseAddChangeEvent(Object element, Integer index, boolean isSet) {

-        if (hasTrackedPropertyChangeListener()) {

-            _persistence_getPropertyChangeListener().propertyChange(new CollectionChangeEvent(this, getTrackedAttributeName(), this, element, CollectionChangeEvent.ADD, index, isSet, true));

-        }

-        if (isRelationshipMaintenanceRequired()) {

-            ((UnitOfWorkQueryValueHolder)getValueHolder()).updateForeignReferenceSet(element, null);

-        }

-    }

-    

-    protected boolean isRelationshipMaintenanceRequired() {

-        if (this.valueHolder instanceof UnitOfWorkQueryValueHolder) {

-            DatabaseMapping mapping = ((UnitOfWorkQueryValueHolder)this.valueHolder).getMapping();

-            return (mapping != null) && (mapping.getRelationshipPartner() != null);

-        }

-        return false;

-    }

-    

-    /**

-     * Raise the remove change event.

-     */

-    protected void raiseRemoveChangeEvent(Object element, Integer index) {

-        raiseRemoveChangeEvent(element, index, false);

-    }

-    protected void raiseRemoveChangeEvent(Object element, Integer index, boolean isSet) {

-        if (hasTrackedPropertyChangeListener()) {

-            _persistence_getPropertyChangeListener().propertyChange(new CollectionChangeEvent(this, getTrackedAttributeName(), this, element, CollectionChangeEvent.REMOVE, index, isSet, true));

-        }

-        if (isRelationshipMaintenanceRequired()) {

-            ((UnitOfWorkQueryValueHolder)getValueHolder()).updateForeignReferenceRemove(element);

-        }

-    }

-

+    
+    /**
+     * Raise the add change event and relationship maintenance.
+     */
+    protected void raiseAddChangeEvent(Object element, Integer index) {
+        raiseAddChangeEvent(element, index, false);
+    }    
+    protected void raiseAddChangeEvent(Object element, Integer index, boolean isSet) {
+        if (hasTrackedPropertyChangeListener()) {
+            _persistence_getPropertyChangeListener().propertyChange(new CollectionChangeEvent(this, getTrackedAttributeName(), this, element, CollectionChangeEvent.ADD, index, isSet, true));
+        }
+        if (isRelationshipMaintenanceRequired()) {
+            ((UnitOfWorkQueryValueHolder)getValueHolder()).updateForeignReferenceSet(element, null);
+        }
+    }
+    
+    protected boolean isRelationshipMaintenanceRequired() {
+        if (this.valueHolder instanceof UnitOfWorkQueryValueHolder) {
+            DatabaseMapping mapping = ((UnitOfWorkQueryValueHolder)this.valueHolder).getMapping();
+            return (mapping != null) && (mapping.getRelationshipPartner() != null);
+        }
+        return false;
+    }
+    
+    /**
+     * Raise the remove change event.
+     */
+    protected void raiseRemoveChangeEvent(Object element, Integer index) {
+        raiseRemoveChangeEvent(element, index, false);
+    }
+    protected void raiseRemoveChangeEvent(Object element, Integer index, boolean isSet) {
+        if (hasTrackedPropertyChangeListener()) {
+            _persistence_getPropertyChangeListener().propertyChange(new CollectionChangeEvent(this, getTrackedAttributeName(), this, element, CollectionChangeEvent.REMOVE, index, isSet, true));
+        }
+        if (isRelationshipMaintenanceRequired()) {
+            ((UnitOfWorkQueryValueHolder)getValueHolder()).updateForeignReferenceRemove(element);
+        }
+    }
+
     /**
      * @see java.util.Vector#add(java.lang.Object)
      */
+    @Override
     public boolean add(E element) {
         if (!this.isRegistered) {
             return getDelegate().add(element);
         }
-        boolean added = true;

-        // PERF: If not instantiated just record the add to avoid the instantiation.

-        if (shouldAvoidInstantiation()) {

-            if (hasRemovedElements() && getRemovedElements().contains(element)) {

-                getRemovedElements().remove(element);

-            } else if (isRelationshipMaintenanceRequired() && getAddedElements().contains(element)) {

-                // Must avoid recursion for relationship maintenance.

-                return false;

-            } else {

-                getAddedElements().add(element);

-            }

-        } else {

-            added = getDelegate().add(element);

-        }

-        raiseAddChangeEvent(element, null);

-        return added;

-    }

-

+        boolean added = true;
+        // PERF: If not instantiated just record the add to avoid the instantiation.
+        if (shouldAvoidInstantiation()) {
+            if (hasRemovedElements() && getRemovedElements().contains(element)) {
+                getRemovedElements().remove(element);
+            } else if (isRelationshipMaintenanceRequired() && getAddedElements().contains(element)) {
+                // Must avoid recursion for relationship maintenance.
+                return false;
+            } else {
+                getAddedElements().add(element);
+            }
+        } else {
+            added = getDelegate().add(element);
+        }
+        raiseAddChangeEvent(element, null);
+        return added;
+    }
+
     /**
      * @see java.util.Vector#addAll(int, java.util.Collection)
      */
+    @Override
     public boolean addAll(int index, Collection<? extends E> c) {
         Iterator<? extends E> objects = c.iterator();
         // Must trigger add events if tracked or uow.
         if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {
             while (objects.hasNext()) {
-                this.add(index, objects.next());

-                index++;

-            }

-            return true;

-        }

-

-        return getDelegate().addAll(index, c);

-

-    }

-

+                this.add(index, objects.next());
+                index++;
+            }
+            return true;
+        }
+
+        return getDelegate().addAll(index, c);
+
+    }
+
     /**
      * @see java.util.Vector#addAll(java.util.Collection)
      */
+    @Override
     public boolean addAll(Collection<? extends E> c) {
         // Must trigger add events if tracked or uow.
         if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {
@@ -234,174 +245,187 @@
             while (objects.hasNext()) {
                 this.add(objects.next());
             }
-            return true;

-        }

-

-        return getDelegate().addAll(c);

-    }

-

+            return true;
+        }
+
+        return getDelegate().addAll(c);
+    }
+
     /**
      * @see java.util.Vector#addElement(java.lang.Object)
      */
+    @Override
     public void addElement(E obj) {
         add(obj);
     }
 
-    /**

-     * INTERNAL:

-     * Return the freshly-built delegate.

-     */

-    protected Vector buildDelegate() {

-        Vector delegate = (Vector)getValueHolder().getValue();

-        if (delegate == null) {

-            delegate = new Vector(this.initialCapacity, this.capacityIncrement);

-        }

-        // This can either be another indirect list or a Vector.

-        // It can be another indirect list because the mapping's query uses the same container policy.

-        // Unwrap any redundant indirection layers, which can cause issues and impact performance.

-        while (delegate instanceof IndirectList) {

-            if(((IndirectList) delegate).isListOrderBrokenInDb()) {

-                this.isListOrderBrokenInDb = true;

-            }

-            delegate = ((IndirectList) delegate).getDelegate();

-        }

-        // First add/remove any cached changes.

-        if (hasAddedElements()) {

-            int size = getAddedElements().size();

-            for (int index = 0; index < size; index++) {

-                Object element = ((List)getAddedElements()).get(index);

-                // On a flush or resume the element may already be in the database.

-                if (!delegate.contains(element)) {

-                    delegate.add(element);

-                }

-            }

-            this.addedElements = null;

-        }

-        if (hasRemovedElements()) {

-            int size = getRemovedElements().size();

-            for (int index = 0; index < size; index++) {

-                delegate.remove(((List)getRemovedElements()).get(index));

-            }

-            this.removedElements = null;

-        }

-        return delegate;

-    }

-

-    /**

-     * @see java.util.Vector#capacity()

-     */

-    public int capacity() {

-        return getDelegate().capacity();

-    }

-

-    /**

-     * @see java.util.Vector#clear()

-     */

-    public void clear() {

-        removeAllElements();

-    }

-    

-    /**

-     * INTERNAL:

-     * clear any changes that have been deferred to instantiation.

-     * Indirect collections with change tracking avoid instantiation on add/remove.

-     */

-    public void clearDeferredChanges(){

-        addedElements = null;

-        removedElements = null;

-    }

-    

-    /**

-     * PUBLIC:

-     * @see java.util.Vector#clone()

-     * This will result in a database query if necessary.

-     */

-

-    /*

-        There are 3 situations when clone() is called:

-        1.    The developer actually wants to clone the collection (typically to modify one

-            of the 2 resulting collections). In which case the contents must be read from

-            the database.

-        2.    A UnitOfWork needs a clone (or backup clone) of the collection. But the

-            UnitOfWork checks "instantiation" before cloning collections ("un-instantiated"

-            collections are not cloned).

-        3.    A MergeManager needs an extra copy of the collection (because the "backup"

-            and "target" are the same object?). But the MergeManager checks "instantiation"

-            before merging collections (again, "un-instantiated" collections are not merged).

-    */

-    public synchronized Object clone() {

-        IndirectList result = (IndirectList)super.clone();

-        result.delegate = (Vector)this.getDelegate().clone();

-        result.valueHolder = new ValueHolder(result.delegate);

-        result.attributeName = null;

-        result.changeListener = null;

-        return result;

-    }

-

-    /**

-     * PUBLIC:

-     * @see java.util.Vector#contains(java.lang.Object)

-     */

-    public boolean contains(Object element) {

-        // PERF: Avoid instantiation if not required.

-        if (hasAddedElements()) {

-            if (getAddedElements().contains(element)) {

-                return true;

-            }

-        }

-        if (hasRemovedElements()) {

-            if (getRemovedElements().contains(element)) {

-                return false;

-            }

-        }

-        return getDelegate().contains(element);

-    }

-

-    /**

-     * @see java.util.Vector#containsAll(java.util.Collection)

-     */

-    public boolean containsAll(Collection c) {

-        return getDelegate().containsAll(c);

-    }

-

-    /**

-     * @see java.util.Vector#copyInto(java.lang.Object[])

-     */

-    public synchronized void copyInto(Object[] anArray) {

-        getDelegate().copyInto(anArray);

-    }

-

+    /**
+     * INTERNAL:
+     * Return the freshly-built delegate.
+     */
+    protected Vector<E> buildDelegate() {
+        Vector delegate = (Vector<E>)getValueHolder().getValue();
+        if (delegate == null) {
+            delegate = new Vector<>(this.initialCapacity, this.capacityIncrement);
+        }
+        // This can either be another indirect list or a Vector.
+        // It can be another indirect list because the mapping's query uses the same container policy.
+        // Unwrap any redundant indirection layers, which can cause issues and impact performance.
+        while (delegate instanceof IndirectList) {
+            if(((IndirectList) delegate).isListOrderBrokenInDb()) {
+                this.isListOrderBrokenInDb = true;
+            }
+            delegate = ((IndirectList) delegate).getDelegate();
+        }
+        // First add/remove any cached changes.
+        if (hasAddedElements()) {
+            int size = getAddedElements().size();
+            for (int index = 0; index < size; index++) {
+                Object element = ((List)getAddedElements()).get(index);
+                // On a flush or resume the element may already be in the database.
+                if (!delegate.contains(element)) {
+                    delegate.add(element);
+                }
+            }
+            this.addedElements = null;
+        }
+        if (hasRemovedElements()) {
+            int size = getRemovedElements().size();
+            for (int index = 0; index < size; index++) {
+                delegate.remove(((List)getRemovedElements()).get(index));
+            }
+            this.removedElements = null;
+        }
+        return delegate;
+    }
+
+    /**
+     * @see java.util.Vector#capacity()
+     */
+    @Override
+    public int capacity() {
+        return getDelegate().capacity();
+    }
+
+    /**
+     * @see java.util.Vector#clear()
+     */
+    @Override
+    public void clear() {
+        removeAllElements();
+    }
+    
+    /**
+     * INTERNAL:
+     * clear any changes that have been deferred to instantiation.
+     * Indirect collections with change tracking avoid instantiation on add/remove.
+     */
+    @Override
+    public void clearDeferredChanges(){
+        addedElements = null;
+        removedElements = null;
+    }
+    
+    /**
+     * PUBLIC:
+     * @see java.util.Vector#clone()
+     * This will result in a database query if necessary.
+     */
+
+    /*
+        There are 3 situations when clone() is called:
+        1.    The developer actually wants to clone the collection (typically to modify one
+            of the 2 resulting collections). In which case the contents must be read from
+            the database.
+        2.    A UnitOfWork needs a clone (or backup clone) of the collection. But the
+            UnitOfWork checks "instantiation" before cloning collections ("un-instantiated"
+            collections are not cloned).
+        3.    A MergeManager needs an extra copy of the collection (because the "backup"
+            and "target" are the same object?). But the MergeManager checks "instantiation"
+            before merging collections (again, "un-instantiated" collections are not merged).
+    */
+    @Override
+    public synchronized Object clone() {
+        IndirectList<E> result = (IndirectList<E>)super.clone();
+        result.delegate = (Vector<E>)this.getDelegate().clone();
+        result.valueHolder = new ValueHolder(result.delegate);
+        result.attributeName = null;
+        result.changeListener = null;
+        return result;
+    }
+
+    /**
+     * PUBLIC:
+     * @see java.util.Vector#contains(java.lang.Object)
+     */
+    @Override
+    public boolean contains(Object element) {
+        // PERF: Avoid instantiation if not required.
+        if (hasAddedElements()) {
+            if (getAddedElements().contains(element)) {
+                return true;
+            }
+        }
+        if (hasRemovedElements()) {
+            if (getRemovedElements().contains(element)) {
+                return false;
+            }
+        }
+        return getDelegate().contains(element);
+    }
+
+    /**
+     * @see java.util.Vector#containsAll(java.util.Collection)
+     */
+    @Override
+    public boolean containsAll(Collection<?> c) {
+        return getDelegate().containsAll(c);
+    }
+
+    /**
+     * @see java.util.Vector#copyInto(java.lang.Object[])
+     */
+    @Override
+    public synchronized void copyInto(Object[] anArray) {
+        getDelegate().copyInto(anArray);
+    }
+
     /**
      * @see java.util.Vector#elementAt(int)
      */
+    @Override
     public E elementAt(int index) {
         return getDelegate().elementAt(index);
     }
 
-    /**

-     * @see java.util.Vector#elements()

-     */

-    public Enumeration elements() {

-        return getDelegate().elements();

-    }

-

-    /**

-     * @see java.util.Vector#ensureCapacity(int)

-     */

-    public void ensureCapacity(int minCapacity) {

-        getDelegate().ensureCapacity(minCapacity);

-    }

-

-    /**

-     * @see java.util.Vector#equals(java.lang.Object)

-     */

-    public boolean equals(Object o) {

-        return getDelegate().equals(o);

-    }

-

+    /**
+     * @see java.util.Vector#elements()
+     */
+    @Override
+    public Enumeration<E> elements() {
+        return getDelegate().elements();
+    }
+
+    /**
+     * @see java.util.Vector#ensureCapacity(int)
+     */
+    @Override
+    public void ensureCapacity(int minCapacity) {
+        getDelegate().ensureCapacity(minCapacity);
+    }
+
+    /**
+     * @see java.util.Vector#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object o) {
+        return getDelegate().equals(o);
+    }
+
     /**
      * @see java.util.Vector#firstElement()
      */
+    @Override
     public E firstElement() {
         return getDelegate().firstElement();
     }
@@ -409,13 +433,14 @@
     /**
      * @see java.util.Vector#get(int)
      */
+    @Override
     public E get(int index) {
         return getDelegate().get(index);
     }
 
-    /**

-     * INTERNAL:

-     * Check whether the contents have been read from the database.

+    /**
+     * INTERNAL:
+     * Check whether the contents have been read from the database.
      * If they have not, read them and set the delegate.
      * This method used to be synchronized, which caused deadlock.
      */
@@ -423,539 +448,565 @@
         if (delegate == null) {
             synchronized(this){
                 if (delegate == null) {
-                    delegate = this.buildDelegate();

-                }

-            }

-        }

-        return delegate;

-    }    

-    

-    /**

-     * INTERNAL:

-     * Return the real collection object.

-     * This will force instantiation.

-     */

-    public Object getDelegateObject() {

-        return getDelegate();

-    }

-

-    /**

-     * INTERNAL:

-     * Return the valueHolder.

-     * This method used to be synchronized, which caused deadlock.

-     */

-    public ValueHolderInterface getValueHolder() {

-        // PERF: lazy initialize value holder and vector as are normally set after creation.

-        if (valueHolder == null) {

-            synchronized(this) {

-                if (valueHolder == null) {

-                        valueHolder = new ValueHolder(new Vector(this.initialCapacity, this.capacityIncrement));

-                }

-            }

-        }

-        return valueHolder;

-    }

-

-    /**

-     * INTERNAL:

-     * return whether this IndirectList has been registered with the UnitOfWork

-     */

-    public boolean hasBeenRegistered() {

-        return getValueHolder() instanceof UnitOfWorkQueryValueHolder;

-    }

-

-    /**

-     * INTERNAL:

-     * @see java.util.Vector#hashCode()

-     */

-    public int hashCode() {

-        return this.getDelegate().hashCode();

-    }

-

-    /**

-     * @see java.util.Vector#indexOf(java.lang.Object)

-     */

-    public int indexOf(Object elem) {

-        return this.getDelegate().indexOf(elem);

-    }

-

-    /**

-     * @see java.util.Vector#indexOf(java.lang.Object, int)

-     */

-    public int indexOf(Object elem, int index) {

-        return this.getDelegate().indexOf(elem, index);

-    }

-

+                    delegate = this.buildDelegate();
+                }
+            }
+        }
+        return delegate;
+    }    
+    
+    /**
+     * INTERNAL:
+     * Return the real collection object.
+     * This will force instantiation.
+     */
+    @Override
+    public Object getDelegateObject() {
+        return getDelegate();
+    }
+
+    /**
+     * INTERNAL:
+     * Return the valueHolder.
+     * This method used to be synchronized, which caused deadlock.
+     */
+    @Override
+    public ValueHolderInterface getValueHolder() {
+        // PERF: lazy initialize value holder and vector as are normally set after creation.
+        if (valueHolder == null) {
+            synchronized(this) {
+                if (valueHolder == null) {
+                        valueHolder = new ValueHolder(new Vector(this.initialCapacity, this.capacityIncrement));
+                }
+            }
+        }
+        return valueHolder;
+    }
+
+    /**
+     * INTERNAL:
+     * return whether this IndirectList has been registered with the UnitOfWork
+     */
+    public boolean hasBeenRegistered() {
+        return getValueHolder() instanceof UnitOfWorkQueryValueHolder;
+    }
+
+    /**
+     * INTERNAL:
+     * @see java.util.Vector#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return this.getDelegate().hashCode();
+    }
+
+    /**
+     * @see java.util.Vector#indexOf(java.lang.Object)
+     */
+    @Override
+    public int indexOf(Object elem) {
+        return this.getDelegate().indexOf(elem);
+    }
+
+    /**
+     * @see java.util.Vector#indexOf(java.lang.Object, int)
+     */
+    @Override
+    public int indexOf(Object elem, int index) {
+        return this.getDelegate().indexOf(elem, index);
+    }
+
     /**
      * @see java.util.Vector#insertElementAt(java.lang.Object, int)
      */
+    @Override
     public void insertElementAt(E obj, int index) {
         this.getDelegate().insertElementAt(obj, index);
         this.raiseAddChangeEvent(obj, Integer.valueOf(index));
     }
-

-    /**

-     * @see java.util.Vector#isEmpty()

-     */

-    public boolean isEmpty() {

-        return this.getDelegate().isEmpty();

-    }

-

-    /**

-     * PUBLIC:

-     * Return whether the contents have been read from the database.

-     */

-    public boolean isInstantiated() {

-        return getValueHolder().isInstantiated();

-    }

-

-    /**

-     * @see java.util.AbstractList#iterator()

-     */

-    public Iterator iterator() {

-        // Must wrap the interator to raise the remove event.

-        return listIterator(0);

-    }

-

+
+    /**
+     * @see java.util.Vector#isEmpty()
+     */
+    @Override
+    public boolean isEmpty() {
+        return this.getDelegate().isEmpty();
+    }
+
+    /**
+     * PUBLIC:
+     * Return whether the contents have been read from the database.
+     */
+    @Override
+    public boolean isInstantiated() {
+        return getValueHolder().isInstantiated();
+    }
+
+    /**
+     * @see java.util.AbstractList#iterator()
+     */
+    @Override
+    public Iterator<E> iterator() {
+        // Must wrap the interator to raise the remove event.
+        return listIterator(0);
+    }
+
     /**
      * @see java.util.Vector#lastElement()
      */
+    @Override
     public E lastElement() {
         return getDelegate().lastElement();
     }
 
-    /**

-     * @see java.util.Vector#lastIndexOf(java.lang.Object)

-     */

-    public int lastIndexOf(Object elem) {

-        return getDelegate().lastIndexOf(elem);

-    }

-

-    /**

-     * @see java.util.Vector#lastIndexOf(java.lang.Object, int)

-     */

-    public int lastIndexOf(Object elem, int index) {

-        return getDelegate().lastIndexOf(elem, index);

-    }

-

-    /**

-     * @see java.util.AbstractList#listIterator()

-     */

-    public ListIterator listIterator() {

-        return listIterator(0);

-    }

-

-    /**

-     * @see java.util.AbstractList#listIterator(int)

-     */

-    public ListIterator listIterator(final int index) {

-        // Must wrap the interator to raise the remove event.

-        return new ListIterator() {

-            ListIterator delegateIterator = IndirectList.this.getDelegate().listIterator(index);

-            Object currentObject;

-            

-            public boolean hasNext() {

-                return this.delegateIterator.hasNext();

-            }

-            

-            public boolean hasPrevious() {

-                return this.delegateIterator.hasPrevious();

-            }

-            

-            public int previousIndex() {

-                return this.delegateIterator.previousIndex();

-            }

-            

-            public int nextIndex() {

-                return this.delegateIterator.nextIndex();

-            }

-            

-            public Object next() {

-                this.currentObject = this.delegateIterator.next();

-                return this.currentObject;

-            }

-            

-            public Object previous() {

-                this.currentObject = this.delegateIterator.previous();

-                return this.currentObject;

-            }

-            

-            public void remove() {

-                this.delegateIterator.remove();

-                IndirectList.this.raiseRemoveChangeEvent(this.currentObject, Integer.valueOf(this.delegateIterator.nextIndex()));

-            }

-            

-            public void set(Object object) {

-                this.delegateIterator.set(object);

-                Integer index = Integer.valueOf(this.delegateIterator.previousIndex());

-                IndirectList.this.raiseRemoveChangeEvent(this.currentObject, index, true);

-                IndirectList.this.raiseAddChangeEvent(object, index, true);

-            }

-            

-            public void add(Object object) {

-                this.delegateIterator.add(object);

-                IndirectList.this.raiseAddChangeEvent(object, Integer.valueOf(this.delegateIterator.previousIndex()));

-            }

-        };

-    }

-

+    /**
+     * @see java.util.Vector#lastIndexOf(java.lang.Object)
+     */
+    @Override
+    public int lastIndexOf(Object elem) {
+        return getDelegate().lastIndexOf(elem);
+    }
+
+    /**
+     * @see java.util.Vector#lastIndexOf(java.lang.Object, int)
+     */
+    @Override
+    public int lastIndexOf(Object elem, int index) {
+        return getDelegate().lastIndexOf(elem, index);
+    }
+
+    /**
+     * @see java.util.AbstractList#listIterator()
+     */
+    @Override
+    public ListIterator<E> listIterator() {
+        return listIterator(0);
+    }
+
+    /**
+     * @see java.util.AbstractList#listIterator(int)
+     */
+    @Override
+    public ListIterator<E> listIterator(final int index) {
+        // Must wrap the interator to raise the remove event.
+        return new ListIterator<E>() {
+            ListIterator<E> delegateIterator = IndirectList.this.getDelegate().listIterator(index);
+            E currentObject;
+            
+            @Override
+            public boolean hasNext() {
+                return this.delegateIterator.hasNext();
+            }
+            
+            @Override
+            public boolean hasPrevious() {
+                return this.delegateIterator.hasPrevious();
+            }
+            
+            @Override
+            public int previousIndex() {
+                return this.delegateIterator.previousIndex();
+            }
+            
+            @Override
+            public int nextIndex() {
+                return this.delegateIterator.nextIndex();
+            }
+            
+            @Override
+            public E next() {
+                this.currentObject = this.delegateIterator.next();
+                return this.currentObject;
+            }
+            
+            @Override
+            public E previous() {
+                this.currentObject = this.delegateIterator.previous();
+                return this.currentObject;
+            }
+            
+            @Override
+            public void remove() {
+                this.delegateIterator.remove();
+                IndirectList.this.raiseRemoveChangeEvent(this.currentObject, Integer.valueOf(this.delegateIterator.nextIndex()));
+            }
+            
+            @Override
+            public void set(E object) {
+                this.delegateIterator.set(object);
+                Integer index = Integer.valueOf(this.delegateIterator.previousIndex());
+                IndirectList.this.raiseRemoveChangeEvent(this.currentObject, index, true);
+                IndirectList.this.raiseAddChangeEvent(object, index, true);
+            }
+            
+            @Override
+            public void add(E object) {
+                this.delegateIterator.add(object);
+                IndirectList.this.raiseAddChangeEvent(object, Integer.valueOf(this.delegateIterator.previousIndex()));
+            }
+        };
+    }
+
     /**
      * @see java.util.Vector#remove(int)
      */
+    @Override
     public E remove(int index) {
         E value = getDelegate().remove(index);
         this.raiseRemoveChangeEvent(value, Integer.valueOf(index));
         return value;
     }
-

-    /**

-     * @see java.util.Vector#remove(java.lang.Object)

-     */

-    public boolean remove(Object element) {

-        if (!this.isRegistered) {

-            return getDelegate().remove(element);

-        }

-        // PERF: If not instantiated just record the removal to avoid the instantiation.

-        if (shouldAvoidInstantiation()) {

-            if (hasAddedElements() && getAddedElements().contains(element)) {

-                getAddedElements().remove(element);

-            } else if (getRemovedElements().contains(element)) {

-                // Must avoid recursion for relationship maintenance.

-                return false;

-            } else {

-                getRemovedElements().add(element);

-            }

-            this.raiseRemoveChangeEvent(element, null);

-            return true;

-        } else { 

-            int index = this.getDelegate().indexOf(element);

-            if(index > -1) {

-                this.getDelegate().remove(index);

-                this.raiseRemoveChangeEvent(element, index);

-                return true;

-            }

-        }  

-        return false;

-    }

-

-    /**

-     * @see java.util.Vector#removeAll(java.util.Collection)

-     */

-    public boolean removeAll(Collection c) {

-        // Must trigger remove events if tracked or uow.

-        if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {

-            boolean hasChanged = false;

-            Iterator objects = c.iterator();

-            while (objects.hasNext()) {

-                hasChanged |= remove(objects.next());

-            }

-            return hasChanged;

-        }

-        return getDelegate().removeAll(c);

-    }

-

-    /**

-     * @see java.util.Vector#removeAllElements()

-     */

-    public void removeAllElements() {

-        // Must trigger remove events if tracked or uow.

-        if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {

-            Iterator objects = iterator();

-            while (objects.hasNext()) {

-                objects.next();

-                objects.remove();

-            }

-            return;

-        }

-        getDelegate().removeAllElements();

-    }

-

-    /**

-     * @see java.util.Vector#removeElement(java.lang.Object)

-     */

-    public boolean removeElement(Object obj) {

-        return remove(obj);

-    }

-

-    /**

-     * @see java.util.Vector#removeElementAt(int)

-     */

-    public void removeElementAt(int index) {

-        remove(index);

-    }

-

-    /**

-     * @see java.util.Vector#retainAll(java.util.Collection)

-     */

-    public boolean retainAll(Collection c) {

-        // Must trigger remove events if tracked or uow.

-        if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {

-            Iterator objects = getDelegate().iterator();

-            while (objects.hasNext()) {

-                Object object = objects.next();

-                if (!c.contains(object)) {

-                    objects.remove();

-                    raiseRemoveChangeEvent(object, null);

-                }

-            }

-            return true;

-        }

-        return getDelegate().retainAll(c);

-    }

-

+
+    /**
+     * @see java.util.Vector#remove(java.lang.Object)
+     */
+    @Override
+    public boolean remove(Object element) {
+        if (!this.isRegistered) {
+            return getDelegate().remove(element);
+        }
+        // PERF: If not instantiated just record the removal to avoid the instantiation.
+        if (shouldAvoidInstantiation()) {
+            if (hasAddedElements() && getAddedElements().contains(element)) {
+                getAddedElements().remove(element);
+            } else if (getRemovedElements().contains(element)) {
+                // Must avoid recursion for relationship maintenance.
+                return false;
+            } else {
+                getRemovedElements().add(element);
+            }
+            this.raiseRemoveChangeEvent(element, null);
+            return true;
+        } else { 
+            int index = this.getDelegate().indexOf(element);
+            if(index > -1) {
+                this.getDelegate().remove(index);
+                this.raiseRemoveChangeEvent(element, index);
+                return true;
+            }
+        }  
+        return false;
+    }
+
+    /**
+     * @see java.util.Vector#removeAll(java.util.Collection)
+     */
+    @Override
+    public boolean removeAll(Collection<?> c) {
+        // Must trigger remove events if tracked or uow.
+        if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {
+            boolean hasChanged = false;
+            Iterator objects = c.iterator();
+            while (objects.hasNext()) {
+                hasChanged |= remove(objects.next());
+            }
+            return hasChanged;
+        }
+        return getDelegate().removeAll(c);
+    }
+
+    /**
+     * @see java.util.Vector#removeAllElements()
+     */
+    @Override
+    public void removeAllElements() {
+        // Must trigger remove events if tracked or uow.
+        if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {
+            Iterator objects = iterator();
+            while (objects.hasNext()) {
+                objects.next();
+                objects.remove();
+            }
+            return;
+        }
+        getDelegate().removeAllElements();
+    }
+
+    /**
+     * @see java.util.Vector#removeElement(java.lang.Object)
+     */
+    @Override
+    public boolean removeElement(Object obj) {
+        return remove(obj);
+    }
+
+    /**
+     * @see java.util.Vector#removeElementAt(int)
+     */
+    @Override
+    public void removeElementAt(int index) {
+        remove(index);
+    }
+
+    /**
+     * @see java.util.Vector#retainAll(java.util.Collection)
+     */
+    @Override
+    public boolean retainAll(Collection<?> c) {
+        // Must trigger remove events if tracked or uow.
+        if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {
+            Iterator objects = getDelegate().iterator();
+            while (objects.hasNext()) {
+                Object object = objects.next();
+                if (!c.contains(object)) {
+                    objects.remove();
+                    raiseRemoveChangeEvent(object, null);
+                }
+            }
+            return true;
+        }
+        return getDelegate().retainAll(c);
+    }
+
     /**
      * @see java.util.Vector#set(int, java.lang.Object)
      */
+    @Override
     public E set(int index, E element) {
         E oldValue = getDelegate().set(index, element);
         Integer bigIntIndex = Integer.valueOf(index);
         raiseRemoveChangeEvent(oldValue, bigIntIndex, true);
         raiseAddChangeEvent(element, bigIntIndex, true);
-        return oldValue;

-    }

-

+        return oldValue;
+    }
+
     /**
      * @see java.util.Vector#setElementAt(java.lang.Object, int)
      */
+    @Override
     public void setElementAt(E obj, int index) {
         set(index, obj);
     }
 
-    /**

-     * @see java.util.Vector#setSize(int)

-     */

-    public void setSize(int newSize) {

-        // Must trigger remove events if tracked or uow.

-        if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {

-            if (newSize > size()) {

-                for (int index = size(); index > newSize; index--) {

-                    this.remove(index - 1);

-                }

-            }

-        }    

-        getDelegate().setSize(newSize);

-    }

-

-    /**

-     * INTERNAL

-     * Set whether this collection should attempt do deal with adds and removes without retrieving the 

-     * collection from the dB

-     */

-    public void setUseLazyInstantiation(boolean useLazyInstantiation){

-        this.useLazyInstantiation = useLazyInstantiation;

-    }

-    

-    /**

-     * INTERNAL:

-     * Set the value holder.

-     */

-    public void setValueHolder(ValueHolderInterface valueHolder) {

-        this.delegate = null;

-        this.valueHolder = valueHolder;

-        if (valueHolder instanceof UnitOfWorkQueryValueHolder) {

-            this.isRegistered = true;

-        }

-    }

-

-    /**

-     * @see java.util.Vector#size()

-     */

-    public int size() {

-        return getDelegate().size();
+    /**
+     * @see java.util.Vector#setSize(int)
+     */
+    @Override
+    public void setSize(int newSize) {
+        // Must trigger remove events if tracked or uow.
+        if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {
+            if (newSize > size()) {
+                for (int index = size(); index > newSize; index--) {
+                    this.remove(index - 1);
+                }
+            }
+        }    
+        getDelegate().setSize(newSize);
     }
 
-    // TODO: Rewrite to work directly with Vector#sort(Comparator) when source level will be at least 1.8
     /**
-     * Sort content of this instance according to the order induced by provided comparator.
-     * @param c The comparator to determine the order of the array. A {@code null} value
-     *          indicates that the elements' {@linkplain Comparable natural ordering}
-     *          should be used.
-     * @throws UnsupportedOperationException when running with JDK &lt; 1.8.
-     * @since 2.6.0 with JDK 1.8
+     * INTERNAL
+     * Set whether this collection should attempt do deal with adds and removes without retrieving the 
+     * collection from the dB
      */
-    public void sort(Comparator<? super E> c) {
-        Vector<E> delegate = getDelegate();
-        Method sortM;
-        try {
-            sortM = delegate.getClass().getMethod("sort", Comparator.class);
-            sortM.invoke(delegate, c);
-        } catch (IllegalArgumentException | NoSuchMethodException e) {
-            throw new UnsupportedOperationException(e);
-        } catch (IllegalAccessException | InvocationTargetException e) {
-            throw new IllegalStateException(e);
+    @Override
+    public void setUseLazyInstantiation(boolean useLazyInstantiation){
+        this.useLazyInstantiation = useLazyInstantiation;
+    }
+    
+    /**
+     * INTERNAL:
+     * Set the value holder.
+     */
+    @Override
+    public void setValueHolder(ValueHolderInterface valueHolder) {
+        this.delegate = null;
+        this.valueHolder = valueHolder;
+        if (valueHolder instanceof UnitOfWorkQueryValueHolder) {
+            this.isRegistered = true;
         }
     }
 
     /**
+     * @see java.util.Vector#size()
+     */
+    @Override
+    public int size() {
+        return getDelegate().size();
+    }
+
+    /**
      * Return whether this collection should attempt do deal with adds and removes without retrieving the
      * collection from the dB
-     * @return

-     */

-    protected boolean shouldUseLazyInstantiation(){

-        return useLazyInstantiation;

-    }

-    

-    /**

-     * @see java.util.Vector#subList(int, int)

-     */

-    public List subList(int fromIndex, int toIndex) {

-        return getDelegate().subList(fromIndex, toIndex);

-    }

-

-    /**

-     * @see java.util.Vector#toArray()

-     */

-    public Object[] toArray() {

-        return getDelegate().toArray();

-    }

-

-    /**

-     * @see java.util.Vector#toArray(java.lang.Object[])

-     */

-    public Object[] toArray(Object[] a) {

-        return getDelegate().toArray(a);

-    }

-

-    /**

-     * PUBLIC:

-     * Use the java.util.Vector#toString(); but wrap it with braces to indicate

-     * there is a bit of indirection.

-     * Don't allow this method to trigger a database read.

-     * @see java.util.Vector#toString()

-     */

-    public String toString() {

-        if (ValueHolderInterface.shouldToStringInstantiate) {

-            return getDelegate().toString();

-        }

-        if (this.isInstantiated()) {

-            return "{" + getDelegate().toString() + "}";

-        } else {

-            return "{" + org.eclipse.persistence.internal.helper.Helper.getShortClassName(this.getClass()) + ": not instantiated}";

-        }

-    }

-

-    /**

-     * @see java.util.Vector#trimToSize()

-     */

-    public void trimToSize() {

-        getDelegate().trimToSize();

-    }

-    

-    /**

-     * INTERNAL:

-     * Return the property change listener for change tracking.

-     */

-     public PropertyChangeListener _persistence_getPropertyChangeListener() {

-         return changeListener;

-     }

-    

-    /**

-     * INTERNAL:

-     * Return if the collection has a property change listener for change tracking.

-     */

-     public boolean hasTrackedPropertyChangeListener() {

-         return this.changeListener != null;

-     }

-     

-    /**

-     * INTERNAL:

-     * Set the property change listener for change tracking.

-     */

-     public void _persistence_setPropertyChangeListener(PropertyChangeListener changeListener) {

-         this.changeListener = changeListener;

-         if (changeListener != null) {

-             this.isRegistered = true;

-         }

-     }

-     

-    /**

-     * INTERNAL:

-     * Return the mapping attribute name, used to raise change events.

-     */

-     public String getTrackedAttributeName() {

-         return attributeName;

-     }

-     

-    /**

-     * INTERNAL:

-     * Set the mapping attribute name, used to raise change events.

-     * This is required if the change listener is set.

-     */

-     public void setTrackedAttributeName(String attributeName) {

-         this.attributeName = attributeName;

-     }

-          

-    /**

-     * INTERNAL:

-     * Return the elements that have been removed before instantiation.

-     */

-    public Collection getRemovedElements() {

-        if (removedElements == null) {

-            removedElements = new ArrayList();

-        }

-        return removedElements;

-    }  

-

-    /**

-     * INTERNAL:

-     * Return the elements that have been added before instantiation.

-     */

-    public Collection getAddedElements() {

-        if (addedElements == null) {

-            addedElements = new ArrayList();

-        }

-        return addedElements;

-    }

-

-    /**

-     * INTERNAL:

-     * Return if any elements that have been added before instantiation.

-     */

-    public boolean hasAddedElements() {

-        return (addedElements != null) && (!addedElements.isEmpty());

-    }

-

-    /**

-     * INTERNAL:

-     * Return if any elements that have been removed before instantiation.

-     */

-    public boolean hasRemovedElements() {

-        return (removedElements != null) && (!removedElements.isEmpty());

-    }

-    

-    /**

-     * INTERNAL:

-     * Return if any elements that have been added or removed before instantiation.

-     */

-    public boolean hasDeferredChanges() {

-        return hasRemovedElements() || hasAddedElements();

-    }

-    

-    /**

-     * INTERNAL:

-     * Return if add/remove should trigger instantiation or avoid.

-     * Current instantiation is avoided is using change tracking.

-     */

-    protected boolean shouldAvoidInstantiation() {

-        return (!isInstantiated())  && (shouldUseLazyInstantiation()) && (_persistence_getPropertyChangeListener() instanceof AttributeChangeListener) && !usesListOrderField() && ((WeavedAttributeValueHolderInterface)getValueHolder()).shouldAllowInstantiationDeferral();

-    }

-    

-    /**

-     * INTERNAL:

-     * Returns whether the mapping has listOrderField.

-     */

-    protected boolean usesListOrderField() {

-        if(this.valueHolder instanceof UnitOfWorkValueHolder) {

-            return ((CollectionMapping)((UnitOfWorkValueHolder)this.valueHolder).getMapping()).getListOrderField() != null;

-        } else {

-            return false;

-        }

-    }

-

-    public boolean isListOrderBrokenInDb() {

-        return this.isListOrderBrokenInDb;

-    }

-    public void setIsListOrderBrokenInDb(boolean isBroken) {

-        this.isListOrderBrokenInDb = isBroken;

-    }

-}

+     * @return
+     */
+    protected boolean shouldUseLazyInstantiation(){
+        return useLazyInstantiation;
+    }
+    
+    /**
+     * @see java.util.Vector#subList(int, int)
+     */
+    @Override
+    public List<E> subList(int fromIndex, int toIndex) {
+        return getDelegate().subList(fromIndex, toIndex);
+    }
+
+    /**
+     * @see java.util.Vector#toArray()
+     */
+    @Override
+    public Object[] toArray() {
+        return getDelegate().toArray();
+    }
+
+    /**
+     * @see java.util.Vector#toArray(java.lang.Object[])
+     */
+    @Override
+    public <T> T[] toArray(T[] a) {
+        return getDelegate().toArray(a);
+    }
+
+    /**
+     * PUBLIC:
+     * Use the java.util.Vector#toString(); but wrap it with braces to indicate
+     * there is a bit of indirection.
+     * Don't allow this method to trigger a database read.
+     * @see java.util.Vector#toString()
+     */
+    @Override
+    public String toString() {
+        if (ValueHolderInterface.shouldToStringInstantiate) {
+            return getDelegate().toString();
+        }
+        if (this.isInstantiated()) {
+            return "{" + getDelegate().toString() + "}";
+        } else {
+            return "{" + org.eclipse.persistence.internal.helper.Helper.getShortClassName(this.getClass()) + ": not instantiated}";
+        }
+    }
+
+    /**
+     * @see java.util.Vector#trimToSize()
+     */
+    @Override
+    public void trimToSize() {
+        getDelegate().trimToSize();
+    }
+    
+    /**
+     * INTERNAL:
+     * Return the property change listener for change tracking.
+     */
+    @Override
+     public PropertyChangeListener _persistence_getPropertyChangeListener() {
+         return changeListener;
+     }
+    
+    /**
+     * INTERNAL:
+     * Return if the collection has a property change listener for change tracking.
+     */
+     public boolean hasTrackedPropertyChangeListener() {
+         return this.changeListener != null;
+     }
+     
+    /**
+     * INTERNAL:
+     * Set the property change listener for change tracking.
+     */
+    @Override
+     public void _persistence_setPropertyChangeListener(PropertyChangeListener changeListener) {
+         this.changeListener = changeListener;
+         if (changeListener != null) {
+             this.isRegistered = true;
+         }
+     }
+     
+    /**
+     * INTERNAL:
+     * Return the mapping attribute name, used to raise change events.
+     */
+    @Override
+     public String getTrackedAttributeName() {
+         return attributeName;
+     }
+     
+    /**
+     * INTERNAL:
+     * Set the mapping attribute name, used to raise change events.
+     * This is required if the change listener is set.
+     */
+    @Override
+     public void setTrackedAttributeName(String attributeName) {
+         this.attributeName = attributeName;
+     }
+          
+    /**
+     * INTERNAL:
+     * Return the elements that have been removed before instantiation.
+     */
+    @Override
+    public Collection getRemovedElements() {
+        if (removedElements == null) {
+            removedElements = new ArrayList();
+        }
+        return removedElements;
+    }  
+
+    /**
+     * INTERNAL:
+     * Return the elements that have been added before instantiation.
+     */
+    @Override
+    public Collection getAddedElements() {
+        if (addedElements == null) {
+            addedElements = new ArrayList();
+        }
+        return addedElements;
+    }
+
+    /**
+     * INTERNAL:
+     * Return if any elements that have been added before instantiation.
+     */
+    public boolean hasAddedElements() {
+        return (addedElements != null) && (!addedElements.isEmpty());
+    }
+
+    /**
+     * INTERNAL:
+     * Return if any elements that have been removed before instantiation.
+     */
+    public boolean hasRemovedElements() {
+        return (removedElements != null) && (!removedElements.isEmpty());
+    }
+    
+    /**
+     * INTERNAL:
+     * Return if any elements that have been added or removed before instantiation.
+     */
+    @Override
+    public boolean hasDeferredChanges() {
+        return hasRemovedElements() || hasAddedElements();
+    }
+    
+    /**
+     * INTERNAL:
+     * Return if add/remove should trigger instantiation or avoid.
+     * Current instantiation is avoided is using change tracking.
+     */
+    protected boolean shouldAvoidInstantiation() {
+        return (!isInstantiated())  && (shouldUseLazyInstantiation()) && (_persistence_getPropertyChangeListener() instanceof AttributeChangeListener) && !usesListOrderField() && ((WeavedAttributeValueHolderInterface)getValueHolder()).shouldAllowInstantiationDeferral();
+    }
+    
+    /**
+     * INTERNAL:
+     * Returns whether the mapping has listOrderField.
+     */
+    protected boolean usesListOrderField() {
+        if(this.valueHolder instanceof UnitOfWorkValueHolder) {
+            return ((CollectionMapping)((UnitOfWorkValueHolder)this.valueHolder).getMapping()).getListOrderField() != null;
+        } else {
+            return false;
+        }
+    }
+
+    public boolean isListOrderBrokenInDb() {
+        return this.isListOrderBrokenInDb;
+    }
+    public void setIsListOrderBrokenInDb(boolean isBroken) {
+        this.isListOrderBrokenInDb = isBroken;
+    }
+}
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectMap.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectMap.java
index 33435ba..bfdaaac 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectMap.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectMap.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.

+ * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the 

  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 

  * which accompanies this distribution. 

@@ -13,8 +13,15 @@
 package org.eclipse.persistence.indirection;

 

 import java.beans.PropertyChangeListener;

-import java.util.*;

-import org.eclipse.persistence.descriptors.changetracking.*;

+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.persistence.descriptors.changetracking.CollectionChangeEvent;
+import org.eclipse.persistence.descriptors.changetracking.CollectionChangeTracker;
+import org.eclipse.persistence.descriptors.changetracking.MapChangeEvent;
 

 /**

  * IndirectMap allows a domain class to take advantage of TopLink indirection

@@ -29,15 +36,17 @@
  * the datatabase. With the first message sent to the IndirectMap, the contents

  * are fetched from the database and normal Hashtable/Map behavior is resumed.

  *

+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
  * @see org.eclipse.persistence.mappings.CollectionMapping

  * @see org.eclipse.persistence.indirection.IndirectList

  * @author Big Country

  * @since TOPLink/Java 2.5

  */

-public class IndirectMap extends Hashtable implements CollectionChangeTracker, IndirectCollection {

+public class IndirectMap<K, V> extends Hashtable<K, V> implements CollectionChangeTracker, IndirectCollection {
 

     /** Reduce type casting */

-    protected volatile Hashtable delegate;

+    protected volatile Hashtable<K, V> delegate;
 

     /** Delegate indirection behavior to a value holder */

     protected ValueHolderInterface valueHolder;

@@ -97,7 +106,7 @@
      * in the given Map or 11 (whichever is greater), and a default load factor, which is 0.75.

      * @param m a map containing the mappings to use

      */

-    public IndirectMap(Map m) {

+    public IndirectMap(Map<? extends K, ? extends V> m) {
         super(0);

         this.initialize(m);

     }

@@ -105,10 +114,10 @@
     /**

      * Return the freshly-built delegate.

      */

-    protected Hashtable buildDelegate() {

-        Hashtable value = (Hashtable)getValueHolder().getValue();

+    protected Hashtable<K, V> buildDelegate() {
+        Hashtable<K, V> value = (Hashtable<K, V>)getValueHolder().getValue();
         if (value == null) {

-            value = new Hashtable(this.initialCapacity, this.loadFactor);

+            value = new Hashtable<>(this.initialCapacity, this.loadFactor);
         }

         return value;

     }

@@ -116,11 +125,12 @@
     /**

      * @see java.util.Hashtable#clear()

      */

+    @Override
     public synchronized void clear() {

         if (hasTrackedPropertyChangeListener()) {

-            Iterator objects = this.keySet().iterator();

+            Iterator<K> objects = this.keySet().iterator();
             while (objects.hasNext()) {

-                Object o = objects.next();

+                K o = objects.next();
                 objects.remove();

                 this.raiseRemoveChangeEvent(o, this.get(o));

             }

@@ -135,6 +145,7 @@
      * clear any changes that have been deferred to instantiation.

      * Indirect collections with change tracking avoid instantiation on add/remove.

      */

+    @Override
     public void clearDeferredChanges(){

     }

     

@@ -155,9 +166,10 @@
             and "target" are the same object?). But the MergeManager checks "instantiation"

             before merging collections (again, "un-instantiated" collections are not merged).

     */

+    @Override
     public synchronized Object clone() {

-        IndirectMap result = (IndirectMap)super.clone();

-        result.delegate = (Hashtable)this.getDelegate().clone();

+        IndirectMap<K, V> result = (IndirectMap<K, V>)super.clone();
+        result.delegate = (Hashtable<K, V>)this.getDelegate().clone();
         result.valueHolder = new ValueHolder(result.delegate);

         result.attributeName = null;

         result.changeListener = null;

@@ -167,6 +179,7 @@
     /**

      * @see java.util.Hashtable#contains(java.lang.Object)

      */

+    @Override
     public synchronized boolean contains(Object value) {

         return this.getDelegate().contains(value);

     }

@@ -174,6 +187,7 @@
     /**

      * @see java.util.Hashtable#containsKey(java.lang.Object)

      */

+    @Override
     public synchronized boolean containsKey(Object key) {

         return this.getDelegate().containsKey(key);

     }

@@ -181,6 +195,7 @@
     /**

      * @see java.util.Hashtable#containsValue(java.lang.Object)

      */

+    @Override
     public boolean containsValue(Object value) {

         return this.getDelegate().containsValue(value);

     }

@@ -188,62 +203,75 @@
     /**

      * @see java.util.Hashtable#elements()

      */

-    public synchronized Enumeration elements() {

+    @Override
+    public synchronized Enumeration<V> elements() {
         return this.getDelegate().elements();

     }

 

     /**

      * @see java.util.Hashtable#entrySet()

      */

-    public Set entrySet() {

-        return new Set (){

-            Set delegateSet = IndirectMap.this.getDelegate().entrySet();

+    @Override
+    public Set<Map.Entry<K,V>> entrySet() {
+        return new Set<Map.Entry<K,V>> (){
+            Set<Map.Entry<K,V>> delegateSet = IndirectMap.this.getDelegate().entrySet();
             

+            @Override
             public int size(){

                 return this.delegateSet.size();

             }

         

+            @Override
             public boolean isEmpty(){

                 return this.delegateSet.isEmpty();

             }

         

+            @Override
             public boolean contains(Object o){

                 return this.delegateSet.contains(o);

             }

         

-            public Iterator iterator(){

-                return new Iterator() {

-                    Iterator delegateIterator = delegateSet.iterator();

-                    Object currentObject;

+            @Override
+            public Iterator<Map.Entry<K,V>> iterator(){
+                return new Iterator<Map.Entry<K,V>>() {
+                    Iterator<Map.Entry<K, V>> delegateIterator = delegateSet.iterator();
+                    Map.Entry<K, V> currentObject;
                     

+                    @Override
                     public boolean hasNext() {

                         return this.delegateIterator.hasNext();

                     }

                     

-                    public Object next() {

+                    @Override
+                    public Map.Entry<K, V> next() {
                         this.currentObject = this.delegateIterator.next();

                         return this.currentObject;

                     }

                     

+                    @Override
                     public void remove() {

-                        raiseRemoveChangeEvent(((Map.Entry)currentObject).getKey(), ((Map.Entry)currentObject).getValue());

+                        raiseRemoveChangeEvent(currentObject.getKey(), currentObject.getValue());
                         this.delegateIterator.remove();

                     }

                 };

             }

         

+            @Override
             public Object[] toArray(){

                 return this.delegateSet.toArray();

             }

     

-            public Object[] toArray(Object a[]){

+            @Override
+            public <T> T[] toArray(T a[]){
                 return this.delegateSet.toArray(a);

             }

     

-            public boolean add(Object o){

+            @Override
+            public boolean add(Map.Entry<K, V> o){
                 return this.delegateSet.add(o);

             }

         

+            @Override
             public boolean remove(Object o){

                 if (!(o instanceof Map.Entry)) {

                     return false;

@@ -251,15 +279,18 @@
                 return (IndirectMap.this.remove(((Map.Entry)o).getKey()) != null);

             }

         

-            public boolean containsAll(Collection c){

+            @Override
+            public boolean containsAll(Collection<?> c){
                 return this.delegateSet.containsAll(c);

             }

         

-            public boolean addAll(Collection c){

+            @Override
+            public boolean addAll(Collection<? extends Map.Entry<K, V>> c){
                 return this.delegateSet.addAll(c);

             }

         

-            public boolean retainAll(Collection c){

+            @Override
+            public boolean retainAll(Collection<?> c){
                 boolean result = false;

                 Iterator objects = delegateSet.iterator();

                 while (objects.hasNext()) {

@@ -273,7 +304,8 @@
                 return result;

             }

             

-            public boolean removeAll(Collection c){

+            @Override
+            public boolean removeAll(Collection<?> c){
                 boolean result = false;

                 for (Iterator cs = c.iterator(); cs.hasNext(); ){

                     Object object = cs.next();

@@ -288,14 +320,17 @@
                 return result;

             }

         

+            @Override
             public void clear(){

                 IndirectMap.this.clear();

             }

         

+            @Override
             public boolean equals(Object o){

                 return this.delegateSet.equals(o);

             }

             

+            @Override
             public int hashCode(){

                 return this.delegateSet.hashCode();

             }

@@ -305,6 +340,7 @@
     /**

      * @see java.util.Hashtable#equals(java.lang.Object)

      */

+    @Override
     public synchronized boolean equals(Object o) {

         return this.getDelegate().equals(o);

     }

@@ -312,7 +348,8 @@
     /**

      * @see java.util.Hashtable#get(java.lang.Object)

      */

-    public synchronized Object get(Object key) {

+    @Override
+    public synchronized V get(Object key) {
         return this.getDelegate().get(key);

     }

 

@@ -322,7 +359,7 @@
      * If they have not, read them and set the delegate.

      * This method used to be synchronized, which caused deadlock.

      */

-    protected Hashtable getDelegate() {

+    protected Hashtable<K, V> getDelegate() {
         if (delegate == null) {

             synchronized(this){

                 if (delegate == null) {

@@ -338,6 +375,7 @@
      * Return the real collection object.

      * This will force instantiation.

      */

+    @Override
     public Object getDelegateObject() {

         return getDelegate();

     }

@@ -346,6 +384,7 @@
      * INTERNAL:

      * Return the mapping attribute name, used to raise change events.

      */

+    @Override
      public String getTrackedAttributeName() {

          return attributeName;

      }

@@ -353,6 +392,7 @@
     /**

      * Return the property change listener for change tracking.

      */

+    @Override
      public PropertyChangeListener _persistence_getPropertyChangeListener() {

          return changeListener;

      }

@@ -362,12 +402,13 @@
       * Return the valueHolder.

       * This method used to be synchronized, which caused deadlock.

       */

+    @Override
      public ValueHolderInterface getValueHolder() {

          // PERF: lazy initialize value holder and vector as are normally set after creation.

          if (valueHolder == null) {

              synchronized(this){

                  if (valueHolder == null) {

-                     valueHolder = new ValueHolder(new Hashtable(initialCapacity, loadFactor));

+                     valueHolder = new ValueHolder(new Hashtable<>(initialCapacity, loadFactor));
                  }

              }

          }

@@ -377,6 +418,7 @@
     /**

      * @see java.util.Hashtable#hashCode()

      */

+    @Override
     public synchronized int hashCode() {

         return this.getDelegate().hashCode();

     }

@@ -402,9 +444,9 @@
     /**

      * Initialize the instance.

      */

-    protected void initialize(Map m) {

+    protected void initialize(Map<? extends K, ? extends V> m) {
         this.delegate = null;

-        Hashtable temp = new Hashtable(m);

+        Hashtable<K, V> temp = new Hashtable<>(m);
 

         this.valueHolder = new ValueHolder(temp);

     }

@@ -412,6 +454,7 @@
     /**

      * @see java.util.Hashtable#isEmpty()

      */

+    @Override
     public boolean isEmpty() {

         return this.getDelegate().isEmpty();

     }

@@ -420,6 +463,7 @@
      * PUBLIC:

      * Return whether the contents have been read from the database.

      */

+    @Override
     public boolean isInstantiated() {

         return this.getValueHolder().isInstantiated();

     }

@@ -427,44 +471,53 @@
     /**

      * @see java.util.Hashtable#keys()

      */

-    public synchronized Enumeration keys() {

+    @Override
+    public synchronized Enumeration<K> keys() {
         return this.getDelegate().keys();

     }

 

     /**

      * @see java.util.Hashtable#keySet()

      */

-    public Set keySet() {

+    @Override
+    public Set<K> keySet() {
         

-        return new Set (){

-            Set delegateSet = IndirectMap.this.getDelegate().keySet();

+        return new Set<K> (){
+            Set<K> delegateSet = IndirectMap.this.getDelegate().keySet();
             

+            @Override
             public int size(){

                 return this.delegateSet.size();

             }

         

+            @Override
             public boolean isEmpty(){

                 return this.delegateSet.isEmpty();

             }

         

+            @Override
             public boolean contains(Object o){

                 return this.delegateSet.contains(o);

             }

         

-            public Iterator iterator(){

-                return new Iterator() {

-                    Iterator delegateIterator = delegateSet.iterator();

-                    Object currentObject;

+            @Override
+            public Iterator<K> iterator(){
+                return new Iterator<K>() {
+                    Iterator<K> delegateIterator = delegateSet.iterator();
+                    K currentObject;
                     

+                    @Override
                     public boolean hasNext() {

                         return this.delegateIterator.hasNext();

                     }

                     

-                    public Object next() {

+                    @Override
+                    public K next() {
                         this.currentObject = this.delegateIterator.next();

                         return this.currentObject;

                     }

                     

+                    @Override
                     public void remove() {

                         IndirectMap.this.raiseRemoveChangeEvent(currentObject, IndirectMap.this.getDelegate().get(currentObject));

                         this.delegateIterator.remove();

@@ -472,31 +525,38 @@
                 };

             }

         

+            @Override
             public Object[] toArray(){

                 return this.delegateSet.toArray();

             }

     

+            @Override
             public Object[] toArray(Object a[]){

                 return this.delegateSet.toArray(a);

             }

     

-            public boolean add(Object o){

+            @Override
+            public boolean add(K o){
                 return this.delegateSet.add(o);

             }

         

+            @Override
             public boolean remove(Object o){

                 return (IndirectMap.this.remove(o) != null);

             }

         

-            public boolean containsAll(Collection c){

+            @Override
+            public boolean containsAll(Collection<?> c){
                 return this.delegateSet.containsAll(c);

             }

         

-            public boolean addAll(Collection c){

+            @Override
+            public boolean addAll(Collection<? extends K> c){
                 return this.delegateSet.addAll(c);

             }

         

-            public boolean retainAll(Collection c){

+            @Override
+            public boolean retainAll(Collection<?> c){
                 boolean result = false;

                 Iterator objects = delegateSet.iterator();

                 while (objects.hasNext()) {

@@ -510,9 +570,10 @@
                 return result;

             }

             

-            public boolean removeAll(Collection c){

+            @Override
+            public boolean removeAll(Collection<?> c){
                 boolean result = false;

-                for (Iterator cs = c.iterator(); cs.hasNext(); ){

+                for (Iterator<?> cs = c.iterator(); cs.hasNext(); ){
                     if (IndirectMap.this.remove(cs.next()) != null ) {

                         result = true;

                     }

@@ -520,14 +581,17 @@
                 return result;

             }

         

+            @Override
             public void clear(){

                 IndirectMap.this.clear();

             }

         

+            @Override
             public boolean equals(Object o){

                 return this.delegateSet.equals(o);

             }

             

+            @Override
             public int hashCode(){

                 return this.delegateSet.hashCode();

             }

@@ -539,8 +603,9 @@
     /**

      * @see java.util.Hashtable#put(java.lang.Object, java.lang.Object)

      */

-    public synchronized Object put(Object key, Object value) {

-        Object oldValue = this.getDelegate().put(key, value);

+    @Override
+    public synchronized V put(K key, V value) {
+        V oldValue = this.getDelegate().put(key, value);
         if (oldValue != null){

             raiseRemoveChangeEvent(key, oldValue);

         }

@@ -552,12 +617,13 @@
     /**

      * @see java.util.Hashtable#putAll(java.util.Map)

      */

-    public synchronized void putAll(Map t) {

+    @Override
+    public synchronized void putAll(Map<? extends K,? extends V> t) {
         // Must trigger add events if tracked or uow.

         if (hasTrackedPropertyChangeListener()) {

-            Iterator objects = t.keySet().iterator();

+            Iterator<? extends K> objects = t.keySet().iterator();
             while (objects.hasNext()) {

-                Object key = objects.next();

+                K key = objects.next();
                 this.put(key, t.get(key));

             }

         }else{

@@ -568,6 +634,7 @@
     /**

      * @see java.util.Hashtable#rehash()

      */

+    @Override
     protected void rehash() {

         throw new InternalError("unsupported");

     }

@@ -595,8 +662,9 @@
     /**

      * @see java.util.Hashtable#remove(java.lang.Object)

      */

-    public synchronized Object remove(Object key) {

-        Object value = this.getDelegate().remove(key);

+    @Override
+    public synchronized V remove(Object key) {
+        V value = this.getDelegate().remove(key);
         if (value != null){

             raiseRemoveChangeEvent(key, value);

         }

@@ -608,6 +676,7 @@
      * Set the mapping attribute name, used to raise change events.

      * This is required if the change listener is set.

      */

+    @Override
      public void setTrackedAttributeName(String attributeName) {

          this.attributeName = attributeName;

      }

@@ -616,6 +685,7 @@
      * INTERNAL:

      * Set the property change listener for change tracking.

      */

+    @Override
      public void _persistence_setPropertyChangeListener(PropertyChangeListener changeListener) {

          this.changeListener = changeListener;

      }

@@ -624,6 +694,7 @@
      * INTERNAL:

      * Set the value holder.

      */

+    @Override
     public void setValueHolder(ValueHolderInterface valueHolder) {

         this.delegate = null;

         this.valueHolder = valueHolder;

@@ -632,6 +703,7 @@
     /**

      * @see java.util.Hashtable#size()

      */

+    @Override
     public int size() {

         return this.getDelegate().size();

     }

@@ -641,6 +713,7 @@
      * Set whether this collection should attempt do deal with adds and removes without retrieving the 

      * collection from the dB

      */

+    @Override
     public void setUseLazyInstantiation(boolean useLazyInstantiation){

     }

     

@@ -648,6 +721,7 @@
      * INTERNAL:

      * Return the elements that have been removed before instantiation.

      */

+    @Override
     public Collection getRemovedElements() {

         return null;

     }

@@ -656,6 +730,7 @@
      * INTERNAL:

      * Return the elements that have been added before instantiation.

      */

+    @Override
     public Collection getAddedElements() {

         return null;

     }

@@ -664,6 +739,7 @@
      * INTERNAL:

      * Return if any elements that have been added or removed before instantiation.

      */

+    @Override
     public boolean hasDeferredChanges() {

         return false;

     }

@@ -675,6 +751,7 @@
      * Don't allow this method to trigger a database read.

      * @see java.util.Hashtable#toString()

      */

+    @Override
     public String toString() {

         if (ValueHolderInterface.shouldToStringInstantiate) {

             return this.getDelegate().toString();

@@ -689,36 +766,44 @@
     /**

      * @see java.util.Hashtable#values()

      */

-    public Collection values() {

-        return new Collection() {

-            protected Collection delegateCollection = IndirectMap.this.getDelegate().values();

+    @Override
+    public Collection<V> values() {
+        return new Collection<V>() {
+            protected Collection<V> delegateCollection = IndirectMap.this.getDelegate().values();
 

+            @Override
             public int size(){

                 return delegateCollection.size();

             }

             

+            @Override
             public boolean isEmpty(){

                 return delegateCollection.isEmpty();

             }

             

+            @Override
             public boolean contains(Object o){

                 return delegateCollection.contains(o);

             }

             

-            public Iterator iterator() {

-                return new Iterator() {

-                    Iterator delegateIterator = delegateCollection.iterator();

-                    Object currentObject;

+            @Override
+            public Iterator<V> iterator() {
+                return new Iterator<V>() {
+                    Iterator<V> delegateIterator = delegateCollection.iterator();
+                    V currentObject;
                     

+                    @Override
                     public boolean hasNext() {

                         return this.delegateIterator.hasNext();

                     }

                     

-                    public Object next() {

+                    @Override
+                    public V next() {
                         this.currentObject = this.delegateIterator.next();

                         return this.currentObject;

                     }

                     

+                    @Override
                     public void remove() {

                         Iterator iterator = IndirectMap.this.getDelegate().entrySet().iterator();

                         while (iterator.hasNext()){

@@ -733,18 +818,22 @@
                 };

             }

         

+            @Override
             public Object[] toArray(){

                 return this.delegateCollection.toArray();

             }

             

-            public Object[] toArray(Object a[]){

+            @Override
+            public <T> T[] toArray(T a[]){
                 return this.delegateCollection.toArray(a);

             }

             

-            public boolean add(Object o){

+            @Override
+            public boolean add(V o){
                 return this.delegateCollection.add(o);

             }

             

+            @Override
             public boolean remove(Object o){

                 Iterator iterator = IndirectMap.this.getDelegate().entrySet().iterator();

                 while (iterator.hasNext()){

@@ -757,17 +846,20 @@
                 return false;

             }

             

-            public boolean containsAll(Collection c){

+            @Override
+            public boolean containsAll(Collection<?> c){
                 return this.delegateCollection.containsAll(c);

             }

             

-            public boolean addAll(Collection c){

+            @Override
+            public boolean addAll(Collection<? extends V> c){
                 return this.delegateCollection.addAll(c);

             }

             

-            public boolean removeAll(Collection c){

+            @Override
+            public boolean removeAll(Collection<?> c){
                 boolean result = false;

-                for (Iterator iterator = c.iterator(); iterator.hasNext();){

+                for (Iterator<?> iterator = c.iterator(); iterator.hasNext();){
                     if (remove(iterator.next()) ){

                         result = true;

                     }

@@ -775,7 +867,8 @@
                 return result;

             }

             

-            public boolean retainAll(Collection c){

+            @Override
+            public boolean retainAll(Collection<?> c){
                 boolean result = false;

                 for (Iterator iterator = IndirectMap.this.entrySet().iterator(); iterator.hasNext();){

                     Map.Entry entry = (Map.Entry)iterator.next();

@@ -787,15 +880,18 @@
                 return result;

             }

             

+            @Override
             public void clear(){

                 IndirectMap.this.clear();

             }

             

             

+            @Override
             public boolean equals(Object o){

                 return this.delegateCollection.equals(o);

             }

             

+            @Override
             public int hashCode(){

                 return this.delegateCollection.hashCode();

             }

diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectSet.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectSet.java
index 781a3e0..28933a0 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectSet.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/indirection/IndirectSet.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.

+ * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the 

  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 

  * which accompanies this distribution. 

@@ -14,14 +14,18 @@
 

 import java.security.AccessController;

 import java.security.PrivilegedActionException;

-import java.util.*;

-import java.io.*;

 import java.beans.PropertyChangeListener;

+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import org.eclipse.persistence.descriptors.changetracking.CollectionChangeEvent;
+import org.eclipse.persistence.descriptors.changetracking.CollectionChangeTracker;
 import org.eclipse.persistence.exceptions.QueryException;

 import org.eclipse.persistence.internal.descriptors.changetracking.AttributeChangeListener;

+import org.eclipse.persistence.internal.indirection.UnitOfWorkQueryValueHolder;
 import org.eclipse.persistence.internal.localization.ToStringLocalization;

-import org.eclipse.persistence.descriptors.changetracking.*;

-import org.eclipse.persistence.internal.indirection.*;

 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;

 import org.eclipse.persistence.internal.security.PrivilegedGetMethod;

 import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker;

@@ -70,14 +74,15 @@
  * read. This is not required behavior.

  * </ul>

  *

+ * @param <E> the type of elements maintained by this set
  * @see org.eclipse.persistence.mappings.CollectionMapping

  * @author Big Country

  * @since TOPLink/Java 3.0+

  */

-public class IndirectSet implements CollectionChangeTracker, Set, IndirectCollection, Cloneable, Serializable {

+public class IndirectSet<E> implements CollectionChangeTracker, Set<E>, IndirectCollection, Cloneable, Serializable {
 

     /** Reduce type casting */

-    private volatile Set delegate;

+    private volatile Set<E> delegate;
 

     /** Delegate indirection behavior to a value holder */

     private ValueHolderInterface valueHolder;

@@ -150,9 +155,9 @@
      *

      * @param   c   the initial elements of the set

      */

-    public IndirectSet(Collection c) {

+    public IndirectSet(Collection<? extends E> c) {
         this.delegate = null;

-        this.valueHolder = new ValueHolder(new HashSet(c));

+        this.valueHolder = new ValueHolder(new HashSet<>(c));
     }

     

     protected boolean isRelationshipMaintenanceRequired() {

@@ -166,7 +171,8 @@
     /**

      * @see java.util.Set#add(java.lang.Object)

      */

-    public boolean add(Object element) {

+    @Override
+    public boolean add(E element) {
         boolean added = true;

         // PERF: If not instantiated just record the add to avoid the instantiation.

         if (shouldAvoidInstantiation()) {

@@ -190,10 +196,11 @@
     /**

      * @see java.util.Set#addAll(java.util.Collection)

      */

-    public boolean addAll(Collection c) {

+    @Override
+    public boolean addAll(Collection<? extends E> c) {
         // Must trigger add events if tracked or uow.

         if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {

-            Iterator objects = c.iterator();

+            Iterator<? extends E> objects = c.iterator();
             while (objects.hasNext()) {

                 this.add(objects.next());

             }

@@ -207,10 +214,10 @@
      * INTERNAL:

      * Return the freshly-built delegate.

      */

-    protected Set buildDelegate() {

+    protected Set<E> buildDelegate() {
         Set delegate = (Set)getValueHolder().getValue();

         if (delegate == null) {

-            delegate = new HashSet(this.initialCapacity, this.loadFactor);

+            delegate = new HashSet<>(this.initialCapacity, this.loadFactor);
         }

         // This can either be another indirect set or a HashSet.

         // It can be another indirect list because the mapping's query uses the same container policy.

@@ -237,9 +244,10 @@
     /**

      * @see java.util.Set#clear()

      */

+    @Override
     public void clear() {

         if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {

-            Iterator objects = iterator();

+            Iterator<E> objects = iterator();
             while (objects.hasNext()) {

                 objects.next();

                 objects.remove();

@@ -254,6 +262,7 @@
      * clear any changes that have been deferred to instantiation.

      * Indirect collections with change tracking avoid instantiation on add/remove.

      */

+    @Override
     public void clearDeferredChanges(){

         addedElements = null;

         removedElements = null;

@@ -276,9 +285,10 @@
             and "target" are the same object?). But the MergeManager also checks "instantiation"

             before merging collections (again, "un-instantiated" collections are not merged).

     */

+    @Override
     public Object clone() {

         try {

-            IndirectSet result = (IndirectSet)super.clone();

+            IndirectSet<E> result = (IndirectSet<E>)super.clone();
             result.delegate = this.cloneDelegate();

             result.valueHolder = new ValueHolder(result.delegate);

             result.attributeName = null;

@@ -293,7 +303,7 @@
      * INTERNAL:

      * Clone the delegate.

      */

-    protected Set cloneDelegate() {

+    protected Set<E> cloneDelegate() {
         java.lang.reflect.Method cloneMethod;

         try {

             if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){

@@ -312,7 +322,7 @@
         try {

             if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){

                 try {

-                    return (Set)AccessController.doPrivileged(new PrivilegedMethodInvoker(cloneMethod, this.getDelegate(), (Object[])null));

+                    return (Set<E>)AccessController.doPrivileged(new PrivilegedMethodInvoker(cloneMethod, this.getDelegate(), (Object[])null));
                 } catch (PrivilegedActionException exception) {

                     Exception throwableException = exception.getException();

                     if (throwableException instanceof IllegalAccessException) {

@@ -322,7 +332,7 @@
                     }

                 }

             } else {

-                return (Set)PrivilegedAccessHelper.invokeMethod(cloneMethod, this.getDelegate(), (Object[])null);

+                return (Set<E>)PrivilegedAccessHelper.invokeMethod(cloneMethod, this.getDelegate(), (Object[])null);
             }

         } catch (IllegalAccessException ex1) {

             throw QueryException.cloneMethodInaccessible();

@@ -334,6 +344,7 @@
     /**

      * @see java.util.Set#contains(java.lang.Object)

      */

+    @Override
     public boolean contains(Object element) {

         // PERF: Avoid instantiation if not required.

         if (hasAddedElements()) {

@@ -352,13 +363,15 @@
     /**

      * @see java.util.Set#containsAll(java.util.Collection)

      */

-    public boolean containsAll(Collection c) {

+    @Override
+    public boolean containsAll(Collection<?> c) {
         return this.getDelegate().containsAll(c);

     }

 

     /**

      * @see java.util.Set#equals(java.lang.Object)

      */

+    @Override
     public boolean equals(Object o) {

         return this.getDelegate().equals(o);

     }

@@ -368,7 +381,7 @@
      * Check whether the contents have been read from the database.

      * If they have not, read them and set the delegate.

      */

-    protected Set getDelegate() {

+    protected Set<E> getDelegate() {
         if (delegate == null) {

             synchronized(this){

                 if (delegate == null) {

@@ -384,6 +397,7 @@
      * Return the real collection object.

      * This will force instantiation.

      */

+    @Override
     public Object getDelegateObject() {

         return getDelegate();

     }

@@ -392,6 +406,7 @@
      * INTERNAL:

      * Return the valueHolder.

      */

+    @Override
     public ValueHolderInterface getValueHolder() {

         // PERF: lazy initialize value holder and vector as are normally set after creation.

         if (valueHolder == null) {

@@ -415,6 +430,7 @@
     /**

      * @see java.util.Set#hashCode()

      */

+    @Override
     public int hashCode() {

         return this.getDelegate().hashCode();

     }

@@ -422,6 +438,7 @@
     /**

      * @see java.util.Set#isEmpty()

      */

+    @Override
     public boolean isEmpty() {

         return this.getDelegate().isEmpty();

     }

@@ -429,6 +446,7 @@
     /**

      * Return whether the contents have been read from the database.

      */

+    @Override
     public boolean isInstantiated() {

         return this.getValueHolder().isInstantiated();

     }

@@ -436,21 +454,25 @@
     /**

      * @see java.util.Set#iterator()

      */

-    public Iterator iterator() {

+    @Override
+    public Iterator<E> iterator() {
         // Must wrap the interator to raise the remove event.

-        return new Iterator() {

-            Iterator delegateIterator = IndirectSet.this.getDelegate().iterator();

-            Object currentObject;

+        return new Iterator<E>() {
+            Iterator<E> delegateIterator = IndirectSet.this.getDelegate().iterator();
+            E currentObject;
             

+            @Override
             public boolean hasNext() {

                 return this.delegateIterator.hasNext();

             }

             

-            public Object next() {

+            @Override
+            public E next() {
                 this.currentObject = this.delegateIterator.next();

                 return this.currentObject;

             }

             

+            @Override
             public void remove() {

                 this.delegateIterator.remove();

                 IndirectSet.this.raiseRemoveChangeEvent(this.currentObject);

@@ -461,6 +483,7 @@
     /**

      * @see java.util.Set#remove(java.lang.Object)

      */

+    @Override
     public boolean remove(Object element) {

         // PERF: If not instantiated just record the removal to avoid the instantiation.

         if (shouldAvoidInstantiation()) {

@@ -484,7 +507,8 @@
     /**

      * @see java.util.Set#removeAll(java.util.Collection)

      */

-    public boolean removeAll(Collection c) {

+    @Override
+    public boolean removeAll(Collection<?> c) {
         // Must trigger remove events if tracked or uow.

         if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {

             Iterator objects = c.iterator();

@@ -499,7 +523,8 @@
     /**

      * @see java.util.Set#retainAll(java.util.Collection)

      */

-    public boolean retainAll(Collection c) {

+    @Override
+    public boolean retainAll(Collection<?> c) {
         // Must trigger remove events if tracked or uow.

         if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {

             Iterator objects = getDelegate().iterator();

@@ -520,6 +545,7 @@
      * Set the value holder.

      * Note that the delegate must be cleared out.

      */

+    @Override
     public void setValueHolder(ValueHolderInterface valueHolder) {

         this.delegate = null;

         this.valueHolder = valueHolder;

@@ -530,6 +556,7 @@
      * Set whether this collection should attempt do deal with adds and removes without retrieving the 

      * collection from the dB

      */

+    @Override
     public void setUseLazyInstantiation(boolean useLazyInstantiation){

         this.useLazyInstantiation = useLazyInstantiation;

     }

@@ -537,6 +564,7 @@
     /**

      * @see java.util.Set#size()

      */

+    @Override
     public int size() {

         return this.getDelegate().size();

     }

@@ -553,6 +581,7 @@
     /**

      * @see java.util.Set#toArray()

      */

+    @Override
     public Object[] toArray() {

         return this.getDelegate().toArray();

     }

@@ -560,7 +589,8 @@
     /**

      * @see java.util.Set#toArray(java.lang.Object[])

      */

-    public Object[] toArray(Object[] a) {

+    @Override
+    public <E> E[] toArray(E[] a) {
         return this.getDelegate().toArray(a);

     }

 

@@ -570,6 +600,7 @@
      * Don't allow this method to trigger a database read.

      * @see java.util.HashSet#toString()

      */

+    @Override
     public String toString() {

         if (ValueHolderInterface.shouldToStringInstantiate) {

             return this.getDelegate().toString();

@@ -610,6 +641,7 @@
      * INTERNAL:

      * Return the property change listener for change tracking.

      */

+    @Override
      public PropertyChangeListener _persistence_getPropertyChangeListener() {

          return changeListener;

      }

@@ -626,6 +658,7 @@
      * INTERNAL:

      * Set the property change listener for change tracking.

      */

+    @Override
      public void _persistence_setPropertyChangeListener(PropertyChangeListener changeListener) {

          this.changeListener = changeListener;

      }

@@ -634,6 +667,7 @@
      * INTERNAL:

      * Return the mapping attribute name, used to raise change events.

      */

+    @Override
      public String getTrackedAttributeName() {

          return attributeName;

      }

@@ -643,6 +677,7 @@
      * Set the mapping attribute name, used to raise change events.

      * This is required if the change listener is set.

      */

+    @Override
      public void setTrackedAttributeName(String attributeName) {

          this.attributeName = attributeName;

      }

@@ -651,9 +686,10 @@
      * INTERNAL:

      * Return the elements that have been removed before instantiation.

      */

+    @Override
     public Collection getRemovedElements() {

         if (removedElements == null) {

-            removedElements = new HashSet();

+            removedElements = new HashSet<>();
         }

         return removedElements;

     }

@@ -662,9 +698,10 @@
      * INTERNAL:

      * Return the elements that have been added before instantiation.

      */

+    @Override
     public Collection getAddedElements() {

         if (addedElements == null) {

-            addedElements = new HashSet();

+            addedElements = new HashSet<>();
         }

         return addedElements;

     }

@@ -689,6 +726,7 @@
      * INTERNAL:

      * Return if any elements that have been added or removed before instantiation.

      */

+    @Override
     public boolean hasDeferredChanges() {

         return hasRemovedElements() || hasAddedElements();

     }

diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/ClassConstants.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/ClassConstants.java
index d08ec4a..922c753 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/ClassConstants.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/ClassConstants.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.

+ * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the 

  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 

  * which accompanies this distribution. 

@@ -23,6 +23,7 @@
 import org.w3c.dom.Document;

 import org.w3c.dom.Node;

 

+import org.eclipse.persistence.indirection.IndirectCollectionsFactory;
 import org.eclipse.persistence.internal.core.helper.CoreClassConstants;

 import org.eclipse.persistence.internal.sessions.DatabaseSessionImpl;

 import org.eclipse.persistence.internal.sessions.AbstractSession;

@@ -60,9 +61,9 @@
     public static final Class FunctionExpression_Class = org.eclipse.persistence.internal.expressions.FunctionExpression.class;

     public static final Class ArgumentListFunctionExpression_Class = org.eclipse.persistence.internal.expressions.ArgumentListFunctionExpression.class;

     public static final Class IndirectContainer_Class = org.eclipse.persistence.indirection.IndirectContainer.class;

-    public static final Class IndirectList_Class = org.eclipse.persistence.indirection.IndirectList.class;

-    public static final Class IndirectSet_Class = org.eclipse.persistence.indirection.IndirectSet.class;

-    public static final Class IndirectMap_Class = org.eclipse.persistence.indirection.IndirectMap.class;

+    public static final Class IndirectList_Class = IndirectCollectionsFactory.IndirectList_Class;
+    public static final Class IndirectSet_Class = IndirectCollectionsFactory.IndirectSet_Class;
+    public static final Class IndirectMap_Class = IndirectCollectionsFactory.IndirectMap_Class;
     public static final Class LogicalExpression_Class = org.eclipse.persistence.internal.expressions.LogicalExpression.class;

     public static final Class PublicInterfaceDatabaseSession_Class = DatabaseSessionImpl.class;

     public static final Class PerformanceProfiler_Class = org.eclipse.persistence.tools.profiler.PerformanceProfiler.class;

diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/jdk8/IndirectCollectionsProvider.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/jdk8/IndirectCollectionsProvider.java
new file mode 100644
index 0000000..0c0bc9c
--- /dev/null
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/jdk8/IndirectCollectionsProvider.java
@@ -0,0 +1,78 @@
+/**
+ * *****************************************************************************
+ * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
+ * program and the accompanying materials are made available under the terms of
+ * the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 which
+ * accompanies this distribution. The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution
+ * License is available at http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors: Oracle - initial API and implementation
+ *****************************************************************************
+ */
+package org.eclipse.persistence.internal.indirection.jdk8;
+
+import java.util.Collection;
+import java.util.Map;
+import org.eclipse.persistence.indirection.IndirectCollection;
+import org.eclipse.persistence.indirection.IndirectCollectionsFactory;
+import org.eclipse.persistence.indirection.IndirectList;
+import org.eclipse.persistence.indirection.IndirectMap;
+import org.eclipse.persistence.indirection.IndirectSet;
+
+/**
+ * Responsible for creating Java SE 8+ specific implementations of {@link IndirectCollection}s.
+ *
+ * @author Lukas Jungmann
+ * @see IndirectCollection
+ * @see IndirectCollectionsFactory
+ * @see IndirectCollectionsFactory.IndirectCollectionsProvider
+ * @since EclispeLink 2.6.0
+ */
+public final class IndirectCollectionsProvider implements IndirectCollectionsFactory.IndirectCollectionsProvider {
+
+    @Override
+    public Class getListClass() {
+        return org.eclipse.persistence.internal.indirection.jdk8.IndirectList.class;
+    }
+
+    @Override
+    public <E> IndirectList<E> createIndirectList(int initialCapacity, int capacityIncrement) {
+        return new org.eclipse.persistence.internal.indirection.jdk8.IndirectList<>(initialCapacity, capacityIncrement);
+    }
+
+    @Override
+    public <E> IndirectList<E> createIndirectList(Collection<? extends E> collection) {
+        return new org.eclipse.persistence.internal.indirection.jdk8.IndirectList<>(collection);
+    }
+
+    @Override
+    public Class getSetClass() {
+        return org.eclipse.persistence.internal.indirection.jdk8.IndirectSet.class;
+    }
+
+    @Override
+    public <E> IndirectSet<E> createIndirectSet(int initialCapacity, float loadFactor) {
+        return new org.eclipse.persistence.internal.indirection.jdk8.IndirectSet<>(initialCapacity, loadFactor);
+    }
+
+    @Override
+    public <E> IndirectSet<E> createIndirectSet(Collection<? extends E> collection) {
+        return new org.eclipse.persistence.internal.indirection.jdk8.IndirectSet<>(collection);
+    }
+
+    @Override
+    public Class getMapClass() {
+        return org.eclipse.persistence.internal.indirection.jdk8.IndirectMap.class;
+    }
+
+    @Override
+    public <K, V> IndirectMap<K, V> createIndirectMap(int initialCapacity, float loadFactor) {
+        return new org.eclipse.persistence.internal.indirection.jdk8.IndirectMap<>(initialCapacity, loadFactor);
+    }
+
+    @Override
+    public <K, V> IndirectMap<K, V> createIndirectMap(Map<? extends K, ? extends V> map) {
+        return new org.eclipse.persistence.internal.indirection.jdk8.IndirectMap<>(map);
+    }
+}
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/jdk8/IndirectList.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/jdk8/IndirectList.java
new file mode 100644
index 0000000..e44340f
--- /dev/null
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/jdk8/IndirectList.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.persistence.internal.indirection.jdk8;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Spliterator;
+import java.util.Vector;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import java.util.stream.Stream;
+
+/**
+ * Java SE 8 additions to {@link org.eclipse.persistence.indirection.IndirectList}.
+ *
+ * @author Lukas Jungmann
+ */
+public class IndirectList<E> extends org.eclipse.persistence.indirection.IndirectList<E> {
+
+    public IndirectList() {
+        super();
+    }
+
+    public IndirectList(int initialCapacity) {
+        super(initialCapacity);
+    }
+
+    public IndirectList(int initialCapacity, int capacityIncrement) {
+        super(initialCapacity, capacityIncrement);
+    }
+
+    public IndirectList(Collection<? extends E> vector) {
+        super(vector);
+    }
+
+    @Override
+    public Spliterator<E> spliterator() {
+        return getDelegate().spliterator();
+    }
+
+    @Override
+    public synchronized void replaceAll(UnaryOperator<E> operator) {
+        getDelegate().replaceAll(operator);
+    }
+
+    @Override
+    public synchronized boolean removeIf(Predicate<? super E> filter) {
+        return getDelegate().removeIf(filter);
+    }
+
+    @Override
+    public synchronized void forEach(Consumer<? super E> action) {
+        getDelegate().forEach(action);
+    }
+
+    @Override
+    public Stream<E> parallelStream() {
+        return getDelegate().parallelStream();
+    }
+
+    @Override
+    public Stream<E> stream() {
+        return getDelegate().stream();
+    }
+
+    @Override
+    public void sort(Comparator<? super E> c) {
+        getDelegate().sort(c);
+    }
+
+}
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/jdk8/IndirectMap.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/jdk8/IndirectMap.java
new file mode 100644
index 0000000..3ad0e07
--- /dev/null
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/jdk8/IndirectMap.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.persistence.internal.indirection.jdk8;
+
+import java.util.Map;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+/**
+ * Java SE 8 additions to {@link org.eclipse.persistence.indirection.IndirectMap}.
+ *
+ * @author Lukas Jungmann
+ */
+public class IndirectMap<K, V> extends org.eclipse.persistence.indirection.IndirectMap<K, V> {
+
+    public IndirectMap() {
+        super();
+    }
+
+    public IndirectMap(int initialCapacity) {
+        super(initialCapacity);
+    }
+
+    public IndirectMap(int initialCapacity, float loadFactor) {
+        super(initialCapacity, loadFactor);
+    }
+
+    public IndirectMap(Map<? extends K, ? extends V> m) {
+        super(m);
+    }
+
+    @Override
+    public synchronized V merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction) {
+        return getDelegate().merge(key, value, remappingFunction);
+    }
+
+    @Override
+    public synchronized V compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction) {
+        return getDelegate().compute(key, remappingFunction);
+    }
+
+    @Override
+    public synchronized V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction) {
+        return getDelegate().computeIfPresent(key, remappingFunction);
+    }
+
+    @Override
+    public synchronized V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction) {
+        return getDelegate().computeIfAbsent(key, mappingFunction);
+    }
+
+    @Override
+    public synchronized V replace(K key, V value) {
+        return getDelegate().replace(key, value);
+    }
+
+    @Override
+    public synchronized boolean replace(K key, V oldValue, V newValue) {
+        return getDelegate().replace(key, oldValue, newValue);
+    }
+
+    @Override
+    public synchronized boolean remove(Object key, Object value) {
+        return getDelegate().remove(key, value);
+    }
+
+    @Override
+    public synchronized V putIfAbsent(K key, V value) {
+        return getDelegate().putIfAbsent(key, value);
+    }
+
+    @Override
+    public synchronized void replaceAll(BiFunction function) {
+        getDelegate().replaceAll(function);
+    }
+
+    @Override
+    public synchronized void forEach(BiConsumer<? super K,? super V> action) {
+        getDelegate().forEach(action);
+    }
+
+    @Override
+    public synchronized V getOrDefault(Object key, V defaultValue) {
+        return getDelegate().getOrDefault(key, defaultValue);
+    }
+
+}
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/jdk8/IndirectSet.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/jdk8/IndirectSet.java
new file mode 100644
index 0000000..73689f2
--- /dev/null
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/indirection/jdk8/IndirectSet.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.persistence.internal.indirection.jdk8;
+
+import java.util.Collection;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+/**
+ * Java SE 8 additions to {@link org.eclipse.persistence.indirection.IndirectSet}.
+ *
+ * @author Lukas Jungmann
+ */
+public class IndirectSet<E> extends org.eclipse.persistence.indirection.IndirectSet<E> {
+
+    public IndirectSet() {
+        super();
+    }
+
+    public IndirectSet(int initialCapacity) {
+        super(initialCapacity);
+    }
+
+    public IndirectSet(int initialCapacity, float loadFactor) {
+        super(initialCapacity, loadFactor);
+    }
+
+    public IndirectSet(Collection<? extends E> c) {
+        super(c);
+    }
+
+    @Override
+    public Spliterator<E> spliterator() {
+        return getDelegate().spliterator();
+    }
+
+    @Override
+    public Stream<E> parallelStream() {
+        return getDelegate().parallelStream();
+    }
+
+    @Override
+    public Stream<E> stream() {
+        return getDelegate().stream();
+    }
+
+    @Override
+    public boolean removeIf(Predicate<? super E> filter) {
+        return getDelegate().removeIf(filter);
+    }
+
+    @Override
+    public void forEach(Consumer<? super E> action) {
+        getDelegate().forEach(action);
+    }
+
+}
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/queries/ContainerPolicy.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/queries/ContainerPolicy.java
index f937112..b3f25ce 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/queries/ContainerPolicy.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/queries/ContainerPolicy.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.

+ * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the 

  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 

  * which accompanies this distribution. 

@@ -34,7 +34,6 @@
 import org.eclipse.persistence.internal.sessions.ObjectChangeSet;

 import org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet;

 import org.eclipse.persistence.queries.*;

-import org.eclipse.persistence.sessions.DatabaseRecord;

 import org.eclipse.persistence.exceptions.*;

 import org.eclipse.persistence.expressions.Expression;

 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;

@@ -46,8 +45,7 @@
 import org.eclipse.persistence.descriptors.ClassDescriptor;

 import org.eclipse.persistence.descriptors.changetracking.CollectionChangeEvent;

 import org.eclipse.persistence.indirection.IndirectCollection;

-import org.eclipse.persistence.indirection.IndirectList;

-import org.eclipse.persistence.indirection.IndirectSet;

+import org.eclipse.persistence.indirection.IndirectCollectionsFactory;
 import org.eclipse.persistence.internal.sessions.AbstractRecord;

 import org.eclipse.persistence.mappings.CollectionMapping;

 import org.eclipse.persistence.mappings.DatabaseMapping;

@@ -614,9 +612,9 @@
         Class containerClass = getContainerClass();

         // PERF: Avoid reflection for common cases.

         if (containerClass == ClassConstants.IndirectList_Class) {

-            return new IndirectList();

+            return IndirectCollectionsFactory.createIndirectList();
         } else if (containerClass == ClassConstants.IndirectSet_Class) {

-            return new IndirectSet();

+            return IndirectCollectionsFactory.createIndirectSet();
         } else if (containerClass == ClassConstants.ArrayList_class) {

             return new ArrayList();

         } else if (containerClass == ClassConstants.Vector_class) {

@@ -653,9 +651,9 @@
         try {

             // PERF: Avoid reflection for common cases.

             if (containerClass == ClassConstants.IndirectList_Class) {

-                return new IndirectList(initialCapacity);

+                return IndirectCollectionsFactory.createIndirectList(initialCapacity);
             } else if (containerClass == ClassConstants.IndirectSet_Class) {

-                return new IndirectSet(initialCapacity);

+                return IndirectCollectionsFactory.createIndirectSet(initialCapacity);
             } else if (containerClass == ClassConstants.ArrayList_class) {

                 return new ArrayList(initialCapacity);

             } else if (containerClass == ClassConstants.Vector_class) {

diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/queries/IndirectListContainerPolicy.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/queries/IndirectListContainerPolicy.java
index 5c18c2e..9c76b64 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/queries/IndirectListContainerPolicy.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/queries/IndirectListContainerPolicy.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.

+ * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the 

  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 

  * which accompanies this distribution. 

@@ -14,7 +14,7 @@
 

 import java.util.*;

 

-import org.eclipse.persistence.indirection.*;

+import org.eclipse.persistence.indirection.IndirectCollectionsFactory;
 import org.eclipse.persistence.internal.sessions.AbstractSession;

 

 /**

@@ -56,7 +56,7 @@
             return ((Vector)container).clone();

         } catch (Exception notVector) {

             // Could potentially be another Collection type as well.

-            return new IndirectList((Collection)container);

+            return IndirectCollectionsFactory.createIndirectList((Collection)container);
         }

     }

     

@@ -65,7 +65,7 @@
      * Just return the Vector.

      */

     public Object buildContainerFromVector(Vector vector, AbstractSession session) {

-        return new IndirectList(vector);

+        return IndirectCollectionsFactory.createIndirectList(vector);
     }

     

     /**

@@ -73,7 +73,7 @@
      * Return a new Vector.

      */

     public Object containerInstance() {

-        return new IndirectList();

+        return IndirectCollectionsFactory.createIndirectList();
     }

     

     /**

@@ -81,6 +81,6 @@
      * Return a new Vector.

      */

     public Object containerInstance(int initialCapacity) {

-        return new IndirectList(initialCapacity);

+        return IndirectCollectionsFactory.createIndirectList(initialCapacity);
     }

 }