Merge "Update java.util.Map partially to 11+28"
diff --git a/api/current.txt b/api/current.txt
index 544fb3e..ac9f19a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13232,6 +13232,7 @@
     method @Nullable public default V computeIfPresent(K, @NonNull java.util.function.BiFunction<? super K,? super V,? extends V>);
     method public boolean containsKey(@Nullable Object);
     method public boolean containsValue(@Nullable Object);
+    method public static <K, V> java.util.Map<K,V> copyOf(java.util.Map<? extends K,? extends V>);
     method @NonNull public static <K, V> java.util.Map.Entry<K,V> entry(@NonNull K, @NonNull V);
     method @NonNull public java.util.Set<java.util.Map.Entry<K,V>> entrySet();
     method public boolean equals(@Nullable Object);
diff --git a/nullability_warnings.txt b/nullability_warnings.txt
index 8bfd6a8..ec1b52a 100644
--- a/nullability_warnings.txt
+++ b/nullability_warnings.txt
@@ -1,2 +1,4 @@
+WARNING: method java.util.Map.copyOf(java.util.Map<? extends K,? extends V>), parameter map, MISSING
+WARNING: method java.util.Map.copyOf(java.util.Map<? extends K,? extends V>), return value, MISSING
 WARNING: method java.util.Set.copyOf(java.util.Collection<? extends E>), parameter coll, MISSING
 WARNING: method java.util.Set.copyOf(java.util.Collection<? extends E>), return value, MISSING
diff --git a/ojluni/src/main/java/java/util/Map.java b/ojluni/src/main/java/java/util/Map.java
index ed365ec..cf07a11 100644
--- a/ojluni/src/main/java/java/util/Map.java
+++ b/ojluni/src/main/java/java/util/Map.java
@@ -1653,4 +1653,30 @@
         // KeyValueHolder checks for nulls
         return new KeyValueHolder<>(k, v);
     }
+
+    /**
+     * Returns an <a href="#unmodifiable">unmodifiable Map</a> containing the entries
+     * of the given Map. The given Map must not be null, and it must not contain any
+     * null keys or values. If the given Map is subsequently modified, the returned
+     * Map will not reflect such modifications.
+     *
+     * @implNote
+     * If the given Map is an <a href="#unmodifiable">unmodifiable Map</a>,
+     * calling copyOf will generally not create a copy.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param map a {@code Map} from which entries are drawn, must be non-null
+     * @return a {@code Map} containing the entries of the given {@code Map}
+     * @throws NullPointerException if map is null, or if it contains any null keys or values
+     * @since 10
+     */
+    @SuppressWarnings({"rawtypes","unchecked"})
+    static <K, V> Map<K, V> copyOf(Map<? extends K, ? extends V> map) {
+        if (map instanceof ImmutableCollections.AbstractImmutableMap) {
+            return (Map<K,V>)map;
+        } else {
+            return (Map<K,V>)Map.ofEntries(map.entrySet().toArray(new Entry[0]));
+        }
+    }
 }
diff --git a/ojluni/src/test/java/util/Map/MapFactories.java b/ojluni/src/test/java/util/Map/MapFactories.java
new file mode 100644
index 0000000..7fe14e4
--- /dev/null
+++ b/ojluni/src/test/java/util/Map/MapFactories.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.util.Map;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertNotSame;
+import static org.testng.Assert.assertSame;
+
+/*
+ * @test
+ * @bug 8048330
+ * @summary Test convenience static factory methods on Map.
+ * @run testng MapFactories
+ */
+
+public class MapFactories {
+
+    Map<Integer, String> genMap() {
+        Map<Integer, String> map = new HashMap<>();
+        map.put(1, "a");
+        map.put(2, "b");
+        map.put(3, "c");
+        return map;
+    }
+
+    @Test
+    public void copyOfResultsEqual() {
+        Map<Integer, String> orig = genMap();
+        Map<Integer, String> copy = Map.copyOf(orig);
+
+        assertEquals(orig, copy);
+        assertEquals(copy, orig);
+    }
+
+    @Test
+    public void copyOfModifiedUnequal() {
+        Map<Integer, String> orig = genMap();
+        Map<Integer, String> copy = Map.copyOf(orig);
+        orig.put(4, "d");
+
+        assertNotEquals(orig, copy);
+        assertNotEquals(copy, orig);
+    }
+
+    @Test
+    public void copyOfIdentity() {
+        Map<Integer, String> orig = genMap();
+        Map<Integer, String> copy1 = Map.copyOf(orig);
+        Map<Integer, String> copy2 = Map.copyOf(copy1);
+
+        assertNotSame(orig, copy1);
+        assertSame(copy1, copy2);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void copyOfRejectsNullMap() {
+        Map<Integer, String> map = Map.copyOf(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void copyOfRejectsNullKey() {
+        Map<Integer, String> map = genMap();
+        map.put(null, "x");
+        Map<Integer, String> copy = Map.copyOf(map);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void copyOfRejectsNullValue() {
+        Map<Integer, String> map = genMap();
+        map.put(-1, null);
+        Map<Integer, String> copy = Map.copyOf(map);
+    }
+}