Merge
This commit is contained in:
commit
3c1a419a4e
@ -393,3 +393,4 @@ a22e2671d88f6b22a4aa82e3966986542ed2a381 jdk-9+146
|
||||
3ffc3e886c74736e387f3685e86b557cdea706c8 jdk-9+148
|
||||
b119012d1c2ab2570fe8718633840d0c1f1f441d jdk-9+149
|
||||
6234069ff9789f7582e1faa32cb6283cbd1a5a2d jdk-9+150
|
||||
71a766d4c18041a7f833ee22823125b02e1a7f1e jdk-9+151
|
||||
|
@ -147,15 +147,6 @@ AC_DEFUN_ONCE([FLAGS_SETUP_USER_SUPPLIED_FLAGS],
|
||||
EXTRA_CXXFLAGS="$with_extra_cxxflags"
|
||||
EXTRA_LDFLAGS="$with_extra_ldflags"
|
||||
|
||||
# Hotspot needs these set in their legacy form
|
||||
LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $EXTRA_CFLAGS"
|
||||
LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $EXTRA_CXXFLAGS"
|
||||
LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS $EXTRA_LDFLAGS"
|
||||
|
||||
AC_SUBST(LEGACY_EXTRA_CFLAGS)
|
||||
AC_SUBST(LEGACY_EXTRA_CXXFLAGS)
|
||||
AC_SUBST(LEGACY_EXTRA_LDFLAGS)
|
||||
|
||||
AC_SUBST(EXTRA_CFLAGS)
|
||||
AC_SUBST(EXTRA_CXXFLAGS)
|
||||
AC_SUBST(EXTRA_LDFLAGS)
|
||||
@ -192,10 +183,6 @@ AC_DEFUN([FLAGS_SETUP_SYSROOT_FLAGS],
|
||||
$1SYSROOT_CFLAGS="-isysroot [$]$1SYSROOT"
|
||||
$1SYSROOT_LDFLAGS="-isysroot [$]$1SYSROOT"
|
||||
fi
|
||||
# Propagate the sysroot args to hotspot
|
||||
$1LEGACY_EXTRA_CFLAGS="[$]$1LEGACY_EXTRA_CFLAGS [$]$1SYSROOT_CFLAGS"
|
||||
$1LEGACY_EXTRA_CXXFLAGS="[$]$1LEGACY_EXTRA_CXXFLAGS [$]$1SYSROOT_CFLAGS"
|
||||
$1LEGACY_EXTRA_LDFLAGS="[$]$1LEGACY_EXTRA_LDFLAGS [$]$1SYSROOT_LDFLAGS"
|
||||
# The global CFLAGS and LDFLAGS variables need these for configure to function
|
||||
$1CFLAGS="[$]$1CFLAGS [$]$1SYSROOT_CFLAGS"
|
||||
$1CPPFLAGS="[$]$1CPPFLAGS [$]$1SYSROOT_CFLAGS"
|
||||
|
@ -854,9 +854,6 @@ SYSROOT_CFLAGS
|
||||
EXTRA_LDFLAGS
|
||||
EXTRA_CXXFLAGS
|
||||
EXTRA_CFLAGS
|
||||
LEGACY_EXTRA_LDFLAGS
|
||||
LEGACY_EXTRA_CXXFLAGS
|
||||
LEGACY_EXTRA_CFLAGS
|
||||
EXE_SUFFIX
|
||||
OBJ_SUFFIX
|
||||
STATIC_LIBRARY
|
||||
@ -5170,7 +5167,7 @@ VS_SDK_PLATFORM_NAME_2013=
|
||||
#CUSTOM_AUTOCONF_INCLUDE
|
||||
|
||||
# Do not change or remove the following line, it is needed for consistency checks:
|
||||
DATE_WHEN_GENERATED=1482828098
|
||||
DATE_WHEN_GENERATED=1483542685
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
@ -31290,8 +31287,6 @@ $as_echo "yes" >&6; }
|
||||
as_fn_error $? "--enable-static-build is only supported for macosx builds" "$LINENO" 5
|
||||
fi
|
||||
STATIC_BUILD_CFLAGS="-DSTATIC_BUILD=1"
|
||||
LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $STATIC_BUILD_CFLAGS"
|
||||
LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $STATIC_BUILD_CFLAGS"
|
||||
CFLAGS_JDKLIB_EXTRA="$CFLAGS_JDKLIB_EXTRA $STATIC_BUILD_CFLAGS"
|
||||
CXXFLAGS_JDKLIB_EXTRA="$CXXFLAGS_JDKLIB_EXTRA $STATIC_BUILD_CFLAGS"
|
||||
STATIC_BUILD=true
|
||||
@ -31493,15 +31488,6 @@ fi
|
||||
EXTRA_CXXFLAGS="$with_extra_cxxflags"
|
||||
EXTRA_LDFLAGS="$with_extra_ldflags"
|
||||
|
||||
# Hotspot needs these set in their legacy form
|
||||
LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $EXTRA_CFLAGS"
|
||||
LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $EXTRA_CXXFLAGS"
|
||||
LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS $EXTRA_LDFLAGS"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -31533,10 +31519,6 @@ fi
|
||||
SYSROOT_CFLAGS="-isysroot $SYSROOT"
|
||||
SYSROOT_LDFLAGS="-isysroot $SYSROOT"
|
||||
fi
|
||||
# Propagate the sysroot args to hotspot
|
||||
LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $SYSROOT_CFLAGS"
|
||||
LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $SYSROOT_CFLAGS"
|
||||
LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS $SYSROOT_LDFLAGS"
|
||||
# The global CFLAGS and LDFLAGS variables need these for configure to function
|
||||
CFLAGS="$CFLAGS $SYSROOT_CFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $SYSROOT_CFLAGS"
|
||||
@ -44053,10 +44035,6 @@ $as_echo "$BUILD_DEVKIT_ROOT" >&6; }
|
||||
BUILD_SYSROOT_CFLAGS="-isysroot $BUILD_SYSROOT"
|
||||
BUILD_SYSROOT_LDFLAGS="-isysroot $BUILD_SYSROOT"
|
||||
fi
|
||||
# Propagate the sysroot args to hotspot
|
||||
BUILD_LEGACY_EXTRA_CFLAGS="$BUILD_LEGACY_EXTRA_CFLAGS $BUILD_SYSROOT_CFLAGS"
|
||||
BUILD_LEGACY_EXTRA_CXXFLAGS="$BUILD_LEGACY_EXTRA_CXXFLAGS $BUILD_SYSROOT_CFLAGS"
|
||||
BUILD_LEGACY_EXTRA_LDFLAGS="$BUILD_LEGACY_EXTRA_LDFLAGS $BUILD_SYSROOT_LDFLAGS"
|
||||
# The global CFLAGS and LDFLAGS variables need these for configure to function
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS $BUILD_SYSROOT_CFLAGS"
|
||||
BUILD_CPPFLAGS="$BUILD_CPPFLAGS $BUILD_SYSROOT_CFLAGS"
|
||||
@ -52779,9 +52757,8 @@ $as_echo_n "checking if native coverage is enabled... " >&6; }
|
||||
$as_echo "yes" >&6; }
|
||||
GCOV_CFLAGS="-fprofile-arcs -ftest-coverage -fno-inline"
|
||||
GCOV_LDFLAGS="-fprofile-arcs"
|
||||
LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $GCOV_CFLAGS"
|
||||
LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $GCOV_CFLAGS"
|
||||
LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS $GCOV_LDFLAGS"
|
||||
JVM_CFLAGS="$JVM_CFLAGS $GCOV_CFLAGS"
|
||||
JVM_LDFLAGS="$JVM_LDFLAGS $GCOV_LDFLAGS"
|
||||
CFLAGS_JDKLIB="$CFLAGS_JDKLIB $GCOV_CFLAGS"
|
||||
CFLAGS_JDKEXE="$CFLAGS_JDKEXE $GCOV_CFLAGS"
|
||||
CXXFLAGS_JDKLIB="$CXXFLAGS_JDKLIB $GCOV_CFLAGS"
|
||||
@ -52982,7 +52959,7 @@ $as_echo "yes, forced" >&6; }
|
||||
$as_echo "no, forced" >&6; }
|
||||
BUILD_GTEST="false"
|
||||
elif test "x$enable_hotspot_gtest" = "x"; then
|
||||
if test "x$GTEST_DIR_EXISTS" = "xtrue" && test "x$OPENJDK_TARGET_OS" != "xaix"; then
|
||||
if test "x$GTEST_DIR_EXISTS" = "xtrue"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
BUILD_GTEST="true"
|
||||
|
@ -320,9 +320,8 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_CODE_COVERAGE],
|
||||
AC_MSG_RESULT([yes])
|
||||
GCOV_CFLAGS="-fprofile-arcs -ftest-coverage -fno-inline"
|
||||
GCOV_LDFLAGS="-fprofile-arcs"
|
||||
LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $GCOV_CFLAGS"
|
||||
LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $GCOV_CFLAGS"
|
||||
LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS $GCOV_LDFLAGS"
|
||||
JVM_CFLAGS="$JVM_CFLAGS $GCOV_CFLAGS"
|
||||
JVM_LDFLAGS="$JVM_LDFLAGS $GCOV_LDFLAGS"
|
||||
CFLAGS_JDKLIB="$CFLAGS_JDKLIB $GCOV_CFLAGS"
|
||||
CFLAGS_JDKEXE="$CFLAGS_JDKEXE $GCOV_CFLAGS"
|
||||
CXXFLAGS_JDKLIB="$CXXFLAGS_JDKLIB $GCOV_CFLAGS"
|
||||
@ -360,8 +359,6 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_STATIC_BUILD],
|
||||
AC_MSG_ERROR([--enable-static-build is only supported for macosx builds])
|
||||
fi
|
||||
STATIC_BUILD_CFLAGS="-DSTATIC_BUILD=1"
|
||||
LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $STATIC_BUILD_CFLAGS"
|
||||
LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $STATIC_BUILD_CFLAGS"
|
||||
CFLAGS_JDKLIB_EXTRA="$CFLAGS_JDKLIB_EXTRA $STATIC_BUILD_CFLAGS"
|
||||
CXXFLAGS_JDKLIB_EXTRA="$CXXFLAGS_JDKLIB_EXTRA $STATIC_BUILD_CFLAGS"
|
||||
STATIC_BUILD=true
|
||||
|
@ -263,6 +263,7 @@ var getJibProfilesCommon = function (input, data) {
|
||||
labels: "open"
|
||||
};
|
||||
|
||||
common.configure_args_64bit = ["--with-target-bits=64"];
|
||||
common.configure_args_32bit = ["--with-target-bits=32"];
|
||||
|
||||
/**
|
||||
@ -419,7 +420,7 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
target_os: "linux",
|
||||
target_cpu: "x64",
|
||||
dependencies: ["devkit"],
|
||||
configure_args: ["--with-zlib=system"],
|
||||
configure_args: concat(common.configure_args_64bit, "--with-zlib=system"),
|
||||
default_make_targets: ["docs-bundles"],
|
||||
},
|
||||
|
||||
@ -436,27 +437,30 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
target_os: "macosx",
|
||||
target_cpu: "x64",
|
||||
dependencies: ["devkit"],
|
||||
configure_args: concat(common.configure_args, "--with-zlib=system"),
|
||||
configure_args: concat(common.configure_args_64bit, "--with-zlib=system"),
|
||||
},
|
||||
|
||||
"solaris-x64": {
|
||||
target_os: "solaris",
|
||||
target_cpu: "x64",
|
||||
dependencies: ["devkit", "cups"],
|
||||
configure_args: ["--with-zlib=system", "--enable-dtrace"],
|
||||
configure_args: concat(common.configure_args_64bit,
|
||||
"--with-zlib=system", "--enable-dtrace"),
|
||||
},
|
||||
|
||||
"solaris-sparcv9": {
|
||||
target_os: "solaris",
|
||||
target_cpu: "sparcv9",
|
||||
dependencies: ["devkit", "cups"],
|
||||
configure_args: ["--with-zlib=system", "--enable-dtrace"],
|
||||
configure_args: concat(common.configure_args_64bit,
|
||||
"--with-zlib=system", "--enable-dtrace"),
|
||||
},
|
||||
|
||||
"windows-x64": {
|
||||
target_os: "windows",
|
||||
target_cpu: "x64",
|
||||
dependencies: ["devkit", "freetype"],
|
||||
configure_args: concat(common.configure_args_64bit),
|
||||
},
|
||||
|
||||
"windows-x86": {
|
||||
@ -518,11 +522,11 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
target_os: "linux",
|
||||
target_cpu: "x64",
|
||||
dependencies: ["devkit"],
|
||||
configure_args: [
|
||||
configure_args: concat(common.configure_args_64bit, [
|
||||
"--with-zlib=system",
|
||||
"--with-jvm-variants=zero",
|
||||
"--enable-libffi-bundling"
|
||||
]
|
||||
])
|
||||
},
|
||||
|
||||
"linux-x86-zero": {
|
||||
|
@ -393,3 +393,4 @@ dc49e0922a8e4387cbf8670bbe1dc51c9874b74b jdk-9+147
|
||||
f95cc86b6ac22ec1ade5d4f825dc7782adeea228 jdk-9+148
|
||||
00b19338e505690abe93d5995ed74a473d969c2c jdk-9+149
|
||||
9205e980062a5c4530b51021c6e274025f4ccbdf jdk-9+150
|
||||
77f827f5bbad3ef795664bc675f72d98d156b9f8 jdk-9+151
|
||||
|
@ -553,3 +553,4 @@ a82cb5350cad96a0b4de496afebe3ded89f27efa jdk-9+146
|
||||
5e4e893520ecdbd517c6ed6375f0885664fe62c4 jdk-9+148
|
||||
30e1996bd55da36183434f24ed964adebf9ca71e jdk-9+149
|
||||
98fe046473c90204cbc9b34c512b9fc10dfb8479 jdk-9+150
|
||||
2a2ac7d9f52c8cb2b80077e515b5840b947e640c jdk-9+151
|
||||
|
@ -49,6 +49,7 @@ else
|
||||
DEST := $(JDK_OUTPUTDIR)/lib, \
|
||||
FILES := $(filter-out %$(SHARED_LIBRARY_SUFFIX), $(LIB_TARGETS)), \
|
||||
MACRO := link-file-relative, \
|
||||
LOG_ACTION := Creating symlink, \
|
||||
))
|
||||
|
||||
TARGETS += $(COPY_LIBS) $(LINK_LIBS)
|
||||
|
@ -393,3 +393,4 @@ ce81d03ad7320dca3d673374c1a33bc0efd9136a jdk-9+143
|
||||
c45db75bfe8bc20bb80b4a009ae3f69c9cd2d885 jdk-9+148
|
||||
5978df8bfa3894f2b3d07b7256f25f78dffb1f9c jdk-9+149
|
||||
f85154af719f99a3b4d81b67a8b4c18a650d10f9 jdk-9+150
|
||||
13c6906bfc861d99dc35a19c80b7a99f0b0ac58d jdk-9+151
|
||||
|
@ -393,3 +393,4 @@ c41140100bf1e5c10c7b8f3bde91c16eff7485f5 jdk-9+147
|
||||
9098b2b9d997d65af0026fc2f39cf75234e26bc5 jdk-9+148
|
||||
5a846396a24c7aff01d6a8feaa7afc0a6369f04d jdk-9+149
|
||||
71e198ef3839045e829a879af1d709be16ab0f88 jdk-9+150
|
||||
d27bab22ff62823902d93d1d35ca397cfd50d059 jdk-9+151
|
||||
|
@ -532,11 +532,13 @@ public final class FilePermission extends Permission implements Serializable {
|
||||
* simple {@code npath} is inside a wildcard {@code npath} if and only if
|
||||
* {@code simple_npath.relativize(wildcard_npath)} is exactly "..",
|
||||
* a simple {@code npath} is recursively inside a wildcard {@code npath}
|
||||
* if and only if {@code simple_npath.relativize(wildcard_npath)}
|
||||
* is a series of one or more "..". An invalid {@code FilePermission} does
|
||||
* not imply any object except for itself. An invalid {@code FilePermission}
|
||||
* is not implied by any object except for itself or a {@code FilePermission}
|
||||
* on {@literal "<<ALL FILES>>"} whose actions is a superset of this
|
||||
* if and only if {@code simple_npath.relativize(wildcard_npath)} is a
|
||||
* series of one or more "..". This means "/-" implies "/foo" but not "foo".
|
||||
* <p>
|
||||
* An invalid {@code FilePermission} does not imply any object except for
|
||||
* itself. An invalid {@code FilePermission} is not implied by any object
|
||||
* except for itself or a {@code FilePermission} on
|
||||
* {@literal "<<ALL FILES>>"} whose actions is a superset of this
|
||||
* invalid {@code FilePermission}. Even if two {@code FilePermission}
|
||||
* are created with the same invalid path, one does not imply the other.
|
||||
*
|
||||
|
@ -26,8 +26,6 @@
|
||||
package java.lang;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.module.ModuleDescriptor.Version;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReader;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.io.IOException;
|
||||
@ -42,7 +40,6 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.GenericDeclaration;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Layer;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
@ -54,7 +51,6 @@ import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@ -62,19 +58,15 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.loader.BootLoader;
|
||||
import jdk.internal.loader.BuiltinClassLoader;
|
||||
import jdk.internal.loader.ResourceHelper;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.misc.VM;
|
||||
import jdk.internal.module.ModuleHashes;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.ConstantPool;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
@ -532,7 +524,8 @@ public final class Class<T> implements java.io.Serializable,
|
||||
}
|
||||
try {
|
||||
Class<?>[] empty = {};
|
||||
final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
|
||||
final Constructor<T> c = getReflectionFactory().copyConstructor(
|
||||
getConstructor0(empty, Member.DECLARED));
|
||||
// Disable accessibility checks on the constructor
|
||||
// since we have to do the security check here anyway
|
||||
// (the stack depth is wrong for the Constructor's
|
||||
@ -1024,6 +1017,11 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* @return an array of interfaces directly implemented by this class
|
||||
*/
|
||||
public Class<?>[] getInterfaces() {
|
||||
// defensively copy before handing over to user code
|
||||
return getInterfaces(true);
|
||||
}
|
||||
|
||||
private Class<?>[] getInterfaces(boolean cloneArray) {
|
||||
ReflectionData<T> rd = reflectionData();
|
||||
if (rd == null) {
|
||||
// no cloning required
|
||||
@ -1034,8 +1032,8 @@ public final class Class<T> implements java.io.Serializable,
|
||||
interfaces = getInterfaces0();
|
||||
rd.interfaces = interfaces;
|
||||
}
|
||||
// defensively copy before handing over to user code
|
||||
return interfaces.clone();
|
||||
// defensively copy if requested
|
||||
return cloneArray ? interfaces.clone() : interfaces;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1767,15 +1765,6 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* Class} object, including those declared by the class or interface and
|
||||
* those inherited from superclasses and superinterfaces.
|
||||
*
|
||||
* <p> If this {@code Class} object represents a type that has multiple
|
||||
* public methods with the same name and parameter types, but different
|
||||
* return types, then the returned array has a {@code Method} object for
|
||||
* each such method.
|
||||
*
|
||||
* <p> If this {@code Class} object represents a type with a class
|
||||
* initialization method {@code <clinit>}, then the returned array does
|
||||
* <em>not</em> have a corresponding {@code Method} object.
|
||||
*
|
||||
* <p> If this {@code Class} object represents an array type, then the
|
||||
* returned array has a {@code Method} object for each of the public
|
||||
* methods inherited by the array type from {@code Object}. It does not
|
||||
@ -1788,16 +1777,54 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* has length 0. (Note that a {@code Class} object which represents a class
|
||||
* always has public methods, inherited from {@code Object}.)
|
||||
*
|
||||
* <p> If this {@code Class} object represents a primitive type or void,
|
||||
* then the returned array has length 0.
|
||||
*
|
||||
* <p> Static methods declared in superinterfaces of the class or interface
|
||||
* represented by this {@code Class} object are not considered members of
|
||||
* the class or interface.
|
||||
* <p> The returned array never contains methods with names "{@code <init>}"
|
||||
* or "{@code <clinit>}".
|
||||
*
|
||||
* <p> The elements in the returned array are not sorted and are not in any
|
||||
* particular order.
|
||||
*
|
||||
* <p> Generally, the result is computed as with the following 4 step algorithm.
|
||||
* Let C be the class or interface represented by this {@code Class} object:
|
||||
* <ol>
|
||||
* <li> A union of methods is composed of:
|
||||
* <ol type="a">
|
||||
* <li> C's declared public instance and static methods as returned by
|
||||
* {@link #getDeclaredMethods()} and filtered to include only public
|
||||
* methods.</li>
|
||||
* <li> If C is a class other than {@code Object}, then include the result
|
||||
* of invoking this algorithm recursively on the superclass of C.</li>
|
||||
* <li> Include the results of invoking this algorithm recursively on all
|
||||
* direct superinterfaces of C, but include only instance methods.</li>
|
||||
* </ol></li>
|
||||
* <li> Union from step 1 is partitioned into subsets of methods with same
|
||||
* signature (name, parameter types) and return type.</li>
|
||||
* <li> Within each such subset only the most specific methods are selected.
|
||||
* Let method M be a method from a set of methods with same signature
|
||||
* and return type. M is most specific if there is no such method
|
||||
* N != M from the same set, such that N is more specific than M.
|
||||
* N is more specific than M if:
|
||||
* <ol type="a">
|
||||
* <li> N is declared by a class and M is declared by an interface; or</li>
|
||||
* <li> N and M are both declared by classes or both by interfaces and
|
||||
* N's declaring type is the same as or a subtype of M's declaring type
|
||||
* (clearly, if M's and N's declaring types are the same type, then
|
||||
* M and N are the same method).</li>
|
||||
* </ol></li>
|
||||
* <li> The result of this algorithm is the union of all selected methods from
|
||||
* step 3.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @apiNote There may be more than one method with a particular name
|
||||
* and parameter types in a class because while the Java language forbids a
|
||||
* class to declare multiple methods with the same signature but different
|
||||
* return types, the Java virtual machine does not. This
|
||||
* increased flexibility in the virtual machine can be used to
|
||||
* implement various language features. For example, covariant
|
||||
* returns can be implemented with {@linkplain
|
||||
* java.lang.reflect.Method#isBridge bridge methods}; the bridge
|
||||
* method and the overriding method would have the same
|
||||
* signature but different return types.
|
||||
*
|
||||
* @return the array of {@code Method} objects representing the
|
||||
* public methods of this class
|
||||
* @throws SecurityException
|
||||
@ -1900,12 +1927,13 @@ public final class Class<T> implements java.io.Serializable,
|
||||
@CallerSensitive
|
||||
public Field getField(String name)
|
||||
throws NoSuchFieldException, SecurityException {
|
||||
Objects.requireNonNull(name);
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
Field field = getField0(name);
|
||||
if (field == null) {
|
||||
throw new NoSuchFieldException(name);
|
||||
}
|
||||
return field;
|
||||
return getReflectionFactory().copyField(field);
|
||||
}
|
||||
|
||||
|
||||
@ -1919,47 +1947,69 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* order. If {@code parameterTypes} is {@code null}, it is
|
||||
* treated as if it were an empty array.
|
||||
*
|
||||
* <p> If the {@code name} is "{@code <init>}" or "{@code <clinit>}" a
|
||||
* {@code NoSuchMethodException} is raised. Otherwise, the method to
|
||||
* be reflected is determined by the algorithm that follows. Let C be the
|
||||
* class or interface represented by this object:
|
||||
* <OL>
|
||||
* <LI> C is searched for a <I>matching method</I>, as defined below. If a
|
||||
* matching method is found, it is reflected.</LI>
|
||||
* <LI> If no matching method is found by step 1 then:
|
||||
* <OL TYPE="a">
|
||||
* <LI> If C is a class other than {@code Object}, then this algorithm is
|
||||
* invoked recursively on the superclass of C.</LI>
|
||||
* <LI> If C is the class {@code Object}, or if C is an interface, then
|
||||
* the superinterfaces of C (if any) are searched for a matching
|
||||
* method. If any such method is found, it is reflected.</LI>
|
||||
* </OL></LI>
|
||||
* </OL>
|
||||
* <p> If this {@code Class} object represents an array type, then this
|
||||
* method finds any public method inherited by the array type from
|
||||
* {@code Object} except method {@code clone()}.
|
||||
*
|
||||
* <p> To find a matching method in a class or interface C: If C
|
||||
* declares exactly one public method with the specified name and exactly
|
||||
* the same formal parameter types, that is the method reflected. If more
|
||||
* than one such method is found in C, and one of these methods has a
|
||||
* return type that is more specific than any of the others, that method is
|
||||
* reflected; otherwise one of the methods is chosen arbitrarily.
|
||||
* <p> If this {@code Class} object represents an interface then this
|
||||
* method does not find any implicitly declared method from
|
||||
* {@code Object}. Therefore, if no methods are explicitly declared in
|
||||
* this interface or any of its superinterfaces, then this method does not
|
||||
* find any method.
|
||||
*
|
||||
* <p>Note that there may be more than one matching method in a
|
||||
* class because while the Java language forbids a class to
|
||||
* declare multiple methods with the same signature but different
|
||||
* <p> This method does not find any method with name "{@code <init>}" or
|
||||
* "{@code <clinit>}".
|
||||
*
|
||||
* <p> Generally, the method to be reflected is determined by the 4 step
|
||||
* algorithm that follows.
|
||||
* Let C be the class or interface represented by this {@code Class} object:
|
||||
* <ol>
|
||||
* <li> A union of methods is composed of:
|
||||
* <ol type="a">
|
||||
* <li> C's declared public instance and static methods as returned by
|
||||
* {@link #getDeclaredMethods()} and filtered to include only public
|
||||
* methods that match given {@code name} and {@code parameterTypes}</li>
|
||||
* <li> If C is a class other than {@code Object}, then include the result
|
||||
* of invoking this algorithm recursively on the superclass of C.</li>
|
||||
* <li> Include the results of invoking this algorithm recursively on all
|
||||
* direct superinterfaces of C, but include only instance methods.</li>
|
||||
* </ol></li>
|
||||
* <li> This union is partitioned into subsets of methods with same
|
||||
* return type (the selection of methods from step 1 also guarantees that
|
||||
* they have the same method name and parameter types).</li>
|
||||
* <li> Within each such subset only the most specific methods are selected.
|
||||
* Let method M be a method from a set of methods with same VM
|
||||
* signature (return type, name, parameter types).
|
||||
* M is most specific if there is no such method N != M from the same
|
||||
* set, such that N is more specific than M. N is more specific than M
|
||||
* if:
|
||||
* <ol type="a">
|
||||
* <li> N is declared by a class and M is declared by an interface; or</li>
|
||||
* <li> N and M are both declared by classes or both by interfaces and
|
||||
* N's declaring type is the same as or a subtype of M's declaring type
|
||||
* (clearly, if M's and N's declaring types are the same type, then
|
||||
* M and N are the same method).</li>
|
||||
* </ol></li>
|
||||
* <li> The result of this algorithm is chosen arbitrarily from the methods
|
||||
* with most specific return type among all selected methods from step 3.
|
||||
* Let R be a return type of a method M from the set of all selected methods
|
||||
* from step 3. M is a method with most specific return type if there is
|
||||
* no such method N != M from the same set, having return type S != R,
|
||||
* such that S is a subtype of R as determined by
|
||||
* R.class.{@link #isAssignableFrom}(S.class).
|
||||
* </ol>
|
||||
*
|
||||
* @apiNote There may be more than one method with matching name and
|
||||
* parameter types in a class because while the Java language forbids a
|
||||
* class to declare multiple methods with the same signature but different
|
||||
* return types, the Java virtual machine does not. This
|
||||
* increased flexibility in the virtual machine can be used to
|
||||
* implement various language features. For example, covariant
|
||||
* returns can be implemented with {@linkplain
|
||||
* java.lang.reflect.Method#isBridge bridge methods}; the bridge
|
||||
* method and the method being overridden would have the same
|
||||
* signature but different return types.
|
||||
*
|
||||
* <p> If this {@code Class} object represents an array type, then this
|
||||
* method does not find the {@code clone()} method.
|
||||
*
|
||||
* <p> Static methods declared in superinterfaces of the class or interface
|
||||
* represented by this {@code Class} object are not considered members of
|
||||
* the class or interface.
|
||||
* method and the overriding method would have the same
|
||||
* signature but different return types. This method would return the
|
||||
* overriding method as it would have a more specific return type.
|
||||
*
|
||||
* @param name the name of the method
|
||||
* @param parameterTypes the list of parameters
|
||||
@ -1983,12 +2033,13 @@ public final class Class<T> implements java.io.Serializable,
|
||||
@CallerSensitive
|
||||
public Method getMethod(String name, Class<?>... parameterTypes)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
Objects.requireNonNull(name);
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
Method method = getMethod0(name, parameterTypes, true);
|
||||
Method method = getMethod0(name, parameterTypes);
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
|
||||
}
|
||||
return method;
|
||||
return getReflectionFactory().copyMethod(method);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2004,7 +2055,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* "<init>"or "<clinit>".
|
||||
*/
|
||||
Method getMethodOrNull(String name, Class<?>... parameterTypes) {
|
||||
return getMethod0(name, parameterTypes, true);
|
||||
Objects.requireNonNull(name);
|
||||
Method method = getMethod0(name, parameterTypes);
|
||||
return method == null ? null : getReflectionFactory().copyMethod(method);
|
||||
}
|
||||
|
||||
|
||||
@ -2041,7 +2094,8 @@ public final class Class<T> implements java.io.Serializable,
|
||||
public Constructor<T> getConstructor(Class<?>... parameterTypes)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
return getConstructor0(parameterTypes, Member.PUBLIC);
|
||||
return getReflectionFactory().copyConstructor(
|
||||
getConstructor0(parameterTypes, Member.PUBLIC));
|
||||
}
|
||||
|
||||
|
||||
@ -2283,12 +2337,13 @@ public final class Class<T> implements java.io.Serializable,
|
||||
@CallerSensitive
|
||||
public Field getDeclaredField(String name)
|
||||
throws NoSuchFieldException, SecurityException {
|
||||
Objects.requireNonNull(name);
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
Field field = searchFields(privateGetDeclaredFields(false), name);
|
||||
if (field == null) {
|
||||
throw new NoSuchFieldException(name);
|
||||
}
|
||||
return field;
|
||||
return getReflectionFactory().copyField(field);
|
||||
}
|
||||
|
||||
|
||||
@ -2343,12 +2398,13 @@ public final class Class<T> implements java.io.Serializable,
|
||||
@CallerSensitive
|
||||
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
Objects.requireNonNull(name);
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
|
||||
}
|
||||
return method;
|
||||
return getReflectionFactory().copyMethod(method);
|
||||
}
|
||||
|
||||
|
||||
@ -2394,7 +2450,8 @@ public final class Class<T> implements java.io.Serializable,
|
||||
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
return getConstructor0(parameterTypes, Member.DECLARED);
|
||||
return getReflectionFactory().copyConstructor(
|
||||
getConstructor0(parameterTypes, Member.DECLARED));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3004,180 +3061,6 @@ public final class Class<T> implements java.io.Serializable,
|
||||
return res;
|
||||
}
|
||||
|
||||
static class MethodArray {
|
||||
// Don't add or remove methods except by add() or remove() calls.
|
||||
private Method[] methods;
|
||||
private int length;
|
||||
private int defaults;
|
||||
|
||||
MethodArray() {
|
||||
this(20);
|
||||
}
|
||||
|
||||
MethodArray(int initialSize) {
|
||||
if (initialSize < 2)
|
||||
throw new IllegalArgumentException("Size should be 2 or more");
|
||||
|
||||
methods = new Method[initialSize];
|
||||
length = 0;
|
||||
defaults = 0;
|
||||
}
|
||||
|
||||
boolean hasDefaults() {
|
||||
return defaults != 0;
|
||||
}
|
||||
|
||||
void add(Method m) {
|
||||
if (length == methods.length) {
|
||||
methods = Arrays.copyOf(methods, 2 * methods.length);
|
||||
}
|
||||
methods[length++] = m;
|
||||
|
||||
if (m != null && m.isDefault())
|
||||
defaults++;
|
||||
}
|
||||
|
||||
void addAll(Method[] ma) {
|
||||
for (Method m : ma) {
|
||||
add(m);
|
||||
}
|
||||
}
|
||||
|
||||
void addAll(MethodArray ma) {
|
||||
for (int i = 0; i < ma.length(); i++) {
|
||||
add(ma.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
void addIfNotPresent(Method newMethod) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
Method m = methods[i];
|
||||
if (m == newMethod || (m != null && m.equals(newMethod))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
add(newMethod);
|
||||
}
|
||||
|
||||
void addAllIfNotPresent(MethodArray newMethods) {
|
||||
for (int i = 0; i < newMethods.length(); i++) {
|
||||
Method m = newMethods.get(i);
|
||||
if (m != null) {
|
||||
addIfNotPresent(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Add Methods declared in an interface to this MethodArray.
|
||||
* Static methods declared in interfaces are not inherited.
|
||||
*/
|
||||
void addInterfaceMethods(Method[] methods) {
|
||||
for (Method candidate : methods) {
|
||||
if (!Modifier.isStatic(candidate.getModifiers())) {
|
||||
add(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int length() {
|
||||
return length;
|
||||
}
|
||||
|
||||
Method get(int i) {
|
||||
return methods[i];
|
||||
}
|
||||
|
||||
Method getFirst() {
|
||||
for (Method m : methods)
|
||||
if (m != null)
|
||||
return m;
|
||||
return null;
|
||||
}
|
||||
|
||||
void removeByNameAndDescriptor(Method toRemove) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
Method m = methods[i];
|
||||
if (m != null && matchesNameAndDescriptor(m, toRemove)) {
|
||||
remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void remove(int i) {
|
||||
if (methods[i] != null && methods[i].isDefault())
|
||||
defaults--;
|
||||
methods[i] = null;
|
||||
}
|
||||
|
||||
private boolean matchesNameAndDescriptor(Method m1, Method m2) {
|
||||
return m1.getReturnType() == m2.getReturnType() &&
|
||||
m1.getName() == m2.getName() && // name is guaranteed to be interned
|
||||
arrayContentsEq(m1.getParameterTypes(),
|
||||
m2.getParameterTypes());
|
||||
}
|
||||
|
||||
void compactAndTrim() {
|
||||
int newPos = 0;
|
||||
// Get rid of null slots
|
||||
for (int pos = 0; pos < length; pos++) {
|
||||
Method m = methods[pos];
|
||||
if (m != null) {
|
||||
if (pos != newPos) {
|
||||
methods[newPos] = m;
|
||||
}
|
||||
newPos++;
|
||||
}
|
||||
}
|
||||
if (newPos != methods.length) {
|
||||
methods = Arrays.copyOf(methods, newPos);
|
||||
}
|
||||
}
|
||||
|
||||
/* Removes all Methods from this MethodArray that have a more specific
|
||||
* default Method in this MethodArray.
|
||||
*
|
||||
* Users of MethodArray are responsible for pruning Methods that have
|
||||
* a more specific <em>concrete</em> Method.
|
||||
*/
|
||||
void removeLessSpecifics() {
|
||||
if (!hasDefaults())
|
||||
return;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
Method m = get(i);
|
||||
if (m == null || !m.isDefault())
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < length; j++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
|
||||
Method candidate = get(j);
|
||||
if (candidate == null)
|
||||
continue;
|
||||
|
||||
if (!matchesNameAndDescriptor(m, candidate))
|
||||
continue;
|
||||
|
||||
if (hasMoreSpecificClass(m, candidate))
|
||||
remove(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Method[] getArray() {
|
||||
return methods;
|
||||
}
|
||||
|
||||
// Returns true if m1 is more specific than m2
|
||||
static boolean hasMoreSpecificClass(Method m1, Method m2) {
|
||||
Class<?> m1Class = m1.getDeclaringClass();
|
||||
Class<?> m2Class = m2.getDeclaringClass();
|
||||
return m1Class != m2Class && m2Class.isAssignableFrom(m1Class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Returns an array of "root" methods. These Method objects must NOT
|
||||
// be propagated to the outside world, but must instead be copied
|
||||
// via ReflectionFactory.copyMethod.
|
||||
@ -3190,51 +3073,29 @@ public final class Class<T> implements java.io.Serializable,
|
||||
}
|
||||
|
||||
// No cached value available; compute value recursively.
|
||||
// Start by fetching public declared methods
|
||||
MethodArray methods = new MethodArray();
|
||||
{
|
||||
Method[] tmp = privateGetDeclaredMethods(true);
|
||||
methods.addAll(tmp);
|
||||
// Start by fetching public declared methods...
|
||||
PublicMethods pms = new PublicMethods();
|
||||
for (Method m : privateGetDeclaredMethods(/* publicOnly */ true)) {
|
||||
pms.merge(m);
|
||||
}
|
||||
// Now recur over superclass and direct superinterfaces.
|
||||
// Go over superinterfaces first so we can more easily filter
|
||||
// out concrete implementations inherited from superclasses at
|
||||
// the end.
|
||||
MethodArray inheritedMethods = new MethodArray();
|
||||
for (Class<?> i : getInterfaces()) {
|
||||
inheritedMethods.addInterfaceMethods(i.privateGetPublicMethods());
|
||||
}
|
||||
if (!isInterface()) {
|
||||
Class<?> c = getSuperclass();
|
||||
if (c != null) {
|
||||
MethodArray supers = new MethodArray();
|
||||
supers.addAll(c.privateGetPublicMethods());
|
||||
// Filter out concrete implementations of any
|
||||
// interface methods
|
||||
for (int i = 0; i < supers.length(); i++) {
|
||||
Method m = supers.get(i);
|
||||
if (m != null &&
|
||||
!Modifier.isAbstract(m.getModifiers()) &&
|
||||
!m.isDefault()) {
|
||||
inheritedMethods.removeByNameAndDescriptor(m);
|
||||
}
|
||||
}
|
||||
// Insert superclass's inherited methods before
|
||||
// superinterfaces' to satisfy getMethod's search
|
||||
// order
|
||||
supers.addAll(inheritedMethods);
|
||||
inheritedMethods = supers;
|
||||
// ...then recur over superclass methods...
|
||||
Class<?> sc = getSuperclass();
|
||||
if (sc != null) {
|
||||
for (Method m : sc.privateGetPublicMethods()) {
|
||||
pms.merge(m);
|
||||
}
|
||||
}
|
||||
// Filter out all local methods from inherited ones
|
||||
for (int i = 0; i < methods.length(); i++) {
|
||||
Method m = methods.get(i);
|
||||
inheritedMethods.removeByNameAndDescriptor(m);
|
||||
// ...and finally over direct superinterfaces.
|
||||
for (Class<?> intf : getInterfaces(/* cloneArray */ false)) {
|
||||
for (Method m : intf.privateGetPublicMethods()) {
|
||||
// static interface methods are not inherited
|
||||
if (!Modifier.isStatic(m.getModifiers())) {
|
||||
pms.merge(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
methods.addAllIfNotPresent(inheritedMethods);
|
||||
methods.removeLessSpecifics();
|
||||
methods.compactAndTrim();
|
||||
res = methods.getArray();
|
||||
|
||||
res = pms.toArray();
|
||||
if (rd != null) {
|
||||
rd.publicMethods = res;
|
||||
}
|
||||
@ -3246,17 +3107,20 @@ public final class Class<T> implements java.io.Serializable,
|
||||
// Helpers for fetchers of one field, method, or constructor
|
||||
//
|
||||
|
||||
// This method does not copy the returned Field object!
|
||||
private static Field searchFields(Field[] fields, String name) {
|
||||
String internedName = name.intern();
|
||||
for (Field field : fields) {
|
||||
if (field.getName() == internedName) {
|
||||
return getReflectionFactory().copyField(field);
|
||||
if (field.getName().equals(name)) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Field getField0(String name) throws NoSuchFieldException {
|
||||
// Returns a "root" Field object. This Field object must NOT
|
||||
// be propagated to the outside world, but must instead be copied
|
||||
// via ReflectionFactory.copyField.
|
||||
private Field getField0(String name) {
|
||||
// Note: the intent is that the search algorithm this routine
|
||||
// uses be equivalent to the ordering imposed by
|
||||
// privateGetPublicFields(). It fetches only the declared
|
||||
@ -3270,7 +3134,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
return res;
|
||||
}
|
||||
// Direct superinterfaces, recursively
|
||||
Class<?>[] interfaces = getInterfaces();
|
||||
Class<?>[] interfaces = getInterfaces(/* cloneArray */ false);
|
||||
for (Class<?> c : interfaces) {
|
||||
if ((res = c.getField0(name)) != null) {
|
||||
return res;
|
||||
@ -3288,87 +3152,85 @@ public final class Class<T> implements java.io.Serializable,
|
||||
return null;
|
||||
}
|
||||
|
||||
// This method does not copy the returned Method object!
|
||||
private static Method searchMethods(Method[] methods,
|
||||
String name,
|
||||
Class<?>[] parameterTypes)
|
||||
{
|
||||
ReflectionFactory fact = getReflectionFactory();
|
||||
Method res = null;
|
||||
String internedName = name.intern();
|
||||
for (Method m : methods) {
|
||||
if (m.getName() == internedName
|
||||
&& arrayContentsEq(parameterTypes, m.getParameterTypes())
|
||||
if (m.getName().equals(name)
|
||||
&& arrayContentsEq(parameterTypes,
|
||||
fact.getExecutableSharedParameterTypes(m))
|
||||
&& (res == null
|
||||
|| res.getReturnType().isAssignableFrom(m.getReturnType())))
|
||||
|| (res.getReturnType() != m.getReturnType()
|
||||
&& res.getReturnType().isAssignableFrom(m.getReturnType()))))
|
||||
res = m;
|
||||
}
|
||||
|
||||
return (res == null ? res : getReflectionFactory().copyMethod(res));
|
||||
return res;
|
||||
}
|
||||
|
||||
private Method getMethod0(String name, Class<?>[] parameterTypes, boolean includeStaticMethods) {
|
||||
MethodArray interfaceCandidates = new MethodArray(2);
|
||||
Method res = privateGetMethodRecursive(name, parameterTypes, includeStaticMethods, interfaceCandidates);
|
||||
if (res != null)
|
||||
private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
|
||||
|
||||
// Returns a "root" Method object. This Method object must NOT
|
||||
// be propagated to the outside world, but must instead be copied
|
||||
// via ReflectionFactory.copyMethod.
|
||||
private Method getMethod0(String name, Class<?>[] parameterTypes) {
|
||||
PublicMethods.MethodList res = getMethodsRecursive(
|
||||
name,
|
||||
parameterTypes == null ? EMPTY_CLASS_ARRAY : parameterTypes,
|
||||
/* includeStatic */ true);
|
||||
return res == null ? null : res.getMostSpecific();
|
||||
}
|
||||
|
||||
// Returns a list of "root" Method objects. These Method objects must NOT
|
||||
// be propagated to the outside world, but must instead be copied
|
||||
// via ReflectionFactory.copyMethod.
|
||||
private PublicMethods.MethodList getMethodsRecursive(String name,
|
||||
Class<?>[] parameterTypes,
|
||||
boolean includeStatic) {
|
||||
// 1st check declared public methods
|
||||
Method[] methods = privateGetDeclaredMethods(/* publicOnly */ true);
|
||||
PublicMethods.MethodList res = PublicMethods.MethodList
|
||||
.filter(methods, name, parameterTypes, includeStatic);
|
||||
// if there is at least one match among declared methods, we need not
|
||||
// search any further as such match surely overrides matching methods
|
||||
// declared in superclass(es) or interface(s).
|
||||
if (res != null) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Not found on class or superclass directly
|
||||
interfaceCandidates.removeLessSpecifics();
|
||||
return interfaceCandidates.getFirst(); // may be null
|
||||
}
|
||||
|
||||
private Method privateGetMethodRecursive(String name,
|
||||
Class<?>[] parameterTypes,
|
||||
boolean includeStaticMethods,
|
||||
MethodArray allInterfaceCandidates) {
|
||||
// Note: the intent is that the search algorithm this routine
|
||||
// uses be equivalent to the ordering imposed by
|
||||
// privateGetPublicMethods(). It fetches only the declared
|
||||
// public methods for each class, however, to reduce the
|
||||
// number of Method objects which have to be created for the
|
||||
// common case where the method being requested is declared in
|
||||
// the class which is being queried.
|
||||
//
|
||||
// Due to default methods, unless a method is found on a superclass,
|
||||
// methods declared in any superinterface needs to be considered.
|
||||
// Collect all candidates declared in superinterfaces in {@code
|
||||
// allInterfaceCandidates} and select the most specific if no match on
|
||||
// a superclass is found.
|
||||
|
||||
// Must _not_ return root methods
|
||||
Method res;
|
||||
// Search declared public methods
|
||||
if ((res = searchMethods(privateGetDeclaredMethods(true),
|
||||
name,
|
||||
parameterTypes)) != null) {
|
||||
if (includeStaticMethods || !Modifier.isStatic(res.getModifiers()))
|
||||
return res;
|
||||
}
|
||||
// Search superclass's methods
|
||||
if (!isInterface()) {
|
||||
Class<? super T> c = getSuperclass();
|
||||
if (c != null) {
|
||||
if ((res = c.getMethod0(name, parameterTypes, true)) != null) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Search superinterfaces' methods
|
||||
Class<?>[] interfaces = getInterfaces();
|
||||
for (Class<?> c : interfaces)
|
||||
if ((res = c.getMethod0(name, parameterTypes, false)) != null)
|
||||
allInterfaceCandidates.add(res);
|
||||
// Not found
|
||||
return null;
|
||||
// if there was no match among declared methods,
|
||||
// we must consult the superclass (if any) recursively...
|
||||
Class<?> sc = getSuperclass();
|
||||
if (sc != null) {
|
||||
res = sc.getMethodsRecursive(name, parameterTypes, includeStatic);
|
||||
}
|
||||
|
||||
// ...and coalesce the superclass methods with methods obtained
|
||||
// from directly implemented interfaces excluding static methods...
|
||||
for (Class<?> intf : getInterfaces(/* cloneArray */ false)) {
|
||||
res = PublicMethods.MethodList.merge(
|
||||
res, intf.getMethodsRecursive(name, parameterTypes,
|
||||
/* includeStatic */ false));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Returns a "root" Constructor object. This Constructor object must NOT
|
||||
// be propagated to the outside world, but must instead be copied
|
||||
// via ReflectionFactory.copyConstructor.
|
||||
private Constructor<T> getConstructor0(Class<?>[] parameterTypes,
|
||||
int which) throws NoSuchMethodException
|
||||
{
|
||||
ReflectionFactory fact = getReflectionFactory();
|
||||
Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
|
||||
for (Constructor<T> constructor : constructors) {
|
||||
if (arrayContentsEq(parameterTypes,
|
||||
constructor.getParameterTypes())) {
|
||||
return getReflectionFactory().copyConstructor(constructor);
|
||||
fact.getExecutableSharedParameterTypes(constructor))) {
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
|
||||
|
272
jdk/src/java.base/share/classes/java/lang/PublicMethods.java
Normal file
272
jdk/src/java.base/share/classes/java/lang/PublicMethods.java
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.lang;
|
||||
|
||||
import jdk.internal.reflect.ReflectionFactory;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.AccessController;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A collection of most specific public methods. Methods are added to it using
|
||||
* {@link #merge(Method)} method. Only the most specific methods for a
|
||||
* particular signature are kept.
|
||||
*/
|
||||
final class PublicMethods {
|
||||
|
||||
/**
|
||||
* a map of (method name, parameter types) -> linked list of Method(s)
|
||||
*/
|
||||
private final Map<Key, MethodList> map = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* keeps track of the number of collected methods
|
||||
*/
|
||||
private int methodCount;
|
||||
|
||||
/**
|
||||
* Merges new method with existing methods. New method is either
|
||||
* ignored (if a more specific method with same signature exists) or added
|
||||
* to the collection. When it is added to the collection, it may replace one
|
||||
* or more existing methods with same signature if they are less specific
|
||||
* than added method.
|
||||
* See comments in code...
|
||||
*/
|
||||
void merge(Method method) {
|
||||
Key key = new Key(method);
|
||||
MethodList existing = map.get(key);
|
||||
int xLen = existing == null ? 0 : existing.length();
|
||||
MethodList merged = MethodList.merge(existing, method);
|
||||
methodCount += merged.length() - xLen;
|
||||
// replace if head of list changed
|
||||
if (merged != existing) {
|
||||
map.put(key, merged);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps methods to array.
|
||||
*/
|
||||
Method[] toArray() {
|
||||
Method[] array = new Method[methodCount];
|
||||
int i = 0;
|
||||
for (MethodList ml : map.values()) {
|
||||
for (; ml != null; ml = ml.next) {
|
||||
array[i++] = ml.method;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method (name, parameter types) tuple.
|
||||
*/
|
||||
private static final class Key {
|
||||
private static final ReflectionFactory reflectionFactory =
|
||||
AccessController.doPrivileged(
|
||||
new ReflectionFactory.GetReflectionFactoryAction());
|
||||
|
||||
private final String name; // must be interned (as from Method.getName())
|
||||
private final Class<?>[] ptypes;
|
||||
|
||||
Key(Method method) {
|
||||
name = method.getName();
|
||||
ptypes = reflectionFactory.getExecutableSharedParameterTypes(method);
|
||||
}
|
||||
|
||||
static boolean matches(Method method,
|
||||
String name, // may not be interned
|
||||
Class<?>[] ptypes) {
|
||||
return method.getName().equals(name) &&
|
||||
Arrays.equals(
|
||||
reflectionFactory.getExecutableSharedParameterTypes(method),
|
||||
ptypes
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof Key)) return false;
|
||||
Key that = (Key) o;
|
||||
//noinspection StringEquality (guaranteed interned String(s))
|
||||
return name == that.name &&
|
||||
Arrays.equals(ptypes, that.ptypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(name) + // guaranteed interned String
|
||||
31 * Arrays.hashCode(ptypes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Node of a inked list containing Method(s) sharing the same
|
||||
* (name, parameter types) tuple.
|
||||
*/
|
||||
static final class MethodList {
|
||||
Method method;
|
||||
MethodList next;
|
||||
|
||||
private MethodList(Method method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the head of a linked list containing given {@code methods}
|
||||
* filtered by given method {@code name}, parameter types
|
||||
* {@code ptypes} and including or excluding static methods as
|
||||
* requested by {@code includeStatic} flag.
|
||||
*/
|
||||
static MethodList filter(Method[] methods, String name,
|
||||
Class<?>[] ptypes, boolean includeStatic) {
|
||||
MethodList head = null, tail = null;
|
||||
for (Method method : methods) {
|
||||
if ((includeStatic || !Modifier.isStatic(method.getModifiers())) &&
|
||||
Key.matches(method, name, ptypes)) {
|
||||
if (tail == null) {
|
||||
head = tail = new MethodList(method);
|
||||
} else {
|
||||
tail = tail.next = new MethodList(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should only be called with the {@code head} (possibly null)
|
||||
* of a list of Method(s) that share the same (method name, parameter types)
|
||||
* and another {@code methodList} that also contains Method(s) with the
|
||||
* same and equal (method name, parameter types) as the 1st list.
|
||||
* It modifies the 1st list and returns the head of merged list
|
||||
* containing only the most specific methods for each signature
|
||||
* (i.e. return type). The returned head of the merged list may or
|
||||
* may not be the same as the {@code head} of the given list.
|
||||
* The given {@code methodList} is not modified.
|
||||
*/
|
||||
static MethodList merge(MethodList head, MethodList methodList) {
|
||||
for (MethodList ml = methodList; ml != null; ml = ml.next) {
|
||||
head = merge(head, ml.method);
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
private static MethodList merge(MethodList head, Method method) {
|
||||
Class<?> dclass = method.getDeclaringClass();
|
||||
Class<?> rtype = method.getReturnType();
|
||||
MethodList prev = null;
|
||||
for (MethodList l = head; l != null; l = l.next) {
|
||||
// eXisting method
|
||||
Method xmethod = l.method;
|
||||
// only merge methods with same signature:
|
||||
// (return type, name, parameter types) tuple
|
||||
// as we only keep methods with same (name, parameter types)
|
||||
// tuple together in one list, we only need to check return type
|
||||
if (rtype == xmethod.getReturnType()) {
|
||||
Class<?> xdclass = xmethod.getDeclaringClass();
|
||||
if (dclass.isInterface() == xdclass.isInterface()) {
|
||||
// both methods are declared by interfaces
|
||||
// or both by classes
|
||||
if (dclass.isAssignableFrom(xdclass)) {
|
||||
// existing method is the same or overrides
|
||||
// new method - ignore new method
|
||||
return head;
|
||||
}
|
||||
if (xdclass.isAssignableFrom(dclass)) {
|
||||
// new method overrides existing
|
||||
// method - knock out existing method
|
||||
if (prev != null) {
|
||||
prev.next = l.next;
|
||||
} else {
|
||||
head = l.next;
|
||||
}
|
||||
// keep iterating
|
||||
} else {
|
||||
// unrelated (should only happen for interfaces)
|
||||
prev = l;
|
||||
// keep iterating
|
||||
}
|
||||
} else if (dclass.isInterface()) {
|
||||
// new method is declared by interface while
|
||||
// existing method is declared by class -
|
||||
// ignore new method
|
||||
return head;
|
||||
} else /* xdclass.isInterface() */ {
|
||||
// new method is declared by class while
|
||||
// existing method is declared by interface -
|
||||
// knock out existing method
|
||||
if (prev != null) {
|
||||
prev.next = l.next;
|
||||
} else {
|
||||
head = l.next;
|
||||
}
|
||||
// keep iterating
|
||||
}
|
||||
} else {
|
||||
// distinct signatures
|
||||
prev = l;
|
||||
// keep iterating
|
||||
}
|
||||
}
|
||||
// append new method to the list
|
||||
if (prev == null) {
|
||||
head = new MethodList(method);
|
||||
} else {
|
||||
prev.next = new MethodList(method);
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
private int length() {
|
||||
int len = 1;
|
||||
for (MethodList ml = next; ml != null; ml = ml.next) {
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 1st method in list with most specific return type
|
||||
*/
|
||||
Method getMostSpecific() {
|
||||
Method m = method;
|
||||
Class<?> rt = m.getReturnType();
|
||||
for (MethodList ml = next; ml != null; ml = ml.next) {
|
||||
Method m2 = ml.method;
|
||||
Class<?> rt2 = m2.getReturnType();
|
||||
if (rt2 != rt && rt.isAssignableFrom(rt2)) {
|
||||
// found more specific return type
|
||||
m = m2;
|
||||
rt = rt2;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1786,10 +1786,6 @@ public abstract class VarHandle {
|
||||
AccessMode(final String methodName, AccessType at) {
|
||||
this.methodName = methodName;
|
||||
this.at = at;
|
||||
|
||||
// Assert that return type is correct
|
||||
// Otherwise, when disabled avoid using reflection
|
||||
assert at.returnType == getReturnType(methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1821,16 +1817,6 @@ public abstract class VarHandle {
|
||||
throw new IllegalArgumentException("No AccessMode value for method name " + methodName);
|
||||
}
|
||||
|
||||
private static Class<?> getReturnType(String name) {
|
||||
try {
|
||||
Method m = VarHandle.class.getMethod(name, Object[].class);
|
||||
return m.getReturnType();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw newInternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
static MemberName getMemberName(int ordinal, VarForm vform) {
|
||||
return vform.memberName_table[ordinal];
|
||||
|
@ -240,6 +240,11 @@ public final class Constructor<T> extends Executable {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
Class<?>[] getSharedParameterTypes() {
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@ -222,6 +222,10 @@ public abstract class Executable extends AccessibleObject
|
||||
*/
|
||||
public abstract TypeVariable<?>[] getTypeParameters();
|
||||
|
||||
// returns shared array of parameter types - must never give it out
|
||||
// to the untrusted code...
|
||||
abstract Class<?>[] getSharedParameterTypes();
|
||||
|
||||
/**
|
||||
* Returns an array of {@code Class} objects that represent the formal
|
||||
* parameter types, in declaration order, of the executable
|
||||
|
@ -290,6 +290,11 @@ public final class Method extends Executable {
|
||||
} else { return getReturnType();}
|
||||
}
|
||||
|
||||
@Override
|
||||
Class<?>[] getSharedParameterTypes() {
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@ -132,6 +132,10 @@ class ReflectAccess implements jdk.internal.reflect.LangReflectAccess {
|
||||
return ex.getTypeAnnotationBytes();
|
||||
}
|
||||
|
||||
public Class<?>[] getExecutableSharedParameterTypes(Executable ex) {
|
||||
return ex.getSharedParameterTypes();
|
||||
}
|
||||
|
||||
//
|
||||
// Copying routines, needed to quickly fabricate new Field,
|
||||
// Method, and Constructor objects from templates
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -172,6 +172,8 @@ public class ChoiceFormat extends NumberFormat {
|
||||
/**
|
||||
* Sets the pattern.
|
||||
* @param newPattern See the class description.
|
||||
* @exception NullPointerException if {@code newPattern}
|
||||
* is {@code null}
|
||||
*/
|
||||
public void applyPattern(String newPattern) {
|
||||
StringBuffer[] segments = new StringBuffer[2];
|
||||
@ -309,6 +311,8 @@ public class ChoiceFormat extends NumberFormat {
|
||||
* Constructs with limits and corresponding formats based on the pattern.
|
||||
*
|
||||
* @param newPattern the new pattern string
|
||||
* @exception NullPointerExcpetion if {@code newPattern} is
|
||||
* {@code null}
|
||||
* @see #applyPattern
|
||||
*/
|
||||
public ChoiceFormat(String newPattern) {
|
||||
@ -320,6 +324,8 @@ public class ChoiceFormat extends NumberFormat {
|
||||
*
|
||||
* @param limits limits in ascending order
|
||||
* @param formats corresponding format strings
|
||||
* @exception NullPointerException if {@code limits} or {@code formats}
|
||||
* is {@code null}
|
||||
* @see #setChoices
|
||||
*/
|
||||
public ChoiceFormat(double[] limits, String[] formats) {
|
||||
@ -339,6 +345,8 @@ public class ChoiceFormat extends NumberFormat {
|
||||
* When formatting with object Y,
|
||||
* if the object is a NumberFormat, then ((NumberFormat) Y).format(X)
|
||||
* is called. Otherwise Y.toString() is called.
|
||||
* @exception NullPointerException if {@code limits} or
|
||||
* {@code formats} is {@code null}
|
||||
*/
|
||||
public void setChoices(double[] limits, String formats[]) {
|
||||
if (limits.length != formats.length) {
|
||||
@ -386,6 +394,8 @@ public class ChoiceFormat extends NumberFormat {
|
||||
* @param number number to be formatted and substituted.
|
||||
* @param toAppendTo where text is appended.
|
||||
* @param status ignore no useful status is returned.
|
||||
* @exception NullPointerException if {@code toAppendTo}
|
||||
* is {@code null}
|
||||
*/
|
||||
public StringBuffer format(double number, StringBuffer toAppendTo,
|
||||
FieldPosition status) {
|
||||
@ -414,6 +424,9 @@ public class ChoiceFormat extends NumberFormat {
|
||||
* status.index is unchanged and status.errorIndex is set to the
|
||||
* first index of the character that caused the parse to fail.
|
||||
* @return A Number representing the value of the number parsed.
|
||||
* @exception NullPointerException if {@code status} is {@code null}
|
||||
* or if {@code text} is {@code null} and the list of
|
||||
* choice strings is not empty.
|
||||
*/
|
||||
public Number parse(String text, ParsePosition status) {
|
||||
// find the best number (defined as the one with the longest parse)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -141,6 +141,25 @@ import sun.util.locale.provider.LocaleServiceProviderPool;
|
||||
* If multiple threads access a format concurrently, it must be synchronized
|
||||
* externally.
|
||||
*
|
||||
* @implSpec
|
||||
* <ul><li>The {@link #format(Date, StringBuffer, FieldPosition)} and
|
||||
* {@link #parse(String, ParsePosition)} methods may throw
|
||||
* {@code NullPointerException}, if any of their parameter is {@code null}.
|
||||
* The subclass may provide its own implementation and specification about
|
||||
* {@code NullPointerException}.</li>
|
||||
* <li>The {@link #setCalendar(Calendar)}, {@link
|
||||
* #setNumberFormat(NumberFormat)} and {@link #setTimeZone(TimeZone)} methods
|
||||
* do not throw {@code NullPointerException} when their parameter is
|
||||
* {@code null}, but any subsequent operations on the same instance may throw
|
||||
* {@code NullPointerException}.</li>
|
||||
* <li>The {@link #getCalendar()}, {@link #getNumberFormat()} and
|
||||
* {@link getTimeZone()} methods may return {@code null}, if the respective
|
||||
* values of this instance is set to {@code null} through the corresponding
|
||||
* setter methods. For Example: {@link #getTimeZone()} may return {@code null},
|
||||
* if the {@code TimeZone} value of this instance is set as
|
||||
* {@link #setTimeZone(java.util.TimeZone) setTimeZone(null)}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see Format
|
||||
* @see NumberFormat
|
||||
* @see SimpleDateFormat
|
||||
@ -296,6 +315,8 @@ public abstract class DateFormat extends Format {
|
||||
* the begin index and end index of fieldPosition will be set to
|
||||
* 5 and 8, respectively, for the first occurrence of the timezone
|
||||
* pattern character 'z'.
|
||||
* @exception IllegalArgumentException if the {@code Format} cannot format
|
||||
* the given {@code obj}.
|
||||
* @see java.text.Format
|
||||
*/
|
||||
public final StringBuffer format(Object obj, StringBuffer toAppendTo,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -514,6 +514,8 @@ public class DecimalFormat extends NumberFormat {
|
||||
* @param result where the text is to be appended
|
||||
* @param fieldPosition On input: an alignment field, if desired.
|
||||
* On output: the offsets of the alignment field.
|
||||
* @exception NullPointerException if {@code result} or
|
||||
* {@code fieldPosition} is {@code null}
|
||||
* @exception ArithmeticException if rounding is needed with rounding
|
||||
* mode being set to RoundingMode.UNNECESSARY
|
||||
* @return The formatted number string
|
||||
@ -632,6 +634,8 @@ public class DecimalFormat extends NumberFormat {
|
||||
* @param result where the text is to be appended
|
||||
* @param fieldPosition On input: an alignment field, if desired.
|
||||
* On output: the offsets of the alignment field.
|
||||
* @exception NullPointerException if {@code result} or
|
||||
* {@code fieldPosition} is {@code null}
|
||||
* @exception ArithmeticException if rounding is needed with rounding
|
||||
* mode being set to RoundingMode.UNNECESSARY
|
||||
* @return The formatted number string
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -356,6 +356,8 @@ public class MessageFormat extends Format {
|
||||
*
|
||||
* @param pattern the pattern for this message format
|
||||
* @exception IllegalArgumentException if the pattern is invalid
|
||||
* @exception NullPointerException if {@code pattern} is
|
||||
* {@code null}
|
||||
*/
|
||||
public MessageFormat(String pattern) {
|
||||
this.locale = Locale.getDefault(Locale.Category.FORMAT);
|
||||
@ -373,6 +375,8 @@ public class MessageFormat extends Format {
|
||||
* @param pattern the pattern for this message format
|
||||
* @param locale the locale for this message format
|
||||
* @exception IllegalArgumentException if the pattern is invalid
|
||||
* @exception NullPointerException if {@code pattern} is
|
||||
* {@code null}
|
||||
* @since 1.4
|
||||
*/
|
||||
public MessageFormat(String pattern, Locale locale) {
|
||||
@ -420,6 +424,8 @@ public class MessageFormat extends Format {
|
||||
*
|
||||
* @param pattern the pattern for this message format
|
||||
* @exception IllegalArgumentException if the pattern is invalid
|
||||
* @exception NullPointerException if {@code pattern} is
|
||||
* {@code null}
|
||||
*/
|
||||
@SuppressWarnings("fallthrough") // fallthrough in switch is expected, suppress it
|
||||
public void applyPattern(String pattern) {
|
||||
@ -814,6 +820,7 @@ public class MessageFormat extends Format {
|
||||
* @exception IllegalArgumentException if an argument in the
|
||||
* <code>arguments</code> array is not of the type
|
||||
* expected by the format element(s) that use it.
|
||||
* @exception NullPointerException if {@code result} is {@code null}
|
||||
*/
|
||||
public final StringBuffer format(Object[] arguments, StringBuffer result,
|
||||
FieldPosition pos)
|
||||
@ -835,6 +842,7 @@ public class MessageFormat extends Format {
|
||||
* or if an argument in the <code>arguments</code> array
|
||||
* is not of the type expected by the format element(s)
|
||||
* that use it.
|
||||
* @exception NullPointerException if {@code pattern} is {@code null}
|
||||
*/
|
||||
public static String format(String pattern, Object ... arguments) {
|
||||
MessageFormat temp = new MessageFormat(pattern);
|
||||
@ -858,6 +866,7 @@ public class MessageFormat extends Format {
|
||||
* @exception IllegalArgumentException if an argument in the
|
||||
* <code>arguments</code> array is not of the type
|
||||
* expected by the format element(s) that use it.
|
||||
* @exception NullPointerException if {@code result} is {@code null}
|
||||
*/
|
||||
public final StringBuffer format(Object arguments, StringBuffer result,
|
||||
FieldPosition pos)
|
||||
@ -947,6 +956,8 @@ public class MessageFormat extends Format {
|
||||
* @param source the string to parse
|
||||
* @param pos the parse position
|
||||
* @return an array of parsed objects
|
||||
* @exception NullPointerException if {@code pos} is {@code null}
|
||||
* for a non-null {@code source} string.
|
||||
*/
|
||||
public Object[] parse(String source, ParsePosition pos) {
|
||||
if (source == null) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -174,6 +174,13 @@ import sun.util.locale.provider.LocaleServiceProviderPool;
|
||||
* If multiple threads access a format concurrently, it must be synchronized
|
||||
* externally.
|
||||
*
|
||||
* @implSpec The {@link #format(double, StringBuffer, FieldPosition)},
|
||||
* {@link #format(long, StringBuffer, FieldPosition)} and
|
||||
* {@link #parse(String, ParsePosition)} methods may throw
|
||||
* {@code NullPointerException}, if any of their parameter is {@code null}.
|
||||
* The subclass may provide its own implementation and specification about
|
||||
* {@code NullPointerException}.
|
||||
*
|
||||
* @see DecimalFormat
|
||||
* @see ChoiceFormat
|
||||
* @author Mark Davis
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -905,6 +905,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
* @param startDate During parsing, two digit years will be placed in the range
|
||||
* <code>startDate</code> to <code>startDate + 100 years</code>.
|
||||
* @see #get2DigitYearStart
|
||||
* @throws NullPointerException if {@code startDate} is {@code null}.
|
||||
* @since 1.2
|
||||
*/
|
||||
public void set2DigitYearStart(Date startDate) {
|
||||
@ -933,7 +934,7 @@ public class SimpleDateFormat extends DateFormat {
|
||||
* @param pos the formatting position. On input: an alignment field,
|
||||
* if desired. On output: the offsets of the alignment field.
|
||||
* @return the formatted date-time string.
|
||||
* @exception NullPointerException if the given {@code date} is {@code null}.
|
||||
* @exception NullPointerException if any of the parameters is {@code null}.
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(Date date, StringBuffer toAppendTo,
|
||||
|
@ -292,12 +292,12 @@ import java.util.Set;
|
||||
* W week-of-month number 4
|
||||
* E day-of-week text Tue; Tuesday; T
|
||||
* e/c localized day-of-week number/text 2; 02; Tue; Tuesday; T
|
||||
* F week-of-month number 3
|
||||
* F day-of-week-in-month number 3
|
||||
*
|
||||
* a am-pm-of-day text PM
|
||||
* h clock-hour-of-am-pm (1-12) number 12
|
||||
* K hour-of-am-pm (0-11) number 0
|
||||
* k clock-hour-of-am-pm (1-24) number 0
|
||||
* k clock-hour-of-day (1-24) number 24
|
||||
*
|
||||
* H hour-of-day (0-23) number 0
|
||||
* m minute-of-hour number 30
|
||||
|
@ -1486,12 +1486,12 @@ public final class DateTimeFormatterBuilder {
|
||||
* W week-of-month number 4
|
||||
* E day-of-week text Tue; Tuesday; T
|
||||
* e/c localized day-of-week number/text 2; 02; Tue; Tuesday; T
|
||||
* F week-of-month number 3
|
||||
* F day-of-week-in-month number 3
|
||||
*
|
||||
* a am-pm-of-day text PM
|
||||
* h clock-hour-of-am-pm (1-12) number 12
|
||||
* K hour-of-am-pm (0-11) number 0
|
||||
* k clock-hour-of-am-pm (1-24) number 0
|
||||
* k clock-hour-of-day (1-24) number 24
|
||||
*
|
||||
* H hour-of-day (0-23) number 0
|
||||
* m minute-of-hour number 30
|
||||
|
@ -871,13 +871,13 @@ public final class ZoneRules implements Serializable {
|
||||
/**
|
||||
* Gets the previous transition before the specified instant.
|
||||
* <p>
|
||||
* This returns details of the previous transition after the specified instant.
|
||||
* This returns details of the previous transition before the specified instant.
|
||||
* For example, if the instant represents a point where "summer" daylight saving time
|
||||
* applies, then the method will return the transition from the previous "winter" time.
|
||||
*
|
||||
* @param instant the instant to get the previous transition after, not null, but null
|
||||
* may be ignored if the rules have a single offset for all instants
|
||||
* @return the previous transition after the specified instant, null if this is before the first transition
|
||||
* @return the previous transition before the specified instant, null if this is before the first transition
|
||||
*/
|
||||
public ZoneOffsetTransition previousTransition(Instant instant) {
|
||||
if (savingsInstantTransitions.length == 0) {
|
||||
|
@ -187,7 +187,7 @@ class Random implements java.io.Serializable {
|
||||
*
|
||||
* This is a linear congruential pseudorandom number generator, as
|
||||
* defined by D. H. Lehmer and described by Donald E. Knuth in
|
||||
* <i>The Art of Computer Programming,</i> Volume 3:
|
||||
* <i>The Art of Computer Programming,</i> Volume 2:
|
||||
* <i>Seminumerical Algorithms</i>, section 3.2.1.
|
||||
*
|
||||
* @param bits random bits
|
||||
@ -570,7 +570,7 @@ class Random implements java.io.Serializable {
|
||||
* }}</pre>
|
||||
* This uses the <i>polar method</i> of G. E. P. Box, M. E. Muller, and
|
||||
* G. Marsaglia, as described by Donald E. Knuth in <i>The Art of
|
||||
* Computer Programming</i>, Volume 3: <i>Seminumerical Algorithms</i>,
|
||||
* Computer Programming</i>, Volume 2: <i>Seminumerical Algorithms</i>,
|
||||
* section 3.4.1, subsection C, algorithm P. Note that it generates two
|
||||
* independent values at the cost of only one call to {@code StrictMath.log}
|
||||
* and one call to {@code StrictMath.sqrt}.
|
||||
|
@ -74,7 +74,7 @@
|
||||
* {@link java.util.function.Function} (unary function from {@code T} to {@code R}),
|
||||
* {@link java.util.function.Consumer} (unary function from {@code T} to {@code void}),
|
||||
* {@link java.util.function.Predicate} (unary function from {@code T} to {@code boolean}),
|
||||
* and {@link java.util.function.Supplier} (nilary function to {@code R}).
|
||||
* and {@link java.util.function.Supplier} (nullary function to {@code R}).
|
||||
* </li>
|
||||
*
|
||||
* <li>Function shapes have a natural arity based on how they are most
|
||||
|
@ -96,6 +96,9 @@ public interface LangReflectAccess {
|
||||
/** Gets the "parameterAnnotations" field from a Constructor (used for serialization) */
|
||||
public byte[] getConstructorParameterAnnotations(Constructor<?> c);
|
||||
|
||||
/** Gets the shared array of parameter types of an Executable. */
|
||||
public Class<?>[] getExecutableSharedParameterTypes(Executable ex);
|
||||
|
||||
//
|
||||
// Copying routines, needed to quickly fabricate new Field,
|
||||
// Method, and Constructor objects from templates
|
||||
|
@ -345,6 +345,10 @@ public class ReflectionFactory {
|
||||
return langReflectAccess().getExecutableTypeAnnotationBytes(ex);
|
||||
}
|
||||
|
||||
public Class<?>[] getExecutableSharedParameterTypes(Executable ex) {
|
||||
return langReflectAccess().getExecutableSharedParameterTypes(ex);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Routines used by serialization
|
||||
|
@ -26,7 +26,6 @@
|
||||
package sun.net.www;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.net.MalformedURLException;
|
||||
@ -49,7 +48,7 @@ public class ParseUtil {
|
||||
static BitSet encodedInPath;
|
||||
|
||||
static {
|
||||
encodedInPath = new BitSet(256);
|
||||
encodedInPath = new BitSet(128);
|
||||
|
||||
// Set the bits corresponding to characters that are encoded in the
|
||||
// path component of a URI.
|
||||
@ -102,14 +101,45 @@ public class ParseUtil {
|
||||
* dependent File.separatorChar.
|
||||
*/
|
||||
public static String encodePath(String path, boolean flag) {
|
||||
char[] retCC = new char[path.length() * 2 + 16];
|
||||
int retLen = 0;
|
||||
char[] pathCC = path.toCharArray();
|
||||
if (flag && File.separatorChar != '/') {
|
||||
return encodePath(path, 0, File.separatorChar);
|
||||
} else {
|
||||
int index = firstEncodeIndex(path);
|
||||
if (index > -1) {
|
||||
return encodePath(path, index, '/');
|
||||
} else {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int n = path.length();
|
||||
for (int i=0; i<n; i++) {
|
||||
private static int firstEncodeIndex(String path) {
|
||||
int len = path.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = path.charAt(i);
|
||||
if (c == '/' || c == '.' ||
|
||||
c >= 'a' && c <= 'z' ||
|
||||
c >= 'A' && c <= 'Z' ||
|
||||
c >= '0' && c <= '9') {
|
||||
continue;
|
||||
} else if (c > 0x007F || encodedInPath.get(c)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static String encodePath(String path, int index, char sep) {
|
||||
char[] pathCC = path.toCharArray();
|
||||
char[] retCC = new char[pathCC.length * 2 + 16 - index];
|
||||
if (index > 0) {
|
||||
System.arraycopy(pathCC, 0, retCC, 0, index);
|
||||
}
|
||||
int retLen = index;
|
||||
|
||||
for (int i = index; i < pathCC.length; i++) {
|
||||
char c = pathCC[i];
|
||||
if ((!flag && c == '/') || (flag && c == File.separatorChar))
|
||||
if (c == sep)
|
||||
retCC[retLen++] = '/';
|
||||
else {
|
||||
if (c <= 0x007F) {
|
||||
@ -117,11 +147,11 @@ public class ParseUtil {
|
||||
c >= 'A' && c <= 'Z' ||
|
||||
c >= '0' && c <= '9') {
|
||||
retCC[retLen++] = c;
|
||||
} else
|
||||
if (encodedInPath.get(c))
|
||||
} else if (encodedInPath.get(c)) {
|
||||
retLen = escape(retCC, c, retLen);
|
||||
else
|
||||
} else {
|
||||
retCC[retLen++] = c;
|
||||
}
|
||||
} else if (c > 0x07FF) {
|
||||
retLen = escape(retCC, (char)(0xE0 | ((c >> 12) & 0x0F)), retLen);
|
||||
retLen = escape(retCC, (char)(0x80 | ((c >> 6) & 0x3F)), retLen);
|
||||
|
@ -242,8 +242,9 @@ class InputRecord implements Record, Closeable {
|
||||
// 2: ClientHello.client_version
|
||||
// 32: ClientHello.random
|
||||
// 1: length byte of ClientHello.session_id
|
||||
// 2: length bytes of ClientHello.cipher_suites
|
||||
// 2: empty ClientHello.compression_methods
|
||||
int requiredSize = 46 + sessionIdLen + ((cipherSpecLen * 2 ) / 3 );
|
||||
int requiredSize = 48 + sessionIdLen + ((cipherSpecLen * 2 ) / 3 );
|
||||
byte[] converted = new byte[requiredSize];
|
||||
|
||||
/*
|
||||
|
@ -935,12 +935,20 @@ public abstract class SSLContextImpl extends SSLContextSpi {
|
||||
}
|
||||
|
||||
private static TrustManager[] getTrustManagers() throws Exception {
|
||||
KeyStore ks =
|
||||
TrustManagerFactoryImpl.getCacertsKeyStore("defaultctx");
|
||||
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
|
||||
TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init(ks);
|
||||
TrustManagerFactory.getDefaultAlgorithm());
|
||||
if ("SunJSSE".equals(tmf.getProvider().getName())) {
|
||||
// The implementation will load the default KeyStore
|
||||
// automatically. Cached trust materials may be used
|
||||
// for performance improvement.
|
||||
tmf.init((KeyStore)null);
|
||||
} else {
|
||||
// Use the explicitly specified KeyStore for third party's
|
||||
// TrustManagerFactory implementation.
|
||||
KeyStore ks = TrustStoreManager.getTrustedKeyStore();
|
||||
tmf.init(ks);
|
||||
}
|
||||
|
||||
return tmf.getTrustManagers();
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ import java.security.cert.*;
|
||||
import javax.net.ssl.*;
|
||||
|
||||
import sun.security.validator.Validator;
|
||||
import sun.security.validator.TrustStoreUtil;
|
||||
|
||||
abstract class TrustManagerFactoryImpl extends TrustManagerFactorySpi {
|
||||
|
||||
@ -47,7 +48,7 @@ abstract class TrustManagerFactoryImpl extends TrustManagerFactorySpi {
|
||||
protected void engineInit(KeyStore ks) throws KeyStoreException {
|
||||
if (ks == null) {
|
||||
try {
|
||||
ks = getCacertsKeyStore("trustmanager");
|
||||
trustManager = getInstance(TrustStoreManager.getTrustedCerts());
|
||||
} catch (SecurityException se) {
|
||||
// eat security exceptions but report other throwables
|
||||
if (debug != null && Debug.isOn("trustmanager")) {
|
||||
@ -72,14 +73,17 @@ abstract class TrustManagerFactoryImpl extends TrustManagerFactorySpi {
|
||||
"SunX509: skip default keystore: " + e);
|
||||
}
|
||||
throw new KeyStoreException(
|
||||
"problem accessing trust store" + e);
|
||||
"problem accessing trust store", e);
|
||||
}
|
||||
} else {
|
||||
trustManager = getInstance(TrustStoreUtil.getTrustedCerts(ks));
|
||||
}
|
||||
trustManager = getInstance(ks);
|
||||
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
abstract X509TrustManager getInstance(KeyStore ks) throws KeyStoreException;
|
||||
abstract X509TrustManager getInstance(
|
||||
Collection<X509Certificate> trustedCerts);
|
||||
|
||||
abstract X509TrustManager getInstance(ManagerFactoryParameters spec)
|
||||
throws InvalidAlgorithmParameterException;
|
||||
@ -126,126 +130,14 @@ abstract class TrustManagerFactoryImpl extends TrustManagerFactorySpi {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the keystore with the configured CA certificates.
|
||||
*/
|
||||
static KeyStore getCacertsKeyStore(String dbgname) throws Exception
|
||||
{
|
||||
String storeFileName = null;
|
||||
File storeFile = null;
|
||||
FileInputStream fis = null;
|
||||
String defaultTrustStoreType;
|
||||
String defaultTrustStoreProvider;
|
||||
final HashMap<String,String> props = new HashMap<>();
|
||||
final String sep = File.separator;
|
||||
KeyStore ks = null;
|
||||
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
||||
@Override
|
||||
public Void run() throws Exception {
|
||||
props.put("trustStore", System.getProperty(
|
||||
"javax.net.ssl.trustStore"));
|
||||
props.put("javaHome", System.getProperty(
|
||||
"java.home"));
|
||||
props.put("trustStoreType", System.getProperty(
|
||||
"javax.net.ssl.trustStoreType",
|
||||
KeyStore.getDefaultType()));
|
||||
props.put("trustStoreProvider", System.getProperty(
|
||||
"javax.net.ssl.trustStoreProvider", ""));
|
||||
props.put("trustStorePasswd", System.getProperty(
|
||||
"javax.net.ssl.trustStorePassword", ""));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Try:
|
||||
* javax.net.ssl.trustStore (if this variable exists, stop)
|
||||
* jssecacerts
|
||||
* cacerts
|
||||
*
|
||||
* If none exists, we use an empty keystore.
|
||||
*/
|
||||
|
||||
try {
|
||||
storeFileName = props.get("trustStore");
|
||||
if (!"NONE".equals(storeFileName)) {
|
||||
if (storeFileName != null) {
|
||||
storeFile = new File(storeFileName);
|
||||
fis = getFileInputStream(storeFile);
|
||||
} else {
|
||||
String javaHome = props.get("javaHome");
|
||||
storeFile = new File(javaHome + sep + "lib" + sep
|
||||
+ "security" + sep +
|
||||
"jssecacerts");
|
||||
if ((fis = getFileInputStream(storeFile)) == null) {
|
||||
storeFile = new File(javaHome + sep + "lib" + sep
|
||||
+ "security" + sep +
|
||||
"cacerts");
|
||||
fis = getFileInputStream(storeFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (fis != null) {
|
||||
storeFileName = storeFile.getPath();
|
||||
} else {
|
||||
storeFileName = "No File Available, using empty keystore.";
|
||||
}
|
||||
}
|
||||
|
||||
defaultTrustStoreType = props.get("trustStoreType");
|
||||
defaultTrustStoreProvider = props.get("trustStoreProvider");
|
||||
if (debug != null && Debug.isOn(dbgname)) {
|
||||
System.out.println("trustStore is: " + storeFileName);
|
||||
System.out.println("trustStore type is : " +
|
||||
defaultTrustStoreType);
|
||||
System.out.println("trustStore provider is : " +
|
||||
defaultTrustStoreProvider);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to initialize trust store.
|
||||
*/
|
||||
if (defaultTrustStoreType.length() != 0) {
|
||||
if (debug != null && Debug.isOn(dbgname)) {
|
||||
System.out.println("init truststore");
|
||||
}
|
||||
if (defaultTrustStoreProvider.length() == 0) {
|
||||
ks = KeyStore.getInstance(defaultTrustStoreType);
|
||||
} else {
|
||||
ks = KeyStore.getInstance(defaultTrustStoreType,
|
||||
defaultTrustStoreProvider);
|
||||
}
|
||||
char[] passwd = null;
|
||||
String defaultTrustStorePassword =
|
||||
props.get("trustStorePasswd");
|
||||
if (defaultTrustStorePassword.length() != 0)
|
||||
passwd = defaultTrustStorePassword.toCharArray();
|
||||
|
||||
// if trustStore is NONE, fis will be null
|
||||
ks.load(fis, passwd);
|
||||
|
||||
// Zero out the temporary password storage
|
||||
if (passwd != null) {
|
||||
for (int i = 0; i < passwd.length; i++) {
|
||||
passwd[i] = (char)0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
fis.close();
|
||||
}
|
||||
}
|
||||
|
||||
return ks;
|
||||
}
|
||||
|
||||
public static final class SimpleFactory extends TrustManagerFactoryImpl {
|
||||
@Override
|
||||
X509TrustManager getInstance(KeyStore ks) throws KeyStoreException {
|
||||
return new X509TrustManagerImpl(Validator.TYPE_SIMPLE, ks);
|
||||
X509TrustManager getInstance(
|
||||
Collection<X509Certificate> trustedCerts) {
|
||||
return new X509TrustManagerImpl(
|
||||
Validator.TYPE_SIMPLE, trustedCerts);
|
||||
}
|
||||
|
||||
@Override
|
||||
X509TrustManager getInstance(ManagerFactoryParameters spec)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
@ -253,13 +145,15 @@ abstract class TrustManagerFactoryImpl extends TrustManagerFactorySpi {
|
||||
("SunX509 TrustManagerFactory does not use "
|
||||
+ "ManagerFactoryParameters");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class PKIXFactory extends TrustManagerFactoryImpl {
|
||||
@Override
|
||||
X509TrustManager getInstance(KeyStore ks) throws KeyStoreException {
|
||||
return new X509TrustManagerImpl(Validator.TYPE_PKIX, ks);
|
||||
X509TrustManager getInstance(
|
||||
Collection<X509Certificate> trustedCerts) {
|
||||
return new X509TrustManagerImpl(Validator.TYPE_PKIX, trustedCerts);
|
||||
}
|
||||
|
||||
@Override
|
||||
X509TrustManager getInstance(ManagerFactoryParameters spec)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
|
@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* 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.ssl;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.cert.*;
|
||||
import java.security.cert.Certificate;
|
||||
|
||||
import sun.security.action.*;
|
||||
import sun.security.validator.TrustStoreUtil;
|
||||
|
||||
/**
|
||||
* Collection of static utility methods to manage the default trusted KeyStores
|
||||
* effectively.
|
||||
*/
|
||||
final class TrustStoreManager {
|
||||
private static final Debug debug = Debug.getInstance("ssl");
|
||||
|
||||
// A singleton service to manage the default trusted KeyStores effectively.
|
||||
private static final TrustAnchorManager tam = new TrustAnchorManager();
|
||||
|
||||
// Restrict instantiation of this class.
|
||||
private TrustStoreManager() {
|
||||
// empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an unmodifiable set of all trusted X509Certificates contained
|
||||
* in the default trusted KeyStore.
|
||||
*/
|
||||
public static Set<X509Certificate> getTrustedCerts() throws Exception {
|
||||
return tam.getTrustedCerts(TrustStoreDescriptor.createInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance of the default trusted KeyStore.
|
||||
*/
|
||||
public static KeyStore getTrustedKeyStore() throws Exception {
|
||||
return tam.getKeyStore(TrustStoreDescriptor.createInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* A descriptor of the default trusted KeyStore.
|
||||
*
|
||||
* The preference of the default trusted KeyStore is:
|
||||
* javax.net.ssl.trustStore
|
||||
* jssecacerts
|
||||
* cacerts
|
||||
*/
|
||||
private static final class TrustStoreDescriptor {
|
||||
private static final String fileSep = File.separator;
|
||||
private static final String defaultStorePath =
|
||||
GetPropertyAction.privilegedGetProperty("java.home") +
|
||||
fileSep + "lib" + fileSep + "security";
|
||||
private static final String defaultStore =
|
||||
defaultStorePath + fileSep + "cacerts";
|
||||
private static final String jsseDefaultStore =
|
||||
defaultStorePath + fileSep + "jssecacerts";
|
||||
|
||||
// the trust store name
|
||||
private final String storeName;
|
||||
|
||||
// the trust store type, JKS/PKCS12
|
||||
private final String storeType;
|
||||
|
||||
// the provider of the trust store
|
||||
private final String storeProvider;
|
||||
|
||||
// the password used for the trust store
|
||||
private final String storePassword;
|
||||
|
||||
// the File object of the trust store
|
||||
private final File storeFile;
|
||||
|
||||
// the last modified time of the store
|
||||
private final long lastModified;
|
||||
|
||||
private TrustStoreDescriptor(String storeName, String storeType,
|
||||
String storeProvider, String storePassword,
|
||||
File storeFile, long lastModified) {
|
||||
this.storeName = storeName;
|
||||
this.storeType = storeType;
|
||||
this.storeProvider = storeProvider;
|
||||
this.storePassword = storePassword;
|
||||
this.storeFile = storeFile;
|
||||
this.lastModified = lastModified;
|
||||
|
||||
if (debug != null && Debug.isOn("trustmanager")) {
|
||||
System.out.println(
|
||||
"trustStore is: " + storeName + "\n" +
|
||||
"trustStore type is: " + storeType + "\n" +
|
||||
"trustStore provider is: " + storeProvider + "\n" +
|
||||
"the last modified time is: " + (new Date(lastModified)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of TrustStoreDescriptor for the default
|
||||
* trusted KeyStore.
|
||||
*/
|
||||
static TrustStoreDescriptor createInstance() {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<>() {
|
||||
|
||||
@Override
|
||||
public TrustStoreDescriptor run() {
|
||||
// Get the system properties for trust store.
|
||||
String storePropName = System.getProperty(
|
||||
"javax.net.ssl.trustStore", jsseDefaultStore);
|
||||
String storePropType = System.getProperty(
|
||||
"javax.net.ssl.trustStoreType",
|
||||
KeyStore.getDefaultType());
|
||||
String storePropProvider = System.getProperty(
|
||||
"javax.net.ssl.trustStoreProvider", "");
|
||||
String storePropPassword = System.getProperty(
|
||||
"javax.net.ssl.trustStorePassword", "");
|
||||
|
||||
String temporaryName = "";
|
||||
File temporaryFile = null;
|
||||
long temporaryTime = 0L;
|
||||
if (!"NONE".equals(storePropName)) {
|
||||
String[] fileNames =
|
||||
new String[] {storePropName, defaultStore};
|
||||
for (String fileName : fileNames) {
|
||||
File f = new File(fileName);
|
||||
if (f.isFile() && f.canRead()) {
|
||||
temporaryName = fileName;;
|
||||
temporaryFile = f;
|
||||
temporaryTime = f.lastModified();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Not break, the file is inaccessible.
|
||||
if (debug != null &&
|
||||
Debug.isOn("trustmanager")) {
|
||||
System.out.println(
|
||||
"Inaccessible trust store: " +
|
||||
storePropName);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
temporaryName = storePropName;
|
||||
}
|
||||
|
||||
return new TrustStoreDescriptor(
|
||||
temporaryName, storePropType, storePropProvider,
|
||||
storePropPassword, temporaryFile, temporaryTime);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof TrustStoreDescriptor) {
|
||||
TrustStoreDescriptor that = (TrustStoreDescriptor)obj;
|
||||
return ((this.lastModified == that.lastModified) &&
|
||||
Objects.equals(this.storeName, that.storeName) &&
|
||||
Objects.equals(this.storeType, that.storeType) &&
|
||||
Objects.equals(this.storeProvider, that.storeProvider));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Please be careful if computing security-sensitive attributes'
|
||||
// hash code. For example the storePassword should not be computed.
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 17;
|
||||
|
||||
if (storeName != null && !storeName.isEmpty()) {
|
||||
result = 31 * result + storeName.hashCode();
|
||||
}
|
||||
|
||||
if (storeType != null && !storeType.isEmpty()) {
|
||||
result = 31 * result + storeType.hashCode();
|
||||
}
|
||||
|
||||
if (storeProvider != null && !storeProvider.isEmpty()) {
|
||||
result = 31 * result + storeProvider.hashCode();
|
||||
}
|
||||
|
||||
if (storeFile != null) {
|
||||
result = 31 * result + storeFile.hashCode();
|
||||
}
|
||||
|
||||
if (lastModified != 0L) {
|
||||
result = (int)(31 * result + lastModified);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The trust anchors manager used to expedite the performance.
|
||||
*
|
||||
* This class can be used to provide singleton services to access default
|
||||
* trust KeyStore more effectively.
|
||||
*/
|
||||
private static final class TrustAnchorManager {
|
||||
// Last trust store descriptor.
|
||||
private TrustStoreDescriptor descriptor;
|
||||
|
||||
// The key store used for the trust anchors.
|
||||
//
|
||||
// Use weak reference so that the heavy loaded KeyStore object can
|
||||
// be atomically cleared, and reloaded if needed.
|
||||
private WeakReference<KeyStore> ksRef;
|
||||
|
||||
// The trusted X.509 certificates in the key store.
|
||||
//
|
||||
// Use weak reference so that the heavy loaded certificates collection
|
||||
// objects can be atomically cleared, and reloaded if needed.
|
||||
private WeakReference<Set<X509Certificate>> csRef;
|
||||
|
||||
private TrustAnchorManager() {
|
||||
this.descriptor = null;
|
||||
this.ksRef = new WeakReference<>(null);
|
||||
this.csRef = new WeakReference<>(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default trusted KeyStore with the specified descriptor.
|
||||
*
|
||||
* @return null if the underlying KeyStore is not available.
|
||||
*/
|
||||
synchronized KeyStore getKeyStore(
|
||||
TrustStoreDescriptor descriptor) throws Exception {
|
||||
|
||||
TrustStoreDescriptor temporaryDesc = this.descriptor;
|
||||
KeyStore ks = ksRef.get();
|
||||
if ((ks != null) && descriptor.equals(temporaryDesc)) {
|
||||
return ks;
|
||||
}
|
||||
|
||||
// Reload a new key store.
|
||||
if ((debug != null) && Debug.isOn("trustmanager")) {
|
||||
System.out.println("Reload the trust store");
|
||||
}
|
||||
|
||||
ks = loadKeyStore(descriptor);
|
||||
this.descriptor = descriptor;
|
||||
this.ksRef = new WeakReference<>(ks);
|
||||
|
||||
return ks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get trusted certificates in the default trusted KeyStore with
|
||||
* the specified descriptor.
|
||||
*
|
||||
* @return empty collection if the underlying KeyStore is not available.
|
||||
*/
|
||||
synchronized Set<X509Certificate> getTrustedCerts(
|
||||
TrustStoreDescriptor descriptor) throws Exception {
|
||||
|
||||
KeyStore ks = null;
|
||||
TrustStoreDescriptor temporaryDesc = this.descriptor;
|
||||
Set<X509Certificate> certs = csRef.get();
|
||||
if (certs != null) {
|
||||
if (descriptor.equals(temporaryDesc)) {
|
||||
return certs;
|
||||
} else {
|
||||
// Use the new descriptor.
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
} else {
|
||||
// Try to use the cached store at first.
|
||||
if (descriptor.equals(temporaryDesc)) {
|
||||
ks = ksRef.get();
|
||||
} else {
|
||||
// Use the new descriptor.
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
// Reload the trust store if needed.
|
||||
if (ks == null) {
|
||||
if ((debug != null) && Debug.isOn("trustmanager")) {
|
||||
System.out.println("Reload the trust store");
|
||||
}
|
||||
ks = loadKeyStore(descriptor);
|
||||
}
|
||||
|
||||
// Reload trust certs from the key store.
|
||||
if ((debug != null) && Debug.isOn("trustmanager")) {
|
||||
System.out.println("Reload trust certs");
|
||||
}
|
||||
|
||||
certs = loadTrustedCerts(ks);
|
||||
if ((debug != null) && Debug.isOn("trustmanager")) {
|
||||
System.out.println("Reloaded " + certs.size() + " trust certs");
|
||||
}
|
||||
|
||||
// Note that as ks is a local variable, it is not
|
||||
// necessary to add it to the ksRef weak reference.
|
||||
this.csRef = new WeakReference<>(certs);
|
||||
|
||||
return certs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the the KeyStore as described in the specified descriptor.
|
||||
*/
|
||||
private static KeyStore loadKeyStore(
|
||||
TrustStoreDescriptor descriptor) throws Exception {
|
||||
if (!"NONE".equals(descriptor.storeName) &&
|
||||
descriptor.storeFile == null) {
|
||||
|
||||
// No file available, no KeyStore available.
|
||||
if (debug != null && Debug.isOn("trustmanager")) {
|
||||
System.out.println("No available key store");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
KeyStore ks;
|
||||
if (descriptor.storeProvider.isEmpty()) {
|
||||
ks = KeyStore.getInstance(descriptor.storeType);
|
||||
} else {
|
||||
ks = KeyStore.getInstance(
|
||||
descriptor.storeType, descriptor.storeProvider);
|
||||
}
|
||||
|
||||
char[] password = null;
|
||||
if (!descriptor.storePassword.isEmpty()) {
|
||||
password = descriptor.storePassword.toCharArray();
|
||||
}
|
||||
|
||||
if (!"NONE".equals(descriptor.storeName)) {
|
||||
try (FileInputStream fis = AccessController.doPrivileged(
|
||||
new OpenFileInputStreamAction(descriptor.storeFile))) {
|
||||
ks.load(fis, password);
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
// No file available, no KeyStore available.
|
||||
if (debug != null && Debug.isOn("trustmanager")) {
|
||||
System.out.println(
|
||||
"Not available key store: " + descriptor.storeName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
ks.load(null, password);
|
||||
}
|
||||
|
||||
return ks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load trusted certificates from the specified KeyStore.
|
||||
*/
|
||||
private static Set<X509Certificate> loadTrustedCerts(KeyStore ks) {
|
||||
if (ks == null) {
|
||||
return Collections.<X509Certificate>emptySet();
|
||||
}
|
||||
|
||||
return TrustStoreUtil.getTrustedCerts(ks);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 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
|
||||
@ -68,16 +68,21 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
|
||||
|
||||
private static final Debug debug = Debug.getInstance("ssl");
|
||||
|
||||
X509TrustManagerImpl(String validatorType, KeyStore ks)
|
||||
throws KeyStoreException {
|
||||
X509TrustManagerImpl(String validatorType,
|
||||
Collection<X509Certificate> trustedCerts) {
|
||||
|
||||
this.validatorType = validatorType;
|
||||
this.pkixParams = null;
|
||||
if (ks == null) {
|
||||
|
||||
if (trustedCerts == null) {
|
||||
trustedCerts = Collections.<X509Certificate>emptySet();
|
||||
} else {
|
||||
trustedCerts = KeyStores.getTrustedCerts(ks);
|
||||
}
|
||||
showTrustedCerts();
|
||||
|
||||
this.trustedCerts = trustedCerts;
|
||||
|
||||
if (debug != null && Debug.isOn("trustmanager")) {
|
||||
showTrustedCerts();
|
||||
}
|
||||
}
|
||||
|
||||
X509TrustManagerImpl(String validatorType, PKIXBuilderParameters params) {
|
||||
@ -90,7 +95,10 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
|
||||
Validator v = getValidator(Validator.VAR_TLS_SERVER);
|
||||
trustedCerts = v.getTrustedCertificates();
|
||||
serverValidator = v;
|
||||
showTrustedCerts();
|
||||
|
||||
if (debug != null && Debug.isOn("trustmanager")) {
|
||||
showTrustedCerts();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -305,22 +313,20 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
|
||||
}
|
||||
|
||||
private void showTrustedCerts() {
|
||||
if (debug != null && Debug.isOn("trustmanager")) {
|
||||
for (X509Certificate cert : trustedCerts) {
|
||||
System.out.println("adding as trusted cert:");
|
||||
System.out.println(" Subject: "
|
||||
+ cert.getSubjectX500Principal());
|
||||
System.out.println(" Issuer: "
|
||||
+ cert.getIssuerX500Principal());
|
||||
System.out.println(" Algorithm: "
|
||||
+ cert.getPublicKey().getAlgorithm()
|
||||
+ "; Serial number: 0x"
|
||||
+ cert.getSerialNumber().toString(16));
|
||||
System.out.println(" Valid from "
|
||||
+ cert.getNotBefore() + " until "
|
||||
+ cert.getNotAfter());
|
||||
System.out.println();
|
||||
}
|
||||
for (X509Certificate cert : trustedCerts) {
|
||||
System.out.println("adding as trusted cert:");
|
||||
System.out.println(" Subject: "
|
||||
+ cert.getSubjectX500Principal());
|
||||
System.out.println(" Issuer: "
|
||||
+ cert.getIssuerX500Principal());
|
||||
System.out.println(" Algorithm: "
|
||||
+ cert.getPublicKey().getAlgorithm()
|
||||
+ "; Serial number: 0x"
|
||||
+ cert.getSerialNumber().toString(16));
|
||||
System.out.println(" Valid from "
|
||||
+ cert.getNotBefore() + " until "
|
||||
+ cert.getNotAfter());
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -25,76 +25,33 @@
|
||||
|
||||
package sun.security.validator;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.cert.*;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.Certificate;
|
||||
|
||||
import sun.security.action.*;
|
||||
|
||||
/**
|
||||
* Collection of static utility methods related to KeyStores.
|
||||
* Collection of static utility methods related to trust anchor KeyStores.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public class KeyStores {
|
||||
public final class TrustStoreUtil {
|
||||
|
||||
private KeyStores() {
|
||||
private TrustStoreUtil() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// in the future, all accesses to the system cacerts keystore should
|
||||
// go through this class. but not right now.
|
||||
/*
|
||||
private static final String javaHome =
|
||||
(String)AccessController.doPrivileged(new GetPropertyAction("java.home"));
|
||||
|
||||
private static final char SEP = File.separatorChar;
|
||||
|
||||
private static KeyStore caCerts;
|
||||
|
||||
private static KeyStore getKeyStore(String type, String name,
|
||||
char[] password) throws IOException {
|
||||
if (type == null) {
|
||||
type = "JKS";
|
||||
}
|
||||
try {
|
||||
KeyStore ks = KeyStore.getInstance(type);
|
||||
FileInputStream in = (FileInputStream)AccessController.doPrivileged
|
||||
(new OpenFileInputStreamAction(name));
|
||||
ks.load(in, password);
|
||||
return ks;
|
||||
} catch (GeneralSecurityException e) {
|
||||
// XXX
|
||||
throw new IOException();
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw (IOException)e.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a KeyStore with the contents of the lib/security/cacerts file.
|
||||
* The file is only opened once per JVM invocation and the contents
|
||||
* cached subsequently.
|
||||
*
|
||||
public static synchronized KeyStore getCaCerts() throws IOException {
|
||||
if (caCerts != null) {
|
||||
return caCerts;
|
||||
}
|
||||
String name = javaHome + SEP + "lib" + SEP + "security" + SEP + "cacerts";
|
||||
caCerts = getKeyStore(null, name, null);
|
||||
return caCerts;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return a Set with all trusted X509Certificates contained in
|
||||
* this KeyStore.
|
||||
* Return an unmodifiable Set with all trusted X509Certificates contained
|
||||
* in the specified KeyStore.
|
||||
*/
|
||||
public static Set<X509Certificate> getTrustedCerts(KeyStore ks) {
|
||||
Set<X509Certificate> set = new HashSet<X509Certificate>();
|
||||
Set<X509Certificate> set = new HashSet<>();
|
||||
try {
|
||||
for (Enumeration<String> e = ks.aliases(); e.hasMoreElements(); ) {
|
||||
String alias = e.nextElement();
|
||||
@ -113,8 +70,10 @@ public class KeyStores {
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
// ignore
|
||||
//
|
||||
// This should be rare, but better to log this in the future.
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSet(set);
|
||||
}
|
||||
}
|
@ -166,7 +166,7 @@ public abstract class Validator {
|
||||
*/
|
||||
public static Validator getInstance(String type, String variant,
|
||||
KeyStore ks) {
|
||||
return getInstance(type, variant, KeyStores.getTrustedCerts(ks));
|
||||
return getInstance(type, variant, TrustStoreUtil.getTrustedCerts(ks));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1248,6 +1248,7 @@ ParseArguments(int *pargc, char ***pargv,
|
||||
char *value = NULL;
|
||||
int kind = GetOpt(&argc, &argv, &option, &value);
|
||||
jboolean has_arg = value != NULL && JLI_StrLen(value) > 0;
|
||||
jboolean has_arg_any_len = value != NULL;
|
||||
|
||||
/*
|
||||
* Option to set main entry point
|
||||
@ -1269,7 +1270,7 @@ ParseArguments(int *pargc, char ***pargv,
|
||||
JLI_StrCCmp(arg, "--class-path=") == 0 ||
|
||||
JLI_StrCmp(arg, "-classpath") == 0 ||
|
||||
JLI_StrCmp(arg, "-cp") == 0) {
|
||||
REPORT_ERROR (has_arg, ARG_ERROR1, arg);
|
||||
REPORT_ERROR (has_arg_any_len, ARG_ERROR1, arg);
|
||||
SetClassPath(value);
|
||||
mode = LM_CLASS;
|
||||
} else if (JLI_StrCmp(arg, "--list-modules") == 0 ||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -226,7 +226,12 @@ handleSetLength(FD fd, jlong length)
|
||||
|
||||
if (fstat64(fd, &sb) == 0 && length > sb.st_blocks*512) {
|
||||
RESTARTABLE(fallocate64(fd, 0, 0, length), result);
|
||||
return result;
|
||||
// Return on success or if errno is neither EOPNOTSUPP nor ENOSYS
|
||||
if (result == 0) {
|
||||
return 0;
|
||||
} else if (errno != EOPNOTSUPP && errno != ENOSYS) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
RESTARTABLE(ftruncate64(fd, length), result);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -197,14 +197,17 @@ Java_sun_nio_ch_FileDispatcherImpl_allocate0(JNIEnv *env, jobject this,
|
||||
* any blocks which can cause a SIGBUS error if the file is subsequently
|
||||
* memory-mapped.
|
||||
*/
|
||||
return handle(env,
|
||||
fallocate64(fdval(env, fdo), 0, 0, size),
|
||||
"Allocation failed");
|
||||
#else
|
||||
// Return on success or if errno is neither EOPNOTSUPP nor ENOSYS
|
||||
int result = fallocate64(fdval(env, fdo), 0, 0, size);
|
||||
if (result == 0) {
|
||||
return 0;
|
||||
} else if (errno != EOPNOTSUPP && errno != ENOSYS) {
|
||||
return handle(env, result, "Allocation failed");
|
||||
}
|
||||
#endif
|
||||
return handle(env,
|
||||
ftruncate64(fdval(env, fdo), size),
|
||||
"Truncation failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
|
@ -64,7 +64,7 @@ import jdk.internal.reflect.Reflection;
|
||||
*</ul>
|
||||
*
|
||||
*<P>
|
||||
* @ImplNote
|
||||
* @implNote
|
||||
* {@code DriverManager} initialization is done lazily and looks up service
|
||||
* providers using the thread context class loader. The drivers loaded and
|
||||
* available to an application will depend on the thread context class loader of
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -275,6 +275,10 @@ public abstract class TransformService implements Transform {
|
||||
dom = true;
|
||||
}
|
||||
Provider p = Security.getProvider(provider);
|
||||
if (p == null) {
|
||||
throw new NoSuchProviderException("No such provider: " +
|
||||
provider);
|
||||
}
|
||||
Service s = p.getService("TransformService", algorithm);
|
||||
if (s != null) {
|
||||
String value = s.getAttribute("MechanismType");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -305,6 +305,10 @@ public abstract class XMLSignatureFactory {
|
||||
}
|
||||
|
||||
Provider p = Security.getProvider(provider);
|
||||
if (p == null) {
|
||||
throw new NoSuchProviderException("No such provider: " +
|
||||
provider);
|
||||
}
|
||||
Service s = p.getService("XMLSignatureFactory", mechanismType);
|
||||
if (s != null) {
|
||||
Object obj = null;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -258,6 +258,10 @@ public abstract class KeyInfoFactory {
|
||||
throw new NoSuchProviderException();
|
||||
}
|
||||
Provider p = Security.getProvider(provider);
|
||||
if (p == null) {
|
||||
throw new NoSuchProviderException("No such provider: " +
|
||||
provider);
|
||||
}
|
||||
Service s = p.getService("KeyInfoFactory", mechanismType);
|
||||
if (s != null) {
|
||||
Object obj = null;
|
||||
|
@ -298,7 +298,11 @@ final class GssKrb5Client extends GssKrb5Base implements SaslClient {
|
||||
Boolean.valueOf(integrity)});
|
||||
}
|
||||
|
||||
intToNetworkByteOrder(recvMaxBufSize, gssInToken, 1, 3);
|
||||
if (privacy || integrity) {
|
||||
// Last paragraph of RFC 4752 3.1: size ... MUST be 0 if the
|
||||
// client does not support any security layer
|
||||
intToNetworkByteOrder(recvMaxBufSize, gssInToken, 1, 3);
|
||||
}
|
||||
if (authzID != null) {
|
||||
// copy authorization id
|
||||
System.arraycopy(authzID, 0, gssInToken, 4, authzID.length);
|
||||
|
@ -49,7 +49,7 @@ interface B3 extends D3 { void m(); }
|
||||
interface C3 extends D3 { void m(); }
|
||||
interface D3 { void m() ; }
|
||||
|
||||
// B.m, D.m
|
||||
// B.m
|
||||
interface A4 extends B4, C4 {}
|
||||
interface B4 extends D4 { void m(); }
|
||||
interface C4 extends D4 {}
|
||||
@ -92,7 +92,7 @@ public class StarInheritance {
|
||||
Class [] l3 = {B3.class, C3.class};
|
||||
test(A3.class.getMethods(), new ArrayList(Arrays.asList(l3)));
|
||||
|
||||
Class [] l4 = {B4.class, D4.class};
|
||||
Class [] l4 = {B4.class};
|
||||
test(A4.class.getMethods(), new ArrayList(Arrays.asList(l4)));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -24,12 +24,15 @@
|
||||
/*
|
||||
* @test
|
||||
* @run testng VarHandleTestAccessModeMethodNames
|
||||
* @modules java.base/java.lang.invoke:open
|
||||
*/
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
@ -43,7 +46,6 @@ public class VarHandleTestAccessModeMethodNames {
|
||||
toArray(Object[][]::new);
|
||||
}
|
||||
|
||||
|
||||
@Test(dataProvider = "accessModesProvider")
|
||||
public void testMethodName(VarHandle.AccessMode am) {
|
||||
assertEquals(am.methodName(), toMethodName(am.name()));
|
||||
@ -58,4 +60,22 @@ public class VarHandleTestAccessModeMethodNames {
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
|
||||
@Test(dataProvider = "accessModesProvider")
|
||||
public void testReturnType(VarHandle.AccessMode am) throws Exception {
|
||||
assertEquals(getReturnType(am.methodName()), getAccessModeReturnType(am));
|
||||
}
|
||||
|
||||
private static Class<?> getReturnType(String name) throws Exception {
|
||||
return VarHandle.class.getMethod(name, Object[].class).getReturnType();
|
||||
}
|
||||
|
||||
private static Class<?> getAccessModeReturnType(VarHandle.AccessMode am) throws Exception {
|
||||
Field field_am_at = VarHandle.AccessMode.class.getDeclaredField("at");
|
||||
field_am_at.setAccessible(true);
|
||||
Field field_at_returnType = field_am_at.getType().getDeclaredField("returnType");
|
||||
field_at_returnType.setAccessible(true);
|
||||
return (Class<?>) field_at_returnType.get(field_am_at.get(am));
|
||||
}
|
||||
}
|
||||
|
@ -36,9 +36,8 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
@ -55,7 +54,7 @@ public class FilterNotMostSpecific {
|
||||
for (MethodDesc expected : expectedMethods) {
|
||||
if (expected.isGetMethodReturn()) {
|
||||
try {
|
||||
Method m = iface.getMethod(expected.name());
|
||||
Method m = iface.getMethod(expected.name(), expected.parameterTypes());
|
||||
if (!assertMatch(expected, m))
|
||||
fail(failMsg(expected, m, iface));
|
||||
else
|
||||
@ -72,26 +71,18 @@ public class FilterNotMostSpecific {
|
||||
public void testGetMethods(Class<?> iface) {
|
||||
List<Method> foundMethods = filterObjectMethods(iface.getMethods());
|
||||
MethodDesc[] expectedMethods = iface.getAnnotationsByType(MethodDesc.class);
|
||||
Set<Method> used = new HashSet<>();
|
||||
|
||||
for (MethodDesc expected : expectedMethods) {
|
||||
boolean found = false;
|
||||
|
||||
for (Method m : foundMethods) {
|
||||
if (used.contains(m))
|
||||
continue;
|
||||
|
||||
if(expected.name().equals(m.getName()) &&
|
||||
expected.declaringClass() ==m.getDeclaringClass()) {
|
||||
|
||||
if (assertMatch(expected, m)) {
|
||||
found = true;
|
||||
assertMatch(expected, m);
|
||||
used.add(m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! found)
|
||||
fail("On: "+ iface +"\nDid not find " + toMethodString(expected) + " among " + foundMethods);
|
||||
if (!found)
|
||||
fail("On: "+ iface +"\nDid not find " + toMethodString(expected) +
|
||||
" among " + foundMethods);
|
||||
}
|
||||
assertEquals(foundMethods.size(), expectedMethods.length,
|
||||
"\non: " + iface +
|
||||
@ -104,6 +95,11 @@ public class FilterNotMostSpecific {
|
||||
return false;
|
||||
if (expected.declaringClass() != m.getDeclaringClass())
|
||||
return false;
|
||||
if (!Arrays.equals(expected.parameterTypes(), m.getParameterTypes()))
|
||||
return false;
|
||||
if (expected.returnType() != NotSpecified.class &&
|
||||
expected.returnType() != m.getReturnType())
|
||||
return false;
|
||||
|
||||
if (expected.kind() == MethodKind.ABSTRACT)
|
||||
assertTrue(Modifier.isAbstract(m.getModifiers()), m + " should be ABSTRACT");
|
||||
@ -128,8 +124,13 @@ public class FilterNotMostSpecific {
|
||||
}
|
||||
|
||||
private String toMethodString(MethodDesc m) {
|
||||
return m.declaringClass().getSimpleName().toString() + "." +
|
||||
m.name() + "()";
|
||||
return (m.returnType() != NotSpecified.class
|
||||
? m.returnType().getSimpleName() + " "
|
||||
: "") +
|
||||
m.declaringClass().getSimpleName().toString() + "." +
|
||||
m.name() + Stream.of(m.parameterTypes())
|
||||
.map(cl -> cl.getSimpleName())
|
||||
.collect(Collectors.joining(", ", "(", ")"));
|
||||
}
|
||||
|
||||
private List<String> toMethodStrings(MethodDesc[] m) {
|
||||
@ -142,11 +143,16 @@ public class FilterNotMostSpecific {
|
||||
@Repeatable(MethodDescs.class)
|
||||
public @interface MethodDesc {
|
||||
String name();
|
||||
Class<?> returnType() default NotSpecified.class;
|
||||
Class<?>[] parameterTypes() default {};
|
||||
Class<?> declaringClass();
|
||||
MethodKind kind() default MethodKind.ABSTRACT;
|
||||
boolean isGetMethodReturn() default false;
|
||||
}
|
||||
|
||||
// special type marking a not-specified return type in @MethodDesc
|
||||
interface NotSpecified {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MethodDescs {
|
||||
MethodDesc[] value();
|
||||
@ -172,22 +178,18 @@ public class FilterNotMostSpecific {
|
||||
|
||||
@MethodDesc(name="nonDefault", declaringClass=Jbis.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=I.class)
|
||||
interface P2 extends Jbis, Jprim {}
|
||||
|
||||
@MethodDesc(name="nonDefault", declaringClass=Jbis.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=I.class)
|
||||
interface P3 extends Jbis, Jprim, I {}
|
||||
|
||||
@MethodDesc(name="nonDefault", declaringClass=I.class,
|
||||
@MethodDesc(name="nonDefault", declaringClass=J.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=J.class)
|
||||
interface P4 extends I, J {}
|
||||
|
||||
@MethodDesc(name="nonDefault", declaringClass=J.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=I.class)
|
||||
interface P5 extends J, I {}
|
||||
|
||||
@MethodDesc(name="nonDefault", declaringClass=J.class,
|
||||
@ -198,14 +200,12 @@ public class FilterNotMostSpecific {
|
||||
isGetMethodReturn=true)
|
||||
interface K1M extends J { void nonDefault(); }
|
||||
|
||||
@MethodDesc(name="nonDefault", declaringClass=I.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=J.class)
|
||||
interface K2 extends I, J {}
|
||||
@MethodDesc(name="nonDefault", declaringClass=J.class,
|
||||
isGetMethodReturn=true)
|
||||
interface K2 extends I, J {}
|
||||
|
||||
@MethodDesc(name="nonDefault", declaringClass=J.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=I.class)
|
||||
interface K2O extends J, I {}
|
||||
|
||||
@MethodDesc(name="nonDefault", declaringClass=K2M.class,
|
||||
@ -244,21 +244,18 @@ public class FilterNotMostSpecific {
|
||||
|
||||
@MethodDesc(name="isDefault", declaringClass=M.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class,
|
||||
isGetMethodReturn=true)
|
||||
interface N2 extends M, L {}
|
||||
|
||||
@MethodDesc(name="isDefault", declaringClass=M.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class,
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class)
|
||||
interface N22 extends L, M {}
|
||||
|
||||
@MethodDesc(name="isDefault", declaringClass=N2D.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class,
|
||||
isGetMethodReturn=true)
|
||||
interface N2D extends M, L { default void isDefault() {}}
|
||||
@ -277,48 +274,36 @@ public class FilterNotMostSpecific {
|
||||
|
||||
@MethodDesc(name="isDefault", declaringClass=N2DN.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class,
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class)
|
||||
interface O1 extends L, M, N2DN {}
|
||||
|
||||
@MethodDesc(name="isDefault", declaringClass=N2DN.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class,
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class)
|
||||
interface O2 extends M, N2DN, L {}
|
||||
|
||||
@MethodDesc(name="isDefault", declaringClass=N2DN.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
interface O3 extends N2DN, L, M {}
|
||||
|
||||
@MethodDesc(name="isDefault", declaringClass=N2DN.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class,
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class)
|
||||
abstract class C1 implements L, M, N2DN {}
|
||||
|
||||
@MethodDesc(name="isDefault", declaringClass=N2DN.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class,
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class)
|
||||
abstract class C2 implements M, N2DN, L {}
|
||||
|
||||
@MethodDesc(name="isDefault", declaringClass=N2DN.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
abstract class C3 implements N2DN, L, M {}
|
||||
@ -345,88 +330,54 @@ public class FilterNotMostSpecific {
|
||||
|
||||
@MethodDesc(name="isDefault", declaringClass=R1.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class,
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class)
|
||||
interface R1 extends L, M, N2DN { void isDefault(); }
|
||||
|
||||
@MethodDesc(name="isDefault", declaringClass=R2.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class,
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class)
|
||||
interface R2 extends M, N2DN, L { void isDefault(); }
|
||||
|
||||
@MethodDesc(name="isDefault", declaringClass=R3.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
interface R3 extends N2DN, L, M { void isDefault(); }
|
||||
|
||||
// this one is strange but logical, getMethod finds N2DN first, which is
|
||||
// default but not the most specific
|
||||
@MethodDesc(name="isDefault", declaringClass=N2DN.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="isDefault", declaringClass=R1.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class,
|
||||
@MethodDesc(name="isDefault", declaringClass=R1.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class)
|
||||
interface R4 extends L, M, N2DN, R1 {}
|
||||
|
||||
// this one is strange but logical, getMethod finds N2DN first, which is
|
||||
// default but not the most specific
|
||||
@MethodDesc(name="isDefault", declaringClass=N2DN.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="isDefault", declaringClass=R2.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class,
|
||||
@MethodDesc(name="isDefault", declaringClass=R2.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class)
|
||||
interface R5 extends M, N2DN, R2, L {}
|
||||
|
||||
// this one is strange but logical, getMethod finds N2DN first, which is
|
||||
// default but not the most specific
|
||||
@MethodDesc(name="isDefault", declaringClass=N2DN.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="isDefault", declaringClass=R3.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class)
|
||||
@MethodDesc(name="isDefault", declaringClass=R3.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
interface R6 extends N2DN, R3, L, M {}
|
||||
|
||||
// the following three finds the "right" one
|
||||
@MethodDesc(name="isDefault", declaringClass=R1.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="isDefault", declaringClass=N2DN.class,
|
||||
kind=MethodKind.DEFAULT)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class,
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class)
|
||||
interface R7 extends L, M, R1, N2DN {}
|
||||
|
||||
@MethodDesc(name="isDefault", declaringClass=R2.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="isDefault", declaringClass=N2DN.class,
|
||||
kind=MethodKind.DEFAULT)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class,
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class)
|
||||
interface R8 extends M, R2, N2DN, L {}
|
||||
|
||||
@MethodDesc(name="isDefault", declaringClass=R3.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="isDefault", declaringClass=N2DN.class,
|
||||
kind=MethodKind.DEFAULT)
|
||||
@MethodDesc(name="nonDefault", declaringClass=L.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=M.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=N2DN.class,
|
||||
isGetMethodReturn=true)
|
||||
interface R9 extends R3, N2DN, L, M {}
|
||||
@ -445,51 +396,40 @@ public class FilterNotMostSpecific {
|
||||
|
||||
interface Z3 extends Z2, Z1 { void z(); }
|
||||
|
||||
@MethodDesc(name="z", declaringClass=Z2.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="z", declaringClass=Z3.class)
|
||||
@MethodDesc(name="z", declaringClass=Z3.class,
|
||||
isGetMethodReturn = true)
|
||||
interface Z41 extends Z1, Z2, Z3 { }
|
||||
|
||||
@MethodDesc(name="z", declaringClass=Z2.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="z", declaringClass=Z3.class)
|
||||
@MethodDesc(name="z", declaringClass=Z3.class,
|
||||
isGetMethodReturn = true)
|
||||
interface Z42 extends Z2, Z3, Z1 { }
|
||||
|
||||
@MethodDesc(name="z", declaringClass=Z3.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="z", declaringClass=Z2.class,
|
||||
kind=MethodKind.DEFAULT)
|
||||
isGetMethodReturn = true)
|
||||
interface Z43 extends Z3, Z1, Z2 { }
|
||||
|
||||
@MethodDesc(name="z", declaringClass=Z2.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="z", declaringClass=Z3.class)
|
||||
@MethodDesc(name="z", declaringClass=Z3.class,
|
||||
isGetMethodReturn = true)
|
||||
abstract class ZC41 implements Z1, Z2, Z3 { }
|
||||
|
||||
@MethodDesc(name="z", declaringClass=Z2.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="z", declaringClass=Z3.class)
|
||||
@MethodDesc(name="z", declaringClass=Z3.class,
|
||||
isGetMethodReturn = true)
|
||||
abstract class ZC42 implements Z2, Z3, Z1 { }
|
||||
|
||||
@MethodDesc(name="z", declaringClass=Z3.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="z", declaringClass=Z2.class,
|
||||
kind=MethodKind.DEFAULT)
|
||||
isGetMethodReturn = true)
|
||||
abstract class ZC43 implements Z3, Z1, Z2 { }
|
||||
|
||||
// More reabstraction + concretization
|
||||
interface X1 { default void x() {} }
|
||||
interface X2 extends X1 { void x(); }
|
||||
|
||||
@MethodDesc(name="x", declaringClass=X1.class,
|
||||
kind=MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
@MethodDesc(name="x", declaringClass=X2.class)
|
||||
@MethodDesc(name="x", declaringClass=X2.class,
|
||||
isGetMethodReturn=true)
|
||||
interface X31 extends X1, X2 {}
|
||||
|
||||
@MethodDesc(name="x", declaringClass=X2.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="x", declaringClass=X1.class,
|
||||
kind=MethodKind.DEFAULT)
|
||||
interface X32 extends X2, X1 {}
|
||||
|
||||
@MethodDesc(name="x", declaringClass=X3.class,
|
||||
@ -524,85 +464,107 @@ public class FilterNotMostSpecific {
|
||||
|
||||
interface K extends I, J { void nonDefault(); }
|
||||
|
||||
@MethodDesc(name="nonDefault", declaringClass=I.class,
|
||||
@MethodDesc(name="nonDefault", declaringClass=K.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=J.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=K.class)
|
||||
abstract class ZZ1 implements I, J, K {}
|
||||
|
||||
@MethodDesc(name="nonDefault", declaringClass=I.class,
|
||||
@MethodDesc(name="nonDefault", declaringClass=K.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=J.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=K.class)
|
||||
abstract class ZZ2 extends ZZ1 implements K, I, J {}
|
||||
|
||||
@MethodDesc(name="nonDefault", declaringClass=I.class,
|
||||
@MethodDesc(name="nonDefault", declaringClass=K.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="nonDefault", declaringClass=J.class)
|
||||
@MethodDesc(name="nonDefault", declaringClass=K.class)
|
||||
abstract class ZZ3 extends ZZ2 implements J, K, I {}
|
||||
|
||||
// bridges
|
||||
interface B1A { Object m(); }
|
||||
interface B1B extends B1A { Map m(); }
|
||||
// bridges...
|
||||
|
||||
@MethodDesc(name="m", declaringClass=B1C.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="m", declaringClass=B1C.class,
|
||||
kind=MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", declaringClass=B1C.class,
|
||||
kind=MethodKind.DEFAULT)
|
||||
interface B1C extends B1B { HashMap m(); }
|
||||
interface B1 { Object m(); }
|
||||
interface B2A extends B1 { Map m(); }
|
||||
interface B2B extends B1 { HashMap m(); }
|
||||
|
||||
@MethodDesc(name="m", declaringClass=B2.class,
|
||||
@MethodDesc(name="m", returnType=Object.class, declaringClass=B3A.class,
|
||||
kind = MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", returnType=Map.class, declaringClass=B3A.class,
|
||||
kind = MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", returnType=HashMap.class, declaringClass=B3A.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="m", declaringClass=B2.class,
|
||||
kind=MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", declaringClass=B2.class,
|
||||
kind=MethodKind.DEFAULT)
|
||||
interface B2 extends B1C { HashMap m(); }
|
||||
interface B3A extends B2A { HashMap m(); }
|
||||
|
||||
@MethodDesc(name="m", declaringClass=B2.class, //HahsMap
|
||||
@MethodDesc(name="m", returnType=Object.class, declaringClass=B4A.class,
|
||||
kind = MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", returnType=Map.class, declaringClass=B4A.class,
|
||||
kind = MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", returnType=HashMap.class, declaringClass= B4A.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="m", declaringClass=B2.class, //Map
|
||||
kind=MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", declaringClass=B2.class, //Object
|
||||
kind=MethodKind.DEFAULT)
|
||||
interface B3A extends B2, B1A {}
|
||||
interface B4A extends B3A { HashMap m(); }
|
||||
|
||||
// this one is funny since HashMap isn't a bridge thus not a default
|
||||
@MethodDesc(name="m", declaringClass=B2.class, //HashMap
|
||||
@MethodDesc(name="m", returnType=Object.class, declaringClass=B4A.class,
|
||||
kind = MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", returnType=Map.class, declaringClass=B4A.class,
|
||||
kind = MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", returnType=HashMap.class, declaringClass= B4A.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="m", declaringClass=B2.class, //Map
|
||||
kind=MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", declaringClass=B2.class, //Object
|
||||
kind=MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", declaringClass=B1C.class) //HashMap
|
||||
interface B3B extends B2, B1C {}
|
||||
interface B5A2 extends B4A, B1 {}
|
||||
|
||||
@MethodDesc(name="m", returnType=Object.class, declaringClass=B4A.class,
|
||||
kind = MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", returnType=Map.class, declaringClass=B4A.class,
|
||||
kind = MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", returnType=HashMap.class, declaringClass= B4A.class,
|
||||
isGetMethodReturn=true)
|
||||
interface B5A4A extends B4A, B3A {}
|
||||
|
||||
// ... + most specific return type for getMethod from two unrelated interfaces
|
||||
|
||||
@MethodDesc(name="m", returnType=Object.class, declaringClass=B2A.class,
|
||||
kind = MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", returnType=Object.class, declaringClass=B2B.class,
|
||||
kind = MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", returnType=Map.class, declaringClass=B2A.class)
|
||||
@MethodDesc(name="m", returnType=HashMap.class, declaringClass=B2B.class,
|
||||
isGetMethodReturn=true)
|
||||
interface B3AB extends B2A, B2B {}
|
||||
|
||||
@MethodDesc(name="m", returnType=Object.class, declaringClass=B2A.class,
|
||||
kind = MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", returnType=Object.class, declaringClass=B2B.class,
|
||||
kind = MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", returnType=Map.class, declaringClass=B2A.class)
|
||||
@MethodDesc(name="m", returnType=HashMap.class, declaringClass=B2B.class,
|
||||
isGetMethodReturn=true)
|
||||
interface B3BA extends B2B, B2A {}
|
||||
|
||||
// same name different params type
|
||||
interface A1 { void m(); void m(int i); void m(int i, int j); }
|
||||
interface A2A extends A1 { void m(); void m(int i); void m(int i, int j); }
|
||||
interface A2B extends A1 { void m(); void m(int i); default void m(int i, int j) {} }
|
||||
|
||||
@MethodDesc(name="m", declaringClass=A1.class,
|
||||
@MethodDesc(name="m", parameterTypes = {}, declaringClass=A2A.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="m", parameterTypes = {int.class}, declaringClass=A2A.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="m", parameterTypes = {int.class, int.class}, declaringClass=A2A.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="m", declaringClass=A1.class)
|
||||
@MethodDesc(name="m", declaringClass=A1.class)
|
||||
@MethodDesc(name="m", declaringClass=A2A.class)
|
||||
@MethodDesc(name="m", declaringClass=A2A.class)
|
||||
@MethodDesc(name="m", declaringClass=A2A.class)
|
||||
interface A3A extends A1, A2A {}
|
||||
|
||||
@MethodDesc(name="m", declaringClass=A1.class,
|
||||
@MethodDesc(name="m", parameterTypes = {}, declaringClass=A2B.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="m", declaringClass=A1.class)
|
||||
@MethodDesc(name="m", declaringClass=A2B.class)
|
||||
@MethodDesc(name="m", declaringClass=A2B.class)
|
||||
@MethodDesc(name="m", declaringClass=A2B.class,
|
||||
kind=MethodKind.DEFAULT)
|
||||
@MethodDesc(name="m", parameterTypes = {int.class}, declaringClass=A2B.class,
|
||||
isGetMethodReturn=true)
|
||||
@MethodDesc(name="m", parameterTypes = {int.class, int.class}, declaringClass=A2B.class,
|
||||
kind = MethodKind.DEFAULT, isGetMethodReturn=true)
|
||||
interface A3B extends A1, A2B {}
|
||||
|
||||
// method in directly implemented interface overrides interface method
|
||||
// inherited by superclass
|
||||
|
||||
interface E { void m(); }
|
||||
interface F extends E { void m(); }
|
||||
abstract class G implements E {}
|
||||
|
||||
@MethodDesc(name="m", declaringClass=F.class, isGetMethodReturn=true)
|
||||
abstract class H extends G implements F {}
|
||||
|
||||
@DataProvider
|
||||
public Object[][] getCases() { return CASES; }
|
||||
public static final Class<?>[][] CASES = {
|
||||
@ -680,12 +642,16 @@ public class FilterNotMostSpecific {
|
||||
{ XC42.class },
|
||||
{ XC43.class },
|
||||
|
||||
{ B1C.class },
|
||||
{ B2.class },
|
||||
{ B3A.class },
|
||||
{ B3B.class },
|
||||
{ B4A.class },
|
||||
{ B5A2.class },
|
||||
{ B5A4A.class },
|
||||
{ B3AB.class },
|
||||
{ B3BA.class },
|
||||
|
||||
{ A3A.class },
|
||||
{ A3B.class },
|
||||
|
||||
{ H.class },
|
||||
};
|
||||
}
|
||||
|
1379
jdk/test/java/lang/reflect/PublicMethods/Case1.results
Normal file
1379
jdk/test/java/lang/reflect/PublicMethods/Case1.results
Normal file
File diff suppressed because it is too large
Load Diff
529
jdk/test/java/lang/reflect/PublicMethods/PublicMethodsTest.java
Normal file
529
jdk/test/java/lang/reflect/PublicMethods/PublicMethodsTest.java
Normal file
@ -0,0 +1,529 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.DiagnosticListener;
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.ForwardingJavaFileManager;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.StandardLocation;
|
||||
import javax.tools.ToolProvider;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8062389
|
||||
* @summary Nearly exhaustive test of Class.getMethod() and Class.getMethods()
|
||||
* @run main PublicMethodsTest
|
||||
*/
|
||||
public class PublicMethodsTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Case c = new Case1();
|
||||
|
||||
int[] diffs = new int[1];
|
||||
try (Stream<Map.Entry<int[], Map<String, String>>>
|
||||
expected = expectedResults(c)) {
|
||||
diffResults(c, expected)
|
||||
.forEach(diff -> {
|
||||
System.out.println(diff);
|
||||
diffs[0]++;
|
||||
});
|
||||
}
|
||||
|
||||
if (diffs[0] > 0) {
|
||||
throw new RuntimeException(
|
||||
"There were " + diffs[0] + " differences.");
|
||||
}
|
||||
}
|
||||
|
||||
// use this to generate .results file for particular case
|
||||
public static class Generate {
|
||||
public static void main(String[] args) {
|
||||
Case c = new Case1();
|
||||
dumpResults(generateResults(c))
|
||||
.forEach(System.out::println);
|
||||
}
|
||||
}
|
||||
|
||||
interface Case {
|
||||
Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\$\\{(.+?)}");
|
||||
|
||||
// possible variants of interface method
|
||||
List<String> INTERFACE_METHODS = List.of(
|
||||
"", "void m();", "default void m() {}", "static void m() {}"
|
||||
);
|
||||
|
||||
// possible variants of class method
|
||||
List<String> CLASS_METHODS = List.of(
|
||||
"", "public abstract void m();",
|
||||
"public void m() {}", "public static void m() {}"
|
||||
);
|
||||
|
||||
// template with placeholders parsed with PLACEHOLDER_PATTERN
|
||||
String template();
|
||||
|
||||
// map of replacementKey (== PLACEHOLDER_PATTERN captured group #1) ->
|
||||
// list of possible replacements
|
||||
Map<String, List<String>> replacements();
|
||||
|
||||
// ordered list of replacement keys
|
||||
List<String> replacementKeys();
|
||||
|
||||
// names of types occurring in the template
|
||||
List<String> classNames();
|
||||
}
|
||||
|
||||
static class Case1 implements Case {
|
||||
|
||||
private static final String TEMPLATE = Stream.of(
|
||||
"interface I { ${I} }",
|
||||
"interface J { ${J} }",
|
||||
"interface K extends I, J { ${K} }",
|
||||
"abstract class C { ${C} }",
|
||||
"abstract class D extends C implements I { ${D} }",
|
||||
"abstract class E extends D implements J, K { ${E} }"
|
||||
).collect(joining("\n"));
|
||||
|
||||
private static final Map<String, List<String>> REPLACEMENTS = Map.of(
|
||||
"I", INTERFACE_METHODS,
|
||||
"J", INTERFACE_METHODS,
|
||||
"K", INTERFACE_METHODS,
|
||||
"C", CLASS_METHODS,
|
||||
"D", CLASS_METHODS,
|
||||
"E", CLASS_METHODS
|
||||
);
|
||||
|
||||
private static final List<String> REPLACEMENT_KEYS = REPLACEMENTS
|
||||
.keySet().stream().sorted().collect(Collectors.toList());
|
||||
|
||||
@Override
|
||||
public String template() {
|
||||
return TEMPLATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> replacements() {
|
||||
return REPLACEMENTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> replacementKeys() {
|
||||
return REPLACEMENT_KEYS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> classNames() {
|
||||
// just by accident, names of classes are equal to replacement keys
|
||||
// (this need not be the case in general)
|
||||
return REPLACEMENT_KEYS;
|
||||
}
|
||||
}
|
||||
|
||||
// generate all combinations as a tuple of indexes into lists of
|
||||
// replacements. The index of the element in int[] tuple represents the index
|
||||
// of the key in replacementKeys() list. The value of the element in int[] tuple
|
||||
// represents the index of the replacement string in list of strings in the
|
||||
// value of the entry of replacements() map with the corresponding key.
|
||||
static Stream<int[]> combinations(Case c) {
|
||||
int[] sizes = c.replacementKeys().stream()
|
||||
.mapToInt(key -> c.replacements().get(key).size())
|
||||
.toArray();
|
||||
|
||||
return Stream.iterate(
|
||||
new int[sizes.length],
|
||||
state -> state != null,
|
||||
state -> {
|
||||
int[] newState = state.clone();
|
||||
for (int i = 0; i < state.length; i++) {
|
||||
if (++newState[i] < sizes[i]) {
|
||||
return newState;
|
||||
}
|
||||
newState[i] = 0;
|
||||
}
|
||||
// wrapped-around
|
||||
return null;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// given the combination of indexes, return the expanded template
|
||||
static String expandTemplate(Case c, int[] combination) {
|
||||
|
||||
// 1st create a map: key -> replacement string
|
||||
Map<String, String> map = new HashMap<>(combination.length * 4 / 3 + 1);
|
||||
for (int i = 0; i < combination.length; i++) {
|
||||
String key = c.replacementKeys().get(i);
|
||||
String repl = c.replacements().get(key).get(combination[i]);
|
||||
map.put(key, repl);
|
||||
}
|
||||
|
||||
return Case.PLACEHOLDER_PATTERN
|
||||
.matcher(c.template())
|
||||
.replaceAll(match -> map.get(match.group(1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* compile expanded template into a ClassLoader that sees compiled classes
|
||||
*/
|
||||
static ClassLoader compile(String source) throws CompileException {
|
||||
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
|
||||
if (javac == null) {
|
||||
throw new AssertionError("No Java compiler tool found.");
|
||||
}
|
||||
|
||||
ErrorsCollector errorsCollector = new ErrorsCollector();
|
||||
StandardJavaFileManager standardJavaFileManager =
|
||||
javac.getStandardFileManager(errorsCollector, Locale.ROOT,
|
||||
Charset.forName("UTF-8"));
|
||||
TestFileManager testFileManager = new TestFileManager(
|
||||
standardJavaFileManager, source);
|
||||
|
||||
JavaCompiler.CompilationTask javacTask;
|
||||
try {
|
||||
javacTask = javac.getTask(
|
||||
null, // use System.err
|
||||
testFileManager,
|
||||
errorsCollector,
|
||||
null,
|
||||
null,
|
||||
List.of(testFileManager.getJavaFileForInput(
|
||||
StandardLocation.SOURCE_PATH,
|
||||
TestFileManager.TEST_CLASS_NAME,
|
||||
JavaFileObject.Kind.SOURCE))
|
||||
);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
|
||||
javacTask.call();
|
||||
|
||||
if (errorsCollector.hasError()) {
|
||||
throw new CompileException(errorsCollector.getErrors());
|
||||
}
|
||||
|
||||
return new TestClassLoader(ClassLoader.getSystemClassLoader(),
|
||||
testFileManager);
|
||||
}
|
||||
|
||||
static class CompileException extends Exception {
|
||||
CompileException(List<Diagnostic<?>> diagnostics) {
|
||||
super(diagnostics.stream()
|
||||
.map(diag -> diag.toString())
|
||||
.collect(Collectors.joining("\n")));
|
||||
}
|
||||
}
|
||||
|
||||
static class TestFileManager
|
||||
extends ForwardingJavaFileManager<StandardJavaFileManager> {
|
||||
static final String TEST_CLASS_NAME = "Test";
|
||||
|
||||
private final String testSource;
|
||||
private final Map<String, ClassFileObject> classes = new HashMap<>();
|
||||
|
||||
TestFileManager(StandardJavaFileManager fileManager, String source) {
|
||||
super(fileManager);
|
||||
testSource = "public class " + TEST_CLASS_NAME + " {}\n" +
|
||||
source; // the rest of classes are package-private
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaFileObject getJavaFileForInput(Location location,
|
||||
String className,
|
||||
JavaFileObject.Kind kind)
|
||||
throws IOException {
|
||||
if (location == StandardLocation.SOURCE_PATH &&
|
||||
kind == JavaFileObject.Kind.SOURCE &&
|
||||
TEST_CLASS_NAME.equals(className)) {
|
||||
return new SourceFileObject(className, testSource);
|
||||
}
|
||||
return super.getJavaFileForInput(location, className, kind);
|
||||
}
|
||||
|
||||
private static class SourceFileObject extends SimpleJavaFileObject {
|
||||
private final String source;
|
||||
|
||||
SourceFileObject(String className, String source) {
|
||||
super(
|
||||
URI.create("memory:/src/" +
|
||||
className.replace('.', '/') + ".java"),
|
||||
Kind.SOURCE
|
||||
);
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaFileObject getJavaFileForOutput(Location location,
|
||||
String className,
|
||||
JavaFileObject.Kind kind,
|
||||
FileObject sibling)
|
||||
throws IOException {
|
||||
if (kind == JavaFileObject.Kind.CLASS) {
|
||||
ClassFileObject cfo = new ClassFileObject(className);
|
||||
classes.put(className, cfo);
|
||||
return cfo;
|
||||
}
|
||||
return super.getJavaFileForOutput(location, className, kind, sibling);
|
||||
}
|
||||
|
||||
private static class ClassFileObject extends SimpleJavaFileObject {
|
||||
final String className;
|
||||
ByteArrayOutputStream byteArrayOutputStream;
|
||||
|
||||
ClassFileObject(String className) {
|
||||
super(
|
||||
URI.create("memory:/out/" +
|
||||
className.replace('.', '/') + ".class"),
|
||||
Kind.CLASS
|
||||
);
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream openOutputStream() throws IOException {
|
||||
return byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
}
|
||||
|
||||
byte[] getBytes() {
|
||||
if (byteArrayOutputStream == null) {
|
||||
throw new IllegalStateException(
|
||||
"No class file written for class: " + className);
|
||||
}
|
||||
return byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
byte[] getClassBytes(String className) {
|
||||
ClassFileObject cfo = classes.get(className);
|
||||
return (cfo == null) ? null : cfo.getBytes();
|
||||
}
|
||||
}
|
||||
|
||||
static class ErrorsCollector implements DiagnosticListener<JavaFileObject> {
|
||||
private final List<Diagnostic<?>> errors = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
|
||||
errors.add(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasError() {
|
||||
return !errors.isEmpty();
|
||||
}
|
||||
|
||||
List<Diagnostic<?>> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
||||
static class TestClassLoader extends ClassLoader {
|
||||
private final TestFileManager fileManager;
|
||||
|
||||
public TestClassLoader(ClassLoader parent, TestFileManager fileManager) {
|
||||
super(parent);
|
||||
this.fileManager = fileManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
byte[] classBytes = fileManager.getClassBytes(name);
|
||||
if (classBytes == null) {
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
return defineClass(name, classBytes, 0, classBytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
static Map<String, String> generateResult(Case c, ClassLoader cl) {
|
||||
return
|
||||
c.classNames()
|
||||
.stream()
|
||||
.map(cn -> {
|
||||
try {
|
||||
return Class.forName(cn, false, cl);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Class not found: " + cn, e);
|
||||
}
|
||||
})
|
||||
.flatMap(clazz -> Stream.of(
|
||||
Map.entry(clazz.getName() + ".gM", generateGetMethodResult(clazz)),
|
||||
Map.entry(clazz.getName() + ".gMs", generateGetMethodsResult(clazz))
|
||||
))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
}
|
||||
|
||||
static String generateGetMethodResult(Class<?> clazz) {
|
||||
try {
|
||||
Method m = clazz.getMethod("m");
|
||||
return m.getDeclaringClass().getName() + "." + m.getName();
|
||||
} catch (NoSuchMethodException e) {
|
||||
return "-";
|
||||
}
|
||||
}
|
||||
|
||||
static String generateGetMethodsResult(Class<?> clazz) {
|
||||
return Stream.of(clazz.getMethods())
|
||||
.filter(m -> m.getDeclaringClass() != Object.class)
|
||||
.map(m -> m.getDeclaringClass().getName()
|
||||
+ "." + m.getName())
|
||||
.collect(Collectors.joining(", ", "[", "]"));
|
||||
}
|
||||
|
||||
static Stream<Map.Entry<int[], Map<String, String>>> generateResults(Case c) {
|
||||
return combinations(c)
|
||||
.flatMap(comb -> {
|
||||
String src = expandTemplate(c, comb);
|
||||
ClassLoader cl;
|
||||
try {
|
||||
cl = compile(src);
|
||||
} catch (CompileException e) {
|
||||
// ignore uncompilable combinations
|
||||
return Stream.empty();
|
||||
}
|
||||
// compilation was successful -> generate result
|
||||
return Stream.of(Map.entry(
|
||||
comb,
|
||||
generateResult(c, cl)
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
static Stream<Map.Entry<int[], Map<String, String>>> expectedResults(Case c) {
|
||||
try {
|
||||
BufferedReader r = new BufferedReader(new InputStreamReader(
|
||||
c.getClass().getResourceAsStream(
|
||||
c.getClass().getSimpleName() + ".results"),
|
||||
"UTF-8"
|
||||
));
|
||||
|
||||
return parseResults(r.lines())
|
||||
.onClose(() -> {
|
||||
try {
|
||||
r.close();
|
||||
} catch (IOException ioe) {
|
||||
throw new UncheckedIOException(ioe);
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static Stream<Map.Entry<int[], Map<String, String>>> parseResults(
|
||||
Stream<String> lines
|
||||
) {
|
||||
return lines
|
||||
.map(l -> l.split(Pattern.quote("#")))
|
||||
.map(lkv -> Map.entry(
|
||||
Stream.of(lkv[0].split(Pattern.quote(",")))
|
||||
.mapToInt(Integer::parseInt)
|
||||
.toArray(),
|
||||
Stream.of(lkv[1].split(Pattern.quote("|")))
|
||||
.map(e -> e.split(Pattern.quote("=")))
|
||||
.collect(toMap(ekv -> ekv[0], ekv -> ekv[1]))
|
||||
));
|
||||
}
|
||||
|
||||
static Stream<String> dumpResults(
|
||||
Stream<Map.Entry<int[], Map<String, String>>> results
|
||||
) {
|
||||
return results
|
||||
.map(le ->
|
||||
IntStream.of(le.getKey())
|
||||
.mapToObj(String::valueOf)
|
||||
.collect(joining(","))
|
||||
+ "#" +
|
||||
le.getValue().entrySet().stream()
|
||||
.map(e -> e.getKey() + "=" + e.getValue())
|
||||
.collect(joining("|"))
|
||||
);
|
||||
}
|
||||
|
||||
static Stream<String> diffResults(
|
||||
Case c,
|
||||
Stream<Map.Entry<int[], Map<String, String>>> expectedResults
|
||||
) {
|
||||
return expectedResults
|
||||
.flatMap(exp -> {
|
||||
int[] comb = exp.getKey();
|
||||
Map<String, String> expected = exp.getValue();
|
||||
|
||||
String src = expandTemplate(c, comb);
|
||||
ClassLoader cl;
|
||||
try {
|
||||
cl = compile(src);
|
||||
} catch (CompileException ce) {
|
||||
return Stream.of(src + "\n" +
|
||||
"got compilation error: " + ce);
|
||||
}
|
||||
|
||||
Map<String, String> actual = generateResult(c, cl);
|
||||
if (actual.equals(expected)) {
|
||||
return Stream.empty();
|
||||
} else {
|
||||
Map<String, String> diff = new HashMap<>(expected);
|
||||
diff.entrySet().removeAll(actual.entrySet());
|
||||
return Stream.of(
|
||||
diff.entrySet()
|
||||
.stream()
|
||||
.map(e -> "expected: " + e.getKey() + ": " +
|
||||
e.getValue() + "\n" +
|
||||
" actual: " + e.getKey() + ": " +
|
||||
actual.get(e.getKey()) + "\n")
|
||||
.collect(joining("\n", src + "\n\n", "\n"))
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@
|
||||
* @summary Stress test connections through the loopback interface
|
||||
* @run main StressLoopback
|
||||
* @run main/othervm -Djdk.net.useFastTcpLoopback StressLoopback
|
||||
* @key randomness
|
||||
* @key randomness intermittent
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 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
|
||||
@ -54,7 +54,8 @@ public class AltSecurityManager implements Runnable {
|
||||
static final String ACTIVATION = "sun.rmi.server.Activation";
|
||||
|
||||
// children should exit in at least this time.
|
||||
static long TIME_OUT = 15000;
|
||||
private static final long TIME_OUT =
|
||||
(long)(15000 * TestLibrary.getTimeoutFactor());
|
||||
|
||||
public AltSecurityManager(int port) {
|
||||
if (port <= 0) {
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8049429
|
||||
* @bug 8049429 8172273
|
||||
* @modules java.management
|
||||
* jdk.crypto.ec/sun.security.ec
|
||||
* @summary Test that all cipher suites work in all versions and all client
|
||||
@ -30,6 +30,21 @@
|
||||
* and all checking is done on the client side.
|
||||
* @compile CipherTestUtils.java JSSEClient.java JSSEServer.java
|
||||
* @run main/othervm
|
||||
* -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2
|
||||
* -DCLIENT_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2
|
||||
* -DCIPHER=SSL_RSA_WITH_RC4_128_MD5
|
||||
* TestJSSE
|
||||
* @run main/othervm
|
||||
* -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2
|
||||
* -DCLIENT_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2
|
||||
* -DCIPHER=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
|
||||
* TestJSSE
|
||||
* @run main/othervm
|
||||
* -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2
|
||||
* -DCLIENT_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2
|
||||
* -DCIPHER=TLS_DHE_RSA_WITH_AES_128_CBC_SHA
|
||||
* TestJSSE
|
||||
* @run main/othervm
|
||||
* -DSERVER_PROTOCOL=SSLv3
|
||||
* -DCLIENT_PROTOCOL=SSLv3
|
||||
* -DCIPHER=SSL_RSA_WITH_RC4_128_MD5
|
||||
|
@ -31,7 +31,7 @@
|
||||
* @bug 7109274
|
||||
* @summary Consider disabling support for X.509 certificates with RSA keys
|
||||
* less than 1024 bits
|
||||
*
|
||||
* @library /javax/net/ssl/templates
|
||||
* @run main/othervm DisabledShortRSAKeys PKIX TLSv1.2
|
||||
* @run main/othervm DisabledShortRSAKeys SunX509 TLSv1.2
|
||||
* @run main/othervm DisabledShortRSAKeys PKIX TLSv1.1
|
||||
@ -56,20 +56,7 @@ import java.security.interfaces.*;
|
||||
import java.util.Base64;
|
||||
|
||||
|
||||
public class DisabledShortRSAKeys {
|
||||
|
||||
/*
|
||||
* =============================================================
|
||||
* Set the various variables needed for the tests, then
|
||||
* specify what tests to run on each side.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Should we run the client or server in a separate thread?
|
||||
* Both sides can throw exceptions, but do you have a preference
|
||||
* as to which side should be the main thread.
|
||||
*/
|
||||
static boolean separateServerThread = true;
|
||||
public class DisabledShortRSAKeys extends SSLSocketTemplate {
|
||||
|
||||
/*
|
||||
* Where do we find the keystores?
|
||||
@ -122,82 +109,51 @@ public class DisabledShortRSAKeys {
|
||||
|
||||
static char passphrase[] = "passphrase".toCharArray();
|
||||
|
||||
/*
|
||||
* Is the server ready to serve?
|
||||
*/
|
||||
volatile static boolean serverReady = false;
|
||||
|
||||
/*
|
||||
* Turn on SSL debugging?
|
||||
*/
|
||||
static boolean debug = false;
|
||||
|
||||
/*
|
||||
* Define the server side of the test.
|
||||
*
|
||||
* If the server prematurely exits, serverReady will be set to true
|
||||
* to avoid infinite hangs.
|
||||
*/
|
||||
void doServerSide() throws Exception {
|
||||
SSLContext context = generateSSLContext(null, targetCertStr,
|
||||
targetPrivateKey);
|
||||
SSLServerSocketFactory sslssf = context.getServerSocketFactory();
|
||||
SSLServerSocket sslServerSocket =
|
||||
(SSLServerSocket)sslssf.createServerSocket(serverPort);
|
||||
serverPort = sslServerSocket.getLocalPort();
|
||||
@Override
|
||||
protected SSLContext createClientSSLContext() throws Exception {
|
||||
return generateSSLContext(trustedCertStr, null, null);
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal Client, we're ready for his connect.
|
||||
*/
|
||||
serverReady = true;
|
||||
@Override
|
||||
protected SSLContext createServerSSLContext() throws Exception {
|
||||
return generateSSLContext(null, targetCertStr, targetPrivateKey);
|
||||
}
|
||||
|
||||
try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) {
|
||||
try (InputStream sslIS = sslSocket.getInputStream()) {
|
||||
@Override
|
||||
protected void runServerApplication(SSLSocket socket) throws Exception {
|
||||
try {
|
||||
try (InputStream sslIS = socket.getInputStream()) {
|
||||
sslIS.read();
|
||||
}
|
||||
|
||||
throw new Exception(
|
||||
"RSA keys shorter than 1024 bits should be disabled");
|
||||
throw new Exception("RSA keys shorter than 1024 bits should be disabled");
|
||||
} catch (SSLHandshakeException sslhe) {
|
||||
// the expected exception, ignore
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Define the client side of the test.
|
||||
*
|
||||
* If the server prematurely exits, serverReady will be set to true
|
||||
* to avoid infinite hangs.
|
||||
*/
|
||||
void doClientSide() throws Exception {
|
||||
@Override
|
||||
protected void runClientApplication(SSLSocket socket) throws Exception {
|
||||
|
||||
/*
|
||||
* Wait for server to get started.
|
||||
*/
|
||||
while (!serverReady) {
|
||||
Thread.sleep(50);
|
||||
}
|
||||
|
||||
SSLContext context = generateSSLContext(trustedCertStr, null, null);
|
||||
SSLSocketFactory sslsf = context.getSocketFactory();
|
||||
|
||||
try (SSLSocket sslSocket =
|
||||
(SSLSocket)sslsf.createSocket("localhost", serverPort)) {
|
||||
try {
|
||||
|
||||
// only enable the target protocol
|
||||
sslSocket.setEnabledProtocols(new String[] {enabledProtocol});
|
||||
|
||||
socket.setEnabledProtocols(new String[] { enabledProtocol });
|
||||
// enable a block cipher
|
||||
sslSocket.setEnabledCipherSuites(
|
||||
new String[] {"TLS_DHE_RSA_WITH_AES_128_CBC_SHA"});
|
||||
socket.setEnabledCipherSuites(
|
||||
new String[] { "TLS_DHE_RSA_WITH_AES_128_CBC_SHA" });
|
||||
|
||||
try (OutputStream sslOS = sslSocket.getOutputStream()) {
|
||||
try (OutputStream sslOS = socket.getOutputStream()) {
|
||||
sslOS.write('B');
|
||||
sslOS.flush();
|
||||
}
|
||||
|
||||
throw new Exception(
|
||||
"RSA keys shorter than 1024 bits should be disabled");
|
||||
"RSA keys shorter than 1024 bits should be disabled");
|
||||
} catch (SSLHandshakeException sslhe) {
|
||||
// the expected exception, ignore
|
||||
}
|
||||
@ -207,16 +163,16 @@ public class DisabledShortRSAKeys {
|
||||
* =============================================================
|
||||
* The remainder is just support stuff
|
||||
*/
|
||||
private static String tmAlgorithm; // trust manager
|
||||
private static String enabledProtocol; // the target protocol
|
||||
private static String tmAlgorithm; // trust manager
|
||||
private static String enabledProtocol; // the target protocol
|
||||
|
||||
private static void parseArguments(String[] args) {
|
||||
tmAlgorithm = args[0];
|
||||
enabledProtocol = args[1];
|
||||
tmAlgorithm = args[0];
|
||||
enabledProtocol = args[1];
|
||||
}
|
||||
|
||||
private static SSLContext generateSSLContext(String trustedCertStr,
|
||||
String keyCertStr, String keySpecStr) throws Exception {
|
||||
String keyCertStr, String keySpecStr) throws Exception {
|
||||
|
||||
// generate certificate from cert string
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
@ -239,10 +195,10 @@ public class DisabledShortRSAKeys {
|
||||
if (keyCertStr != null) {
|
||||
// generate the private key.
|
||||
PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
|
||||
Base64.getMimeDecoder().decode(keySpecStr));
|
||||
Base64.getMimeDecoder().decode(keySpecStr));
|
||||
KeyFactory kf = KeyFactory.getInstance("RSA");
|
||||
RSAPrivateKey priKey =
|
||||
(RSAPrivateKey)kf.generatePrivate(priKeySpec);
|
||||
(RSAPrivateKey)kf.generatePrivate(priKeySpec);
|
||||
|
||||
// generate certificate chain
|
||||
is = new ByteArrayInputStream(keyCertStr.getBytes());
|
||||
@ -281,13 +237,6 @@ public class DisabledShortRSAKeys {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
// use any free port by default
|
||||
volatile int serverPort = 0;
|
||||
|
||||
volatile Exception serverException = null;
|
||||
volatile Exception clientException = null;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (debug)
|
||||
System.setProperty("javax.net.debug", "all");
|
||||
@ -300,142 +249,7 @@ public class DisabledShortRSAKeys {
|
||||
/*
|
||||
* Start the tests.
|
||||
*/
|
||||
new DisabledShortRSAKeys();
|
||||
new DisabledShortRSAKeys().run();
|
||||
}
|
||||
|
||||
Thread clientThread = null;
|
||||
Thread serverThread = null;
|
||||
|
||||
/*
|
||||
* Primary constructor, used to drive remainder of the test.
|
||||
*
|
||||
* Fork off the other side, then do your work.
|
||||
*/
|
||||
DisabledShortRSAKeys() throws Exception {
|
||||
Exception startException = null;
|
||||
try {
|
||||
if (separateServerThread) {
|
||||
startServer(true);
|
||||
startClient(false);
|
||||
} else {
|
||||
startClient(true);
|
||||
startServer(false);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
startException = e;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for other side to close down.
|
||||
*/
|
||||
if (separateServerThread) {
|
||||
if (serverThread != null) {
|
||||
serverThread.join();
|
||||
}
|
||||
} else {
|
||||
if (clientThread != null) {
|
||||
clientThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When we get here, the test is pretty much over.
|
||||
* Which side threw the error?
|
||||
*/
|
||||
Exception local;
|
||||
Exception remote;
|
||||
|
||||
if (separateServerThread) {
|
||||
remote = serverException;
|
||||
local = clientException;
|
||||
} else {
|
||||
remote = clientException;
|
||||
local = serverException;
|
||||
}
|
||||
|
||||
Exception exception = null;
|
||||
|
||||
/*
|
||||
* Check various exception conditions.
|
||||
*/
|
||||
if ((local != null) && (remote != null)) {
|
||||
// If both failed, return the curthread's exception.
|
||||
local.initCause(remote);
|
||||
exception = local;
|
||||
} else if (local != null) {
|
||||
exception = local;
|
||||
} else if (remote != null) {
|
||||
exception = remote;
|
||||
} else if (startException != null) {
|
||||
exception = startException;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there was an exception *AND* a startException,
|
||||
* output it.
|
||||
*/
|
||||
if (exception != null) {
|
||||
if (exception != startException && startException != null) {
|
||||
exception.addSuppressed(startException);
|
||||
}
|
||||
throw exception;
|
||||
}
|
||||
|
||||
// Fall-through: no exception to throw!
|
||||
}
|
||||
|
||||
void startServer(boolean newThread) throws Exception {
|
||||
if (newThread) {
|
||||
serverThread = new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
doServerSide();
|
||||
} catch (Exception e) {
|
||||
/*
|
||||
* Our server thread just died.
|
||||
*
|
||||
* Release the client, if not active already...
|
||||
*/
|
||||
System.err.println("Server died...");
|
||||
serverReady = true;
|
||||
serverException = e;
|
||||
}
|
||||
}
|
||||
};
|
||||
serverThread.start();
|
||||
} else {
|
||||
try {
|
||||
doServerSide();
|
||||
} catch (Exception e) {
|
||||
serverException = e;
|
||||
} finally {
|
||||
serverReady = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startClient(boolean newThread) throws Exception {
|
||||
if (newThread) {
|
||||
clientThread = new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
doClientSide();
|
||||
} catch (Exception e) {
|
||||
/*
|
||||
* Our client thread just died.
|
||||
*/
|
||||
System.err.println("Client died...");
|
||||
clientException = e;
|
||||
}
|
||||
}
|
||||
};
|
||||
clientThread.start();
|
||||
} else {
|
||||
try {
|
||||
doClientSide();
|
||||
} catch (Exception e) {
|
||||
clientException = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8172003
|
||||
* @summary Test that TransformService.getInstance() throws a
|
||||
* NoSuchProviderException when provider is unknown
|
||||
* @run main UnknownProvider
|
||||
*/
|
||||
|
||||
import javax.xml.crypto.dsig.TransformService;
|
||||
import javax.xml.crypto.dsig.Transform;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class UnknownProvider {
|
||||
|
||||
public static void main(String[] args) throws NoSuchAlgorithmException {
|
||||
try {
|
||||
TransformService ts = TransformService.getInstance(
|
||||
Transform.BASE64, "DOM", "SomeProviderThatDoesNotExist");
|
||||
}
|
||||
catch(NoSuchProviderException e) {
|
||||
// this is expected
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8172003
|
||||
* @summary Test that XMLSignatureFactory.getInstance() throws a
|
||||
* NoSuchProviderException when provider is unknown
|
||||
* @run main UnknownProvider
|
||||
*/
|
||||
|
||||
import javax.xml.crypto.dsig.XMLSignatureFactory;
|
||||
import java.security.NoSuchProviderException;
|
||||
|
||||
public class UnknownProvider {
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
XMLSignatureFactory sf = XMLSignatureFactory.getInstance(
|
||||
"DOM", "SomeProviderThatDoesNotExist");
|
||||
}
|
||||
catch(NoSuchProviderException e) {
|
||||
// this is expected
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8172003
|
||||
* @summary Test that KeyInfoFactory.getInstance() throws a
|
||||
* NoSuchProviderException when provider is unknown
|
||||
* @run main UnknownProvider
|
||||
*/
|
||||
|
||||
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
|
||||
import java.security.NoSuchProviderException;
|
||||
|
||||
public class UnknownProvider {
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
KeyInfoFactory fac = KeyInfoFactory.getInstance(
|
||||
"DOM", "SomeProviderThatDoesNotExist");
|
||||
}
|
||||
catch(NoSuchProviderException e) {
|
||||
// this is expected
|
||||
}
|
||||
}
|
||||
}
|
@ -35,7 +35,7 @@ import static org.testng.Assert.assertTrue;
|
||||
/**
|
||||
* Utility class for creating test modules.
|
||||
*/
|
||||
public class ModuleSourceBuilder {
|
||||
public class ModuleInfoMaker {
|
||||
private static String MODULE_INFO_JAVA = "module-info.java";
|
||||
private static Pattern MODULE_PATTERN =
|
||||
Pattern.compile("module\\s+((?:\\w+\\.)*)");
|
||||
@ -45,7 +45,7 @@ public class ModuleSourceBuilder {
|
||||
Pattern.compile("(?:public\\s+)?(?:class|enum|interface)\\s+(\\w+)");
|
||||
|
||||
private final Path dir;
|
||||
public ModuleSourceBuilder(Path dir) {
|
||||
public ModuleInfoMaker(Path dir) {
|
||||
this.dir = dir;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 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
|
||||
@ -21,27 +21,32 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This test is run using PostThruProxy.sh
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.security.KeyStore;
|
||||
import javax.net.*;
|
||||
import javax.net.ssl.*;
|
||||
import java.security.cert.*;
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
/*
|
||||
* This test case is written to test the https POST through a proxy.
|
||||
* There is no proxy authentication done.
|
||||
*
|
||||
* PostThruProxy.java -- includes a simple server that serves
|
||||
* http POST method requests in secure channel, and a client
|
||||
* that makes https POST request through a proxy.
|
||||
* @test
|
||||
* @bug 4423074
|
||||
* @modules java.base/sun.net.www
|
||||
* @summary This test case is written to test the https POST through a proxy.
|
||||
* There is no proxy authentication done. It includes a simple server
|
||||
* that serves http POST method requests in secure channel, and a client
|
||||
* that makes https POST request through a proxy.
|
||||
* @library /test/lib
|
||||
* @compile OriginServer.java ProxyTunnelServer.java
|
||||
* @run main/othervm PostThruProxy
|
||||
*/
|
||||
|
||||
public class PostThruProxy {
|
||||
|
||||
private static final String TEST_SRC = System.getProperty("test.src", ".");
|
||||
private static final int TIMEOUT = 30000;
|
||||
|
||||
/*
|
||||
* Where do we find the keystores?
|
||||
*/
|
||||
@ -76,14 +81,10 @@ public class PostThruProxy {
|
||||
/*
|
||||
* Main method to create the server and client
|
||||
*/
|
||||
public static void main(String args[]) throws Exception
|
||||
{
|
||||
String keyFilename =
|
||||
args[1] + "/" + pathToStores +
|
||||
"/" + keyStoreFile;
|
||||
String trustFilename =
|
||||
args[1] + "/" + pathToStores +
|
||||
"/" + trustStoreFile;
|
||||
public static void main(String args[]) throws Exception {
|
||||
String keyFilename = TEST_SRC + "/" + pathToStores + "/" + keyStoreFile;
|
||||
String trustFilename = TEST_SRC + "/" + pathToStores + "/"
|
||||
+ trustStoreFile;
|
||||
|
||||
System.setProperty("javax.net.ssl.keyStore", keyFilename);
|
||||
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
|
||||
@ -95,10 +96,9 @@ public class PostThruProxy {
|
||||
* setup the server
|
||||
*/
|
||||
try {
|
||||
ServerSocketFactory ssf =
|
||||
PostThruProxy.getServerSocketFactory(useSSL);
|
||||
ServerSocketFactory ssf = getServerSocketFactory(useSSL);
|
||||
ServerSocket ss = ssf.createServerSocket(serverPort);
|
||||
ss.setSoTimeout(30000); // 30 seconds
|
||||
ss.setSoTimeout(TIMEOUT); // 30 seconds
|
||||
serverPort = ss.getLocalPort();
|
||||
new TestServer(ss);
|
||||
} catch (Exception e) {
|
||||
@ -108,35 +108,29 @@ public class PostThruProxy {
|
||||
}
|
||||
// trigger the client
|
||||
try {
|
||||
doClientSide(args[0]);
|
||||
doClientSide();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Client side failed: " +
|
||||
e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ServerSocketFactory getServerSocketFactory
|
||||
(boolean useSSL) throws Exception {
|
||||
if (useSSL) {
|
||||
SSLServerSocketFactory ssf = null;
|
||||
// set up key manager to do server authentication
|
||||
SSLContext ctx;
|
||||
KeyManagerFactory kmf;
|
||||
KeyStore ks;
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
KeyStore ks = KeyStore.getInstance("JKS");
|
||||
char[] passphrase = passwd.toCharArray();
|
||||
|
||||
ctx = SSLContext.getInstance("TLS");
|
||||
kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
ks = KeyStore.getInstance("JKS");
|
||||
|
||||
ks.load(new FileInputStream(System.getProperty(
|
||||
"javax.net.ssl.keyStore")), passphrase);
|
||||
kmf.init(ks, passphrase);
|
||||
ctx.init(kmf.getKeyManagers(), null, null);
|
||||
|
||||
ssf = ctx.getServerSocketFactory();
|
||||
return ssf;
|
||||
return ctx.getServerSocketFactory();
|
||||
} else {
|
||||
return ServerSocketFactory.getDefault();
|
||||
}
|
||||
@ -147,7 +141,7 @@ public class PostThruProxy {
|
||||
*/
|
||||
static String postMsg = "Testing HTTP post on a https server";
|
||||
|
||||
static void doClientSide(String hostname) throws Exception {
|
||||
static void doClientSide() throws Exception {
|
||||
HostnameVerifier reservedHV =
|
||||
HttpsURLConnection.getDefaultHostnameVerifier();
|
||||
try {
|
||||
@ -162,10 +156,12 @@ public class PostThruProxy {
|
||||
*/
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(
|
||||
new NameVerifier());
|
||||
URL url = new URL("https://" + hostname+ ":" + serverPort);
|
||||
URL url = new URL("https://" + getHostname() +":" + serverPort);
|
||||
|
||||
Proxy p = new Proxy(Proxy.Type.HTTP, pAddr);
|
||||
HttpsURLConnection https = (HttpsURLConnection)url.openConnection(p);
|
||||
https.setConnectTimeout(TIMEOUT);
|
||||
https.setReadTimeout(TIMEOUT);
|
||||
https.setDoOutput(true);
|
||||
https.setRequestMethod("POST");
|
||||
PrintStream ps = null;
|
||||
@ -190,6 +186,9 @@ public class PostThruProxy {
|
||||
if (ps != null)
|
||||
ps.close();
|
||||
throw e;
|
||||
} catch (SocketTimeoutException e) {
|
||||
System.out.println("Client can not get response in time: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
} finally {
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
|
||||
@ -210,4 +209,13 @@ public class PostThruProxy {
|
||||
pserver.start();
|
||||
return new InetSocketAddress("localhost", pserver.getPort());
|
||||
}
|
||||
|
||||
private static String getHostname() {
|
||||
try {
|
||||
OutputAnalyzer oa = ProcessTools.executeCommand("hostname");
|
||||
return oa.getOutput().trim();
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("Get hostname failed.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,62 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# @test
|
||||
# @bug 4423074
|
||||
# @summary Need to rebase all the duplicated classes from Merlin
|
||||
# @modules java.base/sun.net.www
|
||||
|
||||
HOSTNAME=`uname -n`
|
||||
OS=`uname -s`
|
||||
case "$OS" in
|
||||
SunOS | Linux | Darwin | AIX )
|
||||
PS=":"
|
||||
FS="/"
|
||||
;;
|
||||
CYGWIN* )
|
||||
PS=";"
|
||||
FS="/"
|
||||
;;
|
||||
Windows* )
|
||||
PS=";"
|
||||
FS="\\"
|
||||
;;
|
||||
* )
|
||||
echo "Unrecognized system!"
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
|
||||
EXTRAOPTS="--add-exports java.base/sun.net.www=ALL-UNNAMED"
|
||||
|
||||
${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . \
|
||||
${TESTSRC}${FS}OriginServer.java \
|
||||
${TESTSRC}${FS}ProxyTunnelServer.java \
|
||||
${TESTSRC}${FS}PostThruProxy.java
|
||||
${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} \
|
||||
PostThruProxy ${HOSTNAME} ${TESTSRC}
|
||||
exit
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 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
|
||||
@ -21,28 +21,32 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This test is run through PostThruProxyWithAuth.sh
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.security.KeyStore;
|
||||
import javax.net.*;
|
||||
import javax.net.ssl.*;
|
||||
import java.security.cert.*;
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
/*
|
||||
* This test case is written to test the https POST through a proxy
|
||||
* with proxy authentication.
|
||||
*
|
||||
* PostThruProxyWithAuth.java -- includes a simple server that serves
|
||||
* http POST method requests in secure channel, and a client
|
||||
* that makes https POST request through a proxy.
|
||||
* @test
|
||||
* @bug 4423074
|
||||
* @modules java.base/sun.net.www
|
||||
* @summary This test case is written to test the https POST through a proxy
|
||||
* with proxy authentication. It includes a simple server that serves
|
||||
* http POST method requests in secure channel, and a client that
|
||||
* makes https POST request through a proxy.
|
||||
* @library /test/lib
|
||||
* @compile OriginServer.java ProxyTunnelServer.java
|
||||
* @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes= PostThruProxyWithAuth
|
||||
*/
|
||||
|
||||
public class PostThruProxyWithAuth {
|
||||
|
||||
private static final String TEST_SRC = System.getProperty("test.src", ".");
|
||||
private static final int TIMEOUT = 30000;
|
||||
|
||||
/*
|
||||
* Where do we find the keystores?
|
||||
*/
|
||||
@ -78,14 +82,10 @@ public class PostThruProxyWithAuth {
|
||||
/*
|
||||
* Main method to create the server and client
|
||||
*/
|
||||
public static void main(String args[]) throws Exception
|
||||
{
|
||||
String keyFilename =
|
||||
args[1] + "/" + pathToStores +
|
||||
"/" + keyStoreFile;
|
||||
String trustFilename =
|
||||
args[1] + "/" + pathToStores +
|
||||
"/" + trustStoreFile;
|
||||
public static void main(String args[]) throws Exception {
|
||||
String keyFilename = TEST_SRC + "/" + pathToStores + "/" + keyStoreFile;
|
||||
String trustFilename = TEST_SRC + "/" + pathToStores + "/"
|
||||
+ trustStoreFile;
|
||||
|
||||
System.setProperty("javax.net.ssl.keyStore", keyFilename);
|
||||
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
|
||||
@ -97,10 +97,9 @@ public class PostThruProxyWithAuth {
|
||||
* setup the server
|
||||
*/
|
||||
try {
|
||||
ServerSocketFactory ssf =
|
||||
PostThruProxyWithAuth.getServerSocketFactory(useSSL);
|
||||
ServerSocketFactory ssf = getServerSocketFactory(useSSL);
|
||||
ServerSocket ss = ssf.createServerSocket(serverPort);
|
||||
ss.setSoTimeout(30000); // 30 seconds
|
||||
ss.setSoTimeout(TIMEOUT); // 30 seconds
|
||||
serverPort = ss.getLocalPort();
|
||||
new TestServer(ss);
|
||||
} catch (Exception e) {
|
||||
@ -110,7 +109,7 @@ public class PostThruProxyWithAuth {
|
||||
}
|
||||
// trigger the client
|
||||
try {
|
||||
doClientSide(args[0]);
|
||||
doClientSide();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Client side failed: " +
|
||||
e.getMessage());
|
||||
@ -121,24 +120,18 @@ public class PostThruProxyWithAuth {
|
||||
private static ServerSocketFactory getServerSocketFactory
|
||||
(boolean useSSL) throws Exception {
|
||||
if (useSSL) {
|
||||
SSLServerSocketFactory ssf = null;
|
||||
// set up key manager to do server authentication
|
||||
SSLContext ctx;
|
||||
KeyManagerFactory kmf;
|
||||
KeyStore ks;
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
KeyStore ks = KeyStore.getInstance("JKS");
|
||||
char[] passphrase = passwd.toCharArray();
|
||||
|
||||
ctx = SSLContext.getInstance("TLS");
|
||||
kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
ks = KeyStore.getInstance("JKS");
|
||||
|
||||
ks.load(new FileInputStream(System.getProperty(
|
||||
"javax.net.ssl.keyStore")), passphrase);
|
||||
kmf.init(ks, passphrase);
|
||||
ctx.init(kmf.getKeyManagers(), null, null);
|
||||
|
||||
ssf = ctx.getServerSocketFactory();
|
||||
return ssf;
|
||||
return ctx.getServerSocketFactory();
|
||||
} else {
|
||||
return ServerSocketFactory.getDefault();
|
||||
}
|
||||
@ -149,7 +142,7 @@ public class PostThruProxyWithAuth {
|
||||
*/
|
||||
static String postMsg = "Testing HTTP post on a https server";
|
||||
|
||||
static void doClientSide(String hostname) throws Exception {
|
||||
static void doClientSide() throws Exception {
|
||||
/*
|
||||
* setup up a proxy
|
||||
*/
|
||||
@ -161,10 +154,12 @@ public class PostThruProxyWithAuth {
|
||||
*/
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(
|
||||
new NameVerifier());
|
||||
URL url = new URL("https://" + hostname + ":" + serverPort);
|
||||
URL url = new URL("https://" + getHostname() + ":" + serverPort);
|
||||
|
||||
Proxy p = new Proxy(Proxy.Type.HTTP, pAddr);
|
||||
HttpsURLConnection https = (HttpsURLConnection)url.openConnection(p);
|
||||
https.setConnectTimeout(TIMEOUT);
|
||||
https.setReadTimeout(TIMEOUT);
|
||||
https.setDoOutput(true);
|
||||
https.setRequestMethod("POST");
|
||||
PrintStream ps = null;
|
||||
@ -188,6 +183,9 @@ public class PostThruProxyWithAuth {
|
||||
if (ps != null)
|
||||
ps.close();
|
||||
throw e;
|
||||
} catch (SocketTimeoutException e) {
|
||||
System.out.println("Client can not get response in time: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,4 +219,13 @@ public class PostThruProxyWithAuth {
|
||||
"test123".toCharArray());
|
||||
}
|
||||
}
|
||||
|
||||
private static String getHostname() {
|
||||
try {
|
||||
OutputAnalyzer oa = ProcessTools.executeCommand("hostname");
|
||||
return oa.getOutput().trim();
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("Get hostname failed.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,62 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# @test
|
||||
# @bug 4423074
|
||||
# @summary Need to rebase all the duplicated classes from Merlin
|
||||
# @modules java.base/sun.net.www
|
||||
|
||||
HOSTNAME=`uname -n`
|
||||
OS=`uname -s`
|
||||
case "$OS" in
|
||||
SunOS | Linux | Darwin | AIX )
|
||||
PS=":"
|
||||
FS="/"
|
||||
;;
|
||||
CYGWIN* )
|
||||
PS=";"
|
||||
FS="/"
|
||||
;;
|
||||
Windows* )
|
||||
PS=";"
|
||||
FS="\\"
|
||||
;;
|
||||
* )
|
||||
echo "Unrecognized system!"
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
|
||||
EXTRAOPTS="--add-exports java.base/sun.net.www=ALL-UNNAMED"
|
||||
${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} \
|
||||
-d . ${TESTSRC}${FS}OriginServer.java \
|
||||
${TESTSRC}${FS}ProxyTunnelServer.java \
|
||||
${TESTSRC}${FS}PostThruProxyWithAuth.java
|
||||
${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} \
|
||||
-Djdk.http.auth.tunneling.disabledSchemes= \
|
||||
PostThruProxyWithAuth ${HOSTNAME} ${TESTSRC}
|
||||
exit
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 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
|
||||
@ -32,13 +32,14 @@
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import javax.net.ssl.*;
|
||||
import javax.net.ServerSocketFactory;
|
||||
import sun.net.www.*;
|
||||
import java.util.Base64;
|
||||
|
||||
public class ProxyTunnelServer extends Thread {
|
||||
|
||||
private static final int TIMEOUT = 30000;
|
||||
|
||||
private static ServerSocket ss = null;
|
||||
/*
|
||||
* holds the registered user's username and password
|
||||
@ -64,8 +65,9 @@ public class ProxyTunnelServer extends Thread {
|
||||
|
||||
public ProxyTunnelServer() throws IOException {
|
||||
if (ss == null) {
|
||||
ss = (ServerSocket) ServerSocketFactory.getDefault().
|
||||
createServerSocket(0);
|
||||
ss = (ServerSocket) ServerSocketFactory.getDefault()
|
||||
.createServerSocket(0);
|
||||
ss.setSoTimeout(TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,6 +88,9 @@ public class ProxyTunnelServer extends Thread {
|
||||
try {
|
||||
clientSocket = ss.accept();
|
||||
processRequests();
|
||||
} catch (SocketTimeoutException e) {
|
||||
System.out.println(
|
||||
"Proxy can not get response in time: " + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
System.out.println("Proxy Failed: " + e);
|
||||
e.printStackTrace();
|
||||
@ -188,8 +193,8 @@ public class ProxyTunnelServer extends Thread {
|
||||
serverToClient.start();
|
||||
System.out.println("Proxy: Started tunneling.......");
|
||||
|
||||
clientToServer.join();
|
||||
serverToClient.join();
|
||||
clientToServer.join(TIMEOUT);
|
||||
serverToClient.join(TIMEOUT);
|
||||
System.out.println("Proxy: Finished tunneling........");
|
||||
|
||||
clientToServer.close();
|
||||
@ -219,13 +224,11 @@ public class ProxyTunnelServer extends Thread {
|
||||
int BUFFER_SIZE = 400;
|
||||
byte[] buf = new byte[BUFFER_SIZE];
|
||||
int bytesRead = 0;
|
||||
int count = 0; // keep track of the amount of data transfer
|
||||
|
||||
try {
|
||||
while ((bytesRead = input.read(buf)) >= 0) {
|
||||
output.write(buf, 0, bytesRead);
|
||||
output.flush();
|
||||
count += bytesRead;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
/*
|
||||
@ -236,7 +239,7 @@ public class ProxyTunnelServer extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
private void close() {
|
||||
try {
|
||||
if (!sockIn.isClosed())
|
||||
sockIn.close();
|
||||
@ -275,7 +278,7 @@ public class ProxyTunnelServer extends Thread {
|
||||
serverPort = Integer.parseInt(connectInfo.substring(endi+1));
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Proxy recieved a request: "
|
||||
+ connectStr);
|
||||
+ connectStr, e);
|
||||
}
|
||||
serverInetAddr = InetAddress.getByName(serverName);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7152176 8168518
|
||||
* @bug 7152176 8168518 8172017
|
||||
* @summary More krb5 tests
|
||||
* @library ../../../../java/security/testlibrary/ /test/lib
|
||||
* @run main/othervm/timeout=300 ReplayCacheTestProc
|
||||
@ -75,19 +75,28 @@ public class ReplayCacheTestProc {
|
||||
private static String HOST = "localhost";
|
||||
|
||||
private static final String SERVICE;
|
||||
private static long uid;
|
||||
private static String cwd;
|
||||
|
||||
static {
|
||||
String tmp = System.getProperty("test.service");
|
||||
SERVICE = (tmp == null) ? "service" : tmp;
|
||||
uid = jdk.internal.misc.VM.geteuid();
|
||||
// Where should the rcache be saved. KRB5RCACHEDIR is not
|
||||
// recognized on Solaris (might be supported on Solaris 12),
|
||||
// and directory name is different when launched by root.
|
||||
// See manpage krb5envvar(5) on KRB5RCNAME.
|
||||
if (System.getProperty("os.name").startsWith("SunOS")) {
|
||||
if (uid == 0) {
|
||||
cwd = "/var/krb5/rcache/root/";
|
||||
} else {
|
||||
cwd = "/var/krb5/rcache/";
|
||||
}
|
||||
} else {
|
||||
cwd = System.getProperty("user.dir");
|
||||
}
|
||||
}
|
||||
|
||||
// Where should the rcache be saved. It seems KRB5RCACHEDIR is not
|
||||
// recognized on Solaris. Maybe version too low? I see 1.6.
|
||||
private static String cwd =
|
||||
System.getProperty("os.name").startsWith("SunOS") ?
|
||||
"/var/krb5/rcache/" :
|
||||
System.getProperty("user.dir");
|
||||
|
||||
private static MessageDigest md5, sha256;
|
||||
|
||||
static {
|
||||
@ -99,7 +108,6 @@ public class ReplayCacheTestProc {
|
||||
}
|
||||
}
|
||||
|
||||
private static long uid;
|
||||
|
||||
public static void main0(String[] args) throws Exception {
|
||||
System.setProperty("java.security.krb5.conf", OneKDC.KRB5_CONF);
|
||||
@ -114,8 +122,6 @@ public class ReplayCacheTestProc {
|
||||
Ex[] result;
|
||||
int numPerType = 2; // number of acceptors per type
|
||||
|
||||
uid = jdk.internal.misc.VM.geteuid();
|
||||
|
||||
KDC kdc = KDC.create(OneKDC.REALM, HOST, 0, true);
|
||||
for (int i=0; i<nc; i++) {
|
||||
kdc.addPrincipal(client(i), OneKDC.PASS);
|
||||
|
@ -23,14 +23,13 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7110803
|
||||
* @bug 7110803 8170732
|
||||
* @summary SASL service for multiple hostnames
|
||||
* @compile -XDignore.symbol.file SaslBasic.java
|
||||
* @run main/othervm SaslBasic bound
|
||||
* @run main/othervm SaslBasic unbound
|
||||
* @run main/othervm SaslBasic bound auth-int
|
||||
* @run main/othervm SaslBasic unbound auth-conf
|
||||
* @run main/othervm SaslBasic bound auth
|
||||
*/
|
||||
import com.sun.security.jgss.InquireType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@ -51,7 +50,7 @@ public class SaslBasic {
|
||||
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
|
||||
|
||||
HashMap clntprops = new HashMap();
|
||||
clntprops.put(Sasl.QOP, "auth-conf");
|
||||
clntprops.put(Sasl.QOP, args[1]);
|
||||
SaslClient sc = Sasl.createSaslClient(
|
||||
new String[]{"GSSAPI"}, null, "server",
|
||||
name, clntprops, null);
|
||||
@ -74,9 +73,11 @@ public class SaslBasic {
|
||||
});
|
||||
|
||||
byte[] token = new byte[0];
|
||||
byte[] lastClientToken = null;
|
||||
while (!sc.isComplete() || !ss.isComplete()) {
|
||||
if (!sc.isComplete()) {
|
||||
token = sc.evaluateChallenge(token);
|
||||
lastClientToken = token;
|
||||
}
|
||||
if (!ss.isComplete()) {
|
||||
token = ss.evaluateResponse(token);
|
||||
@ -94,11 +95,20 @@ public class SaslBasic {
|
||||
if (key == null) {
|
||||
throw new Exception("Extended negotiated property not read");
|
||||
}
|
||||
byte[] hello = "hello".getBytes();
|
||||
token = sc.wrap(hello, 0, hello.length);
|
||||
token = ss.unwrap(token, 0, token.length);
|
||||
if (!Arrays.equals(hello, token)) {
|
||||
throw new Exception("Message altered");
|
||||
|
||||
if (args[1].equals("auth")) {
|
||||
// 8170732. These are the maximum size bytes after jgss/krb5 wrap.
|
||||
if (lastClientToken[17] != 0 || lastClientToken[18] != 0
|
||||
|| lastClientToken[19] != 0) {
|
||||
throw new Exception("maximum size for auth must be 0");
|
||||
}
|
||||
} else {
|
||||
byte[] hello = "hello".getBytes();
|
||||
token = sc.wrap(hello, 0, hello.length);
|
||||
token = ss.unwrap(token, 0, token.length);
|
||||
if (!Arrays.equals(hello, token)) {
|
||||
throw new Exception("Message altered");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2011, 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
|
||||
@ -21,18 +21,21 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
//
|
||||
// SunJSSE does not support dynamic system properties, no way to re-use
|
||||
// system properties in samevm/agentvm mode.
|
||||
//
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4919147
|
||||
* @summary Support for token-based KeyStores
|
||||
* @run main/othervm BadTSProvider
|
||||
*
|
||||
* SunJSSE does not support dynamic system properties, no way to re-use
|
||||
* system properties in samevm/agentvm mode.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.security.*;
|
||||
import javax.net.ssl.*;
|
||||
|
||||
public class BadTSProvider {
|
||||
@ -179,13 +182,19 @@ public class BadTSProvider {
|
||||
// XXX this test must be updated if the exception message changes
|
||||
|
||||
Throwable cause = se.getCause();
|
||||
if (cause instanceof java.security.NoSuchAlgorithmException == false) {
|
||||
if (!(cause instanceof NoSuchAlgorithmException)) {
|
||||
se.printStackTrace();
|
||||
throw new Exception("Unexpected exception" + se);
|
||||
}
|
||||
|
||||
cause = cause.getCause();
|
||||
if (cause instanceof java.security.NoSuchProviderException == false) {
|
||||
if (!(cause instanceof KeyStoreException)) {
|
||||
se.printStackTrace();
|
||||
throw new Exception("Unexpected exception" + se);
|
||||
}
|
||||
|
||||
cause = cause.getCause();
|
||||
if (!(cause instanceof NoSuchProviderException)) {
|
||||
se.printStackTrace();
|
||||
throw new Exception("Unexpected exception" + se);
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
* @bug 4392475
|
||||
* @library /javax/net/ssl/templates
|
||||
* @summary Calling setWantClientAuth(true) disables anonymous suites
|
||||
* @run main/othervm AnonCipherWithWantClientAuth
|
||||
* @run main/othervm -Djavax.net.debug=all AnonCipherWithWantClientAuth
|
||||
*/
|
||||
|
||||
import java.io.InputStream;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
@ -45,7 +45,7 @@ import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import sun.security.validator.KeyStores;
|
||||
import sun.security.validator.TrustStoreUtil;
|
||||
import sun.security.validator.Validator;
|
||||
|
||||
|
||||
@ -113,7 +113,7 @@ public class EndEntityExtensionCheck {
|
||||
|
||||
Validator v = Validator.getInstance(Validator.TYPE_SIMPLE,
|
||||
Validator.VAR_TLS_CLIENT,
|
||||
KeyStores.getTrustedCerts(ks));
|
||||
TrustStoreUtil.getTrustedCerts(ks));
|
||||
try {
|
||||
v.validate(chain);
|
||||
throw new Exception("Chain should not have validated " +
|
||||
|
@ -27,7 +27,7 @@
|
||||
* @summary Basic argument validation for --add-exports
|
||||
* @library /lib/testlibrary
|
||||
* @modules jdk.compiler
|
||||
* @build AddExportsTestWarningError CompilerUtils ModuleSourceBuilder
|
||||
* @build AddExportsTestWarningError CompilerUtils ModuleInfoMaker
|
||||
* @build jdk.testlibrary.*
|
||||
* @run testng AddExportsTestWarningError
|
||||
*/
|
||||
@ -59,7 +59,7 @@ public class AddExportsTestWarningError {
|
||||
|
||||
@BeforeTest
|
||||
public void setup() throws Exception {
|
||||
ModuleSourceBuilder builder = new ModuleSourceBuilder(SRC_DIR);
|
||||
ModuleInfoMaker builder = new ModuleInfoMaker(SRC_DIR);
|
||||
builder.writeJavaFiles("m1",
|
||||
"module m1 { }",
|
||||
"package p1; public class C1 { " +
|
||||
|
@ -27,7 +27,7 @@
|
||||
* @summary Basic argument validation for --add-reads
|
||||
* @library /lib/testlibrary
|
||||
* @modules jdk.compiler
|
||||
* @build AddReadsTestWarningError CompilerUtils ModuleSourceBuilder
|
||||
* @build AddReadsTestWarningError CompilerUtils ModuleInfoMaker
|
||||
* @build jdk.testlibrary.*
|
||||
* @run testng AddReadsTestWarningError
|
||||
*/
|
||||
@ -59,7 +59,7 @@ public class AddReadsTestWarningError {
|
||||
|
||||
@BeforeTest
|
||||
public void setup() throws Exception {
|
||||
ModuleSourceBuilder builder = new ModuleSourceBuilder(SRC_DIR);
|
||||
ModuleInfoMaker builder = new ModuleInfoMaker(SRC_DIR);
|
||||
builder.writeJavaFiles("m1",
|
||||
"module m1 { requires m4; }",
|
||||
"package p1; public class C1 { " +
|
||||
|
@ -95,19 +95,20 @@ public class JavaClassPathTest {
|
||||
public Object[][] classpath() {
|
||||
return new Object[][]{
|
||||
// true indicates that class path default to current working directory
|
||||
{ "", "." },
|
||||
{ "-Djava.class.path", "." },
|
||||
{ "-Djava.class.path=", "" },
|
||||
{ "-Djava.class.path=.", "." },
|
||||
{ List.of(), "." },
|
||||
{ List.of("-cp", ""), "" },
|
||||
{ List.of("-cp", "."), "." },
|
||||
{ List.of("-Djava.class.path"), "." },
|
||||
{ List.of("-Djava.class.path="), "" },
|
||||
{ List.of("-Djava.class.path=."), "." },
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "classpath")
|
||||
public void testUnnamedModule(String option, String expected) throws Throwable {
|
||||
List<String> args = new ArrayList<>();
|
||||
if (!option.isEmpty()) {
|
||||
args.add(option);
|
||||
}
|
||||
public void testUnnamedModule(List<String> options, String expected)
|
||||
throws Throwable
|
||||
{
|
||||
List<String> args = new ArrayList<>(options);
|
||||
args.add(TEST_MAIN);
|
||||
args.add(Boolean.toString(true));
|
||||
args.add(expected);
|
||||
@ -195,8 +196,12 @@ public class JavaClassPathTest {
|
||||
}
|
||||
|
||||
private OutputAnalyzer execute(List<String> options) throws Throwable {
|
||||
ProcessBuilder pb =
|
||||
createJavaProcessBuilder(options.toArray(new String[0]));
|
||||
ProcessBuilder pb = createJavaProcessBuilder(
|
||||
options.stream()
|
||||
.map(this::autoQuote)
|
||||
.toArray(String[]::new)
|
||||
);
|
||||
|
||||
Map<String,String> env = pb.environment();
|
||||
// remove CLASSPATH environment variable
|
||||
String value = env.remove("CLASSPATH");
|
||||
@ -205,4 +210,16 @@ public class JavaClassPathTest {
|
||||
.errorTo(System.out);
|
||||
}
|
||||
|
||||
private static final boolean IS_WINDOWS
|
||||
= System.getProperty("os.name").startsWith("Windows");
|
||||
|
||||
/*
|
||||
* Autoquote empty string argument on Windows
|
||||
*/
|
||||
private String autoQuote(String arg) {
|
||||
if (IS_WINDOWS && arg.isEmpty()) {
|
||||
return "\"\"";
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
@ -67,14 +67,17 @@ ifneq ($(LIBS_DIR), )
|
||||
# or risk invalidating the build output from external changes.
|
||||
ifeq ($(filter $(OUTPUT_ROOT)/%, $(LIBS_DIR)), )
|
||||
LINK_MACRO := install-file
|
||||
LOG_ACTION := Copying
|
||||
else
|
||||
LINK_MACRO := link-file-relative
|
||||
LOG_ACTION := Creating symlink
|
||||
endif
|
||||
$(eval $(call SetupCopyFiles, LINK_LIBS, \
|
||||
SRC := $(LIBS_DIR), \
|
||||
DEST := $(JDK_OUTPUTDIR)/lib, \
|
||||
FILES := $(filter-out %$(SHARED_LIBRARY_SUFFIX), $(call CacheFind, $(LIBS_DIR))), \
|
||||
MACRO := $(LINK_MACRO), \
|
||||
LOG_ACTION := $(LOG_ACTION), \
|
||||
))
|
||||
TARGETS += $(COPY_LIBS) $(LINK_LIBS)
|
||||
endif
|
||||
|
@ -630,13 +630,12 @@ else
|
||||
# in javadoc.
|
||||
java.desktop-gensrc-jdk: java.base-gensrc
|
||||
|
||||
# The annotation processing for jdk.vm.ci needs java.base classes from the
|
||||
# current JDK.
|
||||
jdk.vm.ci-gensrc-hotspot: java.base-java
|
||||
|
||||
# The annotation processing for jdk.vm.compiler needs classes from the current JDK.
|
||||
jdk.vm.compiler-gensrc-hotspot: java.base-java java.management-java \
|
||||
jdk.management-java jdk.vm.ci-java jdk.unsupported-java
|
||||
# The annotation processing for jdk.vm.ci and jdk.vm.compiler needs classes
|
||||
# from the current JDK.
|
||||
jdk.vm.ci-gensrc-hotspot: $(addsuffix -java, \
|
||||
$(call FindTransitiveDepsForModule, jdk.vm.ci))
|
||||
jdk.vm.compiler-gensrc-hotspot: $(addsuffix -java, \
|
||||
$(call FindTransitiveDepsForModule, jdk.vm.compiler))
|
||||
|
||||
# For jdk.vm.compiler, the gensrc step is generating a module-info.java.extra
|
||||
# file to be processed by the gensrc-moduleinfo target.
|
||||
|
@ -76,6 +76,7 @@ else
|
||||
$(filter $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE)/%, \
|
||||
$(TARGETS))), \
|
||||
MACRO := link-file-relative, \
|
||||
LOG_ACTION := Creating symlink, \
|
||||
))
|
||||
endif
|
||||
|
||||
|
@ -694,8 +694,9 @@ define AddFileToCopy
|
||||
# 2 : Dest file
|
||||
# 3 : Variable to add targets to
|
||||
# 4 : Macro to call for copy operation
|
||||
# 5 : Action text to log
|
||||
$2: $1
|
||||
$$(call LogInfo, Copying $$(patsubst $(OUTPUT_ROOT)/%,%,$$@))
|
||||
$$(call LogInfo, $(strip $5) $$(patsubst $(OUTPUT_ROOT)/%,%,$$@))
|
||||
$$($$(strip $4))
|
||||
|
||||
$3 += $2
|
||||
@ -721,6 +722,7 @@ identity = \
|
||||
# Default is 'install-file'
|
||||
# NAME_MACRO : Optionally supply a macro that rewrites the target file name
|
||||
# based on the source file name
|
||||
# LOG_ACTION : Optionally specify a different action text for log messages
|
||||
SetupCopyFiles = $(NamedParamsMacroTemplate)
|
||||
define SetupCopyFilesBody
|
||||
|
||||
@ -737,6 +739,10 @@ define SetupCopyFilesBody
|
||||
$1_NAME_MACRO := identity
|
||||
endif
|
||||
|
||||
ifeq ($$($1_LOG_ACTION), )
|
||||
$1_LOG_ACTION := Copying
|
||||
endif
|
||||
|
||||
# Remove any trailing slash from SRC and DEST
|
||||
$1_SRC := $$(patsubst %/,%,$$($1_SRC))
|
||||
$1_DEST := $$(patsubst %/,%,$$($1_DEST))
|
||||
@ -744,7 +750,7 @@ define SetupCopyFilesBody
|
||||
$$(foreach f, $$(patsubst $$($1_SRC)/%,%,$$($1_FILES)), \
|
||||
$$(eval $$(call AddFileToCopy, $$($1_SRC)/$$f, \
|
||||
$$($1_DEST)/$$(call $$(strip $$($1_NAME_MACRO)),$$(if $$($1_FLATTEN),$$(notdir $$f),$$f)), \
|
||||
$1, $$($1_MACRO))))
|
||||
$1, $$($1_MACRO), $$($1_LOG_ACTION))))
|
||||
|
||||
endef
|
||||
|
||||
|
@ -384,3 +384,4 @@ a7f21ee6ed30695a6de14e74035d2857a754f62b jdk-9+144
|
||||
0a4bc2f049132ddc20985565bb41b2be8a458dda jdk-9+148
|
||||
c281306d33d83c92e0d870ace385d5f99678d7e7 jdk-9+149
|
||||
ace1d994bca775d6545a4c874ae73d1dfc9ec18b jdk-9+150
|
||||
2a0437036a64853334e538044eb68d2df70075fa jdk-9+151
|
||||
|
@ -24,33 +24,33 @@ and downlaoded using
|
||||
|
||||
You can clone Nashorn Mercurial forest using this command:
|
||||
|
||||
hg fclone http://hg.openjdk.java.net/nashorn/jdk8 nashorn~jdk8
|
||||
hg fclone http://hg.openjdk.java.net/nashorn/jdk9 nashorn~jdk9
|
||||
|
||||
To update your copy of the forest (fwith the latest code:
|
||||
|
||||
(cd nashorn~jdk8 ; hg fpull)
|
||||
(cd nashorn~jdk9 ; hg fpull)
|
||||
|
||||
Or just the nashorn subdirectory with
|
||||
|
||||
(cd nashorn~jdk8/nashorn ; hg pull -u)
|
||||
(cd nashorn~jdk9/nashorn ; hg pull -u)
|
||||
|
||||
To learn about Mercurial in detail, please visit http://hgbook.red-bean.com.
|
||||
|
||||
- How to build?
|
||||
|
||||
To build Nashorn, you need to install JDK 8. You may use the Nashorn
|
||||
To build Nashorn, you need to install JDK 9. You may use the Nashorn
|
||||
forest build (recommended) or down load from java.net. You will need to
|
||||
set JAVA_HOME environmental variable to point to your JDK installation
|
||||
directory.
|
||||
|
||||
cd nashorn~jdk8/nashorn/make
|
||||
cd nashorn~jdk9/nashorn/make
|
||||
ant clean; ant
|
||||
|
||||
- How to run?
|
||||
|
||||
Use the jjs script (see RELESE_README):
|
||||
|
||||
cd nashorn~jdk8/nashorn
|
||||
cd nashorn~jdk9/nashorn
|
||||
sh bin/jjs <your .js file>
|
||||
|
||||
Nashorn supports javax.script API. It is possible to drop nashorn.jar in
|
||||
@ -64,7 +64,7 @@ Look for samples under the directory test/src/jdk/nashorn/api/scripting/.
|
||||
Comprehensive development documentation is found in the Nashorn JavaDoc. You can
|
||||
build it using:
|
||||
|
||||
cd nashorn~jdk8/nashorn/make
|
||||
cd nashorn~jdk9/nashorn/make
|
||||
ant javadoc
|
||||
|
||||
after which you can view the generated documentation at dist/javadoc/index.html.
|
||||
@ -90,7 +90,7 @@ Alternatively, you can check it out elsewhere and make
|
||||
test/script/external/test262 a symbolic link to that directory. After
|
||||
you've done this, you can run the ECMA-262 tests using:
|
||||
|
||||
cd nashorn~jdk8/nashorn/make
|
||||
cd nashorn~jdk9/nashorn/make
|
||||
ant test262
|
||||
|
||||
Ant target to get/update external test suites:
|
||||
@ -101,7 +101,7 @@ Ant target to get/update external test suites:
|
||||
These tests take time, so we have a parallelized runner for them that
|
||||
takes advantage of all processor cores on the computer:
|
||||
|
||||
cd nashorn~jdk8/nashorn/make
|
||||
cd nashorn~jdk9/nashorn/make
|
||||
ant test262parallel
|
||||
|
||||
- How to write your own test?
|
||||
|
@ -1,20 +0,0 @@
|
||||
The Nashorn repo is in the process of being migrated to OpenJDK and as such is
|
||||
incomplete in several areas.
|
||||
|
||||
- The build system is not fully integrated. When complete, Nashorn will be
|
||||
installed in its proper location in the JRE.
|
||||
|
||||
- Once integrated, the correct version of the JDK will be wrapped around
|
||||
Nashorn. In the meantime, ensure you use JDK8 b68 or later.
|
||||
|
||||
- The jjs tool has not been implemented in binary form yet. Use "sh bin/jjs"
|
||||
(or bin/jjs.bat on windows) in the interm.
|
||||
|
||||
- The Dynalink component is not fully integrated into Nashorn as yet, but will
|
||||
be when details are finalized.
|
||||
|
||||
- And, finally Nashorn is still in development. To stay up to date, subscribe
|
||||
to nashorn-dev@openjdk.java.net at
|
||||
|
||||
http://mail.openjdk.java.net/mailman/listinfo/nashorn-dev.
|
||||
|
@ -267,7 +267,7 @@
|
||||
|
||||
<!-- generate javadoc for Nashorn classes -->
|
||||
<target name="javadoc" depends="jar">
|
||||
<javadoc destdir="${dist.javadoc.dir}" use="yes" overview="${nashorn.module.src.dir}/overview.html"
|
||||
<javadoc destdir="${dist.javadoc.dir}" use="yes"
|
||||
windowtitle="${nashorn.product.name} ${nashorn.version}"
|
||||
additionalparam="-quiet" failonerror="true" useexternalfile="true">
|
||||
<arg value="--module-source-path"/>
|
||||
@ -285,7 +285,7 @@
|
||||
<!-- generate javadoc only for nashorn extension api classes -->
|
||||
<target name="nashornapi" depends="jar">
|
||||
<mkdir dir="${dist.nashornapi.javadoc.dir}"/>
|
||||
<javadoc destdir="${dist.nashornapi.javadoc.dir}" use="yes" overview="${nashorn.module.src.dir}/overview.html"
|
||||
<javadoc destdir="${dist.nashornapi.javadoc.dir}" use="yes"
|
||||
extdirs="${nashorn.ext.path}" windowtitle="${nashorn.product.name} ${nashorn.version}"
|
||||
additionalparam="-quiet" failonerror="true" useexternalfile="true">
|
||||
<arg value="--module-source-path"/>
|
||||
|
@ -82,197 +82,6 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Dynalink is a library for dynamic linking of high-level operations on objects.
|
||||
* These operations include "read a property",
|
||||
* "write a property", "invoke a function" and so on. Dynalink is primarily
|
||||
* useful for implementing programming languages where at least some expressions
|
||||
* have dynamic types (that is, types that can not be decided statically), and
|
||||
* the operations on dynamic types are expressed as
|
||||
* {@link java.lang.invoke.CallSite call sites}. These call sites will be
|
||||
* linked to appropriate target {@link java.lang.invoke.MethodHandle method handles}
|
||||
* at run time based on actual types of the values the expressions evaluated to.
|
||||
* These can change between invocations, necessitating relinking the call site
|
||||
* multiple times to accommodate new types; Dynalink handles all that and more.
|
||||
* <p>
|
||||
* Dynalink supports implementation of programming languages with object models
|
||||
* that differ (even radically) from the JVM's class-based model and have their
|
||||
* custom type conversions.
|
||||
* <p>
|
||||
* Dynalink is closely related to, and relies on, the {@link java.lang.invoke}
|
||||
* package.
|
||||
* <p>
|
||||
*
|
||||
* While {@link java.lang.invoke} provides a low level API for dynamic linking
|
||||
* of {@code invokedynamic} call sites, it does not provide a way to express
|
||||
* higher level operations on objects, nor methods that implement them. These
|
||||
* operations are the usual ones in object-oriented environments: property
|
||||
* access, access of elements of collections, invocation of methods and
|
||||
* constructors (potentially with multiple dispatch, e.g. link- and run-time
|
||||
* equivalents of Java overloaded method resolution). These are all functions
|
||||
* that are normally desired in a language on the JVM. If a language is
|
||||
* statically typed and its type system matches that of the JVM, it can
|
||||
* accomplish this with use of the usual invocation, field access, etc.
|
||||
* instructions (e.g. {@code invokevirtual}, {@code getfield}). However, if the
|
||||
* language is dynamic (hence, types of some expressions are not known until
|
||||
* evaluated at run time), or its object model or type system don't match
|
||||
* closely that of the JVM, then it should use {@code invokedynamic} call sites
|
||||
* instead and let Dynalink manage them.
|
||||
* <h2>Example</h2>
|
||||
* Dynalink is probably best explained by an example showing its use. Let's
|
||||
* suppose you have a program in a language where you don't have to declare the
|
||||
* type of an object and you want to access a property on it:
|
||||
* <pre>
|
||||
* var color = obj.color;
|
||||
* </pre>
|
||||
* If you generated a Java class to represent the above one-line program, its
|
||||
* bytecode would look something like this:
|
||||
* <pre>
|
||||
* aload 2 // load "obj" on stack
|
||||
* invokedynamic "GET:PROPERTY:color"(Object)Object // invoke property getter on object of unknown type
|
||||
* astore 3 // store the return value into local variable "color"
|
||||
* </pre>
|
||||
* In order to link the {@code invokedynamic} instruction, we need a bootstrap
|
||||
* method. A minimalist bootstrap method with Dynalink could look like this:
|
||||
* <pre>
|
||||
* import java.lang.invoke.*;
|
||||
* import jdk.dynalink.*;
|
||||
* import jdk.dynalink.support.*;
|
||||
*
|
||||
* class MyLanguageRuntime {
|
||||
* private static final DynamicLinker dynamicLinker = new DynamicLinkerFactory().createLinker();
|
||||
*
|
||||
* public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
|
||||
* return dynamicLinker.link(
|
||||
* new SimpleRelinkableCallSite(
|
||||
* new CallSiteDescriptor(lookup, parseOperation(name), type)));
|
||||
* }
|
||||
*
|
||||
* private static Operation parseOperation(String name) {
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* There are several objects of significance in the above code snippet:
|
||||
* <ul>
|
||||
* <li>{@link jdk.dynalink.DynamicLinker} is the main object in Dynalink, it
|
||||
* coordinates the linking of call sites to method handles that implement the
|
||||
* operations named in them. It is configured and created using a
|
||||
* {@link jdk.dynalink.DynamicLinkerFactory}.</li>
|
||||
* <li>When the bootstrap method is invoked, it needs to create a
|
||||
* {@link java.lang.invoke.CallSite} object. In Dynalink, these call sites need
|
||||
* to additionally implement the {@link jdk.dynalink.RelinkableCallSite}
|
||||
* interface. "Relinkable" here alludes to the fact that if the call site
|
||||
* encounters objects of different types at run time, its target will be changed
|
||||
* to a method handle that can perform the operation on the newly encountered
|
||||
* type. {@link jdk.dynalink.support.SimpleRelinkableCallSite} and
|
||||
* {@link jdk.dynalink.support.ChainedCallSite} (not used in the above example)
|
||||
* are two implementations already provided by the library.</li>
|
||||
* <li>Dynalink uses {@link jdk.dynalink.CallSiteDescriptor} objects to
|
||||
* preserve the parameters to the bootstrap method: the lookup and the method type,
|
||||
* as it will need them whenever it needs to relink a call site.</li>
|
||||
* <li>Dynalink uses {@link jdk.dynalink.Operation} objects to express
|
||||
* dynamic operations. It does not prescribe how would you encode the operations
|
||||
* in your call site, though. That is why in the above example the
|
||||
* {@code parseOperation} function is left empty, and you would be expected to
|
||||
* provide the code to parse the string {@code "GET:PROPERTY:color"}
|
||||
* in the call site's name into a named property getter operation object as
|
||||
* {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")}.
|
||||
* </ul>
|
||||
* <p>What can you already do with the above setup? {@code DynamicLinkerFactory}
|
||||
* by default creates a {@code DynamicLinker} that can link Java objects with the
|
||||
* usual Java semantics. If you have these three simple classes:
|
||||
* <pre>
|
||||
* public class A {
|
||||
* public String color;
|
||||
* public A(String color) { this.color = color; }
|
||||
* }
|
||||
*
|
||||
* public class B {
|
||||
* private String color;
|
||||
* public B(String color) { this.color = color; }
|
||||
* public String getColor() { return color; }
|
||||
* }
|
||||
*
|
||||
* public class C {
|
||||
* private int color;
|
||||
* public C(int color) { this.color = color; }
|
||||
* public int getColor() { return color; }
|
||||
* }
|
||||
* </pre>
|
||||
* and you somehow create their instances and pass them to your call site in your
|
||||
* programming language:
|
||||
* <pre>
|
||||
* for each(var obj in [new A("red"), new B("green"), new C(0x0000ff)]) {
|
||||
* print(obj.color);
|
||||
* }
|
||||
* </pre>
|
||||
* then on first invocation, Dynalink will link the {@code .color} getter
|
||||
* operation to a field getter for {@code A.color}, on second invocation it will
|
||||
* relink it to {@code B.getColor()} returning a {@code String}, and finally on
|
||||
* third invocation it will relink it to {@code C.getColor()} returning an {@code int}.
|
||||
* The {@code SimpleRelinkableCallSite} we used above only remembers the linkage
|
||||
* for the last encountered type (it implements what is known as a <i>monomorphic
|
||||
* inline cache</i>). Another already provided implementation,
|
||||
* {@link jdk.dynalink.support.ChainedCallSite} will remember linkages for
|
||||
* several different types (it is a <i>polymorphic inline cache</i>) and is
|
||||
* probably a better choice in serious applications.
|
||||
* <h2>Dynalink and bytecode creation</h2>
|
||||
* {@code CallSite} objects are usually created as part of bootstrapping
|
||||
* {@code invokedynamic} instructions in bytecode. Hence, Dynalink is typically
|
||||
* used as part of language runtimes that compile programs into Java
|
||||
* {@code .class} bytecode format. Dynalink does not address the aspects of
|
||||
* either creating bytecode classes or loading them into the JVM. That said,
|
||||
* Dynalink can also be used without bytecode compilation (e.g. in language
|
||||
* interpreters) by creating {@code CallSite} objects explicitly and associating
|
||||
* them with representations of dynamic operations in the interpreted program
|
||||
* (e.g. a typical representation would be some node objects in a syntax tree).
|
||||
* <h2>Available operations</h2>
|
||||
* Dynalink defines several standard operations in its
|
||||
* {@link jdk.dynalink.StandardOperation} class. The linker for Java
|
||||
* objects can link all of these operations, and you are encouraged to at
|
||||
* minimum support and use these operations in your language too. The
|
||||
* standard operations {@code GET} and {@code SET} need to be combined with
|
||||
* at least one {@link jdk.dynalink.Namespace} to be useful, e.g. to express a
|
||||
* property getter, you'd use {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY)}.
|
||||
* Dynalink defines three standard namespaces in the {@link jdk.dynalink.StandardNamespace} class.
|
||||
* To associate a fixed name with an operation, you can use
|
||||
* {@link jdk.dynalink.NamedOperation} as in the previous example:
|
||||
* {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")}
|
||||
* expresses a getter for the property named "color".
|
||||
* <h2>Operations on multiple namespaces</h2>
|
||||
* Some languages might not have separate namespaces on objects for
|
||||
* properties, elements, and methods, and a source language construct might
|
||||
* address several of them at once. Dynalink supports specifying multiple
|
||||
* {@link jdk.dynalink.Namespace} objects with {@link jdk.dynalink.NamespaceOperation}.
|
||||
* <h2>Language-specific linkers</h2>
|
||||
* Languages that define their own object model different than the JVM
|
||||
* class-based model and/or use their own type conversions will need to create
|
||||
* their own language-specific linkers. See the {@link jdk.dynalink.linker}
|
||||
* package and specifically the {@link jdk.dynalink.linker.GuardingDynamicLinker}
|
||||
* interface to get started.
|
||||
* <h2>Dynalink and Java objects</h2>
|
||||
* The {@code DynamicLinker} objects created by {@code DynamicLinkerFactory} by
|
||||
* default contain an internal instance of
|
||||
* {@code BeansLinker}, which is a language-specific linker
|
||||
* that implements the usual Java semantics for all of the above operations and
|
||||
* can link any Java object that no other language-specific linker has managed
|
||||
* to link. This way, all language runtimes have built-in interoperability with
|
||||
* ordinary Java objects. See {@link jdk.dynalink.beans.BeansLinker} for details
|
||||
* on how it links the various operations.
|
||||
* <h2>Cross-language interoperability</h2>
|
||||
* A {@code DynamicLinkerFactory} can be configured with a
|
||||
* {@link jdk.dynalink.DynamicLinkerFactory#setClassLoader(ClassLoader) class
|
||||
* loader}. It will try to instantiate all
|
||||
* {@link jdk.dynalink.linker.GuardingDynamicLinkerExporter} classes visible to
|
||||
* that class loader and compose the linkers they provide into the
|
||||
* {@code DynamicLinker} it creates. This allows for interoperability between
|
||||
* languages: if you have two language runtimes A and B deployed in your JVM and
|
||||
* they export their linkers through the above mechanism, language runtime A
|
||||
* will have a language-specific linker instance from B and vice versa inside
|
||||
* their {@code DynamicLinker} objects. This means that if an object from
|
||||
* language runtime B gets passed to code from language runtime A, the linker
|
||||
* from B will get a chance to link the call site in A when it encounters the
|
||||
* object from B.
|
||||
* Contains interfaces and classes that are used to link an {@code invokedynamic} call site.
|
||||
*/
|
||||
package jdk.dynalink;
|
||||
|
@ -24,7 +24,198 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Dynalink
|
||||
* <p>
|
||||
* Dynalink is a library for dynamic linking of high-level operations on objects.
|
||||
* These operations include "read a property",
|
||||
* "write a property", "invoke a function" and so on. Dynalink is primarily
|
||||
* useful for implementing programming languages where at least some expressions
|
||||
* have dynamic types (that is, types that can not be decided statically), and
|
||||
* the operations on dynamic types are expressed as
|
||||
* {@link java.lang.invoke.CallSite call sites}. These call sites will be
|
||||
* linked to appropriate target {@link java.lang.invoke.MethodHandle method handles}
|
||||
* at run time based on actual types of the values the expressions evaluated to.
|
||||
* These can change between invocations, necessitating relinking the call site
|
||||
* multiple times to accommodate new types; Dynalink handles all that and more.
|
||||
* <p>
|
||||
* Dynalink supports implementation of programming languages with object models
|
||||
* that differ (even radically) from the JVM's class-based model and have their
|
||||
* custom type conversions.
|
||||
* <p>
|
||||
* Dynalink is closely related to, and relies on, the {@link java.lang.invoke}
|
||||
* package.
|
||||
* <p>
|
||||
*
|
||||
* While {@link java.lang.invoke} provides a low level API for dynamic linking
|
||||
* of {@code invokedynamic} call sites, it does not provide a way to express
|
||||
* higher level operations on objects, nor methods that implement them. These
|
||||
* operations are the usual ones in object-oriented environments: property
|
||||
* access, access of elements of collections, invocation of methods and
|
||||
* constructors (potentially with multiple dispatch, e.g. link- and run-time
|
||||
* equivalents of Java overloaded method resolution). These are all functions
|
||||
* that are normally desired in a language on the JVM. If a language is
|
||||
* statically typed and its type system matches that of the JVM, it can
|
||||
* accomplish this with use of the usual invocation, field access, etc.
|
||||
* instructions (e.g. {@code invokevirtual}, {@code getfield}). However, if the
|
||||
* language is dynamic (hence, types of some expressions are not known until
|
||||
* evaluated at run time), or its object model or type system don't match
|
||||
* closely that of the JVM, then it should use {@code invokedynamic} call sites
|
||||
* instead and let Dynalink manage them.
|
||||
* <h2>Example</h2>
|
||||
* Dynalink is probably best explained by an example showing its use. Let's
|
||||
* suppose you have a program in a language where you don't have to declare the
|
||||
* type of an object and you want to access a property on it:
|
||||
* <pre>
|
||||
* var color = obj.color;
|
||||
* </pre>
|
||||
* If you generated a Java class to represent the above one-line program, its
|
||||
* bytecode would look something like this:
|
||||
* <pre>
|
||||
* aload 2 // load "obj" on stack
|
||||
* invokedynamic "GET:PROPERTY:color"(Object)Object // invoke property getter on object of unknown type
|
||||
* astore 3 // store the return value into local variable "color"
|
||||
* </pre>
|
||||
* In order to link the {@code invokedynamic} instruction, we need a bootstrap
|
||||
* method. A minimalist bootstrap method with Dynalink could look like this:
|
||||
* <pre>
|
||||
* import java.lang.invoke.*;
|
||||
* import jdk.dynalink.*;
|
||||
* import jdk.dynalink.support.*;
|
||||
*
|
||||
* class MyLanguageRuntime {
|
||||
* private static final DynamicLinker dynamicLinker = new DynamicLinkerFactory().createLinker();
|
||||
*
|
||||
* public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
|
||||
* return dynamicLinker.link(
|
||||
* new SimpleRelinkableCallSite(
|
||||
* new CallSiteDescriptor(lookup, parseOperation(name), type)));
|
||||
* }
|
||||
*
|
||||
* private static Operation parseOperation(String name) {
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* There are several objects of significance in the above code snippet:
|
||||
* <ul>
|
||||
* <li>{@link jdk.dynalink.DynamicLinker} is the main object in Dynalink, it
|
||||
* coordinates the linking of call sites to method handles that implement the
|
||||
* operations named in them. It is configured and created using a
|
||||
* {@link jdk.dynalink.DynamicLinkerFactory}.</li>
|
||||
* <li>When the bootstrap method is invoked, it needs to create a
|
||||
* {@link java.lang.invoke.CallSite} object. In Dynalink, these call sites need
|
||||
* to additionally implement the {@link jdk.dynalink.RelinkableCallSite}
|
||||
* interface. "Relinkable" here alludes to the fact that if the call site
|
||||
* encounters objects of different types at run time, its target will be changed
|
||||
* to a method handle that can perform the operation on the newly encountered
|
||||
* type. {@link jdk.dynalink.support.SimpleRelinkableCallSite} and
|
||||
* {@link jdk.dynalink.support.ChainedCallSite} (not used in the above example)
|
||||
* are two implementations already provided by the library.</li>
|
||||
* <li>Dynalink uses {@link jdk.dynalink.CallSiteDescriptor} objects to
|
||||
* preserve the parameters to the bootstrap method: the lookup and the method type,
|
||||
* as it will need them whenever it needs to relink a call site.</li>
|
||||
* <li>Dynalink uses {@link jdk.dynalink.Operation} objects to express
|
||||
* dynamic operations. It does not prescribe how would you encode the operations
|
||||
* in your call site, though. That is why in the above example the
|
||||
* {@code parseOperation} function is left empty, and you would be expected to
|
||||
* provide the code to parse the string {@code "GET:PROPERTY:color"}
|
||||
* in the call site's name into a named property getter operation object as
|
||||
* {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")}.
|
||||
* </ul>
|
||||
* <p>What can you already do with the above setup? {@code DynamicLinkerFactory}
|
||||
* by default creates a {@code DynamicLinker} that can link Java objects with the
|
||||
* usual Java semantics. If you have these three simple classes:
|
||||
* <pre>
|
||||
* public class A {
|
||||
* public String color;
|
||||
* public A(String color) { this.color = color; }
|
||||
* }
|
||||
*
|
||||
* public class B {
|
||||
* private String color;
|
||||
* public B(String color) { this.color = color; }
|
||||
* public String getColor() { return color; }
|
||||
* }
|
||||
*
|
||||
* public class C {
|
||||
* private int color;
|
||||
* public C(int color) { this.color = color; }
|
||||
* public int getColor() { return color; }
|
||||
* }
|
||||
* </pre>
|
||||
* and you somehow create their instances and pass them to your call site in your
|
||||
* programming language:
|
||||
* <pre>
|
||||
* for each(var obj in [new A("red"), new B("green"), new C(0x0000ff)]) {
|
||||
* print(obj.color);
|
||||
* }
|
||||
* </pre>
|
||||
* then on first invocation, Dynalink will link the {@code .color} getter
|
||||
* operation to a field getter for {@code A.color}, on second invocation it will
|
||||
* relink it to {@code B.getColor()} returning a {@code String}, and finally on
|
||||
* third invocation it will relink it to {@code C.getColor()} returning an {@code int}.
|
||||
* The {@code SimpleRelinkableCallSite} we used above only remembers the linkage
|
||||
* for the last encountered type (it implements what is known as a <i>monomorphic
|
||||
* inline cache</i>). Another already provided implementation,
|
||||
* {@link jdk.dynalink.support.ChainedCallSite} will remember linkages for
|
||||
* several different types (it is a <i>polymorphic inline cache</i>) and is
|
||||
* probably a better choice in serious applications.
|
||||
* <h2>Dynalink and bytecode creation</h2>
|
||||
* {@code CallSite} objects are usually created as part of bootstrapping
|
||||
* {@code invokedynamic} instructions in bytecode. Hence, Dynalink is typically
|
||||
* used as part of language runtimes that compile programs into Java
|
||||
* {@code .class} bytecode format. Dynalink does not address the aspects of
|
||||
* either creating bytecode classes or loading them into the JVM. That said,
|
||||
* Dynalink can also be used without bytecode compilation (e.g. in language
|
||||
* interpreters) by creating {@code CallSite} objects explicitly and associating
|
||||
* them with representations of dynamic operations in the interpreted program
|
||||
* (e.g. a typical representation would be some node objects in a syntax tree).
|
||||
* <h2>Available operations</h2>
|
||||
* Dynalink defines several standard operations in its
|
||||
* {@link jdk.dynalink.StandardOperation} class. The linker for Java
|
||||
* objects can link all of these operations, and you are encouraged to at
|
||||
* minimum support and use these operations in your language too. The
|
||||
* standard operations {@code GET} and {@code SET} need to be combined with
|
||||
* at least one {@link jdk.dynalink.Namespace} to be useful, e.g. to express a
|
||||
* property getter, you'd use {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY)}.
|
||||
* Dynalink defines three standard namespaces in the {@link jdk.dynalink.StandardNamespace} class.
|
||||
* To associate a fixed name with an operation, you can use
|
||||
* {@link jdk.dynalink.NamedOperation} as in the previous example:
|
||||
* {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")}
|
||||
* expresses a getter for the property named "color".
|
||||
* <h2>Operations on multiple namespaces</h2>
|
||||
* Some languages might not have separate namespaces on objects for
|
||||
* properties, elements, and methods, and a source language construct might
|
||||
* address several of them at once. Dynalink supports specifying multiple
|
||||
* {@link jdk.dynalink.Namespace} objects with {@link jdk.dynalink.NamespaceOperation}.
|
||||
* <h2>Language-specific linkers</h2>
|
||||
* Languages that define their own object model different than the JVM
|
||||
* class-based model and/or use their own type conversions will need to create
|
||||
* their own language-specific linkers. See the {@link jdk.dynalink.linker}
|
||||
* package and specifically the {@link jdk.dynalink.linker.GuardingDynamicLinker}
|
||||
* interface to get started.
|
||||
* <h2>Dynalink and Java objects</h2>
|
||||
* The {@code DynamicLinker} objects created by {@code DynamicLinkerFactory} by
|
||||
* default contain an internal instance of
|
||||
* {@code BeansLinker}, which is a language-specific linker
|
||||
* that implements the usual Java semantics for all of the above operations and
|
||||
* can link any Java object that no other language-specific linker has managed
|
||||
* to link. This way, all language runtimes have built-in interoperability with
|
||||
* ordinary Java objects. See {@link jdk.dynalink.beans.BeansLinker} for details
|
||||
* on how it links the various operations.
|
||||
* <h2>Cross-language interoperability</h2>
|
||||
* A {@code DynamicLinkerFactory} can be configured with a
|
||||
* {@link jdk.dynalink.DynamicLinkerFactory#setClassLoader(ClassLoader) class
|
||||
* loader}. It will try to instantiate all
|
||||
* {@link jdk.dynalink.linker.GuardingDynamicLinkerExporter} classes visible to
|
||||
* that class loader and compose the linkers they provide into the
|
||||
* {@code DynamicLinker} it creates. This allows for interoperability between
|
||||
* languages: if you have two language runtimes A and B deployed in your JVM and
|
||||
* they export their linkers through the above mechanism, language runtime A
|
||||
* will have a language-specific linker instance from B and vice versa inside
|
||||
* their {@code DynamicLinker} objects. This means that if an object from
|
||||
* language runtime B gets passed to code from language runtime A, the linker
|
||||
* from B will get a chance to link the call site in A when it encounters the
|
||||
* object from B.
|
||||
*/
|
||||
module jdk.dynalink {
|
||||
requires java.logging;
|
||||
|
@ -24,7 +24,71 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Nashorn
|
||||
<p>
|
||||
Nashorn is a runtime environment for programs written in ECMAScript 5.1.
|
||||
</p>
|
||||
<h1>Usage</h1>
|
||||
The recommended way to use Nashorn is through the <a href="http://jcp.org/en/jsr/detail?id=223" target="_top">JSR-223
|
||||
"Scripting for the Java Platform"</a> APIs found in the {@link javax.script} package. Usually, you'll obtain a
|
||||
{@link javax.script.ScriptEngine} instance for Nashorn using:
|
||||
<pre>
|
||||
import javax.script.*;
|
||||
...
|
||||
ScriptEngine nashornEngine = new ScriptEngineManager().getEngineByName("nashorn");
|
||||
</pre>
|
||||
and then use it just as you would any other JSR-223 script engine. See
|
||||
<a href="jdk/nashorn/api/scripting/package-summary.html">{@code jdk.nashorn.api.scripting}</a> package
|
||||
for details.
|
||||
<h1>Compatibility</h1>
|
||||
Nashorn is 100% compliant with the <a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm"
|
||||
target="_top">ECMA-262 Standard, Edition 5.1</a>. It requires a Java Virtual Machine that implements the
|
||||
<a href="http://jcp.org/en/jsr/detail?id=292" target="_top">JSR-292 "Supporting Dynamically Typed Languages on the Java
|
||||
Platform"</a> specification (often referred to as "invokedynamic"), as well as the already mentioned JSR-223.
|
||||
<h1>Interoperability with the Java platform</h1>
|
||||
In addition to being a 100% ECMAScript 5.1 runtime, Nashorn provides features for interoperability of the ECMAScript
|
||||
programs with the Java platform. In general, any Java object put into the script engine's context will be visible from
|
||||
the script. In terms of the standard, such Java objects are not considered "native objects", but rather "host objects",
|
||||
as defined in section 4.3.8. This distinction allows certain semantical differences in handling them compared to native
|
||||
objects. For most purposes, Java objects behave just as native objects do: you can invoke their methods, get and set
|
||||
their properties. In most cases, though, you can't add arbitrary properties to them, nor can you remove existing
|
||||
properties.
|
||||
<h2>Java collection handling</h2>
|
||||
Native Java arrays and {@link java.util.List}s support indexed access to their elements through the property accessors,
|
||||
and {@link java.util.Map}s support both property and element access through both dot and square-bracket property
|
||||
accessors, with the difference being that dot operator gives precedence to object properties (its fields and properties
|
||||
defined as {@code getXxx} and {@code setXxx} methods) while the square bracket operator gives precedence to map
|
||||
elements. Native Java arrays expose the {@code length} property.
|
||||
<h2>ECMAScript primitive types</h2>
|
||||
ECMAScript primitive types for number, string, and boolean are represented with {@link java.lang.Number},
|
||||
{@link java.lang.CharSequence}, and {@link java.lang.Boolean} objects. While the most often used number type is
|
||||
{@link java.lang.Double} and the most often used string type is {@link java.lang.String}, don't rely on it as various
|
||||
internal optimizations cause other subclasses of {@code Number} and internal implementations of {@code CharSequence} to
|
||||
be used.
|
||||
<h2>Type conversions</h2>
|
||||
When a method on a Java object is invoked, the arguments are converted to the formal parameter types of the Java method
|
||||
using all allowed ECMAScript conversions. This can be surprising, as in general, conversions from string to number will
|
||||
succeed according to Standard's section 9.3 "ToNumber" and so on; string to boolean, number to boolean, Object to
|
||||
number, Object to string all work. Note that if the Java method's declared parameter type is {@code java.lang.Object},
|
||||
Nashorn objects are passed without any conversion whatsoever; specifically if the JavaScript value being passed is of
|
||||
primitive string type, you can only rely on it being a {@code java.lang.CharSequence}, and if the value is a number, you
|
||||
can only rely on it being a {@code java.lang.Number}. If the Java method declared parameter type is more specific (e.g.
|
||||
{@code java.lang.String} or {@code java.lang.Double}), then Nashorn will of course ensure the required type is passed.
|
||||
<h2>SAM types</h2>
|
||||
As a special extension when invoking Java methods, ECMAScript function objects can be passed in place of an argument
|
||||
whose Java type is so-called "single abstract method" or "SAM" type. While this name usually covers single-method
|
||||
interfaces, Nashorn is a bit more versatile, and it recognizes a type as a SAM type if all its abstract methods are
|
||||
overloads of the same name, and it is either an interface, or it is an abstract class with
|
||||
a no-arg constructor. The type itself must be public, while the constructor and the methods can be either public or
|
||||
protected. If there are multiple abstract overloads of the same name, the single function will serve as the shared
|
||||
implementation for all of them, <em>and additionally it will also override any non-abstract methods of the same name</em>.
|
||||
This is done to be consistent with the fact that ECMAScript does not have the concept of overloaded methods.
|
||||
<h2>The {@code Java} object</h2>
|
||||
Nashorn exposes a non-standard global object named {@code Java} that is the primary API entry point into Java
|
||||
platform-specific functionality. You can use it to create instances of Java classes, convert from Java arrays to native
|
||||
arrays and back, and so on.
|
||||
<h2>Other non-standard built-in objects</h2>
|
||||
In addition to {@code Java}, Nashorn also exposes some other non-standard built-in objects:
|
||||
{@code JSAdapter}, {@code JavaImporter}, {@code Packages}
|
||||
*/
|
||||
module jdk.scripting.nashorn {
|
||||
requires java.logging;
|
||||
@ -47,4 +111,3 @@ module jdk.scripting.nashorn {
|
||||
provides jdk.dynalink.linker.GuardingDynamicLinkerExporter
|
||||
with jdk.nashorn.api.linker.NashornLinkerExporter;
|
||||
}
|
||||
|
||||
|
@ -1,113 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2010, 2013, 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.
|
||||
-->
|
||||
<body>
|
||||
<p>
|
||||
Nashorn is a runtime environment for programs written in ECMAScript 5.1.
|
||||
</p>
|
||||
<h1>Usage</h1>
|
||||
<p>
|
||||
The recommended way to use Nashorn is through the <a href="http://jcp.org/en/jsr/detail?id=223" target="_top">JSR-223
|
||||
"Scripting for the Java Platform"</a> APIs found in the {@link javax.script} package. Usually, you'll obtain a
|
||||
{@link javax.script.ScriptEngine} instance for Nashorn using:
|
||||
<pre>
|
||||
import javax.script.*;
|
||||
...
|
||||
ScriptEngine nashornEngine = new ScriptEngineManager().getEngineByName("nashorn");
|
||||
</pre>
|
||||
and then use it just as you would any other JSR-223 script engine. See
|
||||
<a href="jdk/nashorn/api/scripting/package-summary.html">{@code jdk.nashorn.api.scripting}</a> package
|
||||
for details.
|
||||
<p>
|
||||
<h1>Compatibility</h1>
|
||||
Nashorn is 100% compliant with the <a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm"
|
||||
target="_top">ECMA-262 Standard, Edition 5.1</a>. It requires a Java Virtual Machine that implements the
|
||||
<a href="http://jcp.org/en/jsr/detail?id=292" target="_top">JSR-292 "Supporting Dynamically Typed Languages on the Java
|
||||
Platform"</a> specification (often referred to as "invokedynamic"), as well as the already mentioned JSR-223.
|
||||
<h1>Interoperability with the Java platform</h1>
|
||||
<p>
|
||||
In addition to being a 100% ECMAScript 5.1 runtime, Nashorn provides features for interoperability of the ECMAScript
|
||||
programs with the Java platform. In general, any Java object put into the script engine's context will be visible from
|
||||
the script. In terms of the standard, such Java objects are not considered "native objects", but rather "host objects",
|
||||
as defined in section 4.3.8. This distinction allows certain semantical differences in handling them compared to native
|
||||
objects. For most purposes, Java objects behave just as native objects do: you can invoke their methods, get and set
|
||||
their properties. In most cases, though, you can't add arbitrary properties to them, nor can you remove existing
|
||||
properties.
|
||||
<p>
|
||||
<h2>Java collection handling</h2>
|
||||
<p>
|
||||
Native Java arrays and {@link java.util.List}s support indexed access to their elements through the property accessors,
|
||||
and {@link java.util.Map}s support both property and element access through both dot and square-bracket property
|
||||
accessors, with the difference being that dot operator gives precedence to object properties (its fields and properties
|
||||
defined as {@code getXxx} and {@code setXxx} methods) while the square bracket operator gives precedence to map
|
||||
elements. Native Java arrays expose the {@code length} property.
|
||||
<p>
|
||||
<h2>ECMAScript primitive types</h2>
|
||||
<p>
|
||||
ECMAScript primitive types for number, string, and boolean are represented with {@link java.lang.Number},
|
||||
{@link java.lang.CharSequence}, and {@link java.lang.Boolean} objects. While the most often used number type is
|
||||
{@link java.lang.Double} and the most often used string type is {@link java.lang.String}, don't rely on it as various
|
||||
internal optimizations cause other subclasses of {@code Number} and internal implementations of {@code CharSequence} to
|
||||
be used.
|
||||
<p>
|
||||
<h2>Type conversions</h2>
|
||||
<p>
|
||||
When a method on a Java object is invoked, the arguments are converted to the formal parameter types of the Java method
|
||||
using all allowed ECMAScript conversions. This can be surprising, as in general, conversions from string to number will
|
||||
succeed according to Standard's section 9.3 "ToNumber" and so on; string to boolean, number to boolean, Object to
|
||||
number, Object to string all work. Note that if the Java method's declared parameter type is {@code java.lang.Object},
|
||||
Nashorn objects are passed without any conversion whatsoever; specifically if the JavaScript value being passed is of
|
||||
primitive string type, you can only rely on it being a {@code java.lang.CharSequence}, and if the value is a number, you
|
||||
can only rely on it being a {@code java.lang.Number}. If the Java method declared parameter type is more specific (e.g.
|
||||
{@code java.lang.String} or {@code java.lang.Double}), then Nashorn will of course ensure the required type is passed.
|
||||
<p>
|
||||
<h2>SAM types</h2>
|
||||
<p>
|
||||
As a special extension when invoking Java methods, ECMAScript function objects can be passed in place of an argument
|
||||
whose Java type is so-called "single abstract method" or "SAM" type. While this name usually covers single-method
|
||||
interfaces, Nashorn is a bit more versatile, and it recognizes a type as a SAM type if all its abstract methods are
|
||||
overloads of the same name, and it is either an interface, or it is an abstract class with
|
||||
a no-arg constructor. The type itself must be public, while the constructor and the methods can be either public or
|
||||
protected. If there are multiple abstract overloads of the same name, the single function will serve as the shared
|
||||
implementation for all of them, <em>and additionally it will also override any non-abstract methods of the same name</em>.
|
||||
This is done to be consistent with the fact that ECMAScript does not have the concept of overloaded methods.
|
||||
<p>
|
||||
<h2>The {@code Java} object</h2>
|
||||
Nashorn exposes a non-standard global object named {@code Java} that is the primary API entry point into Java
|
||||
platform-specific functionality. You can use it to create instances of Java classes, convert from Java arrays to native
|
||||
arrays and back, and so on. The methods on the objects are directly implemented by public static methods on the class
|
||||
<a href="jdk/nashorn/internal/objects/NativeJava.html">{@code NativeJava}</a>, see that class for details on what
|
||||
functionality is available.
|
||||
<h2>Representations of Java types</h2>
|
||||
The method <a href="jdk/nashorn/internal/objects/NativeJava.html#type(java.lang.Object,%20java.lang.Object)">
|
||||
{@code Java.type(typeName)}</a> takes a name of a type, and returns an object representing a Java type. You can
|
||||
use that object to both create new instances of Java classes, as well as to access static fields and methods on them.
|
||||
The type object is distinct from the {@code java.lang.Class} object, which represents the reflective run-time type
|
||||
identity and doesn't carry i.e. static members. Again, see the link for {@code NativeJava} above for details.
|
||||
<h2>Other non-standard built-in objects</h2>
|
||||
In addition to {@code Java}, Nashorn also exposes some other non-standard built-in objects:
|
||||
<a href="jdk/nashorn/internal/objects/NativeJSAdapter.html">{@code JSAdapter}</a>,
|
||||
<a href="jdk/nashorn/internal/objects/NativeJavaImporter.html">{@code JavaImporter}</a>,
|
||||
<a href="jdk/nashorn/internal/runtime/NativeJavaPackage.html">{@code Packages}.</a>
|
||||
</body>
|
Loading…
x
Reference in New Issue
Block a user