Merge "Speed up DHPublicKeyTest; make DHPrivateKeyTest consistent."
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodHandleAccessorsTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleAccessorsTest.java
new file mode 100644
index 0000000..a9f6802
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleAccessorsTest.java
@@ -0,0 +1,922 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.lang.invoke;
+
+import junit.framework.TestCase;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.WrongMethodTypeException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class MethodHandleAccessorsTest extends junit.framework.TestCase {
+ public static class ValueHolder {
+ public boolean m_z = false;
+ public byte m_b = 0;
+ public char m_c = 'a';
+ public short m_s = 0;
+ public int m_i = 0;
+ public float m_f = 0.0f;
+ public double m_d = 0.0;
+ public long m_j = 0;
+ public String m_l = "a";
+
+ public static boolean s_z;
+ public static byte s_b;
+ public static char s_c;
+ public static short s_s;
+ public static int s_i;
+ public static float s_f;
+ public static double s_d;
+ public static long s_j;
+ public static String s_l;
+
+ public final int m_fi = 0xa5a5a5a5;
+ public static final int s_fi = 0x5a5a5a5a;
+ }
+
+ private static enum PrimitiveType {
+ Boolean,
+ Byte,
+ Char,
+ Short,
+ Int,
+ Long,
+ Float,
+ Double,
+ String,
+ }
+
+ private static enum AccessorType {
+ IPUT,
+ SPUT,
+ IGET,
+ SGET,
+ }
+
+ static void setByte(MethodHandle m, ValueHolder v, byte value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void setByte(MethodHandle m, byte value, boolean expectFailure) throws Throwable {
+ setByte(m, null, value, expectFailure);
+ }
+
+ static void getByte(MethodHandle m, ValueHolder v, byte value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final byte got;
+ if (v == null) {
+ got = (byte)m.invokeExact();
+ } else {
+ got = (byte)m.invokeExact(v);
+ }
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void getByte(MethodHandle m, byte value, boolean expectFailure) throws Throwable {
+ getByte(m, null, value, expectFailure);
+ }
+
+ static void setChar(MethodHandle m, ValueHolder v, char value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void setChar(MethodHandle m, char value, boolean expectFailure) throws Throwable {
+ setChar(m, null, value, expectFailure);
+ }
+
+ static void getChar(MethodHandle m, ValueHolder v, char value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final char got;
+ if (v == null) {
+ got = (char)m.invokeExact();
+ } else {
+ got = (char)m.invokeExact(v);
+ }
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void getChar(MethodHandle m, char value, boolean expectFailure) throws Throwable {
+ getChar(m, null, value, expectFailure);
+ }
+
+ static void setShort(MethodHandle m, ValueHolder v, short value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void setShort(MethodHandle m, short value, boolean expectFailure) throws Throwable {
+ setShort(m, null, value, expectFailure);
+ }
+
+ static void getShort(MethodHandle m, ValueHolder v, short value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final short got = (v == null) ? (short)m.invokeExact() : (short)m.invokeExact(v);
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void getShort(MethodHandle m, short value, boolean expectFailure) throws Throwable {
+ getShort(m, null, value, expectFailure);
+ }
+
+ static void setInt(MethodHandle m, ValueHolder v, int value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void setInt(MethodHandle m, int value, boolean expectFailure) throws Throwable {
+ setInt(m, null, value, expectFailure);
+ }
+
+ static void getInt(MethodHandle m, ValueHolder v, int value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final int got = (v == null) ? (int)m.invokeExact() : (int)m.invokeExact(v);
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void getInt(MethodHandle m, int value, boolean expectFailure) throws Throwable {
+ getInt(m, null, value, expectFailure);
+ }
+
+ static void setLong(MethodHandle m, ValueHolder v, long value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void setLong(MethodHandle m, long value, boolean expectFailure) throws Throwable {
+ setLong(m, null, value, expectFailure);
+ }
+
+ static void getLong(MethodHandle m, ValueHolder v, long value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final long got = (v == null) ? (long)m.invokeExact() : (long)m.invokeExact(v);
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void getLong(MethodHandle m, long value, boolean expectFailure) throws Throwable {
+ getLong(m, null, value, expectFailure);
+ }
+
+ static void setFloat(MethodHandle m, ValueHolder v, float value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void setFloat(MethodHandle m, float value, boolean expectFailure) throws Throwable {
+ setFloat(m, null, value, expectFailure);
+ }
+
+ static void getFloat(MethodHandle m, ValueHolder v, float value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final float got = (v == null) ? (float)m.invokeExact() : (float)m.invokeExact(v);
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void getFloat(MethodHandle m, float value, boolean expectFailure) throws Throwable {
+ getFloat(m, null, value, expectFailure);
+ }
+
+ static void setDouble(MethodHandle m, ValueHolder v, double value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void setDouble(MethodHandle m, double value, boolean expectFailure)
+ throws Throwable {
+ setDouble(m, null, value, expectFailure);
+ }
+
+ static void getDouble(MethodHandle m, ValueHolder v, double value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final double got = (v == null) ? (double)m.invokeExact() : (double)m.invokeExact(v);
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void getDouble(MethodHandle m, double value, boolean expectFailure)
+ throws Throwable {
+ getDouble(m, null, value, expectFailure);
+ }
+
+ static void setString(MethodHandle m, ValueHolder v, String value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void setString(MethodHandle m, String value, boolean expectFailure)
+ throws Throwable {
+ setString(m, null, value, expectFailure);
+ }
+
+ static void getString(MethodHandle m, ValueHolder v, String value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final String got = (v == null) ? (String)m.invokeExact() : (String)m.invokeExact(v);
+ assertTrue(got.equals(value));
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void getString(MethodHandle m, String value, boolean expectFailure)
+ throws Throwable {
+ getString(m, null, value, expectFailure);
+ }
+
+ static void setBoolean(MethodHandle m, ValueHolder v, boolean value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void setBoolean(MethodHandle m, boolean value, boolean expectFailure)
+ throws Throwable {
+ setBoolean(m, null, value, expectFailure);
+ }
+
+ static void getBoolean(MethodHandle m, ValueHolder v, boolean value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final boolean got =
+ (v == null) ? (boolean)m.invokeExact() : (boolean)m.invokeExact(v);
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertEquals(exceptionThrown, expectFailure);
+ }
+
+ static void getBoolean(MethodHandle m, boolean value, boolean expectFailure)
+ throws Throwable {
+ getBoolean(m, null, value, expectFailure);
+ }
+
+ static boolean resultFor(PrimitiveType actualType, PrimitiveType expectedType,
+ AccessorType actualAccessor,
+ AccessorType expectedAccessor) {
+ return (actualType != expectedType) || (actualAccessor != expectedAccessor);
+ }
+
+ static void tryAccessor(MethodHandle methodHandle,
+ ValueHolder valueHolder,
+ PrimitiveType primitive,
+ Object value,
+ AccessorType accessor) throws Throwable {
+ boolean booleanValue =
+ value instanceof Boolean ? ((Boolean)value).booleanValue() : false;
+ setBoolean(methodHandle, valueHolder, booleanValue,
+ resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.IPUT));
+ setBoolean(methodHandle, booleanValue,
+ resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.SPUT));
+ getBoolean(methodHandle, valueHolder, booleanValue,
+ resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.IGET));
+ getBoolean(methodHandle, booleanValue,
+ resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.SGET));
+
+ byte byteValue = value instanceof Byte ? ((Byte)value).byteValue() : (byte)0;
+ setByte(methodHandle, valueHolder, byteValue,
+ resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.IPUT));
+ setByte(methodHandle, byteValue,
+ resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.SPUT));
+ getByte(methodHandle, valueHolder, byteValue,
+ resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.IGET));
+ getByte(methodHandle, byteValue,
+ resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.SGET));
+
+ char charValue = value instanceof Character ? ((Character)value).charValue() : 'z';
+ setChar(methodHandle, valueHolder, charValue,
+ resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.IPUT));
+ setChar(methodHandle, charValue,
+ resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.SPUT));
+ getChar(methodHandle, valueHolder, charValue,
+ resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.IGET));
+ getChar(methodHandle, charValue,
+ resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.SGET));
+
+ short shortValue = value instanceof Short ? ((Short)value).shortValue() : (short)0;
+ setShort(methodHandle, valueHolder, shortValue,
+ resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.IPUT));
+ setShort(methodHandle, shortValue,
+ resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.SPUT));
+ getShort(methodHandle, valueHolder, shortValue,
+ resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.IGET));
+ getShort(methodHandle, shortValue,
+ resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.SGET));
+
+ int intValue = value instanceof Integer ? ((Integer)value).intValue() : -1;
+ setInt(methodHandle, valueHolder, intValue,
+ resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.IPUT));
+ setInt(methodHandle, intValue,
+ resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.SPUT));
+ getInt(methodHandle, valueHolder, intValue,
+ resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.IGET));
+ getInt(methodHandle, intValue,
+ resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.SGET));
+
+ long longValue = value instanceof Long ? ((Long)value).longValue() : (long)-1;
+ setLong(methodHandle, valueHolder, longValue,
+ resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.IPUT));
+ setLong(methodHandle, longValue,
+ resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.SPUT));
+ getLong(methodHandle, valueHolder, longValue,
+ resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.IGET));
+ getLong(methodHandle, longValue,
+ resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.SGET));
+
+ float floatValue = value instanceof Float ? ((Float)value).floatValue() : -1.0f;
+ setFloat(methodHandle, valueHolder, floatValue,
+ resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.IPUT));
+ setFloat(methodHandle, floatValue,
+ resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.SPUT));
+ getFloat(methodHandle, valueHolder, floatValue,
+ resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.IGET));
+ getFloat(methodHandle, floatValue,
+ resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.SGET));
+
+ double doubleValue = value instanceof Double ? ((Double)value).doubleValue() : -1.0;
+ setDouble(methodHandle, valueHolder, doubleValue,
+ resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.IPUT));
+ setDouble(methodHandle, doubleValue,
+ resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.SPUT));
+ getDouble(methodHandle, valueHolder, doubleValue,
+ resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.IGET));
+ getDouble(methodHandle, doubleValue,
+ resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.SGET));
+
+ String stringValue = value instanceof String ? ((String) value) : "No Spock, no";
+ setString(methodHandle, valueHolder, stringValue,
+ resultFor(primitive, PrimitiveType.String, accessor, AccessorType.IPUT));
+ setString(methodHandle, stringValue,
+ resultFor(primitive, PrimitiveType.String, accessor, AccessorType.SPUT));
+ getString(methodHandle, valueHolder, stringValue,
+ resultFor(primitive, PrimitiveType.String, accessor, AccessorType.IGET));
+ getString(methodHandle, stringValue,
+ resultFor(primitive, PrimitiveType.String, accessor, AccessorType.SGET));
+ }
+
+ public void testBooleanSettersAndGetters() throws Throwable {
+ ValueHolder valueHolder = new ValueHolder();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ boolean[] booleans = {false, true, false};
+ for (boolean b : booleans) {
+ Boolean boxed = new Boolean(b);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_z", boolean.class),
+ valueHolder, PrimitiveType.Boolean, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_z", boolean.class),
+ valueHolder, PrimitiveType.Boolean, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_z == b);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_z", boolean.class),
+ valueHolder, PrimitiveType.Boolean, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_z", boolean.class),
+ valueHolder, PrimitiveType.Boolean, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_z == b);
+ }
+ }
+
+ public void testByteSettersAndGetters() throws Throwable {
+ ValueHolder valueHolder = new ValueHolder();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ byte[] bytes = {(byte) 0x73, (byte) 0xfe};
+ for (byte b : bytes) {
+ Byte boxed = new Byte(b);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_b", byte.class),
+ valueHolder, PrimitiveType.Byte, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_b", byte.class),
+ valueHolder, PrimitiveType.Byte, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_b == b);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_b", byte.class),
+ valueHolder, PrimitiveType.Byte, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_b", byte.class),
+ valueHolder, PrimitiveType.Byte, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_b == b);
+ }
+ }
+
+ public void testCharSettersAndGetters() throws Throwable {
+ ValueHolder valueHolder = new ValueHolder();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ char[] chars = {'a', 'b', 'c'};
+ for (char c : chars) {
+ Character boxed = new Character(c);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_c", char.class),
+ valueHolder, PrimitiveType.Char, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_c", char.class),
+ valueHolder, PrimitiveType.Char, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_c == c);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_c", char.class),
+ valueHolder, PrimitiveType.Char, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_c", char.class),
+ valueHolder, PrimitiveType.Char, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_c == c);
+ }
+ }
+
+ public void testShortSettersAndGetters() throws Throwable {
+ ValueHolder valueHolder = new ValueHolder();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ short[] shorts = {(short) 0x1234, (short) 0x4321};
+ for (short s : shorts) {
+ Short boxed = new Short(s);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_s", short.class),
+ valueHolder, PrimitiveType.Short, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_s", short.class),
+ valueHolder, PrimitiveType.Short, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_s == s);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_s", short.class),
+ valueHolder, PrimitiveType.Short, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_s", short.class),
+ valueHolder, PrimitiveType.Short, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_s == s);
+ }
+ }
+
+ public void testIntSettersAndGetters() throws Throwable {
+ ValueHolder valueHolder = new ValueHolder();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ int[] ints = {-100000000, 10000000};
+ for (int i : ints) {
+ Integer boxed = new Integer(i);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_i", int.class),
+ valueHolder, PrimitiveType.Int, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_i", int.class),
+ valueHolder, PrimitiveType.Int, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_i == i);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_i", int.class),
+ valueHolder, PrimitiveType.Int, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_i", int.class),
+ valueHolder, PrimitiveType.Int, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_i == i);
+ }
+ }
+
+ public void testFloatSettersAndGetters() throws Throwable {
+ ValueHolder valueHolder = new ValueHolder();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ float[] floats = {0.99f, -1.23e-17f};
+ for (float f : floats) {
+ Float boxed = new Float(f);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_f", float.class),
+ valueHolder, PrimitiveType.Float, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_f", float.class),
+ valueHolder, PrimitiveType.Float, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_f == f);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_f", float.class),
+ valueHolder, PrimitiveType.Float, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_f", float.class),
+ valueHolder, PrimitiveType.Float, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_f == f);
+ }
+ }
+
+ public void testDoubleSettersAndGetters() throws Throwable {
+ ValueHolder valueHolder = new ValueHolder();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ double[] doubles = {0.44444444444e37, -0.555555555e-37};
+ for (double d : doubles) {
+ Double boxed = new Double(d);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_d", double.class),
+ valueHolder, PrimitiveType.Double, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_d", double.class),
+ valueHolder, PrimitiveType.Double, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_d == d);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_d", double.class),
+ valueHolder, PrimitiveType.Double, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_d", double.class),
+ valueHolder, PrimitiveType.Double, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_d == d);
+ }
+ }
+
+ public void testLongSettersAndGetters() throws Throwable {
+ ValueHolder valueHolder = new ValueHolder();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ long[] longs = {0x0123456789abcdefl, 0xfedcba9876543210l};
+ for (long j : longs) {
+ Long boxed = new Long(j);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_j", long.class),
+ valueHolder, PrimitiveType.Long, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_j", long.class),
+ valueHolder, PrimitiveType.Long, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_j == j);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_j", long.class),
+ valueHolder, PrimitiveType.Long, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_j", long.class),
+ valueHolder, PrimitiveType.Long, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_j == j);
+ }
+ }
+
+ public void testStringSettersAndGetters() throws Throwable {
+ ValueHolder valueHolder = new ValueHolder();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ String [] strings = { "octopus", "crab" };
+ for (String s : strings) {
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_l", String.class),
+ valueHolder, PrimitiveType.String, s, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_l", String.class),
+ valueHolder, PrimitiveType.String, s, AccessorType.IGET);
+ assertTrue(s.equals(valueHolder.m_l));
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_l", String.class),
+ valueHolder, PrimitiveType.String, s, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_l", String.class),
+ valueHolder, PrimitiveType.String, s, AccessorType.SGET);
+ assertTrue(s.equals(ValueHolder.s_l));
+ }
+ }
+
+ public void testLookup() throws Throwable {
+ // NB having a static field test here is essential for
+ // this test. MethodHandles need to ensure the class
+ // (ValueHolder) is initialized. This happens in the
+ // invoke-polymorphic dispatch.
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ try {
+ MethodHandle mh = lookup.findStaticGetter(ValueHolder.class, "s_fi", int.class);
+ int initialValue = (int)mh.invokeExact();
+ System.out.println(initialValue);
+ } catch (NoSuchFieldException e) { fail(); }
+ try {
+ MethodHandle mh = lookup.findStaticSetter(ValueHolder.class, "s_i", int.class);
+ mh.invokeExact(0);
+ } catch (NoSuchFieldException e) { fail(); }
+ try {
+ lookup.findStaticGetter(ValueHolder.class, "s_fi", byte.class);
+ fail();
+ } catch (NoSuchFieldException e) {}
+ try {
+ lookup.findGetter(ValueHolder.class, "s_fi", byte.class);
+ fail();
+ } catch (NoSuchFieldException e) {}
+ try {
+ lookup.findStaticSetter(ValueHolder.class, "s_fi", int.class);
+ fail();
+ } catch (IllegalAccessException e) {}
+
+ lookup.findGetter(ValueHolder.class, "m_fi", int.class);
+ try {
+ lookup.findGetter(ValueHolder.class, "m_fi", byte.class);
+ fail();
+ } catch (NoSuchFieldException e) {}
+ try {
+ lookup.findStaticGetter(ValueHolder.class, "m_fi", byte.class);
+ fail();
+ } catch (NoSuchFieldException e) {}
+ try {
+ lookup.findSetter(ValueHolder.class, "m_fi", int.class);
+ fail();
+ } catch (IllegalAccessException e) {}
+ }
+
+ public void testStaticGetter() throws Throwable {
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ MethodHandle h0 = lookup.findStaticGetter(ValueHolder.class, "s_fi", int.class);
+ h0.invoke();
+ Number t = (Number)h0.invoke();
+ int u = (int)h0.invoke();
+ Integer v = (Integer)h0.invoke();
+ long w = (long)h0.invoke();
+ try {
+ byte x = (byte)h0.invoke();
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ try {
+ String y = (String)h0.invoke();
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ try {
+ Long z = (Long)h0.invoke();
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ }
+
+ public void testMemberGetter() throws Throwable {
+ ValueHolder valueHolder = new ValueHolder();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ MethodHandle h0 = lookup.findGetter(ValueHolder.class, "m_fi", int.class);
+ h0.invoke(valueHolder);
+ Number t = (Number)h0.invoke(valueHolder);
+ int u = (int)h0.invoke(valueHolder);
+ Integer v = (Integer)h0.invoke(valueHolder);
+ long w = (long)h0.invoke(valueHolder);
+ try {
+ byte x = (byte)h0.invoke(valueHolder);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ try {
+ String y = (String)h0.invoke(valueHolder);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ try {
+ Long z = (Long)h0.invoke(valueHolder);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ }
+
+ /*package*/ static Number getDoubleAsNumber() {
+ return new Double(1.4e77);
+ }
+ /*package*/ static Number getFloatAsNumber() {
+ return new Float(7.77);
+ }
+ /*package*/ static Object getFloatAsObject() {
+ return new Float(-7.77);
+ }
+
+ public void testMemberSetter() throws Throwable {
+ ValueHolder valueHolder = new ValueHolder();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ MethodHandle h0 = lookup.findSetter(ValueHolder.class, "m_f", float.class);
+ h0.invoke(valueHolder, 0.22f);
+ h0.invoke(valueHolder, new Float(1.11f));
+ Number floatNumber = getFloatAsNumber();
+ h0.invoke(valueHolder, floatNumber);
+ assertTrue(valueHolder.m_f == floatNumber.floatValue());
+ Object objNumber = getFloatAsObject();
+ h0.invoke(valueHolder, objNumber);
+ assertTrue(valueHolder.m_f == ((Float) objNumber).floatValue());
+ try {
+ h0.invoke(valueHolder, (Float)null);
+ fail();
+ } catch (NullPointerException e) {}
+
+ h0.invoke(valueHolder, (byte)1);
+ h0.invoke(valueHolder, (short)2);
+ h0.invoke(valueHolder, 3);
+ h0.invoke(valueHolder, 4l);
+
+ assertTrue(null == (Object) h0.invoke(valueHolder, 33));
+ assertTrue(0.0f == (float) h0.invoke(valueHolder, 33));
+ assertTrue(0l == (long) h0.invoke(valueHolder, 33));
+
+ try {
+ h0.invoke(valueHolder, 0.33);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ try {
+ Number doubleNumber = getDoubleAsNumber();
+ h0.invoke(valueHolder, doubleNumber);
+ fail();
+ } catch (ClassCastException e) {}
+ try {
+ Number doubleNumber = null;
+ h0.invoke(valueHolder, doubleNumber);
+ fail();
+ } catch (NullPointerException e) {}
+ try {
+ // Mismatched return type - float != void
+ float tmp = (float)h0.invoke(valueHolder, 0.45f);
+ assertTrue(tmp == 0.0);
+ } catch (Exception e) { fail(); }
+ try {
+ h0.invoke(valueHolder, "bam");
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ try {
+ String s = null;
+ h0.invoke(valueHolder, s);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ }
+
+ public void testStaticSetter() throws Throwable {
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ MethodHandle h0 = lookup.findStaticSetter(ValueHolder.class, "s_f", float.class);
+ h0.invoke(0.22f);
+ h0.invoke(new Float(1.11f));
+ Number floatNumber = new Float(0.88f);
+ h0.invoke(floatNumber);
+ assertTrue(ValueHolder.s_f == floatNumber.floatValue());
+
+ try {
+ h0.invoke((Float)null);
+ fail();
+ } catch (NullPointerException e) {}
+
+ h0.invoke((byte)1);
+ h0.invoke((short)2);
+ h0.invoke(3);
+ h0.invoke(4l);
+
+ assertTrue(null == (Object) h0.invoke(33));
+ assertTrue(0.0f == (float) h0.invoke(33));
+ assertTrue(0l == (long) h0.invoke(33));
+
+ try {
+ h0.invoke(0.33);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ try {
+ Number doubleNumber = getDoubleAsNumber();
+ h0.invoke(doubleNumber);
+ fail();
+ } catch (ClassCastException e) {}
+ try {
+ Number doubleNumber = new Double(1.01);
+ doubleNumber = (doubleNumber.doubleValue() != 0.1) ? null : doubleNumber;
+ h0.invoke(doubleNumber);
+ fail();
+ } catch (NullPointerException e) {}
+ try {
+ // Mismatched return type - float != void
+ float tmp = (float)h0.invoke(0.45f);
+ assertTrue(tmp == 0.0);
+ } catch (Exception e) { fail(); }
+ try {
+ h0.invoke("bam");
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ try {
+ String s = null;
+ h0.invoke(s);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
new file mode 100644
index 0000000..4c65161
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
@@ -0,0 +1,1636 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.lang.invoke;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.WrongMethodTypeException;
+import java.util.ArrayList;
+
+import junit.framework.TestCase;
+
+public class MethodHandleCombinersTest extends TestCase {
+
+ public static void testThrowException() throws Throwable {
+ MethodHandle handle = MethodHandles.throwException(String.class,
+ IllegalArgumentException.class);
+
+ if (handle.type().returnType() != String.class) {
+ fail("Unexpected return type for handle: " + handle +
+ " [ " + handle.type() + "]");
+ }
+
+ final IllegalArgumentException iae = new IllegalArgumentException("boo!");
+ try {
+ handle.invoke(iae);
+ fail("Expected an exception of type: java.lang.IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ if (expected != iae) {
+ fail("Wrong exception: expected " + iae + " but was " + expected);
+ }
+ }
+ }
+
+ public static void dropArguments_delegate(String message, long message2) {
+ assertEquals("foo", message);
+ assertEquals(42l, message2);
+ }
+
+ public static void testDropArguments() throws Throwable {
+ MethodHandle delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+ "dropArguments_delegate",
+ MethodType.methodType(void.class, new Class<?>[]{String.class, long.class}));
+
+ MethodHandle transform = MethodHandles.dropArguments(
+ delegate, 0, int.class, Object.class);
+
+ // The transformer will accept two additional arguments at position zero.
+ try {
+ transform.invokeExact("foo", 42l);
+ fail();
+ } catch (WrongMethodTypeException expected) {
+ }
+
+ transform.invokeExact(45, new Object(), "foo", 42l);
+ transform.invoke(45, new Object(), "foo", 42l);
+
+ // Additional arguments at position 1.
+ transform = MethodHandles.dropArguments(delegate, 1, int.class, Object.class);
+ transform.invokeExact("foo", 45, new Object(), 42l);
+ transform.invoke("foo", 45, new Object(), 42l);
+
+ // Additional arguments at position 2.
+ transform = MethodHandles.dropArguments(delegate, 2, int.class, Object.class);
+ transform.invokeExact("foo", 42l, 45, new Object());
+ transform.invoke("foo", 42l, 45, new Object());
+
+ // Note that we still perform argument conversions even for the arguments that
+ // are subsequently dropped.
+ try {
+ transform.invoke("foo", 42l, 45l, new Object());
+ fail();
+ } catch (WrongMethodTypeException expected) {
+ } catch (IllegalArgumentException expected) {
+ // TODO(narayan): We currently throw the wrong type of exception here,
+ // it's IAE and should be WMTE instead.
+ }
+
+ // Check that asType works as expected.
+ transform = MethodHandles.dropArguments(delegate, 0, int.class, Object.class);
+ transform = transform.asType(MethodType.methodType(void.class,
+ new Class<?>[]{short.class, Object.class, String.class, long.class}));
+ transform.invokeExact((short) 45, new Object(), "foo", 42l);
+
+ // Invalid argument location, should not be allowed.
+ try {
+ MethodHandles.dropArguments(delegate, -1, int.class, Object.class);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // Invalid argument location, should not be allowed.
+ try {
+ MethodHandles.dropArguments(delegate, 3, int.class, Object.class);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ MethodHandles.dropArguments(delegate, 1, void.class);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public static String testCatchException_target(String arg1, long arg2, String exceptionMessage)
+ throws Throwable {
+ if (exceptionMessage != null) {
+ throw new IllegalArgumentException(exceptionMessage);
+ }
+
+ assertEquals(null, exceptionMessage);
+ assertEquals(42l, arg2);
+ return "target";
+ }
+
+ public static String testCatchException_handler(IllegalArgumentException iae, String arg1,
+ long arg2,
+ String exMsg) {
+ // Check that the thrown exception has the right message.
+ assertEquals("exceptionMessage", iae.getMessage());
+ // Check the other arguments.
+ assertEquals("foo", arg1);
+ assertEquals(42, arg2);
+ assertEquals("exceptionMessage", exMsg);
+
+ return "handler1";
+ }
+
+ public static String testCatchException_handler2(IllegalArgumentException iae, String arg1) {
+ assertEquals("exceptionMessage", iae.getMessage());
+ assertEquals("foo", arg1);
+
+ return "handler2";
+ }
+
+ public static void testCatchException() throws Throwable {
+ MethodHandle target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+ "testCatchException_target",
+ MethodType
+ .methodType(String.class, new Class<?>[]{String.class, long.class, String.class}));
+
+ MethodHandle handler = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+ "testCatchException_handler",
+ MethodType.methodType(String.class, new Class<?>[]{IllegalArgumentException.class,
+ String.class, long.class, String.class}));
+
+ MethodHandle adapter = MethodHandles.catchException(target, IllegalArgumentException.class,
+ handler);
+
+ String returnVal = null;
+
+ // These two should end up calling the target always. We're passing a null exception
+ // message here, which means the target will not throw.
+ returnVal = (String) adapter.invoke("foo", 42, null);
+ assertEquals("target", returnVal);
+ returnVal = (String) adapter.invokeExact("foo", 42l, (String) null);
+ assertEquals("target", returnVal);
+
+ // We're passing a non-null exception message here, which means the target will throw,
+ // which in turn means that the handler must be called for the next two invokes.
+ returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
+ assertEquals("handler1", returnVal);
+ returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
+ assertEquals("handler1", returnVal);
+
+ handler = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+ "testCatchException_handler2",
+ MethodType.methodType(String.class, new Class<?>[]{IllegalArgumentException.class,
+ String.class}));
+ adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler);
+
+ returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
+ assertEquals("handler2", returnVal);
+ returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
+ assertEquals("handler2", returnVal);
+
+ // Test that the type of the invoke doesn't matter. Here we call
+ // IllegalArgumentException.toString() on the exception that was thrown by
+ // the target.
+ handler = MethodHandles.lookup().findVirtual(IllegalArgumentException.class,
+ "toString", MethodType.methodType(String.class));
+ adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler);
+
+ returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage");
+ assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
+ returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage");
+ assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
+
+ // Check that asType works as expected.
+ adapter = MethodHandles.catchException(target, IllegalArgumentException.class,
+ handler);
+ adapter = adapter.asType(MethodType.methodType(String.class,
+ new Class<?>[]{String.class, int.class, String.class}));
+ returnVal = (String) adapter.invokeExact("foo", 42, "exceptionMessage");
+ assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal);
+ }
+
+ public static boolean testGuardWithTest_test(String arg1, long arg2) {
+ return "target".equals(arg1) && 42 == arg2;
+ }
+
+ public static String testGuardWithTest_target(String arg1, long arg2, int arg3) {
+ // Make sure that the test passed.
+ assertTrue(testGuardWithTest_test(arg1, arg2));
+ // Make sure remaining arguments were passed through unmodified.
+ assertEquals(56, arg3);
+
+ return "target";
+ }
+
+ public static String testGuardWithTest_fallback(String arg1, long arg2, int arg3) {
+ // Make sure that the test failed.
+ assertTrue(!testGuardWithTest_test(arg1, arg2));
+ // Make sure remaining arguments were passed through unmodified.
+ assertEquals(56, arg3);
+
+ return "fallback";
+ }
+
+ public static void testGuardWithTest() throws Throwable {
+ MethodHandle test = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+ "testGuardWithTest_test",
+ MethodType.methodType(boolean.class, new Class<?>[]{String.class, long.class}));
+
+ final MethodType type = MethodType.methodType(String.class,
+ new Class<?>[]{String.class, long.class, int.class});
+
+ final MethodHandle target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+ "testGuardWithTest_target", type);
+ final MethodHandle fallback = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+ "testGuardWithTest_fallback", type);
+
+ MethodHandle adapter = MethodHandles.guardWithTest(test, target, fallback);
+
+ String returnVal = null;
+
+ returnVal = (String) adapter.invoke("target", 42, 56);
+ assertEquals("target", returnVal);
+ returnVal = (String) adapter.invokeExact("target", 42l, 56);
+ assertEquals("target", returnVal);
+
+ returnVal = (String) adapter.invoke("fallback", 42l, 56);
+ assertEquals("fallback", returnVal);
+ returnVal = (String) adapter.invoke("target", 46l, 56);
+ assertEquals("fallback", returnVal);
+ returnVal = (String) adapter.invokeExact("target", 42l, 56);
+ assertEquals("target", returnVal);
+
+ // Check that asType works as expected.
+ adapter = adapter.asType(MethodType.methodType(String.class,
+ new Class<?>[]{String.class, int.class, int.class}));
+ returnVal = (String) adapter.invokeExact("target", 42, 56);
+ assertEquals("target", returnVal);
+ }
+
+ public static void testArrayElementGetter() throws Throwable {
+ MethodHandle getter = MethodHandles.arrayElementGetter(int[].class);
+
+ {
+ int[] array = new int[1];
+ array[0] = 42;
+ int value = (int) getter.invoke(array, 0);
+ assertEquals(42, value);
+
+ try {
+ value = (int) getter.invoke(array, -1);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ }
+
+ try {
+ value = (int) getter.invoke(null, -1);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ {
+ getter = MethodHandles.arrayElementGetter(long[].class);
+ long[] array = new long[1];
+ array[0] = 42;
+ long value = (long) getter.invoke(array, 0);
+ assertEquals(42l, value);
+ }
+
+ {
+ getter = MethodHandles.arrayElementGetter(short[].class);
+ short[] array = new short[1];
+ array[0] = 42;
+ short value = (short) getter.invoke(array, 0);
+ assertEquals((short) 42, value);
+ }
+
+ {
+ getter = MethodHandles.arrayElementGetter(char[].class);
+ char[] array = new char[1];
+ array[0] = 42;
+ char value = (char) getter.invoke(array, 0);
+ assertEquals((char) 42, value);
+ }
+
+ {
+ getter = MethodHandles.arrayElementGetter(byte[].class);
+ byte[] array = new byte[1];
+ array[0] = (byte) 0x8;
+ byte value = (byte) getter.invoke(array, 0);
+ assertEquals((byte) 0x8, value);
+ }
+
+ {
+ getter = MethodHandles.arrayElementGetter(boolean[].class);
+ boolean[] array = new boolean[1];
+ array[0] = true;
+ boolean value = (boolean) getter.invoke(array, 0);
+ assertTrue(value);
+ }
+
+ {
+ getter = MethodHandles.arrayElementGetter(float[].class);
+ float[] array = new float[1];
+ array[0] = 42.0f;
+ float value = (float) getter.invoke(array, 0);
+ assertEquals(42.0f, value);
+ }
+
+ {
+ getter = MethodHandles.arrayElementGetter(double[].class);
+ double[] array = new double[1];
+ array[0] = 42.0;
+ double value = (double) getter.invoke(array, 0);
+ assertEquals(42.0, value);
+ }
+
+ {
+ getter = MethodHandles.arrayElementGetter(String[].class);
+ String[] array = new String[3];
+ array[0] = "42";
+ array[1] = "48";
+ array[2] = "54";
+ String value = (String) getter.invoke(array, 0);
+ assertEquals("42", value);
+ value = (String) getter.invoke(array, 1);
+ assertEquals("48", value);
+ value = (String) getter.invoke(array, 2);
+ assertEquals("54", value);
+ }
+ }
+
+ public static void testArrayElementSetter() throws Throwable {
+ MethodHandle setter = MethodHandles.arrayElementSetter(int[].class);
+
+ {
+ int[] array = new int[2];
+ setter.invoke(array, 0, 42);
+ setter.invoke(array, 1, 43);
+
+ assertEquals(42, array[0]);
+ assertEquals(43, array[1]);
+
+ try {
+ setter.invoke(array, -1, 42);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ }
+
+ try {
+ setter.invoke(null, 0, 42);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ {
+ setter = MethodHandles.arrayElementSetter(long[].class);
+ long[] array = new long[1];
+ setter.invoke(array, 0, 42l);
+ assertEquals(42l, array[0]);
+ }
+
+ {
+ setter = MethodHandles.arrayElementSetter(short[].class);
+ short[] array = new short[1];
+ setter.invoke(array, 0, (short) 42);
+ assertEquals((short) 42, array[0]);
+ }
+
+ {
+ setter = MethodHandles.arrayElementSetter(char[].class);
+ char[] array = new char[1];
+ setter.invoke(array, 0, (char) 42);
+ assertEquals((char) 42, array[0]);
+ }
+
+ {
+ setter = MethodHandles.arrayElementSetter(byte[].class);
+ byte[] array = new byte[1];
+ setter.invoke(array, 0, (byte) 0x8);
+ assertEquals((byte) 0x8, array[0]);
+ }
+
+ {
+ setter = MethodHandles.arrayElementSetter(boolean[].class);
+ boolean[] array = new boolean[1];
+ setter.invoke(array, 0, true);
+ assertTrue(array[0]);
+ }
+
+ {
+ setter = MethodHandles.arrayElementSetter(float[].class);
+ float[] array = new float[1];
+ setter.invoke(array, 0, 42.0f);
+ assertEquals(42.0f, array[0]);
+ }
+
+ {
+ setter = MethodHandles.arrayElementSetter(double[].class);
+ double[] array = new double[1];
+ setter.invoke(array, 0, 42.0);
+ assertEquals(42.0, array[0]);
+ }
+
+ {
+ setter = MethodHandles.arrayElementSetter(String[].class);
+ String[] array = new String[3];
+ setter.invoke(array, 0, "42");
+ setter.invoke(array, 1, "48");
+ setter.invoke(array, 2, "54");
+ assertEquals("42", array[0]);
+ assertEquals("48", array[1]);
+ assertEquals("54", array[2]);
+ }
+ }
+
+ public static void testIdentity() throws Throwable {
+ {
+ MethodHandle identity = MethodHandles.identity(boolean.class);
+ boolean value = (boolean) identity.invoke(false);
+ assertFalse(value);
+ }
+
+ {
+ MethodHandle identity = MethodHandles.identity(byte.class);
+ byte value = (byte) identity.invoke((byte) 0x8);
+ assertEquals((byte) 0x8, value);
+ }
+
+ {
+ MethodHandle identity = MethodHandles.identity(char.class);
+ char value = (char) identity.invoke((char) -56);
+ assertEquals((char) -56, value);
+ }
+
+ {
+ MethodHandle identity = MethodHandles.identity(short.class);
+ short value = (short) identity.invoke((short) -59);
+ assertEquals((short) -59, value);
+ }
+
+ {
+ MethodHandle identity = MethodHandles.identity(int.class);
+ int value = (int) identity.invoke(52);
+ assertEquals((int) 52, value);
+ }
+
+ {
+ MethodHandle identity = MethodHandles.identity(long.class);
+ long value = (long) identity.invoke(-76l);
+ assertEquals(-76l, value);
+ }
+
+ {
+ MethodHandle identity = MethodHandles.identity(float.class);
+ float value = (float) identity.invoke(56.0f);
+ assertEquals(56.0f, value);
+ }
+
+ {
+ MethodHandle identity = MethodHandles.identity(double.class);
+ double value = (double) identity.invoke((double) 72.0);
+ assertEquals(72.0, value);
+ }
+
+ {
+ MethodHandle identity = MethodHandles.identity(String.class);
+ String value = (String) identity.invoke("bazman");
+ assertEquals("bazman", value);
+ }
+ }
+
+ public static void testConstant() throws Throwable {
+ // int constants.
+ {
+ MethodHandle constant = MethodHandles.constant(int.class, 56);
+ assertEquals(56, (int) constant.invoke());
+
+ // short constant values are converted to int.
+ constant = MethodHandles.constant(int.class, (short) 52);
+ assertEquals(52, (int) constant.invoke());
+
+ // char constant values are converted to int.
+ constant = MethodHandles.constant(int.class, (char) 'b');
+ assertEquals('b', (int) constant.invoke());
+
+ // int constant values are converted to int.
+ constant = MethodHandles.constant(int.class, (byte) 0x1);
+ assertEquals(0x1, (int) constant.invoke());
+
+ // boolean, float, double and long primitive constants are not convertible
+ // to int, so the handle creation must fail with a CCE.
+ try {
+ MethodHandles.constant(int.class, false);
+ fail();
+ } catch (ClassCastException expected) {
+ }
+
+ try {
+ MethodHandles.constant(int.class, 0.1f);
+ fail();
+ } catch (ClassCastException expected) {
+ }
+
+ try {
+ MethodHandles.constant(int.class, 0.2);
+ fail();
+ } catch (ClassCastException expected) {
+ }
+
+ try {
+ MethodHandles.constant(int.class, 73l);
+ fail();
+ } catch (ClassCastException expected) {
+ }
+ }
+
+ // long constants.
+ {
+ MethodHandle constant = MethodHandles.constant(long.class, 56l);
+ assertEquals(56l, (long) constant.invoke());
+
+ constant = MethodHandles.constant(long.class, (int) 56);
+ assertEquals(56l, (long) constant.invoke());
+ }
+
+ // byte constants.
+ {
+ MethodHandle constant = MethodHandles.constant(byte.class, (byte) 0x12);
+ assertEquals((byte) 0x12, (byte) constant.invoke());
+ }
+
+ // boolean constants.
+ {
+ MethodHandle constant = MethodHandles.constant(boolean.class, true);
+ assertTrue((boolean) constant.invoke());
+ }
+
+ // char constants.
+ {
+ MethodHandle constant = MethodHandles.constant(char.class, 'f');
+ assertEquals('f', (char) constant.invoke());
+ }
+
+ // short constants.
+ {
+ MethodHandle constant = MethodHandles.constant(short.class, (short) 123);
+ assertEquals((short) 123, (short) constant.invoke());
+ }
+
+ // float constants.
+ {
+ MethodHandle constant = MethodHandles.constant(float.class, 56.0f);
+ assertEquals(56.0f, (float) constant.invoke());
+ }
+
+ // double constants.
+ {
+ MethodHandle constant = MethodHandles.constant(double.class, 256.0);
+ assertEquals(256.0, (double) constant.invoke());
+ }
+
+ // reference constants.
+ {
+ MethodHandle constant = MethodHandles.constant(String.class, "256.0");
+ assertEquals("256.0", (String) constant.invoke());
+ }
+ }
+
+ public static void testBindTo() throws Throwable {
+ MethodHandle stringCharAt = MethodHandles.lookup().findVirtual(
+ String.class, "charAt", MethodType.methodType(char.class, int.class));
+
+ char value = (char) stringCharAt.invoke("foo", 0);
+ if (value != 'f') {
+ fail("Unexpected value: " + value);
+ }
+
+ MethodHandle bound = stringCharAt.bindTo("foo");
+ value = (char) bound.invoke(0);
+ if (value != 'f') {
+ fail("Unexpected value: " + value);
+ }
+
+ try {
+ stringCharAt.bindTo(new Object());
+ fail();
+ } catch (ClassCastException expected) {
+ }
+
+ bound = stringCharAt.bindTo(null);
+ try {
+ bound.invoke(0);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ MethodHandle integerParseInt = MethodHandles.lookup().findStatic(
+ Integer.class, "parseInt", MethodType.methodType(int.class, String.class));
+
+ bound = integerParseInt.bindTo("78452");
+ int intValue = (int) bound.invoke();
+ if (intValue != 78452) {
+ fail("Unexpected value: " + intValue);
+ }
+ }
+
+ public static String filterReturnValue_target(int a) {
+ return "ReturnValue" + a;
+ }
+
+ public static boolean filterReturnValue_filter(String value) {
+ return value.indexOf("42") != -1;
+ }
+
+ public static int filterReturnValue_intTarget(String a) {
+ return Integer.parseInt(a);
+ }
+
+ public static int filterReturnValue_intFilter(int b) {
+ return b + 1;
+ }
+
+ public static void filterReturnValue_voidTarget() {
+ }
+
+ public static int filterReturnValue_voidFilter() {
+ return 42;
+ }
+
+ public static void testFilterReturnValue() throws Throwable {
+ // A target that returns a reference.
+ {
+ final MethodHandle target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+ "filterReturnValue_target", MethodType.methodType(String.class, int.class));
+ final MethodHandle filter = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+ "filterReturnValue_filter", MethodType.methodType(boolean.class, String.class));
+
+ MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
+
+ boolean value = (boolean) adapter.invoke((int) 42);
+ if (!value) {
+ fail("Unexpected value: " + value);
+ }
+ value = (boolean) adapter.invoke((int) 43);
+ if (value) {
+ fail("Unexpected value: " + value);
+ }
+ }
+
+ // A target that returns a primitive.
+ {
+ final MethodHandle target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+ "filterReturnValue_intTarget", MethodType.methodType(int.class, String.class));
+ final MethodHandle filter = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+ "filterReturnValue_intFilter", MethodType.methodType(int.class, int.class));
+
+ MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
+
+ int value = (int) adapter.invoke("56");
+ if (value != 57) {
+ fail("Unexpected value: " + value);
+ }
+ }
+
+ // A target that returns void.
+ {
+ final MethodHandle target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+ "filterReturnValue_voidTarget", MethodType.methodType(void.class));
+ final MethodHandle filter = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+ "filterReturnValue_voidFilter", MethodType.methodType(int.class));
+
+ MethodHandle adapter = MethodHandles.filterReturnValue(target, filter);
+
+ int value = (int) adapter.invoke();
+ if (value != 42) {
+ fail("Unexpected value: " + value);
+ }
+ }
+ }
+
+ public static void permuteArguments_callee(boolean a, byte b, char c,
+ short d, int e, long f, float g, double h) {
+ assertTrue(a);
+ assertEquals((byte) 'b', b);
+ assertEquals('c', c);
+ assertEquals((short) 56, d);
+ assertEquals(78, e);
+ assertEquals(97l, f);
+ assertEquals(98.0f, g);
+ assertEquals(97.0, h);
+ }
+
+ public static void permuteArguments_boxingCallee(boolean a, Integer b) {
+ assertTrue(a);
+ assertEquals(Integer.valueOf(42), b);
+ }
+
+ public static void testPermuteArguments() throws Throwable {
+ {
+ final MethodHandle target = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "permuteArguments_callee",
+ MethodType.methodType(void.class, new Class<?>[]{
+ boolean.class, byte.class, char.class, short.class, int.class,
+ long.class, float.class, double.class}));
+
+ final MethodType newType = MethodType.methodType(void.class, new Class<?>[]{
+ double.class, float.class, long.class, int.class, short.class, char.class,
+ byte.class, boolean.class});
+
+ final MethodHandle permutation = MethodHandles.permuteArguments(
+ target, newType, new int[]{7, 6, 5, 4, 3, 2, 1, 0});
+
+ permutation.invoke((double) 97.0, (float) 98.0f, (long) 97, 78,
+ (short) 56, 'c', (byte) 'b', (boolean) true);
+
+ // The permutation array was not of the right length.
+ try {
+ MethodHandles.permuteArguments(target, newType,
+ new int[]{7});
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // The permutation array has an element that's out of bounds
+ // (there's no argument with idx == 8).
+ try {
+ MethodHandles.permuteArguments(target, newType,
+ new int[]{8, 6, 5, 4, 3, 2, 1, 0});
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // The permutation array maps to an incorrect type.
+ try {
+ MethodHandles.permuteArguments(target, newType,
+ new int[]{7, 7, 5, 4, 3, 2, 1, 0});
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ // Tests for reference arguments as well as permutations that
+ // repeat arguments.
+ {
+ final MethodHandle target = MethodHandles.lookup().findVirtual(
+ String.class, "concat", MethodType.methodType(String.class, String.class));
+
+ final MethodType newType = MethodType.methodType(String.class, String.class,
+ String.class);
+
+ assertEquals("foobar", (String) target.invoke("foo", "bar"));
+
+ MethodHandle permutation = MethodHandles.permuteArguments(target,
+ newType, new int[]{1, 0});
+ assertEquals("barfoo", (String) permutation.invoke("foo", "bar"));
+
+ permutation = MethodHandles.permuteArguments(target, newType, new int[]{0, 0});
+ assertEquals("foofoo", (String) permutation.invoke("foo", "bar"));
+
+ permutation = MethodHandles.permuteArguments(target, newType, new int[]{1, 1});
+ assertEquals("barbar", (String) permutation.invoke("foo", "bar"));
+ }
+
+ // Tests for boxing and unboxing.
+ {
+ final MethodHandle target = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "permuteArguments_boxingCallee",
+ MethodType.methodType(void.class, new Class<?>[]{boolean.class, Integer.class}));
+
+ final MethodType newType = MethodType.methodType(void.class,
+ new Class<?>[]{Integer.class, boolean.class});
+
+ MethodHandle permutation = MethodHandles.permuteArguments(target,
+ newType, new int[]{1, 0});
+
+ permutation.invoke(42, true);
+ permutation.invoke(42, Boolean.TRUE);
+ permutation.invoke(Integer.valueOf(42), true);
+ permutation.invoke(Integer.valueOf(42), Boolean.TRUE);
+ }
+ }
+
+ private static Object returnBar() {
+ return "bar";
+ }
+
+ public static void testInvokers() throws Throwable {
+ final MethodType targetType = MethodType.methodType(String.class, String.class);
+ final MethodHandle target = MethodHandles.lookup().findVirtual(
+ String.class, "concat", targetType);
+
+ MethodHandle invoker = MethodHandles.invoker(target.type());
+ assertEquals("barbar", (String) invoker.invoke(target, "bar", "bar"));
+ assertEquals("barbar", (String) invoker.invoke(target, (Object) returnBar(), "bar"));
+ try {
+ String foo = (String) invoker.invoke(target, "bar", "bar", 24);
+ fail();
+ } catch (WrongMethodTypeException expected) {
+ }
+
+ MethodHandle exactInvoker = MethodHandles.exactInvoker(target.type());
+ assertEquals("barbar", (String) exactInvoker.invoke(target, "bar", "bar"));
+ try {
+ String foo = (String) exactInvoker.invoke(target, (Object) returnBar(), "bar");
+ fail();
+ } catch (WrongMethodTypeException expected) {
+ }
+ try {
+ String foo = (String) exactInvoker.invoke(target, "bar", "bar", 24);
+ fail();
+ } catch (WrongMethodTypeException expected) {
+ }
+ }
+
+ public static int spreadReferences(String a, String b, String c) {
+ assertEquals("a", a);
+ assertEquals("b", b);
+ assertEquals("c", c);
+ return 42;
+ }
+
+ public static int spreadReferences_Unbox(String a, int b) {
+ assertEquals("a", a);
+ assertEquals(43, b);
+ return 43;
+ }
+
+ public static void testSpreaders_reference() throws Throwable {
+ MethodType methodType = MethodType.methodType(int.class,
+ new Class<?>[]{String.class, String.class, String.class});
+ MethodHandle delegate = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "spreadReferences", methodType);
+
+ // Basic checks on array lengths.
+ //
+ // Array size = 0
+ MethodHandle mhAsSpreader = delegate.asSpreader(String[].class, 0);
+ int ret = (int) mhAsSpreader.invoke("a", "b", "c", new String[]{});
+ assertEquals(42, ret);
+ // Array size = 1
+ mhAsSpreader = delegate.asSpreader(String[].class, 1);
+ ret = (int) mhAsSpreader.invoke("a", "b", new String[]{"c"});
+ assertEquals(42, ret);
+ // Array size = 2
+ mhAsSpreader = delegate.asSpreader(String[].class, 2);
+ ret = (int) mhAsSpreader.invoke("a", new String[]{"b", "c"});
+ assertEquals(42, ret);
+ // Array size = 3
+ mhAsSpreader = delegate.asSpreader(String[].class, 3);
+ ret = (int) mhAsSpreader.invoke(new String[]{"a", "b", "c"});
+ assertEquals(42, ret);
+
+ // Exception case, array size = 4 is illegal.
+ try {
+ delegate.asSpreader(String[].class, 4);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // Exception case, calling with an arg of the wrong size.
+ // Array size = 3
+ mhAsSpreader = delegate.asSpreader(String[].class, 3);
+ try {
+ ret = (int) mhAsSpreader.invoke(new String[]{"a", "b"});
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // Various other hijinks, pass as Object[] arrays, Object etc.
+ mhAsSpreader = delegate.asSpreader(Object[].class, 2);
+ ret = (int) mhAsSpreader.invoke("a", new String[]{"b", "c"});
+ assertEquals(42, ret);
+
+ mhAsSpreader = delegate.asSpreader(Object[].class, 2);
+ ret = (int) mhAsSpreader.invoke("a", new Object[]{"b", "c"});
+ assertEquals(42, ret);
+
+ mhAsSpreader = delegate.asSpreader(Object[].class, 2);
+ ret = (int) mhAsSpreader.invoke("a", (Object) new Object[]{"b", "c"});
+ assertEquals(42, ret);
+
+ // Test implicit unboxing.
+ MethodType methodType2 = MethodType.methodType(int.class,
+ new Class<?>[]{String.class, int.class});
+ MethodHandle delegate2 = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "spreadReferences_Unbox", methodType2);
+
+ // .. with an Integer[] array.
+ mhAsSpreader = delegate2.asSpreader(Integer[].class, 1);
+ ret = (int) mhAsSpreader.invoke("a", new Integer[]{43});
+ assertEquals(43, ret);
+
+ // .. with an Integer[] array declared as an Object[] argument type.
+ mhAsSpreader = delegate2.asSpreader(Object[].class, 1);
+ ret = (int) mhAsSpreader.invoke("a", new Integer[]{43});
+ assertEquals(43, ret);
+
+ // .. with an Object[] array.
+ mhAsSpreader = delegate2.asSpreader(Object[].class, 1);
+ ret = (int) mhAsSpreader.invoke("a", new Object[]{Integer.valueOf(43)});
+ assertEquals(43, ret);
+
+ // -- Part 2--
+ // Run a subset of these tests on MethodHandles.spreadInvoker, which only accepts
+ // a trailing argument type of Object[].
+ MethodHandle spreadInvoker = MethodHandles.spreadInvoker(methodType2, 1);
+ ret = (int) spreadInvoker.invoke(delegate2, "a", new Object[]{Integer.valueOf(43)});
+ assertEquals(43, ret);
+
+ ret = (int) spreadInvoker.invoke(delegate2, "a", new Integer[]{43});
+ assertEquals(43, ret);
+
+ // NOTE: Annoyingly, the second argument here is leadingArgCount and not
+ // arrayLength.
+ spreadInvoker = MethodHandles.spreadInvoker(methodType, 3);
+ ret = (int) spreadInvoker.invoke(delegate, "a", "b", "c", new String[]{});
+ assertEquals(42, ret);
+
+ spreadInvoker = MethodHandles.spreadInvoker(methodType, 0);
+ ret = (int) spreadInvoker.invoke(delegate, new String[]{"a", "b", "c"});
+ assertEquals(42, ret);
+
+ // Exact invokes: Double check that the expected parameter type is
+ // Object[] and not T[].
+ try {
+ spreadInvoker.invokeExact(delegate, new String[]{"a", "b", "c"});
+ fail();
+ } catch (WrongMethodTypeException expected) {
+ }
+
+ ret = (int) spreadInvoker.invoke(delegate, new Object[]{"a", "b", "c"});
+ assertEquals(42, ret);
+ }
+
+ public static int spreadBoolean(String a, Boolean b, boolean c) {
+ assertEquals("a", a);
+ assertSame(Boolean.TRUE, b);
+ assertFalse(c);
+
+ return 44;
+ }
+
+ public static int spreadByte(String a, Byte b, byte c,
+ short d, int e, long f, float g, double h) {
+ assertEquals("a", a);
+ assertEquals(Byte.valueOf((byte) 1), b);
+ assertEquals((byte) 2, c);
+ assertEquals((short) 3, d);
+ assertEquals(4, e);
+ assertEquals(5l, f);
+ assertEquals(6.0f, g);
+ assertEquals(7.0, h);
+
+ return 45;
+ }
+
+ public static int spreadChar(String a, Character b, char c,
+ int d, long e, float f, double g) {
+ assertEquals("a", a);
+ assertEquals(Character.valueOf('1'), b);
+ assertEquals('2', c);
+ assertEquals((short) '3', d);
+ assertEquals('4', e);
+ assertEquals((float) '5', f);
+ assertEquals((double) '6', g);
+
+ return 46;
+ }
+
+ public static int spreadShort(String a, Short b, short c,
+ int d, long e, float f, double g) {
+ assertEquals("a", a);
+ assertEquals(Short.valueOf((short) 1), b);
+ assertEquals(2, c);
+ assertEquals(3, d);
+ assertEquals(4l, e);
+ assertEquals(5.0f, f);
+ assertEquals(6.0, g);
+
+ return 47;
+ }
+
+ public static int spreadInt(String a, Integer b, int c,
+ long d, float e, double f) {
+ assertEquals("a", a);
+ assertEquals(Integer.valueOf(1), b);
+ assertEquals(2, c);
+ assertEquals(3l, d);
+ assertEquals(4.0f, e);
+ assertEquals(5.0, f);
+
+ return 48;
+ }
+
+ public static int spreadLong(String a, Long b, long c, float d, double e) {
+ assertEquals("a", a);
+ assertEquals(Long.valueOf(1), b);
+ assertEquals(2l, c);
+ assertEquals(3.0f, d);
+ assertEquals(4.0, e);
+
+ return 49;
+ }
+
+ public static int spreadFloat(String a, Float b, float c, double d) {
+ assertEquals("a", a);
+ assertEquals(Float.valueOf(1.0f), b);
+ assertEquals(2.0f, c);
+ assertEquals(3.0, d);
+
+ return 50;
+ }
+
+ public static int spreadDouble(String a, Double b, double c) {
+ assertEquals("a", a);
+ assertEquals(Double.valueOf(1.0), b);
+ assertEquals(2.0, c);
+
+ return 51;
+ }
+
+ public static void testSpreaders_primitive() throws Throwable {
+ // boolean[]
+ // ---------------------
+ MethodType type = MethodType.methodType(int.class,
+ new Class<?>[]{String.class, Boolean.class, boolean.class});
+ MethodHandle delegate = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "spreadBoolean", type);
+
+ MethodHandle spreader = delegate.asSpreader(boolean[].class, 2);
+ int ret = (int) spreader.invokeExact("a", new boolean[]{true, false});
+ assertEquals(44, ret);
+ ret = (int) spreader.invoke("a", new boolean[]{true, false});
+ assertEquals(44, ret);
+
+ // boolean can't be cast to String (the first argument to the method).
+ try {
+ delegate.asSpreader(boolean[].class, 3);
+ fail();
+ } catch (WrongMethodTypeException expected) {
+ }
+
+ // int can't be cast to boolean to supply the last argument to the method.
+ try {
+ delegate.asSpreader(int[].class, 1);
+ fail();
+ } catch (WrongMethodTypeException expected) {
+ }
+
+ // byte[]
+ // ---------------------
+ type = MethodType.methodType(int.class,
+ new Class<?>[]{
+ String.class, Byte.class, byte.class,
+ short.class, int.class, long.class,
+ float.class, double.class});
+ delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "spreadByte", type);
+
+ spreader = delegate.asSpreader(byte[].class, 7);
+ ret = (int) spreader.invokeExact("a",
+ new byte[]{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7});
+ assertEquals(45, ret);
+ ret = (int) spreader.invoke("a",
+ new byte[]{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7});
+ assertEquals(45, ret);
+
+ // char[]
+ // ---------------------
+ type = MethodType.methodType(int.class,
+ new Class<?>[]{
+ String.class, Character.class, char.class,
+ int.class, long.class, float.class, double.class});
+ delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "spreadChar", type);
+
+ spreader = delegate.asSpreader(char[].class, 6);
+ ret = (int) spreader.invokeExact("a",
+ new char[]{'1', '2', '3', '4', '5', '6'});
+ assertEquals(46, ret);
+ ret = (int) spreader.invokeExact("a",
+ new char[]{'1', '2', '3', '4', '5', '6'});
+ assertEquals(46, ret);
+
+ // short[]
+ // ---------------------
+ type = MethodType.methodType(int.class,
+ new Class<?>[]{
+ String.class, Short.class, short.class,
+ int.class, long.class, float.class, double.class});
+ delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "spreadShort", type);
+
+ spreader = delegate.asSpreader(short[].class, 6);
+ ret = (int) spreader.invokeExact("a",
+ new short[]{0x1, 0x2, 0x3, 0x4, 0x5, 0x6});
+ assertEquals(47, ret);
+ ret = (int) spreader.invoke("a",
+ new short[]{0x1, 0x2, 0x3, 0x4, 0x5, 0x6});
+ assertEquals(47, ret);
+
+ // int[]
+ // ---------------------
+ type = MethodType.methodType(int.class,
+ new Class<?>[]{
+ String.class, Integer.class, int.class,
+ long.class, float.class, double.class});
+ delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "spreadInt", type);
+
+ spreader = delegate.asSpreader(int[].class, 5);
+ ret = (int) spreader.invokeExact("a", new int[]{1, 2, 3, 4, 5});
+ assertEquals(48, ret);
+ ret = (int) spreader.invokeExact("a", new int[]{1, 2, 3, 4, 5});
+ assertEquals(48, ret);
+
+ // long[]
+ // ---------------------
+ type = MethodType.methodType(int.class,
+ new Class<?>[]{
+ String.class, Long.class, long.class, float.class, double.class});
+ delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "spreadLong", type);
+
+ spreader = delegate.asSpreader(long[].class, 4);
+ ret = (int) spreader.invokeExact("a",
+ new long[]{0x1, 0x2, 0x3, 0x4});
+ assertEquals(49, ret);
+ ret = (int) spreader.invoke("a",
+ new long[]{0x1, 0x2, 0x3, 0x4});
+ assertEquals(49, ret);
+
+ // float[]
+ // ---------------------
+ type = MethodType.methodType(int.class,
+ new Class<?>[]{
+ String.class, Float.class, float.class, double.class});
+ delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "spreadFloat", type);
+
+ spreader = delegate.asSpreader(float[].class, 3);
+ ret = (int) spreader.invokeExact("a",
+ new float[]{1.0f, 2.0f, 3.0f});
+ assertEquals(50, ret);
+ ret = (int) spreader.invokeExact("a",
+ new float[]{1.0f, 2.0f, 3.0f});
+ assertEquals(50, ret);
+
+ // double[]
+ // ---------------------
+ type = MethodType.methodType(int.class,
+ new Class<?>[]{String.class, Double.class, double.class});
+ delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "spreadDouble", type);
+
+ spreader = delegate.asSpreader(double[].class, 2);
+ ret = (int) spreader.invokeExact("a", new double[]{1.0, 2.0});
+ assertEquals(51, ret);
+ ret = (int) spreader.invokeExact("a", new double[]{1.0, 2.0});
+ assertEquals(51, ret);
+ }
+
+ public static void testInvokeWithArguments() throws Throwable {
+ MethodType methodType = MethodType.methodType(int.class,
+ new Class<?>[]{String.class, String.class, String.class});
+ MethodHandle handle = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "spreadReferences", methodType);
+
+ Object ret = handle.invokeWithArguments(new Object[]{"a", "b", "c"});
+ assertEquals(42, (int) ret);
+ handle.invokeWithArguments(new String[]{"a", "b", "c"});
+ assertEquals(42, (int) ret);
+
+ // Pass in an array that's too small. Should throw an IAE.
+ try {
+ handle.invokeWithArguments(new Object[]{"a", "b"});
+ fail();
+ } catch (IllegalArgumentException expected) {
+ } catch (WrongMethodTypeException expected) {
+ }
+
+ // Test implicit unboxing.
+ MethodType methodType2 = MethodType.methodType(int.class,
+ new Class<?>[]{String.class, int.class});
+ MethodHandle handle2 = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "spreadReferences_Unbox", methodType2);
+
+ ret = (int) handle2.invokeWithArguments(new Object[]{"a", 43});
+ assertEquals(43, (int) ret);
+ }
+
+ public static int collectBoolean(String a, boolean[] b) {
+ assertEquals("a", a);
+ assertTrue(b[0]);
+ assertFalse(b[1]);
+
+ return 44;
+ }
+
+ public static int collectByte(String a, byte[] b) {
+ assertEquals("a", a);
+ assertEquals((byte) 1, b[0]);
+ assertEquals((byte) 2, b[1]);
+ return 45;
+ }
+
+ public static int collectChar(String a, char[] b) {
+ assertEquals("a", a);
+ assertEquals('a', b[0]);
+ assertEquals('b', b[1]);
+ return 46;
+ }
+
+ public static int collectShort(String a, short[] b) {
+ assertEquals("a", a);
+ assertEquals((short) 3, b[0]);
+ assertEquals((short) 4, b[1]);
+
+ return 47;
+ }
+
+ public static int collectInt(String a, int[] b) {
+ assertEquals("a", a);
+ assertEquals(42, b[0]);
+ assertEquals(43, b[1]);
+
+ return 48;
+ }
+
+ public static int collectLong(String a, long[] b) {
+ assertEquals("a", a);
+ assertEquals(100l, b[0]);
+ assertEquals(99l, b[1]);
+
+ return 49;
+ }
+
+ public static int collectFloat(String a, float[] b) {
+ assertEquals("a", a);
+ assertEquals(8.9f, b[0]);
+ assertEquals(9.1f, b[1]);
+
+ return 50;
+ }
+
+ public static int collectDouble(String a, double[] b) {
+ assertEquals("a", a);
+ assertEquals(6.7, b[0]);
+ assertEquals(7.8, b[1]);
+
+ return 51;
+ }
+
+ public static int collectCharSequence(String a, CharSequence[] b) {
+ assertEquals("a", a);
+ assertEquals("b", b[0]);
+ assertEquals("c", b[1]);
+ return 99;
+ }
+
+ public static void testAsCollector() throws Throwable {
+ // Reference arrays.
+ // -------------------
+ MethodHandle trailingRef = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "collectCharSequence",
+ MethodType.methodType(int.class, String.class, CharSequence[].class));
+
+ // int[] is not convertible to CharSequence[].class.
+ try {
+ trailingRef.asCollector(int[].class, 1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // Object[] is not convertible to CharSequence[].class.
+ try {
+ trailingRef.asCollector(Object[].class, 1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // String[].class is convertible to CharSequence.class
+ MethodHandle collector = trailingRef.asCollector(String[].class, 2);
+ assertEquals(99, (int) collector.invoke("a", "b", "c"));
+
+ // Too few arguments should fail with a WMTE.
+ try {
+ collector.invoke("a", "b");
+ fail();
+ } catch (WrongMethodTypeException expected) {
+ }
+
+ // Too many arguments should fail with a WMTE.
+ try {
+ collector.invoke("a", "b", "c", "d");
+ fail();
+ } catch (WrongMethodTypeException expected) {
+ }
+
+ // Sanity checks on other array types.
+
+ MethodHandle target = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "collectBoolean",
+ MethodType.methodType(int.class, String.class, boolean[].class));
+ assertEquals(44, (int) target.asCollector(boolean[].class, 2).invoke("a", true, false));
+
+ target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "collectByte",
+ MethodType.methodType(int.class, String.class, byte[].class));
+ assertEquals(45, (int) target.asCollector(byte[].class, 2).invoke("a", (byte) 1, (byte) 2));
+
+ target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "collectChar",
+ MethodType.methodType(int.class, String.class, char[].class));
+ assertEquals(46, (int) target.asCollector(char[].class, 2).invoke("a", 'a', 'b'));
+
+ target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "collectShort",
+ MethodType.methodType(int.class, String.class, short[].class));
+ assertEquals(47, (int) target.asCollector(short[].class, 2).invoke("a", (short) 3, (short) 4));
+
+ target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "collectInt",
+ MethodType.methodType(int.class, String.class, int[].class));
+ assertEquals(48, (int) target.asCollector(int[].class, 2).invoke("a", 42, 43));
+
+ target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "collectLong",
+ MethodType.methodType(int.class, String.class, long[].class));
+ assertEquals(49, (int) target.asCollector(long[].class, 2).invoke("a", 100, 99));
+
+ target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "collectFloat",
+ MethodType.methodType(int.class, String.class, float[].class));
+ assertEquals(50, (int) target.asCollector(float[].class, 2).invoke("a", 8.9f, 9.1f));
+
+ target = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "collectDouble",
+ MethodType.methodType(int.class, String.class, double[].class));
+ assertEquals(51, (int) target.asCollector(double[].class, 2).invoke("a", 6.7, 7.8));
+ }
+
+ public static String filter1(char a) {
+ return String.valueOf(a);
+ }
+
+ public static char filter2(String b) {
+ return b.charAt(0);
+ }
+
+ public static String badFilter1(char a, char b) {
+ return "bad";
+ }
+
+ public static int filterTarget(String a, char b, String c, char d) {
+ assertEquals("a", a);
+ assertEquals('b', b);
+ assertEquals("c", c);
+ assertEquals('d', d);
+ return 56;
+ }
+
+ public static void testFilterArguments() throws Throwable {
+ MethodHandle filter1 = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "filter1", MethodType.methodType(String.class, char.class));
+ MethodHandle filter2 = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "filter2", MethodType.methodType(char.class, String.class));
+
+ MethodHandle target = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "filterTarget", MethodType.methodType(int.class,
+ String.class, char.class, String.class, char.class));
+
+ // In all the cases below, the values printed will be 'a', 'b', 'c', 'd'.
+
+ // Filter arguments [0, 1] - all other arguments are passed through
+ // as is.
+ MethodHandle adapter = MethodHandles.filterArguments(
+ target, 0, filter1, filter2);
+ assertEquals(56, (int) adapter.invokeExact('a', "bXXXX", "c", 'd'));
+
+ // Filter arguments [1, 2].
+ adapter = MethodHandles.filterArguments(target, 1, filter2, filter1);
+ assertEquals(56, (int) adapter.invokeExact("a", "bXXXX", 'c', 'd'));
+
+ // Filter arguments [2, 3].
+ adapter = MethodHandles.filterArguments(target, 2, filter1, filter2);
+ assertEquals(56, (int) adapter.invokeExact("a", 'b', 'c', "dXXXXX"));
+
+ // Try out a few error cases :
+
+ // The return types of the filter doesn't align with the expected argument
+ // type of the target.
+ try {
+ adapter = MethodHandles.filterArguments(target, 2, filter2, filter1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // There are more filters than arguments.
+ try {
+ adapter = MethodHandles.filterArguments(target, 3, filter2, filter1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // We pass in an obviously bogus position.
+ try {
+ adapter = MethodHandles.filterArguments(target, -1, filter2, filter1);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ }
+
+ // We pass in a function that has more than one argument.
+ MethodHandle badFilter1 = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "badFilter1",
+ MethodType.methodType(String.class, char.class, char.class));
+
+ try {
+ adapter = MethodHandles.filterArguments(target, 0, badFilter1, filter2);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ static void voidFilter(char a, char b) {
+ }
+
+ static String filter(char a, char b) {
+ return String.valueOf(a) + "+" + b;
+ }
+
+ static char badFilter(char a, char b) {
+ return 0;
+ }
+
+ static String target(String a, String b, String c) {
+ return ("a: " + a + ", b: " + b + ", c: " + c);
+ }
+
+ public static void testCollectArguments() throws Throwable {
+ // Test non-void filters.
+ MethodHandle filter = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "filter",
+ MethodType.methodType(String.class, char.class, char.class));
+
+ MethodHandle target = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "target",
+ MethodType.methodType(String.class, String.class, String.class, String.class));
+
+ // Filter at position 0.
+ MethodHandle adapter = MethodHandles.collectArguments(target, 0, filter);
+ assertEquals("a: a+b, b: c, c: d",
+ (String) adapter.invokeExact('a', 'b', "c", "d"));
+
+ // Filter at position 1.
+ adapter = MethodHandles.collectArguments(target, 1, filter);
+ assertEquals("a: a, b: b+c, c: d",
+ (String) adapter.invokeExact("a", 'b', 'c', "d"));
+
+ // Filter at position 2.
+ adapter = MethodHandles.collectArguments(target, 2, filter);
+ assertEquals("a: a, b: b, c: c+d",
+ (String) adapter.invokeExact("a", "b", 'c', 'd'));
+
+ // Test void filters. Note that we're passing in one more argument
+ // than usual because the filter returns nothing - we have to invoke with
+ // the full set of filter args and the full set of target args.
+ filter = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class, "voidFilter",
+ MethodType.methodType(void.class, char.class, char.class));
+ adapter = MethodHandles.collectArguments(target, 0, filter);
+ assertEquals("a: a, b: b, c: c",
+ (String) adapter.invokeExact('a', 'b', "a", "b", "c"));
+
+ adapter = MethodHandles.collectArguments(target, 1, filter);
+ assertEquals("a: a, b: b, c: c",
+ (String) adapter.invokeExact("a", 'a', 'b', "b", "c"));
+
+ // Test out a few failure cases.
+ filter = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "filter",
+ MethodType.methodType(String.class, char.class, char.class));
+
+ // Bogus filter position.
+ try {
+ adapter = MethodHandles.collectArguments(target, 3, filter);
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ }
+
+ // Mismatch in filter return type.
+ filter = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "badFilter",
+ MethodType.methodType(char.class, char.class, char.class));
+ try {
+ adapter = MethodHandles.collectArguments(target, 0, filter);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ static int insertReceiver(String a, int b, Integer c, String d) {
+ assertEquals("foo", a);
+ assertEquals(56, b);
+ assertEquals(Integer.valueOf(57), c);
+ assertEquals("bar", d);
+
+ return 73;
+ }
+
+ public static void testInsertArguments() throws Throwable {
+ MethodHandle target = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "insertReceiver",
+ MethodType.methodType(int.class,
+ String.class, int.class, Integer.class, String.class));
+
+ // Basic single element array inserted at position 0.
+ MethodHandle adapter = MethodHandles.insertArguments(
+ target, 0, new Object[]{"foo"});
+ assertEquals(73, (int) adapter.invokeExact(56, Integer.valueOf(57), "bar"));
+
+ // Exercise unboxing.
+ adapter = MethodHandles.insertArguments(
+ target, 1, new Object[]{Integer.valueOf(56), 57});
+ assertEquals(73, (int) adapter.invokeExact("foo", "bar"));
+
+ // Exercise a widening conversion.
+ adapter = MethodHandles.insertArguments(
+ target, 1, new Object[]{(short) 56, Integer.valueOf(57)});
+ assertEquals(73, (int) adapter.invokeExact("foo", "bar"));
+
+ // Insert an argument at the last position.
+ adapter = MethodHandles.insertArguments(
+ target, 3, new Object[]{"bar"});
+ assertEquals(73, (int) adapter.invokeExact("foo", 56, Integer.valueOf(57)));
+
+ // Exercise a few error cases.
+
+ // A reference type that can't be cast to another reference type.
+ try {
+ MethodHandles.insertArguments(target, 3, new Object[]{new Object()});
+ fail();
+ } catch (ClassCastException expected) {
+ }
+
+ // A boxed type that can't be unboxed correctly.
+ try {
+ MethodHandles.insertArguments(target, 1, new Object[]{Long.valueOf(56)});
+ fail();
+ } catch (ClassCastException expected) {
+ }
+ }
+
+ public static String foldFilter(char a, char b) {
+ return String.valueOf(a) + "+" + b;
+ }
+
+ public static void voidFoldFilter(String e, char a, char b) {
+ assertEquals("a", e);
+ assertEquals('c', a);
+ assertEquals('d', b);
+ }
+
+ public static String foldTarget(String a, char b, char c, String d) {
+ return ("a: " + a + " ,b:" + b + " ,c:" + c + " ,d:" + d);
+ }
+
+ public static void mismatchedVoidFilter(Integer a) {
+ }
+
+ public static Integer mismatchedNonVoidFilter(char a, char b) {
+ return null;
+ }
+
+ public static void testFoldArguments() throws Throwable {
+ // Test non-void filters.
+ MethodHandle filter = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "foldFilter",
+ MethodType.methodType(String.class, char.class, char.class));
+
+ MethodHandle target = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "foldTarget",
+ MethodType.methodType(String.class, String.class,
+ char.class, char.class, String.class));
+
+ // Folder with a non-void type.
+ MethodHandle adapter = MethodHandles.foldArguments(target, filter);
+ assertEquals("a: c+d ,b:c ,c:d ,d:e",
+ (String) adapter.invokeExact('c', 'd', "e"));
+
+ // Folder with a void type.
+ filter = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "voidFoldFilter",
+ MethodType.methodType(void.class, String.class, char.class, char.class));
+ adapter = MethodHandles.foldArguments(target, filter);
+ assertEquals("a: a ,b:c ,c:d ,d:e",
+ (String) adapter.invokeExact("a", 'c', 'd', "e"));
+
+ // Test a few erroneous cases.
+
+ filter = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "mismatchedVoidFilter",
+ MethodType.methodType(void.class, Integer.class));
+ try {
+ adapter = MethodHandles.foldArguments(target, filter);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ filter = MethodHandles.lookup().findStatic(
+ MethodHandleCombinersTest.class, "mismatchedNonVoidFilter",
+ MethodType.methodType(Integer.class, char.class, char.class));
+ try {
+ adapter = MethodHandles.foldArguments(target, filter);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java
index 3705744..f833840 100644
--- a/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java
@@ -152,6 +152,23 @@
}
}
+ public void test_methodType_basicTestsReturnTypeAndMethodTypeParameters() {
+ MethodType mt = MethodType.methodType(int.class, long.class, String.class);
+ assertEquals(int.class, mt.returnType());
+
+ MethodType mt2 = MethodType.methodType(long.class, mt);
+
+ assertEquals(long.class, mt2.returnType());
+ assertEquals(long.class, mt2.parameterType(0));
+ assertEquals(String.class, mt2.parameterType(1));
+
+ try {
+ MethodType.methodType(int.class, (MethodType) null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
public void testGenericMethodType() {
MethodType mt = MethodType.genericMethodType(0);
assertEquals(0, mt.parameterCount());
diff --git a/luni/src/test/java/libcore/java/net/URLConnectionTest.java b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
index 9231cd0..c80d2ec 100644
--- a/luni/src/test/java/libcore/java/net/URLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
@@ -1068,7 +1068,35 @@
}
// http://b/33763156
- public void testDisconnectDuringConnect() throws IOException {
+ public void testDisconnectDuringConnect_getInputStream() throws IOException {
+ checkDisconnectDuringConnect(HttpURLConnection::getInputStream);
+ }
+
+ // http://b/33763156
+ public void testDisconnectDuringConnect_getOutputStream() throws IOException {
+ checkDisconnectDuringConnect(HttpURLConnection::getOutputStream);
+ }
+
+ // http://b/33763156
+ public void testDisconnectDuringConnect_getResponseCode() throws IOException {
+ checkDisconnectDuringConnect(HttpURLConnection::getResponseCode);
+ }
+
+ // http://b/33763156
+ public void testDisconnectDuringConnect_getResponseMessage() throws IOException {
+ checkDisconnectDuringConnect(HttpURLConnection::getResponseMessage);
+ }
+
+ interface ConnectStrategy {
+ /**
+ * Causes the given {@code connection}, which was previously disconnected,
+ * to initiate the connection.
+ */
+ void connect(HttpURLConnection connection) throws IOException;
+ }
+
+ // http://b/33763156
+ private void checkDisconnectDuringConnect(ConnectStrategy connectStrategy) throws IOException {
server.enqueue(new MockResponse().setBody("This should never be sent"));
server.play();
@@ -1088,7 +1116,7 @@
HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
connectionHolder.set(connection);
try {
- connection.getInputStream();
+ connectStrategy.connect(connection);
fail();
} catch (IOException expected) {
assertEquals("Canceled", expected.getMessage());
diff --git a/luni/src/test/java/libcore/java/nio/file/DirectoryIteratorExceptionTest.java b/luni/src/test/java/libcore/java/nio/file/DirectoryIteratorExceptionTest.java
new file mode 100644
index 0000000..8fb2571
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/DirectoryIteratorExceptionTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.nio.file;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.nio.file.DirectoryIteratorException;
+
+public class DirectoryIteratorExceptionTest extends TestCase {
+
+ public void test_constructor() {
+ IOException ioException = new IOException();
+ DirectoryIteratorException exception = new DirectoryIteratorException(ioException);
+
+ assertSame(ioException, exception.getCause());
+
+ try {
+ new DirectoryIteratorException(null);
+ fail();
+ } catch (NullPointerException expected) {}
+ }
+}
diff --git a/luni/src/test/java/libcore/java/nio/file/FileSystemAlreadyExistsExceptionTest.java b/luni/src/test/java/libcore/java/nio/file/FileSystemAlreadyExistsExceptionTest.java
new file mode 100644
index 0000000..4130ddc
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/FileSystemAlreadyExistsExceptionTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.nio.file;
+
+import junit.framework.TestCase;
+
+import java.nio.file.FileSystemAlreadyExistsException;
+
+public class FileSystemAlreadyExistsExceptionTest extends TestCase {
+
+ public void test_constructor$String() {
+ String message = "message";
+ FileSystemAlreadyExistsException exception = new FileSystemAlreadyExistsException(message);
+ assertEquals(message, exception.getMessage());
+
+ message = null;
+ exception = new FileSystemAlreadyExistsException(message);
+ assertEquals(message, exception.getMessage());
+ }
+}
diff --git a/luni/src/test/java/libcore/java/nio/file/FileSystemNotFoundExceptionTest.java b/luni/src/test/java/libcore/java/nio/file/FileSystemNotFoundExceptionTest.java
new file mode 100644
index 0000000..2a0fe1e
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/FileSystemNotFoundExceptionTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.nio.file;
+
+import junit.framework.TestCase;
+
+import java.nio.file.FileSystemNotFoundException;
+
+public class FileSystemNotFoundExceptionTest extends TestCase {
+
+ public void test_constructor_empty() {
+ FileSystemNotFoundException exception = new FileSystemNotFoundException();
+ assertEquals(null, exception.getMessage());
+ }
+
+ public void test_constructor$String() {
+ String message = "message";
+ FileSystemNotFoundException exception = new FileSystemNotFoundException(message);
+ assertEquals(message, exception.getMessage());
+ }
+}
diff --git a/luni/src/test/java/libcore/java/nio/file/InvalidPathExceptionTest.java b/luni/src/test/java/libcore/java/nio/file/InvalidPathExceptionTest.java
new file mode 100644
index 0000000..267581c
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/InvalidPathExceptionTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.nio.file;
+
+import junit.framework.TestCase;
+
+import java.nio.file.InvalidPathException;
+
+public class InvalidPathExceptionTest extends TestCase {
+
+ public void test_Constructor$String$String$Int() {
+ String reason = "reason";
+ String input = "input";
+ int index = 0;
+
+ InvalidPathException exception = new InvalidPathException(input, reason, index);
+ assertEquals(index, exception.getIndex());
+ assertEquals(reason, exception.getReason());
+ assertEquals(input, exception.getInput());
+
+ // Test the case where index = -1.
+ index = -1;
+ exception = new InvalidPathException(input, reason, index);
+ assertEquals(index, exception.getIndex());
+ assertEquals(reason, exception.getReason());
+ assertEquals(input, exception.getInput());
+
+ // Test the case where index < -1;
+ index = -2;
+ try {
+ new InvalidPathException(input, reason, index);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+
+ // Test the case where input is null, reason is not null and index >= -1.
+ try {
+ index = 0;
+ new InvalidPathException(null, reason, index);
+ fail();
+ } catch (NullPointerException expected) {}
+
+ // Test the case where input is null, reason is not null and index < -1.
+ try {
+ index = -1;
+ new InvalidPathException(null, reason, index);
+ fail();
+ } catch (NullPointerException expected) {}
+
+ // Test the case where reason is null, input is not null and index >= -1.
+ try {
+ index = 0;
+ new InvalidPathException(input, null, index);
+ fail();
+ } catch (NullPointerException expected) {}
+
+ // Test the case where input is not null, reason is null and index < -1.
+ try {
+ index = -1;
+ new InvalidPathException(input, null, index);
+ fail();
+ } catch (NullPointerException expected) {}
+ }
+
+ public void test_Constructor$String$String() {
+ String reason = "reason";
+ String input = "input";
+
+ InvalidPathException exception = new InvalidPathException(input, reason);
+ assertEquals(-1, exception.getIndex());
+ assertEquals(reason, exception.getReason());
+ assertEquals(input, exception.getInput());
+
+ // Test the case where input is null and reason is not null.
+ try {
+ new InvalidPathException(null, reason);
+ fail();
+ } catch (NullPointerException expected) {}
+
+ // Test the case where reason is null and input is not null.
+ try {
+ new InvalidPathException(input, null);
+ fail();
+ } catch (NullPointerException expected) {}
+ }
+}
diff --git a/luni/src/test/java/libcore/java/nio/file/LinkPermissionTest.java b/luni/src/test/java/libcore/java/nio/file/LinkPermissionTest.java
new file mode 100644
index 0000000..b01350d
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/LinkPermissionTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.nio.file;
+
+import junit.framework.TestCase;
+
+import java.nio.file.LinkPermission;
+
+public class LinkPermissionTest extends TestCase {
+
+ public void test_constructor$String() {
+ // Only "hard" and "symbolic" are the supported permission target names.
+ LinkPermission linkPermission = new LinkPermission("hard");
+ assertNull(linkPermission.getName());
+
+ linkPermission = new LinkPermission("symbolic");
+ assertNull(linkPermission.getName());
+
+ // Non supported permission target names.
+ try {
+ new LinkPermission("test");
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_constructor$String$String() {
+ // Only empty string or null is accepted as action.
+ String actions = "";
+ LinkPermission linkPermission = new LinkPermission("hard", actions);
+ assertEquals("", linkPermission.getActions());
+
+ actions = null;
+ linkPermission = new LinkPermission("hard", actions);
+ assertEquals("", linkPermission.getActions());
+
+ // When actions is non empty string.
+ try {
+ actions = "abc";
+ new LinkPermission("hard", actions);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+}
diff --git a/luni/src/test/java/libcore/java/nio/file/ProviderNotFoundExceptionTest.java b/luni/src/test/java/libcore/java/nio/file/ProviderNotFoundExceptionTest.java
new file mode 100644
index 0000000..277db4f
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/ProviderNotFoundExceptionTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.nio.file;
+
+import junit.framework.TestCase;
+
+import java.nio.file.ProviderNotFoundException;
+
+public class ProviderNotFoundExceptionTest extends TestCase {
+
+ public void test_constructor$String() {
+ String message = "message";
+ ProviderNotFoundException exception = new ProviderNotFoundException(message);
+ assertEquals(message, exception.getMessage());
+
+ message = null;
+ exception = new ProviderNotFoundException(message);
+ assertEquals(message, exception.getMessage());
+ }
+}
diff --git a/luni/src/test/java/libcore/java/nio/file/SimpleFileVisitorTest.java b/luni/src/test/java/libcore/java/nio/file/SimpleFileVisitorTest.java
new file mode 100644
index 0000000..f712cbf
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/SimpleFileVisitorTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.nio.file;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+
+import static org.mockito.Mockito.mock;
+
+public class SimpleFileVisitorTest extends TestCase {
+
+ public void test_preVisitDirectory() throws IOException {
+ Path stubPath = mock(Path.class);
+ BasicFileAttributes stubAttributes = mock(BasicFileAttributes.class);
+ SimpleFileVisitor<Path> fileVisitor = new TestSimpleFileVisitor();
+
+ assertEquals(FileVisitResult.CONTINUE, fileVisitor.preVisitDirectory(stubPath,
+ stubAttributes));
+
+ try {
+ fileVisitor.preVisitDirectory(null, stubAttributes);
+ fail();
+ } catch (NullPointerException expected) {}
+
+ try {
+ fileVisitor.preVisitDirectory(stubPath, null);
+ fail();
+ } catch (NullPointerException expected) {}
+ }
+
+ public void test_postVisitDirectory() throws IOException {
+ Path stubPath = mock(Path.class);
+ IOException ioException = new IOException();
+ SimpleFileVisitor<Path> fileVisitor = new TestSimpleFileVisitor();
+
+ assertEquals(FileVisitResult.CONTINUE, fileVisitor.postVisitDirectory(stubPath, null));
+
+ try {
+ fileVisitor.postVisitDirectory(null, ioException);
+ fail();
+ } catch (NullPointerException expected) {}
+
+ try {
+ fileVisitor.postVisitDirectory(stubPath, ioException);
+ fail();
+ } catch (IOException actual) {
+ assertSame(ioException, actual);
+ }
+ }
+
+ public void test_visitFile() throws IOException {
+ Path stubPath = mock(Path.class);
+ BasicFileAttributes stubAttributes = mock(BasicFileAttributes.class);
+ SimpleFileVisitor<Path> fileVisitor = new TestSimpleFileVisitor();
+
+ assertEquals(FileVisitResult.CONTINUE, fileVisitor.visitFile(stubPath, stubAttributes));
+
+ try {
+ fileVisitor.visitFile(null, stubAttributes);
+ fail();
+ } catch (NullPointerException expected) {}
+
+ try {
+ fileVisitor.visitFile(stubPath, null);
+ fail();
+ } catch (NullPointerException expected) {}
+ }
+
+ public void test_visitFileFailed() throws IOException {
+ Path stubPath = mock(Path.class);
+ IOException ioException = new IOException();
+ SimpleFileVisitor<Path> fileVisitor = new TestSimpleFileVisitor();
+
+ try {
+ assertEquals(FileVisitResult.CONTINUE, fileVisitor.visitFileFailed(stubPath, null));
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ assertEquals(FileVisitResult.CONTINUE, fileVisitor.visitFileFailed(null,
+ ioException));
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ assertEquals(FileVisitResult.CONTINUE, fileVisitor.visitFileFailed(stubPath,
+ ioException));
+ fail();
+ } catch (IOException actual) {
+ assertSame(ioException, actual);
+ }
+ }
+
+ /**
+ * SimpleFileVisitor only has a protected constructor so we use a basic subclass for tests.
+ */
+ private static class TestSimpleFileVisitor extends SimpleFileVisitor<Path> {
+ }
+}
diff --git a/luni/src/test/java/libcore/util/NativeAllocationRegistryTest.java b/luni/src/test/java/libcore/util/NativeAllocationRegistryTest.java
index af45bfa..99be1fd 100644
--- a/luni/src/test/java/libcore/util/NativeAllocationRegistryTest.java
+++ b/luni/src/test/java/libcore/util/NativeAllocationRegistryTest.java
@@ -87,9 +87,8 @@
// Verify most of the allocations have been freed.
long nativeBytes = getNumNativeBytesAllocated();
- assertTrue("Native bytes allocated (" + nativeBytes + ")"
- + " exceeds max memory (" + max + ")",
- getNumNativeBytesAllocated() < max);
+ assertTrue("Excessive native bytes still allocated (" + nativeBytes + ")"
+ + " given max memory of (" + max + ")", nativeBytes < 2 * max);
}
public void testNativeAllocationAllocatorAndSharedRegistry() {
diff --git a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
index 383a358..c67a0a4 100644
--- a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
+++ b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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
@@ -113,29 +113,56 @@
}
/**
- * This method has the same contract as ensureCapacity, but is
- * never synchronized.
+ * For positive values of {@code minimumCapacity}, this method
+ * behaves like {@code ensureCapacity}, however it is never
+ * synchronized.
+ * If {@code minimumCapacity} is non positive due to numeric
+ * overflow, this method throws {@code OutOfMemoryError}.
*/
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
- if (minimumCapacity - value.length > 0)
- expandCapacity(minimumCapacity);
+ if (minimumCapacity - value.length > 0) {
+ value = Arrays.copyOf(value,
+ newCapacity(minimumCapacity));
+ }
}
/**
- * This implements the expansion semantics of ensureCapacity with no
- * size check or synchronization.
+ * The maximum size of array to allocate (unless necessary).
+ * Some VMs reserve some header words in an array.
+ * Attempts to allocate larger arrays may result in
+ * OutOfMemoryError: Requested array size exceeds VM limit
*/
- void expandCapacity(int minimumCapacity) {
- int newCapacity = value.length * 2 + 2;
- if (newCapacity - minimumCapacity < 0)
- newCapacity = minimumCapacity;
- if (newCapacity < 0) {
- if (minimumCapacity < 0) // overflow
- throw new OutOfMemoryError();
- newCapacity = Integer.MAX_VALUE;
+ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+ /**
+ * Returns a capacity at least as large as the given minimum capacity.
+ * Returns the current capacity increased by the same amount + 2 if
+ * that suffices.
+ * Will not return a capacity greater than {@code MAX_ARRAY_SIZE}
+ * unless the given minimum capacity is greater than that.
+ *
+ * @param minCapacity the desired minimum capacity
+ * @throws OutOfMemoryError if minCapacity is less than zero or
+ * greater than Integer.MAX_VALUE
+ */
+ private int newCapacity(int minCapacity) {
+ // overflow-conscious code
+ int newCapacity = (value.length << 1) + 2;
+ if (newCapacity - minCapacity < 0) {
+ newCapacity = minCapacity;
}
- value = Arrays.copyOf(value, newCapacity);
+ return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
+ ? hugeCapacity(minCapacity)
+ : newCapacity;
+ }
+
+ private int hugeCapacity(int minCapacity) {
+ if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
+ throw new OutOfMemoryError();
+ }
+ return (minCapacity > MAX_ARRAY_SIZE)
+ ? minCapacity : MAX_ARRAY_SIZE;
}
/**
diff --git a/ojluni/src/main/java/java/lang/StringBuffer.java b/ojluni/src/main/java/java/lang/StringBuffer.java
index 95a583d..6781f11 100644
--- a/ojluni/src/main/java/java/lang/StringBuffer.java
+++ b/ojluni/src/main/java/java/lang/StringBuffer.java
@@ -171,9 +171,7 @@
@Override
public synchronized void ensureCapacity(int minimumCapacity) {
- if (minimumCapacity > value.length) {
- expandCapacity(minimumCapacity);
- }
+ super.ensureCapacity(minimumCapacity);
}
/**
diff --git a/ojluni/src/main/java/java/time/Instant.java b/ojluni/src/main/java/java/time/Instant.java
index 91a177c..9b9efa5 100644
--- a/ojluni/src/main/java/java/time/Instant.java
+++ b/ojluni/src/main/java/java/time/Instant.java
@@ -1229,8 +1229,14 @@
* @throws ArithmeticException if numeric overflow occurs
*/
public long toEpochMilli() {
- long millis = Math.multiplyExact(seconds, 1000);
- return millis + nanos / 1000_000;
+ if (seconds < 0 && nanos > 0) {
+ long millis = Math.multiplyExact(seconds+1, 1000);
+ long adjustment = nanos / 1000_000 - 1000;
+ return Math.addExact(millis, adjustment);
+ } else {
+ long millis = Math.multiplyExact(seconds, 1000);
+ return Math.addExact(millis, nanos / 1000_000);
+ }
}
//-----------------------------------------------------------------------
diff --git a/ojluni/src/main/java/java/time/chrono/HijrahChronology.java b/ojluni/src/main/java/java/time/chrono/HijrahChronology.java
index 67cca69..9fc86c4 100644
--- a/ojluni/src/main/java/java/time/chrono/HijrahChronology.java
+++ b/ojluni/src/main/java/java/time/chrono/HijrahChronology.java
@@ -544,10 +544,9 @@
//-----------------------------------------------------------------------
@Override
public boolean isLeapYear(long prolepticYear) {
- checkCalendarInit();
- int epochMonth = yearToEpochMonth((int) prolepticYear);
- if (epochMonth < 0 || epochMonth > maxEpochDay) {
- throw new DateTimeException("Hijrah date out of range");
+ checkCalendarInit();
+ if (prolepticYear < getMinimumYear() || prolepticYear > getMaximumYear()) {
+ return false;
}
int len = getYearLength((int) prolepticYear);
return (len > 354);
diff --git a/ojluni/src/main/java/java/util/zip/Deflater.java b/ojluni/src/main/java/java/util/zip/Deflater.java
index 54a649f..ca9fc14 100644
--- a/ojluni/src/main/java/java/util/zip/Deflater.java
+++ b/ojluni/src/main/java/java/util/zip/Deflater.java
@@ -320,7 +320,9 @@
* should be called in order to provide more input
*/
public boolean needsInput() {
- return len <= 0;
+ synchronized (zsRef) {
+ return len <= 0;
+ }
}
/**
diff --git a/ojluni/src/main/java/sun/invoke/empty/Empty.java b/ojluni/src/main/java/sun/invoke/empty/Empty.java
deleted file mode 100644
index f75d2b3..0000000
--- a/ojluni/src/main/java/sun/invoke/empty/Empty.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2009, 2011, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.invoke.empty;
-
-/**
- * An empty class in an empty package.
- * Used as a proxy for unprivileged code, since making access checks
- * against it will only succeed against public methods in public types.
- * <p>
- * This class also stands (internally to sun.invoke) for the type of a
- * value that cannot be produced, because the expression of this type
- * always returns abnormally. (Cf. Nothing in the closures proposal.)
- * @author jrose
- */
-public class Empty {
- private Empty() { throw new InternalError(); }
-}
diff --git a/ojluni/src/main/java/sun/invoke/util/package-info.java b/ojluni/src/main/java/sun/invoke/util/package-info.java
deleted file mode 100644
index 785ca80..0000000
--- a/ojluni/src/main/java/sun/invoke/util/package-info.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2008, 2011, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-
-/**
- * Extra support for using JSR 292 RI, package java.lang.invoke.
- * @author jrose
- */
-
-package sun.invoke.util;
diff --git a/ojluni/src/main/java/sun/misc/JavaSecurityProtectionDomainAccess.java b/ojluni/src/main/java/sun/misc/JavaSecurityProtectionDomainAccess.java
deleted file mode 100644
index 95560ff..0000000
--- a/ojluni/src/main/java/sun/misc/JavaSecurityProtectionDomainAccess.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2009, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.misc;
-
-import java.security.PermissionCollection;
-import java.security.ProtectionDomain;
-
-public interface JavaSecurityProtectionDomainAccess {
- interface ProtectionDomainCache {
- void put(ProtectionDomain pd, PermissionCollection pc);
- PermissionCollection get(ProtectionDomain pd);
- }
- /**
- * Returns the ProtectionDomainCache.
- */
- ProtectionDomainCache getProtectionDomainCache();
-}
diff --git a/ojluni/src/main/java/sun/misc/Service.java b/ojluni/src/main/java/sun/misc/Service.java
deleted file mode 100644
index 96eb20c..0000000
--- a/ojluni/src/main/java/sun/misc/Service.java
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright (c) 1999, 2003, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.misc;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.TreeSet;
-
-
-/**
- * A simple service-provider lookup mechanism. A <i>service</i> is a
- * well-known set of interfaces and (usually abstract) classes. A <i>service
- * provider</i> is a specific implementation of a service. The classes in a
- * provider typically implement the interfaces and subclass the classes defined
- * in the service itself. Service providers may be installed in an
- * implementation of the Java platform in the form of extensions, that is, jar
- * files placed into any of the usual extension directories. Providers may
- * also be made available by adding them to the applet or application class
- * path or by some other platform-specific means.
- *
- * <p> In this lookup mechanism a service is represented by an interface or an
- * abstract class. (A concrete class may be used, but this is not
- * recommended.) A provider of a given service contains one or more concrete
- * classes that extend this <i>service class</i> with data and code specific to
- * the provider. This <i>provider class</i> will typically not be the entire
- * provider itself but rather a proxy that contains enough information to
- * decide whether the provider is able to satisfy a particular request together
- * with code that can create the actual provider on demand. The details of
- * provider classes tend to be highly service-specific; no single class or
- * interface could possibly unify them, so no such class has been defined. The
- * only requirement enforced here is that provider classes must have a
- * zero-argument constructor so that they may be instantiated during lookup.
- *
- * <p> A service provider identifies itself by placing a provider-configuration
- * file in the resource directory <tt>META-INF/services</tt>. The file's name
- * should consist of the fully-qualified name of the abstract service class.
- * The file should contain a list of fully-qualified concrete provider-class
- * names, one per line. Space and tab characters surrounding each name, as
- * well as blank lines, are ignored. The comment character is <tt>'#'</tt>
- * (<tt>0x23</tt>); on each line all characters following the first comment
- * character are ignored. The file must be encoded in UTF-8.
- *
- * <p> If a particular concrete provider class is named in more than one
- * configuration file, or is named in the same configuration file more than
- * once, then the duplicates will be ignored. The configuration file naming a
- * particular provider need not be in the same jar file or other distribution
- * unit as the provider itself. The provider must be accessible from the same
- * class loader that was initially queried to locate the configuration file;
- * note that this is not necessarily the class loader that found the file.
- *
- * <p> <b>Example:</b> Suppose we have a service class named
- * <tt>java.io.spi.CharCodec</tt>. It has two abstract methods:
- *
- * <pre>
- * public abstract CharEncoder getEncoder(String encodingName);
- * public abstract CharDecoder getDecoder(String encodingName);
- * </pre>
- *
- * Each method returns an appropriate object or <tt>null</tt> if it cannot
- * translate the given encoding. Typical <tt>CharCodec</tt> providers will
- * support more than one encoding.
- *
- * <p> If <tt>sun.io.StandardCodec</tt> is a provider of the <tt>CharCodec</tt>
- * service then its jar file would contain the file
- * <tt>META-INF/services/java.io.spi.CharCodec</tt>. This file would contain
- * the single line:
- *
- * <pre>
- * sun.io.StandardCodec # Standard codecs for the platform
- * </pre>
- *
- * To locate an encoder for a given encoding name, the internal I/O code would
- * do something like this:
- *
- * <pre>
- * CharEncoder getEncoder(String encodingName) {
- * Iterator ps = Service.providers(CharCodec.class);
- * while (ps.hasNext()) {
- * CharCodec cc = (CharCodec)ps.next();
- * CharEncoder ce = cc.getEncoder(encodingName);
- * if (ce != null)
- * return ce;
- * }
- * return null;
- * }
- * </pre>
- *
- * The provider-lookup mechanism always executes in the security context of the
- * caller. Trusted system code should typically invoke the methods in this
- * class from within a privileged security context.
- *
- * @author Mark Reinhold
- * @since 1.3
- */
-
-public final class Service {
-
- private static final String prefix = "META-INF/services/";
-
- private Service() { }
-
- private static void fail(Class service, String msg, Throwable cause)
- throws ServiceConfigurationError
- {
- ServiceConfigurationError sce
- = new ServiceConfigurationError(service.getName() + ": " + msg);
- sce.initCause(cause);
- throw sce;
- }
-
- private static void fail(Class service, String msg)
- throws ServiceConfigurationError
- {
- throw new ServiceConfigurationError(service.getName() + ": " + msg);
- }
-
- private static void fail(Class service, URL u, int line, String msg)
- throws ServiceConfigurationError
- {
- fail(service, u + ":" + line + ": " + msg);
- }
-
- /**
- * Parse a single line from the given configuration file, adding the name
- * on the line to both the names list and the returned set iff the name is
- * not already a member of the returned set.
- */
- private static int parseLine(Class service, URL u, BufferedReader r, int lc,
- List names, Set returned)
- throws IOException, ServiceConfigurationError
- {
- String ln = r.readLine();
- if (ln == null) {
- return -1;
- }
- int ci = ln.indexOf('#');
- if (ci >= 0) ln = ln.substring(0, ci);
- ln = ln.trim();
- int n = ln.length();
- if (n != 0) {
- if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
- fail(service, u, lc, "Illegal configuration-file syntax");
- int cp = ln.codePointAt(0);
- if (!Character.isJavaIdentifierStart(cp))
- fail(service, u, lc, "Illegal provider-class name: " + ln);
- for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
- cp = ln.codePointAt(i);
- if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
- fail(service, u, lc, "Illegal provider-class name: " + ln);
- }
- if (!returned.contains(ln)) {
- names.add(ln);
- returned.add(ln);
- }
- }
- return lc + 1;
- }
-
- /**
- * Parse the content of the given URL as a provider-configuration file.
- *
- * @param service
- * The service class for which providers are being sought;
- * used to construct error detail strings
- *
- * @param url
- * The URL naming the configuration file to be parsed
- *
- * @param returned
- * A Set containing the names of provider classes that have already
- * been returned. This set will be updated to contain the names
- * that will be yielded from the returned <tt>Iterator</tt>.
- *
- * @return A (possibly empty) <tt>Iterator</tt> that will yield the
- * provider-class names in the given configuration file that are
- * not yet members of the returned set
- *
- * @throws ServiceConfigurationError
- * If an I/O error occurs while reading from the given URL, or
- * if a configuration-file format error is detected
- */
- private static Iterator parse(Class service, URL u, Set returned)
- throws ServiceConfigurationError
- {
- InputStream in = null;
- BufferedReader r = null;
- ArrayList names = new ArrayList();
- try {
- in = u.openStream();
- r = new BufferedReader(new InputStreamReader(in, "utf-8"));
- int lc = 1;
- while ((lc = parseLine(service, u, r, lc, names, returned)) >= 0);
- } catch (IOException x) {
- fail(service, ": " + x);
- } finally {
- try {
- if (r != null) r.close();
- if (in != null) in.close();
- } catch (IOException y) {
- fail(service, ": " + y);
- }
- }
- return names.iterator();
- }
-
-
- /**
- * Private inner class implementing fully-lazy provider lookup
- */
- private static class LazyIterator implements Iterator {
-
- Class service;
- ClassLoader loader;
- Enumeration configs = null;
- Iterator pending = null;
- Set returned = new TreeSet();
- String nextName = null;
-
- private LazyIterator(Class service, ClassLoader loader) {
- this.service = service;
- this.loader = loader;
- }
-
- public boolean hasNext() throws ServiceConfigurationError {
- if (nextName != null) {
- return true;
- }
- if (configs == null) {
- try {
- String fullName = prefix + service.getName();
- if (loader == null)
- configs = ClassLoader.getSystemResources(fullName);
- else
- configs = loader.getResources(fullName);
- } catch (IOException x) {
- fail(service, ": " + x);
- }
- }
- while ((pending == null) || !pending.hasNext()) {
- if (!configs.hasMoreElements()) {
- return false;
- }
- pending = parse(service, (URL)configs.nextElement(), returned);
- }
- nextName = (String)pending.next();
- return true;
- }
-
- public Object next() throws ServiceConfigurationError {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- String cn = nextName;
- nextName = null;
- Class<?> c = null;
- try {
- c = Class.forName(cn, false, loader);
- } catch (ClassNotFoundException x) {
- fail(service,
- "Provider " + cn + " not found");
- }
- if (!service.isAssignableFrom(c)) {
- fail(service,
- "Provider " + cn + " not a subtype");
- }
- try {
- return service.cast(c.newInstance());
- } catch (Throwable x) {
- fail(service,
- "Provider " + cn + " could not be instantiated: " + x,
- x);
- }
- return null; /* This cannot happen */
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- }
-
-
- /**
- * Locates and incrementally instantiates the available providers of a
- * given service using the given class loader.
- *
- * <p> This method transforms the name of the given service class into a
- * provider-configuration filename as described above and then uses the
- * <tt>getResources</tt> method of the given class loader to find all
- * available files with that name. These files are then read and parsed to
- * produce a list of provider-class names. The iterator that is returned
- * uses the given class loader to lookup and then instantiate each element
- * of the list.
- *
- * <p> Because it is possible for extensions to be installed into a running
- * Java virtual machine, this method may return different results each time
- * it is invoked. <p>
- *
- * @param service
- * The service's abstract service class
- *
- * @param loader
- * The class loader to be used to load provider-configuration files
- * and instantiate provider classes, or <tt>null</tt> if the system
- * class loader (or, failing that the bootstrap class loader) is to
- * be used
- *
- * @return An <tt>Iterator</tt> that yields provider objects for the given
- * service, in some arbitrary order. The iterator will throw a
- * <tt>ServiceConfigurationError</tt> if a provider-configuration
- * file violates the specified format or if a provider class cannot
- * be found and instantiated.
- *
- * @throws ServiceConfigurationError
- * If a provider-configuration file violates the specified format
- * or names a provider class that cannot be found and instantiated
- *
- * @see #providers(java.lang.Class)
- * @see #installedProviders(java.lang.Class)
- */
- public static Iterator providers(Class service, ClassLoader loader)
- throws ServiceConfigurationError
- {
- return new LazyIterator(service, loader);
- }
-
-
- /**
- * Locates and incrementally instantiates the available providers of a
- * given service using the context class loader. This convenience method
- * is equivalent to
- *
- * <pre>
- * ClassLoader cl = Thread.currentThread().getContextClassLoader();
- * return Service.providers(service, cl);
- * </pre>
- *
- * @param service
- * The service's abstract service class
- *
- * @return An <tt>Iterator</tt> that yields provider objects for the given
- * service, in some arbitrary order. The iterator will throw a
- * <tt>ServiceConfigurationError</tt> if a provider-configuration
- * file violates the specified format or if a provider class cannot
- * be found and instantiated.
- *
- * @throws ServiceConfigurationError
- * If a provider-configuration file violates the specified format
- * or names a provider class that cannot be found and instantiated
- *
- * @see #providers(java.lang.Class, java.lang.ClassLoader)
- */
- public static Iterator providers(Class service)
- throws ServiceConfigurationError
- {
- ClassLoader cl = Thread.currentThread().getContextClassLoader();
- return Service.providers(service, cl);
- }
-
-
- /**
- * Locates and incrementally instantiates the available providers of a
- * given service using the extension class loader. This convenience method
- * simply locates the extension class loader, call it
- * <tt>extClassLoader</tt>, and then does
- *
- * <pre>
- * return Service.providers(service, extClassLoader);
- * </pre>
- *
- * If the extension class loader cannot be found then the system class
- * loader is used; if there is no system class loader then the bootstrap
- * class loader is used.
- *
- * @param service
- * The service's abstract service class
- *
- * @return An <tt>Iterator</tt> that yields provider objects for the given
- * service, in some arbitrary order. The iterator will throw a
- * <tt>ServiceConfigurationError</tt> if a provider-configuration
- * file violates the specified format or if a provider class cannot
- * be found and instantiated.
- *
- * @throws ServiceConfigurationError
- * If a provider-configuration file violates the specified format
- * or names a provider class that cannot be found and instantiated
- *
- * @see #providers(java.lang.Class, java.lang.ClassLoader)
- */
- public static Iterator installedProviders(Class service)
- throws ServiceConfigurationError
- {
- ClassLoader cl = ClassLoader.getSystemClassLoader();
- ClassLoader prev = null;
- while (cl != null) {
- prev = cl;
- cl = cl.getParent();
- }
- return Service.providers(service, prev);
- }
-
-}
diff --git a/ojluni/src/main/java/sun/misc/ServiceConfigurationError.java b/ojluni/src/main/java/sun/misc/ServiceConfigurationError.java
deleted file mode 100644
index 5659b23..0000000
--- a/ojluni/src/main/java/sun/misc/ServiceConfigurationError.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 1999, 2000, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.misc;
-
-
-/**
- * Error thrown when something goes wrong while looking up service providers.
- * In particular, this error will be thrown in the following situations:
- *
- * <ul>
- * <li> A concrete provider class cannot be found,
- * <li> A concrete provider class cannot be instantiated,
- * <li> The format of a provider-configuration file is illegal, or
- * <li> An IOException occurs while reading a provider-configuration file.
- * </ul>
- *
- * @author Mark Reinhold
- * @since 1.3
- */
-
-public class ServiceConfigurationError extends Error {
-
- /**
- * Constructs a new instance with the specified detail string.
- */
- public ServiceConfigurationError(String msg) {
- super(msg);
- }
-
- /**
- * Constructs a new instance that wraps the specified throwable.
- */
- public ServiceConfigurationError(Throwable x) {
- super(x);
- }
-
-}
diff --git a/ojluni/src/main/java/sun/misc/SoftCache.java b/ojluni/src/main/java/sun/misc/SoftCache.java
deleted file mode 100644
index b1d98ff..0000000
--- a/ojluni/src/main/java/sun/misc/SoftCache.java
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * Copyright (c) 1998, 2006, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.misc;
-
-import java.lang.ref.SoftReference;
-import java.lang.ref.ReferenceQueue;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.AbstractMap;
-import java.util.HashMap;
-import java.util.Set;
-import java.util.AbstractSet;
-import java.util.NoSuchElementException;
-
-
-/**
- * A memory-sensitive implementation of the <code>Map</code> interface.
- *
- * <p> A <code>SoftCache</code> object uses {@link java.lang.ref.SoftReference
- * soft references} to implement a memory-sensitive hash map. If the garbage
- * collector determines at a certain point in time that a value object in a
- * <code>SoftCache</code> entry is no longer strongly reachable, then it may
- * remove that entry in order to release the memory occupied by the value
- * object. All <code>SoftCache</code> objects are guaranteed to be completely
- * cleared before the virtual machine will throw an
- * <code>OutOfMemoryError</code>. Because of this automatic clearing feature,
- * the behavior of this class is somewhat different from that of other
- * <code>Map</code> implementations.
- *
- * <p> Both null values and the null key are supported. This class has the
- * same performance characteristics as the <code>HashMap</code> class, and has
- * the same efficiency parameters of <em>initial capacity</em> and <em>load
- * factor</em>.
- *
- * <p> Like most collection classes, this class is not synchronized. A
- * synchronized <code>SoftCache</code> may be constructed using the
- * <code>Collections.synchronizedMap</code> method.
- *
- * <p> In typical usage this class will be subclassed and the <code>fill</code>
- * method will be overridden. When the <code>get</code> method is invoked on a
- * key for which there is no mapping in the cache, it will in turn invoke the
- * <code>fill</code> method on that key in an attempt to construct a
- * corresponding value. If the <code>fill</code> method returns such a value
- * then the cache will be updated and the new value will be returned. Thus,
- * for example, a simple URL-content cache can be constructed as follows:
- *
- * <pre>
- * public class URLCache extends SoftCache {
- * protected Object fill(Object key) {
- * return ((URL)key).getContent();
- * }
- * }
- * </pre>
- *
- * <p> The behavior of the <code>SoftCache</code> class depends in part upon
- * the actions of the garbage collector, so several familiar (though not
- * required) <code>Map</code> invariants do not hold for this class. <p>
- * Because entries are removed from a <code>SoftCache</code> in response to
- * dynamic advice from the garbage collector, a <code>SoftCache</code> may
- * behave as though an unknown thread is silently removing entries. In
- * particular, even if you synchronize on a <code>SoftCache</code> instance and
- * invoke none of its mutator methods, it is possible for the <code>size</code>
- * method to return smaller values over time, for the <code>isEmpty</code>
- * method to return <code>false</code> and then <code>true</code>, for the
- * <code>containsKey</code> method to return <code>true</code> and later
- * <code>false</code> for a given key, for the <code>get</code> method to
- * return a value for a given key but later return <code>null</code>, for the
- * <code>put</code> method to return <code>null</code> and the
- * <code>remove</code> method to return <code>false</code> for a key that
- * previously appeared to be in the map, and for successive examinations of the
- * key set, the value set, and the entry set to yield successively smaller
- * numbers of elements.
- *
- * @author Mark Reinhold
- * @since 1.2
- * @see java.util.HashMap
- * @see java.lang.ref.SoftReference
- */
-
-
-public class SoftCache extends AbstractMap implements Map {
-
- /* The basic idea of this implementation is to maintain an internal HashMap
- that maps keys to soft references whose referents are the keys' values;
- the various accessor methods dereference these soft references before
- returning values. Because we don't have access to the innards of the
- HashMap, each soft reference must contain the key that maps to it so
- that the processQueue method can remove keys whose values have been
- discarded. Thus the HashMap actually maps keys to instances of the
- ValueCell class, which is a simple extension of the SoftReference class.
- */
-
-
- static private class ValueCell extends SoftReference {
- static private Object INVALID_KEY = new Object();
- static private int dropped = 0;
- private Object key;
-
- private ValueCell(Object key, Object value, ReferenceQueue queue) {
- super(value, queue);
- this.key = key;
- }
-
- private static ValueCell create(Object key, Object value,
- ReferenceQueue queue)
- {
- if (value == null) return null;
- return new ValueCell(key, value, queue);
- }
-
- private static Object strip(Object val, boolean drop) {
- if (val == null) return null;
- ValueCell vc = (ValueCell)val;
- Object o = vc.get();
- if (drop) vc.drop();
- return o;
- }
-
- private boolean isValid() {
- return (key != INVALID_KEY);
- }
-
- private void drop() {
- super.clear();
- key = INVALID_KEY;
- dropped++;
- }
-
- }
-
-
- /* Hash table mapping keys to ValueCells */
- private Map hash;
-
- /* Reference queue for cleared ValueCells */
- private ReferenceQueue queue = new ReferenceQueue();
-
-
- /* Process any ValueCells that have been cleared and enqueued by the
- garbage collector. This method should be invoked once by each public
- mutator in this class. We don't invoke this method in public accessors
- because that can lead to surprising ConcurrentModificationExceptions.
- */
- private void processQueue() {
- ValueCell vc;
- while ((vc = (ValueCell)queue.poll()) != null) {
- if (vc.isValid()) hash.remove(vc.key);
- else ValueCell.dropped--;
- }
- }
-
-
- /* -- Constructors -- */
-
- /**
- * Construct a new, empty <code>SoftCache</code> with the given
- * initial capacity and the given load factor.
- *
- * @param initialCapacity The initial capacity of the cache
- *
- * @param loadFactor A number between 0.0 and 1.0
- *
- * @throws IllegalArgumentException If the initial capacity is less than
- * or equal to zero, or if the load
- * factor is less than zero
- */
- public SoftCache(int initialCapacity, float loadFactor) {
- hash = new HashMap(initialCapacity, loadFactor);
- }
-
- /**
- * Construct a new, empty <code>SoftCache</code> with the given
- * initial capacity and the default load factor.
- *
- * @param initialCapacity The initial capacity of the cache
- *
- * @throws IllegalArgumentException If the initial capacity is less than
- * or equal to zero
- */
- public SoftCache(int initialCapacity) {
- hash = new HashMap(initialCapacity);
- }
-
- /**
- * Construct a new, empty <code>SoftCache</code> with the default
- * capacity and the default load factor.
- */
- public SoftCache() {
- hash = new HashMap();
- }
-
-
- /* -- Simple queries -- */
-
- /**
- * Return the number of key-value mappings in this cache. The time
- * required by this operation is linear in the size of the map.
- */
- public int size() {
- return entrySet().size();
- }
-
- /**
- * Return <code>true</code> if this cache contains no key-value mappings.
- */
- public boolean isEmpty() {
- return entrySet().isEmpty();
- }
-
- /**
- * Return <code>true</code> if this cache contains a mapping for the
- * specified key. If there is no mapping for the key, this method will not
- * attempt to construct one by invoking the <code>fill</code> method.
- *
- * @param key The key whose presence in the cache is to be tested
- */
- public boolean containsKey(Object key) {
- return ValueCell.strip(hash.get(key), false) != null;
- }
-
-
- /* -- Lookup and modification operations -- */
-
- /**
- * Create a value object for the given <code>key</code>. This method is
- * invoked by the <code>get</code> method when there is no entry for
- * <code>key</code>. If this method returns a non-<code>null</code> value,
- * then the cache will be updated to map <code>key</code> to that value,
- * and that value will be returned by the <code>get</code> method.
- *
- * <p> The default implementation of this method simply returns
- * <code>null</code> for every <code>key</code> value. A subclass may
- * override this method to provide more useful behavior.
- *
- * @param key The key for which a value is to be computed
- *
- * @return A value for <code>key</code>, or <code>null</code> if one
- * could not be computed
- * @see #get
- */
- protected Object fill(Object key) {
- return null;
- }
-
- /**
- * Return the value to which this cache maps the specified
- * <code>key</code>. If the cache does not presently contain a value for
- * this key, then invoke the <code>fill</code> method in an attempt to
- * compute such a value. If that method returns a non-<code>null</code>
- * value, then update the cache and return the new value. Otherwise,
- * return <code>null</code>.
- *
- * <p> Note that because this method may update the cache, it is considered
- * a mutator and may cause <code>ConcurrentModificationException</code>s to
- * be thrown if invoked while an iterator is in use.
- *
- * @param key The key whose associated value, if any, is to be returned
- *
- * @see #fill
- */
- public Object get(Object key) {
- processQueue();
- Object v = hash.get(key);
- if (v == null) {
- v = fill(key);
- if (v != null) {
- hash.put(key, ValueCell.create(key, v, queue));
- return v;
- }
- }
- return ValueCell.strip(v, false);
- }
-
- /**
- * Update this cache so that the given <code>key</code> maps to the given
- * <code>value</code>. If the cache previously contained a mapping for
- * <code>key</code> then that mapping is replaced and the old value is
- * returned.
- *
- * @param key The key that is to be mapped to the given
- * <code>value</code>
- * @param value The value to which the given <code>key</code> is to be
- * mapped
- *
- * @return The previous value to which this key was mapped, or
- * <code>null</code> if if there was no mapping for the key
- */
- public Object put(Object key, Object value) {
- processQueue();
- ValueCell vc = ValueCell.create(key, value, queue);
- return ValueCell.strip(hash.put(key, vc), true);
- }
-
- /**
- * Remove the mapping for the given <code>key</code> from this cache, if
- * present.
- *
- * @param key The key whose mapping is to be removed
- *
- * @return The value to which this key was mapped, or <code>null</code> if
- * there was no mapping for the key
- */
- public Object remove(Object key) {
- processQueue();
- return ValueCell.strip(hash.remove(key), true);
- }
-
- /**
- * Remove all mappings from this cache.
- */
- public void clear() {
- processQueue();
- hash.clear();
- }
-
-
- /* -- Views -- */
-
- private static boolean valEquals(Object o1, Object o2) {
- return (o1 == null) ? (o2 == null) : o1.equals(o2);
- }
-
-
- /* Internal class for entries.
- Because it uses SoftCache.this.queue, this class cannot be static.
- */
- private class Entry implements Map.Entry {
- private Map.Entry ent;
- private Object value; /* Strong reference to value, to prevent the GC
- from flushing the value while this Entry
- exists */
-
- Entry(Map.Entry ent, Object value) {
- this.ent = ent;
- this.value = value;
- }
-
- public Object getKey() {
- return ent.getKey();
- }
-
- public Object getValue() {
- return value;
- }
-
- public Object setValue(Object value) {
- return ent.setValue(ValueCell.create(ent.getKey(), value, queue));
- }
-
- public boolean equals(Object o) {
- if (! (o instanceof Map.Entry)) return false;
- Map.Entry e = (Map.Entry)o;
- return (valEquals(ent.getKey(), e.getKey())
- && valEquals(value, e.getValue()));
- }
-
- public int hashCode() {
- Object k;
- return ((((k = getKey()) == null) ? 0 : k.hashCode())
- ^ ((value == null) ? 0 : value.hashCode()));
- }
-
- }
-
-
- /* Internal class for entry sets */
- private class EntrySet extends AbstractSet {
- Set hashEntries = hash.entrySet();
-
- public Iterator iterator() {
-
- return new Iterator() {
- Iterator hashIterator = hashEntries.iterator();
- Entry next = null;
-
- public boolean hasNext() {
- while (hashIterator.hasNext()) {
- Map.Entry ent = (Map.Entry)hashIterator.next();
- ValueCell vc = (ValueCell)ent.getValue();
- Object v = null;
- if ((vc != null) && ((v = vc.get()) == null)) {
- /* Value has been flushed by GC */
- continue;
- }
- next = new Entry(ent, v);
- return true;
- }
- return false;
- }
-
- public Object next() {
- if ((next == null) && !hasNext())
- throw new NoSuchElementException();
- Entry e = next;
- next = null;
- return e;
- }
-
- public void remove() {
- hashIterator.remove();
- }
-
- };
- }
-
- public boolean isEmpty() {
- return !(iterator().hasNext());
- }
-
- public int size() {
- int j = 0;
- for (Iterator i = iterator(); i.hasNext(); i.next()) j++;
- return j;
- }
-
- public boolean remove(Object o) {
- processQueue();
- if (o instanceof Entry) return hashEntries.remove(((Entry)o).ent);
- else return false;
- }
-
- }
-
-
- private Set entrySet = null;
-
- /**
- * Return a <code>Set</code> view of the mappings in this cache.
- */
- public Set entrySet() {
- if (entrySet == null) entrySet = new EntrySet();
- return entrySet;
- }
-
-}
diff --git a/ojluni/src/main/java/sun/net/spi/nameservice/NameServiceDescriptor.java b/ojluni/src/main/java/sun/net/spi/nameservice/NameServiceDescriptor.java
deleted file mode 100644
index 6e246c5..0000000
--- a/ojluni/src/main/java/sun/net/spi/nameservice/NameServiceDescriptor.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2000, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.net.spi.nameservice;
-
-public interface NameServiceDescriptor {
- /**
- * Create a new instance of the corresponding name service.
- */
- public NameService createNameService () throws Exception ;
-
- /**
- * Returns this service provider's name
- *
- */
- public String getProviderName();
-
- /**
- * Returns this name service type
- * "dns" "nis" etc
- */
- public String getType();
-}
diff --git a/ojluni/src/main/java/sun/reflect/ConstructorAccessor.java b/ojluni/src/main/java/sun/reflect/ConstructorAccessor.java
deleted file mode 100644
index 7aac26f..0000000
--- a/ojluni/src/main/java/sun/reflect/ConstructorAccessor.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2001, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.reflect;
-
-import java.lang.reflect.InvocationTargetException;
-
-/** This interface provides the declaration for
- java.lang.reflect.Constructor.invoke(). Each Constructor object is
- configured with a (possibly dynamically-generated) class which
- implements this interface. */
-
-public interface ConstructorAccessor {
- /** Matches specification in {@link java.lang.reflect.Constructor} */
- public Object newInstance(Object[] args)
- throws InstantiationException,
- IllegalArgumentException,
- InvocationTargetException;
-}
diff --git a/ojluni/src/main/java/sun/reflect/package.html b/ojluni/src/main/java/sun/reflect/package.html
deleted file mode 100644
index 7f2bb85..0000000
--- a/ojluni/src/main/java/sun/reflect/package.html
+++ /dev/null
@@ -1,190 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<HTML>
-<HEAD>
-<!--
-
- Copyright (c) 2001, 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. Oracle designates this
- particular file as subject to the "Classpath" exception as provided
- by Oracle in the LICENSE file that accompanied this code.
-
- 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.
-
--->
-</HEAD>
-<BODY BGCOLOR="white">
-<P>
-
-<B> Licensee impact of JDK 1.4 reflection changes </B>
-
-</P>
-<P>
-
-Sun's JDK 1.4 contains a new implementation of java.lang.reflect which
-offers substantially higher performance than previous JDKs' native
-code. Licensees can at their discretion port these changes. There are
-no public API or documentation changes associated with the new
-reflection implementation aside from a few minor clarifications in the
-specifications of Method.invoke(), Constructor.newInstance(), and a
-few methods in java.lang.reflect.Field.
-
-</P>
-<P>
-
-The bulk of the new implementation is Java programming language code
-which generates bytecodes, and is therefore portable. If licensees
-desire to port it, the following JVM changes are required:
-
-<OL>
-<LI> The following four new JVM entry points must be added:
-
- <UL>
- <LI> JVM_GetClassDeclaredConstructors
- <LI> JVM_GetClassDeclaredFields
- <LI> JVM_GetClassDeclaredMethods
- <LI> JVM_GetClassAccessFlags
- </UL>
-
-The first three return the declared constructors, fields, and methods
-for a given class, with an option to return only the public ones. They
-are similar in functionality to the earlier GetClassConstructors,
-GetClassFields, and GetClassMethods. JVM_GetClassDeclaredFields and
-JVM_GetClassDeclaredMethods must intern the Strings for the names of
-the Field and Method objects returned. The fouth returns the access
-flags for a given class as marked in the class file, as opposed to in
-the InnerClasses attribute if the class is an inner class, and
-therefore differs from JVM_GetClassModifiers for inner classes (most
-importantly, protected inner classes; see 4471811.)
-
-<LI> The JVM's link resolver must be modified to allow all field and
-method references from subclasses of sun.reflect.MagicAccessorImpl to
-any other class (even to private members of other classes) to
-succeed. This allows setAccessible() and its associated checks to be
-implemented in Java.
-
-<LI> The code which calls the verifier must skip verification for all
-subclasses of sun.reflect.MagicAccessorImpl. (It was originally
-intended that only a subset of the stub classes used for serialization
-would not pass the verifier, specifically, those subclassing
-SerializationConstructorAccessorImpl; see 4486457 for a case where
-this does not work.)
-
-<LI> The stack walker for security checks must be modified to skip not
-only all Method.invoke() frames, but also any frames for which the
-class is a subclass of sun.reflect.MethodAccessorImpl.
-
-<LI> The JVM entry points JVM_InvokeMethod and
-JVM_NewInstanceFromConstructor are currently still used because the
-first invocation of the bytecode-based reflection is currently slower
-than the original native code. The security checks they perform can,
-however, be disabled, as they are now performed by Java programming
-language code.
-
-</OL>
-
-</P>
-<P>
-
-The following changes were discovered to be necessary for backward
-compatibility with certain applications (see bug 4474172):
-
-<OL>
-
-<LI> The existing JVM entry point JVM_LatestUserDefinedLoader
-(typically used in applications which rely on the 1.1 security
-framework) must skip reflection-related frames in its stack walk:
-specifically all frames associated with subclasses of
-sun.reflect.MethodAccessorImpl and
-sun.reflect.ConstructorAccessorImpl.
-
-<LI> The new reflection implementation can cause class loading to
-occur in previously-unexpected places (namely during reflective
-calls). This can cause class loaders which contain subtle bugs to
-break. In general it is not possible to guarantee complete backward
-bug compatibility, but one kind of bug has been observed more than
-once: the inability of a user-defined loader to handle delegation to
-it for a class it has already loaded. The new reflection
-implementation is predicated on delegation working properly, as it
-loads stub classes into newly-fabricated class loaders of type
-sun.reflect.DelegatingClassLoader, one stub class per loader, to allow
-unloading of the stub classes to occur more quickly. To handle this
-kind of bug, the JVM's internal class lookup mechanism must be
-slightly modified to check for instances of
-sun.reflect.DelegatingClassLoader as the incoming class loader and
-silently traverse the "parent" field once for such loaders before
-entering the bulk of the resolution code. This avoids an upcall to
-Java programming language code which certain loaders can not handle.
-
-</OL>
-
-</P>
-<P>
-
-The following JVM entry points may be deleted:
-
-<UL>
-<LI> JVM_GetClassFields
-<LI> JVM_GetClassMethods
-<LI> JVM_GetClassConstructors
-<LI> JVM_GetClassField
-<LI> JVM_GetClassMethod
-<LI> JVM_GetClassConstructor
-<LI> JVM_NewInstance
-<LI> JVM_GetField
-<LI> JVM_GetPrimitiveField
-<LI> JVM_SetField
-<LI> JVM_SetPrimitiveField
-</UL>
-
-</P>
-<P>
-
-To keep using the previous reflection implementation, licensees should
-not take changes from Sun's JDK 1.4 relating specifically to the
-implementation of reflection in the following classes/methods and
-any associated native code:
-
-<UL>
-<LI> java.lang.Class.newInstance0
-<LI> java.lang.Class.getClassLoader0
-<LI> java.lang.Class.getFields
-<LI> java.lang.Class.getMethods
-<LI> java.lang.Class.getDeclaredFields
-<LI> java.lang.Class.getDeclaredMethods
-<LI> java.lang.Class.getFields0
-<LI> java.lang.Class.getMethods0
-<LI> java.lang.Class.getConstructors0
-<LI> java.lang.Class.getField0
-<LI> java.lang.Class.getMethod0
-<LI> java.lang.Class.getConstructor0
-<LI> java.lang.ClassLoader.getCallerClassLoader
-<LI> java.lang.System.getCallerClass
-<LI> java.lang.reflect.AccessibleObject
-<LI> java.lang.reflect.Constructor
-<LI> java.lang.reflect.Field
-<LI> java.lang.reflect.Method
-<LI> java.lang.reflect.Modifier
-<LI> sun.misc.ClassReflector
-</UL>
-
-</P>
-<!-- Begin ANDROID changed -->
-</BODY>
-<!-- End ANDROID changed -->
-</HTML>
diff --git a/ojluni/src/main/java/sun/security/action/LoadLibraryAction.java b/ojluni/src/main/java/sun/security/action/LoadLibraryAction.java
deleted file mode 100644
index c351015..0000000
--- a/ojluni/src/main/java/sun/security/action/LoadLibraryAction.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 1998, 2006, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.security.action;
-
-/**
- * A convenience class for loading a system library as a privileged action.
- *
- * <p>An instance of this class can be used as the argument of
- * <code>AccessController.doPrivileged</code>.
- *
- * <p>The following code attempts to load the system library named
- * <code>"lib"</code> as a privileged action: <p>
- *
- * <pre>
- * java.security.AccessController.doPrivileged(new LoadLibraryAction("lib"));
- * </pre>
- *
- * @author Roland Schemers
- * @see java.security.PrivilegedAction
- * @see java.security.AccessController
- * @since 1.2
- */
-
-public class LoadLibraryAction implements java.security.PrivilegedAction<Void> {
- private String theLib;
-
- /**
- * Constructor that takes the name of the system library that needs to be
- * loaded.
- *
- * <p>The manner in which a library name is mapped to the
- * actual system library is system dependent.
- *
- * @param theLib the name of the library.
- */
- public LoadLibraryAction(String theLib) {
- this.theLib = theLib;
- }
-
- /**
- * Loads the system library whose name was specified in the constructor.
- */
- public Void run() {
- System.loadLibrary(theLib);
- return null;
- }
-}
diff --git a/ojluni/src/main/java/sun/util/calendar/TzIDOldMapping.java b/ojluni/src/main/java/sun/util/calendar/TzIDOldMapping.java
deleted file mode 100644
index 4f23007..0000000
--- a/ojluni/src/main/java/sun/util/calendar/TzIDOldMapping.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2008, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 sun.util.calendar;
-
-import java.util.Map;
-import java.util.HashMap;
-
-class TzIDOldMapping {
- static final Map<String, String> MAP = new HashMap<String, String>();
- static {
- String[][] oldmap = {
- { "ACT", "Australia/Darwin" },
- { "AET", "Australia/Sydney" },
- { "AGT", "America/Argentina/Buenos_Aires" },
- { "ART", "Africa/Cairo" },
- { "AST", "America/Anchorage" },
- { "BET", "America/Sao_Paulo" },
- { "BST", "Asia/Dhaka" },
- { "CAT", "Africa/Harare" },
- { "CNT", "America/St_Johns" },
- { "CST", "America/Chicago" },
- { "CTT", "Asia/Shanghai" },
- { "EAT", "Africa/Addis_Ababa" },
- { "ECT", "Europe/Paris" },
- { "EST", "America/New_York" },
- { "HST", "Pacific/Honolulu" },
- { "IET", "America/Indianapolis" },
- { "IST", "Asia/Calcutta" },
- { "JST", "Asia/Tokyo" },
- { "MIT", "Pacific/Apia" },
- { "MST", "America/Denver" },
- { "NET", "Asia/Yerevan" },
- { "NST", "Pacific/Auckland" },
- { "PLT", "Asia/Karachi" },
- { "PNT", "America/Phoenix" },
- { "PRT", "America/Puerto_Rico" },
- { "PST", "America/Los_Angeles" },
- { "SST", "Pacific/Guadalcanal" },
- { "VST", "Asia/Saigon" },
- };
- for (String[] pair : oldmap) {
- MAP.put(pair[0], pair[1]);
- }
- }
-}
diff --git a/ojluni/src/test/java/time/tck/java/time/TCKInstant.java b/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
index 3d89db5..1b8fea7 100644
--- a/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
+++ b/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
@@ -1931,6 +1931,16 @@
Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1).toEpochMilli();
}
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void test_toEpochMillis_overflow() {
+ Instant.ofEpochSecond(Long.MAX_VALUE / 1000, 809_000_000).toEpochMilli();
+ }
+
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void test_toEpochMillis_overflow2() {
+ Instant.ofEpochSecond(-9223372036854776L, 1).toEpochMilli();
+ }
+
//-----------------------------------------------------------------------
// compareTo()
//-----------------------------------------------------------------------
diff --git a/ojluni/src/test/java/time/test/java/time/TestInstant.java b/ojluni/src/test/java/time/test/java/time/TestInstant.java
index cf135a1..203bb57 100644
--- a/ojluni/src/test/java/time/test/java/time/TestInstant.java
+++ b/ojluni/src/test/java/time/test/java/time/TestInstant.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, 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
@@ -62,6 +62,8 @@
import java.time.Instant;
import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.assertEquals;
/**
* Test Instant.
@@ -74,4 +76,24 @@
assertImmutable(Instant.class);
}
+ @DataProvider(name="sampleEpochMillis")
+ private Object[][] provider_sampleEpochMillis() {
+ return new Object[][] {
+ {"Long.MAX_VALUE", Long.MAX_VALUE},
+ {"Long.MAX_VALUE-1", Long.MAX_VALUE - 1},
+ {"1", 1L},
+ {"0", 0L},
+ {"-1", -1L},
+ {"Long.MIN_VALUE+1", Long.MIN_VALUE + 1},
+ {"Long.MIN_VALUE", Long.MIN_VALUE}
+ };
+ }
+
+ @Test(dataProvider="sampleEpochMillis")
+ public void test_epochMillis(String name, long millis) {
+ Instant t1 = Instant.ofEpochMilli(millis);
+ long m = t1.toEpochMilli();
+ assertEquals(millis, m, name);
+ }
+
}
diff --git a/ojluni/src/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java b/ojluni/src/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java
index 9fbe6d1..ab61c71 100644
--- a/ojluni/src/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java
+++ b/ojluni/src/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java
@@ -30,6 +30,7 @@
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoField.YEAR;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
@@ -530,6 +531,23 @@
assertEquals(date.isLeapYear(), leapyear);
}
+ // Data provider to verify that a given hijrah year is outside the range of supported years
+ // The values are dependent on the currently configured UmmAlQura calendar data
+ @DataProvider(name="OutOfRangeLeapYears")
+ Object[][] data_invalid_leapyears() {
+ return new Object[][] {
+ {1299},
+ {1601},
+ {Integer.MAX_VALUE},
+ {Integer.MIN_VALUE},
+ };
+ }
+
+ @Test(dataProvider="OutOfRangeLeapYears")
+ public void test_notLeapYears(int y) {
+ assertFalse(HijrahChronology.INSTANCE.isLeapYear(y), "Out of range leap year");
+ }
+
// Date samples to convert HijrahDate to LocalDate and vice versa
@DataProvider(name="samples")
Object[][] data_samples() {
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index a64b131..50c4b84 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -800,7 +800,6 @@
ojluni/src/main/java/java/time/Duration.java \
ojluni/src/main/java/java/time/LocalDateTime.java \
ojluni/src/main/java/java/time/OffsetDateTime.java \
- ojluni/src/main/java/java/time/overview.html \
ojluni/src/main/java/java/time/Instant.java \
ojluni/src/main/java/java/time/temporal/ValueRange.java \
ojluni/src/main/java/java/time/temporal/TemporalAmount.java \
@@ -1357,7 +1356,6 @@
ojluni/src/main/java/jdk/net/NetworkPermission.java \
ojluni/src/main/java/jdk/net/SocketFlow.java \
ojluni/src/main/java/jdk/net/Sockets.java \
- ojluni/src/main/java/sun/invoke/empty/Empty.java \
ojluni/src/main/java/sun/invoke/util/BytecodeDescriptor.java \
ojluni/src/main/java/sun/invoke/util/Wrapper.java \
ojluni/src/main/java/sun/invoke/util/VerifyAccess.java \
@@ -1381,7 +1379,6 @@
ojluni/src/main/java/sun/misc/IOUtils.java \
ojluni/src/main/java/sun/misc/JarIndex.java \
ojluni/src/main/java/sun/misc/JavaIOFileDescriptorAccess.java \
- ojluni/src/main/java/sun/misc/JavaSecurityProtectionDomainAccess.java \
ojluni/src/main/java/sun/misc/LRUCache.java \
ojluni/src/main/java/sun/misc/MessageUtils.java \
ojluni/src/main/java/sun/misc/MetaIndex.java \
@@ -1389,10 +1386,7 @@
ojluni/src/main/java/sun/misc/RegexpPool.java \
ojluni/src/main/java/sun/misc/RegexpTarget.java \
ojluni/src/main/java/sun/misc/Resource.java \
- ojluni/src/main/java/sun/misc/ServiceConfigurationError.java \
ojluni/src/main/java/sun/misc/SharedSecrets.java \
- ojluni/src/main/java/sun/misc/Service.java \
- ojluni/src/main/java/sun/misc/SoftCache.java \
ojluni/src/main/java/sun/misc/URLClassPath.java \
ojluni/src/main/java/sun/misc/Unsafe.java \
ojluni/src/main/java/sun/misc/Version.java \
@@ -1420,7 +1414,6 @@
ojluni/src/main/java/sun/net/ResourceManager.java \
ojluni/src/main/java/sun/net/SocksProxy.java \
ojluni/src/main/java/sun/net/spi/DefaultProxySelector.java \
- ojluni/src/main/java/sun/net/spi/nameservice/NameServiceDescriptor.java \
ojluni/src/main/java/sun/net/spi/nameservice/NameService.java \
ojluni/src/main/java/sun/net/TelnetInputStream.java \
ojluni/src/main/java/sun/net/TelnetOutputStream.java \
@@ -1556,13 +1549,11 @@
ojluni/src/main/java/sun/nio/fs/UnixUriUtils.java \
ojluni/src/main/java/sun/nio/fs/UnixUserPrincipals.java \
ojluni/src/main/java/sun/nio/fs/Util.java \
- ojluni/src/main/java/sun/reflect/ConstructorAccessor.java \
ojluni/src/main/java/sun/reflect/misc/ReflectUtil.java \
ojluni/src/main/java/sun/reflect/Reflection.java \
ojluni/src/main/java/sun/security/action/GetBooleanAction.java \
ojluni/src/main/java/sun/security/action/GetIntegerAction.java \
ojluni/src/main/java/sun/security/action/GetPropertyAction.java \
- ojluni/src/main/java/sun/security/action/LoadLibraryAction.java \
ojluni/src/main/java/sun/security/jca/GetInstance.java \
ojluni/src/main/java/sun/security/jca/JCAUtil.java \
ojluni/src/main/java/sun/security/jca/ProviderConfig.java \
@@ -1721,7 +1712,6 @@
ojluni/src/main/java/sun/util/calendar/ImmutableGregorianDate.java \
ojluni/src/main/java/sun/util/calendar/JulianCalendar.java \
ojluni/src/main/java/sun/util/calendar/LocalGregorianCalendar.java \
- ojluni/src/main/java/sun/util/calendar/TzIDOldMapping.java \
ojluni/src/main/java/sun/util/locale/BaseLocale.java \
ojluni/src/main/java/sun/util/locale/Extension.java \
ojluni/src/main/java/sun/util/locale/InternalLocaleBuilder.java \
diff --git a/tzdata/update2/src/main/libcore/tzdata/update2/BundleVersion.java b/tzdata/update2/src/main/libcore/tzdata/update2/BundleVersion.java
index 1889f18..775846f 100644
--- a/tzdata/update2/src/main/libcore/tzdata/update2/BundleVersion.java
+++ b/tzdata/update2/src/main/libcore/tzdata/update2/BundleVersion.java
@@ -28,7 +28,8 @@
/**
* The major bundle format version supported by this device.
- * Increment this for non-backwards compatible changes to the bundle format.
+ * Increment this for non-backwards compatible changes to the bundle format. Reset the minor
+ * version to 1 when doing so.
*/
public static final int CURRENT_FORMAT_MAJOR_VERSION = 1;
@@ -189,8 +190,9 @@
}
private static int validate3DigitVersion(int value) throws BundleException {
- if (value < 1 || value > 999) {
- throw new BundleException("Expected 1 <= value <= 999, was " + value);
+ // 0 is allowed but is reserved for testing.
+ if (value < 0 || value > 999) {
+ throw new BundleException("Expected 0 <= value <= 999, was " + value);
}
return value;
}
diff --git a/tzdata/update2/src/test/libcore/tzdata/update2/BundleVersionTest.java b/tzdata/update2/src/test/libcore/tzdata/update2/BundleVersionTest.java
index 3c2bff8..fe9023e 100644
--- a/tzdata/update2/src/test/libcore/tzdata/update2/BundleVersionTest.java
+++ b/tzdata/update2/src/test/libcore/tzdata/update2/BundleVersionTest.java
@@ -20,7 +20,7 @@
public class BundleVersionTest extends TestCase {
- private static final int INVALID_VERSION_LOW = 0;
+ private static final int INVALID_VERSION_LOW = -1;
private static final int VALID_VERSION = 23;
private static final int INVALID_VERSION_HIGH = 1000;
private static final String VALID_RULES_VERSION = "2016a";
@@ -79,19 +79,20 @@
BundleVersion.CURRENT_FORMAT_MINOR_VERSION + 1);
assertTrue(BundleVersion.isCompatibleWithThisDevice(newerMinor));
- if (BundleVersion.CURRENT_FORMAT_MAJOR_VERSION > 1) {
- BundleVersion olderMajor = createBundleVersion(
- BundleVersion.CURRENT_FORMAT_MAJOR_VERSION - 1,
- BundleVersion.CURRENT_FORMAT_MINOR_VERSION);
- assertFalse(BundleVersion.isCompatibleWithThisDevice(olderMajor));
- }
+ // The constant versions should never be below 1. We allow 0 but want to start version
+ // numbers at 1 to allow testing of older version logic.
+ assertTrue(BundleVersion.CURRENT_FORMAT_MAJOR_VERSION >= 1);
+ assertTrue(BundleVersion.CURRENT_FORMAT_MINOR_VERSION >= 1);
- if (BundleVersion.CURRENT_FORMAT_MINOR_VERSION > 1) {
- BundleVersion olderMinor = createBundleVersion(
- BundleVersion.CURRENT_FORMAT_MAJOR_VERSION,
- BundleVersion.CURRENT_FORMAT_MINOR_VERSION - 1);
- assertFalse(BundleVersion.isCompatibleWithThisDevice(olderMinor));
- }
+ BundleVersion olderMajor = createBundleVersion(
+ BundleVersion.CURRENT_FORMAT_MAJOR_VERSION - 1,
+ BundleVersion.CURRENT_FORMAT_MINOR_VERSION);
+ assertFalse(BundleVersion.isCompatibleWithThisDevice(olderMajor));
+
+ BundleVersion olderMinor = createBundleVersion(
+ BundleVersion.CURRENT_FORMAT_MAJOR_VERSION,
+ BundleVersion.CURRENT_FORMAT_MINOR_VERSION - 1);
+ assertFalse(BundleVersion.isCompatibleWithThisDevice(olderMinor));
}
private BundleVersion createBundleVersion(int majorFormatVersion, int minorFormatVersion)