# HG changeset patch # User lana # Date 1381269452 25200 # Node ID a7dcd7811f02b1ef0b96524d72dd33743ab94ce8 # Parent 5f3e7611790a99e5de4e93b81f7e7eab19f22cbe# Parent bd0a8b142cb3d05328d7118b09f778b17da67be3 Merge diff -r 5f3e7611790a -r a7dcd7811f02 jdk/make/docs/Makefile --- a/jdk/make/docs/Makefile Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/make/docs/Makefile Tue Oct 08 14:57:32 2013 -0700 @@ -50,6 +50,7 @@ DEV_DOCS_URL-5 = http://java.sun.com/j2se/1.5.0/docs/index.html DEV_DOCS_URL-6 = http://download.oracle.com/javase/6/docs/index.html DEV_DOCS_URL-7 = http://download.oracle.com/javase/7/docs/index.html +DEV_DOCS_URL-8 = http://download.oracle.com/javase/8/docs/index.html DEV_DOCS_URL = $(DEV_DOCS_URL-$(JDK_MINOR_VERSION)) DOCS_BASE_URL = http://download.oracle.com/javase/7/docs diff -r 5f3e7611790a -r a7dcd7811f02 jdk/make/java/java/FILES_c.gmk --- a/jdk/make/java/java/FILES_c.gmk Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/make/java/java/FILES_c.gmk Tue Oct 08 14:57:32 2013 -0700 @@ -33,6 +33,7 @@ Console_md.c \ Double.c \ Executable.c \ + Field.c \ FileDescriptor_md.c \ FileInputStream.c \ FileInputStream_md.c \ diff -r 5f3e7611790a -r a7dcd7811f02 jdk/make/java/java/mapfile-vers --- a/jdk/make/java/java/mapfile-vers Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/make/java/java/mapfile-vers Tue Oct 08 14:57:32 2013 -0700 @@ -190,6 +190,8 @@ Java_java_lang_reflect_Array_setLong; Java_java_lang_reflect_Array_setShort; Java_java_lang_reflect_Executable_getParameters0; + Java_java_lang_reflect_Executable_getTypeAnnotationBytes0; + Java_java_lang_reflect_Field_getTypeAnnotationBytes0; Java_java_lang_Runtime_freeMemory; Java_java_lang_Runtime_maxMemory; Java_java_lang_Runtime_gc; diff -r 5f3e7611790a -r a7dcd7811f02 jdk/make/netbeans/common/java-data-native.ent --- a/jdk/make/netbeans/common/java-data-native.ent Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/make/netbeans/common/java-data-native.ent Tue Oct 08 14:57:32 2013 -0700 @@ -31,14 +31,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + ${root}/src/share/classes ${root}/src/macosx/classes ${root}/src/solaris/classes ${root}/src/windows/classes ${bootstrap.jdk}/jre/lib/rt.jar - ${root}/build/${platform}-${arch}/classes + ${root}/../build/${platform}-${arch}/jdk/classes ${root}/build/${platform}-${arch}/docs/api 1.8 diff -r 5f3e7611790a -r a7dcd7811f02 jdk/make/netbeans/common/java-data-no-native.ent --- a/jdk/make/netbeans/common/java-data-no-native.ent Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/make/netbeans/common/java-data-no-native.ent Tue Oct 08 14:57:32 2013 -0700 @@ -31,11 +31,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> - + ${root}/src/share/classes ${bootstrap.jdk}/jre/lib/rt.jar - ${root}/build/${platform}-${arch}/classes + ${root}/../build/${platform}-${arch}/jdk/classes ${root}/build/${platform}-${arch}/docs/api 1.8 diff -r 5f3e7611790a -r a7dcd7811f02 jdk/make/tools/src/build/tools/buildmetaindex/BuildMetaIndex.java --- a/jdk/make/tools/src/build/tools/buildmetaindex/BuildMetaIndex.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/make/tools/src/build/tools/buildmetaindex/BuildMetaIndex.java Tue Oct 08 14:57:32 2013 -0700 @@ -174,6 +174,44 @@ private HashMap> knownPrefixMap = new HashMap<>(); /* + * A class for mapping package prefixes to the number of + * levels of package elements to include. + */ + static class ExtraLevel { + public ExtraLevel(String prefix, int levels) { + this.prefix = prefix; + this.levels = levels; + } + String prefix; + int levels; + } + + /* + * A list of the special-cased package names. + */ + private static ArrayList extraLevels = new ArrayList<>(); + + static { + // The order of these statements is significant, + // since we stop looking after the first match. + + // Need more precise information to disambiguate + // (illegal) references from applications to + // obsolete backported collections classes in + // com/sun/java/util + extraLevels.add(new ExtraLevel("com/sun/java/util/", Integer.MAX_VALUE)); + extraLevels.add(new ExtraLevel("com/sun/java/", 4)); + // Need more information than just first two package + // name elements to determine that classes in + // deploy.jar are not in rt.jar + extraLevels.add(new ExtraLevel("com/sun/", 3)); + // Need to make sure things in jfr.jar aren't + // confused with other com/oracle/** packages + extraLevels.add(new ExtraLevel("com/oracle/jrockit", 3)); + } + + + /* * We add maximum 5 second level entries to "sun", "java" and * "javax" entries. Tune this parameter to get a balance on the * cold start and footprint. @@ -237,39 +275,25 @@ String[] pkgElements = name.split("/"); // Last one is the class name; definitely ignoring that if (pkgElements.length > 2) { - String meta = null; - // Need more information than just first two package - // name elements to determine that classes in - // deploy.jar are not in rt.jar - if (pkgElements.length > 3 && - pkgElements[0].equals("com") && - pkgElements[1].equals("sun")) { - // Need more precise information to disambiguate - // (illegal) references from applications to - // obsolete backported collections classes in - // com/sun/java/util - if (pkgElements.length > 4 && - pkgElements[2].equals("java")) { - int bound = 0; - if (pkgElements[3].equals("util")) { - // Take all of the packages - bound = pkgElements.length - 1; - } else { - // Trim it somewhat more - bound = 4; - } - meta = ""; - for (int j = 0; j < bound; j++) { - meta += pkgElements[j] + "/"; - } - } else { - meta = pkgElements[0] + "/" + pkgElements[1] - + "/" + pkgElements[2] + "/"; + String meta = ""; + + // Default is 2 levels of package elements + int levels = 2; + + // But for some packages we add more elements + for(ExtraLevel el : extraLevels) { + if (name.startsWith(el.prefix)) { + levels = el.levels; + break; } - } else { - meta = pkgElements[0] + "/" + pkgElements[1] + "/"; + } + for (int i = 0; i < levels && i < pkgElements.length - 1; i++) { + meta += pkgElements[i] + "/"; } - indexSet.add(meta); + + if (!meta.equals("")) { + indexSet.add(meta); + } } } // end of "while" loop; diff -r 5f3e7611790a -r a7dcd7811f02 jdk/makefiles/CompileJavaClasses.gmk --- a/jdk/makefiles/CompileJavaClasses.gmk Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/makefiles/CompileJavaClasses.gmk Tue Oct 08 14:57:32 2013 -0700 @@ -237,10 +237,10 @@ # These files do not appear in the build result of the old build. This # is because they are generated sources, but the AUTO_JAVA_FILES won't -# pick them up since they aren't generated when the source dirs are +# pick them up since they aren't generated when the source dirs are # searched and they aren't referenced by any other classes so they won't # be picked up by implicit compilation. On a rebuild, they are picked up -# and compiled. Exclude them here to produce the same rt.jar as the old +# and compiled. Exclude them here to produce the same rt.jar as the old # build does when building just once. EXFILES+=javax/swing/plaf/nimbus/InternalFrameTitlePanePainter.java \ javax/swing/plaf/nimbus/OptionPaneMessageAreaPainter.java \ @@ -308,19 +308,6 @@ ########################################################################################## -ifndef OPENJDK - - $(eval $(call SetupJavaCompilation,BUILD_ALTCLASSES,\ - SETUP:=GENERATE_JDKBYTECODE,\ - SRC:=$(JDK_TOPDIR)/src/closed/share/altclasses, \ - BIN:=$(JDK_OUTPUTDIR)/altclasses_classes)) - - $(BUILD_ALTCLASSES): $(BUILD_JDK) - -endif - -########################################################################################## - $(JDK_OUTPUTDIR)/classes/META-INF/services/com.sun.tools.xjc.Plugin: $(MKDIR) -p $(@D) $(TOUCH) $@ @@ -403,7 +390,7 @@ ########################################################################################## -all: $(BUILD_JDK) $(BUILD_ALTCLASSES) $(BUILD_JOBJC) $(BUILD_JOBJC_HEADERS) $(COPY_EXTRA) \ +all: $(BUILD_JDK) $(BUILD_JOBJC) $(BUILD_JOBJC_HEADERS) $(COPY_EXTRA) \ $(JDK_OUTPUTDIR)/classes/META-INF/services/com.sun.tools.xjc.Plugin \ $(BUILD_ACCESSBRIDGE_32) $(BUILD_ACCESSBRIDGE_64) \ $(BUILD_ACCESSBRIDGE_LEGACY) diff -r 5f3e7611790a -r a7dcd7811f02 jdk/makefiles/CreateJars.gmk --- a/jdk/makefiles/CreateJars.gmk Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/makefiles/CreateJars.gmk Tue Oct 08 14:57:32 2013 -0700 @@ -1003,15 +1003,6 @@ ########################################################################################## -ifndef OPENJDK - $(eval $(call SetupArchive,BUILD_ALT_RT_JAR,,\ - SRCS:=$(JDK_OUTPUTDIR)/altclasses_classes,\ - JAR:=$(IMAGES_OUTPUTDIR)/lib/alt-rt.jar)) - -endif - -########################################################################################## - # This file is imported from hotspot in Import.gmk. Copying it into images/lib so that # all jars can be found in one place when creating images in Images.gmk. It needs to be # done here so that clean targets can be simple and accurate. diff -r 5f3e7611790a -r a7dcd7811f02 jdk/makefiles/Profiles.gmk --- a/jdk/makefiles/Profiles.gmk Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/makefiles/Profiles.gmk Tue Oct 08 14:57:32 2013 -0700 @@ -40,8 +40,8 @@ # imported (signed jars) rather than built. # # The incoming lists, eg PROFILE_1_JRE_JARS_FILES, are the jars to be -# included in this profile. They have the jar name relative to the lib -# directory. We have to turn these into targets by adding the +# included in this profile. They have the jar name relative to the lib +# directory. We have to turn these into targets by adding the # $(IMAGES_OUTPUTDIR)/lib prefix # # Note that some jars may be optional depending on the type of build (jdk vs. @@ -69,10 +69,6 @@ $(addprefix $(IMAGES_OUTPUTDIR)/lib/, $(PROFILE_3_JRE_JAR_FILES)) \ $(PROFILE_2_JARS) -ifdef OPENJDK - FULL_JRE_JAR_FILES := $(filter-out alt-rt.jar, $(FULL_JRE_JAR_FILES)) -endif - ifneq ($(ENABLE_JFR), true) FULL_JRE_JAR_FILES := $(filter-out jfr.jar, $(FULL_JRE_JAR_FILES)) endif @@ -107,7 +103,7 @@ ifeq ($(OPENJDK_TARGET_OS),windows) ALL_JARS += $(IMAGES_OUTPUTDIR)/lib/ext/sunmscapi.jar -endif +endif ifeq ($(OPENJDK_TARGET_OS),macosx) ALL_JARS += $(IMAGES_OUTPUTDIR)/lib/JObjC.jar @@ -142,7 +138,7 @@ $(PROFILE_1_JRE_BIN_FILES) \ $(PROFILE_2_JRE_BIN_FILES) \ $(PROFILE_3_JRE_BIN_FILES) \ - $(FULL_JRE_BIN_FILES) + $(FULL_JRE_BIN_FILES) NOT_JRE_BIN_FILES := $(filter-out $(ALL_JRE_BIN_FILES), $(NEW_ALL_BIN_LIST)) @@ -151,18 +147,18 @@ NOT_JRE_BIN_FILES += \ $(PROFILE_2_JRE_BIN_FILES) \ $(PROFILE_3_JRE_BIN_FILES) \ - $(FULL_JRE_BIN_FILES) + $(FULL_JRE_BIN_FILES) endif ifeq ($(PROFILE), profile_2) NOT_JRE_BIN_FILES += \ $(PROFILE_3_JRE_BIN_FILES) \ - $(FULL_JRE_BIN_FILES) + $(FULL_JRE_BIN_FILES) endif ifeq ($(PROFILE), profile_3) NOT_JRE_BIN_FILES += \ - $(FULL_JRE_BIN_FILES) + $(FULL_JRE_BIN_FILES) endif NOT_JRE_BIN_FILES := $(addprefix $(JDK_OUTPUTDIR)/bin/, $(NOT_JRE_BIN_FILES)) @@ -175,7 +171,7 @@ $(PROFILE_1_JRE_LIB_FILES) \ $(PROFILE_2_JRE_LIB_FILES) \ $(PROFILE_3_JRE_LIB_FILES) \ - $(FULL_JRE_LIB_FILES) + $(FULL_JRE_LIB_FILES) NOT_JRE_LIB_FILES := $(filter-out $(ALL_JRE_LIB_FILES), $(NEW_ALL_LIB_LIST)) @@ -191,18 +187,18 @@ NOT_JRE_LIB_FILES += \ $(PROFILE_2_JRE_LIB_FILES) \ $(PROFILE_3_JRE_LIB_FILES) \ - $(FULL_JRE_LIB_FILES) + $(FULL_JRE_LIB_FILES) endif ifeq ($(PROFILE), profile_2) NOT_JRE_LIB_FILES += \ $(PROFILE_3_JRE_LIB_FILES) \ - $(FULL_JRE_LIB_FILES) + $(FULL_JRE_LIB_FILES) endif ifeq ($(PROFILE), profile_3) NOT_JRE_LIB_FILES += \ - $(FULL_JRE_LIB_FILES) + $(FULL_JRE_LIB_FILES) endif # Exclude the custom jar files as these will be added back via a special rule @@ -210,7 +206,7 @@ ############################################################################### # Customization of rt.jar file contents -# These are expressed as exclusions from everything found in the +# These are expressed as exclusions from everything found in the # JDK_OUTPUTDIR/classes directory ############################################################################### @@ -231,8 +227,8 @@ # # These are specific types that must be included within a package. # There are two cases: -# - individual types in a package that is otherwise excluded at this -# profile level. The only arises if there are split packages. +# - individual types in a package that is otherwise excluded at this +# profile level. The only arises if there are split packages. # # - A higher-level package is included in a high profile where a subpackage # is included in a lower profile. Including the package in the high profile @@ -247,7 +243,7 @@ # containing package is include. Again this occurs with split packges. # # So the exclude list for each profile consists of the include lists -# for all profiles above it, together with any explicitly excluded types. +# for all profiles above it, together with any explicitly excluded types. # This is then combined with the overall RT_JAR_EXCLUDES list (which covers # things that go into other jar files). # @@ -257,7 +253,7 @@ # profile 3 includes the entire package, but it is harmless to add them # explicitly, and complex to determine if we still need to include them. # -# Need a way to express: +# Need a way to express: # for (int i = profile+1; i < 4; i++) # RT_JAR_EXCLUDES += PROFILE_$i_RTJAR_INCLUDE_PACKAGES # @@ -267,7 +263,7 @@ # # These are META-INF/services/ entries found in resources.jar. Together # resources.jar and rt.jar hold the contents of the classes directory, (the -# classes in rt.jar and everything else in resources.jar).Hence the +# classes in rt.jar and everything else in resources.jar).Hence the # include/exclude information for resources.jar is tied to that of rt.jar include profile-rtjar-includes.txt @@ -324,7 +320,7 @@ # Filter out non-OpenJDK services ifdef OPENJDK - EXCLUDED_SERVICES := META-INF/services/javax.script.ScriptEngineFactory + EXCLUDED_SERVICES := META-INF/services/javax.script.ScriptEngineFactory PROFILE_INCLUDE_METAINF_SERVICES := $(filter-out $(EXCLUDED_SERVICES),$(PROFILE_INCLUDE_METAINF_SERVICES)) endif diff -r 5f3e7611790a -r a7dcd7811f02 jdk/makefiles/mapfiles/libjava/mapfile-vers --- a/jdk/makefiles/mapfiles/libjava/mapfile-vers Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/makefiles/mapfiles/libjava/mapfile-vers Tue Oct 08 14:57:32 2013 -0700 @@ -190,6 +190,8 @@ Java_java_lang_reflect_Array_setLong; Java_java_lang_reflect_Array_setShort; Java_java_lang_reflect_Executable_getParameters0; + Java_java_lang_reflect_Executable_getTypeAnnotationBytes0; + Java_java_lang_reflect_Field_getTypeAnnotationBytes0; Java_java_lang_Runtime_freeMemory; Java_java_lang_Runtime_maxMemory; Java_java_lang_Runtime_gc; diff -r 5f3e7611790a -r a7dcd7811f02 jdk/makefiles/profile-includes.txt --- a/jdk/makefiles/profile-includes.txt Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/makefiles/profile-includes.txt Tue Oct 08 14:57:32 2013 -0700 @@ -107,14 +107,14 @@ rmid$(EXE_SUFFIX) \ rmiregistry$(EXE_SUFFIX) -PROFILE_2_JRE_LIB_FILES := +PROFILE_2_JRE_LIB_FILES := -PROFILE_2_JRE_OTHER_FILES := +PROFILE_2_JRE_OTHER_FILES := -PROFILE_2_JRE_JAR_FILES := +PROFILE_2_JRE_JAR_FILES := -PROFILE_3_JRE_BIN_FILES := +PROFILE_3_JRE_BIN_FILES := PROFILE_3_JRE_LIB_FILES := \ $(OPENJDK_TARGET_CPU_LEGACY_LIB)/$(LIBRARY_PREFIX)hprof$(SHARED_LIBRARY_SUFFIX) \ @@ -138,7 +138,7 @@ management/management.properties \ management/snmp.acl.template -PROFILE_3_JRE_OTHER_FILES := +PROFILE_3_JRE_OTHER_FILES := PROFILE_3_JRE_JAR_FILES := \ management-agent.jar @@ -171,7 +171,6 @@ $(OPENJDK_TARGET_CPU_LEGACY_LIB)/$(LIBRARY_PREFIX)splashscreen$(SHARED_LIBRARY_SUFFIX) \ $(OPENJDK_TARGET_CPU_LEGACY_LIB)/$(LIBRARY_PREFIX)t2k$(SHARED_LIBRARY_SUFFIX) \ $(OPENJDK_TARGET_CPU_LEGACY_LIB)/$(LIBRARY_PREFIX)unpack$(SHARED_LIBRARY_SUFFIX) \ - alt-rt.jar \ charsets.jar \ cmm/CIEXYZ.pf \ cmm/GRAY.pf \ @@ -248,7 +247,6 @@ man/man1/unpack200.1 FULL_JRE_JAR_FILES := \ - alt-rt.jar \ charsets.jar \ ext/cldrdata.jar \ ext/dnsns.jar \ diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/macosx/classes/apple/security/AppleProvider.java --- a/jdk/src/macosx/classes/apple/security/AppleProvider.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/macosx/classes/apple/security/AppleProvider.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -43,7 +43,7 @@ public AppleProvider() { /* We are the Apple provider */ - super("Apple", 1.1, info); + super("Apple", 1.8d, info); AccessController.doPrivileged(new java.security.PrivilegedAction() { public Object run() { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java --- a/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java Tue Oct 08 14:57:32 2013 -0700 @@ -104,7 +104,7 @@ public SunJCE() { /* We are the "SunJCE" provider */ - super("SunJCE", 1.7d, info); + super("SunJCE", 1.8d, info); final String BLOCK_MODES = "ECB|CBC|PCBC|CTR|CTS|CFB|OFB" + "|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64" + diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -303,7 +303,7 @@ } else { if (!packfile.toLowerCase().endsWith(".pack") && !packfile.toLowerCase().endsWith(".pac")) { - System.err.println(MessageFormat.format(RESOURCE.getString(DriverResource.WIRTE_PACKGZ_FILE),packfile)); + System.err.println(MessageFormat.format(RESOURCE.getString(DriverResource.WRITE_PACKGZ_FILE),packfile)); printUsage(doPack, false, System.err); System.exit(2); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/com/sun/java/util/jar/pack/DriverResource.java --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/DriverResource.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/DriverResource.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -22,110 +22,99 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package com.sun.java.util.jar.pack; import java.util.ListResourceBundle; public class DriverResource extends ListResourceBundle { - public static final String VERSION ="VERSION"; - public static final String BAD_ARGUMENT ="BAD_ARGUMENT"; - public static final String BAD_OPTION ="BAD_OPTION"; - public static final String BAD_REPACK_OUTPUT="BAD_REPACK_OUTPUT"; - public static final String DETECTED_ZIP_COMMENT="DETECTED_ZIP_COMMENT"; - public static final String SKIP_FOR_REPACKED ="SKIP_FOR_REPACKED"; - public static final String WRITE_PACK_FILE ="WRITE_PACK_FILE"; - public static final String WIRTE_PACKGZ_FILE="WIRTE_PACKGZ_FILE"; - public static final String SKIP_FOR_MOVE_FAILED="SKIP_FOR_MOVE_FAILED"; - public static final String PACK_HELP="PACK_HELP"; - public static final String UNPACK_HELP ="UNPACK_HELP"; - public static final String MORE_INFO = "MORE_INFO"; - public static final String DUPLICATE_OPTION = "DUPLICATE_OPTION"; - public static final String BAD_SPEC = "BAD_SPEC"; - //The following string is duplicate in PACK and UNPACK comment,which was draw out to ruduce translation work. - private static final String PARAMETER_V = " -v, --verbose increase program verbosity"; - private static final String PARAMETER_Q = " -q, --quiet set verbosity to lowest level"; - private static final String PARAMETER_LF = " -l{F}, --log-file={F} output to the given log file, or '-' for System.out"; - private static final String PARAMETER_H = " -?, -h, --help print this message"; - private static final String PARAMETER_VER = " -V, --version print program version"; - private static final String PARAMETER_J = " -J{X} pass option X to underlying Java VM"; - + public static final String VERSION = "VERSION"; + public static final String BAD_ARGUMENT = "BAD_ARGUMENT"; + public static final String BAD_OPTION = "BAD_OPTION"; + public static final String BAD_REPACK_OUTPUT = "BAD_REPACK_OUTPUT"; + public static final String DETECTED_ZIP_COMMENT = "DETECTED_ZIP_COMMENT"; + public static final String SKIP_FOR_REPACKED = "SKIP_FOR_REPACKED"; + public static final String WRITE_PACK_FILE = "WRITE_PACK_FILE"; + public static final String WRITE_PACKGZ_FILE = "WRITE_PACKGZ_FILE"; + public static final String SKIP_FOR_MOVE_FAILED = "SKIP_FOR_MOVE_FAILED"; + public static final String PACK_HELP = "PACK_HELP"; + public static final String UNPACK_HELP = "UNPACK_HELP"; + public static final String MORE_INFO = "MORE_INFO"; + public static final String DUPLICATE_OPTION = "DUPLICATE_OPTION"; + public static final String BAD_SPEC = "BAD_SPEC"; - //The following are outputs of command 'pack200' and 'unpack200'. - //Don't translate command arguments ,words with a prefix of '-' or '--'. - // - private static final Object[][] resource= { - {VERSION,"{0} version {1}"},//parameter 0:class name;parameter 1: version value - {BAD_ARGUMENT,"Bad argument: {0}"}, - {BAD_OPTION,"Bad option: {0}={1}"},//parameter 0:option name;parameter 1:option value - {BAD_REPACK_OUTPUT,"Bad --repack output: {0}"},//parameter 0:filename - {DETECTED_ZIP_COMMENT,"Detected ZIP comment: {0}"},//parameter 0:comment - {SKIP_FOR_REPACKED,"Skipping because already repacked: {0}"},//parameter 0:filename - {WRITE_PACK_FILE,"To write a *.pack file, specify --no-gzip: {0}"},//parameter 0:filename - {WIRTE_PACKGZ_FILE,"To write a *.pack.gz file, specify --gzip: {0}"},//parameter 0:filename - {SKIP_FOR_MOVE_FAILED,"Skipping unpack because move failed: {0}"},//parameter 0:filename - {PACK_HELP,new String[]{ - "Usage: pack200 [-opt... | --option=value]... x.pack[.gz] y.jar", - "", - "Packing Options", - " -g, --no-gzip output a plain *.pack file with no zipping", - " --gzip (default) post-process the pack output with gzip", - " -G, --strip-debug remove debugging attributes while packing", - " -O, --no-keep-file-order do not transmit file ordering information", - " --keep-file-order (default) preserve input file ordering", - " -S{N}, --segment-limit={N} output segment limit (default N=1Mb)", - " -E{N}, --effort={N} packing effort (default N=5)", - " -H{h}, --deflate-hint={h} transmit deflate hint: true, false, or keep (default)", - " -m{V}, --modification-time={V} transmit modtimes: latest or keep (default)", - " -P{F}, --pass-file={F} transmit the given input element(s) uncompressed", - " -U{a}, --unknown-attribute={a} unknown attribute action: error, strip, or pass (default)", - " -C{N}={L}, --class-attribute={N}={L} (user-defined attribute)", - " -F{N}={L}, --field-attribute={N}={L} (user-defined attribute)", - " -M{N}={L}, --method-attribute={N}={L} (user-defined attribute)", - " -D{N}={L}, --code-attribute={N}={L} (user-defined attribute)", - " -f{F}, --config-file={F} read file F for Pack200.Packer properties", - PARAMETER_V , - PARAMETER_Q , - PARAMETER_LF , - PARAMETER_H , - PARAMETER_VER , - PARAMETER_J, - "", - "Notes:", - " The -P, -C, -F, -M, and -D options accumulate.", - " Example attribute definition: -C SourceFile=RUH .", - " Config. file properties are defined by the Pack200 API.", - " For meaning of -S, -E, -H-, -m, -U values, see Pack200 API.", - " Layout definitions (like RUH) are defined by JSR 200.", - "", - "Repacking mode updates the JAR file with a pack/unpack cycle:", - " pack200 [-r|--repack] [-opt | --option=value]... [repackedy.jar] y.jar\n" - } - }, - {UNPACK_HELP,new String[]{ - "Usage: unpack200 [-opt... | --option=value]... x.pack[.gz] y.jar\n", - "", - "Unpacking Options", - " -H{h}, --deflate-hint={h} override transmitted deflate hint: true, false, or keep (default)", - " -r, --remove-pack-file remove input file after unpacking", - PARAMETER_V , - PARAMETER_Q , - PARAMETER_LF , - PARAMETER_H , - PARAMETER_VER , - PARAMETER_J, - } - }, + /* + * The following are the output of 'pack200' and 'unpack200' commands. + * Do not translate command arguments and words with a prefix of '-' or '--'. + */ + private static final Object[][] resource = { + {VERSION, "{0} version {1}"}, // parameter 0:class name;parameter 1: version value + {BAD_ARGUMENT, "Bad argument: {0}"}, + {BAD_OPTION, "Bad option: {0}={1}"}, // parameter 0:option name;parameter 1:option value + {BAD_REPACK_OUTPUT, "Bad --repack output: {0}"}, // parameter 0:filename + {DETECTED_ZIP_COMMENT, "Detected ZIP comment: {0}"}, // parameter 0:comment + {SKIP_FOR_REPACKED, "Skipping because already repacked: {0}"}, // parameter 0:filename + {WRITE_PACK_FILE, "To write a *.pack file, specify --no-gzip: {0}"}, // parameter 0:filename + {WRITE_PACKGZ_FILE, "To write a *.pack.gz file, specify --gzip: {0}"}, // parameter 0:filename + {SKIP_FOR_MOVE_FAILED, "Skipping unpack because move failed: {0}"}, // parameter 0:filename + {PACK_HELP, new String[] { + "Usage: pack200 [-opt... | --option=value]... x.pack[.gz] y.jar", + "", + "Packing Options", + " -g, --no-gzip output a plain *.pack file with no zipping", + " --gzip (default) post-process the pack output with gzip", + " -G, --strip-debug remove debugging attributes while packing", + " -O, --no-keep-file-order do not transmit file ordering information", + " --keep-file-order (default) preserve input file ordering", + " -S{N}, --segment-limit={N} output segment limit (default N=1Mb)", + " -E{N}, --effort={N} packing effort (default N=5)", + " -H{h}, --deflate-hint={h} transmit deflate hint: true, false, or keep (default)", + " -m{V}, --modification-time={V} transmit modtimes: latest or keep (default)", + " -P{F}, --pass-file={F} transmit the given input element(s) uncompressed", + " -U{a}, --unknown-attribute={a} unknown attribute action: error, strip, or pass (default)", + " -C{N}={L}, --class-attribute={N}={L} (user-defined attribute)", + " -F{N}={L}, --field-attribute={N}={L} (user-defined attribute)", + " -M{N}={L}, --method-attribute={N}={L} (user-defined attribute)", + " -D{N}={L}, --code-attribute={N}={L} (user-defined attribute)", + " -f{F}, --config-file={F} read file F for Pack200.Packer properties", + " -v, --verbose increase program verbosity", + " -q, --quiet set verbosity to lowest level", + " -l{F}, --log-file={F} output to the given log file, or '-' for System.out", + " -?, -h, --help print this message", + " -V, --version print program version", + " -J{X} pass option X to underlying Java VM", + "", + "Notes:", + " The -P, -C, -F, -M, and -D options accumulate.", + " Example attribute definition: -C SourceFile=RUH .", + " Config. file properties are defined by the Pack200 API.", + " For meaning of -S, -E, -H-, -m, -U values, see Pack200 API.", + " Layout definitions (like RUH) are defined by JSR 200.", + "", + "Repacking mode updates the JAR file with a pack/unpack cycle:", + " pack200 [-r|--repack] [-opt | --option=value]... [repackedy.jar] y.jar\n" + } + }, + {UNPACK_HELP, new String[] { + "Usage: unpack200 [-opt... | --option=value]... x.pack[.gz] y.jar\n", + "", + "Unpacking Options", + " -H{h}, --deflate-hint={h} override transmitted deflate hint: true, false, or keep (default)", + " -r, --remove-pack-file remove input file after unpacking", + " -v, --verbose increase program verbosity", + " -q, --quiet set verbosity to lowest level", + " -l{F}, --log-file={F} output to the given log file, or '-' for System.out", + " -?, -h, --help print this message", + " -V, --version print program version", + " -J{X} pass option X to underlying Java VM" + } + }, + {MORE_INFO, "(For more information, run {0} --help .)"}, // parameter 0:command name + {DUPLICATE_OPTION, "duplicate option: {0}"}, // parameter 0:option + {BAD_SPEC, "bad spec for {0}: {1}"}, // parameter 0:option;parameter 1:specifier + }; - {MORE_INFO,"(For more information, run {0} --help .)"},//parameter 0:command name - {DUPLICATE_OPTION,"duplicate option: {0}"},//parameter 0:option - {BAD_SPEC,"bad spec for {0}: {1}"},//parameter 0:option;parameter 1:specifier - }; - - protected Object[][] getContents() { - return resource; - } - - + protected Object[][] getContents() { + return resource; + } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/com/sun/security/sasl/Provider.java --- a/jdk/src/share/classes/com/sun/security/sasl/Provider.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/com/sun/security/sasl/Provider.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -53,7 +53,7 @@ " server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5, NTLM)"; public Provider() { - super("SunSASL", 1.7d, info); + super("SunSASL", 1.8d, info); AccessController.doPrivileged(new PrivilegedAction() { public Void run() { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/io/File.java --- a/jdk/src/share/classes/java/io/File.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/io/File.java Tue Oct 08 14:57:32 2013 -0700 @@ -1908,10 +1908,18 @@ } else { n = Math.abs(n); } + + // Use only the file name from the supplied prefix + prefix = (new File(prefix)).getName(); + String name = prefix + Long.toString(n) + suffix; File f = new File(dir, name); - if (!name.equals(f.getName()) || f.isInvalid()) - throw new IOException("Unable to create temporary file"); + if (!name.equals(f.getName()) || f.isInvalid()) { + if (System.getSecurityManager() != null) + throw new IOException("Unable to create temporary file"); + else + throw new IOException("Unable to create temporary file, " + f); + } return f; } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/Class.java --- a/jdk/src/share/classes/java/lang/Class.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/Class.java Tue Oct 08 14:57:32 2013 -0700 @@ -3414,16 +3414,20 @@ transient ClassValue.ClassValueMap classValueMap; /** - * Returns an AnnotatedType object that represents the use of a type to specify - * the superclass of the entity represented by this Class. (The use of type - * Foo to specify the superclass in '... extends Foo' is distinct from the - * declaration of type Foo.) + * Returns an {@code AnnotatedType} object that represents the use of a + * type to specify the superclass of the entity represented by this {@code + * Class} object. (The use of type Foo to specify the superclass + * in '... extends Foo' is distinct from the declaration of type + * Foo.) * - * If this Class represents a class type whose declaration does not explicitly - * indicate an annotated superclass, the return value is null. + *

If this {@code Class} object represents a type whose declaration + * does not explicitly indicate an annotated superclass, then the return + * value is an {@code AnnotatedType} object representing an element with no + * annotations. * - * If this Class represents either the Object class, an interface type, an - * array type, a primitive type, or void, the return value is null. + *

If this {@code Class} represents either the {@code Object} class, an + * interface type, an array type, a primitive type, or void, the return + * value is {@code null}. * * @return an object representing the superclass * @since 1.8 @@ -3441,30 +3445,33 @@ } /** - * Returns an array of AnnotatedType objects that represent the use of types to - * specify superinterfaces of the entity represented by this Class. (The use - * of type Foo to specify a superinterface in '... implements Foo' is - * distinct from the declaration of type Foo.) + * Returns an array of {@code AnnotatedType} objects that represent the use + * of types to specify superinterfaces of the entity represented by this + * {@code Class} object. (The use of type Foo to specify a + * superinterface in '... implements Foo' is distinct from the + * declaration of type Foo.) * - * If this Class represents a class, the return value is an array - * containing objects representing the uses of interface types to specify - * interfaces implemented by the class. The order of the objects in the - * array corresponds to the order of the interface types used in the - * 'implements' clause of the declaration of this Class. + *

If this {@code Class} object represents a class, the return value is + * an array containing objects representing the uses of interface types to + * specify interfaces implemented by the class. The order of the objects in + * the array corresponds to the order of the interface types used in the + * 'implements' clause of the declaration of this {@code Class} object. * - * If this Class represents an interface, the return value is an array - * containing objects representing the uses of interface types to specify - * interfaces directly extended by the interface. The order of the objects in - * the array corresponds to the order of the interface types used in the - * 'extends' clause of the declaration of this Class. + *

If this {@code Class} object represents an interface, the return + * value is an array containing objects representing the uses of interface + * types to specify interfaces directly extended by the interface. The + * order of the objects in the array corresponds to the order of the + * interface types used in the 'extends' clause of the declaration of this + * {@code Class} object. * - * If this Class represents a class or interface whose declaration does not - * explicitly indicate any annotated superinterfaces, the return value is an + *

If this {@code Class} object represents a class or interface whose + * declaration does not explicitly indicate any annotated superinterfaces, + * the return value is an array of length 0. + * + *

If this {@code Class} object represents either the {@code Object} + * class, an array type, a primitive type, or void, the return value is an * array of length 0. * - * If this Class represents either the Object class, an array type, a - * primitive type, or void, the return value is an array of length 0. - * * @return an array representing the superinterfaces * @since 1.8 */ diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java --- a/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Tue Oct 08 14:57:32 2013 -0700 @@ -125,10 +125,7 @@ this.implMethod = implMethod; this.implInfo = caller.revealDirect(implMethod); - // @@@ Temporary work-around pending resolution of 8005119 - this.implKind = (implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeSpecial) - ? MethodHandleInfo.REF_invokeVirtual - : implInfo.getReferenceKind(); + this.implKind = implInfo.getReferenceKind(); this.implIsInstanceMethod = implKind == MethodHandleInfo.REF_invokeVirtual || implKind == MethodHandleInfo.REF_invokeSpecial || diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java --- a/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java Tue Oct 08 14:57:32 2013 -0700 @@ -360,6 +360,10 @@ return new Name(mh, mhName); } + NamedFunction getterFunction(int i) { + return new NamedFunction(getters[i]); + } + static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class); private SpeciesData(String types, Class clazz) { @@ -394,6 +398,7 @@ private boolean isPlaceholder() { return clazz == null; } private static final HashMap CACHE = new HashMap<>(); + static { CACHE.put("", EMPTY); } // make bootstrap predictable private static final boolean INIT_DONE; // set after finishes... SpeciesData extendWithType(char type) { @@ -524,18 +529,18 @@ * A concrete BMH species adheres to the following schema: * *

-         * class Species_<> extends BoundMethodHandle {
-         *     <>
-         *     final SpeciesData speciesData() { return SpeciesData.get("<>"); }
+         * class Species_[[types]] extends BoundMethodHandle {
+         *     [[fields]]
+         *     final SpeciesData speciesData() { return SpeciesData.get("[[types]]"); }
          * }
          * 
* - * The {@code <>} signature is precisely the string that is passed to this + * The {@code [[types]]} signature is precisely the string that is passed to this * method. * - * The {@code <>} section consists of one field definition per character in + * The {@code [[fields]]} section consists of one field definition per character in * the type signature, adhering to the naming schema described in the definition of - * {@link #makeFieldName()}. + * {@link #makeFieldName}. * * For example, a concrete BMH species for two reference and one integral bound values * would have the following shape: @@ -817,7 +822,7 @@ * {@code }. To avoid this, we add an indirection by invoking {@code } through * {@link MethodHandle#linkToSpecial}. * - * The last {@link LambdaForm#Name Name} in the argument's form is expected to be the {@code void} + * The last {@link LambdaForm.Name Name} in the argument's form is expected to be the {@code void} * result of the {@code } invocation. This entry is replaced. */ private static MethodHandle linkConstructor(MethodHandle cmh) { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/CallSite.java --- a/jdk/src/share/classes/java/lang/invoke/CallSite.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/CallSite.java Tue Oct 08 14:57:32 2013 -0700 @@ -60,7 +60,7 @@ *

* Here is a sample use of call sites and bootstrap methods which links every * dynamic call site to print its arguments: -


+
{@code
 static void test() throws Throwable {
     // THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
     InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
@@ -79,7 +79,7 @@
   // ignore caller and name, but match the type:
   return new ConstantCallSite(printArgs.asType(type));
 }
-
+}
* @author John Rose, JSR 292 EG */ abstract @@ -199,12 +199,12 @@ * which has been linked to this call site. *

* This method is equivalent to the following code: - *

+     * 
{@code
      * MethodHandle getTarget, invoker, result;
      * getTarget = MethodHandles.publicLookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class));
      * invoker = MethodHandles.exactInvoker(this.type());
      * result = MethodHandles.foldArguments(invoker, getTarget)
-     * 
+ * }
* * @return a method handle which always invokes this call site's current target */ @@ -261,7 +261,7 @@ Object info, // Caller information: Class callerClass) { - Object caller = IMPL_LOOKUP.in(callerClass); + MethodHandles.Lookup caller = IMPL_LOOKUP.in(callerClass); CallSite site; try { Object binding; @@ -273,14 +273,44 @@ } else { Object[] argv = (Object[]) info; maybeReBoxElements(argv); - if (3 + argv.length > 255) - throw new BootstrapMethodError("too many bootstrap method arguments"); - MethodType bsmType = bootstrapMethod.type(); - if (bsmType.parameterCount() == 4 && bsmType.parameterType(3) == Object[].class) - binding = bootstrapMethod.invoke(caller, name, type, argv); - else - binding = MethodHandles.spreadInvoker(bsmType, 3) - .invoke(bootstrapMethod, caller, name, type, argv); + switch (argv.length) { + case 0: + binding = bootstrapMethod.invoke(caller, name, type); + break; + case 1: + binding = bootstrapMethod.invoke(caller, name, type, + argv[0]); + break; + case 2: + binding = bootstrapMethod.invoke(caller, name, type, + argv[0], argv[1]); + break; + case 3: + binding = bootstrapMethod.invoke(caller, name, type, + argv[0], argv[1], argv[2]); + break; + case 4: + binding = bootstrapMethod.invoke(caller, name, type, + argv[0], argv[1], argv[2], argv[3]); + break; + case 5: + binding = bootstrapMethod.invoke(caller, name, type, + argv[0], argv[1], argv[2], argv[3], argv[4]); + break; + case 6: + binding = bootstrapMethod.invoke(caller, name, type, + argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); + break; + default: + final int NON_SPREAD_ARG_COUNT = 3; // (caller, name, type) + if (NON_SPREAD_ARG_COUNT + argv.length > MethodType.MAX_MH_ARITY) + throw new BootstrapMethodError("too many bootstrap method arguments"); + MethodType bsmType = bootstrapMethod.type(); + MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argv.length); + MethodHandle typedBSM = bootstrapMethod.asType(invocationType); + MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT); + binding = spreader.invokeExact(typedBSM, (Object)caller, (Object)name, (Object)type, argv); + } } //System.out.println("BSM for "+name+type+" => "+binding); if (binding instanceof CallSite) { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java --- a/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java Tue Oct 08 14:57:32 2013 -0700 @@ -257,12 +257,12 @@ assert(names.length == nameCursor); if (doesAlloc) { // names = { argx,y,z,... new C, init method } - names[NEW_OBJ] = new Name(NF_allocateInstance, names[DMH_THIS]); - names[GET_MEMBER] = new Name(NF_constructorMethod, names[DMH_THIS]); + names[NEW_OBJ] = new Name(Lazy.NF_allocateInstance, names[DMH_THIS]); + names[GET_MEMBER] = new Name(Lazy.NF_constructorMethod, names[DMH_THIS]); } else if (needsInit) { - names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]); + names[GET_MEMBER] = new Name(Lazy.NF_internalMemberNameEnsureInit, names[DMH_THIS]); } else { - names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]); + names[GET_MEMBER] = new Name(Lazy.NF_internalMemberName, names[DMH_THIS]); } Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class); assert(outArgs[outArgs.length-1] == names[GET_MEMBER]); // look, shifted args! @@ -637,18 +637,18 @@ final int RESULT = nameCursor-1; // either the call or the cast Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType()); if (needsInit) - names[INIT_BAR] = new Name(NF_ensureInitialized, names[DMH_THIS]); + names[INIT_BAR] = new Name(Lazy.NF_ensureInitialized, names[DMH_THIS]); if (needsCast && !isGetter) - names[PRE_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[SET_VALUE]); + names[PRE_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[SET_VALUE]); Object[] outArgs = new Object[1 + linkerType.parameterCount()]; assert(outArgs.length == (isGetter ? 3 : 4)); outArgs[0] = UNSAFE; if (isStatic) { - outArgs[1] = names[F_HOLDER] = new Name(NF_staticBase, names[DMH_THIS]); - outArgs[2] = names[F_OFFSET] = new Name(NF_staticOffset, names[DMH_THIS]); + outArgs[1] = names[F_HOLDER] = new Name(Lazy.NF_staticBase, names[DMH_THIS]); + outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_staticOffset, names[DMH_THIS]); } else { - outArgs[1] = names[OBJ_CHECK] = new Name(NF_checkBase, names[OBJ_BASE]); - outArgs[2] = names[F_OFFSET] = new Name(NF_fieldOffset, names[DMH_THIS]); + outArgs[1] = names[OBJ_CHECK] = new Name(Lazy.NF_checkBase, names[OBJ_BASE]); + outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_fieldOffset, names[DMH_THIS]); } if (!isGetter) { outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]); @@ -656,7 +656,7 @@ for (Object a : outArgs) assert(a != null); names[LINKER_CALL] = new Name(linker, outArgs); if (needsCast && isGetter) - names[POST_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[LINKER_CALL]); + names[POST_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[LINKER_CALL]); for (Name n : names) assert(n != null); String fieldOrStatic = (isStatic ? "Static" : "Field"); String lambdaName = (linkerName + fieldOrStatic); // significant only for debugging @@ -665,48 +665,54 @@ return new LambdaForm(lambdaName, ARG_LIMIT, names, RESULT); } - private static final NamedFunction - NF_internalMemberName, - NF_internalMemberNameEnsureInit, - NF_ensureInitialized, - NF_fieldOffset, - NF_checkBase, - NF_staticBase, - NF_staticOffset, - NF_checkCast, - NF_allocateInstance, - NF_constructorMethod; - static { - try { - NamedFunction nfs[] = { - NF_internalMemberName = new NamedFunction(DirectMethodHandle.class - .getDeclaredMethod("internalMemberName", Object.class)), - NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class - .getDeclaredMethod("internalMemberNameEnsureInit", Object.class)), - NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class - .getDeclaredMethod("ensureInitialized", Object.class)), - NF_fieldOffset = new NamedFunction(DirectMethodHandle.class - .getDeclaredMethod("fieldOffset", Object.class)), - NF_checkBase = new NamedFunction(DirectMethodHandle.class - .getDeclaredMethod("checkBase", Object.class)), - NF_staticBase = new NamedFunction(DirectMethodHandle.class - .getDeclaredMethod("staticBase", Object.class)), - NF_staticOffset = new NamedFunction(DirectMethodHandle.class - .getDeclaredMethod("staticOffset", Object.class)), - NF_checkCast = new NamedFunction(DirectMethodHandle.class - .getDeclaredMethod("checkCast", Object.class, Object.class)), - NF_allocateInstance = new NamedFunction(DirectMethodHandle.class - .getDeclaredMethod("allocateInstance", Object.class)), - NF_constructorMethod = new NamedFunction(DirectMethodHandle.class - .getDeclaredMethod("constructorMethod", Object.class)) - }; - for (NamedFunction nf : nfs) { - // Each nf must be statically invocable or we get tied up in our bootstraps. - assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf; - nf.resolve(); + /** + * Pre-initialized NamedFunctions for bootstrapping purposes. + * Factored in an inner class to delay initialization until first usage. + */ + private static class Lazy { + static final NamedFunction + NF_internalMemberName, + NF_internalMemberNameEnsureInit, + NF_ensureInitialized, + NF_fieldOffset, + NF_checkBase, + NF_staticBase, + NF_staticOffset, + NF_checkCast, + NF_allocateInstance, + NF_constructorMethod; + static { + try { + NamedFunction nfs[] = { + NF_internalMemberName = new NamedFunction(DirectMethodHandle.class + .getDeclaredMethod("internalMemberName", Object.class)), + NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class + .getDeclaredMethod("internalMemberNameEnsureInit", Object.class)), + NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class + .getDeclaredMethod("ensureInitialized", Object.class)), + NF_fieldOffset = new NamedFunction(DirectMethodHandle.class + .getDeclaredMethod("fieldOffset", Object.class)), + NF_checkBase = new NamedFunction(DirectMethodHandle.class + .getDeclaredMethod("checkBase", Object.class)), + NF_staticBase = new NamedFunction(DirectMethodHandle.class + .getDeclaredMethod("staticBase", Object.class)), + NF_staticOffset = new NamedFunction(DirectMethodHandle.class + .getDeclaredMethod("staticOffset", Object.class)), + NF_checkCast = new NamedFunction(DirectMethodHandle.class + .getDeclaredMethod("checkCast", Object.class, Object.class)), + NF_allocateInstance = new NamedFunction(DirectMethodHandle.class + .getDeclaredMethod("allocateInstance", Object.class)), + NF_constructorMethod = new NamedFunction(DirectMethodHandle.class + .getDeclaredMethod("constructorMethod", Object.class)) + }; + for (NamedFunction nf : nfs) { + // Each nf must be statically invocable or we get tied up in our bootstraps. + assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf; + nf.resolve(); + } + } catch (ReflectiveOperationException ex) { + throw newInternalError(ex); } - } catch (ReflectiveOperationException ex) { - throw newInternalError(ex); } } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/InvokeGeneric.java --- a/jdk/src/share/classes/java/lang/invoke/InvokeGeneric.java Tue Oct 08 14:53:14 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.lang.invoke; - -import sun.invoke.util.*; -import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; - -/** - * Adapters which manage inexact MethodHandle.invoke calls. - * The JVM calls one of these when the exact type match fails. - * @author jrose - */ -class InvokeGeneric { - // erased type for the call, which originates from an inexact invoke site - private final MethodType erasedCallerType; - // an invoker of type (MT, MH; A...) -> R - private final MethodHandle initialInvoker; - - /** Compute and cache information for this adapter, so that it can - * call out to targets of the erasure-family of the given erased type. - */ - /*non-public*/ InvokeGeneric(MethodType erasedCallerType) throws ReflectiveOperationException { - assert(erasedCallerType.equals(erasedCallerType.erase())); - this.erasedCallerType = erasedCallerType; - this.initialInvoker = makeInitialInvoker(); - assert initialInvoker.type().equals(erasedCallerType - .insertParameterTypes(0, MethodType.class, MethodHandle.class)) - : initialInvoker.type(); - } - - private static MethodHandles.Lookup lookup() { - return IMPL_LOOKUP; - } - - /** Return the adapter information for this type's erasure. */ - /*non-public*/ static MethodHandle generalInvokerOf(MethodType erasedCallerType) throws ReflectiveOperationException { - InvokeGeneric gen = new InvokeGeneric(erasedCallerType); - return gen.initialInvoker; - } - - private MethodHandle makeInitialInvoker() throws ReflectiveOperationException { - // postDispatch = #(MH'; MT, MH; A...){MH'(MT, MH; A)} - MethodHandle postDispatch = makePostDispatchInvoker(); - MethodHandle invoker; - if (returnConversionPossible()) { - invoker = MethodHandles.foldArguments(postDispatch, - dispatcher("dispatchWithConversion")); - } else { - invoker = MethodHandles.foldArguments(postDispatch, dispatcher("dispatch")); - } - return invoker; - } - - private static final Class[] EXTRA_ARGS = { MethodType.class, MethodHandle.class }; - private MethodHandle makePostDispatchInvoker() { - // Take (MH'; MT, MH; A...) and run MH'(MT, MH; A...). - MethodType invokerType = erasedCallerType.insertParameterTypes(0, EXTRA_ARGS); - return invokerType.invokers().exactInvoker(); - } - private MethodHandle dropDispatchArguments(MethodHandle targetInvoker) { - assert(targetInvoker.type().parameterType(0) == MethodHandle.class); - return MethodHandles.dropArguments(targetInvoker, 1, EXTRA_ARGS); - } - - private MethodHandle dispatcher(String dispatchName) throws ReflectiveOperationException { - return lookup().bind(this, dispatchName, - MethodType.methodType(MethodHandle.class, - MethodType.class, MethodHandle.class)); - } - - static final boolean USE_AS_TYPE_PATH = true; - - /** Return a method handle to invoke on the callerType, target, and remaining arguments. - * The method handle must finish the call. - * This is the first look at the caller type and target. - */ - private MethodHandle dispatch(MethodType callerType, MethodHandle target) { - MethodType targetType = target.type(); - if (USE_AS_TYPE_PATH || target.isVarargsCollector()) { - MethodHandle newTarget = target.asType(callerType); - targetType = callerType; - Invokers invokers = targetType.invokers(); - MethodHandle invoker = invokers.erasedInvokerWithDrops; - if (invoker == null) { - invokers.erasedInvokerWithDrops = invoker = - dropDispatchArguments(invokers.erasedInvoker()); - } - return invoker.bindTo(newTarget); - } - throw new RuntimeException("NYI"); - } - - private MethodHandle dispatchWithConversion(MethodType callerType, MethodHandle target) { - MethodHandle finisher = dispatch(callerType, target); - if (returnConversionNeeded(callerType, target)) - finisher = addReturnConversion(finisher, callerType.returnType()); //FIXME: slow - return finisher; - } - - private boolean returnConversionPossible() { - Class needType = erasedCallerType.returnType(); - return !needType.isPrimitive(); - } - private boolean returnConversionNeeded(MethodType callerType, MethodHandle target) { - Class needType = callerType.returnType(); - if (needType == erasedCallerType.returnType()) - return false; // no conversions possible, since must be primitive or Object - Class haveType = target.type().returnType(); - if (VerifyType.isNullConversion(haveType, needType) && !needType.isInterface()) - return false; - return true; - } - private MethodHandle addReturnConversion(MethodHandle finisher, Class type) { - // FIXME: This is slow because it creates a closure node on every call that requires a return cast. - MethodType finisherType = finisher.type(); - MethodHandle caster = ValueConversions.identity(type); - caster = caster.asType(caster.type().changeParameterType(0, finisherType.returnType())); - finisher = MethodHandles.filterReturnValue(finisher, caster); - return finisher.asType(finisherType); - } - - public String toString() { - return "InvokeGeneric"+erasedCallerType; - } -} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java --- a/jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Tue Oct 08 14:57:32 2013 -0700 @@ -242,9 +242,6 @@ /** * Extract the MemberName of a newly-defined method. - * - * @param classFile - * @return */ private MemberName loadMethod(byte[] classFile) { Class invokerClass = loadAndInitializeInvokerClass(classFile, cpPatches(classFile)); @@ -253,10 +250,6 @@ /** * Define a given class as anonymous class in the runtime system. - * - * @param classBytes - * @param patches - * @return */ private static Class loadAndInitializeInvokerClass(byte[] classBytes, Object[] patches) { Class invokerClass = UNSAFE.defineAnonymousClass(HOST_CLASS, classBytes, patches); @@ -264,14 +257,6 @@ return invokerClass; } - /** - * TODO - * - * @param invokerClass - * @param name - * @param type - * @return - */ private static MemberName resolveInvokerMember(Class invokerClass, String name, MethodType type) { MemberName member = new MemberName(invokerClass, name, type, REF_invokeStatic); //System.out.println("resolveInvokerMember => "+member); @@ -499,10 +484,6 @@ /** * Generate customized bytecode for a given LambdaForm. - * - * @param form - * @param invokerType - * @return */ static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) { InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType); @@ -565,8 +546,6 @@ /** * Emit an invoke for the given name. - * - * @param name */ void emitInvoke(Name name) { if (true) { @@ -645,8 +624,6 @@ /** * Emit an invoke for the given name, using the MemberName directly. - * - * @param name */ void emitStaticInvoke(MemberName member, Name name) { assert(member.equals(name.function.member())); @@ -690,9 +667,6 @@ /** * Check if MemberName is a call to MethodHandleImpl.selectAlternative. - * - * @param member - * @return true if member is a call to MethodHandleImpl.selectAlternative */ private boolean isSelectAlternative(MemberName member) { return member != null && @@ -704,14 +678,12 @@ * Emit bytecode for the selectAlternative idiom. * * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest): - * + *
{@code
      *   Lambda(a0:L,a1:I)=>{
      *     t2:I=foo.test(a1:I);
      *     t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
      *     t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
-     *
-     * @param selectAlternativeName
-     * @param invokeBasicName
+     * }
*/ private void emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) { MethodType type = selectAlternativeName.function.methodType(); @@ -750,11 +722,6 @@ mv.visitLabel(L_done); } - /** - * - * @param name - * @param paramIndex - */ private void emitPushArgument(Name name, int paramIndex) { Object arg = name.arguments[paramIndex]; char ptype = name.function.parameterType(paramIndex); @@ -923,9 +890,6 @@ /** * Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments. - * - * @param sig - * @return */ static MemberName generateLambdaFormInterpreterEntryPoint(String sig) { assert(LambdaForm.isValidSignature(sig)); @@ -993,10 +957,6 @@ /** * Generate bytecode for a NamedFunction invoker. - * - * @param srcType - * @param dstType - * @return */ static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) { MethodType invokerType = LambdaForm.NamedFunction.INVOKER_METHOD_TYPE; diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/Invokers.java --- a/jdk/src/share/classes/java/lang/invoke/Invokers.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/Invokers.java Tue Oct 08 14:57:32 2013 -0700 @@ -44,6 +44,7 @@ // exact invoker for the outgoing call private /*lazy*/ MethodHandle exactInvoker; + private /*lazy*/ MethodHandle basicInvoker; // invokeBasic (unchecked exact) // erased (partially untyped but with primitives) invoker for the outgoing call // FIXME: get rid of @@ -74,21 +75,7 @@ /*non-public*/ MethodHandle exactInvoker() { MethodHandle invoker = exactInvoker; if (invoker != null) return invoker; - MethodType mtype = targetType; - MethodType invokerType = mtype.invokerType(); - LambdaForm lform; - final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value - if (mtype.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY - MTYPE_ARG_APPENDED) { - lform = invokeForm(mtype, false, MethodTypeForm.LF_EX_INVOKER); - invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype); - } else { - // At maximum arity, we cannot afford an extra mtype argument, - // so build a fully customized (non-cached) invoker form. - lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_INVOKER); - invoker = SimpleMethodHandle.make(invokerType, lform); - } - invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invokeExact", mtype)); - assert(checkInvoker(invoker)); + invoker = makeExactOrGeneralInvoker(true); exactInvoker = invoker; return invoker; } @@ -96,43 +83,56 @@ /*non-public*/ MethodHandle generalInvoker() { MethodHandle invoker = generalInvoker; if (invoker != null) return invoker; - MethodType mtype = targetType; - MethodType invokerType = mtype.invokerType(); - LambdaForm lform; - final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value - assert(GENERIC_INVOKER_SLOP >= MTYPE_ARG_APPENDED); - if (mtype.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY - GENERIC_INVOKER_SLOP) { - prepareForGenericCall(mtype); - lform = invokeForm(mtype, false, MethodTypeForm.LF_GEN_INVOKER); - invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype); - } else { - // At maximum arity, we cannot afford an extra mtype argument, - // so build a fully customized (non-cached) invoker form. - lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_INVOKER); - invoker = SimpleMethodHandle.make(invokerType, lform); - } - invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invoke", mtype)); - assert(checkInvoker(invoker)); + invoker = makeExactOrGeneralInvoker(false); generalInvoker = invoker; return invoker; } - /*non-public*/ MethodHandle makeBasicInvoker() { - MethodHandle invoker = DirectMethodHandle.make(invokeBasicMethod(targetType)); - assert(targetType == targetType.basicType()); - // Note: This is not cached here. It is cached by the calling MethodTypeForm. + private MethodHandle makeExactOrGeneralInvoker(boolean isExact) { + MethodType mtype = targetType; + MethodType invokerType = mtype.invokerType(); + int which = (isExact ? MethodTypeForm.LF_EX_INVOKER : MethodTypeForm.LF_GEN_INVOKER); + LambdaForm lform = invokeHandleForm(mtype, false, which); + MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype); + String whichName = (isExact ? "invokeExact" : "invoke"); + invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype)); assert(checkInvoker(invoker)); + maybeCompileToBytecode(invoker); return invoker; } - static MemberName invokeBasicMethod(MethodType type) { - type = type.basicType(); - String name = "invokeBasic"; + /** If the target type seems to be common enough, eagerly compile the invoker to bytecodes. */ + private void maybeCompileToBytecode(MethodHandle invoker) { + final int EAGER_COMPILE_ARITY_LIMIT = 10; + if (targetType == targetType.erase() && + targetType.parameterCount() < EAGER_COMPILE_ARITY_LIMIT) { + invoker.form.compileToBytecode(); + } + } + + /*non-public*/ MethodHandle basicInvoker() { + MethodHandle invoker = basicInvoker; + if (invoker != null) return invoker; + MethodType basicType = targetType.basicType(); + if (basicType != targetType) { + // double cache; not used significantly + return basicInvoker = basicType.invokers().basicInvoker(); + } + MemberName method = invokeBasicMethod(basicType); + invoker = DirectMethodHandle.make(method); + assert(checkInvoker(invoker)); + basicInvoker = invoker; + return invoker; + } + + // This next one is called from LambdaForm.NamedFunction.. + /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) { + assert(basicType == basicType.basicType()); try { //Lookup.findVirtual(MethodHandle.class, name, type); - return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, name, type); + return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType); } catch (ReflectiveOperationException ex) { - throw newInternalError("JVM cannot find invoker for "+type, ex); + throw newInternalError("JVM cannot find invoker for "+basicType, ex); } } @@ -184,6 +184,7 @@ vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader); } assert(vaInvoker.type().equals(spreadInvokerType.invokerType())); + maybeCompileToBytecode(vaInvoker); spreadInvokers[leadingArgCount] = vaInvoker; return vaInvoker; } @@ -231,32 +232,38 @@ return "Invokers"+targetType; } - static MemberName exactInvokerMethod(MethodType mtype, Object[] appendixResult) { + static MemberName methodHandleInvokeLinkerMethod(String name, + MethodType mtype, + Object[] appendixResult) { + int which; + switch (name) { + case "invokeExact": which = MethodTypeForm.LF_EX_LINKER; break; + case "invoke": which = MethodTypeForm.LF_GEN_LINKER; break; + default: throw new InternalError("not invoker: "+name); + } LambdaForm lform; - final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value - if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MTYPE_ARG_APPENDED) { - lform = invokeForm(mtype, false, MethodTypeForm.LF_EX_LINKER); + if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) { + lform = invokeHandleForm(mtype, false, which); appendixResult[0] = mtype; } else { - lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_LINKER); + lform = invokeHandleForm(mtype, true, which); } return lform.vmentry; } - static MemberName genericInvokerMethod(MethodType mtype, Object[] appendixResult) { - LambdaForm lform; - final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value - if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - (MTYPE_ARG_APPENDED + GENERIC_INVOKER_SLOP)) { - lform = invokeForm(mtype, false, MethodTypeForm.LF_GEN_LINKER); - appendixResult[0] = mtype; - prepareForGenericCall(mtype); - } else { - lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_LINKER); - } - return lform.vmentry; - } + // argument count to account for trailing "appendix value" (typically the mtype) + private static final int MH_LINKER_ARG_APPENDED = 1; - private static LambdaForm invokeForm(MethodType mtype, boolean customized, int which) { + /** Returns an adapter for invokeExact or generic invoke, as a MH or constant pool linker. + * If !customized, caller is responsible for supplying, during adapter execution, + * a copy of the exact mtype. This is because the adapter might be generalized to + * a basic type. + * @param mtype the caller's method type (either basic or full-custom) + * @param customized whether to use a trailing appendix argument (to carry the mtype) + * @param which bit-encoded 0x01 whether it is a CP adapter ("linker") or MHs.invoker value ("invoker"); + * 0x02 whether it is for invokeExact or generic invoke + */ + private static LambdaForm invokeHandleForm(MethodType mtype, boolean customized, int which) { boolean isCached; if (!customized) { mtype = mtype.basicType(); // normalize Z to I, String to Object, etc. @@ -301,41 +308,24 @@ : Arrays.asList(mtype, customized, which, nameCursor, names.length); if (MTYPE_ARG >= INARG_LIMIT) { assert(names[MTYPE_ARG] == null); - names[MTYPE_ARG] = BoundMethodHandle.getSpeciesData("L").getterName(names[THIS_MH], 0); + NamedFunction getter = BoundMethodHandle.getSpeciesData("L").getterFunction(0); + names[MTYPE_ARG] = new Name(getter, names[THIS_MH]); // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM) } // Make the final call. If isGeneric, then prepend the result of type checking. - MethodType outCallType; - Object[] outArgs; + MethodType outCallType = mtype.basicType(); + Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class); Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]); if (!isGeneric) { names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg); // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*) - outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class); - outCallType = mtype; - } else if (customized) { - names[CHECK_TYPE] = new Name(NF_asType, names[CALL_MH], mtypeArg); - // mh.invokeGeneric(a*):R => - // let mt=TYPEOF(a*:R), tmh=asType(mh, mt); - // tmh.invokeBasic(a*) - outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class); - outCallType = mtype; } else { names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg); - // mh.invokeGeneric(a*):R => - // let mt=TYPEOF(a*:R), gamh=checkGenericType(mh, mt); - // gamh.invokeBasic(mt, mh, a*) - final int PREPEND_GAMH = 0, PREPEND_MT = 1, PREPEND_COUNT = 2; - assert(GENERIC_INVOKER_SLOP == PREPEND_COUNT); - outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT + PREPEND_COUNT, Object[].class); - // prepend arguments: - System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT); - outArgs[PREPEND_GAMH] = names[CHECK_TYPE]; - outArgs[PREPEND_MT] = mtypeArg; - outCallType = mtype.insertParameterTypes(0, MethodType.class, MethodHandle.class); + // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*) + outArgs[0] = names[CHECK_TYPE]; } - names[LINKER_CALL] = new Name(invokeBasicMethod(outCallType), outArgs); + names[LINKER_CALL] = new Name(outCallType, outArgs); lform = new LambdaForm(debugName, INARG_LIMIT, names); if (isLinker) lform.compileToBytecode(); // JVM needs a real methodOop @@ -343,7 +333,6 @@ lform = mtype.form().setCachedLambdaForm(which, lform); return lform; } - private static final int GENERIC_INVOKER_SLOP = 2; // used elsewhere to avoid arity problems /*non-public*/ static WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) { @@ -362,47 +351,53 @@ throw newWrongMethodTypeException(expected, actual); } - /** Static definition of MethodHandle.invokeGeneric checking code. */ + /** Static definition of MethodHandle.invokeGeneric checking code. + * Directly returns the type-adjusted MH to invoke, as follows: + * {@code (R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)} + */ /*non-public*/ static @ForceInline Object checkGenericType(Object mhObj, Object expectedObj) { MethodHandle mh = (MethodHandle) mhObj; MethodType expected = (MethodType) expectedObj; - //MethodType actual = mh.type(); - MethodHandle gamh = expected.form().genericInvoker; - if (gamh != null) return gamh; - return prepareForGenericCall(expected); - } - - /** - * Returns an adapter GA for invoking a MH with type adjustments. - * The MethodType of the generic invocation site is prepended to MH - * and its arguments as follows: - * {@code (R)MH.invoke(A*) => GA.invokeBasic(TYPEOF, MH, A*)} - */ - /*non-public*/ static MethodHandle prepareForGenericCall(MethodType mtype) { - // force any needed adapters to be preconstructed - MethodTypeForm form = mtype.form(); - MethodHandle gamh = form.genericInvoker; - if (gamh != null) return gamh; - try { - // Trigger adapter creation. - gamh = InvokeGeneric.generalInvokerOf(form.erasedType); - form.genericInvoker = gamh; - return gamh; - } catch (Exception ex) { - throw newInternalError("Exception while resolving inexact invoke", ex); - } + if (mh.type() == expected) return mh; + MethodHandle atc = mh.asTypeCache; + if (atc != null && atc.type() == expected) return atc; + return mh.asType(expected); + /* Maybe add more paths here. Possible optimizations: + * for (R)MH.invoke(a*), + * let MT0 = TYPEOF(a*:R), MT1 = MH.type + * + * if MT0==MT1 or MT1 can be safely called by MT0 + * => MH.invokeBasic(a*) + * if MT1 can be safely called by MT0[R := Object] + * => MH.invokeBasic(a*) & checkcast(R) + * if MT1 can be safely called by MT0[* := Object] + * => checkcast(A)* & MH.invokeBasic(a*) & checkcast(R) + * if a big adapter BA can be pulled out of (MT0,MT1) + * => BA.invokeBasic(MT0,MH,a*) + * if a local adapter LA can cached on static CS0 = new GICS(MT0) + * => CS0.LA.invokeBasic(MH,a*) + * else + * => MH.asType(MT0).invokeBasic(A*) + */ } static MemberName linkToCallSiteMethod(MethodType mtype) { - LambdaForm lform = callSiteForm(mtype); + LambdaForm lform = callSiteForm(mtype, false); return lform.vmentry; } - private static LambdaForm callSiteForm(MethodType mtype) { + static MemberName linkToTargetMethod(MethodType mtype) { + LambdaForm lform = callSiteForm(mtype, true); + return lform.vmentry; + } + + // skipCallSite is true if we are optimizing a ConstantCallSite + private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) { mtype = mtype.basicType(); // normalize Z to I, String to Object, etc. - LambdaForm lform = mtype.form().cachedLambdaForm(MethodTypeForm.LF_CS_LINKER); + final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER); + LambdaForm lform = mtype.form().cachedLambdaForm(which); if (lform != null) return lform; // exactInvokerForm (Object,Object)Object // link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial @@ -410,24 +405,26 @@ final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount(); final int INARG_LIMIT = OUTARG_LIMIT + 1; int nameCursor = OUTARG_LIMIT; - final int CSITE_ARG = nameCursor++; // the last in-argument - final int CALL_MH = nameCursor++; // result of getTarget + final int APPENDIX_ARG = nameCursor++; // the last in-argument + final int CSITE_ARG = skipCallSite ? -1 : APPENDIX_ARG; + final int CALL_MH = skipCallSite ? APPENDIX_ARG : nameCursor++; // result of getTarget final int LINKER_CALL = nameCursor++; - MethodType invokerFormType = mtype.appendParameterTypes(CallSite.class); + MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class); Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType); assert(names.length == nameCursor); - assert(names[CSITE_ARG] != null); - names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]); + assert(names[APPENDIX_ARG] != null); + if (!skipCallSite) + names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]); // (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*) final int PREPEND_MH = 0, PREPEND_COUNT = 1; Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class); // prepend MH argument: System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT); outArgs[PREPEND_MH] = names[CALL_MH]; - names[LINKER_CALL] = new Name(invokeBasicMethod(mtype), outArgs); - lform = new LambdaForm("linkToCallSite", INARG_LIMIT, names); + names[LINKER_CALL] = new Name(mtype, outArgs); + lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names); lform.compileToBytecode(); // JVM needs a real methodOop - lform = mtype.form().setCachedLambdaForm(MethodTypeForm.LF_CS_LINKER, lform); + lform = mtype.form().setCachedLambdaForm(which, lform); return lform; } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/LambdaForm.java --- a/jdk/src/share/classes/java/lang/invoke/LambdaForm.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/LambdaForm.java Tue Oct 08 14:57:32 2013 -0700 @@ -50,7 +50,7 @@ * The result of the lambda is defined as one of the names, often the last one. *

* Here is an approximate grammar: - *

+ * 
{@code
  * LambdaForm = "(" ArgName* ")=>{" TempName* Result "}"
  * ArgName = "a" N ":" T
  * TempName = "t" N ":" T "=" Function "(" Argument* ");"
@@ -60,7 +60,7 @@
  * NameRef = "a" N | "t" N
  * N = (any whole number)
  * T = "L" | "I" | "J" | "F" | "D" | "V"
- * 
+ * }
* Names are numbered consecutively from left to right starting at zero. * (The letters are merely a taste of syntax sugar.) * Thus, the first temporary (if any) is always numbered N (where N=arity). @@ -69,7 +69,7 @@ * A lambda has a void result if and only if its result index is -1. * If a temporary has the type "V", it cannot be the subject of a NameRef, * even though possesses a number. - * Note that all reference types are erased to "L", which stands for {@code Object). + * Note that all reference types are erased to "L", which stands for {@code Object}. * All subword types (boolean, byte, short, char) are erased to "I" which is {@code int}. * The other types stand for the usual primitive types. *

@@ -89,7 +89,7 @@ * encoded by using temporary expressions which call type-transformed identity functions. *

* Examples: - *

+ * 
{@code
  * (a0:J)=>{ a0 }
  *     == identity(long)
  * (a0:I)=>{ t1:V = System.out#println(a0); void }
@@ -113,14 +113,14 @@
  * (a0:L, a1:L)=>{ t2:L = BoundMethodHandle#argument(a0);
  *                 t3:L = Class#cast(t2,a1); t3 }
  *     == invoker for identity method handle which performs cast
- * 
+ * }
*

* @author John Rose, JSR 292 EG */ class LambdaForm { final int arity; final int result; - final Name[] names; + @Stable final Name[] names; final String debugName; MemberName vmentry; // low-level behavior, or null if not yet prepared private boolean isCompiled; @@ -457,7 +457,7 @@ isCompiled = true; return vmentry; } catch (Error | Exception ex) { - throw newInternalError(this.toString(), ex); + throw newInternalError("compileToBytecode", ex); } } @@ -683,8 +683,9 @@ */ static void traceInterpreter(String event, Object obj, Object... args) { - if (!TRACE_INTERPRETER) return; - System.out.println("LFI: "+event+" "+(obj != null ? obj : "")+(args != null && args.length != 0 ? Arrays.asList(args) : "")); + if (TRACE_INTERPRETER) { + System.out.println("LFI: "+event+" "+(obj != null ? obj : "")+(args != null && args.length != 0 ? Arrays.asList(args) : "")); + } } static void traceInterpreter(String event, Object obj) { traceInterpreter(event, obj, (Object[])null); @@ -971,8 +972,8 @@ static class NamedFunction { final MemberName member; - MethodHandle resolvedHandle; - MethodHandle invoker; + @Stable MethodHandle resolvedHandle; + @Stable MethodHandle invoker; NamedFunction(MethodHandle resolvedHandle) { this(resolvedHandle.internalMemberName(), resolvedHandle); @@ -982,6 +983,16 @@ //resolvedHandle = eraseSubwordTypes(resolvedHandle); this.resolvedHandle = resolvedHandle; } + NamedFunction(MethodType basicInvokerType) { + assert(basicInvokerType == basicInvokerType.basicType()) : basicInvokerType; + if (basicInvokerType.parameterSlotCount() < MethodType.MAX_MH_INVOKER_ARITY) { + this.resolvedHandle = basicInvokerType.invokers().basicInvoker(); + this.member = resolvedHandle.internalMemberName(); + } else { + // necessary to pass BigArityTest + this.member = Invokers.invokeBasicMethod(basicInvokerType); + } + } // The next 3 constructors are used to break circular dependencies on MH.invokeStatic, etc. // Any LambdaForm containing such a member is not interpretable. @@ -1229,7 +1240,7 @@ } public String toString() { - if (member == null) return resolvedHandle.toString(); + if (member == null) return String.valueOf(resolvedHandle); return member.getDeclaringClass().getSimpleName()+"."+member.getName(); } } @@ -1267,7 +1278,7 @@ final char type; private short index; final NamedFunction function; - final Object[] arguments; + @Stable final Object[] arguments; private Name(int index, char type, NamedFunction function, Object[] arguments) { this.index = (short)index; @@ -1279,6 +1290,10 @@ Name(MethodHandle function, Object... arguments) { this(new NamedFunction(function), arguments); } + Name(MethodType functionType, Object... arguments) { + this(new NamedFunction(functionType), arguments); + assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == 'L'); + } Name(MemberName function, Object... arguments) { this(new NamedFunction(function), arguments); } @@ -1426,8 +1441,6 @@ * Does this Name precede the given binding node in some canonical order? * This predicate is used to order data bindings (via insertion sort) * with some stability. - * @param binding - * @return */ boolean isSiblingBindingBefore(Name binding) { assert(!binding.isParam()); @@ -1622,4 +1635,12 @@ */ static { NamedFunction.initializeInvokers(); } + + // The following hack is necessary in order to suppress TRACE_INTERPRETER + // during execution of the static initializes of this class. + // Turning on TRACE_INTERPRETER too early will cause + // stack overflows and other misbehavior during attempts to trace events + // that occur during LambdaForm.. + // Therefore, do not move this line higher in this file, and do not remove. + private static final boolean TRACE_INTERPRETER = MethodHandleStatics.TRACE_INTERPRETER; } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/MemberName.java --- a/jdk/src/share/classes/java/lang/invoke/MemberName.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/MemberName.java Tue Oct 08 14:57:32 2013 -0700 @@ -70,13 +70,13 @@ * @author jrose */ /*non-public*/ final class MemberName implements Member, Cloneable { - private Class clazz; // class in which the method is defined - private String name; // may be null if not yet materialized - private Object type; // may be null if not yet materialized - private int flags; // modifier bits; see reflect.Modifier + private Class clazz; // class in which the method is defined + private String name; // may be null if not yet materialized + private Object type; // may be null if not yet materialized + private int flags; // modifier bits; see reflect.Modifier //@Injected JVM_Method* vmtarget; //@Injected int vmindex; - private Object resolution; // if null, this guy is resolved + private Object resolution; // if null, this guy is resolved /** Return the declaring class of this member. * In the case of a bare name and type, the declaring class will be null. @@ -98,7 +98,9 @@ public String getName() { if (name == null) { expandFromVM(); - if (name == null) return null; + if (name == null) { + return null; + } } return name; } @@ -119,28 +121,39 @@ public MethodType getMethodType() { if (type == null) { expandFromVM(); - if (type == null) return null; + if (type == null) { + return null; + } + } + if (!isInvocable()) { + throw newIllegalArgumentException("not invocable, no method type"); } - if (!isInvocable()) - throw newIllegalArgumentException("not invocable, no method type"); - if (type instanceof MethodType) { - return (MethodType) type; + + { + // Get a snapshot of type which doesn't get changed by racing threads. + final Object type = this.type; + if (type instanceof MethodType) { + return (MethodType) type; + } } - if (type instanceof String) { - String sig = (String) type; - MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader()); - this.type = res; - return res; + + // type is not a MethodType yet. Convert it thread-safely. + synchronized (this) { + if (type instanceof String) { + String sig = (String) type; + MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader()); + type = res; + } else if (type instanceof Object[]) { + Object[] typeInfo = (Object[]) type; + Class[] ptypes = (Class[]) typeInfo[1]; + Class rtype = (Class) typeInfo[0]; + MethodType res = MethodType.methodType(rtype, ptypes); + type = res; + } + // Make sure type is a MethodType for racing threads. + assert type instanceof MethodType : "bad method type " + type; } - if (type instanceof Object[]) { - Object[] typeInfo = (Object[]) type; - Class[] ptypes = (Class[]) typeInfo[1]; - Class rtype = (Class) typeInfo[0]; - MethodType res = MethodType.methodType(rtype, ptypes); - this.type = res; - return res; - } - throw new InternalError("bad method type "+type); + return (MethodType) type; } /** Return the actual type under which this method or constructor must be invoked. @@ -173,21 +186,34 @@ public Class getFieldType() { if (type == null) { expandFromVM(); - if (type == null) return null; + if (type == null) { + return null; + } } - if (isInvocable()) + if (isInvocable()) { throw newIllegalArgumentException("not a field or nested class, no simple type"); - if (type instanceof Class) { - return (Class) type; } - if (type instanceof String) { - String sig = (String) type; - MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader()); - Class res = mtype.returnType(); - this.type = res; - return res; + + { + // Get a snapshot of type which doesn't get changed by racing threads. + final Object type = this.type; + if (type instanceof Class) { + return (Class) type; + } } - throw new InternalError("bad field type "+type); + + // type is not a Class yet. Convert it thread-safely. + synchronized (this) { + if (type instanceof String) { + String sig = (String) type; + MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader()); + Class res = mtype.returnType(); + type = res; + } + // Make sure type is a Class for racing threads. + assert type instanceof Class : "bad field type " + type; + } + return (Class) type; } /** Utility method to produce either the method type or field type of this member. */ @@ -201,10 +227,10 @@ public String getSignature() { if (type == null) { expandFromVM(); - if (type == null) return null; + if (type == null) { + return null; + } } - if (type instanceof String) - return (String) type; if (isInvocable()) return BytecodeDescriptor.unparse(getMethodType()); else @@ -463,10 +489,17 @@ //assert(referenceKindIsConsistent()); // do this after resolution } + /** + * Calls down to the VM to fill in the fields. This method is + * synchronized to avoid racing calls. + */ private void expandFromVM() { - if (!isResolved()) return; - if (type instanceof Object[]) - type = null; // don't saddle JVM w/ typeInfo + if (type != null) { + return; + } + if (!isResolved()) { + return; + } MethodHandleNatives.expand(this); } @@ -523,6 +556,9 @@ } throw new IllegalArgumentException(this.toString()); } + /** If this MN is not REF_newInvokeSpecial, return a clone with that ref. kind. + * In that case it must already be REF_invokeSpecial. + */ public MemberName asConstructor() { switch (getReferenceKind()) { case REF_invokeSpecial: return clone().changeReferenceKind(REF_newInvokeSpecial, REF_invokeSpecial); @@ -530,6 +566,32 @@ } throw new IllegalArgumentException(this.toString()); } + /** If this MN is a REF_invokeSpecial, return a clone with the "normal" kind + * REF_invokeVirtual; also switch either to REF_invokeInterface if clazz.isInterface. + * The end result is to get a fully virtualized version of the MN. + * (Note that resolving in the JVM will sometimes devirtualize, changing + * REF_invokeVirtual of a final to REF_invokeSpecial, and REF_invokeInterface + * in some corner cases to either of the previous two; this transform + * undoes that change under the assumption that it occurred.) + */ + public MemberName asNormalOriginal() { + byte normalVirtual = clazz.isInterface() ? REF_invokeInterface : REF_invokeVirtual; + byte refKind = getReferenceKind(); + byte newRefKind = refKind; + MemberName result = this; + switch (refKind) { + case REF_invokeInterface: + case REF_invokeVirtual: + case REF_invokeSpecial: + newRefKind = normalVirtual; + break; + } + if (newRefKind == refKind) + return this; + result = clone().changeReferenceKind(newRefKind, refKind); + assert(this.referenceKindIsConsistentWith(result.getReferenceKind())); + return result; + } /** Create a name for the given reflected constructor. The resulting name will be in a resolved state. */ @SuppressWarnings("LeakingThisInConstructor") public MemberName(Constructor ctor) { @@ -627,7 +689,7 @@ @Override public int hashCode() { - return Objects.hash(clazz, flags, name, getType()); + return Objects.hash(clazz, getReferenceKind(), name, getType()); } @Override public boolean equals(Object that) { @@ -643,13 +705,14 @@ if (this == that) return true; if (that == null) return false; return this.clazz == that.clazz - && this.flags == that.flags + && this.getReferenceKind() == that.getReferenceKind() && Objects.equals(this.name, that.name) && Objects.equals(this.getType(), that.getType()); } // Construction from symbolic parts, for queries: - /** Create a field or type name from the given components: Declaring class, name, type, reference kind. + /** Create a field or type name from the given components: + * Declaring class, name, type, reference kind. * The declaring class may be supplied as null if this is to be a bare name and type. * The resulting name will in an unresolved state. */ @@ -673,21 +736,34 @@ * The resulting name will in an unresolved state. */ public MemberName(Class defClass, String name, MethodType type, byte refKind) { - @SuppressWarnings("LocalVariableHidesMemberVariable") - int flags = (name != null && name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD); - init(defClass, name, type, flagsMods(flags, 0, refKind)); + int initFlags = (name != null && name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD); + init(defClass, name, type, flagsMods(initFlags, 0, refKind)); initResolved(false); } -// /** Create a method or constructor name from the given components: Declaring class, name, type, modifiers. -// * It will be a constructor if and only if the name is {@code "<init>"}. -// * The declaring class may be supplied as null if this is to be a bare name and type. -// * The modifier flags default to zero. -// * The resulting name will in an unresolved state. -// */ -// public MemberName(Class defClass, String name, MethodType type, Void unused) { -// this(defClass, name, type, REF_NONE); -// } - + /** Create a method, constructor, or field name from the given components: + * Reference kind, declaring class, name, type. + */ + public MemberName(byte refKind, Class defClass, String name, Object type) { + int kindFlags; + if (MethodHandleNatives.refKindIsField(refKind)) { + kindFlags = IS_FIELD; + if (!(type instanceof Class)) + throw newIllegalArgumentException("not a field type"); + } else if (MethodHandleNatives.refKindIsMethod(refKind)) { + kindFlags = IS_METHOD; + if (!(type instanceof MethodType)) + throw newIllegalArgumentException("not a method type"); + } else if (refKind == REF_newInvokeSpecial) { + kindFlags = IS_CONSTRUCTOR; + if (!(type instanceof MethodType) || + !CONSTRUCTOR_NAME.equals(name)) + throw newIllegalArgumentException("not a constructor type or name"); + } else { + throw newIllegalArgumentException("bad reference kind "+refKind); + } + init(defClass, name, type, flagsMods(kindFlags, 0, refKind)); + initResolved(false); + } /** Query whether this member name is resolved to a non-static, non-final method. */ public boolean hasReceiverTypeDispatch() { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/MethodHandle.java --- a/jdk/src/share/classes/java/lang/invoke/MethodHandle.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java Tue Oct 08 14:57:32 2013 -0700 @@ -292,7 +292,7 @@ * generates a single invokevirtual instruction with * the symbolic type descriptor indicated in the following comment. * In these examples, the helper method {@code assertEquals} is assumed to - * be a method which calls {@link java.util.Objects#equals(Object,Object) Objects.equals } + * be a method which calls {@link java.util.Objects#equals(Object,Object) Objects.equals} * on its arguments, and asserts that the result is true. * *

Exceptions

@@ -392,7 +392,7 @@ * Java types. *
    *
  • Method types range over all possible arities, - * from no arguments to up to 255 of arguments (a limit imposed by the JVM). + * from no arguments to up to the maximum number of allowed arguments. * Generics are not variadic, and so cannot represent this.
  • *
  • Method types can specify arguments of primitive types, * which Java generic types cannot range over.
  • @@ -402,6 +402,22 @@ * genericity with a Java type parameter. *
* + *

Arity limits

+ * The JVM imposes on all methods and constructors of any kind an absolute + * limit of 255 stacked arguments. This limit can appear more restrictive + * in certain cases: + *
    + *
  • A {@code long} or {@code double} argument counts (for purposes of arity limits) as two argument slots. + *
  • A non-static method consumes an extra argument for the object on which the method is called. + *
  • A constructor consumes an extra argument for the object which is being constructed. + *
  • Since a method handle’s {@code invoke} method (or other signature-polymorphic method) is non-virtual, + * it consumes an extra argument for the method handle itself, in addition to any non-virtual receiver object. + *
+ * These limits imply that certain method handles cannot be created, solely because of the JVM limit on stacked arguments. + * For example, if a static JVM method accepts exactly 255 arguments, a method handle cannot be created for it. + * Attempts to create method handles with impossible method types lead to an {@link IllegalArgumentException}. + * In particular, a method handle’s type must not have an arity of the exact maximum 255. + * * @see MethodType * @see MethodHandles * @author John Rose, JSR 292 EG @@ -420,6 +436,8 @@ private final MethodType type; /*private*/ final LambdaForm form; // form is not private so that invokers can easily fetch it + /*private*/ MethodHandle asTypeCache; + // asTypeCache is not private so that invokers can easily fetch it /** * Reports the type of this method handle. @@ -557,10 +575,10 @@ /*non-public*/ static native @PolymorphicSignature Object linkToInterface(Object... args) throws Throwable; /** - * Performs a variable arity invocation, passing the arguments in the given array + * Performs a variable arity invocation, passing the arguments in the given list * to the method handle, as if via an inexact {@link #invoke invoke} from a call site * which mentions only the type {@code Object}, and whose arity is the length - * of the argument array. + * of the argument list. *

* Specifically, execution proceeds as if by the following steps, * although the methods are not guaranteed to be called if the JVM @@ -590,10 +608,10 @@ * or forced to null if the return type is void. *

* This call is equivalent to the following code: - *

+     * 

{@code
      * MethodHandle invoker = MethodHandles.spreadInvoker(this.type(), 0);
      * Object result = invoker.invokeExact(this, arguments);
-     * 
+ * }
*

* Unlike the signature polymorphic methods {@code invokeExact} and {@code invoke}, * {@code invokeWithArguments} can be accessed normally via the Core Reflection API and JNI. @@ -626,7 +644,7 @@ *

* This method is also equivalent to the following code: *

-     * {@link #invokeWithArguments(Object...) invokeWithArguments}(arguments.toArray())
+     * {@link #invokeWithArguments(Object...) invokeWithArguments}{@code(arguments.toArray())}
      * 
* * @param arguments the arguments to pass to the target @@ -739,10 +757,24 @@ * @see MethodHandles#explicitCastArguments */ public MethodHandle asType(MethodType newType) { - if (!type.isConvertibleTo(newType)) { + // Fast path alternative to a heavyweight {@code asType} call. + // Return 'this' if the conversion will be a no-op. + if (newType == type) { + return this; + } + // Return 'this.asTypeCache' if the conversion is already memoized. + MethodHandle atc = asTypeCache; + if (atc != null && newType == atc.type) { + return atc; + } + return asTypeUncached(newType); + } + + /** Override this to change asType behavior. */ + /*non-public*/ MethodHandle asTypeUncached(MethodType newType) { + if (!type.isConvertibleTo(newType)) throw new WrongMethodTypeException("cannot convert "+this+" to "+newType); - } - return convertArguments(newType); + return asTypeCache = convertArguments(newType); } /** @@ -772,6 +804,10 @@ * to the target method handle. * (The array may also be null when zero elements are required.) *

+ * If, when the adapter is called, the supplied array argument does + * not have the correct number of elements, the adapter will throw + * an {@link IllegalArgumentException} instead of invoking the target. + *

* Here are some simple examples of array-spreading method handles: *

{@code
 MethodHandle equals = publicLookup()
@@ -782,6 +818,12 @@
 MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
 assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
 assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
+// try to spread from anything but a 2-array:
+for (int n = 0; n <= 10; n++) {
+  Object[] badArityArgs = (n == 2 ? null : new Object[n]);
+  try { assert((boolean) eq2.invokeExact(badArityArgs) && false); }
+  catch (IllegalArgumentException ex) { } // OK
+}
 // spread both arguments from a String array:
 MethodHandle eq2s = equals.asSpreader(String[].class, 2);
 assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));
@@ -815,10 +857,12 @@
      * @return a new method handle which spreads its final array argument,
      *         before calling the original method handle
      * @throws NullPointerException if {@code arrayType} is a null reference
-     * @throws IllegalArgumentException if {@code arrayType} is not an array type
-     * @throws IllegalArgumentException if target does not have at least
+     * @throws IllegalArgumentException if {@code arrayType} is not an array type,
+     *         or if target does not have at least
      *         {@code arrayLength} parameter types,
-     *         or if {@code arrayLength} is negative
+     *         or if {@code arrayLength} is negative,
+     *         or if the resulting method handle's type would have
+     *         too many parameters
      * @throws WrongMethodTypeException if the implied {@code asType} call fails
      * @see #asCollector
      */
@@ -931,7 +975,9 @@
      * @throws NullPointerException if {@code arrayType} is a null reference
      * @throws IllegalArgumentException if {@code arrayType} is not an array type
      *         or {@code arrayType} is not assignable to this method handle's trailing parameter type,
-     *         or {@code arrayLength} is not a legal array size
+     *         or {@code arrayLength} is not a legal array size,
+     *         or the resulting method handle's type would have
+     *         too many parameters
      * @throws WrongMethodTypeException if the implied {@code asType} call fails
      * @see #asSpreader
      * @see #asVarargsCollector
@@ -1226,9 +1272,9 @@
      * starting with the string {@code "MethodHandle"} and
      * ending with the string representation of the method handle's type.
      * In other words, this method returns a string equal to the value of:
-     * 
+     * 
{@code
      * "MethodHandle" + type().toString()
-     * 
+ * }
*

* (Note: Future releases of this API may add further information * to the string representation. @@ -1285,6 +1331,11 @@ } /*non-public*/ + Class internalCallerClass() { + return null; // caller-bound MH for @CallerSensitive method returns caller + } + + /*non-public*/ MethodHandle withInternalMemberName(MemberName member) { if (member != null) { return MethodHandleImpl.makeWrappedMember(this, member); @@ -1434,7 +1485,6 @@ * Threads may continue running the old form indefinitely, * but it is likely that the new one will be preferred for new executions. * Use with discretion. - * @param newForm */ /*non-public*/ void updateForm(LambdaForm newForm) { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java Tue Oct 08 14:57:32 2013 -0700 @@ -314,13 +314,13 @@ static class AsVarargsCollector extends MethodHandle { private final MethodHandle target; private final Class arrayType; - private MethodHandle cache; + private /*@Stable*/ MethodHandle asCollectorCache; AsVarargsCollector(MethodHandle target, MethodType type, Class arrayType) { super(type, reinvokerForm(target)); this.target = target; this.arrayType = arrayType; - this.cache = target.asCollector(arrayType, 0); + this.asCollectorCache = target.asCollector(arrayType, 0); } @Override MethodHandle reinvokerTarget() { return target; } @@ -336,18 +336,19 @@ } @Override - public MethodHandle asType(MethodType newType) { + public MethodHandle asTypeUncached(MethodType newType) { MethodType type = this.type(); int collectArg = type.parameterCount() - 1; int newArity = newType.parameterCount(); if (newArity == collectArg+1 && type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) { // if arity and trailing parameter are compatible, do normal thing - return asFixedArity().asType(newType); + return asTypeCache = asFixedArity().asType(newType); } // check cache - if (cache.type().parameterCount() == newArity) - return cache.asType(newType); + MethodHandle acc = asCollectorCache; + if (acc != null && acc.type().parameterCount() == newArity) + return asTypeCache = acc.asType(newType); // build and cache a collector int arrayLength = newArity - collectArg; MethodHandle collector; @@ -357,8 +358,8 @@ } catch (IllegalArgumentException ex) { throw new WrongMethodTypeException("cannot build collector", ex); } - cache = collector; - return collector.asType(newType); + asCollectorCache = collector; + return asTypeCache = collector.asType(newType); } @Override @@ -380,6 +381,10 @@ MemberName internalMemberName() { return asFixedArity().internalMemberName(); } + @Override + Class internalCallerClass() { + return asFixedArity().internalCallerClass(); + } /*non-public*/ @Override @@ -435,7 +440,7 @@ // Spread the array. MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType); Name array = names[argIndex]; - names[nameCursor++] = new Name(NF_checkSpreadArgument, array, spreadArgCount); + names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount); for (int j = 0; j < spreadArgCount; i++, j++) { indexes[i] = nameCursor; names[nameCursor++] = new Name(aload, array, j); @@ -459,14 +464,8 @@ } static void checkSpreadArgument(Object av, int n) { - // FIXME: regression test for bug 7141637 erroneously expects an NPE, and other tests may expect IAE - // but the actual exception raised by an arity mismatch should be WMTE - final boolean RAISE_RANDOM_EXCEPTIONS = true; // FIXME: delete in JSR 292 M1 if (av == null) { if (n == 0) return; - int len; - if (RAISE_RANDOM_EXCEPTIONS) - len = ((Object[])av).length; // throw NPE; but delete this after tests are fixed } else if (av instanceof Object[]) { int len = ((Object[])av).length; if (len == n) return; @@ -475,19 +474,23 @@ if (len == n) return; } // fall through to error: - if (RAISE_RANDOM_EXCEPTIONS) - throw newIllegalArgumentException("Array is not of length "+n); - throw new WrongMethodTypeException("Array is not of length "+n); + throw newIllegalArgumentException("array is not of length "+n); } - private static final NamedFunction NF_checkSpreadArgument; - static { - try { - NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class - .getDeclaredMethod("checkSpreadArgument", Object.class, int.class)); - NF_checkSpreadArgument.resolve(); - } catch (ReflectiveOperationException ex) { - throw newInternalError(ex); + /** + * Pre-initialized NamedFunctions for bootstrapping purposes. + * Factored in an inner class to delay initialization until first usage. + */ + private static class Lazy { + static final NamedFunction NF_checkSpreadArgument; + static { + try { + NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class + .getDeclaredMethod("checkSpreadArgument", Object.class, int.class)); + NF_checkSpreadArgument.resolve(); + } catch (ReflectiveOperationException ex) { + throw newInternalError(ex); + } } } @@ -832,7 +835,7 @@ MethodHandle vamh = prepareForInvoker(mh); // Cache the result of makeInjectedInvoker once per argument class. MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass); - return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName()); + return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass); } private static MethodHandle makeInjectedInvoker(Class hostClass) { @@ -887,10 +890,12 @@ } // Undo the adapter effect of prepareForInvoker: - private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, MemberName member) { + private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, + MemberName member, + Class hostClass) { MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount()); mh = mh.asType(type); - mh = mh.withInternalMemberName(member); + mh = new WrappedMember(mh, type, member, hostClass); return mh; } @@ -959,11 +964,13 @@ static class WrappedMember extends MethodHandle { private final MethodHandle target; private final MemberName member; + private final Class callerClass; - private WrappedMember(MethodHandle target, MethodType type, MemberName member) { + private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class callerClass) { super(type, reinvokerForm(target)); this.target = target; this.member = member; + this.callerClass = callerClass; } @Override @@ -971,23 +978,33 @@ return target; } @Override + public MethodHandle asTypeUncached(MethodType newType) { + // This MH is an alias for target, except for the MemberName + // Drop the MemberName if there is any conversion. + return asTypeCache = target.asType(newType); + } + @Override MemberName internalMemberName() { return member; } @Override + Class internalCallerClass() { + return callerClass; + } + @Override boolean isInvokeSpecial() { return target.isInvokeSpecial(); } @Override MethodHandle viewAsType(MethodType newType) { - return new WrappedMember(target, newType, member); + return new WrappedMember(target, newType, member, callerClass); } } static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) { if (member.equals(target.internalMemberName())) return target; - return new WrappedMember(target, target.type(), member); + return new WrappedMember(target, target.type(), member, null); } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java Tue Oct 08 14:57:32 2013 -0700 @@ -32,9 +32,10 @@ import static java.lang.invoke.MethodHandleStatics.*; /** - * A symbolic reference obtained by cracking a method handle into its consitutent symbolic parts. + * A symbolic reference obtained by cracking a direct method handle + * into its consitutent symbolic parts. * To crack a direct method handle, call {@link Lookup#revealDirect Lookup.revealDirect}. - *

+ *

Direct Method Handles

* A direct method handle represents a method, constructor, or field without * any intervening argument bindings or other transformations. * The method, constructor, or field referred to by a direct method handle is called @@ -56,11 +57,25 @@ * or {@link Lookup#unreflectSetter Lookup.unreflectSetter} * to convert a {@link Field} into a method handle. * - * In all of these cases, it is possible to crack the resulting direct method handle + * + *

Restrictions on Cracking

+ * Given a suitable {@code Lookup} object, it is possible to crack any direct method handle * to recover a symbolic reference for the underlying method, constructor, or field. * Cracking must be done via a {@code Lookup} object equivalent to that which created * the target method handle, or which has enough access permissions to recreate * an equivalent method handle. + *

+ * If the underlying method is caller sensitive, + * the direct method handle will have been "bound" to a particular caller class, the + * {@linkplain java.lang.invoke.MethodHandles.Lookup#lookupClass() lookup class} + * of the lookup object used to create it. + * Cracking this method handle with a different lookup class will fail + * even if the underlying method is public (like {@code Class.forName}). + *

+ * The requirement of lookup object matching provides a "fast fail" behavior + * for programs which may otherwise trust erroneous revelation of a method + * handle with symbolic information (or caller binding) from an unexpected scope. + * Use {@link java.lang.invoke.MethodHandles#reflectAs} to override this limitation. * *

Reference kinds

* The Lookup Factory Methods @@ -190,7 +205,7 @@ * @return the Java language modifiers for underlying member, * or -1 if the member cannot be accessed * @see Modifier - * @see reflectAs + * @see #reflectAs */ public int getModifiers(); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -233,20 +233,19 @@ } static String refKindName(byte refKind) { assert(refKindIsValid(refKind)); - return REFERENCE_KIND_NAME[refKind]; + switch (refKind) { + case REF_getField: return "getField"; + case REF_getStatic: return "getStatic"; + case REF_putField: return "putField"; + case REF_putStatic: return "putStatic"; + case REF_invokeVirtual: return "invokeVirtual"; + case REF_invokeStatic: return "invokeStatic"; + case REF_invokeSpecial: return "invokeSpecial"; + case REF_newInvokeSpecial: return "newInvokeSpecial"; + case REF_invokeInterface: return "invokeInterface"; + default: return "REF_???"; + } } - private static String[] REFERENCE_KIND_NAME = { - null, - "getField", - "getStatic", - "putField", - "putStatic", - "invokeVirtual", - "invokeStatic", - "invokeSpecial", - "newInvokeSpecial", - "invokeInterface" - }; private static native int getNamedCon(int which, Object[] name); static boolean verifyConstants() { @@ -294,12 +293,18 @@ Class caller = (Class)callerObj; String name = nameObj.toString().intern(); MethodType type = (MethodType)typeObj; - appendixResult[0] = CallSite.makeSite(bootstrapMethod, + CallSite callSite = CallSite.makeSite(bootstrapMethod, name, type, staticArguments, caller); - return Invokers.linkToCallSiteMethod(type); + if (callSite instanceof ConstantCallSite) { + appendixResult[0] = callSite.dynamicInvoker(); + return Invokers.linkToTargetMethod(type); + } else { + appendixResult[0] = callSite; + return Invokers.linkToCallSiteMethod(type); + } } /** @@ -388,12 +393,7 @@ Object[] appendixResult) { try { if (defc == MethodHandle.class && refKind == REF_invokeVirtual) { - switch (name) { - case "invoke": - return Invokers.genericInvokerMethod(fixMethodType(callerClass, type), appendixResult); - case "invokeExact": - return Invokers.exactInvokerMethod(fixMethodType(callerClass, type), appendixResult); - } + return Invokers.methodHandleInvokeLinkerMethod(name, fixMethodType(callerClass, type), appendixResult); } } catch (Throwable ex) { if (ex instanceof LinkageError) @@ -440,14 +440,34 @@ Lookup lookup = IMPL_LOOKUP.in(callerClass); assert(refKindIsValid(refKind)); return lookup.linkMethodHandleConstant((byte) refKind, defc, name, type); + } catch (IllegalAccessException ex) { + Error err = new IllegalAccessError(ex.getMessage()); + throw initCauseFrom(err, ex); + } catch (NoSuchMethodException ex) { + Error err = new NoSuchMethodError(ex.getMessage()); + throw initCauseFrom(err, ex); + } catch (NoSuchFieldException ex) { + Error err = new NoSuchFieldError(ex.getMessage()); + throw initCauseFrom(err, ex); } catch (ReflectiveOperationException ex) { Error err = new IncompatibleClassChangeError(); - err.initCause(ex); - throw err; + throw initCauseFrom(err, ex); } } /** + * Use best possible cause for err.initCause(), substituting the + * cause for err itself if the cause has the same (or better) type. + */ + static private Error initCauseFrom(Error err, Exception ex) { + Throwable th = ex.getCause(); + if (err.getClass().isInstance(th)) + return (Error) th; + err.initCause(th == null ? ex : th); + return err; + } + + /** * Is this method a caller-sensitive method? * I.e., does it call Reflection.getCallerClass or a similer method * to ask about the identity of its caller? diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java Tue Oct 08 14:57:32 2013 -0700 @@ -107,6 +107,11 @@ * such as abstract classes with single abstract methods. * Future versions of this API may also equip wrapper instances * with one or more additional public "marker" interfaces. + *

+ * If a security manager is installed, this method is caller sensitive. + * During any invocation of the target method handle via the returned wrapper, + * the original creator of the wrapper (the caller) will be visible + * to context checks requested by the security manager. * * @param the desired type of the wrapper, a single-method interface * @param intfc a class object representing {@code T} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/MethodHandles.java --- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java Tue Oct 08 14:57:32 2013 -0700 @@ -39,6 +39,7 @@ import sun.security.util.SecurityConstants; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleNatives.Constants.*; +import java.util.concurrent.ConcurrentHashMap; import sun.security.util.SecurityConstants; /** @@ -48,7 +49,6 @@ *

  • Lookup methods which help create method handles for methods and fields. *
  • Combinator methods, which combine or transform pre-existing method handles into new ones. *
  • Other factory methods to create method handles that emulate other common JVM operations or control flow patterns. - *
  • Wrapper methods which can convert between method handles and interface types. * *

    * @author John Rose, JSR 292 EG @@ -65,12 +65,25 @@ //// Method handle creation from ordinary methods. /** - * Returns a {@link Lookup lookup object} on the caller, - * which has the capability to access any method handle that the caller has access to, - * including direct method handles to private fields and methods. + * Returns a {@link Lookup lookup object} with + * full capabilities to emulate all supported bytecode behaviors of the caller. + * These capabilities include private access to the caller. + * Factory methods on the lookup object can create + * direct method handles + * for any member that the caller has access to via bytecodes, + * including protected and private fields and methods. * This lookup object is a capability which may be delegated to trusted agents. * Do not store it in place where untrusted code can access it. - * @return a lookup object for the caller of this method + *

    + * This method is caller sensitive, which means that it may return different + * values to different callers. + *

    + * For any given caller class {@code C}, the lookup object returned by this call + * has equivalent capabilities to any lookup object + * supplied by the JVM to the bootstrap method of an + * invokedynamic instruction + * executing in the same caller class {@code C}. + * @return a lookup object for the caller of this method, with private access */ @CallerSensitive public static Lookup lookup() { @@ -84,11 +97,17 @@ *

    * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class} * of this lookup object will be {@link java.lang.Object}. - *

    + * + *

    + * Discussion: * The lookup class can be changed to any other class {@code C} using an expression of the form - * {@linkplain Lookup#in publicLookup().in(C.class)}. + * {@link Lookup#in publicLookup().in(C.class)}. * Since all classes have equal access to public names, * such a change would confer no new access rights. + * A public lookup object is always subject to + * security manager checks. + * Also, it cannot access + * caller sensitive methods. * @return a lookup object which is trusted minimally */ public static Lookup publicLookup() { @@ -96,7 +115,8 @@ } /** - * Performs an unchecked "crack" of a direct method handle. + * Performs an unchecked "crack" of a + * direct method handle. * The result is as if the user had obtained a lookup object capable enough * to crack the target method handle, called * {@link java.lang.invoke.MethodHandles.Lookup#revealDirect Lookup.revealDirect} @@ -149,10 +169,17 @@ *

    Lookup Factory Methods

    * The factory methods on a {@code Lookup} object correspond to all major * use cases for methods, constructors, and fields. + * Each method handle created by a factory method is the functional + * equivalent of a particular bytecode behavior. + * (Bytecode behaviors are described in section 5.4.3.5 of the Java Virtual Machine Specification.) * Here is a summary of the correspondence between these factory methods and * the behavior the resulting method handles: * - * + * + * + * + * + * * * * @@ -228,10 +255,12 @@ * In cases where the given member is of variable arity (i.e., a method or constructor) * the returned method handle will also be of {@linkplain MethodHandle#asVarargsCollector variable arity}. * In all other cases, the returned method handle will be of fixed arity. - *

    + *

    + * Discussion: * The equivalence between looked-up method handles and underlying - * class members can break down in a few ways: - *

      + * class members and bytecode behaviors + * can break down in a few ways: + *
        *
      • If {@code C} is not symbolically accessible from the lookup class's loader, * the lookup can still succeed, even when there is no equivalent * Java expression or bytecoded constant. @@ -241,9 +270,13 @@ * For example, lookups for {@code MethodHandle.invokeExact} and * {@code MethodHandle.invoke} will always succeed, regardless of requested type. *
      • If there is a security manager installed, it can forbid the lookup - * on various grounds (see below). - * By contrast, the {@code ldc} instruction is not subject to - * security manager checks. + * on various grounds (see below). + * By contrast, the {@code ldc} instruction on a {@code CONSTANT_MethodHandle} + * constant is not subject to security manager checks. + *
      • If the looked-up method has a + * very large arity, + * the method handle creation may fail, due to the method handle + * type having too many parameters. *
      * *

      Access checking

      @@ -271,7 +304,8 @@ * A lookup can fail, because * the containing class is not accessible to the lookup class, or * because the desired class member is missing, or because the - * desired class member is not accessible to the lookup class. + * desired class member is not accessible to the lookup class, or + * because the lookup object is not trusted enough to access the member. * In any of these cases, a {@code ReflectiveOperationException} will be * thrown from the attempted lookup. The exact class will be one of * the following: @@ -282,11 +316,23 @@ *
    *

    * In general, the conditions under which a method handle may be - * looked up for a method {@code M} are exactly equivalent to the conditions - * under which the lookup class could have compiled and resolved a call to {@code M}. + * looked up for a method {@code M} are no more restrictive than the conditions + * under which the lookup class could have compiled, verified, and resolved a call to {@code M}. + * Where the JVM would raise exceptions like {@code NoSuchMethodError}, + * a method handle lookup will generally raise a corresponding + * checked exception, such as {@code NoSuchMethodException}. * And the effect of invoking the method handle resulting from the lookup - * is exactly equivalent to executing the compiled and resolved call to {@code M}. + * is exactly equivalent + * to executing the compiled, verified, and resolved call to {@code M}. * The same point is true of fields and constructors. + *

    + * Discussion: + * Access checks only apply to named and reflected methods, + * constructors, and fields. + * Other method handle creation methods, such as + * {@link MethodHandle#asType MethodHandle.asType}, + * do not require any access checks, and are used + * independently of any {@code Lookup} object. *

    * If the desired member is {@code protected}, the usual JVM rules apply, * including the requirement that the lookup class must be either be in the @@ -300,6 +346,18 @@ * (which will necessarily be a superclass of the lookup class) * to the lookup class itself. *

    + * The JVM imposes a similar requirement on {@code invokespecial} instruction, + * that the receiver argument must match both the resolved method and + * the current class. Again, this requirement is enforced by narrowing the + * type of the leading parameter to the resulting method handle. + * (See the Java Virtual Machine Specification, section 4.10.1.9.) + *

    + * The JVM represents constructors and static initializer blocks as internal methods + * with special names ({@code ""} and {@code ""}). + * The internal syntax of invocation instructions allows them to refer to such internal + * methods as if they were normal methods, but the JVM bytecode verifier rejects them. + * A lookup of such an internal method will produce a {@code NoSuchMethodException}. + *

    * In some cases, access between nested classes is obtained by the Java compiler by creating * an wrapper method to access a private method of another class * in the same top-level declaration. @@ -313,6 +371,43 @@ * which can transform a lookup on {@code C.E} into one on any of those other * classes, without special elevation of privilege. *

    + * The accesses permitted to a given lookup object may be limited, + * according to its set of {@link #lookupModes lookupModes}, + * to a subset of members normally accessible to the lookup class. + * For example, the {@link MethodHandles#publicLookup publicLookup} + * method produces a lookup object which is only allowed to access + * public members in public classes. + * The caller sensitive method {@link MethodHandles#lookup lookup} + * produces a lookup object with full capabilities relative to + * its caller class, to emulate all supported bytecode behaviors. + * Also, the {@link Lookup#in Lookup.in} method may produce a lookup object + * with fewer access modes than the original lookup object. + * + *

    + * + * Discussion of private access: + * We say that a lookup has private access + * if its {@linkplain #lookupModes lookup modes} + * include the possibility of accessing {@code private} members. + * As documented in the relevant methods elsewhere, + * only lookups with private access possess the following capabilities: + *

      + *
    • access private fields, methods, and constructors of the lookup class + *
    • create method handles which invoke caller sensitive methods, + * such as {@code Class.forName} + *
    • create method handles which {@link Lookup#findSpecial emulate invokespecial} instructions + *
    • avoid package access checks + * for classes accessible to the lookup class + *
    • create {@link Lookup#in delegated lookup objects} which have private access to other classes + * within the same package member + *
    + *

    + * Each of these permissions is a consequence of the fact that a lookup object + * with private access can be securely traced back to an originating class, + * whose bytecode behaviors and Java language access permissions + * can be reliably determined and emulated by method handles. + * + *

    Security manager interactions

    * Although bytecode instructions can only refer to classes in * a related class loader, this API can search for methods in any * class, as long as a reference to its {@code Class} object is @@ -325,16 +420,6 @@ * and the Core Reflection API * (as found on {@link java.lang.Class Class}). *

    - * Access checks only apply to named and reflected methods, - * constructors, and fields. - * Other method handle creation methods, such as - * {@link MethodHandle#asType MethodHandle.asType}, - * do not require any access checks, and are done - * with static methods of {@link MethodHandles}, - * independently of any {@code Lookup} object. - * - *

    Security manager interactions

    - * * If a security manager is present, member lookups are subject to * additional checks. * From one to three calls are made to the security manager. @@ -347,26 +432,79 @@ * member is actually defined. * The value {@code lookc} is defined as not present * if the current lookup object does not have - * {@linkplain java.lang.invoke.MethodHandles.Lookup#PRIVATE private access}. + * private access. * The calls are made according to the following rules: *
      - *
    • If {@code lookc} is not present, or if its class loader is not + *
    • Step 1: + * If {@code lookc} is not present, or if its class loader is not * the same as or an ancestor of the class loader of {@code refc}, * then {@link SecurityManager#checkPackageAccess * smgr.checkPackageAccess(refcPkg)} is called, * where {@code refcPkg} is the package of {@code refc}. - *
    • If the retrieved member is not public and + *
    • Step 2: + * If the retrieved member is not public and * {@code lookc} is not present, then * {@link SecurityManager#checkPermission smgr.checkPermission} * with {@code RuntimePermission("accessDeclaredMembers")} is called. - *
    • If the retrieved member is not public, + *
    • Step 3: + * If the retrieved member is not public, + * and if {@code lookc} is not present, * and if {@code defc} and {@code refc} are different, * then {@link SecurityManager#checkPackageAccess * smgr.checkPackageAccess(defcPkg)} is called, * where {@code defcPkg} is the package of {@code defc}. *
    + * Security checks are performed after other access checks have passed. + * Therefore, the above rules presuppose a member that is public, + * or else that is being accessed from a lookup class that has + * rights to access the member. + * + *

    Caller sensitive methods

    + * A small number of Java methods have a special property called caller sensitivity. + * A caller-sensitive method can behave differently depending on the + * identity of its immediate caller. + *

    + * If a method handle for a caller-sensitive method is requested, + * the general rules for bytecode behaviors apply, + * but they take account of the lookup class in a special way. + * The resulting method handle behaves as if it were called + * from an instruction contained in the lookup class, + * so that the caller-sensitive method detects the lookup class. + * (By contrast, the invoker of the method handle is disregarded.) + * Thus, in the case of caller-sensitive methods, + * different lookup classes may give rise to + * differently behaving method handles. + *

    + * In cases where the lookup object is + * {@link MethodHandles#publicLookup() publicLookup()}, + * or some other lookup object without + * private access, + * the lookup class is disregarded. + * In such cases, no caller-sensitive method handle can be created, + * access is forbidden, and the lookup fails with an + * {@code IllegalAccessException}. + *

    + * Discussion: + * For example, the caller-sensitive method + * {@link java.lang.Class#forName(String) Class.forName(x)} + * can return varying classes or throw varying exceptions, + * depending on the class loader of the class that calls it. + * A public lookup of {@code Class.forName} will fail, because + * there is no reasonable way to determine its bytecode behavior. + *

    + * If an application caches method handles for broad sharing, + * it should use {@code publicLookup()} to create them. + * If there is a lookup of {@code Class.forName}, it will fail, + * and the application must take appropriate action in that case. + * It may be that a later lookup, perhaps during the invocation of a + * bootstrap method, can incorporate the specific identity + * of the caller, making the method accessible. + *

    + * The function {@code MethodHandles.lookup} is caller sensitive + * so that there can be a secure foundation for lookups. + * Nearly all other methods in the JSR 292 API rely on lookup + * objects to check access requests. */ - // FIXME in MR1: clarify that the bytecode behavior of a caller-ID method (like Class.forName) is relative to the lookupClass used to create the method handle, not the dynamic caller of the method handle public static final class Lookup { /** The class on behalf of whom the lookup is being performed. */ @@ -592,13 +730,23 @@ * (Since static methods do not take receivers, there is no * additional receiver argument inserted into the method handle type, * as there would be with {@link #findVirtual findVirtual} or {@link #findSpecial findSpecial}.) - * The method and all its argument types must be accessible to the lookup class. - * If the method's class has not yet been initialized, that is done - * immediately, before the method handle is returned. + * The method and all its argument types must be accessible to the lookup object. *

    * The returned method handle will have * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if * the method's variable arity modifier bit ({@code 0x0080}) is set. + *

    + * If the returned method handle is invoked, the method's class will + * be initialized, if it has not already been initialized. + *

    Example: + *

    {@code
    +import static java.lang.invoke.MethodHandles.*;
    +import static java.lang.invoke.MethodType.*;
    +...
    +MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,
    +  "asList", methodType(List.class, Object[].class));
    +assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
    +         * }
    * @param refc the class from which the method is accessed * @param name the name of the method * @param type the type of the method @@ -615,7 +763,6 @@ public MethodHandle findStatic(Class refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type); - checkSecurityManager(refc, method); return getDirectMethod(REF_invokeStatic, refc, method, findBoundCallerClass(method)); } @@ -623,7 +770,7 @@ * Produces a method handle for a virtual method. * The type of the method handle will be that of the method, * with the receiver type (usually {@code refc}) prepended. - * The method and all its argument types must be accessible to the lookup class. + * The method and all its argument types must be accessible to the lookup object. *

    * When called, the handle will treat the first argument as a receiver * and dispatch on the receiver's type to determine which method @@ -640,7 +787,7 @@ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if * the method's variable arity modifier bit ({@code 0x0080}) is set. *

    - * Because of the general equivalence between {@code invokevirtual} + * Because of the general equivalence between {@code invokevirtual} * instructions and method handles produced by {@code findVirtual}, * if the class is {@code MethodHandle} and the name string is * {@code invokeExact} or {@code invoke}, the resulting @@ -649,6 +796,34 @@ * {@link java.lang.invoke.MethodHandles#invoker MethodHandles.invoker} * with the same {@code type} argument. * + * Example: + *

    {@code
    +import static java.lang.invoke.MethodHandles.*;
    +import static java.lang.invoke.MethodType.*;
    +...
    +MethodHandle MH_concat = publicLookup().findVirtual(String.class,
    +  "concat", methodType(String.class, String.class));
    +MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class,
    +  "hashCode", methodType(int.class));
    +MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class,
    +  "hashCode", methodType(int.class));
    +assertEquals("xy", (String) MH_concat.invokeExact("x", "y"));
    +assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy"));
    +assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy"));
    +// interface method:
    +MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class,
    +  "subSequence", methodType(CharSequence.class, int.class, int.class));
    +assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString());
    +// constructor "internal method" must be accessed differently:
    +MethodType MT_newString = methodType(void.class); //()V for new String()
    +try { assertEquals("impossible", lookup()
    +        .findVirtual(String.class, "", MT_newString));
    + } catch (NoSuchMethodException ex) { } // OK
    +MethodHandle MH_newString = publicLookup()
    +  .findConstructor(String.class, MT_newString);
    +assertEquals("", (String) MH_newString.invokeExact());
    +         * }
    + * * @param refc the class or interface from which the method is accessed * @param name the name of the method * @param type the type of the method, with the receiver argument omitted @@ -669,7 +844,6 @@ } byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual); MemberName method = resolveOrFail(refKind, refc, name, type); - checkSecurityManager(refc, method); return getDirectMethod(refKind, refc, method, findBoundCallerClass(method)); } private MethodHandle findVirtualForMH(String name, MethodType type) { @@ -687,16 +861,35 @@ * the constructor of the specified type. * The parameter types of the method handle will be those of the constructor, * while the return type will be a reference to the constructor's class. - * The constructor and all its argument types must be accessible to the lookup class. - * If the constructor's class has not yet been initialized, that is done - * immediately, before the method handle is returned. + * The constructor and all its argument types must be accessible to the lookup object. *

    - * Note: The requested type must have a return type of {@code void}. - * This is consistent with the JVM's treatment of constructor type descriptors. + * The requested type must have a return type of {@code void}. + * (This is consistent with the JVM's treatment of constructor type descriptors.) *

    * The returned method handle will have * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if * the constructor's variable arity modifier bit ({@code 0x0080}) is set. + *

    + * If the returned method handle is invoked, the constructor's class will + * be initialized, if it has not already been initialized. + *

    Example: + *

    {@code
    +import static java.lang.invoke.MethodHandles.*;
    +import static java.lang.invoke.MethodType.*;
    +...
    +MethodHandle MH_newArrayList = publicLookup().findConstructor(
    +  ArrayList.class, methodType(void.class, Collection.class));
    +Collection orig = Arrays.asList("x", "y");
    +Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
    +assert(orig != copy);
    +assertEquals(orig, copy);
    +// a variable-arity constructor:
    +MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
    +  ProcessBuilder.class, methodType(void.class, String[].class));
    +ProcessBuilder pb = (ProcessBuilder)
    +  MH_newProcessBuilder.invoke("x", "y", "z");
    +assertEquals("[x, y, z]", pb.command().toString());
    +         * }
    * @param refc the class or interface from which the method is accessed * @param type the type of the method, with the receiver argument omitted, and a void return type * @return the desired method handle @@ -711,31 +904,68 @@ public MethodHandle findConstructor(Class refc, MethodType type) throws NoSuchMethodException, IllegalAccessException { String name = ""; MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type); - checkSecurityManager(refc, ctor); return getDirectConstructor(refc, ctor); } /** - * Produces an early-bound method handle for a virtual method, - * as if called from an {@code invokespecial} - * instruction from {@code caller}. + * Produces an early-bound method handle for a virtual method. + * It will bypass checks for overriding methods on the receiver, + * as if called from an {@code invokespecial} + * instruction from within the explicitly specified {@code specialCaller}. * The type of the method handle will be that of the method, - * with a suitably restricted receiver type (such as {@code caller}) prepended. + * with a suitably restricted receiver type prepended. + * (The receiver type will be {@code specialCaller} or a subtype.) * The method and all its argument types must be accessible - * to the caller. + * to the lookup object. *

    - * When called, the handle will treat the first argument as a receiver, - * but will not dispatch on the receiver's type. - * (This direct invocation action is identical with that performed by an - * {@code invokespecial} instruction.) - *

    - * If the explicitly specified caller class is not identical with the - * lookup class, or if this lookup object does not have private access + * Before method resolution, + * if the explicitly specified caller class is not identical with the + * lookup class, or if this lookup object does not have + * private access * privileges, the access fails. *

    * The returned method handle will have * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if * the method's variable arity modifier bit ({@code 0x0080}) is set. + *

    + * (Note: JVM internal methods named {@code ""} are not visible to this API, + * even though the {@code invokespecial} instruction can refer to them + * in special circumstances. Use {@link #findConstructor findConstructor} + * to access instance initialization methods in a safe manner.) + *

    Example: + *

    {@code
    +import static java.lang.invoke.MethodHandles.*;
    +import static java.lang.invoke.MethodType.*;
    +...
    +static class Listie extends ArrayList {
    +  public String toString() { return "[wee Listie]"; }
    +  static Lookup lookup() { return MethodHandles.lookup(); }
    +}
    +...
    +// no access to constructor via invokeSpecial:
    +MethodHandle MH_newListie = Listie.lookup()
    +  .findConstructor(Listie.class, methodType(void.class));
    +Listie l = (Listie) MH_newListie.invokeExact();
    +try { assertEquals("impossible", Listie.lookup().findSpecial(
    +        Listie.class, "", methodType(void.class), Listie.class));
    + } catch (NoSuchMethodException ex) { } // OK
    +// access to super and self methods via invokeSpecial:
    +MethodHandle MH_super = Listie.lookup().findSpecial(
    +  ArrayList.class, "toString" , methodType(String.class), Listie.class);
    +MethodHandle MH_this = Listie.lookup().findSpecial(
    +  Listie.class, "toString" , methodType(String.class), Listie.class);
    +MethodHandle MH_duper = Listie.lookup().findSpecial(
    +  Object.class, "toString" , methodType(String.class), Listie.class);
    +assertEquals("[]", (String) MH_super.invokeExact(l));
    +assertEquals(""+l, (String) MH_this.invokeExact(l));
    +assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method
    +try { assertEquals("inaccessible", Listie.lookup().findSpecial(
    +        String.class, "toString", methodType(String.class), Listie.class));
    + } catch (IllegalAccessException ex) { } // OK
    +Listie subl = new Listie() { public String toString() { return "[subclass]"; } };
    +assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
    +         * }
    + * * @param refc the class or interface from which the method is accessed * @param name the name of the method (which must not be "<init>") * @param type the type of the method, with the receiver argument omitted @@ -754,7 +984,6 @@ checkSpecialCaller(specialCaller); Lookup specialLookup = this.in(specialCaller); MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type); - checkSecurityManager(refc, method); return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, findBoundCallerClass(method)); } @@ -777,7 +1006,6 @@ */ public MethodHandle findGetter(Class refc, String name, Class type) throws NoSuchFieldException, IllegalAccessException { MemberName field = resolveOrFail(REF_getField, refc, name, type); - checkSecurityManager(refc, field); return getDirectField(REF_getField, refc, field); } @@ -800,7 +1028,6 @@ */ public MethodHandle findSetter(Class refc, String name, Class type) throws NoSuchFieldException, IllegalAccessException { MemberName field = resolveOrFail(REF_putField, refc, name, type); - checkSecurityManager(refc, field); return getDirectField(REF_putField, refc, field); } @@ -810,6 +1037,9 @@ * value type. * The method handle will take no arguments. * Access checking is performed immediately on behalf of the lookup class. + *

    + * If the returned method handle is invoked, the field's class will + * be initialized, if it has not already been initialized. * @param refc the class or interface from which the method is accessed * @param name the field's name * @param type the field's type @@ -822,7 +1052,6 @@ */ public MethodHandle findStaticGetter(Class refc, String name, Class type) throws NoSuchFieldException, IllegalAccessException { MemberName field = resolveOrFail(REF_getStatic, refc, name, type); - checkSecurityManager(refc, field); return getDirectField(REF_getStatic, refc, field); } @@ -832,6 +1061,9 @@ * The method handle will take a single * argument, of the field's value type, the value to be stored. * Access checking is performed immediately on behalf of the lookup class. + *

    + * If the returned method handle is invoked, the field's class will + * be initialized, if it has not already been initialized. * @param refc the class or interface from which the method is accessed * @param name the field's name * @param type the field's type @@ -844,7 +1076,6 @@ */ public MethodHandle findStaticSetter(Class refc, String name, Class type) throws NoSuchFieldException, IllegalAccessException { MemberName field = resolveOrFail(REF_putStatic, refc, name, type); - checkSecurityManager(refc, field); return getDirectField(REF_putStatic, refc, field); } @@ -852,7 +1083,7 @@ * Produces an early-bound method handle for a non-static method. * The receiver must have a supertype {@code defc} in which a method * of the given name and type is accessible to the lookup class. - * The method and all its argument types must be accessible to the lookup class. + * The method and all its argument types must be accessible to the lookup object. * The type of the method handle will be that of the method, * without any insertion of an additional receiver parameter. * The given receiver will be bound into the method handle, @@ -867,17 +1098,17 @@ * the given receiver value will be bound to it.) *

    * This is equivalent to the following code: - *

    +         * 
    {@code
     import static java.lang.invoke.MethodHandles.*;
     import static java.lang.invoke.MethodType.*;
     ...
    -MethodHandle mh0 = lookup().{@link #findVirtual findVirtual}(defc, name, type);
    -MethodHandle mh1 = mh0.{@link MethodHandle#bindTo bindTo}(receiver);
    +MethodHandle mh0 = lookup().findVirtual(defc, name, type);
    +MethodHandle mh1 = mh0.bindTo(receiver);
     MethodType mt1 = mh1.type();
     if (mh0.isVarargsCollector())
       mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1));
     return mh1;
    -         * 
    + * }
    * where {@code defc} is either {@code receiver.getClass()} or a super * type of that class, in which the requested method is accessible * to the lookup class. @@ -893,17 +1124,19 @@ * @exception SecurityException if a security manager is present and it * refuses access * @throws NullPointerException if any argument is null + * @see MethodHandle#bindTo + * @see #findVirtual */ public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { Class refc = receiver.getClass(); // may get NPE MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type); - checkSecurityManager(refc, method); MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, findBoundCallerClass(method)); return mh.bindReceiver(receiver).setVarargs(method); } /** - * Makes a direct method handle to m, if the lookup class has permission. + * Makes a direct method handle + * to m, if the lookup class has permission. * If m is non-static, the receiver argument is treated as an initial argument. * If m is virtual, overriding is respected on every call. * Unlike the Core Reflection API, exceptions are not wrapped. @@ -916,6 +1149,10 @@ * The returned method handle will have * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if * the method's variable arity modifier bit ({@code 0x0080}) is set. + *

    + * If m is static, and + * if the returned method handle is invoked, the method's class will + * be initialized, if it has not already been initialized. * @param m the reflected method * @return a method handle which can invoke the reflected method * @throws IllegalAccessException if access checking fails @@ -934,7 +1171,7 @@ refKind = REF_invokeVirtual; assert(method.isMethod()); Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this; - return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method)); + return lookup.getDirectMethodNoSecurityManager(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method)); } private MethodHandle unreflectForMH(Method m) { // these names require special lookups because they throw UnsupportedOperationException @@ -946,13 +1183,21 @@ /** * Produces a method handle for a reflected method. * It will bypass checks for overriding methods on the receiver, - * as if by a {@code invokespecial} instruction from within the {@code specialCaller}. + * as if called from an {@code invokespecial} + * instruction from within the explicitly specified {@code specialCaller}. * The type of the method handle will be that of the method, - * with the special caller type prepended (and not the receiver of the method). + * with a suitably restricted receiver type prepended. + * (The receiver type will be {@code specialCaller} or a subtype.) * If the method's {@code accessible} flag is not set, * access checking is performed immediately on behalf of the lookup class, * as if {@code invokespecial} instruction were being linked. *

    + * Before method resolution, + * if the explicitly specified caller class is not identical with the + * lookup class, or if this lookup object does not have + * private access + * privileges, the access fails. + *

    * The returned method handle will have * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if * the method's variable arity modifier bit ({@code 0x0080}) is set. @@ -970,7 +1215,7 @@ MemberName method = new MemberName(m, true); assert(method.isMethod()); // ignore m.isAccessible: this is a new kind of access - return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, findBoundCallerClass(method)); + return specialLookup.getDirectMethodNoSecurityManager(REF_invokeSpecial, method.getDeclaringClass(), method, findBoundCallerClass(method)); } /** @@ -987,6 +1232,9 @@ * The returned method handle will have * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if * the constructor's variable arity modifier bit ({@code 0x0080}) is set. + *

    + * If the returned method handle is invoked, the constructor's class will + * be initialized, if it has not already been initialized. * @param c the reflected constructor * @return a method handle which can invoke the reflected constructor * @throws IllegalAccessException if access checking fails @@ -994,12 +1242,11 @@ * is set and {@code asVarargsCollector} fails * @throws NullPointerException if the argument is null */ - @SuppressWarnings("rawtypes") // Will be Constructor after JSR 292 MR - public MethodHandle unreflectConstructor(Constructor c) throws IllegalAccessException { + public MethodHandle unreflectConstructor(Constructor c) throws IllegalAccessException { MemberName ctor = new MemberName(c); assert(ctor.isConstructor()); Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this; - return lookup.getDirectConstructor(ctor.getDeclaringClass(), ctor); + return lookup.getDirectConstructorNoSecurityManager(ctor.getDeclaringClass(), ctor); } /** @@ -1011,6 +1258,10 @@ * the field. * If the field's {@code accessible} flag is not set, * access checking is performed immediately on behalf of the lookup class. + *

    + * If the field is static, and + * if the returned method handle is invoked, the field's class will + * be initialized, if it has not already been initialized. * @param f the reflected field * @return a method handle which can load values from the reflected field * @throws IllegalAccessException if access checking fails @@ -1025,7 +1276,7 @@ ? MethodHandleNatives.refKindIsSetter(field.getReferenceKind()) : MethodHandleNatives.refKindIsGetter(field.getReferenceKind())); Lookup lookup = f.isAccessible() ? IMPL_LOOKUP : this; - return lookup.getDirectField(field.getReferenceKind(), f.getDeclaringClass(), field); + return lookup.getDirectFieldNoSecurityManager(field.getReferenceKind(), f.getDeclaringClass(), field); } /** @@ -1037,6 +1288,10 @@ * the field, and the value to be stored. * If the field's {@code accessible} flag is not set, * access checking is performed immediately on behalf of the lookup class. + *

    + * If the field is static, and + * if the returned method handle is invoked, the field's class will + * be initialized, if it has not already been initialized. * @param f the reflected field * @return a method handle which can store values into the reflected field * @throws IllegalAccessException if access checking fails @@ -1047,17 +1302,21 @@ } /** - * Cracks a direct method handle created by this lookup object or a similar one. + * Cracks a direct method handle + * created by this lookup object or a similar one. * Security and access checks are performed to ensure that this lookup object * is capable of reproducing the target method handle. * This means that the cracking may fail if target is a direct method handle * but was created by an unrelated lookup object. + * This can happen if the method handle is caller sensitive + * and was created by a lookup object for a different class. * @param target a direct method handle to crack into symbolic reference components * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object * @exception SecurityException if a security manager is present and it * refuses access * @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails * @exception NullPointerException if the target is {@code null} + * @see MethodHandleInfo * @since 1.8 */ public MethodHandleInfo revealDirect(MethodHandle target) { @@ -1077,11 +1336,16 @@ refKind = REF_invokeInterface; // Check SM permissions and member access before cracking. try { + checkAccess(refKind, defc, member); checkSecurityManager(defc, member); - checkAccess(refKind, defc, member); } catch (IllegalAccessException ex) { throw new IllegalArgumentException(ex); } + if (allowedModes != TRUSTED && member.isCallerSensitive()) { + Class callerClass = target.internalCallerClass(); + if (!hasPrivateAccess() || callerClass != lookupClass()) + throw new IllegalArgumentException("method handle is caller sensitive: "+callerClass); + } // Produce the handle to the results. return new InfoFromMemberName(this, member, refKind); } @@ -1090,24 +1354,43 @@ MemberName resolveOrFail(byte refKind, Class refc, String name, Class type) throws NoSuchFieldException, IllegalAccessException { checkSymbolicClass(refc); // do this before attempting to resolve - name.getClass(); type.getClass(); // NPE + name.getClass(); // NPE + type.getClass(); // NPE return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(), NoSuchFieldException.class); } MemberName resolveOrFail(byte refKind, Class refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { checkSymbolicClass(refc); // do this before attempting to resolve - name.getClass(); type.getClass(); // NPE + name.getClass(); // NPE + type.getClass(); // NPE + checkMethodName(refKind, name); // NPE check on name return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(), NoSuchMethodException.class); } + MemberName resolveOrFail(byte refKind, MemberName member) throws ReflectiveOperationException { + checkSymbolicClass(member.getDeclaringClass()); // do this before attempting to resolve + member.getName().getClass(); // NPE + member.getType().getClass(); // NPE + return IMPL_NAMES.resolveOrFail(refKind, member, lookupClassOrNull(), + ReflectiveOperationException.class); + } + void checkSymbolicClass(Class refc) throws IllegalAccessException { + refc.getClass(); // NPE Class caller = lookupClassOrNull(); if (caller != null && !VerifyAccess.isClassAccessible(refc, caller, allowedModes)) throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this); } + /** Check name for an illegal leading "<" character. */ + void checkMethodName(byte refKind, String name) throws NoSuchMethodException { + if (name.startsWith("<") && refKind != REF_newInvokeSpecial) + throw new NoSuchMethodException("illegal method name: "+name); + } + + /** * Find my trustable caller class if m is a caller sensitive method. * If this lookup object has private access, then the caller class is the lookupClass. @@ -1116,8 +1399,8 @@ Class findBoundCallerClass(MemberName m) throws IllegalAccessException { Class callerClass = null; if (MethodHandleNatives.isCallerSensitive(m)) { - // Only full-power lookup is allowed to resolve caller-sensitive methods - if (isFullPowerLookup()) { + // Only lookups with private access are allowed to resolve caller-sensitive methods + if (hasPrivateAccess()) { callerClass = lookupClass; } else { throw new IllegalAccessException("Attempt to lookup caller-sensitive method using restricted lookup object"); @@ -1126,7 +1409,7 @@ return callerClass; } - private boolean isFullPowerLookup() { + private boolean hasPrivateAccess() { return (allowedModes & PRIVATE) != 0; } @@ -1141,22 +1424,21 @@ if (allowedModes == TRUSTED) return; // Step 1: - if (!isFullPowerLookup() || + boolean fullPowerLookup = hasPrivateAccess(); + if (!fullPowerLookup || !VerifyAccess.classLoaderIsAncestor(lookupClass, refc)) { ReflectUtil.checkPackageAccess(refc); } // Step 2: if (m.isPublic()) return; - Class defc = m.getDeclaringClass(); - { - if (!isFullPowerLookup()) { - smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION); - } + if (!fullPowerLookup) { + smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION); } // Step 3: - if (defc != refc) { + Class defc = m.getDeclaringClass(); + if (!fullPowerLookup && defc != refc) { ReflectUtil.checkPackageAccess(defc); } } @@ -1185,6 +1467,7 @@ throw m.makeAccessException(message, this); } + /** Check public/protected/private bits on the symbolic reference class and its member. */ void checkAccess(byte refKind, Class refc, MemberName m) throws IllegalAccessException { assert(m.referenceKindIsConsistentWith(refKind) && MethodHandleNatives.refKindIsValid(refKind) && @@ -1192,6 +1475,26 @@ int allowedModes = this.allowedModes; if (allowedModes == TRUSTED) return; int mods = m.getModifiers(); + if (Modifier.isProtected(mods) && + refKind == REF_invokeVirtual && + m.getDeclaringClass() == Object.class && + m.getName().equals("clone") && + refc.isArray()) { + // The JVM does this hack also. + // (See ClassVerifier::verify_invoke_instructions + // and LinkResolver::check_method_accessability.) + // Because the JVM does not allow separate methods on array types, + // there is no separate method for int[].clone. + // All arrays simply inherit Object.clone. + // But for access checking logic, we make Object.clone + // (normally protected) appear to be public. + // Later on, when the DirectMethodHandle is created, + // its leading argument will be restricted to the + // requested array type. + // N.B. The return type is not adjusted, because + // that is *not* the bytecode behavior. + mods ^= Modifier.PROTECTED | Modifier.PUBLIC; + } if (Modifier.isFinal(mods) && MethodHandleNatives.refKindIsSetter(refKind)) throw m.makeAccessException("unexpected set of a final field", this); @@ -1239,7 +1542,7 @@ private void checkSpecialCaller(Class specialCaller) throws IllegalAccessException { int allowedModes = this.allowedModes; if (allowedModes == TRUSTED) return; - if ((allowedModes & PRIVATE) == 0 + if (!hasPrivateAccess() || (specialCaller != lookupClass() && !(ALLOW_NESTMATE_ACCESS && VerifyAccess.isSamePackageMember(specialCaller, lookupClass())))) @@ -1271,18 +1574,32 @@ return mh.viewAsType(narrowType); } + /** Check access and get the requested method. */ private MethodHandle getDirectMethod(byte refKind, Class refc, MemberName method, Class callerClass) throws IllegalAccessException { - return getDirectMethodCommon(refKind, refc, method, - (refKind == REF_invokeSpecial || - (MethodHandleNatives.refKindHasReceiver(refKind) && - restrictProtectedReceiver(method))), callerClass); + final boolean doRestrict = true; + final boolean checkSecurity = true; + return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass); + } + /** Check access and get the requested method, eliding receiver narrowing rules. */ + private MethodHandle getDirectMethodNoRestrict(byte refKind, Class refc, MemberName method, Class callerClass) throws IllegalAccessException { + final boolean doRestrict = false; + final boolean checkSecurity = true; + return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass); } - private MethodHandle getDirectMethodNoRestrict(byte refKind, Class refc, MemberName method, Class callerClass) throws IllegalAccessException { - return getDirectMethodCommon(refKind, refc, method, false, callerClass); + /** Check access and get the requested method, eliding security manager checks. */ + private MethodHandle getDirectMethodNoSecurityManager(byte refKind, Class refc, MemberName method, Class callerClass) throws IllegalAccessException { + final boolean doRestrict = true; + final boolean checkSecurity = false; // not needed for reflection or for linking CONSTANT_MH constants + return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass); } + /** Common code for all methods; do not call directly except from immediately above. */ private MethodHandle getDirectMethodCommon(byte refKind, Class refc, MemberName method, + boolean checkSecurity, boolean doRestrict, Class callerClass) throws IllegalAccessException { checkMethod(refKind, refc, method); + // Optionally check with the security manager; this isn't needed for unreflect* calls. + if (checkSecurity) + checkSecurityManager(refc, method); assert(!method.isMethodHandleInvoke()); Class refcAsSuper; @@ -1312,7 +1629,11 @@ MethodHandle mh = DirectMethodHandle.make(refKind, refc, method); mh = maybeBindCaller(method, mh, callerClass); mh = mh.setVarargs(method); - if (doRestrict) + // Optionally narrow the receiver argument to refc using restrictReceiver. + if (doRestrict && + (refKind == REF_invokeSpecial || + (MethodHandleNatives.refKindHasReceiver(refKind) && + restrictProtectedReceiver(method)))) mh = restrictReceiver(method, mh, lookupClass()); return mh; } @@ -1322,14 +1643,29 @@ if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method)) return mh; Class hostClass = lookupClass; - if ((allowedModes & PRIVATE) == 0) // caller must use full-power lookup + if (!hasPrivateAccess()) // caller must have private access hostClass = callerClass; // callerClass came from a security manager style stack walk MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass); // Note: caller will apply varargs after this step happens. return cbmh; } + /** Check access and get the requested field. */ private MethodHandle getDirectField(byte refKind, Class refc, MemberName field) throws IllegalAccessException { + final boolean checkSecurity = true; + return getDirectFieldCommon(refKind, refc, field, checkSecurity); + } + /** Check access and get the requested field, eliding security manager checks. */ + private MethodHandle getDirectFieldNoSecurityManager(byte refKind, Class refc, MemberName field) throws IllegalAccessException { + final boolean checkSecurity = false; // not needed for reflection or for linking CONSTANT_MH constants + return getDirectFieldCommon(refKind, refc, field, checkSecurity); + } + /** Common code for all fields; do not call directly except from immediately above. */ + private MethodHandle getDirectFieldCommon(byte refKind, Class refc, MemberName field, + boolean checkSecurity) throws IllegalAccessException { checkField(refKind, refc, field); + // Optionally check with the security manager; this isn't needed for unreflect* calls. + if (checkSecurity) + checkSecurityManager(refc, field); MethodHandle mh = DirectMethodHandle.make(refc, field); boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) && restrictProtectedReceiver(field)); @@ -1337,9 +1673,24 @@ mh = restrictReceiver(field, mh, lookupClass()); return mh; } + /** Check access and get the requested constructor. */ private MethodHandle getDirectConstructor(Class refc, MemberName ctor) throws IllegalAccessException { + final boolean checkSecurity = true; + return getDirectConstructorCommon(refc, ctor, checkSecurity); + } + /** Check access and get the requested constructor, eliding security manager checks. */ + private MethodHandle getDirectConstructorNoSecurityManager(Class refc, MemberName ctor) throws IllegalAccessException { + final boolean checkSecurity = false; // not needed for reflection or for linking CONSTANT_MH constants + return getDirectConstructorCommon(refc, ctor, checkSecurity); + } + /** Common code for all constructors; do not call directly except from immediately above. */ + private MethodHandle getDirectConstructorCommon(Class refc, MemberName ctor, + boolean checkSecurity) throws IllegalAccessException { assert(ctor.isConstructor()); checkAccess(REF_newInvokeSpecial, refc, ctor); + // Optionally check with the security manager; this isn't needed for unreflect* calls. + if (checkSecurity) + checkSecurityManager(refc, ctor); assert(!MethodHandleNatives.isCallerSensitive(ctor)); // maybeBindCaller not relevant here return DirectMethodHandle.make(ctor).setVarargs(ctor); } @@ -1348,29 +1699,75 @@ */ /*non-public*/ MethodHandle linkMethodHandleConstant(byte refKind, Class defc, String name, Object type) throws ReflectiveOperationException { - MemberName resolved = null; - if (type instanceof MemberName) { - resolved = (MemberName) type; - if (!resolved.isResolved()) throw new InternalError("unresolved MemberName"); - assert(name == null || name.equals(resolved.getName())); + if (!(type instanceof Class || type instanceof MethodType)) + throw new InternalError("unresolved MemberName"); + MemberName member = new MemberName(refKind, defc, name, type); + MethodHandle mh = LOOKASIDE_TABLE.get(member); + if (mh != null) { + checkSymbolicClass(defc); + return mh; + } + MemberName resolved = resolveOrFail(refKind, member); + mh = getDirectMethodForConstant(refKind, defc, resolved); + if (mh instanceof DirectMethodHandle + && canBeCached(refKind, defc, resolved)) { + MemberName key = mh.internalMemberName(); + if (key != null) { + key = key.asNormalOriginal(); + } + if (member.equals(key)) { // better safe than sorry + LOOKASIDE_TABLE.put(key, (DirectMethodHandle) mh); + } + } + return mh; + } + private + boolean canBeCached(byte refKind, Class defc, MemberName member) { + if (refKind == REF_invokeSpecial) { + return false; } + if (!Modifier.isPublic(defc.getModifiers()) || + !Modifier.isPublic(member.getDeclaringClass().getModifiers()) || + !member.isPublic() || + member.isCallerSensitive()) { + return false; + } + ClassLoader loader = defc.getClassLoader(); + if (!sun.misc.VM.isSystemDomainLoader(loader)) { + ClassLoader sysl = ClassLoader.getSystemClassLoader(); + boolean found = false; + while (sysl != null) { + if (loader == sysl) { found = true; break; } + sysl = sysl.getParent(); + } + if (!found) { + return false; + } + } + try { + MemberName resolved2 = publicLookup().resolveOrFail(refKind, + new MemberName(refKind, defc, member.getName(), member.getType())); + checkSecurityManager(defc, resolved2); + } catch (ReflectiveOperationException | SecurityException ex) { + return false; + } + return true; + } + private + MethodHandle getDirectMethodForConstant(byte refKind, Class defc, MemberName member) + throws ReflectiveOperationException { if (MethodHandleNatives.refKindIsField(refKind)) { - MemberName field = (resolved != null) ? resolved - : resolveOrFail(refKind, defc, name, (Class) type); - return getDirectField(refKind, defc, field); + return getDirectFieldNoSecurityManager(refKind, defc, member); } else if (MethodHandleNatives.refKindIsMethod(refKind)) { - MemberName method = (resolved != null) ? resolved - : resolveOrFail(refKind, defc, name, (MethodType) type); - return getDirectMethod(refKind, defc, method, lookupClass); + return getDirectMethodNoSecurityManager(refKind, defc, member, lookupClass); } else if (refKind == REF_newInvokeSpecial) { - assert(name == null || name.equals("")); - MemberName ctor = (resolved != null) ? resolved - : resolveOrFail(REF_newInvokeSpecial, defc, name, (MethodType) type); - return getDirectConstructor(defc, ctor); + return getDirectConstructorNoSecurityManager(defc, member); } // oops - throw new ReflectiveOperationException("bad MethodHandle constant #"+refKind+" "+name+" : "+type); + throw newIllegalArgumentException("bad MethodHandle constant #"+member); } + + static ConcurrentHashMap LOOKASIDE_TABLE = new ConcurrentHashMap<>(); } /** @@ -1430,22 +1827,26 @@ *

    * Before invoking its target, the invoker will spread the final array, apply * reference casts as necessary, and unbox and widen primitive arguments. + * If, when the invoker is called, the supplied array argument does + * not have the correct number of elements, the invoker will throw + * an {@link IllegalArgumentException} instead of invoking the target. *

    * This method is equivalent to the following code (though it may be more efficient): - *

    +     * 
    {@code
     MethodHandle invoker = MethodHandles.invoker(type);
     int spreadArgCount = type.parameterCount() - leadingArgCount;
     invoker = invoker.asSpreader(Object[].class, spreadArgCount);
     return invoker;
    -     * 
    - *

    + * }

    * This method throws no reflective or security exceptions. * @param type the desired target type * @param leadingArgCount number of fixed arguments, to be passed unchanged to the target * @return a method handle suitable for invoking any method handle of the given type * @throws NullPointerException if {@code type} is null * @throws IllegalArgumentException if {@code leadingArgCount} is not in - * the range from 0 to {@code type.parameterCount()} inclusive + * the range from 0 to {@code type.parameterCount()} inclusive, + * or if the resulting method handle's type would have + * too many parameters */ static public MethodHandle spreadInvoker(MethodType type, int leadingArgCount) { @@ -1462,9 +1863,7 @@ * an additional leading argument of type {@code MethodHandle}. *

    * This method is equivalent to the following code (though it may be more efficient): - *

    -publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
    -     * 
    + * {@code publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)} * *

    * Discussion: @@ -1479,7 +1878,7 @@ * If spreading, collecting, or other argument transformations are required, * they can be applied once to the invoker {@code X} and reused on many {@code M} * method handle values, as long as they are compatible with the type of {@code X}. - *

    + *

    * (Note: The invoker method is not available via the Core Reflection API. * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke} * on the declared {@code invokeExact} or {@code invoke} method will raise an @@ -1488,6 +1887,8 @@ * This method throws no reflective or security exceptions. * @param type the desired target type * @return a method handle suitable for invoking any method handle of the given type + * @throws IllegalArgumentException if the resulting method handle's type would have + * too many parameters */ static public MethodHandle exactInvoker(MethodType type) { @@ -1508,19 +1909,25 @@ * If the target is a {@linkplain MethodHandle#asVarargsCollector variable arity method handle}, * the required arity conversion will be made, again as if by {@link MethodHandle#asType asType}. *

    - * A {@linkplain MethodType#genericMethodType general method type}, + * This method is equivalent to the following code (though it may be more efficient): + * {@code publicLookup().findVirtual(MethodHandle.class, "invoke", type)} + *

    + * Discussion: + * A {@linkplain MethodType#genericMethodType general method type} is one which * mentions only {@code Object} arguments and return values. * An invoker for such a type is capable of calling any method handle * of the same arity as the general type. - *

    - * This method is equivalent to the following code (though it may be more efficient): - *

    -publicLookup().findVirtual(MethodHandle.class, "invoke", type)
    -     * 
    + *

    + * (Note: The invoker method is not available via the Core Reflection API. + * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke} + * on the declared {@code invokeExact} or {@code invoke} method will raise an + * {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.) *

    * This method throws no reflective or security exceptions. * @param type the desired target type * @return a method handle suitable for invoking any method handle convertible to the given type + * @throws IllegalArgumentException if the resulting method handle's type would have + * too many parameters */ static public MethodHandle invoker(MethodType type) { @@ -1801,7 +2208,7 @@ * they will come after. *

    * Example: - *

    +     * 

    {@code
     import static java.lang.invoke.MethodHandles.*;
     import static java.lang.invoke.MethodType.*;
     ...
    @@ -1812,11 +2219,11 @@
     MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
     assertEquals(bigType, d0.type());
     assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
    -     * 
    + * }
    *

    * This method is also equivalent to the following code: *

    -     * {@link #dropArguments(MethodHandle,int,Class...) dropArguments}(target, pos, valueTypes.toArray(new Class[0]))
    +     * {@link #dropArguments(MethodHandle,int,Class...) dropArguments}{@code (target, pos, valueTypes.toArray(new Class[0]))}
          * 
    * @param target the method handle to invoke after the arguments are dropped * @param valueTypes the type(s) of the argument(s) to drop @@ -1859,7 +2266,7 @@ * they will come after. *

    * Example: - *

    +     * 

    {@code
     import static java.lang.invoke.MethodHandles.*;
     import static java.lang.invoke.MethodType.*;
     ...
    @@ -1874,11 +2281,11 @@
     assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
     MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
     assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
    -     * 
    + * }
    *

    * This method is also equivalent to the following code: *

    -     * {@link #dropArguments(MethodHandle,int,List) dropArguments}(target, pos, Arrays.asList(valueTypes))
    +     * {@link #dropArguments(MethodHandle,int,List) dropArguments}{@code (target, pos, Arrays.asList(valueTypes))}
          * 
    * @param target the method handle to invoke after the arguments are dropped * @param valueTypes the type(s) of the argument(s) to drop @@ -1889,7 +2296,8 @@ * or if the {@code valueTypes} array or any of its elements is null * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class}, * or if {@code pos} is negative or greater than the arity of the target, - * or if the new method handle's type would have too many parameters + * or if the new method handle's type would have + * too many parameters */ public static MethodHandle dropArguments(MethodHandle target, int pos, Class... valueTypes) { @@ -1923,8 +2331,8 @@ * It is an error if there are elements of {@code filters} * (null or not) * which do not correspond to argument positions in the target. - * Example: - *

    +     * 

    Example: + *

    {@code
     import static java.lang.invoke.MethodHandles.*;
     import static java.lang.invoke.MethodType.*;
     ...
    @@ -1939,15 +2347,15 @@
     assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
     MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
     assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
    -     * 
    + * }
    *

    Here is pseudocode for the resulting adapter: - *

    +     * 
    {@code
          * V target(P... p, A[i]... a[i], B... b);
          * A[i] filter[i](V[i]);
          * T adapter(P... p, V[i]... v[i], B... b) {
          *   return target(p..., f[i](v[i])..., b...);
          * }
    -     * 
    + * }
    * * @param target the method handle to invoke after arguments are filtered * @param pos the position of the first argument to filter @@ -1957,7 +2365,9 @@ * or if the {@code filters} array is null * @throws IllegalArgumentException if a non-null element of {@code filters} * does not match a corresponding argument type of target as described above, - * or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()} + * or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()}, + * or if the resulting method handle's type would have + * too many parameters */ public static MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) { @@ -1989,15 +2399,120 @@ return MethodHandleImpl.makeCollectArguments(target, filter, pos, false); } - // FIXME: Make this public in M1. - /*non-public*/ static - MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle collector) { + /** + * Adapts a target method handle by pre-processing + * a sub-sequence of its arguments with a filter (another method handle). + * The pre-processed arguments are replaced by the result (if any) of the + * filter function. + * The target is then called on the modified (usually shortened) argument list. + *

    + * If the filter returns a value, the target must accept that value as + * its argument in position {@code pos}, preceded and/or followed by + * any arguments not passed to the filter. + * If the filter returns void, the target must accept all arguments + * not passed to the filter. + * No arguments are reordered, and a result returned from the filter + * replaces (in order) the whole subsequence of arguments originally + * passed to the adapter. + *

    + * The argument types (if any) of the filter + * replace zero or one argument types of the target, at position {@code pos}, + * in the resulting adapted method handle. + * The return type of the filter (if any) must be identical to the + * argument type of the target at position {@code pos}, and that target argument + * is supplied by the return value of the filter. + *

    + * In all cases, {@code pos} must be greater than or equal to zero, and + * {@code pos} must also be less than or equal to the target's arity. + *

    Example: + *

    {@code
    +import static java.lang.invoke.MethodHandles.*;
    +import static java.lang.invoke.MethodType.*;
    +...
    +MethodHandle deepToString = publicLookup()
    +  .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
    +
    +MethodHandle ts1 = deepToString.asCollector(String[].class, 1);
    +assertEquals("[strange]", (String) ts1.invokeExact("strange"));
    +
    +MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
    +assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));
    +
    +MethodHandle ts3 = deepToString.asCollector(String[].class, 3);
    +MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);
    +assertEquals("[top, [up, down], strange]",
    +             (String) ts3_ts2.invokeExact("top", "up", "down", "strange"));
    +
    +MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);
    +assertEquals("[top, [up, down], [strange]]",
    +             (String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));
    +
    +MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);
    +assertEquals("[top, [[up, down, strange], charm], bottom]",
    +             (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
    +     * }
    + *

    Here is pseudocode for the resulting adapter: + *

    {@code
    +     * T target(A...,V,C...);
    +     * V filter(B...);
    +     * T adapter(A... a,B... b,C... c) {
    +     *   V v = filter(b...);
    +     *   return target(a...,v,c...);
    +     * }
    +     * // and if the filter has no arguments:
    +     * T target2(A...,V,C...);
    +     * V filter2();
    +     * T adapter2(A... a,C... c) {
    +     *   V v = filter2();
    +     *   return target2(a...,v,c...);
    +     * }
    +     * // and if the filter has a void return:
    +     * T target3(A...,C...);
    +     * void filter3(B...);
    +     * void adapter3(A... a,B... b,C... c) {
    +     *   filter3(b...);
    +     *   return target3(a...,c...);
    +     * }
    +     * }
    + *

    + * A collection adapter {@code collectArguments(mh, 0, coll)} is equivalent to + * one which first "folds" the affected arguments, and then drops them, in separate + * steps as follows: + *

    {@code
    +     * mh = MethodHandles.dropArguments(mh, 1, coll.type().parameterList()); //step 2
    +     * mh = MethodHandles.foldArguments(mh, coll); //step 1
    +     * }
    + * If the target method handle consumes no arguments besides than the result + * (if any) of the filter {@code coll}, then {@code collectArguments(mh, 0, coll)} + * is equivalent to {@code filterReturnValue(coll, mh)}. + * If the filter method handle {@code coll} consumes one argument and produces + * a non-void result, then {@code collectArguments(mh, N, coll)} + * is equivalent to {@code filterArguments(mh, N, coll)}. + * Other equivalences are possible but would require argument permutation. + * + * @param target the method handle to invoke after filtering the subsequence of arguments + * @param pos the position of the first adapter argument to pass to the filter, + * and/or the target argument which receives the result of the filter + * @param filter method handle to call on the subsequence of arguments + * @return method handle which incorporates the specified argument subsequence filtering logic + * @throws NullPointerException if either argument is null + * @throws IllegalArgumentException if the return type of {@code filter} + * is non-void and is not the same as the {@code pos} argument of the target, + * or if {@code pos} is not between 0 and the target's arity, inclusive, + * or if the resulting method handle's type would have + * too many parameters + * @see MethodHandles#foldArguments + * @see MethodHandles#filterArguments + * @see MethodHandles#filterReturnValue + */ + public static + MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) { MethodType targetType = target.type(); - MethodType filterType = collector.type(); + MethodType filterType = filter.type(); if (filterType.returnType() != void.class && filterType.returnType() != targetType.parameterType(pos)) throw newIllegalArgumentException("target and filter types do not match", targetType, filterType); - return MethodHandleImpl.makeCollectArguments(target, collector, pos, false); + return MethodHandleImpl.makeCollectArguments(target, filter, pos, false); } /** @@ -2014,8 +2529,8 @@ * in the resulting adapted method handle. * The argument type of the filter (if any) must be identical to the * return type of the target. - * Example: - *

    +     * 

    Example: + *

    {@code
     import static java.lang.invoke.MethodHandles.*;
     import static java.lang.invoke.MethodType.*;
     ...
    @@ -2026,9 +2541,9 @@
     System.out.println((String) cat.invokeExact("x", "y")); // xy
     MethodHandle f0 = filterReturnValue(cat, length);
     System.out.println((int) f0.invokeExact("x", "y")); // 2
    -     * 
    + * }
    *

    Here is pseudocode for the resulting adapter: - *

    +     * 
    {@code
          * V target(A...);
          * T filter(V);
          * T adapter(A... a) {
    @@ -2049,7 +2564,7 @@
          *   V v = target3(a...);
          *   filter3(v);
          * }
    -     * 
    + * }
    * @param target the method handle to invoke before filtering the return value * @param filter method handle to call on the return value * @return method handle which incorporates the specified return value filtering logic @@ -2105,8 +2620,8 @@ * consider using {@link MethodHandle#asCollector asCollector} instead, since those * arguments will not need to be live on the stack on entry to the * target.) - * Example: - *

    +     * 

    Example: + *

    {@code
     import static java.lang.invoke.MethodHandles.*;
     import static java.lang.invoke.MethodType.*;
     ...
    @@ -2119,9 +2634,9 @@
     MethodHandle catTrace = foldArguments(cat, trace);
     // also prints "boo":
     assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
    -     * 
    + * }
    *

    Here is pseudocode for the resulting adapter: - *

    +     * 
    {@code
          * // there are N arguments in A...
          * T target(V, A[N]..., B...);
          * V combiner(A...);
    @@ -2136,7 +2651,7 @@
          *   combiner2(a...);
          *   return target2(a..., b...);
          * }
    -     * 
    + * }
    * @param target the method handle to invoke after arguments are combined * @param combiner method handle to call initially on the incoming arguments * @return method handle which incorporates the specified argument folding logic @@ -2179,7 +2694,7 @@ * of the test must be boolean, and the test is allowed * to have fewer arguments than the other two method handles. *

    Here is pseudocode for the resulting adapter: - *

    +     * 
    {@code
          * boolean test(A...);
          * T target(A...,B...);
          * T fallback(A...,B...);
    @@ -2189,7 +2704,7 @@
          *   else
          *     return fallback(a..., b...);
          * }
    -     * 
    + * }
    * Note that the test arguments ({@code a...} in the pseudocode) cannot * be modified by execution of the test, and so are passed unchanged * from the caller to the target or fallback as appropriate. @@ -2241,7 +2756,7 @@ * (similarly to the predicate in {@link #guardWithTest guardWithTest}). * Also, the handler must have an extra leading parameter of {@code exType} or a supertype. *

    Here is pseudocode for the resulting adapter: - *

    +     * 
    {@code
          * T target(A..., B...);
          * T handler(ExType, A...);
          * T adapter(A... a, B... b) {
    @@ -2251,7 +2766,7 @@
          *     return handler(ex, a...);
          *   }
          * }
    -     * 
    + * }
    * Note that the saved arguments ({@code a...} in the pseudocode) cannot * be modified by execution of the target, and so are passed unchanged * from the caller to the handler, if the handler is invoked. diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/MethodType.java --- a/jdk/src/share/classes/java/lang/invoke/MethodType.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/MethodType.java Tue Oct 08 14:57:32 2013 -0700 @@ -77,7 +77,8 @@ * A method type may be loaded by an {@code ldc} instruction which refers * to a suitable {@code CONSTANT_MethodType} constant pool entry. * The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string. - * For more details, see the package summary. + * (For full details on method type constants, + * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.) *

    * When the JVM materializes a {@code MethodType} from a descriptor string, * all classes named in the descriptor must be accessible, and will be loaded. @@ -94,9 +95,9 @@ private final Class[] ptypes; // The remaining fields are caches of various sorts: - private MethodTypeForm form; // erased form, plus cached data about primitives - private MethodType wrapAlt; // alternative wrapped/unwrapped version - private Invokers invokers; // cache of handy higher-order adapters + private @Stable MethodTypeForm form; // erased form, plus cached data about primitives + private @Stable MethodType wrapAlt; // alternative wrapped/unwrapped version + private @Stable Invokers invokers; // cache of handy higher-order adapters /** * Check the given parameters for validity and store them into the final fields. @@ -940,10 +941,10 @@ * Instead, the return type and parameter type arrays are written directly * from the {@code writeObject} method, using two calls to {@code s.writeObject} * as follows: - *

    +     * 
    {@code
     s.writeObject(this.returnType());
     s.writeObject(this.parameterArray());
    -     * 
    + * }
    *

    * The deserialized field values are checked as if they were * provided to the factory method {@link #methodType(Class,Class[]) methodType}. diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java --- a/jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java Tue Oct 08 14:57:32 2013 -0700 @@ -28,6 +28,7 @@ import sun.invoke.util.Wrapper; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleNatives.Constants.*; + import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; /** * Shared information for a group of method types, which differ @@ -51,12 +52,13 @@ final MethodType basicType; // the canonical erasure, with primitives simplified // Cached adapter information: - /*lazy*/ MethodHandle genericInvoker; // JVM hook for inexact invoke - /*lazy*/ MethodHandle basicInvoker; // cached instance of MH.invokeBasic - /*lazy*/ MethodHandle namedFunctionInvoker; // cached helper for LF.NamedFunction + @Stable String typeString; // argument type signature characters + @Stable MethodHandle genericInvoker; // JVM hook for inexact invoke + @Stable MethodHandle basicInvoker; // cached instance of MH.invokeBasic + @Stable MethodHandle namedFunctionInvoker; // cached helper for LF.NamedFunction // Cached lambda form information, for basic types only: - final LambdaForm[] lambdaForms; + final @Stable LambdaForm[] lambdaForms; // Indexes into lambdaForms: static final int LF_INVVIRTUAL = 0, // DMH invokeVirtual @@ -73,7 +75,8 @@ LF_GEN_LINKER = 11, LF_GEN_INVOKER = 12, LF_CS_LINKER = 13, // linkToCallSite_CS - LF_LIMIT = 14; + LF_MH_LINKER = 14, // linkToCallSite_MH + LF_LIMIT = 15; public MethodType erasedType() { return erasedType; @@ -96,11 +99,24 @@ assert(erasedType == basicType) : "erasedType: " + erasedType + " != basicType: " + basicType; // primitives must be flattened also MethodHandle invoker = basicInvoker; if (invoker != null) return invoker; - invoker = basicType.invokers().makeBasicInvoker(); + invoker = DirectMethodHandle.make(invokeBasicMethod(basicType)); basicInvoker = invoker; return invoker; } + // This next one is called from LambdaForm.NamedFunction.. + /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) { + assert(basicType == basicType.basicType()); + try { + // Do approximately the same as this public API call: + // Lookup.findVirtual(MethodHandle.class, name, type); + // But bypass access and corner case checks, since we know exactly what we need. + return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType); + } catch (ReflectiveOperationException ex) { + throw newInternalError("JVM cannot find invoker for "+basicType, ex); + } + } + /** * Build an MTF for a given type, which must have all references erased to Object. * This MTF will stand for that type and all un-erased variations. diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/MutableCallSite.java --- a/jdk/src/share/classes/java/lang/invoke/MutableCallSite.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/MutableCallSite.java Tue Oct 08 14:57:32 2013 -0700 @@ -38,7 +38,7 @@ * Here is an example of a mutable call site which introduces a * state variable into a method handle chain. * - *

    + * 
    {@code
     MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
     MethodHandle MH_name = name.dynamicInvoker();
     MethodType MT_str1 = MethodType.methodType(String.class);
    @@ -50,10 +50,10 @@
     name.setTarget(MethodHandles.constant(String.class, "Fred"));
     assertEquals("FRED", (String) worker1.invokeExact());
     // (mutation can be continued indefinitely)
    - * 
    + * }
    *

    * The same call site may be used in several places at once. - *

    + * 
    {@code
     MethodType MT_str2 = MethodType.methodType(String.class, String.class);
     MethodHandle MH_cat = lookup().findVirtual(String.class,
       "concat", methodType(String.class, String.class));
    @@ -63,7 +63,7 @@
     name.setTarget(MethodHandles.constant(String.class, "Wilma"));
     assertEquals("WILMA", (String) worker1.invokeExact());
     assertEquals("Wilma, dear?", (String) worker2.invokeExact());
    - * 
    + * }
    *

    * Non-synchronization of target values: * A write to a mutable call site's target does not force other threads diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/Stable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/lang/invoke/Stable.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 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. 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 java.lang.invoke; + +import java.lang.annotation.*; + +/** + * A field may be annotated as stable if all of its component variables + * changes value at most once. + * A field's value counts as its component value. + * If the field is typed as an array, then all the non-null components + * of the array, of depth up to the rank of the field's array type, + * also count as component values. + * By extension, any variable (either array or field) which has annotated + * as stable is called a stable variable, and its non-null or non-zero + * value is called a stable value. + *

    + * Since all fields begin with a default value of null for references + * (resp., zero for primitives), it follows that this annotation indicates + * that the first non-null (resp., non-zero) value stored in the field + * will never be changed. + *

    + * If the field is not of an array type, there are no array elements, + * then the value indicated as stable is simply the value of the field. + * If the dynamic type of the field value is an array but the static type + * is not, the components of the array are not regarded as stable. + *

    + * If the field is an array type, then both the field value and + * all the components of the field value (if the field value is non-null) + * are indicated to be stable. + * If the field type is an array type with rank {@code N > 1}, + * then each component of the field value (if the field value is non-null), + * is regarded as a stable array of rank {@code N-1}. + *

    + * Fields which are declared {@code final} may also be annotated as stable. + * Since final fields already behave as stable values, such an annotation + * indicates no additional information, unless the type of the field is + * an array type. + *

    + * It is (currently) undefined what happens if a field annotated as stable + * is given a third value. In practice, if the JVM relies on this annotation + * to promote a field reference to a constant, it may be that the Java memory + * model would appear to be broken, if such a constant (the second value of the field) + * is used as the value of the field even after the field value has changed. + */ +/* package-private */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@interface Stable { +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/invoke/SwitchPoint.java --- a/jdk/src/share/classes/java/lang/invoke/SwitchPoint.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/SwitchPoint.java Tue Oct 08 14:57:32 2013 -0700 @@ -55,7 +55,7 @@ * At that point {@code guardWithTest} may ignore {@code T} and return {@code F}. *

    * Here is an example of a switch point in action: - *

    + * 
    {@code
     MethodHandle MH_strcat = MethodHandles.lookup()
         .findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
     SwitchPoint spt = new SwitchPoint();
    @@ -68,7 +68,7 @@
     SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
     assert(spt.hasBeenInvalidated());
     assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
    - * 
    + * }
    *

    * Discussion: * Switch points are useful without subclassing. They may also be subclassed. @@ -82,7 +82,7 @@ * Implementation Note: * A switch point behaves as if implemented on top of {@link MutableCallSite}, * approximately as follows: - *

    + * 
    {@code
     public class SwitchPoint {
       private static final MethodHandle
         K_true  = MethodHandles.constant(boolean.class, true),
    @@ -106,7 +106,7 @@
         MutableCallSite.syncAll(mcss.toArray(new MutableCallSite[0]));
       }
     }
    - * 
    + * }
    * @author Remi Forax, JSR 292 EG */ public class SwitchPoint { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java --- a/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java Tue Oct 08 14:57:32 2013 -0700 @@ -27,17 +27,18 @@ /** - * AnnotatedArrayType represents the use of an array type, whose component - * type may itself represent the annotated use of a type. + * {@code AnnotatedArrayType} represents the potentially annotated use of an + * array type, whose component type may itself represent the annotated use of a + * type. * * @since 1.8 */ public interface AnnotatedArrayType extends AnnotatedType { /** - * Returns the annotated generic component type of this array type. + * Returns the potentially annotated generic component type of this array type. * - * @return the annotated generic component type of this array type + * @return the potentially annotated generic component type of this array type */ AnnotatedType getAnnotatedGenericComponentType(); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java --- a/jdk/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java Tue Oct 08 14:57:32 2013 -0700 @@ -26,17 +26,18 @@ package java.lang.reflect; /** - * AnnotatedParameterizedType represents the use of a parameterized type, - * whose type arguments may themselves represent annotated uses of types. + * {@code AnnotatedParameterizedType} represents the potentially annotated use + * of a parameterized type, whose type arguments may themselves represent + * annotated uses of types. * * @since 1.8 */ public interface AnnotatedParameterizedType extends AnnotatedType { /** - * Returns the annotated actual type arguments of this parameterized type. + * Returns the potentially annotated actual type arguments of this parameterized type. * - * @return the annotated actual type arguments of this parameterized type + * @return the potentially annotated actual type arguments of this parameterized type */ AnnotatedType[] getAnnotatedActualTypeArguments(); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/reflect/AnnotatedType.java --- a/jdk/src/share/classes/java/lang/reflect/AnnotatedType.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedType.java Tue Oct 08 14:57:32 2013 -0700 @@ -26,10 +26,10 @@ package java.lang.reflect; /** - * AnnotatedType represents the annotated use of a type in the program - * currently running in this VM. The use may be of any type in the Java - * programming language, including an array type, a parameterized type, a type - * variable, or a wildcard type. + * {@code AnnotatedType} represents the potentially annotated use of a type in + * the program currently running in this VM. The use may be of any type in the + * Java programming language, including an array type, a parameterized type, a + * type variable, or a wildcard type. * * @since 1.8 */ diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java --- a/jdk/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java Tue Oct 08 14:57:32 2013 -0700 @@ -26,18 +26,18 @@ package java.lang.reflect; /** - * AnnotatedTypeVariable represents the use of a type variable, whose - * declaration may have bounds which themselves represent annotated uses of - * types. + * {@code AnnotatedTypeVariable} represents the potentially annotated use of a + * type variable, whose declaration may have bounds which themselves represent + * annotated uses of types. * * @since 1.8 */ public interface AnnotatedTypeVariable extends AnnotatedType { /** - * Returns the annotated bounds of this type variable. + * Returns the potentially annotated bounds of this type variable. * - * @return the annotated bounds of this type variable + * @return the potentially annotated bounds of this type variable */ AnnotatedType[] getAnnotatedBounds(); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java --- a/jdk/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java Tue Oct 08 14:57:32 2013 -0700 @@ -26,24 +26,25 @@ package java.lang.reflect; /** - * AnnotatedWildcardType represents the use of a wildcard type argument, whose - * upper or lower bounds may themselves represent annotated uses of types. + * {@code AnnotatedWildcardType} represents the potentially annotated use of a + * wildcard type argument, whose upper or lower bounds may themselves represent + * annotated uses of types. * * @since 1.8 */ public interface AnnotatedWildcardType extends AnnotatedType { /** - * Returns the annotated lower bounds of this wildcard type. + * Returns the potentially annotated lower bounds of this wildcard type. * - * @return the annotated lower bounds of this wildcard type + * @return the potentially annotated lower bounds of this wildcard type */ AnnotatedType[] getAnnotatedLowerBounds(); /** - * Returns the annotated upper bounds of this wildcard type. + * Returns the potentially annotated upper bounds of this wildcard type. * - * @return the annotated upper bounds of this wildcard type + * @return the potentially annotated upper bounds of this wildcard type */ AnnotatedType[] getAnnotatedUpperBounds(); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/reflect/Constructor.java --- a/jdk/src/share/classes/java/lang/reflect/Constructor.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java Tue Oct 08 14:57:32 2013 -0700 @@ -67,8 +67,6 @@ private transient ConstructorRepository genericInfo; private byte[] annotations; private byte[] parameterAnnotations; - // This is set by the vm at Constructor creation - private byte[] typeAnnotations; // Generics infrastructure // Accessor for factory @@ -141,8 +139,6 @@ res.root = this; // Might as well eagerly propagate this if already present res.constructorAccessor = constructorAccessor; - - res.typeAnnotations = typeAnnotations; return res; } @@ -155,10 +151,6 @@ byte[] getAnnotationBytes() { return annotations; } - @Override - byte[] getTypeAnnotationBytes() { - return typeAnnotations; - } /** * {@inheritDoc} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/reflect/Executable.java --- a/jdk/src/share/classes/java/lang/reflect/Executable.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/reflect/Executable.java Tue Oct 08 14:57:32 2013 -0700 @@ -51,7 +51,6 @@ * Accessor method to allow code sharing */ abstract byte[] getAnnotationBytes(); - abstract byte[] getTypeAnnotationBytes(); /** * Does the Executable have generic information. @@ -287,12 +286,14 @@ * this object. Returns an array of length 0 if the executable * has no parameters. * - * The parameters of the underlying executable do not necessarily + *

    The parameters of the underlying executable do not necessarily * have unique names, or names that are legal identifiers in the * Java programming language (JLS 3.8). * + * @throws MalformedParametersException if the class file contains + * a MethodParameters attribute that is improperly formatted. * @return an array of {@code Parameter} objects representing all - * the parameters to the executable this object represents + * the parameters to the executable this object represents. */ public Parameter[] getParameters() { // TODO: This may eventually need to be guarded by security @@ -316,6 +317,30 @@ return out; } + private void verifyParameters(final Parameter[] parameters) { + final int mask = Modifier.FINAL | Modifier.SYNTHETIC | Modifier.MANDATED; + + if (getParameterTypes().length != parameters.length) + throw new MalformedParametersException("Wrong number of parameters in MethodParameters attribute"); + + for (Parameter parameter : parameters) { + final String name = parameter.getRealName(); + final int mods = parameter.getModifiers(); + + if (name != null) { + if (name.isEmpty() || name.indexOf('.') != -1 || + name.indexOf(';') != -1 || name.indexOf('[') != -1 || + name.indexOf('/') != -1) { + throw new MalformedParametersException("Invalid parameter name \"" + name + "\""); + } + } + + if (mods != (mods & mask)) { + throw new MalformedParametersException("Invalid parameter modifiers"); + } + } + } + private Parameter[] privateGetParameters() { // Use tmp to avoid multiple writes to a volatile. Parameter[] tmp = parameters; @@ -323,7 +348,12 @@ if (tmp == null) { // Otherwise, go to the JVM to get them - tmp = getParameters0(); + try { + tmp = getParameters0(); + } catch(IllegalArgumentException e) { + // Rethrow ClassFormatErrors + throw new MalformedParametersException("Invalid constant pool index"); + } // If we get back nothing, then synthesize parameters if (tmp == null) { @@ -331,6 +361,7 @@ tmp = synthesizeAllParams(); } else { hasRealParameterData = true; + verifyParameters(tmp); } parameters = tmp; @@ -352,6 +383,12 @@ private transient volatile Parameter[] parameters; private native Parameter[] getParameters0(); + private native byte[] getTypeAnnotationBytes0(); + + // Needed by reflectaccess + byte[] getTypeAnnotationBytes() { + return getTypeAnnotationBytes0(); + } /** * Returns an array of {@code Class} objects that represent the @@ -514,18 +551,20 @@ } /** - * Returns an AnnotatedType object that represents the use of a type to + * Returns an {@code AnnotatedType} object that represents the use of a type to * specify the return type of the method/constructor represented by this * Executable. * - * If this Executable represents a constructor, the AnnotatedType object - * represents the type of the constructed object. + * If this {@code Executable} object represents a constructor, the {@code + * AnnotatedType} object represents the type of the constructed object. * - * If this Executable represents a method, the AnnotatedType object - * represents the use of a type to specify the return type of the method. + * If this {@code Executable} object represents a method, the {@code + * AnnotatedType} object represents the use of a type to specify the return + * type of the method. * - * @return an object representing the return type of this method - * or constructor + * @return an object representing the return type of the method + * or constructor represented by this {@code Executable} + * * @since 1.8 */ public abstract AnnotatedType getAnnotatedReturnType(); @@ -539,7 +578,7 @@ * @since 1.8 */ AnnotatedType getAnnotatedReturnType0(Type returnType) { - return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(), + return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(), sun.misc.SharedSecrets.getJavaLangAccess(). getConstantPool(getDeclaringClass()), this, @@ -549,25 +588,30 @@ } /** - * Returns an AnnotatedType object that represents the use of a type to - * specify the receiver type of the method/constructor represented by this - * Executable. The receiver type of a method/constructor is available only - * if the method/constructor declares a formal parameter called 'this'. + * Returns an {@code AnnotatedType} object that represents the use of a + * type to specify the receiver type of the method/constructor represented + * by this Executable object. The receiver type of a method/constructor is + * available only if the method/constructor has a receiver + * parameter (JLS 8.4.1). * - * Returns null if this Executable represents a constructor or instance - * method that either declares no formal parameter called 'this', or - * declares a formal parameter called 'this' with no annotations on its - * type. + * If this {@code Executable} object represents a constructor or instance + * method that does not have a receiver parameter, or has a receiver + * parameter with no annotations on its type, then the return value is an + * {@code AnnotatedType} object representing an element with no + * annotations. * - * Returns null if this Executable represents a static method. + * If this {@code Executable} object represents a static method, then the + * return value is null. * - * @return an object representing the receiver type of the - * method or constructor represented by this Executable + * @return an object representing the receiver type of the method or + * constructor represented by this {@code Executable} * * @since 1.8 */ public AnnotatedType getAnnotatedReceiverType() { - return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(), + if (Modifier.isStatic(this.getModifiers())) + return null; + return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(), sun.misc.SharedSecrets.getJavaLangAccess(). getConstantPool(getDeclaringClass()), this, @@ -577,8 +621,8 @@ } /** - * Returns an array of AnnotatedType objects that represent the use of - * types to specify formal parameter types of the method/constructor + * Returns an array of {@code AnnotatedType} objects that represent the use + * of types to specify formal parameter types of the method/constructor * represented by this Executable. The order of the objects in the array * corresponds to the order of the formal parameter types in the * declaration of the method/constructor. @@ -587,12 +631,13 @@ * parameters. * * @return an array of objects representing the types of the - * formal parameters of this method or constructor + * formal parameters of the method or constructor represented by this + * {@code Executable} * * @since 1.8 */ public AnnotatedType[] getAnnotatedParameterTypes() { - return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes(), + return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes0(), sun.misc.SharedSecrets.getJavaLangAccess(). getConstantPool(getDeclaringClass()), this, @@ -602,8 +647,8 @@ } /** - * Returns an array of AnnotatedType objects that represent the use of - * types to specify the declared exceptions of the method/constructor + * Returns an array of {@code AnnotatedType} objects that represent the use + * of types to specify the declared exceptions of the method/constructor * represented by this Executable. The order of the objects in the array * corresponds to the order of the exception types in the declaration of * the method/constructor. @@ -612,12 +657,13 @@ * exceptions. * * @return an array of objects representing the declared - * exceptions of this method or constructor + * exceptions of the method or constructor represented by this {@code + * Executable} * * @since 1.8 */ public AnnotatedType[] getAnnotatedExceptionTypes() { - return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes(), + return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes0(), sun.misc.SharedSecrets.getJavaLangAccess(). getConstantPool(getDeclaringClass()), this, diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/reflect/Field.java --- a/jdk/src/share/classes/java/lang/reflect/Field.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/reflect/Field.java Tue Oct 08 14:57:32 2013 -0700 @@ -82,8 +82,6 @@ // currently only two levels deep (i.e., one root Field and // potentially many Field objects pointing to it.) private Field root; - // This is set by the vm at Field creation - private byte[] typeAnnotations; // Generics infrastructure @@ -149,7 +147,6 @@ res.fieldAccessor = fieldAccessor; res.overrideFieldAccessor = overrideFieldAccessor; - res.typeAnnotations = typeAnnotations; return res; } @@ -1148,6 +1145,8 @@ return declaredAnnotations; } + private native byte[] getTypeAnnotationBytes0(); + /** * Returns an AnnotatedType object that represents the use of a type to specify * the declared type of the field represented by this Field. @@ -1157,7 +1156,7 @@ * @since 1.8 */ public AnnotatedType getAnnotatedType() { - return TypeAnnotationParser.buildAnnotatedType(typeAnnotations, + return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(), sun.misc.SharedSecrets.getJavaLangAccess(). getConstantPool(getDeclaringClass()), this, diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/reflect/MalformedParametersException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/lang/reflect/MalformedParametersException.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 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. + */ + +package java.lang.reflect; + +/** + * Thrown when {@link java.lang.reflect.Executable#getParameters the + * java.lang.reflect package} attempts to read method parameters from + * a class file and determines that one or more parameters are + * malformed. + * + *

    The following is a list of conditions under which this exception + * can be thrown: + *

      + *
    • The number of parameters (parameter_count) is wrong for the method + *
    • A constant pool index is out of bounds. + *
    • A constant pool index does not refer to a UTF-8 entry + *
    • A parameter's name is "", or contains an illegal character + *
    • The flags field contains an illegal flag (something other than + * FINAL, SYNTHETIC, or MANDATED) + *
    + * + * See {@link java.lang.reflect.Executable#getParameters} for more + * information. + * + * @see java.lang.reflect.Executable#getParameters + * @since 1.8 + */ +public class MalformedParametersException extends RuntimeException { + + private static final long serialVersionUID = 20130919L; + + public MalformedParametersException() {} + + public MalformedParametersException(String reason) { + super(reason); + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/reflect/Method.java --- a/jdk/src/share/classes/java/lang/reflect/Method.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/reflect/Method.java Tue Oct 08 14:57:32 2013 -0700 @@ -80,8 +80,6 @@ // currently only two levels deep (i.e., one root Method and // potentially many Method objects pointing to it.) private Method root; - // This is set by the vm at Method creation - private byte[] typeAnnotations; // Generics infrastructure private String getGenericSignature() {return signature;} @@ -152,8 +150,6 @@ res.root = this; // Might as well eagerly propagate this if already present res.methodAccessor = methodAccessor; - - res.typeAnnotations = typeAnnotations; return res; } @@ -166,10 +162,6 @@ byte[] getAnnotationBytes() { return annotations; } - @Override - byte[] getTypeAnnotationBytes() { - return typeAnnotations; - } /** * {@inheritDoc} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/lang/reflect/Parameter.java --- a/jdk/src/share/classes/java/lang/reflect/Parameter.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/lang/reflect/Parameter.java Tue Oct 08 14:57:32 2013 -0700 @@ -104,7 +104,7 @@ * to the class file. */ public boolean isNamePresent() { - return executable.hasRealParameterData(); + return executable.hasRealParameterData() && name != null; } /** @@ -182,6 +182,11 @@ return name; } + // Package-private accessor to the real name field. + String getRealName() { + return name; + } + /** * Returns a {@code Type} object that identifies the parameterized * type for the parameter represented by this {@code Parameter} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/nio/file/Files.java --- a/jdk/src/share/classes/java/nio/file/Files.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/nio/file/Files.java Tue Oct 08 14:57:32 2013 -0700 @@ -2128,7 +2128,7 @@ /** * Tests whether a file is a symbolic link. * - *

    Where is it required to distinguish an I/O exception from the case + *

    Where it is required to distinguish an I/O exception from the case * that the file is not a symbolic link then the file attributes can be * read with the {@link #readAttributes(Path,Class,LinkOption[]) * readAttributes} method and the file type tested with the {@link @@ -2164,7 +2164,7 @@ * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS * NOFOLLOW_LINKS} is present then symbolic links are not followed. * - *

    Where is it required to distinguish an I/O exception from the case + *

    Where it is required to distinguish an I/O exception from the case * that the file is not a directory then the file attributes can be * read with the {@link #readAttributes(Path,Class,LinkOption[]) * readAttributes} method and the file type tested with the {@link @@ -2201,7 +2201,7 @@ * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS * NOFOLLOW_LINKS} is present then symbolic links are not followed. * - *

    Where is it required to distinguish an I/O exception from the case + *

    Where it is required to distinguish an I/O exception from the case * that the file is not a regular file then the file attributes can be * read with the {@link #readAttributes(Path,Class,LinkOption[]) * readAttributes} method and the file type tested with the {@link @@ -3082,13 +3082,13 @@ * method is invoked to check read access to the file. */ public static byte[] readAllBytes(Path path) throws IOException { - try (FileChannel fc = FileChannel.open(path); - InputStream is = Channels.newInputStream(fc)) { - long size = fc.size(); + try (SeekableByteChannel sbc = Files.newByteChannel(path); + InputStream in = Channels.newInputStream(sbc)) { + long size = sbc.size(); if (size > (long)MAX_BUFFER_SIZE) throw new OutOfMemoryError("Required array size too large"); - return read(is, (int)size); + return read(in, (int)size); } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/nio/file/Path.java --- a/jdk/src/share/classes/java/nio/file/Path.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/nio/file/Path.java Tue Oct 08 14:57:32 2013 -0700 @@ -315,7 +315,7 @@ * and parent directory. In such file systems all occurrences of "{@code .}" * are considered redundant. If a "{@code ..}" is preceded by a * non-"{@code ..}" name then both names are considered redundant (the - * process to identify such names is repeated until is it no longer + * process to identify such names is repeated until it is no longer * applicable). * *

    This method does not access the file system; the path may not locate diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/security/SecureRandom.java --- a/jdk/src/share/classes/java/security/SecureRandom.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/security/SecureRandom.java Tue Oct 08 14:57:32 2013 -0700 @@ -578,39 +578,30 @@ /** * Returns a {@code SecureRandom} object that was selected by using * the algorithms/providers specified in the {@code - * securerandom.strongAlgorithms} Security property. + * securerandom.strongAlgorithms} {@link Security} property. *

    * Some situations require strong random values, such as when * creating high-value/long-lived secrets like RSA public/private * keys. To help guide applications in selecting a suitable strong - * {@code SecureRandom} implementation, Java distributions should + * {@code SecureRandom} implementation, Java distributions * include a list of known strong {@code SecureRandom} * implementations in the {@code securerandom.strongAlgorithms} * Security property. - * - *

    -     *     SecureRandom sr = SecureRandom.getStrongSecureRandom();
    -     *
    -     *     if (sr == null) {
    -     *         // Decide if this is a problem, and whether to recover.
    -     *         sr = new SecureRandom();
    -     *         if (!goodEnough(sr)) {
    -     *             return;
    -     *         }
    -     *     }
    -     *
    -     *     keyPairGenerator.initialize(2048, sr);
    -     * 
    + *

    + * Every implementation of the Java platform is required to + * support at least one strong {@code SecureRandom} implementation. * * @return a strong {@code SecureRandom} implementation as indicated - * by the {@code securerandom.strongAlgorithms} Security property, or - * null if none are available. + * by the {@code securerandom.strongAlgorithms} Security property + * + * @throws NoSuchAlgorithmException if no algorithm is available * * @see Security#getProperty(String) * * @since 1.8 */ - public static SecureRandom getStrongSecureRandom() { + public static SecureRandom getInstanceStrong() + throws NoSuchAlgorithmException { String property = AccessController.doPrivileged( new PrivilegedAction() { @@ -622,7 +613,8 @@ }); if ((property == null) || (property.length() == 0)) { - return null; + throw new NoSuchAlgorithmException( + "Null/empty securerandom.strongAlgorithms Security Property"); } String remainder = property; @@ -649,7 +641,8 @@ } } - return null; + throw new NoSuchAlgorithmException( + "No strong SecureRandom impls available: " + property); } // Declare serialVersionUID to be compatible with JDK1.1 diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/Duration.java --- a/jdk/src/share/classes/java/time/Duration.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/Duration.java Tue Oct 08 14:57:32 2013 -0700 @@ -441,9 +441,13 @@ //----------------------------------------------------------------------- /** - * Obtains a {@code Duration} representing the duration between two instants. + * Obtains a {@code Duration} representing the duration between two temporal objects. *

    - * This calculates the duration between two temporal objects of the same type. + * This calculates the duration between two temporal objects. If the objects + * are of different types, then the duration is calculated based on the type + * of the first object. For example, if the first argument is a {@code LocalTime} + * then the second argument is converted to a {@code LocalTime}. + *

    * The specified temporal objects must support the {@link ChronoUnit#SECONDS SECONDS} unit. * For full accuracy, either the {@link ChronoUnit#NANOS NANOS} unit or the * {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field should be supported. diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/Instant.java --- a/jdk/src/share/classes/java/time/Instant.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/Instant.java Tue Oct 08 14:57:32 2013 -0700 @@ -362,6 +362,10 @@ * @throws DateTimeException if unable to convert to an {@code Instant} */ public static Instant from(TemporalAccessor temporal) { + if (temporal instanceof Instant) { + return (Instant) temporal; + } + Objects.requireNonNull(temporal, "temporal"); long instantSecs = temporal.getLong(INSTANT_SECONDS); int nanoOfSecond = temporal.get(NANO_OF_SECOND); return Instant.ofEpochSecond(instantSecs, nanoOfSecond); @@ -370,7 +374,7 @@ //----------------------------------------------------------------------- /** * Obtains an instance of {@code Instant} from a text string such as - * {@code 2007-12-03T10:15:30:00}. + * {@code 2007-12-03T10:15:30.00Z}. *

    * The string must represent a valid instant in UTC and is parsed using * {@link DateTimeFormatter#ISO_INSTANT}. @@ -1091,7 +1095,8 @@ * The result will be negative if the end is before the start. * The calculation returns a whole number, representing the number of * complete units between the two instants. - * The {@code Temporal} passed to this method must be an {@code Instant}. + * The {@code Temporal} passed to this method is converted to a + * {@code Instant} using {@link #from(TemporalAccessor)}. * For example, the amount in days between two dates can be calculated * using {@code startInstant.until(endInstant, SECONDS)}. *

    @@ -1112,25 +1117,22 @@ *

    * If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

    * This instance is immutable and unaffected by this method call. * - * @param endInstant the end date, which must be an {@code Instant}, not null + * @param endExclusive the end date, exclusive, which is converted to an {@code Instant}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this instant and the end instant - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to an {@code Instant} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endInstant, TemporalUnit unit) { - if (endInstant instanceof Instant == false) { - Objects.requireNonNull(endInstant, "endInstant"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } - Instant end = (Instant) endInstant; + public long until(Temporal endExclusive, TemporalUnit unit) { + Instant end = Instant.from(endExclusive); if (unit instanceof ChronoUnit) { ChronoUnit f = (ChronoUnit) unit; switch (f) { @@ -1145,7 +1147,7 @@ } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return unit.between(this, endInstant); + return unit.between(this, end); } private long nanosUntil(Instant end) { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/LocalDate.java --- a/jdk/src/share/classes/java/time/LocalDate.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/LocalDate.java Tue Oct 08 14:57:32 2013 -0700 @@ -353,6 +353,7 @@ * @throws DateTimeException if unable to convert to a {@code LocalDate} */ public static LocalDate from(TemporalAccessor temporal) { + Objects.requireNonNull(temporal, "temporal"); LocalDate date = temporal.query(TemporalQuery.localDate()); if (date == null) { throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " + temporal.getClass()); @@ -1125,6 +1126,11 @@ */ @Override public LocalDate plus(TemporalAmount amountToAdd) { + if (amountToAdd instanceof Period) { + Period periodToAdd = (Period) amountToAdd; + return plusMonths(periodToAdd.toTotalMonths()).plusDays(periodToAdd.getDays()); + } + Objects.requireNonNull(amountToAdd, "amountToAdd"); return (LocalDate) amountToAdd.addTo(this); } @@ -1353,6 +1359,11 @@ */ @Override public LocalDate minus(TemporalAmount amountToSubtract) { + if (amountToSubtract instanceof Period) { + Period periodToSubtract = (Period) amountToSubtract; + return minusMonths(periodToSubtract.toTotalMonths()).minusDays(periodToSubtract.getDays()); + } + Objects.requireNonNull(amountToSubtract, "amountToSubtract"); return (LocalDate) amountToSubtract.subtractFrom(this); } @@ -1531,7 +1542,8 @@ * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified date. * The result will be negative if the end is before the start. - * The {@code Temporal} passed to this method must be a {@code LocalDate}. + * The {@code Temporal} passed to this method is converted to a + * {@code LocalDate} using {@link #from(TemporalAccessor)}. * For example, the amount in days between two dates can be calculated * using {@code startDate.until(endDate, DAYS)}. *

    @@ -1557,26 +1569,22 @@ *

    * If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

    * This instance is immutable and unaffected by this method call. * - * @param endDate the end date, which must be a {@code LocalDate}, not null + * @param endExclusive the end date, exclusive, which is converted to a {@code LocalDate}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this date and the end date - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code LocalDate} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endDate, TemporalUnit unit) { - Objects.requireNonNull(unit, "unit"); - if (endDate instanceof LocalDate == false) { - Objects.requireNonNull(endDate, "endDate"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } - LocalDate end = (LocalDate) endDate; + public long until(Temporal endExclusive, TemporalUnit unit) { + LocalDate end = LocalDate.from(endExclusive); if (unit instanceof ChronoUnit) { switch ((ChronoUnit) unit) { case DAYS: return daysUntil(end); @@ -1590,7 +1598,7 @@ } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return unit.between(this, endDate); + return unit.between(this, end); } long daysUntil(LocalDate end) { @@ -1632,12 +1640,12 @@ * * The choice should be made based on which makes the code more readable. * - * @param endDate the end date, exclusive, which may be in any chronology, not null + * @param endDateExclusive the end date, exclusive, which may be in any chronology, not null * @return the period between this date and the end date, not null */ @Override - public Period until(ChronoLocalDate endDate) { - LocalDate end = LocalDate.from(endDate); + public Period until(ChronoLocalDate endDateExclusive) { + LocalDate end = LocalDate.from(endDateExclusive); long totalMonths = end.getProlepticMonth() - this.getProlepticMonth(); // safe int days = end.day - this.day; if (totalMonths > 0 && days < 0) { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/LocalDateTime.java --- a/jdk/src/share/classes/java/time/LocalDateTime.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/LocalDateTime.java Tue Oct 08 14:57:32 2013 -0700 @@ -1129,6 +1129,11 @@ */ @Override public LocalDateTime plus(TemporalAmount amountToAdd) { + if (amountToAdd instanceof Period) { + Period periodToAdd = (Period) amountToAdd; + return with(date.plus(periodToAdd), time); + } + Objects.requireNonNull(amountToAdd, "amountToAdd"); return (LocalDateTime) amountToAdd.addTo(this); } @@ -1343,6 +1348,11 @@ */ @Override public LocalDateTime minus(TemporalAmount amountToSubtract) { + if (amountToSubtract instanceof Period) { + Period periodToSubtract = (Period) amountToSubtract; + return with(date.minus(periodToSubtract), time); + } + Objects.requireNonNull(amountToSubtract, "amountToSubtract"); return (LocalDateTime) amountToSubtract.subtractFrom(this); } @@ -1611,7 +1621,8 @@ * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified date-time. * The result will be negative if the end is before the start. - * The {@code Temporal} passed to this method must be a {@code LocalDateTime}. + * The {@code Temporal} passed to this method is converted to a + * {@code LocalDateTime} using {@link #from(TemporalAccessor)}. * For example, the amount in days between two date-times can be calculated * using {@code startDateTime.until(endDateTime, DAYS)}. *

    @@ -1639,25 +1650,22 @@ *

    * If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

    * This instance is immutable and unaffected by this method call. * - * @param endDateTime the end date-time, which must be a {@code LocalDateTime}, not null + * @param endExclusive the end date, exclusive, which is converted to a {@code LocalDateTime}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this date-time and the end date-time - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code LocalDateTime} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endDateTime, TemporalUnit unit) { - if (endDateTime instanceof LocalDateTime == false) { - Objects.requireNonNull(endDateTime, "endDateTime"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } - LocalDateTime end = (LocalDateTime) endDateTime; + public long until(Temporal endExclusive, TemporalUnit unit) { + LocalDateTime end = LocalDateTime.from(endExclusive); if (unit instanceof ChronoUnit) { if (unit.isTimeBased()) { long amount = date.daysUntil(end.date); @@ -1711,7 +1719,7 @@ } return date.until(endDate, unit); } - return unit.between(this, endDateTime); + return unit.between(this, end); } /** diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/LocalTime.java --- a/jdk/src/share/classes/java/time/LocalTime.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/LocalTime.java Tue Oct 08 14:57:32 2013 -0700 @@ -394,6 +394,7 @@ * @throws DateTimeException if unable to convert to a {@code LocalTime} */ public static LocalTime from(TemporalAccessor temporal) { + Objects.requireNonNull(temporal, "temporal"); LocalTime time = temporal.query(TemporalQuery.localTime()); if (time == null) { throw new DateTimeException("Unable to obtain LocalTime from TemporalAccessor: " + temporal.getClass()); @@ -1330,7 +1331,8 @@ * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified time. * The result will be negative if the end is before the start. - * The {@code Temporal} passed to this method must be a {@code LocalTime}. + * The {@code Temporal} passed to this method is converted to a + * {@code LocalTime} using {@link #from(TemporalAccessor)}. * For example, the amount in hours between two times can be calculated * using {@code startTime.until(endTime, HOURS)}. *

    @@ -1356,25 +1358,22 @@ *

    * If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

    * This instance is immutable and unaffected by this method call. * - * @param endTime the end time, which must be a {@code LocalTime}, not null + * @param endExclusive the end time, exclusive, which is converted to a {@code LocalTime}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this time and the end time - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code LocalTime} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endTime, TemporalUnit unit) { - if (endTime instanceof LocalTime == false) { - Objects.requireNonNull(endTime, "endTime"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } - LocalTime end = (LocalTime) endTime; + public long until(Temporal endExclusive, TemporalUnit unit) { + LocalTime end = LocalTime.from(endExclusive); if (unit instanceof ChronoUnit) { long nanosUntil = end.toNanoOfDay() - toNanoOfDay(); // no overflow switch ((ChronoUnit) unit) { @@ -1388,7 +1387,7 @@ } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return unit.between(this, endTime); + return unit.between(this, end); } /** diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/MonthDay.java --- a/jdk/src/share/classes/java/time/MonthDay.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/MonthDay.java Tue Oct 08 14:57:32 2013 -0700 @@ -246,7 +246,8 @@ *

    * The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and * {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} fields. - * The extraction is only permitted if the date-time has an ISO chronology. + * The extraction is only permitted if the temporal object has an ISO + * chronology, or can be converted to a {@code LocalDate}. *

    * This method matches the signature of the functional interface {@link TemporalQuery} * allowing it to be used in queries via method reference, {@code MonthDay::from}. diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/OffsetDateTime.java --- a/jdk/src/share/classes/java/time/OffsetDateTime.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/OffsetDateTime.java Tue Oct 08 14:57:32 2013 -0700 @@ -1592,7 +1592,8 @@ * For example, the period in days between two date-times can be calculated * using {@code startDateTime.until(endDateTime, DAYS)}. *

    - * The {@code Temporal} passed to this method must be an {@code OffsetDateTime}. + * The {@code Temporal} passed to this method is converted to a + * {@code OffsetDateTime} using {@link #from(TemporalAccessor)}. * If the offset differs between the two date-times, the specified * end date-time is normalized to have the same offset as this date-time. *

    @@ -1620,30 +1621,27 @@ *

    * If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

    * This instance is immutable and unaffected by this method call. * - * @param endDateTime the end date-time, which must be an {@code OffsetDateTime}, not null + * @param endExclusive the end date, exclusive, which is converted to an {@code OffsetDateTime}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this date-time and the end date-time - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to an {@code OffsetDateTime} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endDateTime, TemporalUnit unit) { - if (endDateTime instanceof OffsetDateTime == false) { - Objects.requireNonNull(endDateTime, "endDateTime"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } + public long until(Temporal endExclusive, TemporalUnit unit) { + OffsetDateTime end = OffsetDateTime.from(endExclusive); if (unit instanceof ChronoUnit) { - OffsetDateTime end = (OffsetDateTime) endDateTime; end = end.withOffsetSameInstant(offset); return dateTime.until(end.dateTime, unit); } - return unit.between(this, endDateTime); + return unit.between(this, end); } /** diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/OffsetTime.java --- a/jdk/src/share/classes/java/time/OffsetTime.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/OffsetTime.java Tue Oct 08 14:57:32 2013 -0700 @@ -1124,7 +1124,8 @@ * For example, the period in hours between two times can be calculated * using {@code startTime.until(endTime, HOURS)}. *

    - * The {@code Temporal} passed to this method must be an {@code OffsetTime}. + * The {@code Temporal} passed to this method is converted to a + * {@code OffsetTime} using {@link #from(TemporalAccessor)}. * If the offset differs between the two times, then the specified * end time is normalized to have the same offset as this time. *

    @@ -1150,26 +1151,23 @@ *

    * If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

    * This instance is immutable and unaffected by this method call. * - * @param endTime the end time, which must be an {@code OffsetTime}, not null + * @param endExclusive the end date, exclusive, which is converted to an {@code OffsetTime}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this time and the end time - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to an {@code OffsetTime} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endTime, TemporalUnit unit) { - if (endTime instanceof OffsetTime == false) { - Objects.requireNonNull(endTime, "endTime"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } + public long until(Temporal endExclusive, TemporalUnit unit) { + OffsetTime end = OffsetTime.from(endExclusive); if (unit instanceof ChronoUnit) { - OffsetTime end = (OffsetTime) endTime; long nanosUntil = end.toEpochNano() - toEpochNano(); // no overflow switch ((ChronoUnit) unit) { case NANOS: return nanosUntil; @@ -1182,7 +1180,7 @@ } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return unit.between(this, endTime); + return unit.between(this, end); } /** diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/Period.java --- a/jdk/src/share/classes/java/time/Period.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/Period.java Tue Oct 08 14:57:32 2013 -0700 @@ -61,7 +61,6 @@ */ package java.time; -import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoUnit.DAYS; import static java.time.temporal.ChronoUnit.MONTHS; import static java.time.temporal.ChronoUnit.YEARS; @@ -70,17 +69,19 @@ import java.io.DataOutput; import java.io.IOException; import java.io.InvalidObjectException; -import java.io.InvalidObjectException; import java.io.Serializable; import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoPeriod; import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalQuery; import java.time.temporal.TemporalUnit; import java.time.temporal.UnsupportedTemporalTypeException; -import java.time.temporal.ValueRange; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -89,12 +90,13 @@ import java.util.regex.Pattern; /** - * A date-based amount of time, such as '2 years, 3 months and 4 days'. + * A date-based amount of time in the ISO-8601 calendar system, + * such as '2 years, 3 months and 4 days'. *

    * This class models a quantity or amount of time in terms of years, months and days. * See {@link Duration} for the time-based equivalent to this class. *

    - * Durations and period differ in their treatment of daylight savings time + * Durations and periods differ in their treatment of daylight savings time * when added to {@link ZonedDateTime}. A {@code Duration} will add an exact * number of seconds, thus a duration of one day is always exactly 24 hours. * By contrast, a {@code Period} will add a conceptual day, trying to maintain @@ -110,14 +112,12 @@ * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}. * All three fields are always present, but may be set to zero. *

    - * The period may be used with any calendar system. - * The meaning of a "year" or "month" is only applied when the object is added to a date. + * The ISO-8601 calendar system is the modern civil calendar system used today + * in most of the world. It is equivalent to the proleptic Gregorian calendar + * system, in which today's rules for leap years are applied for all time. *

    * The period is modeled as a directed amount of time, meaning that individual parts of the * period may be negative. - *

    - * The months and years fields may be {@linkplain #normalized() normalized}. - * The normalization assumes a 12 month year, so is not appropriate for all calendar systems. * * @implSpec * This class is immutable and thread-safe. @@ -125,7 +125,7 @@ * @since 1.8 */ public final class Period - implements TemporalAmount, Serializable { + implements ChronoPeriod, Serializable { /** * A constant for a period of zero. @@ -140,6 +140,7 @@ */ private final static Pattern PATTERN = Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?", Pattern.CASE_INSENSITIVE); + /** * The set of supported units. */ @@ -234,12 +235,14 @@ *

    * This obtains a period based on the specified amount. * A {@code TemporalAmount} represents an amount of time, which may be - * date-based or time-based, which this factory extracts to a period. + * date-based or time-based, which this factory extracts to a {@code Period}. *

    * The conversion loops around the set of units from the amount and uses * the {@link ChronoUnit#YEARS YEARS}, {@link ChronoUnit#MONTHS MONTHS} * and {@link ChronoUnit#DAYS DAYS} units to create a period. * If any other units are found then an exception is thrown. + *

    + * If the amount is a {@code ChronoPeriod} then it must use the ISO chronology. * * @param amount the temporal amount to convert, not null * @return the equivalent period, not null @@ -247,6 +250,14 @@ * @throws ArithmeticException if the amount of years, months or days exceeds an int */ public static Period from(TemporalAmount amount) { + if (amount instanceof Period) { + return (Period) amount; + } + if (amount instanceof ChronoPeriod) { + if (IsoChronology.INSTANCE.equals(((ChronoPeriod) amount).getChronology()) == false) { + throw new DateTimeException("Period requires ISO chronology: " + amount); + } + } Objects.requireNonNull(amount, "amount"); int years = 0; int months = 0; @@ -358,13 +369,13 @@ * The result of this method can be a negative period if the end is before the start. * The negative sign will be the same in each of year, month and day. * - * @param startDate the start date, inclusive, not null - * @param endDate the end date, exclusive, not null + * @param startDateInclusive the start date, inclusive, not null + * @param endDateExclusive the end date, exclusive, not null * @return the period between this date and the end date, not null * @see ChronoLocalDate#until(ChronoLocalDate) */ - public static Period between(LocalDate startDate, LocalDate endDate) { - return startDate.until(endDate); + public static Period between(LocalDate startDateInclusive, LocalDate endDateExclusive) { + return startDateInclusive.until(endDateExclusive); } //----------------------------------------------------------------------- @@ -439,6 +450,21 @@ return SUPPORTED_UNITS; } + /** + * Gets the chronology of this period, which is the ISO calendar system. + *

    + * The {@code Chronology} represents the calendar system in use. + * The ISO-8601 calendar system is the modern civil calendar system used today + * in most of the world. It is equivalent to the proleptic Gregorian calendar + * system, in which today's rules for leap years are applied for all time. + * + * @return the ISO chronology, not null + */ + @Override + public IsoChronology getChronology() { + return IsoChronology.INSTANCE; + } + //----------------------------------------------------------------------- /** * Checks if all three units of this period are zero. @@ -468,7 +494,7 @@ *

    * This returns the years unit. *

    - * The months unit is not normalized with the years unit. + * The months unit is not automatically normalized with the years unit. * This means that a period of "15 months" is different to a period * of "1 year and 3 months". * @@ -483,7 +509,7 @@ *

    * This returns the months unit. *

    - * The months unit is not normalized with the years unit. + * The months unit is not automatically normalized with the years unit. * This means that a period of "15 months" is different to a period * of "1 year and 3 months". * @@ -511,7 +537,7 @@ * This sets the amount of the years unit in a copy of this period. * The months and days units are unaffected. *

    - * The months unit is not normalized with the years unit. + * The months unit is not automatically normalized with the years unit. * This means that a period of "15 months" is different to a period * of "1 year and 3 months". *

    @@ -533,7 +559,7 @@ * This sets the amount of the months unit in a copy of this period. * The years and days units are unaffected. *

    - * The months unit is not normalized with the years unit. + * The months unit is not automatically normalized with the years unit. * This means that a period of "15 months" is different to a period * of "1 year and 3 months". *

    @@ -572,21 +598,28 @@ * Returns a copy of this period with the specified period added. *

    * This operates separately on the years, months and days. + * No normalization is performed. *

    * For example, "1 year, 6 months and 3 days" plus "2 years, 2 months and 2 days" * returns "3 years, 8 months and 5 days". *

    + * The specified amount is typically an instance of {@code Period}. + * Other types are interpreted using {@link Period#from(TemporalAmount)}. + *

    * This instance is immutable and unaffected by this method call. * * @param amountToAdd the period to add, not null * @return a {@code Period} based on this period with the requested period added, not null + * @throws DateTimeException if the specified amount has a non-ISO chronology or + * contains an invalid unit * @throws ArithmeticException if numeric overflow occurs */ - public Period plus(Period amountToAdd) { + public Period plus(TemporalAmount amountToAdd) { + Period isoAmount = Period.from(amountToAdd); return create( - Math.addExact(years, amountToAdd.years), - Math.addExact(months, amountToAdd.months), - Math.addExact(days, amountToAdd.days)); + Math.addExact(years, isoAmount.years), + Math.addExact(months, isoAmount.months), + Math.addExact(days, isoAmount.days)); } /** @@ -654,21 +687,28 @@ * Returns a copy of this period with the specified period subtracted. *

    * This operates separately on the years, months and days. + * No normalization is performed. *

    * For example, "1 year, 6 months and 3 days" minus "2 years, 2 months and 2 days" * returns "-1 years, 4 months and 1 day". *

    + * The specified amount is typically an instance of {@code Period}. + * Other types are interpreted using {@link Period#from(TemporalAmount)}. + *

    * This instance is immutable and unaffected by this method call. * * @param amountToSubtract the period to subtract, not null * @return a {@code Period} based on this period with the requested period subtracted, not null + * @throws DateTimeException if the specified amount has a non-ISO chronology or + * contains an invalid unit * @throws ArithmeticException if numeric overflow occurs */ - public Period minus(Period amountToSubtract) { + public Period minus(TemporalAmount amountToSubtract) { + Period isoAmount = Period.from(amountToSubtract); return create( - Math.subtractExact(years, amountToSubtract.years), - Math.subtractExact(months, amountToSubtract.months), - Math.subtractExact(days, amountToSubtract.days)); + Math.subtractExact(years, isoAmount.years), + Math.subtractExact(months, isoAmount.months), + Math.subtractExact(days, isoAmount.days)); } /** @@ -766,8 +806,7 @@ //----------------------------------------------------------------------- /** - * Returns a copy of this period with the years and months normalized - * using a 12 month year. + * Returns a copy of this period with the years and months normalized. *

    * This normalizes the years and months units, leaving the days unit unchanged. * The months unit is adjusted to have an absolute value less than 11, @@ -778,8 +817,6 @@ * For example, a period of "1 year and -25 months" will be normalized to * "-1 year and -1 month". *

    - * This normalization uses a 12 month year which is not valid for all calendar systems. - *

    * This instance is immutable and unaffected by this method call. * * @return a {@code Period} based on this period with excess months normalized to years, not null @@ -796,13 +833,11 @@ } /** - * Gets the total number of months in this period using a 12 month year. + * Gets the total number of months in this period. *

    * This returns the total number of months in the period by multiplying the * number of years by 12 and adding the number of months. *

    - * This uses a 12 month year which is not valid for all calendar systems. - *

    * This instance is immutable and unaffected by this method call. * * @return the total number of months in the period, may be negative @@ -817,6 +852,7 @@ *

    * This returns a temporal object of the same observable type as the input * with this period added. + * If the temporal has a chronology, it must be the ISO chronology. *

    * In most cases, it is clearer to reverse the calling pattern by using * {@link Temporal#plus(TemporalAmount)}. @@ -826,10 +862,17 @@ * dateTime = dateTime.plus(thisPeriod); * *

    - * The calculation will add the years, then months, then days. - * Only non-zero amounts will be added. - * If the date-time has a calendar system with a fixed number of months in a - * year, then the years and months will be combined before being added. + * The calculation operates as follows. + * First, the chronology of the temporal is checked to ensure it is ISO chronology or null. + * Second, if the months are zero, the years are added if non-zero, otherwise + * the combination of years and months is added if non-zero. + * Finally, any days are added. + *

    + * This approach ensures that a partial period can be added to a partial date. + * For example, a period of years and/or months can be added to a {@code YearMonth}, + * but a period including days cannot. + * The approach also adds years and months together when necessary, which ensures + * correct behaviour at the end of the month. *

    * This instance is immutable and unaffected by this method call. * @@ -840,18 +883,15 @@ */ @Override public Temporal addTo(Temporal temporal) { - Objects.requireNonNull(temporal, "temporal"); - if ((years | months) != 0) { - long monthRange = monthRange(temporal); - if (monthRange >= 0) { - temporal = temporal.plus(years * monthRange + months, MONTHS); - } else { - if (years != 0) { - temporal = temporal.plus(years, YEARS); - } - if (months != 0) { - temporal = temporal.plus(months, MONTHS); - } + validateChrono(temporal); + if (months == 0) { + if (years != 0) { + temporal = temporal.plus(years, YEARS); + } + } else { + long totalMonths = toTotalMonths(); + if (totalMonths != 0) { + temporal = temporal.plus(totalMonths, MONTHS); } } if (days != 0) { @@ -865,6 +905,7 @@ *

    * This returns a temporal object of the same observable type as the input * with this period subtracted. + * If the temporal has a chronology, it must be the ISO chronology. *

    * In most cases, it is clearer to reverse the calling pattern by using * {@link Temporal#minus(TemporalAmount)}. @@ -874,10 +915,17 @@ * dateTime = dateTime.minus(thisPeriod); * *

    - * The calculation will subtract the years, then months, then days. - * Only non-zero amounts will be subtracted. - * If the date-time has a calendar system with a fixed number of months in a - * year, then the years and months will be combined before being subtracted. + * The calculation operates as follows. + * First, the chronology of the temporal is checked to ensure it is ISO chronology or null. + * Second, if the months are zero, the years are subtracted if non-zero, otherwise + * the combination of years and months is subtracted if non-zero. + * Finally, any days are subtracted. + *

    + * This approach ensures that a partial period can be subtracted from a partial date. + * For example, a period of years and/or months can be subtracted from a {@code YearMonth}, + * but a period including days cannot. + * The approach also subtracts years and months together when necessary, which ensures + * correct behaviour at the end of the month. *

    * This instance is immutable and unaffected by this method call. * @@ -888,18 +936,15 @@ */ @Override public Temporal subtractFrom(Temporal temporal) { - Objects.requireNonNull(temporal, "temporal"); - if ((years | months) != 0) { - long monthRange = monthRange(temporal); - if (monthRange >= 0) { - temporal = temporal.minus(years * monthRange + months, MONTHS); - } else { - if (years != 0) { - temporal = temporal.minus(years, YEARS); - } - if (months != 0) { - temporal = temporal.minus(months, MONTHS); - } + validateChrono(temporal); + if (months == 0) { + if (years != 0) { + temporal = temporal.minus(years, YEARS); + } + } else { + long totalMonths = toTotalMonths(); + if (totalMonths != 0) { + temporal = temporal.minus(totalMonths, MONTHS); } } if (days != 0) { @@ -909,26 +954,21 @@ } /** - * Calculates the range of months based on the temporal. - * - * @param temporal the temporal, not null - * @return the month range, negative if not fixed range + * Validates that the temporal has the correct chronology. */ - private long monthRange(Temporal temporal) { - if (temporal.isSupported(MONTH_OF_YEAR)) { - ValueRange startRange = Chronology.from(temporal).range(MONTH_OF_YEAR); - if (startRange.isFixed() && startRange.isIntValue()) { - return startRange.getMaximum() - startRange.getMinimum() + 1; - } + private void validateChrono(TemporalAccessor temporal) { + Objects.requireNonNull(temporal, "temporal"); + Chronology temporalChrono = temporal.query(TemporalQuery.chronology()); + if (temporalChrono != null && IsoChronology.INSTANCE.equals(temporalChrono) == false) { + throw new DateTimeException("Chronology mismatch, expected: ISO, actual: " + temporalChrono.getId()); } - return -1; } //----------------------------------------------------------------------- /** * Checks if this period is equal to another period. *

    - * The comparison is based on the amounts held in the period. + * The comparison is based on the type {@code Period} and each of the three amounts. * To be equal, the years, months and days units must be individually equal. * Note that this means that a period of "15 Months" is not equal to a period * of "1 Year and 3 Months". diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/Year.java --- a/jdk/src/share/classes/java/time/Year.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/Year.java Tue Oct 08 14:57:32 2013 -0700 @@ -242,6 +242,7 @@ if (temporal instanceof Year) { return (Year) temporal; } + Objects.requireNonNull(temporal, "temporal"); try { if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) { temporal = LocalDate.from(temporal); @@ -859,7 +860,8 @@ * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified year. * The result will be negative if the end is before the start. - * The {@code Temporal} passed to this method must be a {@code Year}. + * The {@code Temporal} passed to this method is converted to a + * {@code Year} using {@link #from(TemporalAccessor)}. * For example, the period in decades between two year can be calculated * using {@code startYear.until(endYear, DECADES)}. *

    @@ -885,25 +887,22 @@ *

    * If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

    * This instance is immutable and unaffected by this method call. * - * @param endYear the end year, which must be a {@code Year}, not null + * @param endExclusive the end date, exclusive, which is converted to a {@code Year}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this year and the end year - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code Year} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endYear, TemporalUnit unit) { - if (endYear instanceof Year == false) { - Objects.requireNonNull(endYear, "endYear"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } - Year end = (Year) endYear; + public long until(Temporal endExclusive, TemporalUnit unit) { + Year end = Year.from(endExclusive); if (unit instanceof ChronoUnit) { long yearsUntil = ((long) end.year) - year; // no overflow switch ((ChronoUnit) unit) { @@ -915,7 +914,7 @@ } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return unit.between(this, endYear); + return unit.between(this, end); } /** diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/YearMonth.java --- a/jdk/src/share/classes/java/time/YearMonth.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/YearMonth.java Tue Oct 08 14:57:32 2013 -0700 @@ -245,6 +245,7 @@ if (temporal instanceof YearMonth) { return (YearMonth) temporal; } + Objects.requireNonNull(temporal, "temporal"); try { if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) { temporal = LocalDate.from(temporal); @@ -992,7 +993,8 @@ * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified year-month. * The result will be negative if the end is before the start. - * The {@code Temporal} passed to this method must be a {@code YearMonth}. + * The {@code Temporal} passed to this method is converted to a + * {@code YearMonth} using {@link #from(TemporalAccessor)}. * For example, the period in years between two year-months can be calculated * using {@code startYearMonth.until(endYearMonth, YEARS)}. *

    @@ -1018,25 +1020,22 @@ *

    * If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

    * This instance is immutable and unaffected by this method call. * - * @param endYearMonth the end year-month, which must be a {@code YearMonth}, not null + * @param endExclusive the end date, exclusive, which is converted to a {@code YearMonth}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this year-month and the end year-month - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code YearMonth} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endYearMonth, TemporalUnit unit) { - if (endYearMonth instanceof YearMonth == false) { - Objects.requireNonNull(endYearMonth, "endYearMonth"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } - YearMonth end = (YearMonth) endYearMonth; + public long until(Temporal endExclusive, TemporalUnit unit) { + YearMonth end = YearMonth.from(endExclusive); if (unit instanceof ChronoUnit) { long monthsUntil = end.getProlepticMonth() - getProlepticMonth(); // no overflow switch ((ChronoUnit) unit) { @@ -1049,7 +1048,7 @@ } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return unit.between(this, endYearMonth); + return unit.between(this, end); } /** diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/ZoneOffset.java --- a/jdk/src/share/classes/java/time/ZoneOffset.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/ZoneOffset.java Tue Oct 08 14:57:32 2013 -0700 @@ -333,6 +333,7 @@ * @throws DateTimeException if unable to convert to an {@code ZoneOffset} */ public static ZoneOffset from(TemporalAccessor temporal) { + Objects.requireNonNull(temporal, "temporal"); ZoneOffset offset = temporal.query(TemporalQuery.offset()); if (offset == null) { throw new DateTimeException("Unable to obtain ZoneOffset from TemporalAccessor: " + temporal.getClass()); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/ZonedDateTime.java --- a/jdk/src/share/classes/java/time/ZonedDateTime.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/ZonedDateTime.java Tue Oct 08 14:57:32 2013 -0700 @@ -1540,6 +1540,11 @@ */ @Override public ZonedDateTime plus(TemporalAmount amountToAdd) { + if (amountToAdd instanceof Period) { + Period periodToAdd = (Period) amountToAdd; + return resolveLocal(dateTime.plus(periodToAdd)); + } + Objects.requireNonNull(amountToAdd, "amountToAdd"); return (ZonedDateTime) amountToAdd.addTo(this); } @@ -1787,6 +1792,11 @@ */ @Override public ZonedDateTime minus(TemporalAmount amountToSubtract) { + if (amountToSubtract instanceof Period) { + Period periodToSubtract = (Period) amountToSubtract; + return resolveLocal(dateTime.minus(periodToSubtract)); + } + Objects.requireNonNull(amountToSubtract, "amountToSubtract"); return (ZonedDateTime) amountToSubtract.subtractFrom(this); } @@ -2034,7 +2044,8 @@ * For example, the period in days between two date-times can be calculated * using {@code startDateTime.until(endDateTime, DAYS)}. *

    - * The {@code Temporal} passed to this method must be a {@code ZonedDateTime}. + * The {@code Temporal} passed to this method is converted to a + * {@code ZonedDateTime} using {@link #from(TemporalAccessor)}. * If the time-zone differs between the two zoned date-times, the specified * end date-time is normalized to have the same zone as this date-time. *

    @@ -2076,26 +2087,23 @@ *

    * If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

    * This instance is immutable and unaffected by this method call. * - * @param endDateTime the end date-time, which must be a {@code ZonedDateTime}, not null + * @param endExclusive the end date, exclusive, which is converted to a {@code ZonedDateTime}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this date-time and the end date-time - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code ZonedDateTime} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endDateTime, TemporalUnit unit) { - if (endDateTime instanceof ZonedDateTime == false) { - Objects.requireNonNull(endDateTime, "endDateTime"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } + public long until(Temporal endExclusive, TemporalUnit unit) { + ZonedDateTime end = ZonedDateTime.from(endExclusive); if (unit instanceof ChronoUnit) { - ZonedDateTime end = (ZonedDateTime) endDateTime; end = end.withZoneSameInstant(zone); if (unit.isDateBased()) { return dateTime.until(end.dateTime, unit); @@ -2103,7 +2111,7 @@ return toOffsetDateTime().until(end.toOffsetDateTime(), unit); } } - return unit.between(this, endDateTime); + return unit.between(this, end); } /** diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/ChronoDateImpl.java --- a/jdk/src/share/classes/java/time/chrono/ChronoDateImpl.java Tue Oct 08 14:53:14 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,455 +0,0 @@ -/* - * Copyright (c) 2012, 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. - */ - -/* - * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of JSR-310 nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package java.time.chrono; - -import static java.time.temporal.ChronoField.DAY_OF_MONTH; -import static java.time.temporal.ChronoField.ERA; -import static java.time.temporal.ChronoField.MONTH_OF_YEAR; -import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; -import static java.time.temporal.ChronoField.YEAR_OF_ERA; - -import java.io.Serializable; -import java.time.DateTimeException; -import java.time.temporal.ChronoUnit; -import java.time.temporal.Temporal; -import java.time.temporal.TemporalAdjuster; -import java.time.temporal.TemporalAmount; -import java.time.temporal.TemporalField; -import java.time.temporal.TemporalUnit; -import java.time.temporal.UnsupportedTemporalTypeException; -import java.time.temporal.ValueRange; -import java.util.Objects; - -/** - * A date expressed in terms of a standard year-month-day calendar system. - *

    - * This class is used by applications seeking to handle dates in non-ISO calendar systems. - * For example, the Japanese, Minguo, Thai Buddhist and others. - *

    - * {@code ChronoLocalDate} is built on the generic concepts of year, month and day. - * The calendar system, represented by a {@link java.time.chrono.Chronology}, expresses the relationship between - * the fields and this class allows the resulting date to be manipulated. - *

    - * Note that not all calendar systems are suitable for use with this class. - * For example, the Mayan calendar uses a system that bears no relation to years, months and days. - *

    - * The API design encourages the use of {@code LocalDate} for the majority of the application. - * This includes code to read and write from a persistent data store, such as a database, - * and to send dates and times across a network. The {@code ChronoLocalDate} instance is then used - * at the user interface level to deal with localized input/output. - * - *

    Example:

    - *
    - *        System.out.printf("Example()%n");
    - *        // Enumerate the list of available calendars and print today for each
    - *        Set<Chronology> chronos = Chronology.getAvailableChronologies();
    - *        for (Chronology chrono : chronos) {
    - *            ChronoLocalDate date = chrono.dateNow();
    - *            System.out.printf("   %20s: %s%n", chrono.getID(), date.toString());
    - *        }
    - *
    - *        // Print the Hijrah date and calendar
    - *        ChronoLocalDate date = Chronology.of("Hijrah").dateNow();
    - *        int day = date.get(ChronoField.DAY_OF_MONTH);
    - *        int dow = date.get(ChronoField.DAY_OF_WEEK);
    - *        int month = date.get(ChronoField.MONTH_OF_YEAR);
    - *        int year = date.get(ChronoField.YEAR);
    - *        System.out.printf("  Today is %s %s %d-%s-%d%n", date.getChronology().getID(),
    - *                dow, day, month, year);
    -
    - *        // Print today's date and the last day of the year
    - *        ChronoLocalDate now1 = Chronology.of("Hijrah").dateNow();
    - *        ChronoLocalDate first = now1.with(ChronoField.DAY_OF_MONTH, 1)
    - *                .with(ChronoField.MONTH_OF_YEAR, 1);
    - *        ChronoLocalDate last = first.plus(1, ChronoUnit.YEARS)
    - *                .minus(1, ChronoUnit.DAYS);
    - *        System.out.printf("  Today is %s: start: %s; end: %s%n", last.getChronology().getID(),
    - *                first, last);
    - * 
    - * - *

    Adding Calendars

    - *

    The set of calendars is extensible by defining a subclass of {@link ChronoLocalDate} - * to represent a date instance and an implementation of {@code Chronology} - * to be the factory for the ChronoLocalDate subclass. - *

    - *

    To permit the discovery of the additional calendar types the implementation of - * {@code Chronology} must be registered as a Service implementing the {@code Chronology} interface - * in the {@code META-INF/Services} file as per the specification of {@link java.util.ServiceLoader}. - * The subclass must function according to the {@code Chronology} class description and must provide its - * {@link java.time.chrono.Chronology#getId() chronlogy ID} and {@link Chronology#getCalendarType() calendar type}.

    - * - * @implSpec - * This abstract class must be implemented with care to ensure other classes operate correctly. - * All implementations that can be instantiated must be final, immutable and thread-safe. - * Subclasses should be Serializable wherever possible. - * - * @param the ChronoLocalDate of this date-time - * @since 1.8 - */ -abstract class ChronoDateImpl - implements ChronoLocalDate, Temporal, TemporalAdjuster, Serializable { - - /** - * Serialization version. - */ - private static final long serialVersionUID = 6282433883239719096L; - - /** - * Casts the {@code Temporal} to {@code ChronoLocalDate} ensuring it bas the specified chronology. - * - * @param chrono the chronology to check for, not null - * @param temporal a date-time to cast, not null - * @return the date-time checked and cast to {@code ChronoLocalDate}, not null - * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate - * or the chronology is not equal this Chronology - */ - static D ensureValid(Chronology chrono, Temporal temporal) { - @SuppressWarnings("unchecked") - D other = (D) temporal; - if (chrono.equals(other.getChronology()) == false) { - throw new ClassCastException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + other.getChronology().getId()); - } - return other; - } - - //----------------------------------------------------------------------- - /** - * Creates an instance. - */ - ChronoDateImpl() { - } - - @Override - @SuppressWarnings("unchecked") - public D with(TemporalAdjuster adjuster) { - return (D) ChronoLocalDate.super.with(adjuster); - } - - @Override - @SuppressWarnings("unchecked") - public D with(TemporalField field, long value) { - return (D) ChronoLocalDate.super.with(field, value); - } - - //----------------------------------------------------------------------- - @Override - @SuppressWarnings("unchecked") - public D plus(TemporalAmount amount) { - return (D) ChronoLocalDate.super.plus(amount); - } - - //----------------------------------------------------------------------- - @Override - @SuppressWarnings("unchecked") - public D plus(long amountToAdd, TemporalUnit unit) { - if (unit instanceof ChronoUnit) { - ChronoUnit f = (ChronoUnit) unit; - switch (f) { - case DAYS: return plusDays(amountToAdd); - case WEEKS: return plusDays(Math.multiplyExact(amountToAdd, 7)); - case MONTHS: return plusMonths(amountToAdd); - case YEARS: return plusYears(amountToAdd); - case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10)); - case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100)); - case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000)); - case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd)); - } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); - } - return (D) ChronoLocalDate.super.plus(amountToAdd, unit); - } - - @Override - @SuppressWarnings("unchecked") - public D minus(TemporalAmount amount) { - return (D) ChronoLocalDate.super.minus(amount); - } - - @Override - @SuppressWarnings("unchecked") - public D minus(long amountToSubtract, TemporalUnit unit) { - return (D) ChronoLocalDate.super.minus(amountToSubtract, unit); - } - - //----------------------------------------------------------------------- - /** - * Returns a copy of this date with the specified period in years added. - *

    - * This adds the specified period in years to the date. - * In some cases, adding years can cause the resulting date to become invalid. - * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure - * that the result is valid. Typically this will select the last valid day of the month. - *

    - * This instance is immutable and unaffected by this method call. - * - * @param yearsToAdd the years to add, may be negative - * @return a date based on this one with the years added, not null - * @throws DateTimeException if the result exceeds the supported date range - */ - abstract D plusYears(long yearsToAdd); - - /** - * Returns a copy of this date with the specified period in months added. - *

    - * This adds the specified period in months to the date. - * In some cases, adding months can cause the resulting date to become invalid. - * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure - * that the result is valid. Typically this will select the last valid day of the month. - *

    - * This instance is immutable and unaffected by this method call. - * - * @param monthsToAdd the months to add, may be negative - * @return a date based on this one with the months added, not null - * @throws DateTimeException if the result exceeds the supported date range - */ - abstract D plusMonths(long monthsToAdd); - - /** - * Returns a copy of this date with the specified period in weeks added. - *

    - * This adds the specified period in weeks to the date. - * In some cases, adding weeks can cause the resulting date to become invalid. - * If this occurs, then other fields will be adjusted to ensure that the result is valid. - *

    - * The default implementation uses {@link #plusDays(long)} using a 7 day week. - *

    - * This instance is immutable and unaffected by this method call. - * - * @param weeksToAdd the weeks to add, may be negative - * @return a date based on this one with the weeks added, not null - * @throws DateTimeException if the result exceeds the supported date range - */ - D plusWeeks(long weeksToAdd) { - return plusDays(Math.multiplyExact(weeksToAdd, 7)); - } - - /** - * Returns a copy of this date with the specified number of days added. - *

    - * This adds the specified period in days to the date. - *

    - * This instance is immutable and unaffected by this method call. - * - * @param daysToAdd the days to add, may be negative - * @return a date based on this one with the days added, not null - * @throws DateTimeException if the result exceeds the supported date range - */ - abstract D plusDays(long daysToAdd); - - //----------------------------------------------------------------------- - /** - * Returns a copy of this date with the specified period in years subtracted. - *

    - * This subtracts the specified period in years to the date. - * In some cases, subtracting years can cause the resulting date to become invalid. - * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure - * that the result is valid. Typically this will select the last valid day of the month. - *

    - * The default implementation uses {@link #plusYears(long)}. - *

    - * This instance is immutable and unaffected by this method call. - * - * @param yearsToSubtract the years to subtract, may be negative - * @return a date based on this one with the years subtracted, not null - * @throws DateTimeException if the result exceeds the supported date range - */ - @SuppressWarnings("unchecked") - D minusYears(long yearsToSubtract) { - return (yearsToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusYears(Long.MAX_VALUE)).plusYears(1) : plusYears(-yearsToSubtract)); - } - - /** - * Returns a copy of this date with the specified period in months subtracted. - *

    - * This subtracts the specified period in months to the date. - * In some cases, subtracting months can cause the resulting date to become invalid. - * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure - * that the result is valid. Typically this will select the last valid day of the month. - *

    - * The default implementation uses {@link #plusMonths(long)}. - *

    - * This instance is immutable and unaffected by this method call. - * - * @param monthsToSubtract the months to subtract, may be negative - * @return a date based on this one with the months subtracted, not null - * @throws DateTimeException if the result exceeds the supported date range - */ - @SuppressWarnings("unchecked") - D minusMonths(long monthsToSubtract) { - return (monthsToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusMonths(Long.MAX_VALUE)).plusMonths(1) : plusMonths(-monthsToSubtract)); - } - - /** - * Returns a copy of this date with the specified period in weeks subtracted. - *

    - * This subtracts the specified period in weeks to the date. - * In some cases, subtracting weeks can cause the resulting date to become invalid. - * If this occurs, then other fields will be adjusted to ensure that the result is valid. - *

    - * The default implementation uses {@link #plusWeeks(long)}. - *

    - * This instance is immutable and unaffected by this method call. - * - * @param weeksToSubtract the weeks to subtract, may be negative - * @return a date based on this one with the weeks subtracted, not null - * @throws DateTimeException if the result exceeds the supported date range - */ - @SuppressWarnings("unchecked") - D minusWeeks(long weeksToSubtract) { - return (weeksToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusWeeks(Long.MAX_VALUE)).plusWeeks(1) : plusWeeks(-weeksToSubtract)); - } - - /** - * Returns a copy of this date with the specified number of days subtracted. - *

    - * This subtracts the specified period in days to the date. - *

    - * The default implementation uses {@link #plusDays(long)}. - *

    - * This instance is immutable and unaffected by this method call. - * - * @param daysToSubtract the days to subtract, may be negative - * @return a date based on this one with the days subtracted, not null - * @throws DateTimeException if the result exceeds the supported date range - */ - @SuppressWarnings("unchecked") - D minusDays(long daysToSubtract) { - return (daysToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusDays(Long.MAX_VALUE)).plusDays(1) : plusDays(-daysToSubtract)); - } - - //----------------------------------------------------------------------- - /** - * {@inheritDoc} - * @throws DateTimeException {@inheritDoc} - * @throws ArithmeticException {@inheritDoc} - */ - @Override - public long until(Temporal endDateTime, TemporalUnit unit) { - Objects.requireNonNull(endDateTime, "endDateTime"); - Objects.requireNonNull(unit, "unit"); - if (endDateTime instanceof ChronoLocalDate == false) { - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } - ChronoLocalDate end = (ChronoLocalDate) endDateTime; - if (getChronology().equals(end.getChronology()) == false) { - throw new DateTimeException("Unable to calculate amount as objects have different chronologies"); - } - if (unit instanceof ChronoUnit) { - switch ((ChronoUnit) unit) { - case DAYS: return daysUntil(end); - case WEEKS: return daysUntil(end) / 7; - case MONTHS: return monthsUntil(end); - case YEARS: return monthsUntil(end) / 12; - case DECADES: return monthsUntil(end) / 120; - case CENTURIES: return monthsUntil(end) / 1200; - case MILLENNIA: return monthsUntil(end) / 12000; - case ERAS: return end.getLong(ERA) - getLong(ERA); - } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); - } - return unit.between(this, endDateTime); - } - - private long daysUntil(ChronoLocalDate end) { - return end.toEpochDay() - toEpochDay(); // no overflow - } - - private long monthsUntil(ChronoLocalDate end) { - ValueRange range = getChronology().range(MONTH_OF_YEAR); - if (range.getMaximum() != 12) { - throw new IllegalStateException("ChronoDateImpl only supports Chronologies with 12 months per year"); - } - long packed1 = getLong(PROLEPTIC_MONTH) * 32L + get(DAY_OF_MONTH); // no overflow - long packed2 = end.getLong(PROLEPTIC_MONTH) * 32L + end.get(DAY_OF_MONTH); // no overflow - return (packed2 - packed1) / 32; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof ChronoLocalDate) { - return compareTo((ChronoLocalDate) obj) == 0; - } - return false; - } - - @Override - public int hashCode() { - long epDay = toEpochDay(); - return getChronology().hashCode() ^ ((int) (epDay ^ (epDay >>> 32))); - } - - @Override - public String toString() { - // getLong() reduces chances of exceptions in toString() - long yoe = getLong(YEAR_OF_ERA); - long moy = getLong(MONTH_OF_YEAR); - long dom = getLong(DAY_OF_MONTH); - StringBuilder buf = new StringBuilder(30); - buf.append(getChronology().toString()) - .append(" ") - .append(getEra()) - .append(" ") - .append(yoe) - .append(moy < 10 ? "-0" : "-").append(moy) - .append(dom < 10 ? "-0" : "-").append(dom); - return buf.toString(); - } - -} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java --- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java Tue Oct 08 14:57:32 2013 -0700 @@ -69,7 +69,6 @@ import java.time.DateTimeException; import java.time.LocalDate; import java.time.LocalTime; -import java.time.Period; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; @@ -292,6 +291,7 @@ if (temporal instanceof ChronoLocalDate) { return (ChronoLocalDate) temporal; } + Objects.requireNonNull(temporal, "temporal"); Chronology chrono = temporal.query(TemporalQuery.chronology()); if (chrono == null) { throw new DateTimeException("Unable to obtain ChronoLocalDate from TemporalAccessor: " + temporal.getClass()); @@ -428,7 +428,7 @@ */ @Override default ChronoLocalDate with(TemporalAdjuster adjuster) { - return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.with(adjuster)); + return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.with(adjuster)); } /** @@ -442,7 +442,7 @@ if (field instanceof ChronoField) { throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } - return ChronoDateImpl.ensureValid(getChronology(), field.adjustInto(this, newValue)); + return ChronoLocalDateImpl.ensureValid(getChronology(), field.adjustInto(this, newValue)); } /** @@ -452,7 +452,7 @@ */ @Override default ChronoLocalDate plus(TemporalAmount amount) { - return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.plus(amount)); + return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.plus(amount)); } /** @@ -465,7 +465,7 @@ if (unit instanceof ChronoUnit) { throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return ChronoDateImpl.ensureValid(getChronology(), unit.addTo(this, amountToAdd)); + return ChronoLocalDateImpl.ensureValid(getChronology(), unit.addTo(this, amountToAdd)); } /** @@ -475,7 +475,7 @@ */ @Override default ChronoLocalDate minus(TemporalAmount amount) { - return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.minus(amount)); + return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.minus(amount)); } /** @@ -486,7 +486,7 @@ */ @Override default ChronoLocalDate minus(long amountToSubtract, TemporalUnit unit) { - return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit)); + return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit)); } //----------------------------------------------------------------------- @@ -561,8 +561,8 @@ * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified date. * The result will be negative if the end is before the start. - * The {@code Temporal} passed to this method must be a - * {@code ChronoLocalDate} in the same chronology. + * The {@code Temporal} passed to this method is converted to a + * {@code ChronoLocalDate} using {@link Chronology#date(TemporalAccessor)}. * The calculation returns a whole number, representing the number of * complete units between the two dates. * For example, the amount in days between two dates can be calculated @@ -586,25 +586,30 @@ *

    * If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as + * passing {@code this} as the first argument and the converted input temporal as * the second argument. *

    * This instance is immutable and unaffected by this method call. * - * @param endDate the end date, which must be a {@code ChronoLocalDate} - * in the same chronology, not null + * @param endExclusive the end date, exclusive, which is converted to a + * {@code ChronoLocalDate} in the same chronology, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this date and the end date - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code ChronoLocalDate} + * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override // override for Javadoc - long until(Temporal endDate, TemporalUnit unit); + long until(Temporal endExclusive, TemporalUnit unit); /** - * Calculates the period between this date and another date as a {@code Period}. + * Calculates the period between this date and another date as a {@code ChronoPeriod}. *

    - * This calculates the period between two dates in terms of years, months and days. + * This calculates the period between two dates. All supplied chronologies + * calculate the period using years, months and days, however the + * {@code ChronoPeriod} API allows the period to be represented using other units. + *

    * The start and end points are {@code this} and the specified date. * The result will be negative if the end is before the start. * The negative sign will be the same in each of year, month and day. @@ -614,12 +619,12 @@ *

    * This instance is immutable and unaffected by this method call. * - * @param endDate the end date, exclusive, which may be in any chronology, not null + * @param endDateExclusive the end date, exclusive, which may be in any chronology, not null * @return the period between this date and the end date, not null * @throws DateTimeException if the period cannot be calculated * @throws ArithmeticException if numeric overflow occurs */ - Period until(ChronoLocalDate endDate); + ChronoPeriod until(ChronoLocalDate endDateExclusive); /** * Formats this date using the specified formatter. diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/ChronoLocalDateImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateImpl.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2012, 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. + */ + +/* + * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package java.time.chrono; + +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.ERA; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; + +import java.io.Serializable; +import java.time.DateTimeException; +import java.time.temporal.ChronoUnit; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalUnit; +import java.time.temporal.UnsupportedTemporalTypeException; +import java.time.temporal.ValueRange; +import java.util.Objects; + +/** + * A date expressed in terms of a standard year-month-day calendar system. + *

    + * This class is used by applications seeking to handle dates in non-ISO calendar systems. + * For example, the Japanese, Minguo, Thai Buddhist and others. + *

    + * {@code ChronoLocalDate} is built on the generic concepts of year, month and day. + * The calendar system, represented by a {@link java.time.chrono.Chronology}, expresses the relationship between + * the fields and this class allows the resulting date to be manipulated. + *

    + * Note that not all calendar systems are suitable for use with this class. + * For example, the Mayan calendar uses a system that bears no relation to years, months and days. + *

    + * The API design encourages the use of {@code LocalDate} for the majority of the application. + * This includes code to read and write from a persistent data store, such as a database, + * and to send dates and times across a network. The {@code ChronoLocalDate} instance is then used + * at the user interface level to deal with localized input/output. + * + *

    Example:

    + *
    + *        System.out.printf("Example()%n");
    + *        // Enumerate the list of available calendars and print today for each
    + *        Set<Chronology> chronos = Chronology.getAvailableChronologies();
    + *        for (Chronology chrono : chronos) {
    + *            ChronoLocalDate date = chrono.dateNow();
    + *            System.out.printf("   %20s: %s%n", chrono.getID(), date.toString());
    + *        }
    + *
    + *        // Print the Hijrah date and calendar
    + *        ChronoLocalDate date = Chronology.of("Hijrah").dateNow();
    + *        int day = date.get(ChronoField.DAY_OF_MONTH);
    + *        int dow = date.get(ChronoField.DAY_OF_WEEK);
    + *        int month = date.get(ChronoField.MONTH_OF_YEAR);
    + *        int year = date.get(ChronoField.YEAR);
    + *        System.out.printf("  Today is %s %s %d-%s-%d%n", date.getChronology().getID(),
    + *                dow, day, month, year);
    +
    + *        // Print today's date and the last day of the year
    + *        ChronoLocalDate now1 = Chronology.of("Hijrah").dateNow();
    + *        ChronoLocalDate first = now1.with(ChronoField.DAY_OF_MONTH, 1)
    + *                .with(ChronoField.MONTH_OF_YEAR, 1);
    + *        ChronoLocalDate last = first.plus(1, ChronoUnit.YEARS)
    + *                .minus(1, ChronoUnit.DAYS);
    + *        System.out.printf("  Today is %s: start: %s; end: %s%n", last.getChronology().getID(),
    + *                first, last);
    + * 
    + * + *

    Adding Calendars

    + *

    The set of calendars is extensible by defining a subclass of {@link ChronoLocalDate} + * to represent a date instance and an implementation of {@code Chronology} + * to be the factory for the ChronoLocalDate subclass. + *

    + *

    To permit the discovery of the additional calendar types the implementation of + * {@code Chronology} must be registered as a Service implementing the {@code Chronology} interface + * in the {@code META-INF/Services} file as per the specification of {@link java.util.ServiceLoader}. + * The subclass must function according to the {@code Chronology} class description and must provide its + * {@link java.time.chrono.Chronology#getId() chronlogy ID} and {@link Chronology#getCalendarType() calendar type}.

    + * + * @implSpec + * This abstract class must be implemented with care to ensure other classes operate correctly. + * All implementations that can be instantiated must be final, immutable and thread-safe. + * Subclasses should be Serializable wherever possible. + * + * @param the ChronoLocalDate of this date-time + * @since 1.8 + */ +abstract class ChronoLocalDateImpl + implements ChronoLocalDate, Temporal, TemporalAdjuster, Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = 6282433883239719096L; + + /** + * Casts the {@code Temporal} to {@code ChronoLocalDate} ensuring it bas the specified chronology. + * + * @param chrono the chronology to check for, not null + * @param temporal a date-time to cast, not null + * @return the date-time checked and cast to {@code ChronoLocalDate}, not null + * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate + * or the chronology is not equal this Chronology + */ + static D ensureValid(Chronology chrono, Temporal temporal) { + @SuppressWarnings("unchecked") + D other = (D) temporal; + if (chrono.equals(other.getChronology()) == false) { + throw new ClassCastException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + other.getChronology().getId()); + } + return other; + } + + //----------------------------------------------------------------------- + /** + * Creates an instance. + */ + ChronoLocalDateImpl() { + } + + @Override + @SuppressWarnings("unchecked") + public D with(TemporalAdjuster adjuster) { + return (D) ChronoLocalDate.super.with(adjuster); + } + + @Override + @SuppressWarnings("unchecked") + public D with(TemporalField field, long value) { + return (D) ChronoLocalDate.super.with(field, value); + } + + //----------------------------------------------------------------------- + @Override + @SuppressWarnings("unchecked") + public D plus(TemporalAmount amount) { + return (D) ChronoLocalDate.super.plus(amount); + } + + //----------------------------------------------------------------------- + @Override + @SuppressWarnings("unchecked") + public D plus(long amountToAdd, TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + ChronoUnit f = (ChronoUnit) unit; + switch (f) { + case DAYS: return plusDays(amountToAdd); + case WEEKS: return plusDays(Math.multiplyExact(amountToAdd, 7)); + case MONTHS: return plusMonths(amountToAdd); + case YEARS: return plusYears(amountToAdd); + case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10)); + case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100)); + case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000)); + case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd)); + } + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); + } + return (D) ChronoLocalDate.super.plus(amountToAdd, unit); + } + + @Override + @SuppressWarnings("unchecked") + public D minus(TemporalAmount amount) { + return (D) ChronoLocalDate.super.minus(amount); + } + + @Override + @SuppressWarnings("unchecked") + public D minus(long amountToSubtract, TemporalUnit unit) { + return (D) ChronoLocalDate.super.minus(amountToSubtract, unit); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the specified period in years added. + *

    + * This adds the specified period in years to the date. + * In some cases, adding years can cause the resulting date to become invalid. + * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure + * that the result is valid. Typically this will select the last valid day of the month. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param yearsToAdd the years to add, may be negative + * @return a date based on this one with the years added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + abstract D plusYears(long yearsToAdd); + + /** + * Returns a copy of this date with the specified period in months added. + *

    + * This adds the specified period in months to the date. + * In some cases, adding months can cause the resulting date to become invalid. + * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure + * that the result is valid. Typically this will select the last valid day of the month. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param monthsToAdd the months to add, may be negative + * @return a date based on this one with the months added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + abstract D plusMonths(long monthsToAdd); + + /** + * Returns a copy of this date with the specified period in weeks added. + *

    + * This adds the specified period in weeks to the date. + * In some cases, adding weeks can cause the resulting date to become invalid. + * If this occurs, then other fields will be adjusted to ensure that the result is valid. + *

    + * The default implementation uses {@link #plusDays(long)} using a 7 day week. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param weeksToAdd the weeks to add, may be negative + * @return a date based on this one with the weeks added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + D plusWeeks(long weeksToAdd) { + return plusDays(Math.multiplyExact(weeksToAdd, 7)); + } + + /** + * Returns a copy of this date with the specified number of days added. + *

    + * This adds the specified period in days to the date. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param daysToAdd the days to add, may be negative + * @return a date based on this one with the days added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + abstract D plusDays(long daysToAdd); + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date with the specified period in years subtracted. + *

    + * This subtracts the specified period in years to the date. + * In some cases, subtracting years can cause the resulting date to become invalid. + * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure + * that the result is valid. Typically this will select the last valid day of the month. + *

    + * The default implementation uses {@link #plusYears(long)}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param yearsToSubtract the years to subtract, may be negative + * @return a date based on this one with the years subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + @SuppressWarnings("unchecked") + D minusYears(long yearsToSubtract) { + return (yearsToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl)plusYears(Long.MAX_VALUE)).plusYears(1) : plusYears(-yearsToSubtract)); + } + + /** + * Returns a copy of this date with the specified period in months subtracted. + *

    + * This subtracts the specified period in months to the date. + * In some cases, subtracting months can cause the resulting date to become invalid. + * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure + * that the result is valid. Typically this will select the last valid day of the month. + *

    + * The default implementation uses {@link #plusMonths(long)}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param monthsToSubtract the months to subtract, may be negative + * @return a date based on this one with the months subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + @SuppressWarnings("unchecked") + D minusMonths(long monthsToSubtract) { + return (monthsToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl)plusMonths(Long.MAX_VALUE)).plusMonths(1) : plusMonths(-monthsToSubtract)); + } + + /** + * Returns a copy of this date with the specified period in weeks subtracted. + *

    + * This subtracts the specified period in weeks to the date. + * In some cases, subtracting weeks can cause the resulting date to become invalid. + * If this occurs, then other fields will be adjusted to ensure that the result is valid. + *

    + * The default implementation uses {@link #plusWeeks(long)}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param weeksToSubtract the weeks to subtract, may be negative + * @return a date based on this one with the weeks subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + @SuppressWarnings("unchecked") + D minusWeeks(long weeksToSubtract) { + return (weeksToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl)plusWeeks(Long.MAX_VALUE)).plusWeeks(1) : plusWeeks(-weeksToSubtract)); + } + + /** + * Returns a copy of this date with the specified number of days subtracted. + *

    + * This subtracts the specified period in days to the date. + *

    + * The default implementation uses {@link #plusDays(long)}. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param daysToSubtract the days to subtract, may be negative + * @return a date based on this one with the days subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + @SuppressWarnings("unchecked") + D minusDays(long daysToSubtract) { + return (daysToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl)plusDays(Long.MAX_VALUE)).plusDays(1) : plusDays(-daysToSubtract)); + } + + //----------------------------------------------------------------------- + @Override + public long until(Temporal endExclusive, TemporalUnit unit) { + Objects.requireNonNull(endExclusive, "endExclusive"); + ChronoLocalDate end = getChronology().date(endExclusive); + if (unit instanceof ChronoUnit) { + switch ((ChronoUnit) unit) { + case DAYS: return daysUntil(end); + case WEEKS: return daysUntil(end) / 7; + case MONTHS: return monthsUntil(end); + case YEARS: return monthsUntil(end) / 12; + case DECADES: return monthsUntil(end) / 120; + case CENTURIES: return monthsUntil(end) / 1200; + case MILLENNIA: return monthsUntil(end) / 12000; + case ERAS: return end.getLong(ERA) - getLong(ERA); + } + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); + } + Objects.requireNonNull(unit, "unit"); + return unit.between(this, end); + } + + private long daysUntil(ChronoLocalDate end) { + return end.toEpochDay() - toEpochDay(); // no overflow + } + + private long monthsUntil(ChronoLocalDate end) { + ValueRange range = getChronology().range(MONTH_OF_YEAR); + if (range.getMaximum() != 12) { + throw new IllegalStateException("ChronoLocalDateImpl only supports Chronologies with 12 months per year"); + } + long packed1 = getLong(PROLEPTIC_MONTH) * 32L + get(DAY_OF_MONTH); // no overflow + long packed2 = end.getLong(PROLEPTIC_MONTH) * 32L + end.get(DAY_OF_MONTH); // no overflow + return (packed2 - packed1) / 32; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ChronoLocalDate) { + return compareTo((ChronoLocalDate) obj) == 0; + } + return false; + } + + @Override + public int hashCode() { + long epDay = toEpochDay(); + return getChronology().hashCode() ^ ((int) (epDay ^ (epDay >>> 32))); + } + + @Override + public String toString() { + // getLong() reduces chances of exceptions in toString() + long yoe = getLong(YEAR_OF_ERA); + long moy = getLong(MONTH_OF_YEAR); + long dom = getLong(DAY_OF_MONTH); + StringBuilder buf = new StringBuilder(30); + buf.append(getChronology().toString()) + .append(" ") + .append(getEra()) + .append(" ") + .append(yoe) + .append(moy < 10 ? "-0" : "-").append(moy) + .append(dom < 10 ? "-0" : "-").append(dom); + return buf.toString(); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java --- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java Tue Oct 08 14:57:32 2013 -0700 @@ -165,6 +165,7 @@ if (temporal instanceof ChronoLocalDateTime) { return (ChronoLocalDateTime) temporal; } + Objects.requireNonNull(temporal, "temporal"); Chronology chrono = temporal.query(TemporalQuery.chronology()); if (chrono == null) { throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " + temporal.getClass()); @@ -174,6 +175,18 @@ //----------------------------------------------------------------------- /** + * Gets the chronology of this date-time. + *

    + * The {@code Chronology} represents the calendar system in use. + * The era and other fields in {@link ChronoField} are defined by the chronology. + * + * @return the chronology, not null + */ + default Chronology getChronology() { + return toLocalDate().getChronology(); + } + + /** * Gets the local date part of this date-time. *

    * This returns a local date with the same year, month and day @@ -250,7 +263,7 @@ */ @Override default ChronoLocalDateTime with(TemporalAdjuster adjuster) { - return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.with(adjuster)); + return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.with(adjuster)); } /** @@ -268,7 +281,7 @@ */ @Override default ChronoLocalDateTime plus(TemporalAmount amount) { - return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.plus(amount)); + return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.plus(amount)); } /** @@ -286,7 +299,7 @@ */ @Override default ChronoLocalDateTime minus(TemporalAmount amount) { - return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amount)); + return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amount)); } /** @@ -296,7 +309,7 @@ */ @Override default ChronoLocalDateTime minus(long amountToSubtract, TemporalUnit unit) { - return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amountToSubtract, unit)); + return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit)); } //----------------------------------------------------------------------- @@ -326,7 +339,7 @@ } else if (query == TemporalQuery.localTime()) { return (R) toLocalTime(); } else if (query == TemporalQuery.chronology()) { - return (R) toLocalDate().getChronology(); + return (R) getChronology(); } else if (query == TemporalQuery.precision()) { return (R) NANOS; } @@ -488,7 +501,7 @@ if (cmp == 0) { cmp = toLocalTime().compareTo(other.toLocalTime()); if (cmp == 0) { - cmp = toLocalDate().getChronology().compareTo(other.toLocalDate().getChronology()); + cmp = getChronology().compareTo(other.getChronology()); } } return cmp; diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java --- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java Tue Oct 08 14:57:32 2013 -0700 @@ -69,7 +69,6 @@ import java.io.ObjectOutput; import java.io.ObjectStreamException; import java.io.Serializable; -import java.time.DateTimeException; import java.time.LocalTime; import java.time.ZoneId; import java.time.temporal.ChronoField; @@ -187,9 +186,9 @@ static ChronoLocalDateTimeImpl ensureValid(Chronology chrono, Temporal temporal) { @SuppressWarnings("unchecked") ChronoLocalDateTimeImpl other = (ChronoLocalDateTimeImpl) temporal; - if (chrono.equals(other.toLocalDate().getChronology()) == false) { + if (chrono.equals(other.getChronology()) == false) { throw new ClassCastException("Chronology mismatch, required: " + chrono.getId() - + ", actual: " + other.toLocalDate().getChronology().getId()); + + ", actual: " + other.getChronology().getId()); } return other; } @@ -220,7 +219,7 @@ return this; } // Validate that the new Temporal is a ChronoLocalDate (and not something else) - D cd = ChronoDateImpl.ensureValid(date.getChronology(), newDate); + D cd = ChronoLocalDateImpl.ensureValid(date.getChronology(), newDate); return new ChronoLocalDateTimeImpl<>(cd, newTime); } @@ -369,15 +368,10 @@ //----------------------------------------------------------------------- @Override - public long until(Temporal endDateTime, TemporalUnit unit) { - if (endDateTime instanceof ChronoLocalDateTime == false) { - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } + public long until(Temporal endExclusive, TemporalUnit unit) { + Objects.requireNonNull(endExclusive, "endExclusive"); @SuppressWarnings("unchecked") - ChronoLocalDateTime end = (ChronoLocalDateTime) endDateTime; - if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) { - throw new DateTimeException("Unable to calculate amount as objects have different chronologies"); - } + ChronoLocalDateTime end = (ChronoLocalDateTime) getChronology().localDateTime(endExclusive); if (unit instanceof ChronoUnit) { if (unit.isTimeBased()) { long amount = end.getLong(EPOCH_DAY) - date.getLong(EPOCH_DAY); @@ -398,7 +392,8 @@ } return date.until(endDate, unit); } - return unit.between(this, endDateTime); + Objects.requireNonNull(unit, "unit"); + return unit.between(this, end); } //----------------------------------------------------------------------- diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/ChronoPeriod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/time/chrono/ChronoPeriod.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,365 @@ +/* + * Copyright (c) 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package java.time.chrono; + +import java.time.DateTimeException; +import java.time.temporal.ChronoUnit; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalUnit; +import java.time.temporal.UnsupportedTemporalTypeException; +import java.util.List; +import java.util.Objects; + +/** + * A date-based amount of time, such as '3 years, 4 months and 5 days' in an + * arbitrary chronology, intended for advanced globalization use cases. + *

    + * This interface models a date-based amount of time in a calendar system. + * While most calendar systems use years, months and days, some do not. + * Therefore, this interface operates solely in terms of a set of supported + * units that are defined by the {@code Chronology}. + * The set of supported units is fixed for a given chronology. + * The amount of a supported unit may be set to zero. + *

    + * The period is modeled as a directed amount of time, meaning that individual + * parts of the period may be negative. + * + * @implSpec + * This interface must be implemented with care to ensure other classes operate correctly. + * All implementations that can be instantiated must be final, immutable and thread-safe. + * Subclasses should be Serializable wherever possible. + * + * @since 1.8 + */ +public interface ChronoPeriod + extends TemporalAmount { + + /** + * Obtains a {@code ChronoPeriod} consisting of amount of time between two dates. + *

    + * The start date is included, but the end date is not. + * The period is calculated using {@link ChronoLocalDate#until(ChronoLocalDate)}. + * As such, the calculation is chronology specific. + *

    + * The chronology of the first date is used. + * The chronology of the second date is ignored, with the date being converted + * to the target chronology system before the calculation starts. + *

    + * The result of this method can be a negative period if the end is before the start. + * In most cases, the positive/negative sign will be the same in each of the supported fields. + * + * @param startDateInclusive the start date, inclusive, specifying the chronology of the calculation, not null + * @param endDateExclusive the end date, exclusive, in any chronology, not null + * @return the period between this date and the end date, not null + * @see ChronoLocalDate#until(ChronoLocalDate) + */ + public static ChronoPeriod between(ChronoLocalDate startDateInclusive, ChronoLocalDate endDateExclusive) { + Objects.requireNonNull(startDateInclusive, "startDateInclusive"); + Objects.requireNonNull(endDateExclusive, "endDateExclusive"); + return startDateInclusive.until(endDateExclusive); + } + + //----------------------------------------------------------------------- + /** + * Gets the value of the requested unit. + *

    + * The supported units are chronology specific. + * They will typically be {@link ChronoUnit#YEARS YEARS}, + * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}. + * Requesting an unsupported unit will throw an exception. + * + * @param unit the {@code TemporalUnit} for which to return the value + * @return the long value of the unit + * @throws DateTimeException if the unit is not supported + * @throws UnsupportedTemporalTypeException if the unit is not supported + */ + @Override + long get(TemporalUnit unit); + + /** + * Gets the set of units supported by this period. + *

    + * The supported units are chronology specific. + * They will typically be {@link ChronoUnit#YEARS YEARS}, + * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}. + * They are returned in order from largest to smallest. + *

    + * This set can be used in conjunction with {@link #get(TemporalUnit)} + * to access the entire state of the period. + * + * @return a list containing the supported units, not null + */ + @Override + List getUnits(); + + /** + * Gets the chronology that defines the meaning of the supported units. + *

    + * The period is defined by the chronology. + * It controls the supported units and restricts addition/subtraction + * to {@code ChronoLocalDate} instances of the same chronology. + * + * @return the chronology defining the period, not null + */ + Chronology getChronology(); + + //----------------------------------------------------------------------- + /** + * Checks if all the supported units of this period are zero. + * + * @return true if this period is zero-length + */ + default boolean isZero() { + for (TemporalUnit unit : getUnits()) { + if (get(unit) != 0) { + return false; + } + } + return true; + } + + /** + * Checks if any of the supported units of this period are negative. + * + * @return true if any unit of this period is negative + */ + default boolean isNegative() { + for (TemporalUnit unit : getUnits()) { + if (get(unit) < 0) { + return true; + } + } + return false; + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this period with the specified period added. + *

    + * If the specified amount is a {@code ChronoPeriod} then it must have + * the same chronology as this period. Implementations may choose to + * accept or reject other {@code TemporalAmount} implementations. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the period to add, not null + * @return a {@code ChronoPeriod} based on this period with the requested period added, not null + * @throws ArithmeticException if numeric overflow occurs + */ + ChronoPeriod plus(TemporalAmount amountToAdd); + + /** + * Returns a copy of this period with the specified period subtracted. + *

    + * If the specified amount is a {@code ChronoPeriod} then it must have + * the same chronology as this period. Implementations may choose to + * accept or reject other {@code TemporalAmount} implementations. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the period to subtract, not null + * @return a {@code ChronoPeriod} based on this period with the requested period subtracted, not null + * @throws ArithmeticException if numeric overflow occurs + */ + ChronoPeriod minus(TemporalAmount amountToSubtract); + + //----------------------------------------------------------------------- + /** + * Returns a new instance with each amount in this period in this period + * multiplied by the specified scalar. + *

    + * This returns a period with each supported unit individually multiplied. + * For example, a period of "2 years, -3 months and 4 days" multiplied by + * 3 will return "6 years, -9 months and 12 days". + * No normalization is performed. + * + * @param scalar the scalar to multiply by, not null + * @return a {@code ChronoPeriod} based on this period with the amounts multiplied + * by the scalar, not null + * @throws ArithmeticException if numeric overflow occurs + */ + ChronoPeriod multipliedBy(int scalar); + + /** + * Returns a new instance with each amount in this period negated. + *

    + * This returns a period with each supported unit individually negated. + * For example, a period of "2 years, -3 months and 4 days" will be + * negated to "-2 years, 3 months and -4 days". + * No normalization is performed. + * + * @return a {@code ChronoPeriod} based on this period with the amounts negated, not null + * @throws ArithmeticException if numeric overflow occurs, which only happens if + * one of the units has the value {@code Long.MIN_VALUE} + */ + default ChronoPeriod negated() { + return multipliedBy(-1); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this period with the amounts of each unit normalized. + *

    + * The process of normalization is specific to each calendar system. + * For example, in the ISO calendar system, the years and months are + * normalized but the days are not, such that "15 months" would be + * normalized to "1 year and 3 months". + *

    + * This instance is immutable and unaffected by this method call. + * + * @return a {@code ChronoPeriod} based on this period with the amounts of each + * unit normalized, not null + * @throws ArithmeticException if numeric overflow occurs + */ + ChronoPeriod normalized(); + + //------------------------------------------------------------------------- + /** + * Adds this period to the specified temporal object. + *

    + * This returns a temporal object of the same observable type as the input + * with this period added. + *

    + * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#plus(TemporalAmount)}. + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   dateTime = thisPeriod.addTo(dateTime);
    +     *   dateTime = dateTime.plus(thisPeriod);
    +     * 
    + *

    + * The specified temporal must have the same chronology as this period. + * This returns a temporal with the non-zero supported units added. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param temporal the temporal object to adjust, not null + * @return an object of the same type with the adjustment made, not null + * @throws DateTimeException if unable to add + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + Temporal addTo(Temporal temporal); + + /** + * Subtracts this period from the specified temporal object. + *

    + * This returns a temporal object of the same observable type as the input + * with this period subtracted. + *

    + * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#minus(TemporalAmount)}. + *

    +     *   // these two lines are equivalent, but the second approach is recommended
    +     *   dateTime = thisPeriod.subtractFrom(dateTime);
    +     *   dateTime = dateTime.minus(thisPeriod);
    +     * 
    + *

    + * The specified temporal must have the same chronology as this period. + * This returns a temporal with the non-zero supported units subtracted. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param temporal the temporal object to adjust, not null + * @return an object of the same type with the adjustment made, not null + * @throws DateTimeException if unable to subtract + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + Temporal subtractFrom(Temporal temporal); + + //----------------------------------------------------------------------- + /** + * Checks if this period is equal to another period, including the chronology. + *

    + * Compares this period with another ensuring that the type, each amount and + * the chronology are the same. + * Note that this means that a period of "15 Months" is not equal to a period + * of "1 Year and 3 Months". + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other period + */ + @Override + boolean equals(Object obj); + + /** + * A hash code for this period. + * + * @return a suitable hash code + */ + @Override + int hashCode(); + + //----------------------------------------------------------------------- + /** + * Outputs this period as a {@code String}. + *

    + * The output will include the period amounts and chronology. + * + * @return a string representation of this period, not null + */ + @Override + String toString(); + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/ChronoPeriodImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/time/chrono/ChronoPeriodImpl.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,399 @@ +/* + * Copyright (c) 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. + */ + +/* + * Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package java.time.chrono; + +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.YEARS; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.time.DateTimeException; +import java.time.temporal.ChronoUnit; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalUnit; +import java.time.temporal.UnsupportedTemporalTypeException; +import java.time.temporal.ValueRange; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * A period expressed in terms of a standard year-month-day calendar system. + *

    + * This class is used by applications seeking to handle dates in non-ISO calendar systems. + * For example, the Japanese, Minguo, Thai Buddhist and others. + * + * @implSpec + * This class is immutable nad thread-safe. + * + * @since 1.8 + */ +final class ChronoPeriodImpl + implements ChronoPeriod, Serializable { + // this class is only used by JDK chronology implementations and makes assumptions based on that fact + + /** + * Serialization version. + */ + private static final long serialVersionUID = 57387258289L; + + /** + * The set of supported units. + */ + private final static List SUPPORTED_UNITS = + Collections.unmodifiableList(Arrays.asList(YEARS, MONTHS, DAYS)); + + /** + * The chronology. + */ + private final Chronology chrono; + /** + * The number of years. + */ + final int years; + /** + * The number of months. + */ + final int months; + /** + * The number of days. + */ + final int days; + + /** + * Creates an instance. + */ + ChronoPeriodImpl(Chronology chrono, int years, int months, int days) { + Objects.requireNonNull(chrono, "chrono"); + this.chrono = chrono; + this.years = years; + this.months = months; + this.days = days; + } + + //----------------------------------------------------------------------- + @Override + public long get(TemporalUnit unit) { + if (unit == ChronoUnit.YEARS) { + return years; + } else if (unit == ChronoUnit.MONTHS) { + return months; + } else if (unit == ChronoUnit.DAYS) { + return days; + } else { + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); + } + } + + @Override + public List getUnits() { + return ChronoPeriodImpl.SUPPORTED_UNITS; + } + + @Override + public Chronology getChronology() { + return chrono; + } + + //----------------------------------------------------------------------- + @Override + public boolean isZero() { + return years == 0 && months == 0 && days == 0; + } + + @Override + public boolean isNegative() { + return years < 0 || months < 0 || days < 0; + } + + //----------------------------------------------------------------------- + @Override + public ChronoPeriod plus(TemporalAmount amountToAdd) { + ChronoPeriodImpl amount = validateAmount(amountToAdd); + return new ChronoPeriodImpl( + chrono, + Math.addExact(years, amount.years), + Math.addExact(months, amount.months), + Math.addExact(days, amount.days)); + } + + @Override + public ChronoPeriod minus(TemporalAmount amountToSubtract) { + ChronoPeriodImpl amount = validateAmount(amountToSubtract); + return new ChronoPeriodImpl( + chrono, + Math.subtractExact(years, amount.years), + Math.subtractExact(months, amount.months), + Math.subtractExact(days, amount.days)); + } + + /** + * Obtains an instance of {@code ChronoPeriodImpl} from a temporal amount. + * + * @param amount the temporal amount to convert, not null + * @return the period, not null + */ + private ChronoPeriodImpl validateAmount(TemporalAmount amount) { + Objects.requireNonNull(amount, "amount"); + if (amount instanceof ChronoPeriodImpl == false) { + throw new DateTimeException("Unable to obtain ChronoPeriod from TemporalAmount: " + amount.getClass()); + } + ChronoPeriodImpl period = (ChronoPeriodImpl) amount; + if (chrono.equals(period.getChronology()) == false) { + throw new ClassCastException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + period.getChronology().getId()); + } + return period; + } + + //----------------------------------------------------------------------- + @Override + public ChronoPeriod multipliedBy(int scalar) { + if (this.isZero() || scalar == 1) { + return this; + } + return new ChronoPeriodImpl( + chrono, + Math.multiplyExact(years, scalar), + Math.multiplyExact(months, scalar), + Math.multiplyExact(days, scalar)); + } + + //----------------------------------------------------------------------- + @Override + public ChronoPeriod normalized() { + long monthRange = monthRange(); + if (monthRange > 0) { + long totalMonths = years * monthRange + months; + long splitYears = totalMonths / monthRange; + int splitMonths = (int) (totalMonths % monthRange); // no overflow + if (splitYears == years && splitMonths == months) { + return this; + } + return new ChronoPeriodImpl(chrono, Math.toIntExact(splitYears), splitMonths, days); + + } + return this; + } + + /** + * Calculates the range of months. + * + * @return the month range, -1 if not fixed range + */ + private long monthRange() { + ValueRange startRange = chrono.range(MONTH_OF_YEAR); + if (startRange.isFixed() && startRange.isIntValue()) { + return startRange.getMaximum() - startRange.getMinimum() + 1; + } + return -1; + } + + //------------------------------------------------------------------------- + @Override + public Temporal addTo(Temporal temporal) { + validateChrono(temporal); + if (months == 0) { + if (years != 0) { + temporal = temporal.plus(years, YEARS); + } + } else { + long monthRange = monthRange(); + if (monthRange > 0) { + temporal = temporal.plus(years * monthRange + months, MONTHS); + } else { + if (years != 0) { + temporal = temporal.plus(years, YEARS); + } + temporal = temporal.plus(months, MONTHS); + } + } + if (days != 0) { + temporal = temporal.plus(days, DAYS); + } + return temporal; + } + + + + @Override + public Temporal subtractFrom(Temporal temporal) { + validateChrono(temporal); + if (months == 0) { + if (years != 0) { + temporal = temporal.minus(years, YEARS); + } + } else { + long monthRange = monthRange(); + if (monthRange > 0) { + temporal = temporal.minus(years * monthRange + months, MONTHS); + } else { + if (years != 0) { + temporal = temporal.minus(years, YEARS); + } + temporal = temporal.minus(months, MONTHS); + } + } + if (days != 0) { + temporal = temporal.minus(days, DAYS); + } + return temporal; + } + + /** + * Validates that the temporal has the correct chronology. + */ + private void validateChrono(TemporalAccessor temporal) { + Objects.requireNonNull(temporal, "temporal"); + Chronology temporalChrono = temporal.query(TemporalQuery.chronology()); + if (temporalChrono != null && chrono.equals(temporalChrono) == false) { + throw new DateTimeException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + temporalChrono.getId()); + } + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ChronoPeriodImpl) { + ChronoPeriodImpl other = (ChronoPeriodImpl) obj; + return years == other.years && months == other.months && + days == other.days && chrono.equals(other.chrono); + } + return false; + } + + @Override + public int hashCode() { + return (years + Integer.rotateLeft(months, 8) + Integer.rotateLeft(days, 16)) ^ chrono.hashCode(); + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + if (isZero()) { + return getChronology().toString() + " P0D"; + } else { + StringBuilder buf = new StringBuilder(); + buf.append(getChronology().toString()).append(' ').append('P'); + if (years != 0) { + buf.append(years).append('Y'); + } + if (months != 0) { + buf.append(months).append('M'); + } + if (days != 0) { + buf.append(days).append('D'); + } + return buf.toString(); + } + } + + //----------------------------------------------------------------------- + /** + * Writes the Chronology using a + * dedicated serialized form. + *

    +     *  out.writeByte(12);  // identifies this as a ChronoPeriodImpl
    +     *  out.writeUTF(getId());  // the chronology
    +     *  out.writeInt(years);
    +     *  out.writeInt(months);
    +     *  out.writeInt(days);
    +     * 
    + * + * @return the instance of {@code Ser}, not null + */ + protected Object writeReplace() { + return new Ser(Ser.CHRONO_PERIOD_TYPE, this); + } + + /** + * Defend against malicious streams. + * @return never + * @throws InvalidObjectException always + */ + private Object readResolve() throws ObjectStreamException { + throw new InvalidObjectException("Deserialization via serialization delegate"); + } + + void writeExternal(DataOutput out) throws IOException { + out.writeUTF(chrono.getId()); + out.writeInt(years); + out.writeInt(months); + out.writeInt(days); + } + + static ChronoPeriodImpl readExternal(DataInput in) throws IOException { + Chronology chrono = Chronology.of(in.readUTF()); + int years = in.readInt(); + int months = in.readInt(); + int days = in.readInt(); + return new ChronoPeriodImpl(chrono, years, months, days); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java --- a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java Tue Oct 08 14:57:32 2013 -0700 @@ -166,6 +166,7 @@ if (temporal instanceof ChronoZonedDateTime) { return (ChronoZonedDateTime) temporal; } + Objects.requireNonNull(temporal, "temporal"); Chronology chrono = temporal.query(TemporalQuery.chronology()); if (chrono == null) { throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " + temporal.getClass()); @@ -246,6 +247,18 @@ ChronoLocalDateTime toLocalDateTime(); /** + * Gets the chronology of this date-time. + *

    + * The {@code Chronology} represents the calendar system in use. + * The era and other fields in {@link ChronoField} are defined by the chronology. + * + * @return the chronology, not null + */ + default Chronology getChronology() { + return toLocalDate().getChronology(); + } + + /** * Gets the zone offset, such as '+01:00'. *

    * This is the offset of the local date-time from UTC/Greenwich. @@ -397,7 +410,7 @@ */ @Override default ChronoZonedDateTime with(TemporalAdjuster adjuster) { - return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.with(adjuster)); + return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.with(adjuster)); } /** @@ -415,7 +428,7 @@ */ @Override default ChronoZonedDateTime plus(TemporalAmount amount) { - return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.plus(amount)); + return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.plus(amount)); } /** @@ -433,7 +446,7 @@ */ @Override default ChronoZonedDateTime minus(TemporalAmount amount) { - return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amount)); + return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amount)); } /** @@ -443,7 +456,7 @@ */ @Override default ChronoZonedDateTime minus(long amountToSubtract, TemporalUnit unit) { - return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amountToSubtract, unit)); + return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit)); } //----------------------------------------------------------------------- @@ -475,7 +488,7 @@ } else if (query == TemporalQuery.localTime()) { return (R) toLocalTime(); } else if (query == TemporalQuery.chronology()) { - return (R) toLocalDate().getChronology(); + return (R) getChronology(); } else if (query == TemporalQuery.precision()) { return (R) NANOS; } @@ -562,7 +575,7 @@ if (cmp == 0) { cmp = getZone().getId().compareTo(other.getZone().getId()); if (cmp == 0) { - cmp = toLocalDate().getChronology().compareTo(other.toLocalDate().getChronology()); + cmp = getChronology().compareTo(other.getChronology()); } } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java --- a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java Tue Oct 08 14:57:32 2013 -0700 @@ -69,7 +69,6 @@ import java.io.ObjectOutput; import java.io.ObjectStreamException; import java.io.Serializable; -import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; @@ -186,7 +185,7 @@ */ @SuppressWarnings("unchecked") private ChronoZonedDateTimeImpl create(Instant instant, ZoneId zone) { - return (ChronoZonedDateTimeImpl)ofInstant(toLocalDate().getChronology(), instant, zone); + return (ChronoZonedDateTimeImpl)ofInstant(getChronology(), instant, zone); } /** @@ -201,9 +200,9 @@ static ChronoZonedDateTimeImpl ensureValid(Chronology chrono, Temporal temporal) { @SuppressWarnings("unchecked") ChronoZonedDateTimeImpl other = (ChronoZonedDateTimeImpl) temporal; - if (chrono.equals(other.toLocalDate().getChronology()) == false) { + if (chrono.equals(other.getChronology()) == false) { throw new ClassCastException("Chronology mismatch, required: " + chrono.getId() - + ", actual: " + other.toLocalDate().getChronology().getId()); + + ", actual: " + other.getChronology().getId()); } return other; } @@ -234,7 +233,7 @@ if (trans != null && trans.isOverlap()) { ZoneOffset earlierOffset = trans.getOffsetBefore(); if (earlierOffset.equals(offset) == false) { - return new ChronoZonedDateTimeImpl(dateTime, earlierOffset, zone); + return new ChronoZonedDateTimeImpl<>(dateTime, earlierOffset, zone); } } return this; @@ -246,7 +245,7 @@ if (trans != null) { ZoneOffset offset = trans.getOffsetAfter(); if (offset.equals(getOffset()) == false) { - return new ChronoZonedDateTimeImpl(dateTime, offset, zone); + return new ChronoZonedDateTimeImpl<>(dateTime, offset, zone); } } return this; @@ -294,7 +293,7 @@ } return ofBest(dateTime.with(field, newValue), zone, offset); } - return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), field.adjustInto(this, newValue)); + return ChronoZonedDateTimeImpl.ensureValid(getChronology(), field.adjustInto(this, newValue)); } //----------------------------------------------------------------------- @@ -303,25 +302,21 @@ if (unit instanceof ChronoUnit) { return with(dateTime.plus(amountToAdd, unit)); } - return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), unit.addTo(this, amountToAdd)); /// TODO: Generics replacement Risk! + return ChronoZonedDateTimeImpl.ensureValid(getChronology(), unit.addTo(this, amountToAdd)); /// TODO: Generics replacement Risk! } //----------------------------------------------------------------------- @Override - public long until(Temporal endDateTime, TemporalUnit unit) { - if (endDateTime instanceof ChronoZonedDateTime == false) { - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } + public long until(Temporal endExclusive, TemporalUnit unit) { + Objects.requireNonNull(endExclusive, "endExclusive"); @SuppressWarnings("unchecked") - ChronoZonedDateTime end = (ChronoZonedDateTime) endDateTime; - if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) { - throw new DateTimeException("Unable to calculate amount as objects have different chronologies"); - } + ChronoZonedDateTime end = (ChronoZonedDateTime) getChronology().zonedDateTime(endExclusive); if (unit instanceof ChronoUnit) { end = end.withZoneSameInstant(offset); return dateTime.until(end.toLocalDateTime(), unit); } - return unit.between(this, endDateTime); + Objects.requireNonNull(unit, "unit"); + return unit.between(this, end); } //----------------------------------------------------------------------- diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/Chronology.java --- a/jdk/src/share/classes/java/time/chrono/Chronology.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/chrono/Chronology.java Tue Oct 08 14:57:32 2013 -0700 @@ -91,14 +91,11 @@ import java.time.Instant; import java.time.LocalDate; import java.time.LocalTime; -import java.time.Month; -import java.time.Year; import java.time.ZoneId; import java.time.format.DateTimeFormatterBuilder; import java.time.format.ResolverStyle; import java.time.format.TextStyle; import java.time.temporal.ChronoField; -import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; @@ -1192,6 +1189,38 @@ //----------------------------------------------------------------------- /** + * Obtains a period for this chronology based on years, months and days. + *

    + * This returns a period tied to this chronology using the specified + * years, months and days. All supplied chronologies use periods + * based on years, months and days, however the {@code ChronoPeriod} API + * allows the period to be represented using other units. + * + * @implSpec + * The default implementation returns an implementation class suitable + * for most calendar systems. It is based solely on the three units. + * Normalization, addition and subtraction derive the number of months + * in a year from the {@link #range(ChronoField)}. If the number of + * months within a year is fixed, then the calculation approach for + * addition, subtraction and normalization is slightly different. + *

    + * If implementing an unusual calendar system that is not based on + * years, months and days, or where you want direct control, then + * the {@code ChronoPeriod} interface must be directly implemented. + *

    + * The returned period is immutable and thread-safe. + * + * @param years the number of years, may be negative + * @param months the number of years, may be negative + * @param days the number of years, may be negative + * @return the period in terms of this chronology, not null + */ + public ChronoPeriod period(int years, int months, int days) { + return new ChronoPeriodImpl(this, years, months, days); + } + + //----------------------------------------------------------------------- + /** * Compares this chronology to another chronology. *

    * The comparison order first by the chronology ID string, then by any diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/HijrahDate.java --- a/jdk/src/share/classes/java/time/chrono/HijrahDate.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/chrono/HijrahDate.java Tue Oct 08 14:57:32 2013 -0700 @@ -73,7 +73,6 @@ import java.time.DateTimeException; import java.time.LocalDate; import java.time.LocalTime; -import java.time.Period; import java.time.ZoneId; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; @@ -109,7 +108,7 @@ * @since 1.8 */ public final class HijrahDate - extends ChronoDateImpl + extends ChronoLocalDateImpl implements ChronoLocalDate, Serializable { /** @@ -582,7 +581,7 @@ } @Override - public Period until(ChronoLocalDate endDate) { + public ChronoPeriod until(ChronoLocalDate endDate) { // TODO: untested HijrahDate end = getChronology().date(endDate); long totalMonths = (end.prolepticYear - this.prolepticYear) * 12 + (end.monthOfYear - this.monthOfYear); // safe @@ -597,7 +596,7 @@ } long years = totalMonths / 12; // safe int months = (int) (totalMonths % 12); // safe - return Period.of(Math.toIntExact(years), months, days); + return getChronology().period(Math.toIntExact(years), months, days); } //----------------------------------------------------------------------- diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/IsoChronology.java --- a/jdk/src/share/classes/java/time/chrono/IsoChronology.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/chrono/IsoChronology.java Tue Oct 08 14:57:32 2013 -0700 @@ -77,6 +77,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Month; +import java.time.Period; import java.time.Year; import java.time.ZoneId; import java.time.ZonedDateTime; @@ -567,6 +568,24 @@ //----------------------------------------------------------------------- /** + * Obtains a period for this chronology based on years, months and days. + *

    + * This returns a period tied to the ISO chronology using the specified + * years, months and days. See {@link Period} for further details. + * + * @param years the number of years, may be negative + * @param months the number of years, may be negative + * @param days the number of years, may be negative + * @return the period in terms of this chronology, not null + * @return the ISO period, not null + */ + @Override // override with covariant return type + public Period period(int years, int months, int days) { + return Period.of(years, months, days); + } + + //----------------------------------------------------------------------- + /** * Writes the Chronology using a * dedicated serialized form. * @serialData diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/JapaneseDate.java --- a/jdk/src/share/classes/java/time/chrono/JapaneseDate.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/chrono/JapaneseDate.java Tue Oct 08 14:57:32 2013 -0700 @@ -61,10 +61,8 @@ import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; import static java.time.temporal.ChronoField.DAY_OF_MONTH; -import static java.time.temporal.ChronoField.DAY_OF_YEAR; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.YEAR; -import static java.time.temporal.ChronoField.YEAR_OF_ERA; import java.io.DataInput; import java.io.DataOutput; @@ -76,7 +74,6 @@ import java.time.LocalDate; import java.time.LocalTime; import java.time.Period; -import java.time.Year; import java.time.ZoneId; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; @@ -119,7 +116,7 @@ * @since 1.8 */ public final class JapaneseDate - extends ChronoDateImpl + extends ChronoLocalDateImpl implements ChronoLocalDate, Serializable { /** @@ -662,8 +659,9 @@ } @Override - public Period until(ChronoLocalDate endDate) { - return isoDate.until(endDate); + public ChronoPeriod until(ChronoLocalDate endDate) { + Period period = isoDate.until(endDate); + return getChronology().period(period.getYears(), period.getMonths(), period.getDays()); } @Override // override for performance diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/MinguoDate.java --- a/jdk/src/share/classes/java/time/chrono/MinguoDate.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/chrono/MinguoDate.java Tue Oct 08 14:57:32 2013 -0700 @@ -96,7 +96,7 @@ * @since 1.8 */ public final class MinguoDate - extends ChronoDateImpl + extends ChronoLocalDateImpl implements ChronoLocalDate, Serializable { /** @@ -421,8 +421,9 @@ } @Override - public Period until(ChronoLocalDate endDate) { - return isoDate.until(endDate); + public ChronoPeriod until(ChronoLocalDate endDate) { + Period period = isoDate.until(endDate); + return getChronology().period(period.getYears(), period.getMonths(), period.getDays()); } @Override // override for performance diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/Ser.java --- a/jdk/src/share/classes/java/time/chrono/Ser.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/chrono/Ser.java Tue Oct 08 14:57:32 2013 -0700 @@ -104,6 +104,7 @@ static final byte HIJRAH_DATE_TYPE = 6; static final byte MINGUO_DATE_TYPE = 7; static final byte THAIBUDDHIST_DATE_TYPE = 8; + static final byte CHRONO_PERIOD_TYPE = 9; /** The type being serialized. */ private byte type; @@ -183,6 +184,9 @@ case THAIBUDDHIST_DATE_TYPE: ((ThaiBuddhistDate) object).writeExternal(out); break; + case CHRONO_PERIOD_TYPE: + ((ChronoPeriodImpl) object).writeExternal(out); + break; default: throw new InvalidClassException("Unknown serialized type"); } @@ -235,6 +239,7 @@ case HIJRAH_DATE_TYPE: return HijrahDate.readExternal(in); case MINGUO_DATE_TYPE: return MinguoDate.readExternal(in); case THAIBUDDHIST_DATE_TYPE: return ThaiBuddhistDate.readExternal(in); + case CHRONO_PERIOD_TYPE: return ChronoPeriodImpl.readExternal(in); default: throw new StreamCorruptedException("Unknown serialized type"); } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java --- a/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java Tue Oct 08 14:57:32 2013 -0700 @@ -96,7 +96,7 @@ * @since 1.8 */ public final class ThaiBuddhistDate - extends ChronoDateImpl + extends ChronoLocalDateImpl implements ChronoLocalDate, Serializable { /** @@ -421,8 +421,9 @@ } @Override - public Period until(ChronoLocalDate endDate) { - return isoDate.until(endDate); + public ChronoPeriod until(ChronoLocalDate endDate) { + Period period = isoDate.until(endDate); + return getChronology().period(period.getYears(), period.getMonths(), period.getDays()); } @Override // override for performance diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/format/Parsed.java --- a/jdk/src/share/classes/java/time/format/Parsed.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/format/Parsed.java Tue Oct 08 14:57:32 2013 -0700 @@ -83,6 +83,8 @@ import java.time.Period; import java.time.ZoneId; import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.ChronoZonedDateTime; import java.time.chrono.Chronology; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; @@ -260,11 +262,34 @@ while (changedCount < 50) { for (Map.Entry entry : fieldValues.entrySet()) { TemporalField targetField = entry.getKey(); - ChronoLocalDate resolvedDate = targetField.resolve(fieldValues, chrono, zone, resolverStyle); - if (resolvedDate != null) { - updateCheckConflict(resolvedDate); - changedCount++; - continue outer; // have to restart to avoid concurrent modification + TemporalAccessor resolvedObject = targetField.resolve(fieldValues, chrono, zone, resolverStyle); + if (resolvedObject != null) { + if (resolvedObject instanceof ChronoZonedDateTime) { + ChronoZonedDateTime czdt = (ChronoZonedDateTime) resolvedObject; + if (zone.equals(czdt.getZone()) == false) { + throw new DateTimeException("ChronoZonedDateTime must use the effective parsed zone: " + zone); + } + resolvedObject = czdt.toLocalDateTime(); + } + if (resolvedObject instanceof ChronoLocalDateTime) { + ChronoLocalDateTime cldt = (ChronoLocalDateTime) resolvedObject; + updateCheckConflict(cldt.toLocalTime(), Period.ZERO); + updateCheckConflict(cldt.toLocalDate()); + changedCount++; + continue outer; // have to restart to avoid concurrent modification + } + if (resolvedObject instanceof ChronoLocalDate) { + updateCheckConflict((ChronoLocalDate) resolvedObject); + changedCount++; + continue outer; // have to restart to avoid concurrent modification + } + if (resolvedObject instanceof LocalTime) { + updateCheckConflict((LocalTime) resolvedObject, Period.ZERO); + changedCount++; + continue outer; // have to restart to avoid concurrent modification + } + throw new DateTimeException("Method resolveFields() can only return ChronoZonedDateTime," + + "ChronoLocalDateTime, ChronoLocalDate or LocalTime"); } else if (fieldValues.containsKey(targetField) == false) { changedCount++; continue outer; // have to restart to avoid concurrent modification @@ -302,7 +327,10 @@ if (cld != null && date.equals(cld) == false) { throw new DateTimeException("Conflict found: Fields resolved to two different dates: " + date + " " + cld); } - } else { + } else if (cld != null) { + if (chrono.equals(cld.getChronology()) == false) { + throw new DateTimeException("ChronoLocalDate must use the effective parsed chronology: " + chrono); + } date = cld; } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/temporal/ChronoUnit.java --- a/jdk/src/share/classes/java/time/temporal/ChronoUnit.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/temporal/ChronoUnit.java Tue Oct 08 14:57:32 2013 -0700 @@ -268,8 +268,8 @@ //----------------------------------------------------------------------- @Override - public long between(Temporal temporal1, Temporal temporal2) { - return temporal1.until(temporal2, this); + public long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive) { + return temporal1Inclusive.until(temporal2Exclusive, this); } //----------------------------------------------------------------------- diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/temporal/IsoFields.java --- a/jdk/src/share/classes/java/time/temporal/IsoFields.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/temporal/IsoFields.java Tue Oct 08 14:57:32 2013 -0700 @@ -684,13 +684,16 @@ } @Override - public long between(Temporal temporal1, Temporal temporal2) { + public long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive) { + if (temporal1Inclusive.getClass() != temporal2Exclusive.getClass()) { + return temporal1Inclusive.until(temporal2Exclusive, this); + } switch(this) { case WEEK_BASED_YEARS: - return Math.subtractExact(temporal2.getLong(WEEK_BASED_YEAR), - temporal1.getLong(WEEK_BASED_YEAR)); + return Math.subtractExact(temporal2Exclusive.getLong(WEEK_BASED_YEAR), + temporal1Inclusive.getLong(WEEK_BASED_YEAR)); case QUARTER_YEARS: - return temporal1.until(temporal2, MONTHS) / 3; + return temporal1Inclusive.until(temporal2Exclusive, MONTHS) / 3; default: throw new IllegalStateException("Unreachable"); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/temporal/Temporal.java --- a/jdk/src/share/classes/java/time/temporal/Temporal.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/temporal/Temporal.java Tue Oct 08 14:57:32 2013 -0700 @@ -170,7 +170,8 @@ * * * @implSpec - * Implementations must not alter either this object. + *

    + * Implementations must not alter either this object or the specified temporal object. * Instead, an adjusted copy of the original must be returned. * This provides equivalent, safe behavior for immutable and mutable implementations. *

    @@ -209,7 +210,7 @@ * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} * passing {@code this} as the first argument. *

    - * Implementations must not alter either this object or the specified temporal object. + * Implementations must not alter this object. * Instead, an adjusted copy of the original must be returned. * This provides equivalent, safe behavior for immutable and mutable implementations. * @@ -232,16 +233,17 @@ *

    * Some example code indicating how and why this method is used: *

    -     *  date = date.plus(period);                      // add a Period instance
    -     *  date = date.plus(duration);                    // add a Duration instance
    -     *  date = date.plus(workingDays(6));              // example user-written workingDays method
    +     *  date = date.plus(period);                // add a Period instance
    +     *  date = date.plus(duration);              // add a Duration instance
    +     *  date = date.plus(workingDays(6));        // example user-written workingDays method
          * 
    *

    * Note that calling {@code plus} followed by {@code minus} is not guaranteed to * return the same date-time. * * @implSpec - * Implementations must not alter either this object. + *

    + * Implementations must not alter either this object or the specified temporal object. * Instead, an adjusted copy of the original must be returned. * This provides equivalent, safe behavior for immutable and mutable implementations. *

    @@ -280,7 +282,7 @@ * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} * passing {@code this} as the first argument. *

    - * Implementations must not alter either this object or the specified temporal object. + * Implementations must not alter this object. * Instead, an adjusted copy of the original must be returned. * This provides equivalent, safe behavior for immutable and mutable implementations. * @@ -303,16 +305,17 @@ *

    * Some example code indicating how and why this method is used: *

    -     *  date = date.minus(period);                      // subtract a Period instance
    -     *  date = date.minus(duration);                    // subtract a Duration instance
    -     *  date = date.minus(workingDays(6));              // example user-written workingDays method
    +     *  date = date.minus(period);               // subtract a Period instance
    +     *  date = date.minus(duration);             // subtract a Duration instance
    +     *  date = date.minus(workingDays(6));       // example user-written workingDays method
          * 
    *

    * Note that calling {@code plus} followed by {@code minus} is not guaranteed to * return the same date-time. * * @implSpec - * Implementations must not alter either this object. + *

    + * Implementations must not alter either this object or the specified temporal object. * Instead, an adjusted copy of the original must be returned. * This provides equivalent, safe behavior for immutable and mutable implementations. *

    @@ -345,7 +348,7 @@ * @implSpec * Implementations must behave in a manor equivalent to the default method behavior. *

    - * Implementations must not alter either this object or the specified temporal object. + * Implementations must not alter this object. * Instead, an adjusted copy of the original must be returned. * This provides equivalent, safe behavior for immutable and mutable implementations. *

    @@ -371,8 +374,9 @@ * Calculates the amount of time until another temporal in terms of the specified unit. *

    * This calculates the amount of time between two temporal objects - * of the same type in terms of a single {@code TemporalUnit}. + * in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified temporal. + * The end point is converted to be of the same type as the start point if different. * The result will be negative if the end is before the start. * For example, the period in hours between two temporal objects can be * calculated using {@code startTime.until(endTime, HOURS)}. @@ -409,31 +413,36 @@ *

    * If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as + * passing {@code this} as the first argument and the converted input temporal as * the second argument. *

    - * In summary, implementations must behave in a manner equivalent to this code: + * In summary, implementations must behave in a manner equivalent to this pseudo-code: *

    -     *  // check input temporal is the same type as this class
    +     *  // convert the end temporal to the same type as this class
          *  if (unit instanceof ChronoUnit) {
          *    // if unit is supported, then calculate and return result
          *    // else throw UnsupportedTemporalTypeException for unsupported units
          *  }
    -     *  return unit.between(this, endTemporal);
    +     *  return unit.between(this, convertedEndTemporal);
          * 
    *

    + * Note that the unit's {@code between} method must only be invoked if the + * two temporal objects have exactly the same type evaluated by {@code getClass()}. + *

    * Implementations must ensure that no observable state is altered when this * read-only method is invoked. * - * @param endTemporal the end temporal, of the same type as this object, not null + * @param endExclusive the end temporal, exclusive, converted to be of the + * same type as this object, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this temporal object and the specified one * in terms of the unit; positive if the specified object is later than this one, * negative if it is earlier than this one - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to the same type as this temporal * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ - long until(Temporal endTemporal, TemporalUnit unit); + long until(Temporal endExclusive, TemporalUnit unit); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/temporal/TemporalField.java --- a/jdk/src/share/classes/java/time/temporal/TemporalField.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/temporal/TemporalField.java Tue Oct 08 14:57:32 2013 -0700 @@ -63,7 +63,6 @@ import java.time.DateTimeException; import java.time.ZoneId; -import java.time.chrono.ChronoLocalDate; import java.time.chrono.Chronology; import java.time.format.ResolverStyle; import java.util.Locale; @@ -350,6 +349,10 @@ * be acceptable for the date fields to be resolved into other {@code ChronoField} * instances that can produce a date, such as {@code EPOCH_DAY}. *

    + * Not all {@code TemporalAccessor} implementations are accepted as return values. + * Implementations must accept {@code ChronoLocalDate}, {@code ChronoLocalDateTime}, + * {@code ChronoZonedDateTime} and {@code LocalTime}. + *

    * The zone is not normally required for resolution, but is provided for completeness. *

    * The default implementation must return null. @@ -358,13 +361,13 @@ * @param chronology the effective chronology, not null * @param zone the effective zone, not null * @param resolverStyle the requested type of resolve, not null - * @return the resolved date; null if resolving only changed the map, - * or no resolve occurred + * @return the resolved temporal object; null if resolving only + * changed the map, or no resolve occurred * @throws ArithmeticException if numeric overflow occurs * @throws DateTimeException if resolving results in an error. This must not be thrown * by querying a field on the temporal without first checking if it is supported */ - default ChronoLocalDate resolve( + default TemporalAccessor resolve( Map fieldValues, Chronology chronology, ZoneId zone, ResolverStyle resolverStyle) { return null; diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/temporal/TemporalUnit.java --- a/jdk/src/share/classes/java/time/temporal/TemporalUnit.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/temporal/TemporalUnit.java Tue Oct 08 14:57:32 2013 -0700 @@ -231,7 +231,9 @@ * Calculates the amount of time between two temporal objects. *

    * This calculates the amount in terms of this unit. The start and end - * points are supplied as temporal objects and must be of the same type. + * points are supplied as temporal objects and must be of compatible types. + * The implementation will convert the second type to be an instance of the + * first type before the calculating the amount. * The result will be negative if the end is before the start. * For example, the amount in hours between two temporal objects can be * calculated using {@code HOURS.between(startTime, endTime)}. @@ -264,15 +266,22 @@ * If the unit is not supported an {@code UnsupportedTemporalTypeException} must be thrown. * Implementations must not alter the specified temporal objects. * - * @param temporal1 the base temporal object, not null - * @param temporal2 the other temporal object, not null - * @return the amount of time between temporal1 and temporal2 in terms of this unit; - * positive if temporal2 is later than temporal1, negative if earlier - * @throws DateTimeException if the amount cannot be calculated + * @implSpec + * Implementations must begin by checking to if the two temporals have the + * same type using {@code getClass()}. If they do not, then the result must be + * obtained by calling {@code temporal1Inclusive.until(temporal2Exclusive, this)}. + * + * @param temporal1Inclusive the base temporal object, not null + * @param temporal2Exclusive the other temporal object, exclusive, not null + * @return the amount of time between temporal1Inclusive and temporal2Exclusive + * in terms of this unit; positive if temporal2Exclusive is later than + * temporal1Inclusive, negative if earlier + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to the same type as the start temporal * @throws UnsupportedTemporalTypeException if the unit is not supported by the temporal * @throws ArithmeticException if numeric overflow occurs */ - long between(Temporal temporal1, Temporal temporal2); + long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive); //----------------------------------------------------------------------- /** diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/time/temporal/ValueRange.java --- a/jdk/src/share/classes/java/time/temporal/ValueRange.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/time/temporal/ValueRange.java Tue Oct 08 14:57:32 2013 -0700 @@ -61,6 +61,7 @@ */ package java.time.temporal; +import java.io.InvalidObjectException; import java.io.Serializable; import java.time.DateTimeException; @@ -337,6 +338,21 @@ } } + /** + * Return the ValueRange for the serialized values. + * The values are validated according to the constraints of the {@link #of} + * factory method. + * @return the ValueRange for the serialized fields + * @throws InvalidObjectException if the serialized object has invalid values + */ + private Object readResolve() throws InvalidObjectException { + try { + return of(minSmallest, minLargest, maxSmallest, maxLargest); + } catch (IllegalArgumentException iae) { + throw new InvalidObjectException("Invalid serialized ValueRange: " + iae.getMessage()); + } + } + //----------------------------------------------------------------------- /** * Checks if this range is equal to another range. diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/Arrays.java --- a/jdk/src/share/classes/java/util/Arrays.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/Arrays.java Tue Oct 08 14:57:32 2013 -0700 @@ -1583,6 +1583,7 @@ * @since 1.8 */ public static void parallelPrefix(T[] array, BinaryOperator op) { + Objects.requireNonNull(op); if (array.length > 0) new ArrayPrefixHelpers.CumulateTask<> (null, op, array, 0, array.length).invoke(); @@ -1606,6 +1607,7 @@ */ public static void parallelPrefix(T[] array, int fromIndex, int toIndex, BinaryOperator op) { + Objects.requireNonNull(op); rangeCheck(array.length, fromIndex, toIndex); if (fromIndex < toIndex) new ArrayPrefixHelpers.CumulateTask<> @@ -1627,6 +1629,7 @@ * @since 1.8 */ public static void parallelPrefix(long[] array, LongBinaryOperator op) { + Objects.requireNonNull(op); if (array.length > 0) new ArrayPrefixHelpers.LongCumulateTask (null, op, array, 0, array.length).invoke(); @@ -1649,6 +1652,7 @@ */ public static void parallelPrefix(long[] array, int fromIndex, int toIndex, LongBinaryOperator op) { + Objects.requireNonNull(op); rangeCheck(array.length, fromIndex, toIndex); if (fromIndex < toIndex) new ArrayPrefixHelpers.LongCumulateTask @@ -1673,6 +1677,7 @@ * @since 1.8 */ public static void parallelPrefix(double[] array, DoubleBinaryOperator op) { + Objects.requireNonNull(op); if (array.length > 0) new ArrayPrefixHelpers.DoubleCumulateTask (null, op, array, 0, array.length).invoke(); @@ -1695,6 +1700,7 @@ */ public static void parallelPrefix(double[] array, int fromIndex, int toIndex, DoubleBinaryOperator op) { + Objects.requireNonNull(op); rangeCheck(array.length, fromIndex, toIndex); if (fromIndex < toIndex) new ArrayPrefixHelpers.DoubleCumulateTask @@ -1716,6 +1722,7 @@ * @since 1.8 */ public static void parallelPrefix(int[] array, IntBinaryOperator op) { + Objects.requireNonNull(op); if (array.length > 0) new ArrayPrefixHelpers.IntCumulateTask (null, op, array, 0, array.length).invoke(); @@ -1738,6 +1745,7 @@ */ public static void parallelPrefix(int[] array, int fromIndex, int toIndex, IntBinaryOperator op) { + Objects.requireNonNull(op); rangeCheck(array.length, fromIndex, toIndex); if (fromIndex < toIndex) new ArrayPrefixHelpers.IntCumulateTask diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/Calendar.java --- a/jdk/src/share/classes/java/util/Calendar.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/Calendar.java Tue Oct 08 14:57:32 2013 -0700 @@ -1937,7 +1937,7 @@ /** * Sets the values for the fields YEAR, MONTH, - * DAY_OF_MONTH, HOUR, MINUTE, and + * DAY_OF_MONTH, HOUR_OF_DAY, MINUTE, and * SECOND. * Previous values of other fields are retained. If this is not desired, * call {@link #clear()} first. diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/Collection.java --- a/jdk/src/share/classes/java/util/Collection.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/Collection.java Tue Oct 08 14:57:32 2013 -0700 @@ -104,6 +104,13 @@ * the specified behavior of underlying {@link Object} methods wherever the * implementor deems it appropriate. * + *

    Some collection operations which perform recursive traversal of the + * collection may fail with an exception for self-referential instances where + * the collection directly or indirectly contains itself. This includes the + * {@code clone()}, {@code equals()}, {@code hashCode()} and {@code toString()} + * methods. Implementations may optionally handle the self-referential scenario, + * however most current implementations do not do so. + * *

    This interface is a member of the * * Java Collections Framework. @@ -379,8 +386,8 @@ /** * Removes all of the elements of this collection that satisfy the given - * predicate. Errors or runtime exceptions thrown by the predicate are - * relayed to the caller. + * predicate. Errors or runtime exceptions thrown during iteration or by + * the predicate are relayed to the caller. * * @implSpec * The default implementation traverses all elements of the collection using @@ -393,9 +400,10 @@ * removed * @return {@code true} if any elements were removed * @throws NullPointerException if the specified filter is null - * @throws UnsupportedOperationException if the {@code remove} - * method is not supported by this collection's - * {@link #iterator} + * @throws UnsupportedOperationException if elements cannot be removed + * from this collection. Implementations may throw this exception if a + * matching element cannot be removed or if, in general, removal is not + * supported. * @since 1.8 */ default boolean removeIf(Predicate filter) { @@ -502,12 +510,10 @@ /** * Creates a {@link Spliterator} over the elements in this collection. * - *

    The returned {@code Spliterator} must report the characteristic - * {@link Spliterator#SIZED}; implementations should document any additional - * characteristic values reported by the returned spliterator. If - * this collection contains no elements then the returned spliterator is - * only required to report {@link Spliterator#SIZED} and is not required to - * report additional characteristic values (if any). + * Implementations should document characteristic values reported by the + * spliterator. Such characteristic values are not required to be reported + * if the spliterator reports {@link Spliterator#SIZED} and this collection + * contains no elements. * *

    The default implementation should be overridden by subclasses that * can return a more efficient spliterator. In order to @@ -533,9 +539,11 @@ * late-binding spliterator * from the collections's {@code Iterator}. The spliterator inherits the * fail-fast properties of the collection's iterator. + *

    + * The created {@code Spliterator} reports {@link Spliterator#SIZED}. * * @implNote - * The returned {@code Spliterator} additionally reports + * The created {@code Spliterator} additionally reports * {@link Spliterator#SUBSIZED}. * *

    If a spliterator covers no elements then the reporting of additional diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/GregorianCalendar.java --- a/jdk/src/share/classes/java/util/GregorianCalendar.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/GregorianCalendar.java Tue Oct 08 14:57:32 2013 -0700 @@ -41,11 +41,8 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.time.Instant; -import java.time.ZoneId; import java.time.ZonedDateTime; -import java.time.chrono.IsoChronology; import java.time.temporal.ChronoField; -import java.time.temporal.TemporalQuery; import sun.util.calendar.BaseCalendar; import sun.util.calendar.CalendarDate; import sun.util.calendar.CalendarSystem; @@ -867,6 +864,7 @@ * false otherwise. * @see Calendar#compareTo(Calendar) */ + @Override public boolean equals(Object obj) { return obj instanceof GregorianCalendar && super.equals(obj) && @@ -876,6 +874,7 @@ /** * Generates the hash code for this GregorianCalendar object. */ + @Override public int hashCode() { return super.hashCode() ^ (int)gregorianCutoverDate; } @@ -908,6 +907,7 @@ * or if any calendar fields have out-of-range values in * non-lenient mode. */ + @Override public void add(int field, int amount) { // If amount == 0, do nothing even the given field is out of // range. This is tested by JCK. @@ -1106,6 +1106,7 @@ * @see #add(int,int) * @see #set(int,int) */ + @Override public void roll(int field, boolean up) { roll(field, up ? +1 : -1); } @@ -1154,6 +1155,7 @@ * @see #set(int,int) * @since 1.2 */ + @Override public void roll(int field, int amount) { // If amount == 0, do nothing even the given field is out of // range. This is tested by JCK. @@ -1272,25 +1274,44 @@ int woy = internalGet(WEEK_OF_YEAR); int value = woy + amount; if (!isCutoverYear(y)) { - // If the new value is in between min and max - // (exclusive), then we can use the value. - if (value > min && value < max) { - set(WEEK_OF_YEAR, value); - return; + int weekYear = getWeekYear(); + if (weekYear == y) { + // If the new value is in between min and max + // (exclusive), then we can use the value. + if (value > min && value < max) { + set(WEEK_OF_YEAR, value); + return; + } + long fd = getCurrentFixedDate(); + // Make sure that the min week has the current DAY_OF_WEEK + // in the calendar year + long day1 = fd - (7 * (woy - min)); + if (calsys.getYearFromFixedDate(day1) != y) { + min++; + } + + // Make sure the same thing for the max week + fd += 7 * (max - internalGet(WEEK_OF_YEAR)); + if (calsys.getYearFromFixedDate(fd) != y) { + max--; + } + } else { + // When WEEK_OF_YEAR and YEAR are out of sync, + // adjust woy and amount to stay in the calendar year. + if (weekYear > y) { + if (amount < 0) { + amount++; + } + woy = max; + } else { + if (amount > 0) { + amount -= woy - max; + } + woy = min; + } } - long fd = getCurrentFixedDate(); - // Make sure that the min week has the current DAY_OF_WEEK - long day1 = fd - (7 * (woy - min)); - if (calsys.getYearFromFixedDate(day1) != y) { - min++; - } - - // Make sure the same thing for the max week - fd += 7 * (max - internalGet(WEEK_OF_YEAR)); - if (calsys.getYearFromFixedDate(fd) != y) { - max--; - } - break; + set(field, getRolledValue(woy, amount, min, max)); + return; } // Handle cutover here. @@ -1510,6 +1531,7 @@ * @see #getActualMinimum(int) * @see #getActualMaximum(int) */ + @Override public int getMinimum(int field) { return MIN_VALUES[field]; } @@ -1533,6 +1555,7 @@ * @see #getActualMinimum(int) * @see #getActualMaximum(int) */ + @Override public int getMaximum(int field) { switch (field) { case MONTH: @@ -1581,6 +1604,7 @@ * @see #getActualMinimum(int) * @see #getActualMaximum(int) */ + @Override public int getGreatestMinimum(int field) { if (field == DAY_OF_MONTH) { BaseCalendar.Date d = getGregorianCutoverDate(); @@ -1610,6 +1634,7 @@ * @see #getActualMinimum(int) * @see #getActualMaximum(int) */ + @Override public int getLeastMaximum(int field) { switch (field) { case MONTH: @@ -1659,6 +1684,7 @@ * @see #getActualMaximum(int) * @since 1.2 */ + @Override public int getActualMinimum(int field) { if (field == DAY_OF_MONTH) { GregorianCalendar gc = getNormalizedCalendar(); @@ -1702,6 +1728,7 @@ * @see #getActualMinimum(int) * @since 1.2 */ + @Override public int getActualMaximum(int field) { final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK| HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK| @@ -1970,6 +1997,7 @@ (internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET)); } + @Override public Object clone() { GregorianCalendar other = (GregorianCalendar) super.clone(); @@ -1987,6 +2015,7 @@ return other; } + @Override public TimeZone getTimeZone() { TimeZone zone = super.getTimeZone(); // To share the zone by CalendarDates @@ -1997,6 +2026,7 @@ return zone; } + @Override public void setTimeZone(TimeZone zone) { super.setTimeZone(zone); // To share the zone by CalendarDates @@ -2227,6 +2257,7 @@ * @see #getActualMaximum(int) * @since 1.7 */ + @Override public int getWeeksInWeekYear() { GregorianCalendar gc = getNormalizedCalendar(); int weekYear = gc.getWeekYear(); @@ -2262,8 +2293,9 @@ * * @see Calendar#complete */ + @Override protected void computeFields() { - int mask = 0; + int mask; if (isPartiallyNormalized()) { // Determine which calendar fields need to be computed. mask = getSetStateFields(); @@ -2598,6 +2630,7 @@ * * @exception IllegalArgumentException if any calendar fields are invalid. */ + @Override protected void computeTime() { // In non-lenient mode, perform brief checking of calendar // fields which have been set externally. Through this diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/List.java --- a/jdk/src/share/classes/java/util/List.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/List.java Tue Oct 08 14:57:32 2013 -0700 @@ -396,11 +396,13 @@ * replacing the first element. * * @param operator the operator to apply to each element - * @throws UnsupportedOperationException if the {@code set} - * operation is not supported by this list + * @throws UnsupportedOperationException if this list is unmodifiable. + * Implementations may throw this exception if an element + * cannot be replaced or if, in general, modification is not + * supported * @throws NullPointerException if the specified operator is null or - * if the element is replaced with a null value and this list - * does not permit null elements + * if the operator result is a null value and this list does + * not permit null elements * (optional) * @since 1.8 */ @@ -685,4 +687,3 @@ return Spliterators.spliterator(this, Spliterator.ORDERED); } } - diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/Map.java --- a/jdk/src/share/classes/java/util/Map.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/Map.java Tue Oct 08 14:57:32 2013 -0700 @@ -86,10 +86,6 @@ * Such exceptions are marked as "optional" in the specification for this * interface. * - *

    This interface is a member of the - * - * Java Collections Framework. - * *

    Many methods in Collections Framework interfaces are defined * in terms of the {@link Object#equals(Object) equals} method. For * example, the specification for the {@link #containsKey(Object) @@ -107,6 +103,17 @@ * the specified behavior of underlying {@link Object} methods wherever the * implementor deems it appropriate. * + *

    Some map operations which perform recursive traversal of the map may fail + * with an exception for self-referential instances where the map directly or + * indirectly contains itself. This includes the {@code clone()}, + * {@code equals()}, {@code hashCode()} and {@code toString()} methods. + * Implementations may optionally handle the self-referential scenario, however + * most current implementations do not do so. + * + *

    This interface is a member of the + * + * Java Collections Framework. + * * @param the type of keys maintained by this map * @param the type of mapped values * diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/Optional.java --- a/jdk/src/share/classes/java/util/Optional.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/Optional.java Tue Oct 08 14:57:32 2013 -0700 @@ -85,6 +85,7 @@ * Constructs an instance with the value present. * * @param value the non-null value to be present + * @throws NullPointerException if value is null */ private Optional(T value) { this.value = Objects.requireNonNull(value); @@ -96,6 +97,7 @@ * @param the class of the value * @param value the value to be present, which must be non-null * @return an {@code Optional} with the value present + * @throws NullPointerException if value is null */ public static Optional of(T value) { return new Optional<>(value); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/Random.java --- a/jdk/src/share/classes/java/util/Random.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/Random.java Tue Oct 08 14:57:32 2013 -0700 @@ -89,7 +89,7 @@ private static final long addend = 0xBL; private static final long mask = (1L << 48) - 1; - private static final double DOUBLE_UNIT = 1.0 / (1L << 53); + private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53) // IllegalArgumentException messages static final String BadBound = "bound must be positive"; diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/Set.java --- a/jdk/src/share/classes/java/util/Set.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/Set.java Tue Oct 08 14:57:32 2013 -0700 @@ -386,15 +386,18 @@ /** * Creates a {@code Spliterator} over the elements in this set. * - *

    The {@code Spliterator} reports {@link Spliterator#SIZED} and - * {@link Spliterator#DISTINCT}. Implementations should document the - * reporting of additional characteristic values. + *

    The {@code Spliterator} reports {@link Spliterator#DISTINCT}. + * Implementations should document the reporting of additional + * characteristic values. * * @implSpec * The default implementation creates a * late-binding spliterator * from the set's {@code Iterator}. The spliterator inherits the * fail-fast properties of the set's iterator. + *

    + * The created {@code Spliterator} additionally reports + * {@link Spliterator#SIZED}. * * @implNote * The created {@code Spliterator} additionally reports diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/SortedSet.java --- a/jdk/src/share/classes/java/util/SortedSet.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/SortedSet.java Tue Oct 08 14:57:32 2013 -0700 @@ -223,10 +223,10 @@ /** * Creates a {@code Spliterator} over the elements in this sorted set. * - *

    The {@code Spliterator} reports {@link Spliterator#SIZED}, - * {@link Spliterator#DISTINCT}, {@link Spliterator#SORTED} and - * {@link Spliterator#ORDERED}. Implementations should document the - * reporting of additional characteristic values. + *

    The {@code Spliterator} reports {@link Spliterator#DISTINCT}, + * {@link Spliterator#SORTED} and {@link Spliterator#ORDERED}. + * Implementations should document the reporting of additional + * characteristic values. * *

    The spliterator's comparator (see * {@link java.util.Spliterator#getComparator()}) must be {@code null} if @@ -240,6 +240,9 @@ * from the sorted set's {@code Iterator}. The spliterator inherits the * fail-fast properties of the set's iterator. The * spliterator's comparator is the same as the sorted set's comparator. + *

    + * The created {@code Spliterator} additionally reports + * {@link Spliterator#SIZED}. * * @implNote * The created {@code Spliterator} additionally reports diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/SplittableRandom.java --- a/jdk/src/share/classes/java/util/SplittableRandom.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/SplittableRandom.java Tue Oct 08 14:57:32 2013 -0700 @@ -107,29 +107,25 @@ * Methods nextLong, nextInt, and derivatives do not return the * sequence (seed) values, but instead a hash-like bit-mix of * their bits, producing more independently distributed sequences. - * For nextLong, the mix64 bit-mixing function computes the same - * value as the "64-bit finalizer" function in Austin Appleby's - * MurmurHash3 algorithm. See - * http://code.google.com/p/smhasher/wiki/MurmurHash3 , which - * comments: "The constants for the finalizers were generated by a - * simple simulated-annealing algorithm, and both avalanche all - * bits of 'h' to within 0.25% bias." The mix32 function is - * equivalent to (int)(mix64(seed) >>> 32), but faster because it - * omits a step that doesn't contribute to result. + * For nextLong, the mix64 function is based on David Stafford's + * (http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html) + * "Mix13" variant of the "64-bit finalizer" function in Austin + * Appleby's MurmurHash3 algorithm (see + * http://code.google.com/p/smhasher/wiki/MurmurHash3). The mix32 + * function is based on Stafford's Mix04 mix function, but returns + * the upper 32 bits cast as int. * * The split operation uses the current generator to form the seed * and gamma for another SplittableRandom. To conservatively * avoid potential correlations between seed and value generation, - * gamma selection (method nextGamma) uses the "Mix13" constants - * for MurmurHash3 described by David Stafford - * (http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html) - * To avoid potential weaknesses in bit-mixing transformations, we - * restrict gammas to odd values with at least 12 and no more than - * 52 bits set. Rather than rejecting candidates with too few or - * too many bits set, method nextGamma flips some bits (which has - * the effect of mapping at most 4 to any given gamma value). - * This reduces the effective set of 64bit odd gamma values by - * about 214, a very tiny percentage, and serves as an + * gamma selection (method mixGamma) uses different + * (Murmurhash3's) mix constants. To avoid potential weaknesses + * in bit-mixing transformations, we restrict gammas to odd values + * with at least 24 0-1 or 1-0 bit transitions. Rather than + * rejecting candidates with too few or too many bits set, method + * mixGamma flips some bits (which has the effect of mapping at + * most 4 to any given gamma value). This reduces the effective + * set of 64bit odd gamma values by about 2%, and serves as an * automated screening for sequence constant selection that is * left as an empirical decision in some other hashing and crypto * algorithms. @@ -140,14 +136,15 @@ * avalanching. * * The default (no-argument) constructor, in essence, invokes - * split() for a common "seeder" SplittableRandom. Unlike other - * cases, this split must be performed in a thread-safe manner, so - * we use an AtomicLong to represent the seed rather than use an - * explicit SplittableRandom. To bootstrap the seeder, we start - * off using a seed based on current time and host unless the - * java.util.secureRandomSeed property is set. This serves as a - * slimmed-down (and insecure) variant of SecureRandom that also - * avoids stalls that may occur when using /dev/random. + * split() for a common "defaultGen" SplittableRandom. Unlike + * other cases, this split must be performed in a thread-safe + * manner, so we use an AtomicLong to represent the seed rather + * than use an explicit SplittableRandom. To bootstrap the + * defaultGen, we start off using a seed based on current time and + * network interface address unless the java.util.secureRandomSeed + * property is set. This serves as a slimmed-down (and insecure) + * variant of SecureRandom that also avoids stalls that may occur + * when using /dev/random. * * It is a relatively simple matter to apply the basic design here * to use 128 bit seeds. However, emulating 128bit arithmetic and @@ -160,17 +157,16 @@ */ /** - * The initial gamma value for (unsplit) SplittableRandoms. Must - * be odd with at least 12 and no more than 52 bits set. Currently - * set to the golden ratio scaled to 64bits. + * The golden ratio scaled to 64bits, used as the initial gamma + * value for (unsplit) SplittableRandoms. */ - private static final long INITIAL_GAMMA = 0x9e3779b97f4a7c15L; + private static final long GOLDEN_GAMMA = 0x9e3779b97f4a7c15L; /** * The least non-zero value returned by nextDouble(). This value * is scaled by a random value of 53 bits to produce a result. */ - private static final double DOUBLE_UNIT = 1.0 / (1L << 53); + private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53); /** * The seed. Updated only via method nextSeed. @@ -191,31 +187,31 @@ } /** - * Computes MurmurHash3 64bit mix function. + * Computes Stafford variant 13 of 64bit mix function. */ private static long mix64(long z) { - z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; - z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L; - return z ^ (z >>> 33); + z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L; + z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL; + return z ^ (z >>> 31); } /** - * Returns the 32 high bits of mix64(z) as int. + * Returns the 32 high bits of Stafford variant 4 mix64 function as int. */ private static int mix32(long z) { - z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; - return (int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) >>> 32); + z = (z ^ (z >>> 33)) * 0x62a9d9ed799705f5L; + return (int)(((z ^ (z >>> 28)) * 0xcb24d0a5c88c35b3L) >>> 32); } /** * Returns the gamma value to use for a new split instance. */ - private static long nextGamma(long z) { - z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L; // Stafford "Mix13" - z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL; - z = (z ^ (z >>> 31)) | 1L; // force to be odd - int n = Long.bitCount(z); // ensure enough 0 and 1 bits - return (n < 12 || n > 52) ? z ^ 0xaaaaaaaaaaaaaaaaL : z; + private static long mixGamma(long z) { + z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; // MurmurHash3 mix constants + z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L; + z = (z ^ (z >>> 33)) | 1L; // force to be odd + int n = Long.bitCount(z ^ (z >>> 1)); // ensure enough transitions + return (n < 24) ? z ^ 0xaaaaaaaaaaaaaaaaL : z; } /** @@ -228,7 +224,7 @@ /** * The seed generator for default constructors. */ - private static final AtomicLong seeder = new AtomicLong(initialSeed()); + private static final AtomicLong defaultGen = new AtomicLong(initialSeed()); private static long initialSeed() { String pp = java.security.AccessController.doPrivileged( @@ -396,7 +392,7 @@ * @param seed the initial seed */ public SplittableRandom(long seed) { - this(seed, INITIAL_GAMMA); + this(seed, GOLDEN_GAMMA); } /** @@ -405,8 +401,10 @@ * of those of any other instances in the current program; and * may, and typically does, vary across program invocations. */ - public SplittableRandom() { // emulate seeder.split() - this.gamma = nextGamma(this.seed = seeder.addAndGet(INITIAL_GAMMA)); + public SplittableRandom() { // emulate defaultGen.split() + long s = defaultGen.getAndAdd(2 * GOLDEN_GAMMA); + this.seed = mix64(s); + this.gamma = mixGamma(s + GOLDEN_GAMMA); } /** @@ -424,8 +422,7 @@ * @return the new SplittableRandom instance */ public SplittableRandom split() { - long s = nextSeed(); - return new SplittableRandom(s, nextGamma(s)); + return new SplittableRandom(nextLong(), mixGamma(nextSeed())); } /** diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java --- a/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java Tue Oct 08 14:57:32 2013 -0700 @@ -194,8 +194,8 @@ private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL; // Constants from SplittableRandom - private static final double DOUBLE_UNIT = 1.0 / (1L << 53); - private static final float FLOAT_UNIT = 1.0f / (1 << 24); + private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53) + private static final float FLOAT_UNIT = 0x1.0p-24f; // 1.0f / (1 << 24) /** Rarely-used holder for the second of a pair of Gaussians */ private static final ThreadLocal nextLocalGaussian = diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/stream/Node.java --- a/jdk/src/share/classes/java/util/stream/Node.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/stream/Node.java Tue Oct 08 14:57:32 2013 -0700 @@ -149,7 +149,9 @@ /** * Copies the content of this {@code Node} into an array, starting at a * given offset into the array. It is the caller's responsibility to ensure - * there is sufficient room in the array. + * there is sufficient room in the array, otherwise unspecified behaviour + * will occur if the array length is less than the number of elements + * contained in this node. * * @param array the array into which to copy the contents of this * {@code Node} @@ -258,6 +260,12 @@ */ @Override default T[] asArray(IntFunction generator) { + if (java.util.stream.Tripwire.ENABLED) + java.util.stream.Tripwire.trip(getClass(), "{0} calling Node.OfPrimitive.asArray"); + + long size = count(); + if (size >= Nodes.MAX_ARRAY_SIZE) + throw new IllegalArgumentException(Nodes.BAD_SIZE); T[] boxed = generator.apply((int) count()); copyInto(boxed, 0); return boxed; diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/stream/Nodes.java --- a/jdk/src/share/classes/java/util/stream/Nodes.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/stream/Nodes.java Tue Oct 08 14:57:32 2013 -0700 @@ -60,6 +60,9 @@ */ static final long MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + // IllegalArgumentException messages + static final String BAD_SIZE = "Stream size exceeds max array size"; + @SuppressWarnings("raw") private static final Node EMPTY_NODE = new EmptyNode.OfRef(); private static final Node.OfInt EMPTY_INT_NODE = new EmptyNode.OfInt(); @@ -317,7 +320,7 @@ long size = helper.exactOutputSizeIfKnown(spliterator); if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) { if (size >= MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(BAD_SIZE); P_OUT[] array = generator.apply((int) size); new SizedCollectorTask.OfRef<>(spliterator, helper, array).invoke(); return node(array); @@ -354,7 +357,7 @@ long size = helper.exactOutputSizeIfKnown(spliterator); if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) { if (size >= MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(BAD_SIZE); int[] array = new int[(int) size]; new SizedCollectorTask.OfInt<>(spliterator, helper, array).invoke(); return node(array); @@ -392,7 +395,7 @@ long size = helper.exactOutputSizeIfKnown(spliterator); if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) { if (size >= MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(BAD_SIZE); long[] array = new long[(int) size]; new SizedCollectorTask.OfLong<>(spliterator, helper, array).invoke(); return node(array); @@ -430,7 +433,7 @@ long size = helper.exactOutputSizeIfKnown(spliterator); if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) { if (size >= MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(BAD_SIZE); double[] array = new double[(int) size]; new SizedCollectorTask.OfDouble<>(spliterator, helper, array).invoke(); return node(array); @@ -460,7 +463,10 @@ */ public static Node flatten(Node node, IntFunction generator) { if (node.getChildCount() > 0) { - T[] array = generator.apply((int) node.count()); + long size = node.count(); + if (size >= MAX_ARRAY_SIZE) + throw new IllegalArgumentException(BAD_SIZE); + T[] array = generator.apply((int) size); new ToArrayTask.OfRef<>(node, array, 0).invoke(); return node(array); } else { @@ -483,7 +489,10 @@ */ public static Node.OfInt flattenInt(Node.OfInt node) { if (node.getChildCount() > 0) { - int[] array = new int[(int) node.count()]; + long size = node.count(); + if (size >= MAX_ARRAY_SIZE) + throw new IllegalArgumentException(BAD_SIZE); + int[] array = new int[(int) size]; new ToArrayTask.OfInt(node, array, 0).invoke(); return node(array); } else { @@ -506,7 +515,10 @@ */ public static Node.OfLong flattenLong(Node.OfLong node) { if (node.getChildCount() > 0) { - long[] array = new long[(int) node.count()]; + long size = node.count(); + if (size >= MAX_ARRAY_SIZE) + throw new IllegalArgumentException(BAD_SIZE); + long[] array = new long[(int) size]; new ToArrayTask.OfLong(node, array, 0).invoke(); return node(array); } else { @@ -529,7 +541,10 @@ */ public static Node.OfDouble flattenDouble(Node.OfDouble node) { if (node.getChildCount() > 0) { - double[] array = new double[(int) node.count()]; + long size = node.count(); + if (size >= MAX_ARRAY_SIZE) + throw new IllegalArgumentException(BAD_SIZE); + double[] array = new double[(int) size]; new ToArrayTask.OfDouble(node, array, 0).invoke(); return node(array); } else { @@ -627,7 +642,7 @@ @SuppressWarnings("unchecked") ArrayNode(long size, IntFunction generator) { if (size >= MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(BAD_SIZE); this.array = generator.apply((int) size); this.curSize = 0; } @@ -777,12 +792,17 @@ public void copyInto(T[] array, int offset) { Objects.requireNonNull(array); left.copyInto(array, offset); + // Cast to int is safe since it is the callers responsibility to + // ensure that there is sufficient room in the array right.copyInto(array, offset + (int) left.count()); } @Override public T[] asArray(IntFunction generator) { - T[] array = generator.apply((int) count()); + long size = count(); + if (size >= MAX_ARRAY_SIZE) + throw new IllegalArgumentException(BAD_SIZE); + T[] array = generator.apply((int) size); copyInto(array, 0); return array; } @@ -836,12 +856,17 @@ @Override public void copyInto(T_ARR array, int offset) { left.copyInto(array, offset); + // Cast to int is safe since it is the callers responsibility to + // ensure that there is sufficient room in the array right.copyInto(array, offset + (int) left.count()); } @Override public T_ARR asPrimitiveArray() { - T_ARR array = newArray((int) count()); + long size = count(); + if (size >= MAX_ARRAY_SIZE) + throw new IllegalArgumentException(BAD_SIZE); + T_ARR array = newArray((int) size); copyInto(array, 0); return array; } @@ -1287,7 +1312,7 @@ IntArrayNode(long size) { if (size >= MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(BAD_SIZE); this.array = new int[(int) size]; this.curSize = 0; } @@ -1343,7 +1368,7 @@ LongArrayNode(long size) { if (size >= MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(BAD_SIZE); this.array = new long[(int) size]; this.curSize = 0; } @@ -1397,7 +1422,7 @@ DoubleArrayNode(long size) { if (size >= MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(BAD_SIZE); this.array = new double[(int) size]; this.curSize = 0; } @@ -1843,8 +1868,8 @@ task = task.makeChild(rightSplit, task.offset + leftSplitSize, task.length - leftSplitSize); } - if (task.offset + task.length >= MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + + assert task.offset + task.length < MAX_ARRAY_SIZE; T_SINK sink = (T_SINK) task; task.helper.wrapAndCopyInto(sink, rightSplit); task.propagateCompletion(); @@ -1854,10 +1879,13 @@ @Override public void begin(long size) { - if(size > length) + if (size > length) throw new IllegalStateException("size passed to Sink.begin exceeds array length"); + // Casts to int are safe since absolute size is verified to be within + // bounds when the root concrete SizedCollectorTask is constructed + // with the shared array index = (int) offset; - fence = (int) offset + (int) length; + fence = index + (int) length; } @SuppressWarnings("serial") diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/stream/SortedOps.java --- a/jdk/src/share/classes/java/util/stream/SortedOps.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/stream/SortedOps.java Tue Oct 08 14:57:32 2013 -0700 @@ -278,7 +278,7 @@ } /** - * {@link ForkJoinTask} for implementing sort on SIZED reference streams. + * {@link Sink} for implementing sort on SIZED reference streams. */ private static final class SizedRefSortingSink extends Sink.ChainedReference { private final Comparator comparator; @@ -293,16 +293,12 @@ @Override public void begin(long size) { if (size >= Nodes.MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(Nodes.BAD_SIZE); array = (T[]) new Object[(int) size]; } @Override public void end() { - // Need to use offset rather than array.length since the downstream - // many be short-circuiting - // @@@ A better approach is to know if the downstream short-circuits - // and check sink.cancellationRequested Arrays.sort(array, 0, offset, comparator); downstream.begin(offset); for (int i = 0; i < offset; i++) @@ -331,6 +327,8 @@ @Override public void begin(long size) { + if (size >= Nodes.MAX_ARRAY_SIZE) + throw new IllegalArgumentException(Nodes.BAD_SIZE); list = (size >= 0) ? new ArrayList((int) size) : new ArrayList(); } @@ -363,7 +361,7 @@ @Override public void begin(long size) { if (size >= Nodes.MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(Nodes.BAD_SIZE); array = new int[(int) size]; } @@ -395,6 +393,8 @@ @Override public void begin(long size) { + if (size >= Nodes.MAX_ARRAY_SIZE) + throw new IllegalArgumentException(Nodes.BAD_SIZE); b = (size > 0) ? new SpinedBuffer.OfInt((int) size) : new SpinedBuffer.OfInt(); } @@ -428,7 +428,7 @@ @Override public void begin(long size) { if (size >= Nodes.MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(Nodes.BAD_SIZE); array = new long[(int) size]; } @@ -460,6 +460,8 @@ @Override public void begin(long size) { + if (size >= Nodes.MAX_ARRAY_SIZE) + throw new IllegalArgumentException(Nodes.BAD_SIZE); b = (size > 0) ? new SpinedBuffer.OfLong((int) size) : new SpinedBuffer.OfLong(); } @@ -493,7 +495,7 @@ @Override public void begin(long size) { if (size >= Nodes.MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(Nodes.BAD_SIZE); array = new double[(int) size]; } @@ -525,6 +527,8 @@ @Override public void begin(long size) { + if (size >= Nodes.MAX_ARRAY_SIZE) + throw new IllegalArgumentException(Nodes.BAD_SIZE); b = (size > 0) ? new SpinedBuffer.OfDouble((int) size) : new SpinedBuffer.OfDouble(); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/stream/SpinedBuffer.java --- a/jdk/src/share/classes/java/util/stream/SpinedBuffer.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/stream/SpinedBuffer.java Tue Oct 08 14:57:32 2013 -0700 @@ -156,6 +156,9 @@ public E get(long index) { // @@@ can further optimize by caching last seen spineIndex, // which is going to be right most of the time + + // Casts to int are safe since the spine array index is the index minus + // the prior element count from the current spine if (spineIndex == 0) { if (index < elementIndex) return curChunk[((int) index)]; @@ -201,11 +204,11 @@ * elements into it. */ public E[] asArray(IntFunction arrayFactory) { - // @@@ will fail for size == MAX_VALUE - E[] result = arrayFactory.apply((int) count()); - + long size = count(); + if (size >= Nodes.MAX_ARRAY_SIZE) + throw new IllegalArgumentException(Nodes.BAD_SIZE); + E[] result = arrayFactory.apply((int) size); copyInto(result, 0); - return result; } @@ -547,8 +550,10 @@ } public T_ARR asPrimitiveArray() { - // @@@ will fail for size == MAX_VALUE - T_ARR result = newArray((int) count()); + long size = count(); + if (size >= Nodes.MAX_ARRAY_SIZE) + throw new IllegalArgumentException(Nodes.BAD_SIZE); + T_ARR result = newArray((int) size); copyInto(result, 0); return result; } @@ -760,11 +765,13 @@ } public int get(long index) { + // Casts to int are safe since the spine array index is the index minus + // the prior element count from the current spine int ch = chunkFor(index); if (spineIndex == 0 && ch == 0) return curChunk[(int) index]; else - return spine[ch][(int) (index-priorElementCount[ch])]; + return spine[ch][(int) (index - priorElementCount[ch])]; } @Override @@ -871,11 +878,13 @@ } public long get(long index) { + // Casts to int are safe since the spine array index is the index minus + // the prior element count from the current spine int ch = chunkFor(index); if (spineIndex == 0 && ch == 0) return curChunk[(int) index]; else - return spine[ch][(int) (index-priorElementCount[ch])]; + return spine[ch][(int) (index - priorElementCount[ch])]; } @Override @@ -984,11 +993,13 @@ } public double get(long index) { + // Casts to int are safe since the spine array index is the index minus + // the prior element count from the current spine int ch = chunkFor(index); if (spineIndex == 0 && ch == 0) return curChunk[(int) index]; else - return spine[ch][(int) (index-priorElementCount[ch])]; + return spine[ch][(int) (index - priorElementCount[ch])]; } @Override diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/java/util/stream/Streams.java --- a/jdk/src/share/classes/java/util/stream/Streams.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/java/util/stream/Streams.java Tue Oct 08 14:57:32 2013 -0700 @@ -169,7 +169,9 @@ private int splitPoint(long size) { int d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO; - // 2 <= size <= 2^32 + // Cast to int is safe since: + // 2 <= size < 2^32 + // 2 <= d <= 8 return (int) (size / d); } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/org/jcp/xml/dsig/internal/dom/XMLDSigRI.java --- a/jdk/src/share/classes/org/jcp/xml/dsig/internal/dom/XMLDSigRI.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/org/jcp/xml/dsig/internal/dom/XMLDSigRI.java Tue Oct 08 14:57:32 2013 -0700 @@ -28,7 +28,7 @@ * =========================================================================== */ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013 Oracle and/or its affiliates. All rights reserved. */ /* * $Id: XMLDSigRI.java 1400021 2012-10-19 10:16:04Z coheigea $ @@ -61,7 +61,7 @@ public XMLDSigRI() { /* We are the XMLDSig provider */ - super("XMLDSig", 1.8, INFO); + super("XMLDSig", 1.8d, INFO); final Map map = new HashMap(); map.put("XMLSignatureFactory.DOM", diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/invoke/WrapperInstance.java --- a/jdk/src/share/classes/sun/invoke/WrapperInstance.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/invoke/WrapperInstance.java Tue Oct 08 14:57:32 2013 -0700 @@ -30,7 +30,7 @@ /** * Private API used inside of java.lang.invoke.MethodHandles. * Interface implemented by every object which is produced by - * {@link java.lang.invoke.MethodHandles#asInstance MethodHandles.asInstance}. + * {@link java.lang.invoke.MethodHandleProxies#asInterfaceInstance MethodHandleProxies.asInterfaceInstance}. * The methods of this interface allow a caller to recover the parameters * to {@code asInstance}. * This allows applications to repeatedly convert between method handles diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/invoke/util/ValueConversions.java --- a/jdk/src/share/classes/sun/invoke/util/ValueConversions.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/invoke/util/ValueConversions.java Tue Oct 08 14:57:32 2013 -0700 @@ -502,51 +502,6 @@ } } - static MethodHandle collectArguments(MethodHandle mh, int pos, MethodHandle collector) { - // FIXME: API needs public MHs.collectArguments. - // Should be: - // return MethodHandles.collectArguments(mh, 0, collector); - // The rest of this code is a workaround for not having that API. - if (COLLECT_ARGUMENTS != null) { - try { - return (MethodHandle) - COLLECT_ARGUMENTS.invokeExact(mh, pos, collector); - } catch (Throwable ex) { - if (ex instanceof RuntimeException) - throw (RuntimeException) ex; - if (ex instanceof Error) - throw (Error) ex; - throw new Error(ex.getMessage(), ex); - } - } - // Emulate MHs.collectArguments using fold + drop. - // This is slightly inefficient. - // More seriously, it can put a MH over the 255-argument limit. - mh = MethodHandles.dropArguments(mh, 1, collector.type().parameterList()); - mh = MethodHandles.foldArguments(mh, collector); - return mh; - } - private static final MethodHandle COLLECT_ARGUMENTS; - static { - MethodHandle mh = null; - try { - final java.lang.reflect.Method m = MethodHandles.class - .getDeclaredMethod("collectArguments", - MethodHandle.class, int.class, MethodHandle.class); - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Void run() { - m.setAccessible(true); - return null; - } - }); - mh = IMPL_LOOKUP.unreflect(m); - } catch (ReflectiveOperationException ex) { - throw newInternalError(ex); - } - COLLECT_ARGUMENTS = mh; - } - private static final EnumMap[] WRAPPER_CASTS = newWrapperCaches(1); @@ -1050,12 +1005,12 @@ if (mh == ARRAY_IDENTITY) mh = rightFiller; else - mh = collectArguments(mh, 0, rightFiller); + mh = MethodHandles.collectArguments(mh, 0, rightFiller); } if (mh == ARRAY_IDENTITY) mh = leftCollector; else - mh = collectArguments(mh, 0, leftCollector); + mh = MethodHandles.collectArguments(mh, 0, leftCollector); return mh; } @@ -1101,7 +1056,7 @@ if (midLen == LEFT_ARGS) return rightFill; else - return collectArguments(rightFill, 0, midFill); + return MethodHandles.collectArguments(rightFill, 0, midFill); } // Type-polymorphic version of varargs maker. diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/invoke/util/VerifyAccess.java --- a/jdk/src/share/classes/sun/invoke/util/VerifyAccess.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/invoke/util/VerifyAccess.java Tue Oct 08 14:57:32 2013 -0700 @@ -172,7 +172,7 @@ * Decide if the given method type, attributed to a member or symbolic * reference of a given reference class, is really visible to that class. * @param type the supposed type of a member or symbolic reference of refc - * @param refc + * @param refc the class attempting to make the reference */ public static boolean isTypeVisible(Class type, Class refc) { if (type == refc) return true; // easy check @@ -197,7 +197,7 @@ * Decide if the given method type, attributed to a member or symbolic * reference of a given reference class, is really visible to that class. * @param type the supposed type of a member or symbolic reference of refc - * @param refc + * @param refc the class attempting to make the reference */ public static boolean isTypeVisible(java.lang.invoke.MethodType type, Class refc) { for (int n = -1, max = type.parameterCount(); n < max; n++) { @@ -210,8 +210,8 @@ /** * Test if two classes have the same class loader and package qualifier. - * @param class1 - * @param class2 + * @param class1 a class + * @param class2 another class * @return whether they are in the same package */ public static boolean isSamePackage(Class class1, Class class2) { @@ -244,8 +244,8 @@ /** * Test if two classes are defined as part of the same package member (top-level class). * If this is true, they can share private access with each other. - * @param class1 - * @param class2 + * @param class1 a class + * @param class2 another class * @return whether they are identical or nested together */ public static boolean isSamePackageMember(Class class1, Class class2) { @@ -287,8 +287,8 @@ /** * Is the class loader of parentClass identical to, or an ancestor of, * the class loader of childClass? - * @param parentClass - * @param childClass + * @param parentClass a class + * @param childClass another class, which may be a descendent of the first class * @return whether parentClass precedes or equals childClass in class loader order */ public static boolean classLoaderIsAncestor(Class parentClass, Class childClass) { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/invoke/util/VerifyType.java --- a/jdk/src/share/classes/sun/invoke/util/VerifyType.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/invoke/util/VerifyType.java Tue Oct 08 14:57:32 2013 -0700 @@ -41,8 +41,8 @@ * True if a value can be stacked as the source type and unstacked as the * destination type, without violating the JVM's type consistency. * - * @param call the type of a stacked value - * @param recv the type by which we'd like to treat it + * @param src the type of a stacked value + * @param dst the type by which we'd like to treat it * @return whether the retyping can be done without motion or reformatting */ public static boolean isNullConversion(Class src, Class dst) { @@ -67,9 +67,8 @@ /** * Specialization of isNullConversion to reference types. - - * @param call the type of a stacked value - * @param recv the reference type by which we'd like to treat it + * @param src the type of a stacked value + * @param dst the reference type by which we'd like to treat it * @return whether the retyping can be done without a cast */ public static boolean isNullReferenceConversion(Class src, Class dst) { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java --- a/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java Tue Oct 08 14:57:32 2013 -0700 @@ -118,6 +118,7 @@ static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION, new TypeAnnotation[0], new TypeAnnotation[0], null); + static final AnnotatedType[] EMPTY_ANNOTATED_TYPE_ARRAY = new AnnotatedType[0]; private static class AnnotatedTypeBaseImpl implements AnnotatedType { private final Type type; diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java --- a/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java Tue Oct 08 14:57:32 2013 -0700 @@ -128,14 +128,18 @@ for (int i = 0; i < size; i++) { @SuppressWarnings("unchecked") ArrayList list = l[i]; + TypeAnnotation[] typeAnnotations; if (list != null) { - TypeAnnotation[] typeAnnotations = list.toArray(new TypeAnnotation[0]); - result[i] = AnnotatedTypeFactory.buildAnnotatedType(types[i], - LocationInfo.BASE_LOCATION, - typeAnnotations, - typeAnnotations, - decl); + typeAnnotations = list.toArray(new TypeAnnotation[list.size()]); + } else { + typeAnnotations = EMPTY_TYPE_ANNOTATION_ARRAY; } + result[i] = AnnotatedTypeFactory.buildAnnotatedType(types[i], + LocationInfo.BASE_LOCATION, + typeAnnotations, + typeAnnotations, + decl); + } return result; } @@ -174,6 +178,11 @@ public static AnnotatedType[] buildAnnotatedInterfaces(byte[] rawAnnotations, ConstantPool cp, Class decl) { + if (decl == Object.class || + decl.isArray() || + decl.isPrimitive() || + decl == Void.TYPE) + return AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE_ARRAY; return buildAnnotatedTypes(rawAnnotations, cp, decl, diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/ec/SunEC.java --- a/jdk/src/share/classes/sun/security/ec/SunEC.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/ec/SunEC.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -67,7 +67,7 @@ } public SunEC() { - super("SunEC", 1.7d, "Sun Elliptic Curve provider (EC, ECDSA, ECDH)"); + super("SunEC", 1.8d, "Sun Elliptic Curve provider (EC, ECDSA, ECDH)"); // if there is no security manager installed, put directly into // the provider. Otherwise, create a temporary map and use a diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/jgss/SunProvider.java --- a/jdk/src/share/classes/sun/security/jgss/SunProvider.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/jgss/SunProvider.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -62,7 +62,7 @@ public SunProvider() { /* We are the Sun JGSS provider */ - super("SunJGSS", 1.7d, INFO); + super("SunJGSS", 1.8d, INFO); AccessController.doPrivileged( new java.security.PrivilegedAction() { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java --- a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java Tue Oct 08 14:57:32 2013 -0700 @@ -525,6 +525,10 @@ // get the mechanism token byte[] mechToken = initToken.getMechToken(); + if (mechToken == null) { + throw new GSSException(GSSException.FAILURE, -1, + "mechToken is missing"); + } /* * Select the best match between the list of mechs diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java --- a/jdk/src/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -120,7 +120,7 @@ public SunNativeProvider() { /* We are the Sun NativeGSS provider */ - super(NAME, 1.0, INFO); + super(NAME, 1.8d, INFO); if (MECH_MAP != null) { AccessController.doPrivileged(new PutAllAction(this, MECH_MAP)); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/pkcs11/Secmod.java --- a/jdk/src/share/classes/sun/security/pkcs11/Secmod.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/pkcs11/Secmod.java Tue Oct 08 14:57:32 2013 -0700 @@ -756,8 +756,12 @@ if (DEBUG) System.out.println("handles: " + handles.length); for (long handle : handles) { - TrustAttributes trust = new TrustAttributes(token, session, handle); - trustMap.put(trust.getHash(), trust); + try { + TrustAttributes trust = new TrustAttributes(token, session, handle); + trustMap.put(trust.getHash(), trust); + } catch (PKCS11Exception e) { + // skip put on pkcs11 error + } } } finally { token.releaseSession(session); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/pkcs11/SunPKCS11.java --- a/jdk/src/share/classes/sun/security/pkcs11/SunPKCS11.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/pkcs11/SunPKCS11.java Tue Oct 08 14:57:32 2013 -0700 @@ -94,7 +94,7 @@ } public SunPKCS11() { - super("SunPKCS11-Dummy", 1.7d, "SunPKCS11-Dummy"); + super("SunPKCS11-Dummy", 1.8d, "SunPKCS11-Dummy"); throw new ProviderException ("SunPKCS11 requires configuration file argument"); } @@ -127,7 +127,7 @@ public SunPKCS11(String configName, InputStream configStream) { super("SunPKCS11-" + Config.getConfig(configName, configStream).getName(), - 1.7d, Config.getConfig(configName, configStream).getDescription()); + 1.8d, Config.getConfig(configName, configStream).getDescription()); this.configName = configName; this.config = Config.removeConfig(configName); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/provider/MD4.java --- a/jdk/src/share/classes/sun/security/provider/MD4.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/provider/MD4.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -65,7 +65,7 @@ private final static Provider md4Provider; static { - md4Provider = new Provider("MD4Provider", 1.0d, "MD4 MessageDigest") { + md4Provider = new Provider("MD4Provider", 1.8d, "MD4 MessageDigest") { private static final long serialVersionUID = -8850464997518327965L; }; AccessController.doPrivileged(new PrivilegedAction() { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/provider/Sun.java --- a/jdk/src/share/classes/sun/security/provider/Sun.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/provider/Sun.java Tue Oct 08 14:57:32 2013 -0700 @@ -47,7 +47,7 @@ public Sun() { /* We are the SUN provider */ - super("SUN", 1.8, INFO); + super("SUN", 1.8d, INFO); // if there is no security manager installed, put directly into // the provider. Otherwise, create a temporary map and use a diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/provider/VerificationProvider.java --- a/jdk/src/share/classes/sun/security/provider/VerificationProvider.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/provider/VerificationProvider.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -61,7 +61,7 @@ } public VerificationProvider() { - super("SunJarVerification", 1.7, "Jar Verification Provider"); + super("SunJarVerification", 1.8d, "Jar Verification Provider"); // register all algorithms normally registered by the Sun and SunRsaSign // providers, but only if they are missing if (ACTIVE == false) { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/rsa/SunRsaSign.java --- a/jdk/src/share/classes/sun/security/rsa/SunRsaSign.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/rsa/SunRsaSign.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -43,7 +43,7 @@ private static final long serialVersionUID = 866040293550393045L; public SunRsaSign() { - super("SunRsaSign", 1.7d, "Sun RSA signature provider"); + super("SunRsaSign", 1.8d, "Sun RSA signature provider"); // if there is no security manager installed, put directly into // the provider. Otherwise, create a temporary map and use a diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/smartcardio/SunPCSC.java --- a/jdk/src/share/classes/sun/security/smartcardio/SunPCSC.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/smartcardio/SunPCSC.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -40,7 +40,7 @@ private static final long serialVersionUID = 6168388284028876579L; public SunPCSC() { - super("SunPCSC", 1.7d, "Sun PC/SC provider"); + super("SunPCSC", 1.8d, "Sun PC/SC provider"); AccessController.doPrivileged(new PrivilegedAction() { public Void run() { put("TerminalFactory.PC/SC", "sun.security.smartcardio.SunPCSC$Factory"); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java --- a/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -92,6 +92,8 @@ private List requestedServerNames = Collections.emptyList(); + private boolean serverNamesAccepted = false; + /* * Constructors */ @@ -567,7 +569,9 @@ // check extensions for (HelloExtension ext : mesg.extensions.list()) { ExtensionType type = ext.type; - if ((type != ExtensionType.EXT_ELLIPTIC_CURVES) + if (type == ExtensionType.EXT_SERVER_NAME) { + serverNamesAccepted = true; + } else if ((type != ExtensionType.EXT_ELLIPTIC_CURVES) && (type != ExtensionType.EXT_EC_POINT_FORMATS) && (type != ExtensionType.EXT_SERVER_NAME) && (type != ExtensionType.EXT_RENEGOTIATION_INFO)) { @@ -864,15 +868,47 @@ break; case K_KRB5: case K_KRB5_EXPORT: - String hostname = getHostSE(); - if (hostname == null) { - throw new IOException("Hostname is required" + - " to use Kerberos cipher suites"); + String sniHostname = null; + for (SNIServerName serverName : requestedServerNames) { + if (serverName instanceof SNIHostName) { + sniHostname = ((SNIHostName) serverName).getAsciiName(); + break; + } } - KerberosClientKeyExchange kerberosMsg = - new KerberosClientKeyExchange( - hostname, isLoopbackSE(), getAccSE(), protocolVersion, - sslContext.getSecureRandom()); + + KerberosClientKeyExchange kerberosMsg = null; + if (sniHostname != null) { + // use first requested SNI hostname + try { + kerberosMsg = new KerberosClientKeyExchange( + sniHostname, getAccSE(), protocolVersion, + sslContext.getSecureRandom()); + } catch(IOException e) { + if (serverNamesAccepted) { + // server accepted requested SNI hostname, + // so it must be used + throw e; + } + // fallback to using hostname + if (debug != null && Debug.isOn("handshake")) { + System.out.println( + "Warning, cannot use Server Name Indication: " + + e.getMessage()); + } + } + } + + if (kerberosMsg == null) { + String hostname = getHostSE(); + if (hostname == null) { + throw new IOException("Hostname is required" + + " to use Kerberos cipher suites"); + } + kerberosMsg = new KerberosClientKeyExchange( + hostname, getAccSE(), protocolVersion, + sslContext.getSecureRandom()); + } + // Record the principals involved in exchange session.setPeerPrincipal(kerberosMsg.getPeerPrincipal()); session.setLocalPrincipal(kerberosMsg.getLocalPrincipal()); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/ssl/Handshaker.java --- a/jdk/src/share/classes/sun/security/ssl/Handshaker.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/ssl/Handshaker.java Tue Oct 08 14:57:32 2013 -0700 @@ -335,14 +335,6 @@ } } - boolean isLoopbackSE() { - if (conn != null) { - return conn.getInetAddress().isLoopbackAddress(); - } else { - return false; - } - } - int getPortSE() { if (conn != null) { return conn.getPort(); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/ssl/JsseJce.java --- a/jdk/src/share/classes/sun/security/ssl/JsseJce.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/ssl/JsseJce.java Tue Oct 08 14:57:32 2013 -0700 @@ -110,7 +110,7 @@ private static final long serialVersionUID = -3284138292032213752L; SunCertificates(final Provider p) { - super("SunCertificates", 1.0d, "SunJSSE internal"); + super("SunCertificates", 1.8d, "SunJSSE internal"); AccessController.doPrivileged(new PrivilegedAction() { @Override public Object run() { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java --- a/jdk/src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/ssl/KerberosClientKeyExchange.java Tue Oct 08 14:57:32 2013 -0700 @@ -77,12 +77,12 @@ // please won't check the value of impl variable } - public KerberosClientKeyExchange(String serverName, boolean isLoopback, + public KerberosClientKeyExchange(String serverName, AccessControlContext acc, ProtocolVersion protocolVersion, SecureRandom rand) throws IOException { if (impl != null) { - init(serverName, isLoopback, acc, protocolVersion, rand); + init(serverName, acc, protocolVersion, rand); } else { throw new IllegalStateException("Kerberos is unavailable"); } @@ -120,12 +120,12 @@ impl.print(p); } - public void init(String serverName, boolean isLoopback, + public void init(String serverName, AccessControlContext acc, ProtocolVersion protocolVersion, SecureRandom rand) throws IOException { if (impl != null) { - impl.init(serverName, isLoopback, acc, protocolVersion, rand); + impl.init(serverName, acc, protocolVersion, rand); } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java --- a/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java Tue Oct 08 14:57:32 2013 -0700 @@ -40,6 +40,8 @@ import javax.security.auth.Subject; +import sun.security.util.KeyUtil; +import sun.security.action.GetPropertyAction; import sun.security.ssl.HandshakeMessage.*; import sun.security.ssl.CipherSuite.*; import sun.security.ssl.SignatureAndHashAlgorithm.*; @@ -93,6 +95,50 @@ // the preferable signature algorithm used by ServerKeyExchange message SignatureAndHashAlgorithm preferableSignatureAlgorithm; + // Flag to use smart ephemeral DH key which size matches the corresponding + // authentication key + private static final boolean useSmartEphemeralDHKeys; + + // Flag to use legacy ephemeral DH key which size is 512 bits for + // exportable cipher suites, and 768 bits for others + private static final boolean useLegacyEphemeralDHKeys; + + // The customized ephemeral DH key size for non-exportable cipher suites. + private static final int customizedDHKeySize; + + static { + String property = AccessController.doPrivileged( + new GetPropertyAction("jdk.tls.ephemeralDHKeySize")); + if (property == null || property.length() == 0) { + useLegacyEphemeralDHKeys = false; + useSmartEphemeralDHKeys = false; + customizedDHKeySize = -1; + } else if ("matched".equals(property)) { + useLegacyEphemeralDHKeys = false; + useSmartEphemeralDHKeys = true; + customizedDHKeySize = -1; + } else if ("legacy".equals(property)) { + useLegacyEphemeralDHKeys = true; + useSmartEphemeralDHKeys = false; + customizedDHKeySize = -1; + } else { + useLegacyEphemeralDHKeys = false; + useSmartEphemeralDHKeys = false; + + try { + customizedDHKeySize = Integer.parseUnsignedInt(property); + if (customizedDHKeySize < 1024 || customizedDHKeySize > 2048) { + throw new IllegalArgumentException( + "Customized DH key size should be positive integer " + + "between 1024 and 2048 bits, inclusive"); + } + } catch (NumberFormatException nfe) { + throw new IllegalArgumentException( + "Invalid system property jdk.tls.ephemeralDHKeySize"); + } + } + } + /* * Constructor ... use the keys found in the auth context. */ @@ -1107,7 +1153,7 @@ } } - setupEphemeralDHKeys(suite.exportable); + setupEphemeralDHKeys(suite.exportable, privateKey); break; case K_ECDHE_RSA: // need RSA certs for authentication @@ -1144,7 +1190,8 @@ if (setupPrivateKeyAndChain("DSA") == false) { return false; } - setupEphemeralDHKeys(suite.exportable); + + setupEphemeralDHKeys(suite.exportable, privateKey); break; case K_ECDHE_ECDSA: // get preferable peer signature algorithm for server key exchange @@ -1188,7 +1235,7 @@ break; case K_DH_ANON: // no certs needed for anonymous - setupEphemeralDHKeys(suite.exportable); + setupEphemeralDHKeys(suite.exportable, null); break; case K_ECDH_ANON: // no certs needed for anonymous @@ -1237,15 +1284,70 @@ * Acquire some "ephemeral" Diffie-Hellman keys for this handshake. * We don't reuse these, for improved forward secrecy. */ - private void setupEphemeralDHKeys(boolean export) { + private void setupEphemeralDHKeys(boolean export, Key key) { /* - * Diffie-Hellman keys ... we use 768 bit private keys due - * to the "use twice as many key bits as bits you want secret" - * rule of thumb, assuming we want the same size premaster - * secret with Diffie-Hellman and RSA key exchanges. Except - * that exportable ciphers max out at 512 bits modulus values. + * 768 bits ephemeral DH private keys were used to be used in + * ServerKeyExchange except that exportable ciphers max out at 512 + * bits modulus values. We still adhere to this behavior in legacy + * mode (system property "jdk.tls.ephemeralDHKeySize" is defined + * as "legacy"). + * + * Old JDK (JDK 7 and previous) releases don't support DH keys bigger + * than 1024 bits. We have to consider the compatibility requirement. + * 1024 bits DH key is always used for non-exportable cipher suites + * in default mode (system property "jdk.tls.ephemeralDHKeySize" + * is not defined). + * + * However, if applications want more stronger strength, setting + * system property "jdk.tls.ephemeralDHKeySize" to "matched" + * is a workaround to use ephemeral DH key which size matches the + * corresponding authentication key. For example, if the public key + * size of an authentication certificate is 2048 bits, then the + * ephemeral DH key size should be 2048 bits accordingly unless + * the cipher suite is exportable. This key sizing scheme keeps + * the cryptographic strength consistent between authentication + * keys and key-exchange keys. + * + * Applications may also want to customize the ephemeral DH key size + * to a fixed length for non-exportable cipher suites. This can be + * approached by setting system property "jdk.tls.ephemeralDHKeySize" + * to a valid positive integer between 1024 and 2048 bits, inclusive. + * + * Note that the minimum acceptable key size is 1024 bits except + * exportable cipher suites or legacy mode. + * + * Note that the maximum acceptable key size is 2048 bits because + * DH keys bigger than 2048 are not always supported by underlying + * JCE providers. + * + * Note that per RFC 2246, the key size limit of DH is 512 bits for + * exportable cipher suites. Because of the weakness, exportable + * cipher suites are deprecated since TLS v1.1 and they are not + * enabled by default in Oracle provider. The legacy behavior is + * reserved and 512 bits DH key is always used for exportable + * cipher suites. */ - dh = new DHCrypt((export ? 512 : 768), sslContext.getSecureRandom()); + int keySize = export ? 512 : 1024; // default mode + if (!export) { + if (useLegacyEphemeralDHKeys) { // legacy mode + keySize = 768; + } else if (useSmartEphemeralDHKeys) { // matched mode + if (key != null) { + int ks = KeyUtil.getKeySize(key); + // Note that SunJCE provider only supports 2048 bits DH + // keys bigger than 1024. Please DON'T use value other + // than 1024 and 2048 at present. We may improve the + // underlying providers and key size here in the future. + // + // keySize = ks <= 1024 ? 1024 : (ks >= 2048 ? 2048 : ks); + keySize = ks <= 1024 ? 1024 : 2048; + } // Otherwise, anonymous cipher suites, 1024-bit is used. + } else if (customizedDHKeySize > 0) { // customized mode + keySize = customizedDHKeySize; + } + } + + dh = new DHCrypt(keySize, sslContext.getSecureRandom()); } // Setup the ephemeral ECDH parameters. diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/ssl/SunJSSE.java --- a/jdk/src/share/classes/sun/security/ssl/SunJSSE.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/ssl/SunJSSE.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -131,7 +131,7 @@ private SunJSSE(java.security.Provider cryptoProvider, String providerName) { - super("SunJSSE", 1.6d, fipsInfo + providerName + ")"); + super("SunJSSE", 1.8d, fipsInfo + providerName + ")"); subclassCheck(); if (cryptoProvider == null) { // Calling Security.getProvider() will cause other providers to be diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java --- a/jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -105,12 +105,12 @@ * secret */ @Override - public void init(String serverName, boolean isLoopback, + public void init(String serverName, AccessControlContext acc, ProtocolVersion protocolVersion, SecureRandom rand) throws IOException { // Get service ticket - KerberosTicket ticket = getServiceTicket(serverName, isLoopback, acc); + KerberosTicket ticket = getServiceTicket(serverName, acc); encodedTicket = ticket.getEncoded(); // Record the Kerberos principals @@ -292,25 +292,33 @@ } // Similar to sun.security.jgss.krb5.Krb5InitCredenetial/Krb5Context - private static KerberosTicket getServiceTicket(String srvName, - boolean isLoopback, final AccessControlContext acc) throws IOException { + private static KerberosTicket getServiceTicket(String serverName, + final AccessControlContext acc) throws IOException { - // get the local hostname if srvName is loopback address - String serverName = srvName; - if (isLoopback) { + if ("localhost".equals(serverName) || + "localhost.localdomain".equals(serverName)) { + + if (debug != null && Debug.isOn("handshake")) { + System.out.println("Get the local hostname"); + } String localHost = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public String run() { - String hostname; try { - hostname = InetAddress.getLocalHost().getHostName(); + return InetAddress.getLocalHost().getHostName(); } catch (java.net.UnknownHostException e) { - hostname = "localhost"; + if (debug != null && Debug.isOn("handshake")) { + System.out.println("Warning," + + " cannot get the local hostname: " + + e.getMessage()); + } + return null; } - return hostname; } }); - serverName = localHost; + if (localHost != null) { + serverName = localHost; + } } // Resolve serverName (possibly in IP addr form) to Kerberos principal diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/tools/keytool/Main.java --- a/jdk/src/share/classes/sun/security/tools/keytool/Main.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/tools/keytool/Main.java Tue Oct 08 14:57:32 2013 -0700 @@ -72,6 +72,8 @@ import sun.security.util.Password; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; import sun.security.pkcs.PKCS9Attribute; import sun.security.tools.KeyStoreUtil; @@ -190,6 +192,10 @@ KEYPASS, KEYSTORE, STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V), + IMPORTPASS("Imports.a.password", + ALIAS, KEYPASS, KEYALG, KEYSIZE, KEYSTORE, + STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, + PROVIDERARG, PROVIDERPATH, V, PROTECTED), IMPORTKEYSTORE("Imports.one.or.all.entries.from.another.keystore", SRCKEYSTORE, DESTKEYSTORE, SRCSTORETYPE, DESTSTORETYPE, SRCSTOREPASS, DESTSTOREPASS, @@ -409,6 +415,8 @@ command = GENKEYPAIR; } else if (collator.compare(flags, "-import") == 0) { command = IMPORTCERT; + } else if (collator.compare(flags, "-importpassword") == 0) { + command = IMPORTPASS; } /* * Help @@ -727,6 +735,7 @@ command != GENSECKEY && command != IDENTITYDB && command != IMPORTCERT && + command != IMPORTPASS && command != IMPORTKEYSTORE && command != PRINTCRL) { throw new Exception(rb.getString @@ -808,6 +817,7 @@ command == GENKEYPAIR || command == GENSECKEY || command == IMPORTCERT || + command == IMPORTPASS || command == IMPORTKEYSTORE || command == KEYCLONE || command == CHANGEALIAS || @@ -958,6 +968,13 @@ } doGenSecretKey(alias, keyAlgName, keysize); kssave = true; + } else if (command == IMPORTPASS) { + if (keyAlgName == null) { + keyAlgName = "PBE"; + } + // password is stored as a secret key + doGenSecretKey(alias, keyAlgName, keysize); + kssave = true; } else if (command == IDENTITYDB) { if (filename != null) { try (InputStream inStream = new FileInputStream(filename)) { @@ -1419,6 +1436,43 @@ } return null; // PKCS11, MSCAPI, or -protected } + + /* + * Prompt the user for the password credential to be stored. + */ + private char[] promptForCredential() throws Exception { + // Handle password supplied via stdin + if (System.console() == null) { + char[] importPass = Password.readPassword(System.in); + passwords.add(importPass); + return importPass; + } + + int count; + for (count = 0; count < 3; count++) { + System.err.print( + rb.getString("Enter.the.password.to.be.stored.")); + System.err.flush(); + char[] entered = Password.readPassword(System.in); + passwords.add(entered); + System.err.print(rb.getString("Re.enter.password.")); + char[] passAgain = Password.readPassword(System.in); + passwords.add(passAgain); + if (!Arrays.equals(entered, passAgain)) { + System.err.println(rb.getString("They.don.t.match.Try.again")); + continue; + } + return entered; + } + + if (count == 3) { + throw new Exception(rb.getString + ("Too.many.failures.key.not.added.to.keystore")); + } + + return null; + } + /** * Creates a new secret key. */ @@ -1436,24 +1490,63 @@ throw new Exception(form.format(source)); } + // Use the keystore's default PBE algorithm for entry protection + boolean useDefaultPBEAlgorithm = true; SecretKey secKey = null; - KeyGenerator keygen = KeyGenerator.getInstance(keyAlgName); - if (keysize != -1) { + + if (keyAlgName.toUpperCase().startsWith("PBE")) { + SecretKeyFactory factory = SecretKeyFactory.getInstance("PBE"); + + // User is prompted for PBE credential + secKey = + factory.generateSecret(new PBEKeySpec(promptForCredential())); + + // Check whether a specific PBE algorithm was specified + if (!"PBE".equalsIgnoreCase(keyAlgName)) { + useDefaultPBEAlgorithm = false; + } + + if (verbose) { + MessageFormat form = new MessageFormat(rb.getString( + "Generated.keyAlgName.secret.key")); + Object[] source = + {useDefaultPBEAlgorithm ? "PBE" : secKey.getAlgorithm()}; + System.err.println(form.format(source)); + } + } else { + KeyGenerator keygen = KeyGenerator.getInstance(keyAlgName); + if (keysize == -1) { + if ("DES".equalsIgnoreCase(keyAlgName)) { + keysize = 56; + } else if ("DESede".equalsIgnoreCase(keyAlgName)) { + keysize = 168; + } else { + throw new Exception(rb.getString + ("Please.provide.keysize.for.secret.key.generation")); + } + } keygen.init(keysize); - } else if ("DES".equalsIgnoreCase(keyAlgName)) { - keygen.init(56); - } else if ("DESede".equalsIgnoreCase(keyAlgName)) { - keygen.init(168); - } else { - throw new Exception(rb.getString - ("Please.provide.keysize.for.secret.key.generation")); + secKey = keygen.generateKey(); + + if (verbose) { + MessageFormat form = new MessageFormat(rb.getString + ("Generated.keysize.bit.keyAlgName.secret.key")); + Object[] source = {new Integer(keysize), + secKey.getAlgorithm()}; + System.err.println(form.format(source)); + } } - secKey = keygen.generateKey(); if (keyPass == null) { keyPass = promptForKeyPass(alias, null, storePass); } - keyStore.setKeyEntry(alias, secKey, keyPass, null); + + if (useDefaultPBEAlgorithm) { + keyStore.setKeyEntry(alias, secKey, keyPass, null); + } else { + keyStore.setEntry(alias, new KeyStore.SecretKeyEntry(secKey), + new KeyStore.PasswordProtection(keyPass, keyAlgName, null)); + } } /** diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/classes/sun/security/tools/keytool/Resources.java --- a/jdk/src/share/classes/sun/security/tools/keytool/Resources.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/classes/sun/security/tools/keytool/Resources.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -65,10 +65,16 @@ {"Generates.certificate.from.a.certificate.request", "Generates certificate from a certificate request"}, //-gencert {"Generates.CRL", "Generates CRL"}, //-gencrl + {"Generated.keyAlgName.secret.key", + "Generated {0} secret key"}, //-genseckey + {"Generated.keysize.bit.keyAlgName.secret.key", + "Generated {0}-bit {1} secret key"}, //-genseckey {"Imports.entries.from.a.JDK.1.1.x.style.identity.database", "Imports entries from a JDK 1.1.x-style identity database"}, //-identitydb {"Imports.a.certificate.or.a.certificate.chain", "Imports a certificate or a certificate chain"}, //-importcert + {"Imports.a.password", + "Imports a password"}, //-importpass {"Imports.one.or.all.entries.from.another.keystore", "Imports one or all entries from another keystore"}, //-importkeystore {"Clones.a.key.entry", @@ -220,6 +226,8 @@ {"Must.specify.alias", "Must specify alias"}, {"Keystore.password.must.be.at.least.6.characters", "Keystore password must be at least 6 characters"}, + {"Enter.the.password.to.be.stored.", + "Enter the password to be stored: "}, {"Enter.keystore.password.", "Enter keystore password: "}, {"Enter.source.keystore.password.", "Enter source keystore password: "}, {"Enter.destination.keystore.password.", "Enter destination keystore password: "}, @@ -328,6 +336,7 @@ {"New.prompt.", "New {0}: "}, {"Passwords.must.differ", "Passwords must differ"}, {"Re.enter.new.prompt.", "Re-enter new {0}: "}, + {"Re.enter.passpword.", "Re-enter password: "}, {"Re.enter.new.password.", "Re-enter new password: "}, {"They.don.t.match.Try.again", "They don't match. Try again"}, {"Enter.prompt.alias.name.", "Enter {0} alias name: "}, diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/demo/management/JTop/JTop.java --- a/jdk/src/share/demo/management/JTop/JTop.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/demo/management/JTop/JTop.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -87,12 +87,36 @@ */ public class JTop extends JPanel { + private static class StatusBar extends JPanel { + private static final long serialVersionUID = -6483392381797633018L; + private final JLabel statusText; + + public StatusBar(boolean defaultVisible) { + super(new GridLayout(1, 1)); + statusText = new JLabel(); + statusText.setVisible(defaultVisible); + add(statusText); + } + + @Override + public Dimension getMaximumSize() { + Dimension maximum = super.getMaximumSize(); + Dimension minimum = getMinimumSize(); + return new Dimension(maximum.width, minimum.height); + } + + public void setMessage(String text) { + statusText.setText(text); + statusText.setVisible(true); + } + } private static final long serialVersionUID = -1499762160973870696L; private MBeanServerConnection server; private ThreadMXBean tmbean; private MyTableModel tmodel; + private final StatusBar statusBar; public JTop() { - super(new GridLayout(1,0)); + super(new GridBagLayout()); tmodel = new MyTableModel(); JTable table = new JTable(tmodel); @@ -108,7 +132,22 @@ JScrollPane scrollPane = new JScrollPane(table); // Add the scroll pane to this panel. - add(scrollPane); + GridBagConstraints c1 = new GridBagConstraints(); + c1.fill = GridBagConstraints.BOTH; + c1.gridy = 0; + c1.gridx = 0; + c1.weightx = 1; + c1.weighty = 1; + add(scrollPane, c1); + + statusBar = new StatusBar(false); + GridBagConstraints c2 = new GridBagConstraints(); + c2.fill = GridBagConstraints.HORIZONTAL; + c2.gridy = 1; + c2.gridx = 0; + c2.weightx = 1.0; + c2.weighty = 0.0; + add(statusBar, c2); } // Set the MBeanServerConnection object for communicating @@ -123,9 +162,13 @@ e.printStackTrace(); } if (!tmbean.isThreadCpuTimeSupported()) { - System.err.println("This VM does not support thread CPU time monitoring"); + statusBar.setMessage("Monitored VM does not support thread CPU time measurement"); } else { - tmbean.setThreadCpuTimeEnabled(true); + try { + tmbean.setThreadCpuTimeEnabled(true); + } catch (SecurityException e) { + statusBar.setMessage("Monitored VM does not have permission for enabling thread cpu time measurement"); + } } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/javavm/export/jvm.h --- a/jdk/src/share/javavm/export/jvm.h Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/javavm/export/jvm.h Tue Oct 08 14:57:32 2013 -0700 @@ -472,6 +472,11 @@ JNIEXPORT jbyteArray JNICALL JVM_GetClassTypeAnnotations(JNIEnv *env, jclass cls); +JNIEXPORT jbyteArray JNICALL +JVM_GetFieldTypeAnnotations(JNIEnv *env, jobject field); + +JNIEXPORT jbyteArray JNICALL +JVM_GetMethodTypeAnnotations(JNIEnv *env, jobject method); /* * New (JDK 1.4) reflection implementation diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/lib/security/java.security-windows --- a/jdk/src/share/lib/security/java.security-windows Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/lib/security/java.security-windows Tue Oct 08 14:57:32 2013 -0700 @@ -127,7 +127,7 @@ # This is a comma-separated list of algorithm and/or algorithm:provider # entries. # -securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI +securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI,SHA1PRNG:SUN # # Class to instantiate as the javax.security.auth.login.Configuration diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/native/java/lang/reflect/Executable.c --- a/jdk/src/share/native/java/lang/reflect/Executable.c Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/share/native/java/lang/reflect/Executable.c Tue Oct 08 14:57:32 2013 -0700 @@ -23,11 +23,7 @@ * questions. */ -#include -#include - #include "jni.h" -#include "jni_util.h" #include "jvm.h" #include "java_lang_reflect_Executable.h" @@ -36,3 +32,9 @@ jobject method) { return JVM_GetMethodParameters(env, method); } + +JNIEXPORT jbyteArray JNICALL +Java_java_lang_reflect_Executable_getTypeAnnotationBytes0(JNIEnv *env, + jobject method) { + return JVM_GetMethodTypeAnnotations(env, method); +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/share/native/java/lang/reflect/Field.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/native/java/lang/reflect/Field.c Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 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. + */ + +#include "jni.h" +#include "jvm.h" +#include "java_lang_reflect_Field.h" + +JNIEXPORT jbyteArray JNICALL +Java_java_lang_reflect_Field_getTypeAnnotationBytes0(JNIEnv *env, + jobject field) { + return JVM_GetFieldTypeAnnotations(env, field); +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/windows/bin/cmdtoargs.c --- a/jdk/src/windows/bin/cmdtoargs.c Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/windows/bin/cmdtoargs.c Tue Oct 08 14:57:32 2013 -0700 @@ -53,6 +53,16 @@ static StdArg *stdargs; static int stdargc; +static int copyCh(USHORT ch, char* dest) { + if (HIBYTE(ch) == 0) { + *dest = (char)ch; + return 1; + } else { + *((USHORT *)dest) = ch; + return 2; + } +} + static char* next_arg(char* cmdline, char* arg, jboolean* wildcard) { char* src = cmdline; @@ -61,31 +71,43 @@ int quotes = 0; int slashes = 0; - char prev = 0; - char ch = 0; + // "prev"/"ch" may contain either a single byte, or a double byte + // character encoded in CP_ACP. + USHORT prev = 0; + USHORT ch = 0; int i; jboolean done = JNI_FALSE; + int charLength; *wildcard = JNI_FALSE; - while ((ch = *src) != 0 && !done) { + while (!done) { + charLength = CharNextExA(CP_ACP, src, 0) - src; + if (charLength == 0) { + break; + } else if (charLength == 1) { + ch = (USHORT)(UCHAR)src[0]; + } else { + ch = ((USHORT *)src)[0]; + } + switch (ch) { - case '"': + case L'"': if (separator) { done = JNI_TRUE; break; } - if (prev == '\\') { + if (prev == L'\\') { for (i = 1; i < slashes; i += 2) { - *dest++ = prev; + dest += copyCh(prev, dest); } if (slashes % 2 == 1) { - *dest++ = ch; + dest += copyCh(ch, dest); } else { quotes++; } - } else if (prev == '"' && quotes % 2 == 0) { + } else if (prev == L'"' && quotes % 2 == 0) { quotes++; - *dest++ = ch; // emit every other consecutive quote + dest += copyCh(ch, dest); // emit every other consecutive quote } else if (quotes == 0) { quotes++; // starting quote } else { @@ -94,7 +116,7 @@ slashes = 0; break; - case '\\': + case L'\\': slashes++; if (separator) { done = JNI_TRUE; @@ -102,23 +124,23 @@ } break; - case ' ': - case '\t': - if (prev == '\\') { + case L' ': + case L'\t': + if (prev == L'\\') { for (i = 0 ; i < slashes; i++) { - *dest++ = prev; + dest += copyCh(prev, dest); } } if (quotes % 2 == 1) { - *dest++ = ch; + dest += copyCh(ch, dest); } else { separator = JNI_TRUE; } slashes = 0; break; - case '*': - case '?': + case L'*': + case L'?': if (separator) { done = JNI_TRUE; separator = JNI_FALSE; @@ -127,36 +149,36 @@ if (quotes % 2 == 0) { *wildcard = JNI_TRUE; } - if (prev == '\\') { + if (prev == L'\\') { for (i = 0 ; i < slashes ; i++) { - *dest++ = prev; + dest += copyCh(prev, dest); } } - *dest++ = ch; + dest += copyCh(ch, dest); break; default: - if (prev == '\\') { + if (prev == L'\\') { for (i = 0 ; i < slashes ; i++) { - *dest++ = prev; + dest += copyCh(prev, dest); } - *dest++ = ch; + dest += copyCh(ch, dest); } else if (separator) { done = JNI_TRUE; } else { - *dest++ = ch; + dest += copyCh(ch, dest); } slashes = 0; } if (!done) { prev = ch; - src++; + src += charLength; } } - if (prev == '\\') { + if (prev == L'\\') { for (i = 0; i < slashes; i++) { - *dest++ = prev; + dest += copyCh(prev, dest); } } *dest = 0; diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/windows/classes/java/net/PlainSocketImpl.java --- a/jdk/src/windows/classes/java/net/PlainSocketImpl.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/windows/classes/java/net/PlainSocketImpl.java Tue Oct 08 14:57:32 2013 -0700 @@ -191,14 +191,17 @@ } protected synchronized void accept(SocketImpl s) throws IOException { - // pass in the real impl not the wrapper. - SocketImpl delegate = ((PlainSocketImpl)s).impl; - delegate.address = new InetAddress(); - delegate.fd = new FileDescriptor(); - impl.accept(delegate); - - // set fd to delegate's fd to be compatible with older releases - s.fd = delegate.fd; + if (s instanceof PlainSocketImpl) { + // pass in the real impl not the wrapper. + SocketImpl delegate = ((PlainSocketImpl)s).impl; + delegate.address = new InetAddress(); + delegate.fd = new FileDescriptor(); + impl.accept(delegate); + // set fd to delegate's fd to be compatible with older releases + s.fd = delegate.fd; + } else { + impl.accept(s); + } } void setFileDescriptor(FileDescriptor fd) { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/windows/classes/sun/security/mscapi/SunMSCAPI.java --- a/jdk/src/windows/classes/sun/security/mscapi/SunMSCAPI.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/windows/classes/sun/security/mscapi/SunMSCAPI.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -56,7 +56,7 @@ } public SunMSCAPI() { - super("SunMSCAPI", 1.7d, INFO); + super("SunMSCAPI", 1.8d, INFO); // if there is no security manager installed, put directly into // the provider. Otherwise, create a temporary map and use a diff -r 5f3e7611790a -r a7dcd7811f02 jdk/src/windows/demo/jvmti/hprof/hprof_md.c --- a/jdk/src/windows/demo/jvmti/hprof/hprof_md.c Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/src/windows/demo/jvmti/hprof/hprof_md.c Tue Oct 08 14:57:32 2013 -0700 @@ -82,9 +82,6 @@ struct sockaddr_in s; int fd; - /* create a socket */ - fd = (int)socket(AF_INET, SOCK_STREAM, 0); - /* find remote host's addr from name */ if ((hentry = gethostbyname(hostname)) == NULL) { return -1; @@ -97,8 +94,15 @@ s.sin_port = htons(port); s.sin_family = AF_INET; + /* create a socket */ + fd = (int)socket(AF_INET, SOCK_STREAM, 0); + if (INVALID_SOCKET == fd) { + return 0; + } + /* now try connecting */ - if (-1 == connect(fd, (struct sockaddr*)&s, sizeof(s))) { + if (SOCKET_ERROR == connect(fd, (struct sockaddr*)&s, sizeof(s))) { + closesocket(fd); return 0; } return fd; diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/ProblemList.txt --- a/jdk/test/ProblemList.txt Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/ProblemList.txt Tue Oct 08 14:57:32 2013 -0700 @@ -134,6 +134,9 @@ # 8021230 java/lang/ThreadLocal/ThreadLocalSupplierTest.java generic-all +# 8023201 +java/lang/instrument/RetransformBigClass.sh generic-all +java/lang/instrument/RedefineBigClass.sh generic-all ############################################################################ @@ -163,9 +166,6 @@ # 7027502 demo/jvmti/hprof/MonitorTest.java generic-all -# 8021186 -jdk/lambda/vm/DefaultMethodsTest.java generic-all - # 8024423 - JVMTI: GetLoadedClasses doesn't enumerate anonymous classes demo/jvmti/hprof/HeapAllTest.java generic-all demo/jvmti/hprof/HeapBinaryFormatTest.java generic-all @@ -322,6 +322,18 @@ # 8007410 tools/launcher/FXLauncherTest.java linux-all +# 8025427 +sun/tools/jstat/jstatLineCounts1.sh generic-all +sun/tools/jstat/jstatLineCounts2.sh generic-all +sun/tools/jstat/jstatLineCounts3.sh generic-all +sun/tools/jstat/jstatTimeStamp1.sh generic-all +sun/tools/jstat/jstatGcCauseOutput1.sh generic-all +sun/tools/jstat/jstatLineCounts4.sh generic-all +sun/tools/jstatd/jstatdDefaults.sh generic-all +sun/tools/jstatd/jstatdExternalRegistry.sh generic-all +sun/tools/jstatd/jstatdPort.sh generic-all +sun/tools/jstatd/jstatdServerName.sh generic-all + ############################################################################ # jdk_jdi diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/io/File/createTempFile/SpecialTempFile.java --- a/jdk/test/java/io/File/createTempFile/SpecialTempFile.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/io/File/createTempFile/SpecialTempFile.java Tue Oct 08 14:57:32 2013 -0700 @@ -23,7 +23,7 @@ /* * @test - * @bug 8013827 8011950 8017212 + * @bug 8013827 8011950 8017212 8025128 * @summary Check whether File.createTempFile can handle special parameters * @author Dan Xu */ @@ -33,7 +33,9 @@ public class SpecialTempFile { - private static void test(String name, String[] prefix, String[] suffix) { + private static void test(String name, String[] prefix, String[] suffix, + boolean exceptionExpected) throws IOException + { if (prefix == null || suffix == null || prefix.length != suffix.length) { @@ -41,24 +43,38 @@ } final String exceptionMsg = "Unable to create temporary file"; - final String errMsg = "IOException is expected"; + String[] dirs = { null, "." }; for (int i = 0; i < prefix.length; i++) { boolean exceptionThrown = false; File f = null; - System.out.println("In test " + name - + ", creating temp file with prefix, " - + prefix[i] + ", suffix, " + suffix[i]); - try { - f = File.createTempFile(prefix[i], suffix[i]); - } catch (IOException e) { - if (exceptionMsg.equals(e.getMessage())) - exceptionThrown = true; - else - System.out.println("Wrong error message:" + e.getMessage()); + + for (String dir: dirs) { + System.out.println("In test " + name + + ", creating temp file with prefix, " + + prefix[i] + ", suffix, " + suffix[i] + + ", in dir, " + dir); + + try { + if (dir == null || dir.isEmpty()) + f = File.createTempFile(prefix[i], suffix[i]); + else + f = File.createTempFile(prefix[i], suffix[i], new File(dir)); + } catch (IOException e) { + if (exceptionExpected) { + if (e.getMessage().startsWith(exceptionMsg)) + exceptionThrown = true; + else + System.out.println("Wrong error message:" + + e.getMessage()); + } else { + throw e; + } + } + + if (exceptionExpected && (!exceptionThrown || f != null)) + throw new RuntimeException("IOException is expected"); } - if (!exceptionThrown || f != null) - throw new RuntimeException(errMsg); } } @@ -71,7 +87,17 @@ } String[] nulPre = { name + "\u0000" }; String[] nulSuf = { ".test" }; - test("NulName", nulPre, nulSuf); + test("NulName", nulPre, nulSuf, true); + + // Test JDK-8025128 + String[] goodPre = { "///..///", "/foo" }; + String[] goodSuf = { ".temp", ".tmp" }; + test("goodName", goodPre, goodSuf, false); + + // Test JDK-8011950 + String[] slashPre = { "temp", "///..///", "/foo" }; + String[] slashSuf = { "///..///..", "///..///..", "///..///.." }; + test("SlashedName", slashPre, slashSuf, true); // Windows tests if (!System.getProperty("os.name").startsWith("Windows")) @@ -80,11 +106,6 @@ // Test JDK-8013827 String[] resvPre = { "LPT1.package.zip", "com7.4.package.zip" }; String[] resvSuf = { ".temp", ".temp" }; - test("ReservedName", resvPre, resvSuf); - - // Test JDK-8011950 - String[] slashPre = { "///..///", "temp", "///..///" }; - String[] slashSuf = { ".temp", "///..///..", "///..///.." }; - test("SlashedName", slashPre, slashSuf); + test("ReservedName", resvPre, resvSuf, true); } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedInterfaces.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedInterfaces.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 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. + * + * 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 8022324 + * @summary Test Class.getAnnotatedInterfaces() returns 0-length array as + * specified. + */ + +import java.lang.reflect.AnnotatedType; +import java.util.Arrays; + +public class GetAnnotatedInterfaces { + private static final Class[] testData = { + GetAnnotatedInterfaces.class, + (new Clz() {}).getClass(), + (new Object() {}).getClass(), + Object[].class, + Object[][].class, + Object[][][].class, + Object.class, + void.class, + int.class, + }; + + private static int failed = 0; + private static int tests = 0; + + public static void main(String[] args) throws Exception { + testReturnsZeroLengthArray(); + + if (failed != 0) + throw new RuntimeException("Test failed, check log for details"); + if (tests != 9) + throw new RuntimeException("Not all cases ran, failing"); + } + + private static void testReturnsZeroLengthArray() { + for (Class toTest : testData) { + tests++; + + AnnotatedType[] res = toTest.getAnnotatedInterfaces(); + + if (res == null) { + failed++; + System.out.println(toTest + ".class.getAnnotatedInterface() returns" + + "'null' should zero length array"); + } else if (res.length != 0) { + failed++; + System.out.println(toTest + ".class.getAnnotatedInterfaces() returns: " + + Arrays.asList(res) + ", should be a zero length array of AnnotatedType"); + } + } + } + + interface If {} + + static abstract class Clz {} +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedReceiverType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedReceiverType.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 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. + * + * 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 8024915 + */ + +import java.lang.reflect.AnnotatedType; +import java.util.Arrays; + +public class GetAnnotatedReceiverType { + public void method() {} + public void method0(GetAnnotatedReceiverType this) {} + public static void method4() {} + + class Inner0 { + public Inner0() {} + } + + class Inner1 { + public Inner1(GetAnnotatedReceiverType GetAnnotatedReceiverType.this) {} + } + + private static int failures = 0; + private static int tests = 0; + + public static void main(String[] args) throws NoSuchMethodException { + checkEmptyAT(GetAnnotatedReceiverType.class.getMethod("method").getAnnotatedReceiverType(), + "getAnnotatedReceiverType for \"method\" should return an empty AnnotatedType"); + checkEmptyAT(Inner0.class.getConstructor(GetAnnotatedReceiverType.class).getAnnotatedReceiverType(), + "getAnnotatedReceiverType for a ctor without a \"this\" should return an empty AnnotatedType"); + + checkEmptyAT(GetAnnotatedReceiverType.class.getMethod("method0").getAnnotatedReceiverType(), + "getAnnotatedReceiverType for \"method0\" should return an empty AnnotatedType"); + checkEmptyAT(Inner1.class.getConstructor(GetAnnotatedReceiverType.class).getAnnotatedReceiverType(), + "getAnnotatedReceiverType for a ctor with a \"this\" should return an empty AnnotatedType"); + + checkNull(GetAnnotatedReceiverType.class.getMethod("method4").getAnnotatedReceiverType(), + "getAnnotatedReceiverType() on a static method should return null"); + + if (failures != 0) + throw new RuntimeException("Test failed, see log for details"); + else if (tests != 5) + throw new RuntimeException("Not all cases ran, failing"); + } + + private static void checkNull(Object o, String msg) { + if (o != null) { + failures++; + System.err.println(msg); + } + tests++; + } + + private static void checkEmptyAT(AnnotatedType a, String msg) { + if (a.getAnnotations().length != 0) { + failures++; + System.err.print(msg); + } + tests++; + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedSuperclass.java --- a/jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedSuperclass.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/lang/annotation/typeAnnotations/GetAnnotatedSuperclass.java Tue Oct 08 14:57:32 2013 -0700 @@ -23,12 +23,16 @@ /* * @test - * @bug 8022343 - * @summary make sure Class.getAnnotatedSuperclass() returns null when specified to do so + * @bug 8022343 8007072 + * @summary Test Class.getAnnotatedSuperclass() returns null/non-null + * AnnotatedType as specified */ +import java.lang.reflect.AnnotatedType; +import java.util.Arrays; + public class GetAnnotatedSuperclass { - private static final Class[] testData = { + private static final Class[] nullTestData = { Object.class, If.class, Object[].class, @@ -36,9 +40,31 @@ int.class, }; + private static final Class[] nonNullTestData = { + Class.class, + GetAnnotatedSuperclass.class, + (new If() {}).getClass(), + (new Clz() {}).getClass(), + (new Object() {}).getClass(), + }; + + private static int failed = 0; + private static int tests = 0; + public static void main(String[] args) throws Exception { - int failed = 0; - for (Class toTest : testData) { + testReturnsNull(); + testReturnsEmptyAT(); + + if (failed != 0) + throw new RuntimeException("Test failed, check log for details"); + if (tests != 10) + throw new RuntimeException("Not all cases ran, failing"); + } + + private static void testReturnsNull() { + for (Class toTest : nullTestData) { + tests++; + Object res = toTest.getAnnotatedSuperclass(); if (res != null) { @@ -47,10 +73,26 @@ + res + ", should be null"); } } + } - if (failed != 0) - throw new RuntimeException("Test failed, check log for details"); + private static void testReturnsEmptyAT() { + for (Class toTest : nonNullTestData) { + tests++; + + AnnotatedType res = toTest.getAnnotatedSuperclass(); + + if (res == null) { + failed++; + System.out.println(toTest + ".getAnnotatedSuperclass() returns 'null' should be non-null"); + } else if (res.getAnnotations().length != 0) { + failed++; + System.out.println(toTest + ".getAnnotatedSuperclass() returns: " + + Arrays.asList(res.getAnnotations()) + ", should be an empty AnnotatedType"); + } + } } interface If {} + + static abstract class Clz {} } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/invoke/8022701/BogoLoader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/8022701/BogoLoader.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 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. + * + * 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 java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.Set; +import java.util.Vector; +import jdk.internal.org.objectweb.asm.*; + +public class BogoLoader extends ClassLoader { + + static interface VisitorMaker { + ClassVisitor make(ClassVisitor visitor); + } + + + /** + * Use this property to verify that the desired classloading is happening. + */ + private final boolean verbose = Boolean.getBoolean("bogoloader.verbose"); + /** + * Use this property to disable replacement for testing purposes. + */ + private final boolean noReplace = Boolean.getBoolean("bogoloader.noreplace"); + + /** + * Set of class names that should be loaded with this loader. + * Others are loaded with the system class loader, except for those + * that are transformed. + */ + private Set nonSystem; + + /** + * Map from class names to a bytecode transformer factory. + */ + private Map replaced; + + /** + * Keep track (not terribly efficiently) of which classes have already + * been loaded by this class loader. + */ + private final Vector history = new Vector(); + + private boolean useSystemLoader(String name) { + return ! nonSystem.contains(name) && ! replaced.containsKey(name); + } + + public BogoLoader(Set non_system, Map replaced) { + super(Thread.currentThread().getContextClassLoader()); + this.nonSystem = non_system; + this.replaced = replaced; + } + + private byte[] readResource(String className) throws IOException { + return readResource(className, "class"); + } + + private byte[] readResource(String className, String suffix) throws IOException { + // Note to the unwary -- "/" works on Windows, leave it alone. + String fileName = className.replace('.', '/') + "." + suffix; + InputStream origStream = getResourceAsStream(fileName); + if (origStream == null) { + throw new IOException("Resource not found : " + fileName); + } + BufferedInputStream stream = new java.io.BufferedInputStream(origStream); + byte[] data = new byte[stream.available()]; + int how_many = stream.read(data); + // Really ought to deal with the corner cases of stream.available() + return data; + } + + protected byte[] getClass(String name) throws ClassNotFoundException, + IOException { + return readResource(name, "class"); + } + + /** + * Loads the named class from the system class loader unless + * the name appears in either replaced or nonSystem. + * nonSystem classes are loaded into this classloader, + * and replaced classes get their content from the specified array + * of bytes (and are also loaded into this classloader). + */ + protected Class loadClass(String name, boolean resolve) + throws ClassNotFoundException { + Class clazz; + + if (history.contains(name)) { + Class c = this.findLoadedClass(name); + return c; + } + if (useSystemLoader(name)) { + clazz = findSystemClass(name); + if (verbose) System.err.println("Loading system class " + name); + } else { + history.add(name); + try { + if (verbose) { + System.err.println("Loading classloader class " + name); + } + byte[] classData = getClass(name);; + boolean expanded = false; + if (!noReplace && replaced.containsKey(name)) { + if (verbose) { + System.err.println("Replacing class " + name); + } + ClassReader cr = new ClassReader(classData); + ClassWriter cw = new ClassWriter(0); + VisitorMaker vm = replaced.get(name); + cr.accept(vm.make(cw), 0); + classData = cw.toByteArray(); + } + clazz = defineClass(name, classData, 0, classData.length); + } catch (java.io.EOFException ioe) { + throw new ClassNotFoundException( + "IO Exception in reading class : " + name + " ", ioe); + } catch (ClassFormatError ioe) { + throw new ClassNotFoundException( + "ClassFormatError in reading class file: ", ioe); + } catch (IOException ioe) { + throw new ClassNotFoundException( + "IO Exception in reading class file: ", ioe); + } + } + if (clazz == null) { + throw new ClassNotFoundException(name); + } + if (resolve) { + resolveClass(clazz); + } + return clazz; + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/invoke/8022701/InvokeSeveralWays.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/8022701/InvokeSeveralWays.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 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. + * + * 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 java.lang.reflect.InvocationTargetException; + +/** + * Tries various ways of ultimately invoking MethodSupplier.m(), + * except that m has been made inaccessible and some exception should be + * thrown instead. + */ +public class InvokeSeveralWays { + public static int test(String args[], Class expected) throws Exception { + int failures = 0; + try { + Class.forName("Invoker").getMethod("invoke").invoke(null); + System.out.println("FAIL: No exception throw, probably failed to load modified bytecodes for MethodSupplier"); + failures++; + } catch (InvocationTargetException e) { + Throwable c = e.getCause(); + if (expected.isInstance(c)) + System.out.println("EXPECTED: " + expected.getName() + ", "+ c); + else { + failures++; + System.out.println("FAIL: Unexpected wrapped exception " + c); + e.printStackTrace(System.out); + } + } catch (Throwable e) { + failures++; + System.out.println("FAIL: Unexpected exception has been caught " + e); + e.printStackTrace(System.out); + } + System.out.println(); + try { + Class.forName("Invoker").getMethod("invoke2").invoke(null); + System.out.println("FAIL: No exception throw, probably failed to load modified bytecodes for MethodSupplier"); + failures++; + } catch (InvocationTargetException e) { + Throwable c = e.getCause(); + if (expected.isInstance(c)) + System.out.println("EXPECTED: " + expected.getName() + ", "+ c); + else { + failures++; + System.out.println("FAIL: Unexpected wrapped exception " + c); + e.printStackTrace(System.out); + } + } catch (Throwable e) { + failures++; + System.out.println("FAIL: Unexpected exception has been caught " + e); + e.printStackTrace(System.out); + } + System.out.println(); + try { + Invoker.invoke(); + System.out.println("FAIL: No exception throw, probably failed to load modified bytecodes for MethodSupplier"); + failures++; + } catch (Throwable e) { + if (expected.isInstance(e)) + System.out.println("EXPECTED: " + expected.getName() + ", "+ e); + else { + failures++; + System.out.println("FAIL: Unexpected exception has been caught " + e); + e.printStackTrace(System.out); + } + } + System.out.println(); + try { + Invoker.invoke2(); + System.out.println("FAIL: No exception throw, probably failed to load modified bytecodes for MethodSupplier"); + failures++; + } catch (Throwable e) { + if (expected.isInstance(e)) + System.out.println("EXPECTED: " + expected.getName() + ", "+ e); + else { + failures++; + System.out.println("FAIL: Unexpected exception has been caught " + e); + e.printStackTrace(System.out); + } + } + System.out.println(); + if (failures > 0) { + System.out.println("Saw " + failures + " failures"); + } + return failures; + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/invoke/8022701/Invoker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/8022701/Invoker.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 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. + * + * 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. + * + */ + +public class Invoker { + /** + * Use a method handle to invoke m. + */ + public static void invoke() { + MyFunctionalInterface fi = null; + fi = new MethodSupplier()::m; + fi.invokeMethodReference(); + } + /** + * Invoke m directly. + */ + public static void invoke2() { + MethodSupplier ms = new MethodSupplier(); + ms.m(); + } +} + +interface MyFunctionalInterface { + void invokeMethodReference(); +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/invoke/8022701/MHIllegalAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/8022701/MHIllegalAccess.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 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. + * + * 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 8022701 + * @summary Illegal access exceptions via methodhandle invocations threw wrong error. + * + * @compile -XDignore.symbol.file BogoLoader.java InvokeSeveralWays.java MHIllegalAccess.java MethodSupplier.java + * @run main/othervm MHIllegalAccess + */ + +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.HashSet; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +public class MHIllegalAccess implements Opcodes { + + public static void main(String args[]) throws Throwable { + System.out.println("Classpath is " + System.getProperty("java.class.path")); + System.out.println(); + + /** + * Make method m be private to provoke an IllegalAccessError. + */ + BogoLoader.VisitorMaker privatize = new BogoLoader.VisitorMaker() { + public ClassVisitor make(ClassVisitor cv) { + return new ClassVisitor(Opcodes.ASM5, cv) { + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { + if (name.equals("m")) + access = (access | ACC_PRIVATE) & ~ (ACC_PUBLIC | ACC_PROTECTED); + return super.visitMethod(access, name, desc, signature, exceptions); + } + }; + } + }; + + /** + * Rename method m as nemo to provoke a NoSuchMethodError. + */ + BogoLoader.VisitorMaker changeName = new BogoLoader.VisitorMaker() { + public ClassVisitor make(ClassVisitor cv) { + return new ClassVisitor(Opcodes.ASM5, cv) { + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { + if (name.equals("m")) + name = "nemo"; + return super.visitMethod(access, name, desc, signature, exceptions); + } + }; + } + }; + + int failures = 0; + failures += testOneError(privatize, args, IllegalAccessError.class); + failures += testOneError(changeName, args, NoSuchMethodError.class); + if (failures > 0) { + System.out.println("Saw " + failures + " failures, see standard out for details"); + throw new Error("FAIL test"); + } + } + + /** + * + * @param vm VisitorMaker, to be stored in a table and passed to a BogoLoader + * @param args A copy of the main args, to be passed on to InvokeSeveralWays.test + * @param expected The class of the exception that should be thrown after + * attempted invocation of MethodSupplier.m. + * @throws ClassNotFoundException + * @throws Throwable + */ + private static int testOneError(BogoLoader.VisitorMaker vm, String[] args, Class expected) throws ClassNotFoundException, Throwable { + HashMap replace = new HashMap(); + replace.put("MethodSupplier", vm); + + HashSet in_bogus = new HashSet(); + in_bogus.add("InvokeSeveralWays"); + in_bogus.add("MyFunctionalInterface"); + in_bogus.add("Invoker"); + + BogoLoader bl = new BogoLoader(in_bogus, replace); + Class isw = bl.loadClass("InvokeSeveralWays"); + Object[] arg_for_args = new Object[2]; + arg_for_args[0] = args; + arg_for_args[1] = expected; + try { + Object result = isw.getMethod("test", String[].class, Class.class).invoke(null, arg_for_args); + return (Integer)result; + } catch (InvocationTargetException e) { + Throwable th = e.getCause(); + throw th == null ? e : th; + } + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/invoke/8022701/MethodSupplier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/8022701/MethodSupplier.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 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. + * + * 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. + * + */ + +/* + * Note: this class is only used in this form to facilitate compilation of the + * rest of the code. Before execution, the bytecodes are mutilated in a + * BogoLoader to either make m be private or have a different name. + */ + +public class MethodSupplier { + public void m() { + System.out.println("good"); + } +} + diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/invoke/AccessControlTest.java --- a/jdk/test/java/lang/invoke/AccessControlTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/lang/invoke/AccessControlTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -133,7 +133,7 @@ } /** Simulate all assertions from the spec. for Lookup.in: - *
    + *
    * Creates a lookup on the specified new lookup class. * [A1] The resulting object will report the specified * class as its own {@link #lookupClass lookupClass}. @@ -155,7 +155,7 @@ * * Other than the above cases, the new lookup will have the same * access capabilities as the original. [A8] - *
    + *
    */ public LookupCase in(Class c2) { Class c1 = lookupClass(); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/invoke/BigArityTest.java --- a/jdk/test/java/lang/invoke/BigArityTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/lang/invoke/BigArityTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -93,6 +93,65 @@ } @Test + public void asCollectorIAE01() throws ReflectiveOperationException { + final int [] INVALID_ARRAY_LENGTHS = { + Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -2, -1, 255, 256, Integer.MAX_VALUE - 1, Integer.MAX_VALUE + }; + MethodHandle target = MethodHandles.publicLookup().findStatic(Arrays.class, + "deepToString", MethodType.methodType(String.class, Object[].class)); + int minbig = Integer.MAX_VALUE; + for (int invalidLength : INVALID_ARRAY_LENGTHS) { + if (minbig > invalidLength && invalidLength > 100) minbig = invalidLength; + try { + target.asCollector(Object[].class, invalidLength); + assert(false) : invalidLength; + } catch (IllegalArgumentException ex) { + System.out.println("OK: "+ex); + } + } + // Sizes not in the above array are good: + target.asCollector(Object[].class, minbig-1); + for (int i = 2; i <= 10; i++) + target.asCollector(Object[].class, minbig-i); + } + + @Test + public void invoker02() { + for (int i = 0; i < 255; i++) { + MethodType mt = MethodType.genericMethodType(i); + MethodType expMT = mt.insertParameterTypes(0, MethodHandle.class); + if (i < 254) { + assertEquals(expMT, MethodHandles.invoker(mt).type()); + } else { + try { + MethodHandles.invoker(mt); + assert(false) : i; + } catch (IllegalArgumentException ex) { + System.out.println("OK: "+ex); + } + } + } + } + + @Test + public void exactInvoker02() { + for (int i = 0; i < 255; i++) { + MethodType mt = MethodType.genericMethodType(i); + MethodType expMT = mt.insertParameterTypes(0, MethodHandle.class); + if (i < 254) { + assertEquals(expMT, MethodHandles.exactInvoker(mt).type()); + } else { + try { + MethodHandles.exactInvoker(mt); + assert(false) : i; + } catch (IllegalArgumentException ex) { + System.out.println("OK: "+ex); + } + } + } + } + + @Test public void testBoundaryValues() throws Throwable { for (int badArity : new int[]{ -1, MAX_JVM_ARITY+1, MAX_JVM_ARITY }) { try { @@ -102,6 +161,37 @@ System.out.println("OK: "+ex); } } + final int MAX_MH_ARITY = MAX_JVM_ARITY - 1; // mh.invoke(arg*[N]) + final int MAX_INVOKER_ARITY = MAX_MH_ARITY - 1; // inv.invoke(mh, arg*[N]) + for (int arity : new int[]{ 0, 1, MAX_MH_ARITY-2, MAX_MH_ARITY-1, MAX_MH_ARITY }) { + MethodHandle mh = MH_hashArguments(arity); + if (arity < MAX_INVOKER_ARITY) { + MethodHandle ximh = MethodHandles.exactInvoker(mh.type()); + MethodHandle gimh = MethodHandles.invoker(mh.type()); + MethodHandle simh = MethodHandles.spreadInvoker(mh.type(), 0); + if (arity != 0) { + simh = MethodHandles.spreadInvoker(mh.type(), 1); + } else { + try { + simh = MethodHandles.spreadInvoker(mh.type(), 1); + assert(false) : arity; + } catch (IllegalArgumentException ex) { + System.out.println("OK: "+ex); + } + } + if (arity != 0) { + simh = MethodHandles.spreadInvoker(mh.type(), arity-1); + } else { + try { + simh = MethodHandles.spreadInvoker(mh.type(), arity-1); + assert(false) : arity; + } catch (IllegalArgumentException ex) { + System.out.println("OK: "+ex); + } + } + simh = MethodHandles.spreadInvoker(mh.type(), arity); + } + } } // Make sure the basic argument spreading and varargs mechanisms are working. @@ -133,7 +223,7 @@ if (cls == Object[].class) r = smh.invokeExact(tail); else if (cls == Integer[].class) - r = smh.invokeExact((Integer[]) tail); + r = smh.invokeExact((Integer[]) tail); //warning OK, see 8019340 else r = smh.invoke(tail); assertEquals(r0, r); @@ -235,21 +325,41 @@ MethodHandle mh_VA = mh.asSpreader(cls, arity); assert(mh_VA.type().parameterType(0) == cls); testArities(cls, arity, iterations, verbose, mh, mh_VA); + // mh_CA will collect arguments of a particular type and pass them to mh_VA + MethodHandle mh_CA = mh_VA.asCollector(cls, arity); + MethodHandle mh_VA2 = mh_CA.asSpreader(cls, arity); + assert(mh_CA.type().equals(mh.type())); + assert(mh_VA2.type().equals(mh_VA.type())); if (cls != Object[].class) { - // mh_CA will collect arguments of a particular type and pass them to mh_VA - MethodHandle mh_CA = mh_VA.asCollector(cls, arity); - MethodHandle mh_VA2 = mh_CA.asSpreader(cls, arity); try { mh_VA2.invokeWithArguments(new Object[arity]); throw new AssertionError("should not reach"); } catch (ClassCastException | WrongMethodTypeException ex) { } - assert(mh_CA.type().equals(mh.type())); - assert(mh_VA2.type().equals(mh_VA.type())); - testArities(cls, arity, iterations, false, mh_CA, mh_VA2); } + int iterations_VA = iterations / 100; + testArities(cls, arity, iterations_VA, false, mh_CA, mh_VA2); } } + + /** + * Tests calls to {@link BigArityTest#hashArguments hashArguments} as related to a single given arity N. + * Applies the given {@code mh} to a set of N integer arguments, checking the answer. + * Also applies the varargs variation {@code mh_VA} to an array of type C[] (given by {@code cls}). + * Test steps: + *
      + *
    • mh_VA.invokeExact(new C[]{ arg, ... })
    • + *
    • mh.invokeWithArguments((Object[]) new C[]{ arg, ... })
    • + *
    • exactInvoker(mh.type()).invokeWithArguments(new Object[]{ mh, arg, ... })
    • + *
    • invoker(mh.type()).invokeWithArguments(new Object[]{ mh, arg, ... })
    • + *
    + * @param cls array type for varargs call (one of Object[], Number[], Integer[], Comparable[]) + * @param arity N, the number of arguments to {@code mh} and length of its varargs array, in [0..255] + * @param iterations number of times to repeat each test step (at least 4) + * @param verbose are we printing extra output? + * @param mh a fixed-arity version of {@code hashArguments} + * @param mh_VA a variable-arity version of {@code hashArguments}, accepting the given array type {@code cls} + */ private void testArities(Class cls, int arity, int iterations, @@ -292,7 +402,7 @@ if (cls == Object[].class) r = mh_VA.invokeExact(args); else if (cls == Integer[].class) - r = mh_VA.invokeExact((Integer[])args); + r = mh_VA.invokeExact((Integer[])args); //warning OK, see 8019340 else r = mh_VA.invoke(args); assertEquals(r0, r); @@ -392,10 +502,16 @@ a[0xE0], a[0xE1], a[0xE2], a[0xE3], a[0xE4], a[0xE5], a[0xE6], a[0xE7], a[0xE8], a[0xE9], a[0xEA], a[0xEB], a[0xEC], a[0xED], a[0xEE], a[0xEF], a[0xF0], a[0xF1], a[0xF2], a[0xF3], a[0xF4], a[0xF5], a[0xF6], a[0xF7], // - a[0xF8], a[0xF9], a[0xFA], a[0xFB]); + a[0xF8], a[0xF9], a[0xFA], a[0xFB]); // hashArguments_252 assertEquals(r0, r); MethodType mt = MethodType.genericMethodType(ARITY); MethodHandle mh = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY, mt); + test252(mh, a, r0); + MethodHandle mh_CA = MH_hashArguments_VA.asFixedArity().asCollector(Object[].class, ARITY); + test252(mh_CA, a, r0); + } + public void test252(MethodHandle mh, Object[] a, Object r0) throws Throwable { + Object r; r = mh.invokeExact( // a[0x00], a[0x01], a[0x02], a[0x03], a[0x04], a[0x05], a[0x06], a[0x07], a[0x08], a[0x09], a[0x0A], a[0x0B], a[0x0C], a[0x0D], a[0x0E], a[0x0F], @@ -599,10 +715,16 @@ a[0xE0], a[0xE1], a[0xE2], a[0xE3], a[0xE4], a[0xE5], a[0xE6], a[0xE7], a[0xE8], a[0xE9], a[0xEA], a[0xEB], a[0xEC], a[0xED], a[0xEE], a[0xEF], a[0xF0], a[0xF1], a[0xF2], a[0xF3], a[0xF4], a[0xF5], a[0xF6], a[0xF7], // - a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC]); + a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC]); // hashArguments_253 assertEquals(r0, r); MethodType mt = MethodType.genericMethodType(ARITY); MethodHandle mh = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY, mt); + test253(mh, a, r0); + MethodHandle mh_CA = MH_hashArguments_VA.asFixedArity().asCollector(Object[].class, ARITY); + test253(mh_CA, a, r0); + } + public void test253(MethodHandle mh, Object[] a, Object r0) throws Throwable { + Object r; r = mh.invokeExact( // a[0x00], a[0x01], a[0x02], a[0x03], a[0x04], a[0x05], a[0x06], a[0x07], a[0x08], a[0x09], a[0x0A], a[0x0B], a[0x0C], a[0x0D], a[0x0E], a[0x0F], @@ -648,7 +770,6 @@ // a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC]); assertEquals(r0, r); - // FIXME: This next one fails, because it uses an internal invoker of arity 255. r = ximh.invokeWithArguments(cat(mh,a)); assertEquals(r0, r); MethodHandle gimh = MethodHandles.invoker(mh.type()); @@ -674,7 +795,6 @@ // a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC]); assertEquals(r0, r); - // FIXME: This next one fails, because it uses an internal invoker of arity 255. r = gimh.invokeWithArguments(cat(mh,a)); assertEquals(r0, r); mh = mh.asType(mh.type().changeParameterType(0x10, Integer.class)); @@ -808,10 +928,16 @@ a[0xE0], a[0xE1], a[0xE2], a[0xE3], a[0xE4], a[0xE5], a[0xE6], a[0xE7], a[0xE8], a[0xE9], a[0xEA], a[0xEB], a[0xEC], a[0xED], a[0xEE], a[0xEF], a[0xF0], a[0xF1], a[0xF2], a[0xF3], a[0xF4], a[0xF5], a[0xF6], a[0xF7], // - a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC], a[0xFD]); + a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC], a[0xFD]); // hashArguments_254 assertEquals(r0, r); MethodType mt = MethodType.genericMethodType(ARITY); MethodHandle mh = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY, mt); + test254(mh, a, r0); + MethodHandle mh_CA = MH_hashArguments_VA.asFixedArity().asCollector(Object[].class, ARITY); + test254(mh_CA, a, r0); + } + public void test254(MethodHandle mh, Object[] a, Object r0) throws Throwable { + Object r; r = mh.invokeExact( // a[0x00], a[0x01], a[0x02], a[0x03], a[0x04], a[0x05], a[0x06], a[0x07], a[0x08], a[0x09], a[0x0A], a[0x0B], a[0x0C], a[0x0D], a[0x0E], a[0x0F], @@ -833,7 +959,6 @@ // a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC], a[0xFD]); assertEquals(r0, r); - // FIXME: This next one fails, because it uses an internal invoker of arity 255. r = mh.invokeWithArguments(a); assertEquals(r0, r); try { @@ -998,7 +1123,7 @@ a[0xE0], a[0xE1], a[0xE2], a[0xE3], a[0xE4], a[0xE5], a[0xE6], a[0xE7], a[0xE8], a[0xE9], a[0xEA], a[0xEB], a[0xEC], a[0xED], a[0xEE], a[0xEF], a[0xF0], a[0xF1], a[0xF2], a[0xF3], a[0xF4], a[0xF5], a[0xF6], a[0xF7], // - a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC], a[0xFD], a[0xFE]); + a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC], a[0xFD], a[0xFE]); // hashArguments_255 assertEquals(r0, r); MethodType mt = MethodType.genericMethodType(ARITY); MethodHandle mh; diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/invoke/CallStaticInitOrder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/CallStaticInitOrder.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,275 @@ +/* + * Copyright (c) 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. + * + * 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 + * @summary static initializer invocation order + * + * @build indify.Indify + * @compile CallStaticInitOrder.java + * @run main/othervm + * indify.Indify + * --expand-properties --classpath ${test.classes} + * --java test.java.lang.invoke.CallStaticInitOrder + */ + +package test.java.lang.invoke; + +import java.io.*; + +import java.lang.invoke.*; +import static java.lang.invoke.MethodHandles.*; +import static java.lang.invoke.MethodType.*; + +public class CallStaticInitOrder { + private static int TICK; + private static synchronized int tick(String event) { + int n = ++TICK; + System.out.println("event #"+n+" = "+event); + return n; + } + + static int Init1Tick; + private static class Init1 { + static { Init1Tick = tick("foo -> Init1."); } + static int foo() { return Init1Tick; } + } + + static int Init2Tick; + private static class Init2 { + static { Init2Tick = tick("bar -> Init2."); } + static int bar() { return Init2Tick; } + } + + static int Init3Tick; + private static class Init3 { + static { Init3Tick = tick("baz -> Init3."); } + static int baz() { return Init3Tick; } + } + + static int Init4Tick; + private static class Init4 { + static { Init4Tick = tick("bat -> Init4."); } + static int bat() { return Init4Tick; } + } + + static int Init5Tick; + private static class Init5 { + static { Init5Tick = tick("read bang -> Init5."); } + static int bang = Init5Tick; + } + + static int Init6Tick; + private static class Init6 { + static { Init6Tick = tick("write pong -> Init6."); } + static int pong; + } + + private static final MutableCallSite CONSTANT_CS_baz; + private static MethodHandle MH_foo() throws ReflectiveOperationException { + return lookup().findStatic(Init1.class, "foo", methodType(int.class)); + } + private static final MethodHandle CONSTANT_MH_bar; + private static MethodHandle MH_baz() throws ReflectiveOperationException { + return lookup().findStatic(Init3.class, "baz", methodType(int.class)); + } + private static final MethodHandle CONSTANT_MH_bat; + private static final MethodHandle CONSTANT_MH_bangGetter; + private static final MethodHandle CONSTANT_MH_pongSetter; + static { + try { + int t1 = tick("CallStaticInitOrder."); + { + CONSTANT_CS_baz = new MutableCallSite(methodType(int.class)); + // MH_foo() := lookup().findStatic(Init1.class, "foo", methodType(int.class)); + CONSTANT_MH_bar = lookup().findStatic(Init2.class, "bar", methodType(int.class)); + // MH_baz() := lookup().findStatic(Init3.class, "baz", methodType(int.class)); + CONSTANT_MH_bat = lookup().unreflect(Init4.class.getDeclaredMethod("bat")); + CONSTANT_MH_bangGetter = lookup().findStaticGetter(Init5.class, "bang", int.class); + MethodHandle pongSetter = lookup().findStaticSetter(Init6.class, "pong", int.class); + MethodHandle tickGetter = lookup().findStaticGetter(CallStaticInitOrder.class, "Init6Tick", int.class); + CONSTANT_MH_pongSetter = filterReturnValue(insertArguments(pongSetter, 0, -99), tickGetter); + } + int t2 = tick("CallStaticInitOrder. done"); + assertEquals(t1+1, t2); // no ticks in between + } catch (Exception ex) { + throw new InternalError(ex.toString()); + } + } + + public static void main(String... av) throws Throwable { + testInit(); + if (LAST_LOSER != null) throw LAST_LOSER; + } + + private static Throwable LAST_LOSER; + + private static void assertEquals(int expected, int actual) { + if (expected != actual) { + Throwable loser = new AssertionError("expected: " + expected + ", actual: " + actual); + if (LAST_LOSER != null) + LAST_LOSER.printStackTrace(System.out); + LAST_LOSER = loser; + } + } + + private static void testInit() throws Throwable { + System.out.println("runFoo = "+runFoo()); + System.out.println("runBar = "+runBar()); + try { + runBaz(); + } catch (IllegalStateException ex) { + tick("runBaz throw/catch"); + } + CONSTANT_CS_baz.setTarget(MH_baz()); + System.out.println("runBaz = "+runBaz()); + System.out.println("runBat = "+runBat()); + System.out.println("runBang = "+runBang()); + System.out.println("runPong = "+runPong()); + } + + private static int runFoo() throws Throwable { + assertEquals(Init1Tick, 0); // Init1 not initialized yet + int t1 = tick("runFoo"); + int t2 = (int) INDY_foo().invokeExact(); + int t3 = tick("runFoo done"); + assertEquals(Init1Tick, t2); // when Init1 was initialized + assertEquals(t1+2, t3); // exactly two ticks in between + assertEquals(t1+1, t2); // init happened inside + return t2; + } + private static MethodHandle INDY_foo() throws Throwable { + shouldNotCallThis(); + return ((CallSite) MH_bsm().invoke(lookup(), "foo", methodType(int.class))).dynamicInvoker(); + } + + private static int runBar() throws Throwable { + assertEquals(Init2Tick, 0); // Init2 not initialized yet + int t1 = tick("runBar"); + int t2 = (int) INDY_bar().invokeExact(); + int t3 = tick("runBar done"); + assertEquals(Init2Tick, t2); // when Init2 was initialized + assertEquals(t1+2, t3); // exactly two ticks in between + assertEquals(t1+1, t2); // init happened inside + return t2; + } + private static MethodHandle INDY_bar() throws Throwable { + shouldNotCallThis(); + return ((CallSite) MH_bsm().invoke(lookup(), "bar", methodType(int.class))).dynamicInvoker(); + } + + private static int runBaz() throws Throwable { + assertEquals(Init3Tick, 0); // Init3 not initialized yet + int t1 = tick("runBaz"); + int t2 = (int) INDY_baz().invokeExact(); + int t3 = tick("runBaz done"); + assertEquals(Init3Tick, t2); // when Init3 was initialized + assertEquals(t1+2, t3); // exactly two ticks in between + assertEquals(t1+1, t2); // init happened inside + return t2; + } + private static MethodHandle INDY_baz() throws Throwable { + shouldNotCallThis(); + return ((CallSite) MH_bsm().invoke(lookup(), "baz", methodType(int.class))).dynamicInvoker(); + } + + private static int runBat() throws Throwable { + assertEquals(Init4Tick, 0); // Init4 not initialized yet + int t1 = tick("runBat"); + int t2 = (int) INDY_bat().invokeExact(); + int t3 = tick("runBat done"); + assertEquals(Init4Tick, t2); // when Init4 was initialized + assertEquals(t1+2, t3); // exactly two ticks in between + assertEquals(t1+1, t2); // init happened inside + return t2; + } + private static MethodHandle INDY_bat() throws Throwable { + shouldNotCallThis(); + return ((CallSite) MH_bsm().invoke(lookup(), "bat", methodType(int.class))).dynamicInvoker(); + } + + private static int runBang() throws Throwable { + assertEquals(Init5Tick, 0); // Init5 not initialized yet + int t1 = tick("runBang"); + int t2 = (int) INDY_bang().invokeExact(); + int t3 = tick("runBang done"); + assertEquals(Init5Tick, t2); // when Init5 was initialized + assertEquals(t1+2, t3); // exactly two ticks in between + assertEquals(t1+1, t2); // init happened inside + return t2; + } + private static MethodHandle INDY_bang() throws Throwable { + shouldNotCallThis(); + return ((CallSite) MH_bsm().invoke(lookup(), "bang", methodType(int.class))).dynamicInvoker(); + } + + private static int runPong() throws Throwable { + assertEquals(Init6Tick, 0); // Init6 not initialized yet + int t1 = tick("runPong"); + int t2 = (int) INDY_pong().invokeExact(); + int t3 = tick("runPong done"); + assertEquals(Init6Tick, t2); // when Init6 was initialized + assertEquals(t1+2, t3); // exactly two ticks in between + assertEquals(t1+1, t2); // init happened inside + return t2; + } + private static MethodHandle INDY_pong() throws Throwable { + shouldNotCallThis(); + return ((CallSite) MH_bsm().invoke(lookup(), "pong", methodType(int.class))).dynamicInvoker(); + } + + private static CallSite bsm(Lookup caller, String name, MethodType type) throws ReflectiveOperationException { + System.out.println("bsm "+name+type); + CallSite res; + switch (name) { + case "foo": + res = new ConstantCallSite(MH_foo()); break; + case "bar": + res = new ConstantCallSite(CONSTANT_MH_bar); break; + case "baz": + res = CONSTANT_CS_baz; break; + case "bat": + res = new ConstantCallSite(CONSTANT_MH_bat); break; + case "bang": + res = new ConstantCallSite(CONSTANT_MH_bangGetter); break; + case "pong": + res = new ConstantCallSite(CONSTANT_MH_pongSetter); break; + default: + res = null; + } + if (res == null || !res.type().equals(type)) { + throw new AssertionError(String.valueOf(res)); + } + return res; + } + private static MethodHandle MH_bsm() throws ReflectiveOperationException { + shouldNotCallThis(); + return lookup().findStatic(lookup().lookupClass(), "bsm", + methodType(CallSite.class, Lookup.class, String.class, MethodType.class)); + } + private static void shouldNotCallThis() { + // if this gets called, the transformation has not taken place + throw new AssertionError("this code should be statically transformed away by Indify"); + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/invoke/JavaDocExamplesTest.java --- a/jdk/test/java/lang/invoke/JavaDocExamplesTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/lang/invoke/JavaDocExamplesTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -53,7 +53,11 @@ } public void run() throws Throwable { + testMisc(); + testFindStatic(); + testFindConstructor(); testFindVirtual(); + testFindSpecial(); testPermuteArguments(); testDropArguments(); testFilterArguments(); @@ -99,7 +103,8 @@ {} - @Test public void testFindVirtual() throws Throwable { + @Test public void testMisc() throws Throwable { +// Extra tests, not from javadoc: {} MethodHandle CONCAT_3 = LOOKUP.findVirtual(String.class, "concat", methodType(String.class, String.class)); @@ -114,6 +119,92 @@ {} } + @Test public void testFindStatic() throws Throwable { +{} +MethodHandle MH_asList = publicLookup().findStatic(Arrays.class, + "asList", methodType(List.class, Object[].class)); +assertEquals("[x, y]", MH_asList.invoke("x", "y").toString()); +{} + } + + @Test public void testFindVirtual() throws Throwable { +{} +MethodHandle MH_concat = publicLookup().findVirtual(String.class, + "concat", methodType(String.class, String.class)); +MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class, + "hashCode", methodType(int.class)); +MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class, + "hashCode", methodType(int.class)); +assertEquals("xy", (String) MH_concat.invokeExact("x", "y")); +assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy")); +assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy")); +// interface method: +MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class, + "subSequence", methodType(CharSequence.class, int.class, int.class)); +assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString()); +// constructor "internal method" must be accessed differently: +MethodType MT_newString = methodType(void.class); //()V for new String() +try { assertEquals("impossible", lookup() + .findVirtual(String.class, "", MT_newString)); + } catch (NoSuchMethodException ex) { } // OK +MethodHandle MH_newString = publicLookup() + .findConstructor(String.class, MT_newString); +assertEquals("", (String) MH_newString.invokeExact()); +{} + } + + @Test public void testFindConstructor() throws Throwable { +{} +MethodHandle MH_newArrayList = publicLookup().findConstructor( + ArrayList.class, methodType(void.class, Collection.class)); +Collection orig = Arrays.asList("x", "y"); +Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig); +assert(orig != copy); +assertEquals(orig, copy); +// a variable-arity constructor: +MethodHandle MH_newProcessBuilder = publicLookup().findConstructor( + ProcessBuilder.class, methodType(void.class, String[].class)); +ProcessBuilder pb = (ProcessBuilder) + MH_newProcessBuilder.invoke("x", "y", "z"); +assertEquals("[x, y, z]", pb.command().toString()); +{} + } + +// for testFindSpecial +{} +static class Listie extends ArrayList { + public String toString() { return "[wee Listie]"; } + static Lookup lookup() { return MethodHandles.lookup(); } +} +{} + + @Test public void testFindSpecial() throws Throwable { +{} +// no access to constructor via invokeSpecial: +MethodHandle MH_newListie = Listie.lookup() + .findConstructor(Listie.class, methodType(void.class)); +Listie l = (Listie) MH_newListie.invokeExact(); +try { assertEquals("impossible", Listie.lookup().findSpecial( + Listie.class, "", methodType(void.class), Listie.class)); + } catch (NoSuchMethodException ex) { } // OK +// access to super and self methods via invokeSpecial: +MethodHandle MH_super = Listie.lookup().findSpecial( + ArrayList.class, "toString" , methodType(String.class), Listie.class); +MethodHandle MH_this = Listie.lookup().findSpecial( + Listie.class, "toString" , methodType(String.class), Listie.class); +MethodHandle MH_duper = Listie.lookup().findSpecial( + Object.class, "toString" , methodType(String.class), Listie.class); +assertEquals("[]", (String) MH_super.invokeExact(l)); +assertEquals(""+l, (String) MH_this.invokeExact(l)); +assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method +try { assertEquals("inaccessible", Listie.lookup().findSpecial( + String.class, "toString", methodType(String.class), Listie.class)); + } catch (IllegalAccessException ex) { } // OK +Listie subl = new Listie() { public String toString() { return "[subclass]"; } }; +assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method +{} + } + @Test public void testPermuteArguments() throws Throwable { {{ {} /// JAVADOC @@ -190,6 +281,28 @@ }} } + @Test public void testCollectArguments() throws Throwable { + {{ +{} /// JAVADOC +MethodHandle deepToString = publicLookup() + .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class)); +MethodHandle ts1 = deepToString.asCollector(String[].class, 1); +assertEquals("[strange]", (String) ts1.invokeExact("strange")); +MethodHandle ts2 = deepToString.asCollector(String[].class, 2); +assertEquals("[up, down]", (String) ts2.invokeExact("up", "down")); +MethodHandle ts3 = deepToString.asCollector(String[].class, 3); +MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2); +assertEquals("[top, [up, down], strange]", + (String) ts3_ts2.invokeExact("top", "up", "down", "strange")); +MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1); +assertEquals("[top, [up, down], [strange]]", + (String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange")); +MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3); +assertEquals("[top, [[up, down, strange], charm], bottom]", + (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom")); + }} + } + @Test public void testFoldArguments() throws Throwable { {{ {} /// JAVADOC @@ -264,6 +377,12 @@ MethodHandle eq2 = equals.asSpreader(Object[].class, 2); assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" })); assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" })); +// try to spread from anything but a 2-array: +for (int n = 0; n <= 10; n++) { + Object[] badArityArgs = (n == 2 ? null : new Object[n]); + try { assert((boolean) eq2.invokeExact(badArityArgs) && false); } + catch (IllegalArgumentException ex) { } // OK +} // spread both arguments from a String array: MethodHandle eq2s = equals.asSpreader(String[].class, 2); assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" })); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/invoke/MethodHandlesTest.java --- a/jdk/test/java/lang/invoke/MethodHandlesTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/lang/invoke/MethodHandlesTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -140,7 +140,7 @@ Object actual = calledLog.get(calledLog.size() - 1); if (expected.equals(actual) && verbosity < 9) return; System.out.println("assertCalled "+name+":"); - System.out.println("expected: "+expected); + System.out.println("expected: "+deepToString(expected)); System.out.println("actual: "+actual); System.out.println("ex. types: "+getClasses(expected)); System.out.println("act. types: "+getClasses(actual)); @@ -148,7 +148,25 @@ } static void printCalled(MethodHandle target, String name, Object... args) { if (verbosity >= 3) - System.out.println("calling MH="+target+" to "+name+Arrays.toString(args)); + System.out.println("calling MH="+target+" to "+name+deepToString(args)); + } + static String deepToString(Object x) { + if (x == null) return "null"; + if (x instanceof Collection) + x = ((Collection)x).toArray(); + if (x instanceof Object[]) { + Object[] ax = (Object[]) x; + ax = Arrays.copyOf(ax, ax.length, Object[].class); + for (int i = 0; i < ax.length; i++) + ax[i] = deepToString(ax[i]); + x = Arrays.deepToString(ax); + } + if (x.getClass().isArray()) + try { + x = Arrays.class.getMethod("toString", x.getClass()).invoke(null, x); + } catch (ReflectiveOperationException ex) { throw new Error(ex); } + assert(!(x instanceof Object[])); + return x.toString(); } static Object castToWrapper(Object value, Class dst) { @@ -230,6 +248,12 @@ { param = c; break; } } } + if (param.isArray()) { + Class ctype = param.getComponentType(); + Object arg = Array.newInstance(ctype, 2); + Array.set(arg, 0, randomArg(ctype)); + return arg; + } if (param.isInterface() && param.isAssignableFrom(List.class)) return Arrays.asList("#"+nextArg()); if (param.isInterface() || param.isAssignableFrom(String.class)) @@ -253,6 +277,9 @@ args[i] = randomArg(param); return args; } + static Object[] randomArgs(List> params) { + return randomArgs(params.toArray(new Class[params.size()])); + } @SafeVarargs @SuppressWarnings("varargs") static T[] array(Class atype, E... a) { @@ -323,6 +350,11 @@ } return list.asType(listType); } + /** Variation of varargsList, but with the given ptypes and rtype. */ + static MethodHandle varargsList(List> ptypes, Class rtype) { + MethodHandle list = varargsList(ptypes.size(), rtype); + return list.asType(MethodType.methodType(rtype, ptypes)); + } private static MethodHandle LIST_TO_STRING, LIST_TO_INT; private static String listToString(List x) { return x.toString(); } private static int listToInt(List x) { return x.toString().hashCode(); } @@ -363,6 +395,7 @@ protected Example(String name) { this.name = name; } @SuppressWarnings("LeakingThisInConstructor") protected Example(int x) { this(); called("protected ", this, x); } + //Example(Void x) { does not exist; lookup elicts NoSuchMethodException } @Override public String toString() { return name; } public void v0() { called("v0", this); } @@ -463,6 +496,9 @@ return lookup.in(defc); } + /** Is findVirtual (etc.) of "<init<" supposed to elicit a NoSuchMethodException? */ + final static boolean INIT_REF_CAUSES_NSME = true; + @Test public void testFindStatic() throws Throwable { if (CAN_SKIP_WORKING) return; @@ -483,6 +519,8 @@ testFindStatic(Example.class, Object.class, "s7", float.class, double.class); testFindStatic(false, PRIVATE, Example.class, void.class, "bogus"); + testFindStatic(false, PRIVATE, Example.class, void.class, "", int.class); + testFindStatic(false, PRIVATE, Example.class, void.class, "", Void.class); testFindStatic(false, PRIVATE, Example.class, void.class, "v0"); } @@ -505,11 +543,12 @@ target = maybeMoveIn(lookup, defc).findStatic(defc, methodName, type); } catch (ReflectiveOperationException ex) { noAccess = ex; + assertExceptionClass( + (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("")) + ? NoSuchMethodException.class + : IllegalAccessException.class, + noAccess); if (verbosity >= 5) ex.printStackTrace(System.out); - if (name.contains("bogus")) - assertTrue(noAccess instanceof NoSuchMethodException); - else - assertTrue(noAccess instanceof IllegalAccessException); } if (verbosity >= 3) System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target @@ -527,6 +566,13 @@ System.out.print(':'); } + static void assertExceptionClass(Class expected, + Throwable actual) { + if (expected.isInstance(actual)) return; + actual.printStackTrace(); + assertEquals(expected, actual.getClass()); + } + static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES"); // rough check of name string @@ -556,6 +602,8 @@ testFindVirtual(PubExample.class, void.class, "Pub/pro_v0"); testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "bogus"); + testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "", int.class); + testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "", Void.class); testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "s0"); // test dispatch @@ -568,6 +616,16 @@ testFindVirtual(IntExample.Impl.class, IntExample.class, void.class, "Int/v0"); } + @Test + public void testFindVirtualClone() throws Throwable { + // test some ad hoc system methods + testFindVirtual(false, PUBLIC, Object.class, Object.class, "clone"); + testFindVirtual(true, PUBLIC, Object[].class, Object.class, "clone"); + testFindVirtual(true, PUBLIC, int[].class, Object.class, "clone"); + for (Class cls : new Class[]{ boolean[].class, long[].class, float[].class, char[].class }) + testFindVirtual(true, PUBLIC, cls, Object.class, "clone"); + } + void testFindVirtual(Class defc, Class ret, String name, Class... params) throws Throwable { Class rcvc = defc; testFindVirtual(rcvc, defc, ret, name, params); @@ -580,6 +638,9 @@ void testFindVirtual(Lookup lookup, Class rcvc, Class defc, Class ret, String name, Class... params) throws Throwable { testFindVirtual(true, lookup, rcvc, defc, ret, name, params); } + void testFindVirtual(boolean positive, Lookup lookup, Class defc, Class ret, String name, Class... params) throws Throwable { + testFindVirtual(positive, lookup, defc, defc, ret, name, params); + } void testFindVirtual(boolean positive, Lookup lookup, Class rcvc, Class defc, Class ret, String name, Class... params) throws Throwable { countTest(positive); String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo @@ -591,11 +652,12 @@ target = maybeMoveIn(lookup, defc).findVirtual(defc, methodName, type); } catch (ReflectiveOperationException ex) { noAccess = ex; + assertExceptionClass( + (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("")) + ? NoSuchMethodException.class + : IllegalAccessException.class, + noAccess); if (verbosity >= 5) ex.printStackTrace(System.out); - if (name.contains("bogus")) - assertTrue(noAccess instanceof NoSuchMethodException); - else - assertTrue(noAccess instanceof IllegalAccessException); } if (verbosity >= 3) System.out.println("findVirtual "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target @@ -618,8 +680,21 @@ Object[] argsWithSelf = randomArgs(paramsWithSelf); if (selfc.isAssignableFrom(rcvc) && rcvc != selfc) argsWithSelf[0] = randomArg(rcvc); printCalled(target, name, argsWithSelf); - target.invokeWithArguments(argsWithSelf); - assertCalled(name, argsWithSelf); + Object res = target.invokeWithArguments(argsWithSelf); + if (Example.class.isAssignableFrom(defc) || IntExample.class.isAssignableFrom(defc)) { + assertCalled(name, argsWithSelf); + } else if (name.equals("clone")) { + // Ad hoc method call outside Example. For Object[].clone. + printCalled(target, name, argsWithSelf); + assertEquals(MethodType.methodType(Object.class, rcvc), target.type()); + Object orig = argsWithSelf[0]; + assertEquals(orig.getClass(), res.getClass()); + if (res instanceof Object[]) + assertArrayEquals((Object[])res, (Object[])argsWithSelf[0]); + assert(Arrays.deepEquals(new Object[]{res}, new Object[]{argsWithSelf[0]})); + } else { + assert(false) : Arrays.asList(positive, lookup, rcvc, defc, ret, name, deepToString(params)); + } if (verbosity >= 1) System.out.print(':'); } @@ -632,11 +707,11 @@ testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0"); testFindSpecial(RemoteExample.class, PubExample.class, void.class, "Pub/pro_v0"); // Do some negative testing: - testFindSpecial(false, EXAMPLE, SubExample.class, Example.class, void.class, "bogus"); - testFindSpecial(false, PRIVATE, SubExample.class, Example.class, void.class, "bogus"); for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) { testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0"); + testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "bogus"); testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "", int.class); + testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "", Void.class); testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0"); } } @@ -662,19 +737,25 @@ countTest(positive); String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo MethodType type = MethodType.methodType(ret, params); + Lookup specialLookup = maybeMoveIn(lookup, specialCaller); + boolean specialAccessOK = (specialLookup.lookupClass() == specialCaller && + (specialLookup.lookupModes() & Lookup.PRIVATE) != 0); MethodHandle target = null; Exception noAccess = null; try { if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); - if (verbosity >= 5) System.out.println(" lookup => "+maybeMoveIn(lookup, specialCaller)); - target = maybeMoveIn(lookup, specialCaller).findSpecial(defc, methodName, type, specialCaller); + if (verbosity >= 5) System.out.println(" lookup => "+specialLookup); + target = specialLookup.findSpecial(defc, methodName, type, specialCaller); } catch (ReflectiveOperationException ex) { noAccess = ex; + assertExceptionClass( + (!specialAccessOK) // this check should happen first + ? IllegalAccessException.class + : (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("")) + ? NoSuchMethodException.class + : IllegalAccessException.class, + noAccess); if (verbosity >= 5) ex.printStackTrace(System.out); - if (name.contains("bogus")) - assertTrue(noAccess instanceof NoSuchMethodException); - else - assertTrue(noAccess instanceof IllegalAccessException); } if (verbosity >= 3) System.out.println("findSpecial from "+specialCaller.getName()+" to "+defc.getName()+"."+name+"/"+type+" => "+target @@ -719,7 +800,7 @@ target = lookup.findConstructor(defc, type); } catch (ReflectiveOperationException ex) { noAccess = ex; - assertTrue(noAccess instanceof IllegalAccessException); + assertTrue(noAccess.getClass().getName(), noAccess instanceof IllegalAccessException); } if (verbosity >= 3) System.out.println("findConstructor "+defc.getName()+"./"+type+" => "+target @@ -750,6 +831,8 @@ testBind(Example.class, Object.class, "v2", int.class, Object.class); testBind(Example.class, Object.class, "v2", int.class, int.class); testBind(false, PRIVATE, Example.class, void.class, "bogus"); + testBind(false, PRIVATE, Example.class, void.class, "", int.class); + testBind(false, PRIVATE, Example.class, void.class, "", Void.class); testBind(SubExample.class, void.class, "Sub/v0"); testBind(SubExample.class, void.class, "Sub/pkg_v0"); testBind(IntExample.Impl.class, void.class, "Int/v0"); @@ -773,11 +856,12 @@ target = maybeMoveIn(lookup, defc).bind(receiver, methodName, type); } catch (ReflectiveOperationException ex) { noAccess = ex; + assertExceptionClass( + (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("")) + ? NoSuchMethodException.class + : IllegalAccessException.class, + noAccess); if (verbosity >= 5) ex.printStackTrace(System.out); - if (name.contains("bogus")) - assertTrue(noAccess instanceof NoSuchMethodException); - else - assertTrue(noAccess instanceof IllegalAccessException); } if (verbosity >= 3) System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target @@ -840,6 +924,10 @@ countTest(positive); String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo MethodType type = MethodType.methodType(ret, params); + Lookup specialLookup = (specialCaller != null ? maybeMoveIn(lookup, specialCaller) : null); + boolean specialAccessOK = (specialCaller != null && + specialLookup.lookupClass() == specialCaller && + (specialLookup.lookupModes() & Lookup.PRIVATE) != 0); Method rmethod = defc.getDeclaredMethod(methodName, params); MethodHandle target = null; Exception noAccess = null; @@ -848,16 +936,15 @@ try { if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); if (isSpecial) - target = maybeMoveIn(lookup, specialCaller).unreflectSpecial(rmethod, specialCaller); + target = specialLookup.unreflectSpecial(rmethod, specialCaller); else target = maybeMoveIn(lookup, defc).unreflect(rmethod); } catch (ReflectiveOperationException ex) { noAccess = ex; + assertExceptionClass( + IllegalAccessException.class, // NSME is impossible, since it was already reflected + noAccess); if (verbosity >= 5) ex.printStackTrace(System.out); - if (name.contains("bogus")) - assertTrue(noAccess instanceof NoSuchMethodException); - else - assertTrue(noAccess instanceof IllegalAccessException); } if (verbosity >= 3) System.out.println("unreflect"+(isSpecial?"Special":"")+" "+defc.getName()+"."+name+"/"+type @@ -1091,11 +1178,12 @@ } catch (ReflectiveOperationException ex) { mh = null; noAccess = ex; + assertExceptionClass( + (fname.contains("bogus")) + ? NoSuchFieldException.class + : IllegalAccessException.class, + noAccess); if (verbosity >= 5) ex.printStackTrace(System.out); - if (fname.contains("bogus")) - assertTrue(noAccess instanceof NoSuchFieldException); - else - assertTrue(noAccess instanceof IllegalAccessException); } if (verbosity >= 3) System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype @@ -1753,24 +1841,24 @@ } @Test // SLOW - public void testCollectArguments() throws Throwable { + public void testAsCollector() throws Throwable { if (CAN_SKIP_WORKING) return; - startTest("collectArguments"); + startTest("asCollector"); for (Class argType : new Class[]{Object.class, Integer.class, int.class}) { if (verbosity >= 3) - System.out.println("collectArguments "+argType); + System.out.println("asCollector "+argType); for (int nargs = 0; nargs < 50; nargs++) { if (CAN_TEST_LIGHTLY && nargs > 11) break; for (int pos = 0; pos <= nargs; pos++) { if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue; if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3) continue; - testCollectArguments(argType, pos, nargs); + testAsCollector(argType, pos, nargs); } } } } - public void testCollectArguments(Class argType, int pos, int nargs) throws Throwable { + public void testAsCollector(Class argType, int pos, int nargs) throws Throwable { countTest(); // fake up a MH with the same type as the desired adapter: MethodHandle fake = varargsArray(nargs); @@ -1917,37 +2005,108 @@ } @Test + public void testCollectArguments() throws Throwable { + if (CAN_SKIP_WORKING) return; + startTest("collectArguments"); + testFoldOrCollectArguments(true); + } + + @Test public void testFoldArguments() throws Throwable { if (CAN_SKIP_WORKING) return; startTest("foldArguments"); - for (int nargs = 0; nargs <= 4; nargs++) { - for (int fold = 0; fold <= nargs; fold++) { - for (int pos = 0; pos <= nargs; pos++) { - testFoldArguments(nargs, pos, fold); + testFoldOrCollectArguments(false); + } + + void testFoldOrCollectArguments(boolean isCollect) throws Throwable { + for (Class lastType : new Class[]{ Object.class, String.class, int.class }) { + for (Class collectType : new Class[]{ Object.class, String.class, int.class, void.class }) { + int maxArity = 10; + if (collectType != String.class) maxArity = 5; + if (lastType != Object.class) maxArity = 4; + for (int nargs = 0; nargs <= maxArity; nargs++) { + ArrayList> argTypes = new ArrayList<>(Collections.nCopies(nargs, Object.class)); + int maxMix = 20; + if (collectType != Object.class) maxMix = 0; + Map argTypesSeen = new HashMap<>(); + for (int mix = 0; mix <= maxMix; mix++) { + if (!mixArgs(argTypes, mix, argTypesSeen)) continue; + for (int collect = 0; collect <= nargs; collect++) { + for (int pos = 0; pos <= nargs - collect; pos++) { + testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect); + } + } + } } } } } - void testFoldArguments(int nargs, int pos, int fold) throws Throwable { - if (pos != 0) return; // can fold only at pos=0 for now + boolean mixArgs(List> argTypes, int mix, Map argTypesSeen) { + assert(mix >= 0); + if (mix == 0) return true; // no change + if ((mix >>> argTypes.size()) != 0) return false; + for (int i = 0; i < argTypes.size(); i++) { + if (i >= 31) break; + boolean bit = (mix & (1 << i)) != 0; + if (bit) { + Class type = argTypes.get(i); + if (type == Object.class) + type = String.class; + else if (type == String.class) + type = int.class; + else + type = Object.class; + argTypes.set(i, type); + } + } + Integer prev = argTypesSeen.put(new ArrayList<>(argTypes), mix); + if (prev != null) { + if (verbosity >= 4) System.out.println("mix "+prev+" repeated "+mix+": "+argTypes); + return false; + } + if (verbosity >= 3) System.out.println("mix "+mix+" = "+argTypes); + return true; + } + + void testFoldOrCollectArguments(List> argTypes, // argument types minus the inserted combineType + int pos, int fold, // position and length of the folded arguments + Class combineType, // type returned from the combiner + Class lastType, // type returned from the target + boolean isCollect) throws Throwable { + int nargs = argTypes.size(); + if (pos != 0 && !isCollect) return; // can fold only at pos=0 for now countTest(); - MethodHandle target = varargsList(1 + nargs); - MethodHandle combine = varargsList(fold).asType(MethodType.genericMethodType(fold)); - List argsToPass = Arrays.asList(randomArgs(nargs, Object.class)); + List> combineArgTypes = argTypes.subList(pos, pos + fold); + List> targetArgTypes = new ArrayList<>(argTypes); + if (isCollect) // does targret see arg[pos..pos+cc-1]? + targetArgTypes.subList(pos, pos + fold).clear(); + if (combineType != void.class) + targetArgTypes.add(pos, combineType); + MethodHandle target = varargsList(targetArgTypes, lastType); + MethodHandle combine = varargsList(combineArgTypes, combineType); + List argsToPass = Arrays.asList(randomArgs(argTypes)); if (verbosity >= 3) - System.out.println("fold "+target+" with "+combine); - MethodHandle target2 = MethodHandles.foldArguments(target, combine); + System.out.println((isCollect ? "collect" : "fold")+" "+target+" with "+combine); + MethodHandle target2; + if (isCollect) + target2 = MethodHandles.collectArguments(target, pos, combine); + else + target2 = MethodHandles.foldArguments(target, combine); // Simulate expected effect of combiner on arglist: - List expected = new ArrayList<>(argsToPass); - List argsToFold = expected.subList(pos, pos + fold); + List expectedList = new ArrayList<>(argsToPass); + List argsToFold = expectedList.subList(pos, pos + fold); if (verbosity >= 3) - System.out.println("fold: "+argsToFold+" into "+target2); + System.out.println((isCollect ? "collect" : "fold")+": "+argsToFold+" into "+target2); Object foldedArgs = combine.invokeWithArguments(argsToFold); - argsToFold.add(0, foldedArgs); + if (isCollect) + argsToFold.clear(); + if (combineType != void.class) + argsToFold.add(0, foldedArgs); Object result = target2.invokeWithArguments(argsToPass); if (verbosity >= 3) System.out.println("result: "+result); + Object expected = target.invokeWithArguments(expectedList); if (!expected.equals(result)) System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result+" != "+expected); assertEquals(expected, result); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/invoke/RevealDirectTest.java --- a/jdk/test/java/lang/invoke/RevealDirectTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/lang/invoke/RevealDirectTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -104,6 +104,9 @@ private static Lookup localLookup() { return lookup(); } private static List members() { return getMembers(lookup().lookupClass()); }; } + static class Nestmate { + private static Lookup localLookup() { return lookup(); } + } static boolean VERBOSE = false; @@ -152,7 +155,10 @@ getMembers(Method.class, "invoke")); mems = callerSensitive(true, publicOnly(mems)); // CS methods cannot be looked up with publicLookup - testOnMembersNoLookup("testCallerSensitiveNegative", mems, publicLookup()); + testOnMembersNoLookup("testCallerSensitiveNegative/1", mems, publicLookup()); + // CS methods have to be revealed with a matching lookupClass + testOnMembersNoReveal("testCallerSensitiveNegative/2", mems, Simple.localLookup(), publicLookup()); + testOnMembersNoReveal("testCallerSensitiveNegative/3", mems, Simple.localLookup(), Nestmate.localLookup()); } @Test public void testMethodHandleNatives() throws Throwable { if (VERBOSE) System.out.println("@Test testMethodHandleNatives"); @@ -703,7 +709,7 @@ try { info = revLookup.revealDirect(mh); if (expectEx2) throw new AssertionError("unexpected revelation for negative test"); - } catch (Throwable ex2) { + } catch (IllegalArgumentException|SecurityException ex2) { if (VERBOSE) System.out.println(" "+variation+": "+res+" => "+mh.getClass().getName()+" => (EX2)"+ex2); if (expectEx2) continue; // this is OK; we expected the reflect to fail diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/invoke/TestPrivateMember.java --- a/jdk/test/java/lang/invoke/TestPrivateMember.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/lang/invoke/TestPrivateMember.java Tue Oct 08 14:57:32 2013 -0700 @@ -47,7 +47,10 @@ MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodType mt = MethodType.methodType(void.class); try { - MethodHandle mh = lookup.findStatic(Class.class, "checkInitted", mt); + Class checkInittedHolder = TestPrivateMemberPackageSibling.class; + // Original model: checkInittedHolder = Class.class; + // Not using Class.checkInitted because it could change without notice. + MethodHandle mh = lookup.findStatic(checkInittedHolder, "checkInitted", mt); throw new RuntimeException("IllegalAccessException not thrown"); } catch (IllegalAccessException e) { // okay @@ -55,3 +58,7 @@ } } } + +class TestPrivateMemberPackageSibling { + private static void checkInitted() { } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/reflect/Parameter/BadClassFiles.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Parameter/BadClassFiles.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,462 @@ +/* + * Copyright (c) 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. + * + * 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 + * @run main BadClassFiles + * @summary The reflection API should throw the correct exceptions. + */ +import java.lang.Class; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.lang.reflect.MalformedParametersException; +import java.lang.ClassLoader; +import java.lang.ClassNotFoundException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +public class BadClassFiles { + private int errors = 0; + + + /* Class files were created by compiling the following source and + * then editing it: + * + * public class EmptyName { + * public void m(int a, int b) {} + * } + * + */ + private static final byte[] EmptyName_bytes = { + -54,-2,-70,-66,0,0,0,52, + 0,18,10,0,3,0,15,7, + 0,16,7,0,17,1,0,6, + 60,105,110,105,116,62,1,0, + 3,40,41,86,1,0,4,67, + 111,100,101,1,0,15,76,105, + 110,101,78,117,109,98,101,114, + 84,97,98,108,101,1,0,1, + 109,1,0,5,40,73,73,41, + 86,1,0,16,77,101,116,104, + 111,100,80,97,114,97,109,101, + 116,101,114,115,1,0,0,1, + 0,1,98,1,0,10,83,111, + 117,114,99,101,70,105,108,101, + 1,0,14,69,109,112,116,121, + 78,97,109,101,46,106,97,118, + 97,12,0,4,0,5,1,0, + 9,69,109,112,116,121,78,97, + 109,101,1,0,16,106,97,118, + 97,47,108,97,110,103,47,79, + 98,106,101,99,116,0,33,0, + 2,0,3,0,0,0,0,0, + 2,0,1,0,4,0,5,0, + 1,0,6,0,0,0,29,0, + 1,0,1,0,0,0,5,42, + -73,0,1,-79,0,0,0,1, + 0,7,0,0,0,6,0,1, + 0,0,0,1,0,1,0,8, + 0,9,0,2,0,6,0,0, + 0,25,0,0,0,3,0,0, + 0,1,-79,0,0,0,1,0, + 7,0,0,0,6,0,1,0, + 0,0,2,0,10,0,0,0, + 9,2,0,11,0,0,0,12, + 0,0,0,1,0,13,0,0, + 0,2,0,14 + }; + + private static final byte[] BadModifiers_bytes = { + -54,-2,-70,-66,0,0,0,52, + 0,18,10,0,3,0,15,7, + 0,16,7,0,17,1,0,6, + 60,105,110,105,116,62,1,0, + 3,40,41,86,1,0,4,67, + 111,100,101,1,0,15,76,105, + 110,101,78,117,109,98,101,114, + 84,97,98,108,101,1,0,1, + 109,1,0,5,40,73,73,41, + 86,1,0,16,77,101,116,104, + 111,100,80,97,114,97,109,101, + 116,101,114,115,1,0,1,97, + 1,0,1,98,1,0,10,83, + 111,117,114,99,101,70,105,108, + 101,1,0,17,66,97,100,77, + 111,100,105,102,105,101,114,115, + 46,106,97,118,97,12,0,4, + 0,5,1,0,12,66,97,100, + 77,111,100,105,102,105,101,114, + 115,1,0,16,106,97,118,97, + 47,108,97,110,103,47,79,98, + 106,101,99,116,0,33,0,2, + 0,3,0,0,0,0,0,2, + 0,1,0,4,0,5,0,1, + 0,6,0,0,0,29,0,1, + 0,1,0,0,0,5,42,-73, + 0,1,-79,0,0,0,1,0, + 7,0,0,0,6,0,1,0, + 0,0,1,0,1,0,8,0, + 9,0,2,0,6,0,0,0, + 25,0,0,0,3,0,0,0, + 1,-79,0,0,0,1,0,7, + 0,0,0,6,0,1,0,0, + 0,2,0,10,0,0,0,9, + 2,0,11,0,51,51,12,0, + 0,0,1,0,13,0,0,0, + 2,0,14 + }; + + private static final byte[] BadNameIndex_bytes = { + -54,-2,-70,-66,0,0,0,52, + 0,18,10,0,3,0,15,7, + 0,16,7,0,17,1,0,6, + 60,105,110,105,116,62,1,0, + 3,40,41,86,1,0,4,67, + 111,100,101,1,0,15,76,105, + 110,101,78,117,109,98,101,114, + 84,97,98,108,101,1,0,1, + 109,1,0,5,40,73,73,41, + 86,1,0,16,77,101,116,104, + 111,100,80,97,114,97,109,101, + 116,101,114,115,1,0,1,97, + 1,0,1,98,1,0,10,83, + 111,117,114,99,101,70,105,108, + 101,1,0,17,66,97,100,78, + 97,109,101,73,110,100,101,120, + 46,106,97,118,97,12,0,4, + 0,5,1,0,12,66,97,100, + 78,97,109,101,73,110,100,101, + 120,1,0,16,106,97,118,97, + 47,108,97,110,103,47,79,98, + 106,101,99,116,0,33,0,2, + 0,3,0,0,0,0,0,2, + 0,1,0,4,0,5,0,1, + 0,6,0,0,0,29,0,1, + 0,1,0,0,0,5,42,-73, + 0,1,-79,0,0,0,1,0, + 7,0,0,0,6,0,1,0, + 0,0,1,0,1,0,8,0, + 9,0,2,0,6,0,0,0, + 25,0,0,0,3,0,0,0, + 1,-79,0,0,0,1,0,7, + 0,0,0,6,0,1,0,0, + 0,2,0,10,0,0,0,9, + 2,0,1,0,0,0,12,0, + 0,0,1,0,13,0,0,0, + 2,0,14 + }; + + private static final byte[] NameIndexOutOfBounds_bytes = { + -54,-2,-70,-66,0,0,0,52, + 0,18,10,0,3,0,15,7, + 0,16,7,0,17,1,0,6, + 60,105,110,105,116,62,1,0, + 3,40,41,86,1,0,4,67, + 111,100,101,1,0,15,76,105, + 110,101,78,117,109,98,101,114, + 84,97,98,108,101,1,0,1, + 109,1,0,5,40,73,73,41, + 86,1,0,16,77,101,116,104, + 111,100,80,97,114,97,109,101, + 116,101,114,115,1,0,1,97, + 1,0,1,98,1,0,10,83, + 111,117,114,99,101,70,105,108, + 101,1,0,25,78,97,109,101, + 73,110,100,101,120,79,117,116, + 79,102,66,111,117,110,100,115, + 46,106,97,118,97,12,0,4, + 0,5,1,0,20,78,97,109, + 101,73,110,100,101,120,79,117, + 116,79,102,66,111,117,110,100, + 115,1,0,16,106,97,118,97, + 47,108,97,110,103,47,79,98, + 106,101,99,116,0,33,0,2, + 0,3,0,0,0,0,0,2, + 0,1,0,4,0,5,0,1, + 0,6,0,0,0,29,0,1, + 0,1,0,0,0,5,42,-73, + 0,1,-79,0,0,0,1,0, + 7,0,0,0,6,0,1,0, + 0,0,1,0,1,0,8,0, + 9,0,2,0,6,0,0,0, + 25,0,0,0,3,0,0,0, + 1,-79,0,0,0,1,0,7, + 0,0,0,6,0,1,0,0, + 0,2,0,10,0,0,0,9, + 2,0,-1,0,0,0,12,0, + 0,0,1,0,13,0,0,0, + 2,0,14 + + }; + + private static final byte[] ExtraParams_bytes = { + -54,-2,-70,-66,0,0,0,52, + 0,18,10,0,3,0,15,7, + 0,16,7,0,17,1,0,6, + 60,105,110,105,116,62,1,0, + 3,40,41,86,1,0,4,67, + 111,100,101,1,0,15,76,105, + 110,101,78,117,109,98,101,114, + 84,97,98,108,101,1,0,1, + 109,1,0,5,40,73,73,41, + 86,1,0,16,77,101,116,104, + 111,100,80,97,114,97,109,101, + 116,101,114,115,1,0,1,97, + 1,0,1,98,1,0,10,83, + 111,117,114,99,101,70,105,108, + 101,1,0,16,69,120,116,114, + 97,80,97,114,97,109,115,46, + 106,97,118,97,12,0,4,0, + 5,1,0,11,69,120,116,114, + 97,80,97,114,97,109,115,1, + 0,16,106,97,118,97,47,108, + 97,110,103,47,79,98,106,101, + 99,116,0,33,0,2,0,3, + 0,0,0,0,0,2,0,1, + 0,4,0,5,0,1,0,6, + 0,0,0,29,0,1,0,1, + 0,0,0,5,42,-73,0,1, + -79,0,0,0,1,0,7,0, + 0,0,6,0,1,0,0,0, + 1,0,1,0,8,0,9,0, + 2,0,6,0,0,0,25,0, + 0,0,3,0,0,0,1,-79, + 0,0,0,1,0,7,0,0, + 0,6,0,1,0,0,0,2, + 0,10,0,0,0,13,3,0, + 11,0,0,0,12,0,0,0, + 11,0,0,0,1,0,13,0, + 0,0,2,0,14 + }; + + private static final byte[] BadName1_bytes = { + -54,-2,-70,-66,0,0,0,52, + 0,18,10,0,3,0,15,7, + 0,16,7,0,17,1,0,6, + 60,105,110,105,116,62,1,0, + 3,40,41,86,1,0,4,67, + 111,100,101,1,0,15,76,105, + 110,101,78,117,109,98,101,114, + 84,97,98,108,101,1,0,1, + 109,1,0,5,40,73,73,41, + 86,1,0,16,77,101,116,104, + 111,100,80,97,114,97,109,101, + 116,101,114,115,1,0,1,46, + 1,0,1,98,1,0,10,83, + 111,117,114,99,101,70,105,108, + 101,1,0,13,66,97,100,78, + 97,109,101,49,46,106,97,118, + 97,12,0,4,0,5,1,0, + 8,66,97,100,78,97,109,101, + 49,1,0,16,106,97,118,97, + 47,108,97,110,103,47,79,98, + 106,101,99,116,0,33,0,2, + 0,3,0,0,0,0,0,2, + 0,1,0,4,0,5,0,1, + 0,6,0,0,0,29,0,1, + 0,1,0,0,0,5,42,-73, + 0,1,-79,0,0,0,1,0, + 7,0,0,0,6,0,1,0, + 0,0,1,0,1,0,8,0, + 9,0,2,0,6,0,0,0, + 25,0,0,0,3,0,0,0, + 1,-79,0,0,0,1,0,7, + 0,0,0,6,0,1,0,0, + 0,2,0,10,0,0,0,9, + 2,0,11,0,0,0,12,0, + 0,0,1,0,13,0,0,0, + 2,0,14 + }; + + private static final byte[] BadName2_bytes = { + -54,-2,-70,-66,0,0,0,52, + 0,18,10,0,3,0,15,7, + 0,16,7,0,17,1,0,6, + 60,105,110,105,116,62,1,0, + 3,40,41,86,1,0,4,67, + 111,100,101,1,0,15,76,105, + 110,101,78,117,109,98,101,114, + 84,97,98,108,101,1,0,1, + 109,1,0,5,40,73,73,41, + 86,1,0,16,77,101,116,104, + 111,100,80,97,114,97,109,101, + 116,101,114,115,1,0,1,91, + 1,0,1,98,1,0,10,83, + 111,117,114,99,101,70,105,108, + 101,1,0,13,66,97,100,78, + 97,109,101,50,46,106,97,118, + 97,12,0,4,0,5,1,0, + 8,66,97,100,78,97,109,101, + 50,1,0,16,106,97,118,97, + 47,108,97,110,103,47,79,98, + 106,101,99,116,0,33,0,2, + 0,3,0,0,0,0,0,2, + 0,1,0,4,0,5,0,1, + 0,6,0,0,0,29,0,1, + 0,1,0,0,0,5,42,-73, + 0,1,-79,0,0,0,1,0, + 7,0,0,0,6,0,1,0, + 0,0,1,0,1,0,8,0, + 9,0,2,0,6,0,0,0, + 25,0,0,0,3,0,0,0, + 1,-79,0,0,0,1,0,7, + 0,0,0,6,0,1,0,0, + 0,2,0,10,0,0,0,9, + 2,0,11,0,0,0,12,0, + 0,0,1,0,13,0,0,0, + 2,0,14 + }; + + private static final byte[] BadName3_bytes = { + -54,-2,-70,-66,0,0,0,52, + 0,18,10,0,3,0,15,7, + 0,16,7,0,17,1,0,6, + 60,105,110,105,116,62,1,0, + 3,40,41,86,1,0,4,67, + 111,100,101,1,0,15,76,105, + 110,101,78,117,109,98,101,114, + 84,97,98,108,101,1,0,1, + 109,1,0,5,40,73,73,41, + 86,1,0,16,77,101,116,104, + 111,100,80,97,114,97,109,101, + 116,101,114,115,1,0,1,59, + 1,0,1,98,1,0,10,83, + 111,117,114,99,101,70,105,108, + 101,1,0,13,66,97,100,78, + 97,109,101,51,46,106,97,118, + 97,12,0,4,0,5,1,0, + 8,66,97,100,78,97,109,101, + 51,1,0,16,106,97,118,97, + 47,108,97,110,103,47,79,98, + 106,101,99,116,0,33,0,2, + 0,3,0,0,0,0,0,2, + 0,1,0,4,0,5,0,1, + 0,6,0,0,0,29,0,1, + 0,1,0,0,0,5,42,-73, + 0,1,-79,0,0,0,1,0, + 7,0,0,0,6,0,1,0, + 0,0,1,0,1,0,8,0, + 9,0,2,0,6,0,0,0, + 25,0,0,0,3,0,0,0, + 1,-79,0,0,0,1,0,7, + 0,0,0,6,0,1,0,0, + 0,2,0,10,0,0,0,9, + 2,0,11,0,0,0,12,0, + 0,0,1,0,13,0,0,0, + 2,0,14 + }; + + private static final byte[] BadName4_bytes = { + -54,-2,-70,-66,0,0,0,52, + 0,18,10,0,3,0,15,7, + 0,16,7,0,17,1,0,6, + 60,105,110,105,116,62,1,0, + 3,40,41,86,1,0,4,67, + 111,100,101,1,0,15,76,105, + 110,101,78,117,109,98,101,114, + 84,97,98,108,101,1,0,1, + 109,1,0,5,40,73,73,41, + 86,1,0,16,77,101,116,104, + 111,100,80,97,114,97,109,101, + 116,101,114,115,1,0,1,47, + 1,0,1,98,1,0,10,83, + 111,117,114,99,101,70,105,108, + 101,1,0,13,66,97,100,78, + 97,109,101,52,46,106,97,118, + 97,12,0,4,0,5,1,0, + 8,66,97,100,78,97,109,101, + 52,1,0,16,106,97,118,97, + 47,108,97,110,103,47,79,98, + 106,101,99,116,0,33,0,2, + 0,3,0,0,0,0,0,2, + 0,1,0,4,0,5,0,1, + 0,6,0,0,0,29,0,1, + 0,1,0,0,0,5,42,-73, + 0,1,-79,0,0,0,1,0, + 7,0,0,0,6,0,1,0, + 0,0,1,0,1,0,8,0, + 9,0,2,0,6,0,0,0, + 25,0,0,0,3,0,0,0, + 1,-79,0,0,0,1,0,7, + 0,0,0,6,0,1,0,0, + 0,2,0,10,0,0,0,9, + 2,0,11,0,0,0,12,0, + 0,0,1,0,13,0,0,0, + 2,0,14 + }; + + private static class InMemoryClassLoader extends ClassLoader { + public Class defineClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }; + + private static final InMemoryClassLoader loader = new InMemoryClassLoader(); + + private final Class[] classes; + + private BadClassFiles() throws ClassNotFoundException { + classes = new Class[] { + loader.defineClass("EmptyName", EmptyName_bytes), + loader.defineClass("BadModifiers", BadModifiers_bytes), + loader.defineClass("BadNameIndex", BadNameIndex_bytes), + loader.defineClass("NameIndexOutOfBounds", NameIndexOutOfBounds_bytes), + loader.defineClass("ExtraParams", ExtraParams_bytes), + // Name with . + loader.defineClass("BadName1", BadName1_bytes), + // Name with [ + loader.defineClass("BadName2", BadName2_bytes), + // Name with ; + loader.defineClass("BadName3", BadName3_bytes), + // Name with / + loader.defineClass("BadName4", BadName4_bytes) + }; + } + + public static void main(String... args) + throws NoSuchMethodException, IOException, ClassNotFoundException { + new BadClassFiles().run(); + } + + public void assertBadParameters(Class cls) throws NoSuchMethodException { + try { + System.err.println("Trying " + cls); + final Method method = cls.getMethod("m", int.class, int.class); + final Parameter[] params = method.getParameters(); + System.err.println("Name " + params[0].getName()); + System.err.println("Did not see expected exception"); + errors++; + } catch(MalformedParametersException e) { + System.err.println("Expected exception seen"); + } + } + + public void run() throws NoSuchMethodException { + for (Class cls : classes) + assertBadParameters(cls); + + if (errors != 0) + throw new RuntimeException(errors + " errors in test"); + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/lang/reflect/Parameter/GetAnnotatedTypeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Parameter/GetAnnotatedTypeTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 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. + * + * 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 + * @compile -parameters GetAnnotatedTypeTest.java + * @run main GetAnnotatedTypeTest + * @summary javac should generate method parameters correctly. + */ + +public class GetAnnotatedTypeTest { + + public void meth(Object param) {} + + public static void main(String[] args) throws NoSuchMethodException { + if (GetAnnotatedTypeTest.class.getMethod("meth", Object.class).getParameters()[0].getAnnotatedType().getType() != Object.class) + throw new RuntimeException("Parameter did not have the expected annotated type"); + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/net/PlainSocketImpl/CustomSocketImplFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/net/PlainSocketImpl/CustomSocketImplFactory.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 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. + * + * 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 8024952 + * @summary ClassCastException in PlainSocketImpl.accept() when using custom socketImpl + * @run main/othervm CustomSocketImplFactory + */ + +import java.net.*; +import java.io.*; + +public class CustomSocketImplFactory implements SocketImplFactory { + + @Override + public SocketImpl createSocketImpl() { + try { + SocketImpl s = new CustomSocketImpl(); + System.out.println("Created " + s); + return s; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) throws Exception { + + Socket.setSocketImplFactory(new CustomSocketImplFactory()); + try (ServerSocket ss = new ServerSocket(0)) { + ss.setSoTimeout(1); + ss.accept(); + System.out.println("PASS"); + } catch (SocketTimeoutException | NullPointerException e) { + // Not a real socket impl + } + } + + class CustomSocketImpl extends SocketImpl { + + public void create(boolean stream) throws IOException { + } + + public void connect(String host, int port) throws IOException { + } + + public void connect(InetAddress addr, int port) throws IOException { + } + + public void connect(SocketAddress addr, int timeout) throws IOException { + } + + public void bind(InetAddress host, int port) throws IOException { + } + + public void listen(int backlog) throws IOException { + } + + public void accept(SocketImpl s) throws IOException { + } + + public InputStream getInputStream() throws IOException { + return null; + } + + public OutputStream getOutputStream() throws IOException { + return null; + } + + public int available() throws IOException { + return 0; + } + + public void close() throws IOException { + } + + public void sendUrgentData(int data) throws IOException { + } + + public Object getOption(int i) throws SocketException { + return null; + } + + public void setOption(int i, Object o) throws SocketException { + } + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/nio/file/Files/BytesAndLines.java --- a/jdk/test/java/nio/file/Files/BytesAndLines.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/nio/file/Files/BytesAndLines.java Tue Oct 08 14:57:32 2013 -0700 @@ -22,7 +22,9 @@ */ /* @test - * @bug 7006126 8020669 + * @bug 7006126 8020669 8024788 + * @build BytesAndLines PassThroughFileSystem + * @run main BytesAndLines * @summary Unit test for methods for Files readAllBytes, readAllLines and * and write methods. */ @@ -92,6 +94,16 @@ byte[] data = Files.readAllBytes(pathStat); assertTrue(data.length > 0, "Files.readAllBytes('" + statFile + "') failed to read"); } + + // test readAllBytes on custom file system + Path myfile = PassThroughFileSystem.create().getPath(file.toString()); + for (int size=0; size<=1024; size+=512) { + byte[] b1 = new byte[size]; + rand.nextBytes(b1); + Files.write(myfile, b1); + byte[] b2 = Files.readAllBytes(myfile); + assertTrue(Arrays.equals(b1, b2), "bytes not equal"); + } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/security/Provider/ProviderVersionCheck.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/security/Provider/ProviderVersionCheck.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 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. + * + * 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 java.security.Provider; +import java.security.Security; +import java.lang.Exception; + +/* + * @test + * @bug 7122707 + * @run main/othervm ProviderVersionCheck + * @summary Verify all providers in the default Providers list have the proper + * version for the release + * @author Anthony Scarpino + */ + +public class ProviderVersionCheck { + + public static void main(String arg[]) throws Exception{ + + boolean failure = false; + + for (Provider p: Security.getProviders()) { + System.out.print(p.getName() + " "); + if (p.getVersion() != 1.8d) { + System.out.println("failed. " + "Version received was " + + p.getVersion()); + failure = true; + } else { + System.out.println("passed."); + } + } + + if (failure) { + throw new Exception("Provider(s) failed to have the expected " + + "version value."); + } + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/AbstractTCKTest.java --- a/jdk/test/java/time/tck/java/time/AbstractTCKTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/AbstractTCKTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -68,6 +68,8 @@ import java.io.ObjectStreamConstants; import java.io.Serializable; import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Formatter; /** * Base test class. @@ -131,10 +133,10 @@ assertEquals(dis.readByte(), ObjectStreamConstants.TC_NULL); // no superclasses if (expectedBytes.length < 256) { assertEquals(dis.readByte(), ObjectStreamConstants.TC_BLOCKDATA); - assertEquals(dis.readUnsignedByte(), expectedBytes.length); + assertEquals(dis.readUnsignedByte(), expectedBytes.length, "blockdata length incorrect"); } else { assertEquals(dis.readByte(), ObjectStreamConstants.TC_BLOCKDATALONG); - assertEquals(dis.readInt(), expectedBytes.length); + assertEquals(dis.readInt(), expectedBytes.length, "blockdatalong length incorrect"); } byte[] input = new byte[expectedBytes.length]; dis.readFully(input); @@ -162,4 +164,33 @@ } } + + /** + * Utility method to dump a byte array in a java syntax. + * @param bytes and array of bytes + * @return a string containing the bytes formatted in java syntax + */ + protected static String dumpSerialStream(byte[] bytes) { + StringBuilder sb = new StringBuilder(bytes.length * 5); + Formatter fmt = new Formatter(sb); + fmt.format(" byte[] bytes = {" ); + final int linelen = 10; + for (int i = 0; i < bytes.length; i++) { + if (i % linelen == 0) { + fmt.format("%n "); + } + fmt.format(" %3d,", bytes[i] & 0xff); + if ((i % linelen) == (linelen-1) || i == bytes.length - 1) { + fmt.format(" /*"); + int s = i / linelen * linelen; + int k = i % linelen; + for (int j = 0; j <= k && s + j < bytes.length; j++) { + fmt.format(" %c", bytes[s + j] & 0xff); + } + fmt.format(" */"); + } + } + fmt.format("%n };%n"); + return sb.toString(); + } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKClock_Fixed.java --- a/jdk/test/java/time/tck/java/time/TCKClock_Fixed.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKClock_Fixed.java Tue Oct 08 14:57:32 2013 -0700 @@ -80,12 +80,6 @@ private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); private static final Instant INSTANT = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).atZone(ZoneOffset.ofHours(2)).toInstant(); - //----------------------------------------------------------------------- - public void test_isSerializable() throws IOException, ClassNotFoundException { - assertSerializable(Clock.fixed(INSTANT, ZoneOffset.UTC)); - assertSerializable(Clock.fixed(INSTANT, PARIS)); - } - //------------------------------------------------------------------------- public void test_fixed_InstantZoneId() { Clock test = Clock.fixed(INSTANT, PARIS); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKClock_Offset.java --- a/jdk/test/java/time/tck/java/time/TCKClock_Offset.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKClock_Offset.java Tue Oct 08 14:57:32 2013 -0700 @@ -62,7 +62,6 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertSame; -import java.io.IOException; import java.time.Clock; import java.time.Duration; import java.time.Instant; @@ -84,11 +83,6 @@ private static final Duration OFFSET = Duration.ofSeconds(2); //----------------------------------------------------------------------- - public void test_isSerializable() throws IOException, ClassNotFoundException { - assertSerializable(Clock.offset(Clock.system(PARIS), OFFSET)); - } - - //----------------------------------------------------------------------- public void test_offset_ClockDuration() { Clock test = Clock.offset(Clock.fixed(INSTANT, PARIS), OFFSET); //System.out.println(test.instant()); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKClock_System.java --- a/jdk/test/java/time/tck/java/time/TCKClock_System.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKClock_System.java Tue Oct 08 14:57:32 2013 -0700 @@ -62,7 +62,6 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; -import java.io.IOException; import java.time.Clock; import java.time.Instant; import java.time.ZoneId; @@ -80,13 +79,6 @@ private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); //----------------------------------------------------------------------- - public void test_isSerializable() throws IOException, ClassNotFoundException { - assertSerializable(Clock.systemUTC()); - assertSerializable(Clock.systemDefaultZone()); - assertSerializable(Clock.system(PARIS)); - } - - //----------------------------------------------------------------------- public void test_instant() { Clock system = Clock.systemUTC(); assertEquals(system.getZone(), ZoneOffset.UTC); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKClock_Tick.java --- a/jdk/test/java/time/tck/java/time/TCKClock_Tick.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKClock_Tick.java Tue Oct 08 14:57:32 2013 -0700 @@ -62,7 +62,6 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertSame; -import java.io.IOException; import java.time.Clock; import java.time.Duration; import java.time.Instant; @@ -81,16 +80,7 @@ private static final ZoneId MOSCOW = ZoneId.of("Europe/Moscow"); private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); - private static final Duration AMOUNT = Duration.ofSeconds(2); private static final ZonedDateTime ZDT = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).atZone(ZoneOffset.ofHours(2)); - private static final Instant INSTANT = ZDT.toInstant(); - - //----------------------------------------------------------------------- - public void test_isSerializable() throws IOException, ClassNotFoundException { - assertSerializable(Clock.tickSeconds(PARIS)); - assertSerializable(Clock.tickMinutes(MOSCOW)); - assertSerializable(Clock.tick(Clock.fixed(INSTANT, PARIS), AMOUNT)); - } //----------------------------------------------------------------------- public void test_tick_ClockDuration_250millis() { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKDuration.java --- a/jdk/test/java/time/tck/java/time/TCKDuration.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKDuration.java Tue Oct 08 14:57:32 2013 -0700 @@ -77,6 +77,7 @@ import java.time.DateTimeException; import java.time.Duration; import java.time.Instant; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Period; @@ -104,26 +105,6 @@ private static final long CYCLE_SECS = 146097L * 86400L; //----------------------------------------------------------------------- - @Test - public void test_serialization() throws Exception { - assertSerializable(Duration.ofHours(5)); - assertSerializable(Duration.ofHours(0)); - assertSerializable(Duration.ofHours(-5)); - } - - @Test - public void test_serialization_format() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(1); - dos.writeLong(654321); - dos.writeInt(123456789); - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(Duration.ofSeconds(654321, 123456789), bytes); - } - - //----------------------------------------------------------------------- // constants //----------------------------------------------------------------------- @Test @@ -863,10 +844,17 @@ assertEquals(Duration.between(end, start), Duration.between(start, end).negated()); } - @Test(expectedExceptions=DateTimeException.class) + @Test public void factory_between_TemporalTemporal_mixedTypes() { Instant start = Instant.ofEpochSecond(1); ZonedDateTime end = Instant.ofEpochSecond(4).atZone(ZoneOffset.UTC); + assertEquals(Duration.between(start, end), Duration.ofSeconds(3)); + } + + @Test(expectedExceptions=DateTimeException.class) + public void factory_between_TemporalTemporal_invalidMixedTypes() { + Instant start = Instant.ofEpochSecond(1); + LocalDate end = LocalDate.of(2010, 6, 20); Duration.between(start, end); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKInstant.java --- a/jdk/test/java/time/tck/java/time/TCKInstant.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKInstant.java Tue Oct 08 14:57:32 2013 -0700 @@ -84,6 +84,7 @@ import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.ZoneOffset; @@ -155,24 +156,6 @@ } //----------------------------------------------------------------------- - @Test - public void test_serialization() throws Exception { - assertSerializable(Instant.ofEpochMilli(134l)); - } - - @Test - public void test_serialization_format() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(2); - dos.writeLong(654321); - dos.writeInt(123456789); - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(Instant.ofEpochSecond(654321, 123456789), bytes); - } - - //----------------------------------------------------------------------- private void check(Instant instant, long epochSecs, int nos) { assertEquals(instant.getEpochSecond(), epochSecs); assertEquals(instant.getNano(), nos); @@ -1818,7 +1801,7 @@ } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit(long seconds1, int nanos1, long seconds2, long nanos2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit(long seconds1, int nanos1, long seconds2, long nanos2, TemporalUnit unit, long expected) { Instant i1 = Instant.ofEpochSecond(seconds1, nanos1); Instant i2 = Instant.ofEpochSecond(seconds2, nanos2); long amount = i1.until(i2, unit); @@ -1826,25 +1809,46 @@ } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit_negated(long seconds1, int nanos1, long seconds2, long nanos2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit_negated(long seconds1, int nanos1, long seconds2, long nanos2, TemporalUnit unit, long expected) { Instant i1 = Instant.ofEpochSecond(seconds1, nanos1); Instant i2 = Instant.ofEpochSecond(seconds2, nanos2); long amount = i2.until(i1, unit); assertEquals(amount, -expected); } + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(long seconds1, int nanos1, long seconds2, long nanos2, TemporalUnit unit, long expected) { + Instant i1 = Instant.ofEpochSecond(seconds1, nanos1); + Instant i2 = Instant.ofEpochSecond(seconds2, nanos2); + long amount = unit.between(i1, i2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + Instant start = Instant.ofEpochSecond(12, 3000); + OffsetDateTime end = start.plusSeconds(2).atOffset(ZoneOffset.ofHours(2)); + assertEquals(start.until(end, SECONDS), 2); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidType() { + Instant start = Instant.ofEpochSecond(12, 3000); + start.until(LocalTime.of(11, 30), SECONDS); + } + @Test(expectedExceptions = UnsupportedTemporalTypeException.class) - public void test_periodUntil_TemporalUnit_unsupportedUnit() { + public void test_until_TemporalUnit_unsupportedUnit() { TEST_12345_123456789.until(TEST_12345_123456789, MONTHS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullEnd() { + public void test_until_TemporalUnit_nullEnd() { TEST_12345_123456789.until(null, HOURS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullUnit() { + public void test_until_TemporalUnit_nullUnit() { TEST_12345_123456789.until(TEST_12345_123456789, null); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKLocalDate.java --- a/jdk/test/java/time/tck/java/time/TCKLocalDate.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKLocalDate.java Tue Oct 08 14:57:32 2013 -0700 @@ -196,28 +196,6 @@ return list; } - - //----------------------------------------------------------------------- - @Test - public void test_serialization() throws Exception { - assertSerializable(TEST_2007_07_15); - assertSerializable(LocalDate.MIN); - assertSerializable(LocalDate.MAX); - } - - @Test - public void test_serialization_format() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(3); - dos.writeInt(2012); - dos.writeByte(9); - dos.writeByte(16); - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(LocalDate.of(2012, 9, 16), bytes); - } - //----------------------------------------------------------------------- private void check(LocalDate test, int y, int m, int d) { assertEquals(test.getYear(), y); @@ -1745,29 +1723,48 @@ } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit(LocalDate date1, LocalDate date2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit(LocalDate date1, LocalDate date2, TemporalUnit unit, long expected) { long amount = date1.until(date2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit_negated(LocalDate date1, LocalDate date2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit_negated(LocalDate date1, LocalDate date2, TemporalUnit unit, long expected) { long amount = date2.until(date1, unit); assertEquals(amount, -expected); } + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(LocalDate date1, LocalDate date2, TemporalUnit unit, long expected) { + long amount = unit.between(date1, date2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + LocalDate start = LocalDate.of(2010, 6, 30); + OffsetDateTime end = start.plusDays(2).atStartOfDay().atOffset(OFFSET_PONE); + assertEquals(start.until(end, DAYS), 2); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidType() { + LocalDate start = LocalDate.of(2010, 6, 30); + start.until(LocalTime.of(11, 30), DAYS); + } + @Test(expectedExceptions = UnsupportedTemporalTypeException.class) - public void test_periodUntil_TemporalUnit_unsupportedUnit() { + public void test_until_TemporalUnit_unsupportedUnit() { TEST_2007_07_15.until(TEST_2007_07_15, HOURS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullEnd() { + public void test_until_TemporalUnit_nullEnd() { TEST_2007_07_15.until(null, DAYS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullUnit() { + public void test_until_TemporalUnit_nullUnit() { TEST_2007_07_15.until(TEST_2007_07_15, null); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKLocalDateTime.java --- a/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java Tue Oct 08 14:57:32 2013 -0700 @@ -242,31 +242,6 @@ } //----------------------------------------------------------------------- - @Test - public void test_serialization() throws Exception { - assertSerializable(TEST_2007_07_15_12_30_40_987654321); - assertSerializable(LocalDateTime.MIN); - assertSerializable(LocalDateTime.MAX); - } - - @Test - public void test_serialization_format() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(5); - dos.writeInt(2012); - dos.writeByte(9); - dos.writeByte(16); - dos.writeByte(22); - dos.writeByte(17); - dos.writeByte(59); - dos.writeInt(459_000_000); - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(LocalDateTime.of(2012, 9, 16, 22, 17, 59, 459_000_000), bytes); - } - - //----------------------------------------------------------------------- // constants //----------------------------------------------------------------------- @Test @@ -2920,24 +2895,43 @@ } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit(LocalDateTime dt1, LocalDateTime dt2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit(LocalDateTime dt1, LocalDateTime dt2, TemporalUnit unit, long expected) { long amount = dt1.until(dt2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit_negated(LocalDateTime dt1, LocalDateTime dt2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit_negated(LocalDateTime dt1, LocalDateTime dt2, TemporalUnit unit, long expected) { long amount = dt2.until(dt1, unit); assertEquals(amount, -expected); } + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(LocalDateTime dt1, LocalDateTime dt2, TemporalUnit unit, long expected) { + long amount = unit.between(dt1, dt2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + LocalDateTime start = LocalDateTime.of(2010, 6, 30, 2, 30); + OffsetDateTime end = start.plusDays(2).atOffset(OFFSET_PONE); + assertEquals(start.until(end, DAYS), 2); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidType() { + LocalDateTime start = LocalDateTime.of(2010, 6, 30, 2, 30); + start.until(LocalTime.of(11, 30), DAYS); + } + @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullEnd() { + public void test_until_TemporalUnit_nullEnd() { TEST_2007_07_15_12_30_40_987654321.until(null, HOURS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullUnit() { + public void test_until_TemporalUnit_nullUnit() { TEST_2007_07_15_12_30_40_987654321.until(TEST_2007_07_15_12_30_40_987654321, null); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKLocalTime.java --- a/jdk/test/java/time/tck/java/time/TCKLocalTime.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKLocalTime.java Tue Oct 08 14:57:32 2013 -0700 @@ -191,64 +191,7 @@ } //----------------------------------------------------------------------- - @Test - public void test_serialization() throws Exception { - assertSerializable(TEST_12_30_40_987654321); - assertSerializable(LocalTime.MIN); - assertSerializable(LocalTime.MAX); - } - @Test - public void test_serialization_format_h() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(4); - dos.writeByte(-1 - 22); - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(LocalTime.of(22, 0), bytes); - } - - @Test - public void test_serialization_format_hm() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(4); - dos.writeByte(22); - dos.writeByte(-1 - 17); - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(LocalTime.of(22, 17), bytes); - } - - @Test - public void test_serialization_format_hms() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(4); - dos.writeByte(22); - dos.writeByte(17); - dos.writeByte(-1 - 59); - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(LocalTime.of(22, 17, 59), bytes); - } - - @Test - public void test_serialization_format_hmsn() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(4); - dos.writeByte(22); - dos.writeByte(17); - dos.writeByte(59); - dos.writeInt(459_000_000); - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(LocalTime.of(22, 17, 59, 459_000_000), bytes); - } - - //----------------------------------------------------------------------- private void check(LocalTime test, int h, int m, int s, int n) { assertEquals(test.getHour(), h); assertEquals(test.getMinute(), m); @@ -2028,29 +1971,48 @@ } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit(LocalTime time1, LocalTime time2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit(LocalTime time1, LocalTime time2, TemporalUnit unit, long expected) { long amount = time1.until(time2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit_negated(LocalTime time1, LocalTime time2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit_negated(LocalTime time1, LocalTime time2, TemporalUnit unit, long expected) { long amount = time2.until(time1, unit); assertEquals(amount, -expected); } + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(LocalTime time1, LocalTime time2, TemporalUnit unit, long expected) { + long amount = unit.between(time1, time2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + LocalTime start = LocalTime.of(11, 30); + LocalDateTime end = start.plusSeconds(2).atDate(LocalDate.of(2010, 6, 30)); + assertEquals(start.until(end, SECONDS), 2); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidType() { + LocalTime start = LocalTime.of(11, 30); + start.until(LocalDate.of(2010, 6, 30), SECONDS); + } + @Test(expectedExceptions = UnsupportedTemporalTypeException.class) - public void test_periodUntil_TemporalUnit_unsupportedUnit() { + public void test_until_TemporalUnit_unsupportedUnit() { TEST_12_30_40_987654321.until(TEST_12_30_40_987654321, DAYS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullEnd() { + public void test_until_TemporalUnit_nullEnd() { TEST_12_30_40_987654321.until(null, HOURS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullUnit() { + public void test_until_TemporalUnit_nullUnit() { TEST_12_30_40_987654321.until(TEST_12_30_40_987654321, null); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKMonthDay.java --- a/jdk/test/java/time/tck/java/time/TCKMonthDay.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKMonthDay.java Tue Oct 08 14:57:32 2013 -0700 @@ -137,24 +137,6 @@ } //----------------------------------------------------------------------- - @Test - public void test_serialization() throws ClassNotFoundException, IOException { - assertSerializable(TEST_07_15); - } - - @Test - public void test_serialization_format() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(13); // java.time.temporal.Ser.MONTH_DAY_TYPE - dos.writeByte(9); - dos.writeByte(16); - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(MonthDay.of(9, 16), bytes); - } - - //----------------------------------------------------------------------- void check(MonthDay test, int m, int d) { assertEquals(test.getMonth().getValue(), m); assertEquals(test.getDayOfMonth(), d); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java --- a/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java Tue Oct 08 14:57:32 2013 -0700 @@ -91,6 +91,13 @@ import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.FOREVER; +import static java.time.temporal.ChronoUnit.HALF_DAYS; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MICROS; +import static java.time.temporal.ChronoUnit.MILLIS; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.MONTHS; import static java.time.temporal.ChronoUnit.NANOS; import static java.time.temporal.ChronoUnit.SECONDS; import static org.testng.Assert.assertEquals; @@ -210,43 +217,6 @@ } //----------------------------------------------------------------------- - @Test - public void test_serialization() throws Exception { - assertSerializable(TEST_2008_6_30_11_30_59_000000500); - assertSerializable(OffsetDateTime.MIN); - assertSerializable(OffsetDateTime.MAX); - } - - @Test - public void test_serialization_format() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(10); // java.time.Ser.OFFSET_DATE_TIME_TYPE - } - byte[] bytes = baos.toByteArray(); - ByteArrayOutputStream baosDateTime = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baosDateTime) ) { - dos.writeByte(5); - dos.writeInt(2012); - dos.writeByte(9); - dos.writeByte(16); - dos.writeByte(22); - dos.writeByte(17); - dos.writeByte(59); - dos.writeInt(464_000_000); - } - byte[] bytesDateTime = baosDateTime.toByteArray(); - ByteArrayOutputStream baosOffset = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baosOffset) ) { - dos.writeByte(8); - dos.writeByte(4); // quarter hours stored: 3600 / 900 - } - byte[] bytesOffset = baosOffset.toByteArray(); - LocalDateTime ldt = LocalDateTime.of(2012, 9, 16, 22, 17, 59, 464_000_000); - assertSerializedBySer(OffsetDateTime.of(ldt, ZoneOffset.ofHours(1)), bytes, bytesDateTime, bytesOffset); - } - - //----------------------------------------------------------------------- // constants //----------------------------------------------------------------------- @Test @@ -1166,6 +1136,74 @@ } //----------------------------------------------------------------------- + // until(Temporal, TemporalUnit) + //----------------------------------------------------------------------- + @DataProvider(name="periodUntilUnit") + Object[][] data_untilUnit() { + return new Object[][] { + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 13, 1, 1, 0, OFFSET_PONE), HALF_DAYS, 1}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 2, 1, 1, 0, OFFSET_PONE), HOURS, 1}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 2, 1, 1, 0, OFFSET_PONE), MINUTES, 60}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 2, 1, 1, 0, OFFSET_PONE), SECONDS, 3600}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 2, 1, 1, 0, OFFSET_PONE), MILLIS, 3600*1000}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 2, 1, 1, 0, OFFSET_PONE), MICROS, 3600*1000*1000L}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 2, 1, 1, 0, OFFSET_PONE), NANOS, 3600*1000*1000L*1000}, + + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 14, 1, 1, 0, OFFSET_PTWO), HALF_DAYS, 1}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 3, 1, 1, 0, OFFSET_PTWO), HOURS, 1}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 3, 1, 1, 0, OFFSET_PTWO), MINUTES, 60}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 3, 1, 1, 0, OFFSET_PTWO), SECONDS, 3600}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 3, 1, 1, 0, OFFSET_PTWO), MILLIS, 3600*1000}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 3, 1, 1, 0, OFFSET_PTWO), MICROS, 3600*1000*1000L}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 3, 1, 1, 0, OFFSET_PTWO), NANOS, 3600*1000*1000L*1000}, + + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 7, 1, 1, 1, 0, 999999999, OFFSET_PONE), DAYS, 0}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 7, 1, 1, 1, 1, 0, OFFSET_PONE), DAYS, 1}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 8, 29, 1, 1, 1, 0, OFFSET_PONE), MONTHS, 1}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 8, 30, 1, 1, 1, 0, OFFSET_PONE), MONTHS, 2}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 8, 31, 1, 1, 1, 0, OFFSET_PONE), MONTHS, 2}, + }; + } + + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit(OffsetDateTime odt1, OffsetDateTime odt2, TemporalUnit unit, long expected) { + long amount = odt1.until(odt2, unit); + assertEquals(amount, expected); + } + + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_negated(OffsetDateTime odt1, OffsetDateTime odt2, TemporalUnit unit, long expected) { + long amount = odt2.until(odt1, unit); + assertEquals(amount, -expected); + } + + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(OffsetDateTime odt1, OffsetDateTime odt2, TemporalUnit unit, long expected) { + long amount = unit.between(odt1, odt2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + OffsetDateTime odt = OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE); + ZonedDateTime zdt = odt.plusSeconds(3).toZonedDateTime(); + assertEquals(odt.until(zdt, SECONDS), 3); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidType() { + OffsetDateTime odt = OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE); + odt.until(Instant.ofEpochSecond(12), SECONDS); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidTemporalUnit() { + OffsetDateTime odt1 = OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE); + OffsetDateTime odt2 = OffsetDateTime.of(2010, 6, 30, 2, 1, 1, 0, OFFSET_PONE); + odt1.until(odt2, FOREVER); + } + + //----------------------------------------------------------------------- // format(DateTimeFormatter) //----------------------------------------------------------------------- @Test diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKOffsetTime.java --- a/jdk/test/java/time/tck/java/time/TCKOffsetTime.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKOffsetTime.java Tue Oct 08 14:57:32 2013 -0700 @@ -184,40 +184,6 @@ } //----------------------------------------------------------------------- - @Test - public void test_serialization() throws Exception { - assertSerializable(TEST_11_30_59_500_PONE); - assertSerializable(OffsetTime.MIN); - assertSerializable(OffsetTime.MAX); - } - - @Test - public void test_serialization_format() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(9); // java.time.Ser.OFFSET_TIME_TYPE - } - byte[] bytes = baos.toByteArray(); - ByteArrayOutputStream baosTime = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baosTime) ) { - dos.writeByte(4); - dos.writeByte(22); - dos.writeByte(17); - dos.writeByte(59); - dos.writeInt(464_000_000); - } - byte[] bytesTime = baosTime.toByteArray(); - ByteArrayOutputStream baosOffset = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baosOffset) ) { - dos.writeByte(8); - dos.writeByte(4); // quarter hours stored: 3600 / 900 - } - byte[] bytesOffset = baosOffset.toByteArray(); - assertSerializedBySer(OffsetTime.of(22, 17, 59, 464_000_000, ZoneOffset.ofHours(1)), bytes, - bytesTime, bytesOffset); - } - - //----------------------------------------------------------------------- // constants //----------------------------------------------------------------------- @Test @@ -1103,49 +1069,61 @@ // until(Temporal, TemporalUnit) //----------------------------------------------------------------------- @DataProvider(name="periodUntilUnit") - Object[][] data_periodUntilUnit() { + Object[][] data_untilUnit() { return new Object[][] { - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(13, 1, 1), ZoneOffset.ofHours(1)), HALF_DAYS, 1}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), HOURS, 1}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), MINUTES, 60}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), SECONDS, 3600}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), MILLIS, 3600*1000}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), MICROS, 3600*1000*1000L}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), NANOS, 3600*1000*1000L*1000}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(13, 1, 1, 0, OFFSET_PONE), HALF_DAYS, 1}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(2, 1, 1, 0, OFFSET_PONE), HOURS, 1}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(2, 1, 1, 0, OFFSET_PONE), MINUTES, 60}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(2, 1, 1, 0, OFFSET_PONE), SECONDS, 3600}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(2, 1, 1, 0, OFFSET_PONE), MILLIS, 3600*1000}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(2, 1, 1, 0, OFFSET_PONE), MICROS, 3600*1000*1000L}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(2, 1, 1, 0, OFFSET_PONE), NANOS, 3600*1000*1000L*1000}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(14, 1, 1), ZoneOffset.ofHours(2)), HALF_DAYS, 1}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), HOURS, 1}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), MINUTES, 60}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), SECONDS, 3600}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), MILLIS, 3600*1000}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), MICROS, 3600*1000*1000L}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), NANOS, 3600*1000*1000L*1000}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(14, 1, 1, 0, OFFSET_PTWO), HALF_DAYS, 1}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(3, 1, 1, 0, OFFSET_PTWO), HOURS, 1}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(3, 1, 1, 0, OFFSET_PTWO), MINUTES, 60}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(3, 1, 1, 0, OFFSET_PTWO), SECONDS, 3600}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(3, 1, 1, 0, OFFSET_PTWO), MILLIS, 3600*1000}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(3, 1, 1, 0, OFFSET_PTWO), MICROS, 3600*1000*1000L}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(3, 1, 1, 0, OFFSET_PTWO), NANOS, 3600*1000*1000L*1000}, }; } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit(OffsetTime offsetTime1, OffsetTime offsetTime2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit(OffsetTime offsetTime1, OffsetTime offsetTime2, TemporalUnit unit, long expected) { long amount = offsetTime1.until(offsetTime2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit_negated(OffsetTime offsetTime1, OffsetTime offsetTime2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit_negated(OffsetTime offsetTime1, OffsetTime offsetTime2, TemporalUnit unit, long expected) { long amount = offsetTime2.until(offsetTime1, unit); assertEquals(amount, -expected); } - @Test(expectedExceptions=DateTimeException.class) - public void test_periodUntil_InvalidType() { - OffsetTime offsetTime = OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)); - OffsetDateTime offsetDateTime = offsetTime.atDate(LocalDate.of(1980, 2, 10)); - offsetTime.until(offsetDateTime, SECONDS); + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(OffsetTime offsetTime1, OffsetTime offsetTime2, TemporalUnit unit, long expected) { + long amount = unit.between(offsetTime1, offsetTime2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + OffsetTime offsetTime = OffsetTime.of(1, 1, 1, 0, OFFSET_PONE); + OffsetDateTime offsetDateTime = offsetTime.plusSeconds(3).atDate(LocalDate.of(1980, 2, 10)); + assertEquals(offsetTime.until(offsetDateTime, SECONDS), 3); } @Test(expectedExceptions=DateTimeException.class) - public void test_periodUntil_InvalidTemporalUnit() { - OffsetTime offsetTime1 = OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)); - OffsetTime offsetTime2 = OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)); + public void test_until_invalidType() { + OffsetTime offsetTime = OffsetTime.of(1, 1, 1, 0, OFFSET_PONE); + offsetTime.until(LocalDate.of(1980, 2, 10), SECONDS); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidTemporalUnit() { + OffsetTime offsetTime1 = OffsetTime.of(1, 1, 1, 0, OFFSET_PONE); + OffsetTime offsetTime2 = OffsetTime.of(2, 1, 1, 0, OFFSET_PONE); offsetTime1.until(offsetTime2, MONTHS); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKPeriod.java --- a/jdk/test/java/time/tck/java/time/TCKPeriod.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKPeriod.java Tue Oct 08 14:57:32 2013 -0700 @@ -60,6 +60,7 @@ package tck.java.time; import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.HOURS; import static java.time.temporal.ChronoUnit.YEARS; import static org.testng.Assert.assertEquals; @@ -67,6 +68,7 @@ import java.time.Duration; import java.time.LocalDate; import java.time.Period; +import java.time.chrono.ThaiBuddhistChronology; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; @@ -87,14 +89,6 @@ public class TCKPeriod extends AbstractTCKTest { //----------------------------------------------------------------------- - @Test - public void test_serialization() throws Exception { - assertSerializable(Period.ZERO); - assertSerializable(Period.ofDays(1)); - assertSerializable(Period.of(1, 2, 3)); - } - - //----------------------------------------------------------------------- // ofYears(int) //----------------------------------------------------------------------- @Test @@ -221,6 +215,41 @@ } @Test(expectedExceptions = DateTimeException.class) + public void factory_from_TemporalAmount_DaysHours() { + TemporalAmount amount = new TemporalAmount() { + @Override + public long get(TemporalUnit unit) { + if (unit == DAYS) { + return 1; + } else { + return 2; + } + } + @Override + public List getUnits() { + List list = new ArrayList<>(); + list.add(DAYS); + list.add(HOURS); + return list; + } + @Override + public Temporal addTo(Temporal temporal) { + throw new UnsupportedOperationException(); + } + @Override + public Temporal subtractFrom(Temporal temporal) { + throw new UnsupportedOperationException(); + } + }; + Period.from(amount); + } + + @Test(expectedExceptions = DateTimeException.class) + public void factory_from_TemporalAmount_NonISO() { + Period.from(ThaiBuddhistChronology.INSTANCE.period(1, 1, 1)); + } + + @Test(expectedExceptions = DateTimeException.class) public void factory_from_TemporalAmount_Duration() { Period.from(Duration.ZERO); } @@ -602,10 +631,45 @@ } @Test(dataProvider="plus") - public void test_plus(Period base, Period add, Period expected) { + public void test_plus_TemporalAmount(Period base, Period add, Period expected) { assertEquals(base.plus(add), expected); } + @Test(expectedExceptions = DateTimeException.class) + public void test_plus_TemporalAmount_nonISO() { + pymd(4, 5, 6).plus(ThaiBuddhistChronology.INSTANCE.period(1, 0, 0)); + } + + @Test(expectedExceptions = DateTimeException.class) + public void test_plus_TemporalAmount_DaysHours() { + TemporalAmount amount = new TemporalAmount() { + @Override + public long get(TemporalUnit unit) { + if (unit == DAYS) { + return 1; + } else { + return 2; + } + } + @Override + public List getUnits() { + List list = new ArrayList<>(); + list.add(DAYS); + list.add(HOURS); + return list; + } + @Override + public Temporal addTo(Temporal temporal) { + throw new UnsupportedOperationException(); + } + @Override + public Temporal subtractFrom(Temporal temporal) { + throw new UnsupportedOperationException(); + } + }; + pymd(4, 5, 6).plus(amount); + } + //----------------------------------------------------------------------- // plusYears() //----------------------------------------------------------------------- @@ -712,10 +776,45 @@ } @Test(dataProvider="minus") - public void test_minus(Period base, Period subtract, Period expected) { + public void test_minus_TemporalAmount(Period base, Period subtract, Period expected) { assertEquals(base.minus(subtract), expected); } + @Test(expectedExceptions = DateTimeException.class) + public void test_minus_TemporalAmount_nonISO() { + pymd(4, 5, 6).minus(ThaiBuddhistChronology.INSTANCE.period(1, 0, 0)); + } + + @Test(expectedExceptions = DateTimeException.class) + public void test_minus_TemporalAmount_DaysHours() { + TemporalAmount amount = new TemporalAmount() { + @Override + public long get(TemporalUnit unit) { + if (unit == DAYS) { + return 1; + } else { + return 2; + } + } + @Override + public List getUnits() { + List list = new ArrayList<>(); + list.add(DAYS); + list.add(HOURS); + return list; + } + @Override + public Temporal addTo(Temporal temporal) { + throw new UnsupportedOperationException(); + } + @Override + public Temporal subtractFrom(Temporal temporal) { + throw new UnsupportedOperationException(); + } + }; + pymd(4, 5, 6).minus(amount); + } + //----------------------------------------------------------------------- // minusYears() //----------------------------------------------------------------------- diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKYear.java --- a/jdk/test/java/time/tck/java/time/TCKYear.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKYear.java Tue Oct 08 14:57:32 2013 -0700 @@ -65,10 +65,8 @@ import static java.time.temporal.ChronoUnit.CENTURIES; import static java.time.temporal.ChronoUnit.DAYS; import static java.time.temporal.ChronoUnit.DECADES; -import static java.time.temporal.ChronoUnit.HOURS; import static java.time.temporal.ChronoUnit.MILLENNIA; import static java.time.temporal.ChronoUnit.MONTHS; -import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.ChronoUnit.YEARS; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -90,8 +88,8 @@ import java.time.YearMonth; import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.chrono.IsoChronology; import java.time.chrono.IsoEra; -import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; @@ -152,25 +150,6 @@ } //----------------------------------------------------------------------- - @Test - public void test_serialization() throws Exception { - assertSerializable(Year.of(2)); - assertSerializable(Year.of(0)); - assertSerializable(Year.of(-2)); - } - - @Test - public void test_serialization_format() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(11); // java.time.temporal.Ser.YEAR_TYPE - dos.writeInt(2012); - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(Year.of(2012), bytes); - } - - //----------------------------------------------------------------------- // now() //----------------------------------------------------------------------- @Test @@ -248,17 +227,17 @@ //----------------------------------------------------------------------- @Test - public void test_factory_CalendricalObject() { + public void test_from_TemporalAccessor() { assertEquals(Year.from(LocalDate.of(2007, 7, 15)), Year.of(2007)); } @Test(expectedExceptions=DateTimeException.class) - public void test_factory_CalendricalObject_invalid_noDerive() { + public void test_from_TemporalAccessor_invalid_noDerive() { Year.from(LocalTime.of(12, 30)); } @Test(expectedExceptions=NullPointerException.class) - public void test_factory_CalendricalObject_null() { + public void test_from_TemporalAccessor_null() { Year.from((TemporalAccessor) null); } @@ -616,13 +595,13 @@ }; } - @Test(groups={"tck"}, dataProvider="plus_long_TemporalUnit") + @Test(dataProvider="plus_long_TemporalUnit") public void test_plus_long_TemporalUnit(Year base, long amount, TemporalUnit unit, Year expectedYear, Class expectedEx) { if (expectedEx == null) { assertEquals(base.plus(amount, unit), expectedYear); } else { try { - Year result = base.plus(amount, unit); + base.plus(amount, unit); fail(); } catch (Exception ex) { assertTrue(expectedEx.isInstance(ex)); @@ -748,7 +727,7 @@ }; } - @Test(groups={"tck"}, dataProvider="minus_long_TemporalUnit") + @Test(dataProvider="minus_long_TemporalUnit") public void test_minus_long_TemporalUnit(Year base, long amount, TemporalUnit unit, Year expectedYear, Class expectedEx) { if (expectedEx == null) { assertEquals(base.minus(amount, unit), expectedYear); @@ -807,7 +786,7 @@ //----------------------------------------------------------------------- // with(TemporalField, long) //----------------------------------------------------------------------- - @Test(groups={"tck"}) + @Test public void test_with() { Year base = Year.of(5); Year result = base.with(ChronoField.ERA, 0); @@ -942,29 +921,48 @@ } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit(Year year1, Year year2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit(Year year1, Year year2, TemporalUnit unit, long expected) { long amount = year1.until(year2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit_negated(Year year1, Year year2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit_negated(Year year1, Year year2, TemporalUnit unit, long expected) { long amount = year2.until(year1, unit); assertEquals(amount, -expected); } + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(Year year1, Year year2, TemporalUnit unit, long expected) { + long amount = unit.between(year1, year2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + Year start = Year.of(2010); + YearMonth end = start.plusYears(2).atMonth(Month.APRIL); + assertEquals(start.until(end, YEARS), 2); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidType() { + Year start = Year.of(2010); + start.until(LocalTime.of(11, 30), YEARS); + } + @Test(expectedExceptions = UnsupportedTemporalTypeException.class) - public void test_periodUntil_TemporalUnit_unsupportedUnit() { + public void test_until_TemporalUnit_unsupportedUnit() { TEST_2008.until(TEST_2008, MONTHS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullEnd() { + public void test_until_TemporalUnit_nullEnd() { TEST_2008.until(null, DAYS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullUnit() { + public void test_until_TemporalUnit_nullUnit() { TEST_2008.until(TEST_2008, null); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKYearMonth.java --- a/jdk/test/java/time/tck/java/time/TCKYearMonth.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKYearMonth.java Tue Oct 08 14:57:32 2013 -0700 @@ -70,7 +70,6 @@ import static java.time.temporal.ChronoUnit.HOURS; import static java.time.temporal.ChronoUnit.MILLENNIA; import static java.time.temporal.ChronoUnit.MONTHS; -import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.ChronoUnit.YEARS; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -157,24 +156,6 @@ } //----------------------------------------------------------------------- - @Test - public void test_serialization() throws IOException, ClassNotFoundException { - assertSerializable(TEST_2008_06); - } - - @Test - public void test_serialization_format() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(12); // java.time.temporal.Ser.YEAR_MONTH_TYPE - dos.writeInt(2012); - dos.writeByte(9); - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(YearMonth.of(2012, 9), bytes); - } - - //----------------------------------------------------------------------- void check(YearMonth test, int y, int m) { assertEquals(test.getYear(), y); assertEquals(test.getMonth().getValue(), m); @@ -288,17 +269,17 @@ //----------------------------------------------------------------------- @Test - public void test_factory_CalendricalObject() { + public void test_from_TemporalAccessor() { assertEquals(YearMonth.from(LocalDate.of(2007, 7, 15)), YearMonth.of(2007, 7)); } @Test(expectedExceptions=DateTimeException.class) - public void test_factory_CalendricalObject_invalid_noDerive() { + public void test_from_TemporalAccessor_invalid_noDerive() { YearMonth.from(LocalTime.of(12, 30)); } @Test(expectedExceptions=NullPointerException.class) - public void test_factory_CalendricalObject_null() { + public void test_from_TemporalAccessor_null() { YearMonth.from((TemporalAccessor) null); } @@ -786,7 +767,7 @@ }; } - @Test(groups={"tck"}, dataProvider="plus_long_TemporalUnit") + @Test(dataProvider="plus_long_TemporalUnit") public void test_plus_long_TemporalUnit(YearMonth base, long amount, TemporalUnit unit, YearMonth expectedYearMonth, Class expectedEx) { if (expectedEx == null) { assertEquals(base.plus(amount, unit), expectedYearMonth); @@ -838,7 +819,7 @@ }; } - @Test(groups={"tck"}, dataProvider="plus_TemporalAmount") + @Test(dataProvider="plus_TemporalAmount") public void test_plus_TemporalAmount(YearMonth base, TemporalAmount temporalAmount, YearMonth expectedYearMonth, Class expectedEx) { if (expectedEx == null) { assertEquals(base.plus(temporalAmount), expectedYearMonth); @@ -1001,7 +982,7 @@ }; } - @Test(groups={"tck"}, dataProvider="minus_long_TemporalUnit") + @Test(dataProvider="minus_long_TemporalUnit") public void test_minus_long_TemporalUnit(YearMonth base, long amount, TemporalUnit unit, YearMonth expectedYearMonth, Class expectedEx) { if (expectedEx == null) { assertEquals(base.minus(amount, unit), expectedYearMonth); @@ -1053,7 +1034,7 @@ }; } - @Test(groups={"tck"}, dataProvider="minus_TemporalAmount") + @Test(dataProvider="minus_TemporalAmount") public void test_minus_TemporalAmount(YearMonth base, TemporalAmount temporalAmount, YearMonth expectedYearMonth, Class expectedEx) { if (expectedEx == null) { assertEquals(base.minus(temporalAmount), expectedYearMonth); @@ -1261,29 +1242,48 @@ } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit(YearMonth ym1, YearMonth ym2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit(YearMonth ym1, YearMonth ym2, TemporalUnit unit, long expected) { long amount = ym1.until(ym2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit_negated(YearMonth ym1, YearMonth ym2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit_negated(YearMonth ym1, YearMonth ym2, TemporalUnit unit, long expected) { long amount = ym2.until(ym1, unit); assertEquals(amount, -expected); } + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(YearMonth ym1, YearMonth ym2, TemporalUnit unit, long expected) { + long amount = unit.between(ym1, ym2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + YearMonth start = YearMonth.of(2010, 6); + LocalDate end = start.plusMonths(2).atDay(12); + assertEquals(start.until(end, MONTHS), 2); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidType() { + YearMonth start = YearMonth.of(2010, 6); + start.until(LocalTime.of(11, 30), MONTHS); + } + @Test(expectedExceptions = UnsupportedTemporalTypeException.class) - public void test_periodUntil_TemporalUnit_unsupportedUnit() { + public void test_until_TemporalUnit_unsupportedUnit() { TEST_2008_06.until(TEST_2008_06, HOURS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullEnd() { + public void test_until_TemporalUnit_nullEnd() { TEST_2008_06.until(null, DAYS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullUnit() { + public void test_until_TemporalUnit_nullUnit() { TEST_2008_06.until(TEST_2008_06, null); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKZoneId.java --- a/jdk/test/java/time/tck/java/time/TCKZoneId.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKZoneId.java Tue Oct 08 14:57:32 2013 -0700 @@ -93,110 +93,6 @@ public class TCKZoneId extends AbstractTCKTest { //----------------------------------------------------------------------- - @Test - public void test_serialization() throws Exception { - assertSerializable(ZoneId.of("Europe/London")); - assertSerializable(ZoneId.of("America/Chicago")); - } - - @Test - public void test_serialization_format() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(7); - dos.writeUTF("Europe/London"); - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(ZoneId.of("Europe/London"), bytes); - } - - @Test - public void test_deserialization_lenient_characters() throws Exception { - // an ID can be loaded without validation during deserialization - String id = "QWERTYUIOPASDFGHJKLZXCVBNM~/._+-"; - ZoneId deser = deserialize(id); - // getId, equals, hashCode, toString and normalized are OK - assertEquals(deser.getId(), id); - assertEquals(deser.toString(), id); - assertEquals(deser, deser); - assertEquals(deser.hashCode(), deser.hashCode()); - assertEquals(deser.normalized(), deser); - // getting the rules is not - try { - deser.getRules(); - fail(); - } catch (ZoneRulesException ex) { - // expected - } - } - - @Test(expectedExceptions=DateTimeException.class) - public void test_deserialization_lenient_badCharacters() throws Exception { - // an ID can be loaded without validation during deserialization - // but there is a check to ensure the ID format is valid - deserialize("|!?"); - } - - @Test(dataProvider="offsetBasedValid") - public void test_deserialization_lenient_offsetNotAllowed_noPrefix(String input, String resolvedId) throws Exception { - ZoneId deserialized = deserialize(input); - assertEquals(deserialized, ZoneId.of(input)); - assertEquals(deserialized, ZoneId.of(resolvedId)); - } - - @Test(dataProvider="offsetBasedValidPrefix") - public void test_deserialization_lenient_offsetNotAllowed_prefixUTC(String input, String resolvedId, String offsetId) throws Exception { - ZoneId deserialized = deserialize("UTC" + input); - assertEquals(deserialized, ZoneId.of("UTC" + input)); - assertEquals(deserialized, ZoneId.of("UTC" + resolvedId)); - } - - @Test(dataProvider="offsetBasedValidPrefix") - public void test_deserialization_lenient_offsetNotAllowed_prefixGMT(String input, String resolvedId, String offsetId) throws Exception { - ZoneId deserialized = deserialize("GMT" + input); - assertEquals(deserialized, ZoneId.of("GMT" + input)); - assertEquals(deserialized, ZoneId.of("GMT" + resolvedId)); - } - - @Test(dataProvider="offsetBasedValidPrefix") - public void test_deserialization_lenient_offsetNotAllowed_prefixUT(String input, String resolvedId, String offsetId) throws Exception { - ZoneId deserialized = deserialize("UT" + input); - assertEquals(deserialized, ZoneId.of("UT" + input)); - assertEquals(deserialized, ZoneId.of("UT" + resolvedId)); - } - - private ZoneId deserialize(String id) throws Exception { - String serClass = ZoneId.class.getPackage().getName() + ".Ser"; - Class serCls = Class.forName(serClass); - Field field = serCls.getDeclaredField("serialVersionUID"); - field.setAccessible(true); - long serVer = (Long) field.get(null); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos)) { - dos.writeShort(ObjectStreamConstants.STREAM_MAGIC); - dos.writeShort(ObjectStreamConstants.STREAM_VERSION); - dos.writeByte(ObjectStreamConstants.TC_OBJECT); - dos.writeByte(ObjectStreamConstants.TC_CLASSDESC); - dos.writeUTF(serClass); - dos.writeLong(serVer); - dos.writeByte(ObjectStreamConstants.SC_EXTERNALIZABLE | ObjectStreamConstants.SC_BLOCK_DATA); - dos.writeShort(0); // number of fields - dos.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); // end of classdesc - dos.writeByte(ObjectStreamConstants.TC_NULL); // no superclasses - dos.writeByte(ObjectStreamConstants.TC_BLOCKDATA); - dos.writeByte(1 + 2 + id.length()); // length of data (1 byte + 2 bytes UTF length + 32 bytes UTF) - dos.writeByte(7); // ZoneId - dos.writeUTF(id); - dos.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); // end of blockdata - } - ZoneId deser = null; - try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { - deser = (ZoneId) ois.readObject(); - } - return deser; - } - - //----------------------------------------------------------------------- // OLD_SHORT_IDS //----------------------------------------------------------------------- public void test_constant_OLD_IDS_PRE_2005() { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKZoneOffset.java --- a/jdk/test/java/time/tck/java/time/TCKZoneOffset.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKZoneOffset.java Tue Oct 08 14:57:32 2013 -0700 @@ -121,46 +121,6 @@ } //----------------------------------------------------------------------- - @Test - public void test_serialization() throws Exception { - assertSerializable(ZoneOffset.of("+01:30")); - } - - @Test - public void test_serialization_format_quarterPositive() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(8); - dos.writeByte(6); // stored as quarter hours - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(ZoneOffset.ofHoursMinutes(1, 30), bytes); - } - - @Test - public void test_serialization_format_quarterNegative() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(8); - dos.writeByte(-10); // stored as quarter hours - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(ZoneOffset.ofHoursMinutes(-2, -30), bytes); - } - - @Test - public void test_serialization_format_full() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(8); - dos.writeByte(127); - dos.writeInt(53265); - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(ZoneOffset.ofTotalSeconds(53265), bytes); - } - - //----------------------------------------------------------------------- // constants //----------------------------------------------------------------------- @Test diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/TCKZonedDateTime.java --- a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java Tue Oct 08 14:57:32 2013 -0700 @@ -223,54 +223,6 @@ } //----------------------------------------------------------------------- - @Test - public void test_serialization() throws ClassNotFoundException, IOException { - assertSerializable(TEST_DATE_TIME); - } - - @Test - public void test_serialization_format_zoneId() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(6); - dos.writeInt(2012); // date - dos.writeByte(9); - dos.writeByte(16); - dos.writeByte(22); // time - dos.writeByte(17); - dos.writeByte(59); - dos.writeInt(470_000_000); - dos.writeByte(4); // offset - dos.writeByte(7); // zoneId - dos.writeUTF("Europe/London"); - } - byte[] bytes = baos.toByteArray(); - ZonedDateTime zdt = LocalDateTime.of(2012, 9, 16, 22, 17, 59, 470_000_000).atZone(ZoneId.of("Europe/London")); - assertSerializedBySer(zdt, bytes); - } - - @Test - public void test_serialization_format_zoneOffset() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(6); - dos.writeInt(2012); // date - dos.writeByte(9); - dos.writeByte(16); - dos.writeByte(22); // time - dos.writeByte(17); - dos.writeByte(59); - dos.writeInt(470_000_000); - dos.writeByte(4); // offset - dos.writeByte(8); // zoneId - dos.writeByte(4); - } - byte[] bytes = baos.toByteArray(); - ZonedDateTime zdt = LocalDateTime.of(2012, 9, 16, 22, 17, 59, 470_000_000).atZone(ZoneOffset.ofHours(1)); - assertSerializedBySer(zdt, bytes); - } - - //----------------------------------------------------------------------- // now() //----------------------------------------------------------------------- @Test @@ -2049,7 +2001,7 @@ // compare results to OffsetDateTime.until, especially wrt dates @Test(dataProvider="plusDays") - public void test_periodUntil_days(ZonedDateTime base, long expected, ZonedDateTime end) { + public void test_until_days(ZonedDateTime base, long expected, ZonedDateTime end) { if (base.toLocalTime().equals(end.toLocalTime()) == false) { return; // avoid DST gap input values } @@ -2057,27 +2009,27 @@ } @Test(dataProvider="plusTime") - public void test_periodUntil_hours(ZonedDateTime base, long expected, ZonedDateTime end) { + public void test_until_hours(ZonedDateTime base, long expected, ZonedDateTime end) { assertEquals(base.until(end, HOURS), expected); } @Test(dataProvider="plusTime") - public void test_periodUntil_minutes(ZonedDateTime base, long expected, ZonedDateTime end) { + public void test_until_minutes(ZonedDateTime base, long expected, ZonedDateTime end) { assertEquals(base.until(end, MINUTES), expected * 60); } @Test(dataProvider="plusTime") - public void test_periodUntil_seconds(ZonedDateTime base, long expected, ZonedDateTime end) { + public void test_until_seconds(ZonedDateTime base, long expected, ZonedDateTime end) { assertEquals(base.until(end, SECONDS), expected * 3600); } @Test(dataProvider="plusTime") - public void test_periodUntil_nanos(ZonedDateTime base, long expected, ZonedDateTime end) { + public void test_until_nanos(ZonedDateTime base, long expected, ZonedDateTime end) { assertEquals(base.until(end, NANOS), expected * 3600_000_000_000L); } @Test - public void test_periodUntil_parisLondon() { + public void test_until_parisLondon() { ZonedDateTime midnightLondon = LocalDate.of(2012, 6, 28).atStartOfDay(ZONE_LONDON); ZonedDateTime midnightParis1 = LocalDate.of(2012, 6, 29).atStartOfDay(ZONE_PARIS); ZonedDateTime oneAm1 = LocalDateTime.of(2012, 6, 29, 1, 0).atZone(ZONE_PARIS); @@ -2093,7 +2045,7 @@ } @Test - public void test_periodUntil_gap() { + public void test_until_gap() { ZonedDateTime before = TEST_PARIS_GAP_2008_03_30_02_30.withHour(0).withMinute(0).atZone(ZONE_PARIS); ZonedDateTime after = TEST_PARIS_GAP_2008_03_30_02_30.withHour(0).withMinute(0).plusDays(1).atZone(ZONE_PARIS); @@ -2102,7 +2054,7 @@ } @Test - public void test_periodUntil_overlap() { + public void test_until_overlap() { ZonedDateTime before = TEST_PARIS_OVERLAP_2008_10_26_02_30.withHour(0).withMinute(0).atZone(ZONE_PARIS); ZonedDateTime after = TEST_PARIS_OVERLAP_2008_10_26_02_30.withHour(0).withMinute(0).plusDays(1).atZone(ZONE_PARIS); @@ -2111,17 +2063,17 @@ } @Test(expectedExceptions=DateTimeException.class) - public void test_periodUntil_differentType() { + public void test_until_differentType() { TEST_DATE_TIME_PARIS.until(TEST_LOCAL_2008_06_30_11_30_59_500, DAYS); } @Test(expectedExceptions=NullPointerException.class) - public void test_periodUntil_nullTemporal() { + public void test_until_nullTemporal() { TEST_DATE_TIME_PARIS.until(null, DAYS); } @Test(expectedExceptions=NullPointerException.class) - public void test_periodUntil_nullUnit() { + public void test_until_nullUnit() { TEST_DATE_TIME_PARIS.until(TEST_DATE_TIME_PARIS, null); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/CopticDate.java --- a/jdk/test/java/time/tck/java/time/chrono/CopticDate.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/chrono/CopticDate.java Tue Oct 08 14:57:32 2013 -0700 @@ -297,18 +297,12 @@ } @Override - public long until(Temporal endDateTime, TemporalUnit unit) { - if (endDateTime instanceof ChronoLocalDate == false) { - throw new DateTimeException("Unable to calculate period between objects of two different types"); - } - ChronoLocalDate end = (ChronoLocalDate) endDateTime; - if (getChronology().equals(end.getChronology()) == false) { - throw new DateTimeException("Unable to calculate period between two different chronologies"); - } + public long until(Temporal endExclusive, TemporalUnit unit) { + CopticDate end = getChronology().date(endExclusive); if (unit instanceof ChronoUnit) { return LocalDate.from(this).until(end, unit); // TODO: this is wrong } - return unit.between(this, endDateTime); + return unit.between(this, end); } @Override @@ -354,4 +348,27 @@ .append(dom < 10 ? "-0" : "-").append(dom); return buf.toString(); } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof CopticDate) { + CopticDate cd = (CopticDate)obj; + if (this.prolepticYear == cd.prolepticYear && + this.month == cd.month && + this.day == cd.day) { + return true; + } + } + return false; + } + + @Override + public int hashCode() { + long epDay = toEpochDay(); + return getChronology().hashCode() ^ ((int) (epDay ^ (epDay >>> 32))); + } + } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/TCKChronoLocalDate.java --- a/jdk/test/java/time/tck/java/time/chrono/TCKChronoLocalDate.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/chrono/TCKChronoLocalDate.java Tue Oct 08 14:57:32 2013 -0700 @@ -306,23 +306,6 @@ } } - //----------------------------------------------------------------------- - // Test Serialization of Calendars - //----------------------------------------------------------------------- - @Test( dataProvider="calendars") - public void test_ChronoSerialization(Chronology chrono) throws Exception { - LocalDate ref = LocalDate.of(2013, 1, 5); - ChronoLocalDate orginal = chrono.date(ref); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(orginal); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - @SuppressWarnings("unchecked") - ChronoLocalDate ser = (ChronoLocalDate) in.readObject(); - assertEquals(ser, orginal, "deserialized date is wrong"); - } //----------------------------------------------------------------------- @Test(dataProvider="calendars") diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/TCKChronoLocalDateTime.java --- a/jdk/test/java/time/tck/java/time/chrono/TCKChronoLocalDateTime.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/chrono/TCKChronoLocalDateTime.java Tue Oct 08 14:57:32 2013 -0700 @@ -318,23 +318,6 @@ } //----------------------------------------------------------------------- - // Test Serialization of ISO via chrono API - //----------------------------------------------------------------------- - @Test( dataProvider="calendars") - public void test_ChronoLocalDateTimeSerialization(Chronology chrono) throws Exception { - LocalDateTime ref = LocalDate.of(2013, 1, 5).atTime(12, 1, 2, 3); - ChronoLocalDateTime orginal = chrono.date(ref).atTime(ref.toLocalTime()); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(orginal); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - ChronoLocalDateTime ser = (ChronoLocalDateTime) in.readObject(); - assertEquals(ser, orginal, "deserialized date is wrong"); - } - - //----------------------------------------------------------------------- @Test(dataProvider="calendars") public void test_from_TemporalAccessor(Chronology chrono) { LocalDateTime refDateTime = LocalDateTime.of(2013, 1, 1, 12, 30); @@ -361,6 +344,13 @@ } //----------------------------------------------------------------------- + @Test(dataProvider="calendars") + public void test_getChronology(Chronology chrono) { + ChronoLocalDateTime test = chrono.localDateTime(LocalDateTime.of(2010, 6, 30, 11, 30)); + assertEquals(test.getChronology(), chrono); + } + + //----------------------------------------------------------------------- /** * FixedAdjusted returns a fixed Temporal in all adjustments. * Construct an adjuster with the Temporal that should be returned from adjust. diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/TCKChronoPeriod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/chrono/TCKChronoPeriod.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,279 @@ +/* + * Copyright (c) 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. + */ + +/* + * Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.chrono; + +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.YEARS; +import static org.testng.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.Period; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoPeriod; +import java.time.chrono.Chronology; +import java.time.chrono.HijrahChronology; +import java.time.chrono.IsoChronology; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.MinguoChronology; +import java.time.chrono.ThaiBuddhistChronology; +import java.time.temporal.Temporal; +import java.time.temporal.UnsupportedTemporalTypeException; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class TCKChronoPeriod { + + //----------------------------------------------------------------------- + // regular data factory for names and descriptions of available calendars + //----------------------------------------------------------------------- + @DataProvider(name = "calendars") + Chronology[][] data_of_calendars() { + return new Chronology[][]{ + {HijrahChronology.INSTANCE}, + {IsoChronology.INSTANCE}, + {JapaneseChronology.INSTANCE}, + {MinguoChronology.INSTANCE}, + {ThaiBuddhistChronology.INSTANCE}}; + } + + //----------------------------------------------------------------------- + // Test Serialization of Calendars + //----------------------------------------------------------------------- + @Test(dataProvider="calendars") + public void test_serialization(Chronology chrono) throws Exception { + ChronoPeriod period = chrono.period(1, 2, 3); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(baos); + out.writeObject(period); + out.close(); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + + ObjectInputStream in = new ObjectInputStream(bais); + ChronoPeriod ser = (ChronoPeriod) in.readObject(); + assertEquals(ser, period, "deserialized ChronoPeriod is wrong"); + } + + @Test(dataProvider="calendars") + public void test_get(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + assertEquals(period.get(YEARS), 1); + assertEquals(period.get(MONTHS), 2); + assertEquals(period.get(DAYS), 3); + } + + @Test(dataProvider="calendars", expectedExceptions=UnsupportedTemporalTypeException.class) + public void test_get_unsupported(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + period.get(HOURS); + } + + @Test(dataProvider="calendars") + public void test_getUnits(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + assertEquals(period.getUnits().size(), 3); + assertEquals(period.getUnits().get(0), YEARS); + assertEquals(period.getUnits().get(1), MONTHS); + assertEquals(period.getUnits().get(2), DAYS); + } + + @Test(dataProvider="calendars") + public void test_getChronology(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + assertEquals(period.getChronology(), chrono); + } + + @Test(dataProvider="calendars") + public void test_isZero_isNegative(Chronology chrono) { + ChronoPeriod periodPositive = chrono.period(1, 2, 3); + assertEquals(periodPositive.isZero(), false); + assertEquals(periodPositive.isNegative(), false); + + ChronoPeriod periodZero = chrono.period(0, 0, 0); + assertEquals(periodZero.isZero(), true); + assertEquals(periodZero.isNegative(), false); + + ChronoPeriod periodNegative = chrono.period(-1, 0, 0); + assertEquals(periodNegative.isZero(), false); + assertEquals(periodNegative.isNegative(), true); + } + + //----------------------------------------------------------------------- + @Test(dataProvider="calendars") + public void test_plus(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + ChronoPeriod period2 = chrono.period(2, 3, 4); + ChronoPeriod result = period.plus(period2); + assertEquals(result, chrono.period(3, 5, 7)); + } + + @Test(dataProvider="calendars", expectedExceptions=DateTimeException.class) + public void test_plus_wrongChrono(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + ChronoPeriod isoPeriod = Period.of(2, 3, 4); + ChronoPeriod thaiPeriod = ThaiBuddhistChronology.INSTANCE.period(2, 3, 4); + // one of these two will fail + period.plus(isoPeriod); + period.plus(thaiPeriod); + } + + @Test(dataProvider="calendars") + public void test_minus(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + ChronoPeriod period2 = chrono.period(2, 3, 4); + ChronoPeriod result = period.minus(period2); + assertEquals(result, chrono.period(-1, -1, -1)); + } + + @Test(dataProvider="calendars", expectedExceptions=DateTimeException.class) + public void test_minus_wrongChrono(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + ChronoPeriod isoPeriod = Period.of(2, 3, 4); + ChronoPeriod thaiPeriod = ThaiBuddhistChronology.INSTANCE.period(2, 3, 4); + // one of these two will fail + period.minus(isoPeriod); + period.minus(thaiPeriod); + } + + //----------------------------------------------------------------------- + @Test(dataProvider="calendars") + public void test_addTo(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + ChronoLocalDate date = chrono.dateNow(); + Temporal result = period.addTo(date); + assertEquals(result, date.plus(14, MONTHS).plus(3, DAYS)); + } + + @Test(dataProvider="calendars", expectedExceptions=DateTimeException.class) + public void test_addTo_wrongChrono(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + ChronoLocalDate isoDate = LocalDate.of(2000, 1, 1); + ChronoLocalDate thaiDate = ThaiBuddhistChronology.INSTANCE.date(2000, 1, 1); + // one of these two will fail + period.addTo(isoDate); + period.addTo(thaiDate); + } + + @Test(dataProvider="calendars") + public void test_subtractFrom(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + ChronoLocalDate date = chrono.dateNow(); + Temporal result = period.subtractFrom(date); + assertEquals(result, date.minus(14, MONTHS).minus(3, DAYS)); + } + + @Test(dataProvider="calendars", expectedExceptions=DateTimeException.class) + public void test_subtractFrom_wrongChrono(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + ChronoLocalDate isoDate = LocalDate.of(2000, 1, 1); + ChronoLocalDate thaiDate = ThaiBuddhistChronology.INSTANCE.date(2000, 1, 1); + // one of these two will fail + period.subtractFrom(isoDate); + period.subtractFrom(thaiDate); + } + + //----------------------------------------------------------------------- + @Test(dataProvider="calendars") + public void test_negated(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + assertEquals(period.negated(), chrono.period(-1, -2, -3)); + } + + @Test(dataProvider="calendars") + public void test_multipliedBy(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + assertEquals(period.multipliedBy(3), chrono.period(3, 6, 9)); + } + + //----------------------------------------------------------------------- + @Test(dataProvider="calendars") + public void test_equals_equal(Chronology chrono) { + ChronoPeriod a1 = chrono.period(1, 2, 3); + ChronoPeriod a2 = chrono.period(1, 2, 3); + assertEquals(a1, a1); + assertEquals(a1, a2); + assertEquals(a2, a1); + assertEquals(a2, a2); + assertEquals(a1.hashCode(), a2.hashCode()); + } + + @Test(dataProvider="calendars") + public void test_equals_notEqual(Chronology chrono) { + ChronoPeriod a = chrono.period(1, 2, 3); + ChronoPeriod b = chrono.period(2, 2, 3); + assertEquals(a.equals(b), false); + assertEquals(b.equals(a), false); + assertEquals(a.equals(""), false); + assertEquals(a.equals(null), false); + } + + @Test(dataProvider="calendars") + public void test_toString(Chronology chrono) { + ChronoPeriod period = chrono.period(1, 2, 3); + if (period instanceof Period == false) { + assertEquals(period.toString(), chrono.getId() + " P1Y2M3D"); + } + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/TCKChronoZonedDateTime.java --- a/jdk/test/java/time/tck/java/time/chrono/TCKChronoZonedDateTime.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/chrono/TCKChronoZonedDateTime.java Tue Oct 08 14:57:32 2013 -0700 @@ -321,24 +321,6 @@ } //----------------------------------------------------------------------- - // Test Serialization of ISO via chrono API - //----------------------------------------------------------------------- - @Test( dataProvider="calendars") - public void test_ChronoZonedDateTimeSerialization(Chronology chrono) throws Exception { - ZonedDateTime ref = LocalDate.of(2013, 1, 5).atTime(12, 1, 2, 3).atZone(ZoneId.of("GMT+01:23")); - ChronoZonedDateTime orginal = chrono.date(ref).atTime(ref.toLocalTime()).atZone(ref.getZone()); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(orginal); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - @SuppressWarnings("unchecked") - ChronoZonedDateTime ser = (ChronoZonedDateTime) in.readObject(); - assertEquals(ser, orginal, "deserialized date is wrong"); - } - - //----------------------------------------------------------------------- @Test(dataProvider="calendars") public void test_from_TemporalAccessor(Chronology chrono) { ZonedDateTime refDateTime = ZonedDateTime.of(2013, 1, 1, 12, 30, 0, 0, ZoneId.of("Europe/Paris")); @@ -363,6 +345,13 @@ } //----------------------------------------------------------------------- + @Test(dataProvider="calendars") + public void test_getChronology(Chronology chrono) { + ChronoZonedDateTime test = chrono.zonedDateTime(ZonedDateTime.of(2010, 6, 30, 11, 30, 0, 0, ZoneOffset.UTC)); + assertEquals(test.getChronology(), chrono); + } + + //----------------------------------------------------------------------- /** * FixedAdjusted returns a fixed Temporal in all adjustments. * Construct an adjuster with the Temporal that should be returned from adjust. diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/TCKChronology.java --- a/jdk/test/java/time/tck/java/time/chrono/TCKChronology.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/chrono/TCKChronology.java Tue Oct 08 14:57:32 2013 -0700 @@ -64,7 +64,6 @@ import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; -import java.util.Locale; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; @@ -338,20 +337,4 @@ Chronology chrono = Chronology.of("FooFoo"); } - //----------------------------------------------------------------------- - // serialization; serialize and check each calendar system - //----------------------------------------------------------------------- - @Test(dataProvider = "calendarNameAndType") - public void test_chronoSerializationSingleton(String id, String _calendarType) throws Exception { - Chronology original = Chronology.of(id); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(original); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - Chronology ser = (Chronology) in.readObject(); - assertEquals(ser, original, "Deserialized Chronology is not correct"); - } - } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/TCKChronologySerialization.java --- a/jdk/test/java/time/tck/java/time/chrono/TCKChronologySerialization.java Tue Oct 08 14:53:14 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/* - * Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of JSR-310 nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tck.java.time.chrono; - -import static org.testng.Assert.assertEquals; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.PrintStream; -import java.time.chrono.Chronology; -import java.time.chrono.HijrahChronology; -import java.time.chrono.IsoChronology; -import java.time.chrono.JapaneseChronology; -import java.time.chrono.MinguoChronology; -import java.time.chrono.ThaiBuddhistChronology; - -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -public class TCKChronologySerialization { - - //----------------------------------------------------------------------- - // regular data factory for names and descriptions of available calendars - //----------------------------------------------------------------------- - @DataProvider(name = "calendars") - Chronology[][] data_of_calendars() { - return new Chronology[][]{ - {HijrahChronology.INSTANCE}, - {IsoChronology.INSTANCE}, - {JapaneseChronology.INSTANCE}, - {MinguoChronology.INSTANCE}, - {ThaiBuddhistChronology.INSTANCE}}; - } - - //----------------------------------------------------------------------- - // Test Serialization of Calendars - //----------------------------------------------------------------------- - @Test(dataProvider="calendars") - public void test_ChronoSerialization(Chronology chrono) throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(chrono); - out.close(); - - byte[] bytes = baos.toByteArray(); - ByteArrayInputStream bais = new ByteArrayInputStream(bytes); - - ObjectInputStream in = new ObjectInputStream(bais); - @SuppressWarnings("unchecked") - Chronology ser = (Chronology) in.readObject(); - assertEquals(ser, chrono, "deserialized Chronology is wrong"); - } - - /** - * Utility method to dump a byte array in a java syntax. - * @param bytes and array of bytes - * @param os the outputstream to receive the output. - */ - static void dumpSerialStream(byte[] bytes, PrintStream os) { - os.printf(" byte[] bytes = {" ); - final int linelen = 10; - for (int i = 0; i < bytes.length; i++) { - if (i % linelen == 0) { - os.printf("%n "); - } - os.printf(" %3d,", bytes[i] & 0xff); - if ((i % linelen) == (linelen-1) || i == bytes.length - 1) { - os.printf(" /*"); - int s = i / linelen * linelen; - int k = i % linelen; - for (int j = 0; j <= k && s + j < bytes.length; j++) { - os.printf(" %c", bytes[s + j] & 0xff); - } - os.printf(" */"); - } - } - os.printf("%n };%n"); - } - -} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/TCKJapaneseChronology.java --- a/jdk/test/java/time/tck/java/time/chrono/TCKJapaneseChronology.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/chrono/TCKJapaneseChronology.java Tue Oct 08 14:57:32 2013 -0700 @@ -79,6 +79,7 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoPeriod; import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.chrono.IsoChronology; @@ -87,6 +88,7 @@ import java.time.chrono.JapaneseEra; import java.time.chrono.MinguoChronology; import java.time.chrono.MinguoDate; +import java.time.chrono.ThaiBuddhistChronology; import java.time.format.ResolverStyle; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; @@ -615,8 +617,8 @@ public void test_periodUntilDate() { JapaneseDate mdate1 = JapaneseDate.of(1970, 1, 1); JapaneseDate mdate2 = JapaneseDate.of(1971, 2, 2); - Period period = mdate1.until(mdate2); - assertEquals(period, Period.of(1, 1, 1)); + ChronoPeriod period = mdate1.until(mdate2); + assertEquals(period, JapaneseChronology.INSTANCE.period(1, 1, 1)); } @Test @@ -632,8 +634,8 @@ JapaneseDate mdate1 = JapaneseDate.of(1970, 1, 1); JapaneseDate mdate2 = JapaneseDate.of(1971, 2, 2); MinguoDate ldate2 = MinguoChronology.INSTANCE.date(mdate2); - Period period = mdate1.until(ldate2); - assertEquals(period, Period.of(1, 1, 1)); + ChronoPeriod period = mdate1.until(ldate2); + assertEquals(period, JapaneseChronology.INSTANCE.period(1, 1, 1)); } //----------------------------------------------------------------------- diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/TCKMinguoChronology.java --- a/jdk/test/java/time/tck/java/time/chrono/TCKMinguoChronology.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/chrono/TCKMinguoChronology.java Tue Oct 08 14:57:32 2013 -0700 @@ -69,13 +69,13 @@ import java.time.LocalTime; import java.time.Month; import java.time.OffsetDateTime; -import java.time.Period; import java.time.Year; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.chrono.ChronoLocalDate; import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.ChronoPeriod; import java.time.chrono.ChronoZonedDateTime; import java.time.chrono.Chronology; import java.time.chrono.Era; @@ -84,8 +84,6 @@ import java.time.chrono.MinguoChronology; import java.time.chrono.MinguoDate; import java.time.chrono.MinguoEra; -import java.time.chrono.MinguoChronology; -import java.time.chrono.MinguoDate; import java.time.chrono.ThaiBuddhistChronology; import java.time.chrono.ThaiBuddhistDate; import java.time.format.ResolverStyle; @@ -499,8 +497,8 @@ public void test_periodUntilDate() { MinguoDate mdate1 = MinguoDate.of(1970, 1, 1); MinguoDate mdate2 = MinguoDate.of(1971, 2, 2); - Period period = mdate1.until(mdate2); - assertEquals(period, Period.of(1, 1, 1)); + ChronoPeriod period = mdate1.until(mdate2); + assertEquals(period, MinguoChronology.INSTANCE.period(1, 1, 1)); } @Test @@ -516,8 +514,8 @@ MinguoDate mdate1 = MinguoDate.of(1970, 1, 1); MinguoDate mdate2 = MinguoDate.of(1971, 2, 2); ThaiBuddhistDate ldate2 = ThaiBuddhistChronology.INSTANCE.date(mdate2); - Period period = mdate1.until(ldate2); - assertEquals(period, Period.of(1, 1, 1)); + ChronoPeriod period = mdate1.until(ldate2); + assertEquals(period, MinguoChronology.INSTANCE.period(1, 1, 1)); } //----------------------------------------------------------------------- diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/TCKTestServiceLoader.java --- a/jdk/test/java/time/tck/java/time/chrono/TCKTestServiceLoader.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/chrono/TCKTestServiceLoader.java Tue Oct 08 14:57:32 2013 -0700 @@ -60,10 +60,6 @@ import static org.testng.Assert.assertEquals; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.time.LocalDate; import java.time.chrono.ChronoLocalDate; import java.time.chrono.Chronology; @@ -78,29 +74,11 @@ public class TCKTestServiceLoader { @Test - public void test_CopticServiceLoader() { + public void test_TestServiceLoader() { Chronology chrono = Chronology.of("Coptic"); ChronoLocalDate copticDate = chrono.date(1729, 4, 27); LocalDate ld = LocalDate.from(copticDate); assertEquals(ld, LocalDate.of(2013, 1, 5), "CopticDate does not match LocalDate"); } - - //----------------------------------------------------------------------- - // Test Serialization of Loaded Coptic Calendar - //----------------------------------------------------------------------- - @Test - public void test_ChronoSerialization() throws Exception { - Chronology chrono = Chronology.of("Coptic"); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(chrono); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - - ObjectInputStream in = new ObjectInputStream(bais); - @SuppressWarnings("unchecked") - Chronology ser = (Chronology) in.readObject(); - assertEquals(ser, chrono, "deserialized Chronology is wrong"); - } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/TCKThaiBuddhistChronology.java --- a/jdk/test/java/time/tck/java/time/chrono/TCKThaiBuddhistChronology.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/chrono/TCKThaiBuddhistChronology.java Tue Oct 08 14:57:32 2013 -0700 @@ -72,11 +72,11 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Month; -import java.time.Period; import java.time.Year; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoPeriod; import java.time.chrono.Chronology; import java.time.chrono.Era; import java.time.chrono.IsoChronology; @@ -458,8 +458,8 @@ public void test_periodUntilDate() { ThaiBuddhistDate mdate1 = ThaiBuddhistDate.of(1, 1, 1); ThaiBuddhistDate mdate2 = ThaiBuddhistDate.of(2, 2, 2); - Period period = mdate1.until(mdate2); - assertEquals(period, Period.of(1, 1, 1)); + ChronoPeriod period = mdate1.until(mdate2); + assertEquals(period, ThaiBuddhistChronology.INSTANCE.period(1, 1, 1)); } @Test @@ -475,8 +475,8 @@ ThaiBuddhistDate mdate1 = ThaiBuddhistDate.of(1, 1, 1); ThaiBuddhistDate mdate2 = ThaiBuddhistDate.of(2, 2, 2); MinguoDate ldate2 = MinguoChronology.INSTANCE.date(mdate2); - Period period = mdate1.until(ldate2); - assertEquals(period, Period.of(1, 1, 1)); + ChronoPeriod period = mdate1.until(ldate2); + assertEquals(period, ThaiBuddhistChronology.INSTANCE.period(1, 1, 1)); } //----------------------------------------------------------------------- diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/serial/TCKChronoLocalDateSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/chrono/serial/TCKChronoLocalDateSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2012, 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. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.chrono.serial; + +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.YEAR; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.ObjectStreamConstants; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.HijrahChronology; +import java.time.chrono.HijrahDate; +import java.time.chrono.JapaneseDate; +import java.time.chrono.JapaneseEra; +import java.time.chrono.MinguoDate; +import java.time.chrono.ThaiBuddhistDate; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + + + +import tck.java.time.AbstractTCKTest; + +/** + * Test serialization of built-in chronologies. + */ +@Test +public class TCKChronoLocalDateSerialization extends AbstractTCKTest { + + static final int CHRONO_TYPE = 1; // java.time.chrono.Ser.CHRONO_TYPE + static final int JAPANESE_DATE_TYPE = 4; // java.time.chrono.Ser.JAPANESE_DATE_TYPE + static final int HIJRAH_DATE_TYPE = 6; // java.time.chrono.Ser.HIJRAH_DATE_TYPE + static final int MINGUO_DATE_TYPE = 7; // java.time.chrono.Ser.MINGUO_DATE_TYPE + static final int THAIBUDDHIST_DATE_TYPE = 8; // java.time.chrono.Ser.THAIBUDDHIST_DATE_TYPE + + //----------------------------------------------------------------------- + // Regular data factory for names and descriptions of available calendars + //----------------------------------------------------------------------- + @DataProvider(name = "calendars") + Object[][] data_of_calendars() { + return new Object[][]{ + {JapaneseDate.of(JapaneseEra.HEISEI, 25, 01, 05), JAPANESE_DATE_TYPE}, + {MinguoDate.of(102, 01, 05), MINGUO_DATE_TYPE}, + {ThaiBuddhistDate.of(2556, 01, 05), THAIBUDDHIST_DATE_TYPE}, + }; + } + + + //----------------------------------------------------------------------- + // Test Serialization of Calendars + //----------------------------------------------------------------------- + @Test( dataProvider="calendars") + public void test_ChronoSerialization(ChronoLocalDate date, int dateType) throws Exception { + assertSerializable(date); + } + + //----------------------------------------------------------------------- + // Test that serialization produces exact sequence of bytes + //----------------------------------------------------------------------- + @Test(dataProvider="calendars") + private void test_serialization_format(ChronoLocalDate date, int dateType) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(dateType); + dos.writeInt(date.get(YEAR)); + dos.writeByte(date.get(MONTH_OF_YEAR)); + dos.writeByte(date.get(DAY_OF_MONTH)); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(date, bytes); + } + + //----------------------------------------------------------------------- + // Test HijrajDate serialization is a type, Chronology, year, month, day + //----------------------------------------------------------------------- + @Test() + public void test_hijrahSerialization_format() throws Exception { + HijrahChronology chrono = HijrahChronology.INSTANCE; + HijrahDate date = HijrahDate.of(1433, 10, 29); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // Expect the type of the HijrahDate in the stream + byte[] hijrahDateBytes = new byte[] {HIJRAH_DATE_TYPE}; + + // Literal reference to Hijrah-Umalqura Chronology + byte[] hijrahChronoBytes = new byte[] { + 115, 113, 0, 126, 0, 0, /* p w \u0001 \u0006 s q \u0000 ~ \u0000 \u0000 */ + 119, 18, 1, 0, 15, 72, 105, 106, 114, 97, /* w \u0012 \u0001 \u0000 \u000f H i j r a */ + 104, 45, 117, 109, 97, 108, 113, 117, 114, 97, /* h - u m a l q u r a */ + 120, /* \u001d x */ + }; + + // Build the sequence that represents the data in the stream + baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(ObjectStreamConstants.TC_BLOCKDATA); + dos.writeByte(6); // 6 bytes follow + dos.writeInt(date.get(YEAR)); + dos.writeByte(date.get(MONTH_OF_YEAR)); + dos.writeByte(date.get(DAY_OF_MONTH)); + dos.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); + } + byte[] dateBytes = baos.toByteArray(); + + assertSerializedBySer(date, hijrahDateBytes, hijrahChronoBytes, dateBytes); + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/serial/TCKChronoLocalDateTimeSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/chrono/serial/TCKChronoLocalDateTimeSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2012, 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. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.chrono.serial; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.Chronology; +import java.time.chrono.HijrahChronology; +import java.time.chrono.IsoChronology; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.MinguoChronology; +import java.time.chrono.ThaiBuddhistChronology; + +import tck.java.time.AbstractTCKTest; + +/** + * Test serialization of ChronoLocalDateTime for all built-in chronologies. + */ +@Test +public class TCKChronoLocalDateTimeSerialization extends AbstractTCKTest { + + //----------------------------------------------------------------------- + // regular data factory for available calendars + //----------------------------------------------------------------------- + @DataProvider(name = "calendars") + Chronology[][] data_of_calendars() { + return new Chronology[][]{ + {HijrahChronology.INSTANCE}, + {IsoChronology.INSTANCE}, + {JapaneseChronology.INSTANCE}, + {MinguoChronology.INSTANCE}, + {ThaiBuddhistChronology.INSTANCE}}; + } + + //----------------------------------------------------------------------- + // Test Serialization of ChronoLocalDateTime + //----------------------------------------------------------------------- + @Test(dataProvider="calendars") + public void test_ChronoLocalDateTimeSerialization(Chronology chrono) throws Exception { + LocalDateTime ref = LocalDate.of(2013, 1, 5).atTime(12, 1, 2, 3); + ChronoLocalDateTime original = chrono.date(ref).atTime(ref.toLocalTime()); + assertSerializable(original); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/serial/TCKChronoZonedDateTimeSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/chrono/serial/TCKChronoZonedDateTimeSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2012, 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. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.chrono.serial; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.chrono.ChronoZonedDateTime; +import java.time.chrono.Chronology; +import java.time.chrono.HijrahChronology; +import java.time.chrono.IsoChronology; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.MinguoChronology; +import java.time.chrono.ThaiBuddhistChronology; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +/** + * Test assertions that must be true for all built-in chronologies. + */ +@Test +public class TCKChronoZonedDateTimeSerialization extends AbstractTCKTest { + + //----------------------------------------------------------------------- + // regular data factory for names and descriptions of available calendars + //----------------------------------------------------------------------- + @DataProvider(name = "calendars") + Chronology[][] data_of_calendars() { + return new Chronology[][]{ + {HijrahChronology.INSTANCE}, + {IsoChronology.INSTANCE}, + {JapaneseChronology.INSTANCE}, + {MinguoChronology.INSTANCE}, + {ThaiBuddhistChronology.INSTANCE}, + }; + } + + //----------------------------------------------------------------------- + // Test Serialization of ISO via chrono API + //----------------------------------------------------------------------- + @Test( dataProvider="calendars") + public void test_ChronoZonedDateTimeSerialization(Chronology chrono) throws Exception { + ZonedDateTime ref = LocalDate.of(2013, 1, 5).atTime(12, 1, 2, 3).atZone(ZoneId.of("GMT+01:23")); + ChronoZonedDateTime original = chrono.date(ref).atTime(ref.toLocalTime()).atZone(ref.getZone()); + assertSerializable(original); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/serial/TCKChronologySerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/chrono/serial/TCKChronologySerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 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. + */ + +/* + * Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.chrono.serial; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; + +import java.time.chrono.Chronology; +import java.time.chrono.HijrahChronology; +import java.time.chrono.IsoChronology; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.MinguoChronology; +import java.time.chrono.ThaiBuddhistChronology; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import tck.java.time.AbstractTCKTest; + +@Test +public class TCKChronologySerialization extends AbstractTCKTest { + + static final int CHRONO_TYPE = 1; // java.time.chrono.Ser.CHRONO_TYPE + + //----------------------------------------------------------------------- + // Regular data factory for available calendars + //----------------------------------------------------------------------- + @DataProvider(name = "calendars") + Chronology[][] data_of_calendars() { + return new Chronology[][]{ + {HijrahChronology.INSTANCE}, + {IsoChronology.INSTANCE}, + {JapaneseChronology.INSTANCE}, + {MinguoChronology.INSTANCE}, + {ThaiBuddhistChronology.INSTANCE}}; + } + + //----------------------------------------------------------------------- + // Test Serialization of Calendars + //----------------------------------------------------------------------- + @Test(dataProvider="calendars") + public void test_chronoSerialization(Chronology chrono) throws Exception { + assertSerializable(chrono); + } + + //----------------------------------------------------------------------- + // Test that serialization produces exact sequence of bytes + //----------------------------------------------------------------------- + @Test(dataProvider="calendars") + private void test_serializationBytes(Chronology chrono) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(CHRONO_TYPE); + dos.writeUTF(chrono.getId()); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(chrono, bytes); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/serial/TCKCopticSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/chrono/serial/TCKCopticSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.chrono.serial; + +import java.io.IOException; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.Chronology; + +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +/** + * Tests the serialization of ChronoLocalDate using a CopticDate. + */ +@Test +public class TCKCopticSerialization extends AbstractTCKTest { + + @Test + public void test_eraSerialization() throws IOException, ClassNotFoundException { + Chronology chrono = Chronology.of("Coptic"); + ChronoLocalDate copticDate = chrono.date(1729, 4, 27); + assertSerializable(copticDate); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/chrono/serial/TCKEraSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/chrono/serial/TCKEraSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.chrono.serial; + + +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.YEAR; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.Era; +import java.time.chrono.HijrahEra; +import java.time.chrono.IsoEra; +import java.time.chrono.JapaneseEra; +import java.time.chrono.MinguoEra; +import java.time.chrono.ThaiBuddhistEra; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import tck.java.time.AbstractTCKTest; + +/** + * Tests the built-in Eras are serializable. + * Note that the serialized form of IsoEra, MinguoEra, ThaiBuddhistEra, + * and HijrahEra are defined and provided by Enum. + * The serialized form of these types are not tested, only that they are + * serializable. + */ +@Test +public class TCKEraSerialization extends AbstractTCKTest { + + static final int JAPANESE_ERA_TYPE = 5; // java.time.chrono.Ser.JAPANESE_ERA + + + //----------------------------------------------------------------------- + // Regular data factory for the available Eras + //----------------------------------------------------------------------- + @DataProvider(name = "Eras") + Era[][] data_of_calendars() { + return new Era[][] { + {HijrahEra.AH}, + {IsoEra.BCE}, + {IsoEra.CE}, + {MinguoEra.BEFORE_ROC}, + {MinguoEra.ROC}, + {ThaiBuddhistEra.BEFORE_BE}, + {ThaiBuddhistEra.BE}, + }; + } + + @Test(dataProvider="Eras") + public void test_eraSerialization(Era era) throws IOException, ClassNotFoundException { + assertSerializableSame(era); + } + + //----------------------------------------------------------------------- + // Test JapaneseEra serialization produces exact sequence of bytes + //----------------------------------------------------------------------- + @Test + private void test_JapaneseErasSerialization() throws Exception { + for (JapaneseEra era : JapaneseEra.values()) { + assertSerializableSame(era); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(JAPANESE_ERA_TYPE); + dos.writeByte(era.getValue()); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(era, bytes); + } + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/format/TCKDateTimeParseResolver.java --- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeParseResolver.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeParseResolver.java Tue Oct 08 14:57:32 2013 -0700 @@ -90,20 +90,33 @@ import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.FOREVER; +import static java.time.temporal.ChronoUnit.NANOS; import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Period; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.chrono.Chronology; +import java.time.chrono.ThaiBuddhistChronology; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; import java.time.format.ResolverStyle; +import java.time.temporal.ChronoUnit; import java.time.temporal.IsoFields; +import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalUnit; +import java.time.temporal.ValueRange; +import java.util.Map; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -872,4 +885,210 @@ } } + //----------------------------------------------------------------------- + @Test + public void test_fieldResolvesToLocalTime() { + TemporalField field = new TemporalField() { + @Override + public TemporalUnit getBaseUnit() { + throw new UnsupportedOperationException(); + } + @Override + public TemporalUnit getRangeUnit() { + throw new UnsupportedOperationException(); + } + @Override + public ValueRange range() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isDateBased() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isTimeBased() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isSupportedBy(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public long getFrom(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public R adjustInto(R temporal, long newValue) { + throw new UnsupportedOperationException(); + } + @Override + public TemporalAccessor resolve( + Map fieldValues, Chronology chronology, + ZoneId zone, ResolverStyle resolverStyle) { + return LocalTime.MIDNIGHT.plusNanos(fieldValues.remove(this)); + } + }; + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(field).toFormatter(); + TemporalAccessor accessor = f.parse("1234567890"); + assertEquals(accessor.query(TemporalQuery.localDate()), null); + assertEquals(accessor.query(TemporalQuery.localTime()), LocalTime.of(0, 0, 1, 234_567_890)); + } + + @Test + public void test_fieldResolvesToChronoLocalDateTime() { + TemporalField field = new TemporalField() { + @Override + public TemporalUnit getBaseUnit() { + throw new UnsupportedOperationException(); + } + @Override + public TemporalUnit getRangeUnit() { + throw new UnsupportedOperationException(); + } + @Override + public ValueRange range() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isDateBased() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isTimeBased() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isSupportedBy(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public long getFrom(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public R adjustInto(R temporal, long newValue) { + throw new UnsupportedOperationException(); + } + @Override + public TemporalAccessor resolve( + Map fieldValues, Chronology chronology, + ZoneId zone, ResolverStyle resolverStyle) { + fieldValues.remove(this); + return LocalDateTime.of(2010, 6, 30, 12, 30); + } + }; + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(field).toFormatter(); + TemporalAccessor accessor = f.parse("1234567890"); + assertEquals(accessor.query(TemporalQuery.localDate()), LocalDate.of(2010, 6, 30)); + assertEquals(accessor.query(TemporalQuery.localTime()), LocalTime.of(12, 30)); + } + + @Test(expectedExceptions = DateTimeParseException.class) + public void test_fieldResolvesWrongChrono() { + TemporalField field = new TemporalField() { + @Override + public TemporalUnit getBaseUnit() { + throw new UnsupportedOperationException(); + } + @Override + public TemporalUnit getRangeUnit() { + throw new UnsupportedOperationException(); + } + @Override + public ValueRange range() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isDateBased() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isTimeBased() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isSupportedBy(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public long getFrom(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public R adjustInto(R temporal, long newValue) { + throw new UnsupportedOperationException(); + } + @Override + public TemporalAccessor resolve( + Map fieldValues, Chronology chronology, + ZoneId zone, ResolverStyle resolverStyle) { + return ThaiBuddhistChronology.INSTANCE.dateNow(); + } + }; + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(field).toFormatter(); + f.parse("1234567890"); + } + + @Test(expectedExceptions = DateTimeParseException.class) + public void test_fieldResolvesWrongZone() { + TemporalField field = new TemporalField() { + @Override + public TemporalUnit getBaseUnit() { + throw new UnsupportedOperationException(); + } + @Override + public TemporalUnit getRangeUnit() { + throw new UnsupportedOperationException(); + } + @Override + public ValueRange range() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isDateBased() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isTimeBased() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isSupportedBy(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public long getFrom(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public R adjustInto(R temporal, long newValue) { + throw new UnsupportedOperationException(); + } + @Override + public TemporalAccessor resolve( + Map fieldValues, Chronology chronology, + ZoneId zone, ResolverStyle resolverStyle) { + return ZonedDateTime.of(2010, 6, 30, 12, 30, 0, 0, ZoneId.of("Europe/Paris")); + } + }; + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(field).toFormatter().withZone(ZoneId.of("Europe/London")); + f.parse("1234567890"); + } + } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKClockSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKClockSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012 Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + + +import java.io.IOException; +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +import org.testng.annotations.Test; + +import tck.java.time.AbstractTCKTest; + +/** + * Test system and offset clocks serialization. + */ +@Test +public class TCKClockSerialization extends AbstractTCKTest { + + private static final ZoneId MOSCOW = ZoneId.of("Europe/Moscow"); + private static final ZoneId PARIS = ZoneId.of("Europe/Paris"); + + private static final Duration AMOUNT = Duration.ofSeconds(2); + private static final ZonedDateTime ZDT = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).atZone(ZoneOffset.ofHours(2)); + private static final Instant INSTANT = ZDT.toInstant(); + + //----------------------------------------------------------------------- + public void test_systemClockSerializable() throws IOException, ClassNotFoundException { + assertSerializable(Clock.systemUTC()); + assertSerializable(Clock.systemDefaultZone()); + assertSerializable(Clock.system(PARIS)); + } + + //----------------------------------------------------------------------- + public void test_offsetClockSerializable() throws IOException, ClassNotFoundException { + assertSerializable(Clock.offset(Clock.system(PARIS), AMOUNT)); + } + + //----------------------------------------------------------------------- + public void test_tickClockSerializable() throws IOException, ClassNotFoundException { + assertSerializable(Clock.tickSeconds(PARIS)); + assertSerializable(Clock.tickMinutes(MOSCOW)); + assertSerializable(Clock.tick(Clock.fixed(INSTANT, PARIS), AMOUNT)); + } + + //----------------------------------------------------------------------- + public void test_fixedClockSerializable() throws IOException, ClassNotFoundException { + assertSerializable(Clock.fixed(INSTANT, ZoneOffset.UTC)); + assertSerializable(Clock.fixed(INSTANT, PARIS)); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKDurationSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKDurationSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + +import static org.testng.Assert.assertTrue; + +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.Serializable; +import java.time.Duration; + +/** + * Test Duration serialization. + */ +@Test +public class TCKDurationSerialization extends AbstractTCKTest { + + //----------------------------------------------------------------------- + @Test + public void test_interfaces() { + assertTrue(Serializable.class.isAssignableFrom(Duration.class)); + assertTrue(Comparable.class.isAssignableFrom(Duration.class)); + } + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(Duration.ofHours(5)); + assertSerializable(Duration.ofHours(0)); + assertSerializable(Duration.ofHours(-5)); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(1); + dos.writeLong(654321); + dos.writeInt(123456789); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(Duration.ofSeconds(654321, 123456789), bytes); + } + + //----------------------------------------------------------------------- + // serialization + //----------------------------------------------------------------------- + @Test + public void test_deserializationSingleton() throws Exception { + assertSerializableSame(Duration.ZERO); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKInstantSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKInstantSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.time.Instant; + +/** + * Test Instant serialization. + */ +@Test +public class TCKInstantSerialization extends AbstractTCKTest { + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(Instant.ofEpochMilli(134l)); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(2); + dos.writeLong(654321); + dos.writeInt(123456789); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(Instant.ofEpochSecond(654321, 123456789), bytes); + } + + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKLocalDateSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKLocalDateSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.time.LocalDate; + +/** + * Test LocalDate serialization. + */ +@Test +public class TCKLocalDateSerialization extends AbstractTCKTest { + + private LocalDate TEST_2007_07_15; + + @BeforeMethod + public void setUp() { + TEST_2007_07_15 = LocalDate.of(2007, 7, 15); + } + + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(TEST_2007_07_15); + assertSerializable(LocalDate.MIN); + assertSerializable(LocalDate.MAX); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(3); + dos.writeInt(2012); + dos.writeByte(9); + dos.writeByte(16); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(LocalDate.of(2012, 9, 16), bytes); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKLocalDateTimeSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKLocalDateTimeSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.time.LocalDateTime; + +/** + * Test serialization of LocalDateTime. + */ +@Test +public class TCKLocalDateTimeSerialization extends AbstractTCKTest { + + private LocalDateTime TEST_2007_07_15_12_30_40_987654321 = LocalDateTime.of(2007, 7, 15, 12, 30, 40, 987654321); + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(TEST_2007_07_15_12_30_40_987654321); + assertSerializable(LocalDateTime.MIN); + assertSerializable(LocalDateTime.MAX); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(5); + dos.writeInt(2012); + dos.writeByte(9); + dos.writeByte(16); + dos.writeByte(22); + dos.writeByte(17); + dos.writeByte(59); + dos.writeInt(459_000_000); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(LocalDateTime.of(2012, 9, 16, 22, 17, 59, 459_000_000), bytes); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKLocalTimeSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKLocalTimeSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.time.LocalTime; + +/** + * Test LocalTime serialization. + */ +@Test +public class TCKLocalTimeSerialization extends AbstractTCKTest { + + + private LocalTime TEST_12_30_40_987654321; + + + @BeforeMethod + public void setUp() { + TEST_12_30_40_987654321 = LocalTime.of(12, 30, 40, 987654321); + } + + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(TEST_12_30_40_987654321); + assertSerializable(LocalTime.MIN); + assertSerializable(LocalTime.MAX); + } + + @Test + public void test_serialization_format_h() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(4); + dos.writeByte(-1 - 22); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(LocalTime.of(22, 0), bytes); + } + + @Test + public void test_serialization_format_hm() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(4); + dos.writeByte(22); + dos.writeByte(-1 - 17); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(LocalTime.of(22, 17), bytes); + } + + @Test + public void test_serialization_format_hms() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(4); + dos.writeByte(22); + dos.writeByte(17); + dos.writeByte(-1 - 59); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(LocalTime.of(22, 17, 59), bytes); + } + + @Test + public void test_serialization_format_hmsn() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(4); + dos.writeByte(22); + dos.writeByte(17); + dos.writeByte(59); + dos.writeInt(459_000_000); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(LocalTime.of(22, 17, 59, 459_000_000), bytes); + } + + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKMonthDaySerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKMonthDaySerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.time.MonthDay; + +/** + * Test MonthDay serialization. + */ +@Test +public class TCKMonthDaySerialization extends AbstractTCKTest { + + private MonthDay TEST_07_15; + + @BeforeMethod + public void setUp() { + TEST_07_15 = MonthDay.of(7, 15); + } + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws ClassNotFoundException, IOException { + assertSerializable(TEST_07_15); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(13); // java.time.temporal.Ser.MONTH_DAY_TYPE + dos.writeByte(9); + dos.writeByte(16); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(MonthDay.of(9, 16), bytes); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKOffsetDateTimeSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKOffsetDateTimeSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +/** + * Test OffsetDateTime serialization. + */ +@Test +public class TCKOffsetDateTimeSerialization extends AbstractTCKTest { + + private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); + private OffsetDateTime TEST_2008_6_30_11_30_59_000000500; + + @BeforeMethod + public void setUp() { + TEST_2008_6_30_11_30_59_000000500 = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 500, OFFSET_PONE); + } + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(TEST_2008_6_30_11_30_59_000000500); + assertSerializable(OffsetDateTime.MIN); + assertSerializable(OffsetDateTime.MAX); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(10); // java.time.Ser.OFFSET_DATE_TIME_TYPE + } + byte[] bytes = baos.toByteArray(); + ByteArrayOutputStream baosDateTime = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baosDateTime) ) { + dos.writeByte(5); + dos.writeInt(2012); + dos.writeByte(9); + dos.writeByte(16); + dos.writeByte(22); + dos.writeByte(17); + dos.writeByte(59); + dos.writeInt(464_000_000); + } + byte[] bytesDateTime = baosDateTime.toByteArray(); + ByteArrayOutputStream baosOffset = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baosOffset) ) { + dos.writeByte(8); + dos.writeByte(4); // quarter hours stored: 3600 / 900 + } + byte[] bytesOffset = baosOffset.toByteArray(); + LocalDateTime ldt = LocalDateTime.of(2012, 9, 16, 22, 17, 59, 464_000_000); + assertSerializedBySer(OffsetDateTime.of(ldt, ZoneOffset.ofHours(1)), bytes, bytesDateTime, bytesOffset); + } + + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKOffsetTimeSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKOffsetTimeSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.time.OffsetTime; +import java.time.ZoneOffset; + +/** + * Test OffsetTime serialization. + */ +@Test +public class TCKOffsetTimeSerialization extends AbstractTCKTest { + + private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); + private OffsetTime TEST_11_30_59_500_PONE; + + @BeforeMethod + public void setUp() { + TEST_11_30_59_500_PONE = OffsetTime.of(11, 30, 59, 500, OFFSET_PONE); + } + + + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(TEST_11_30_59_500_PONE); + assertSerializable(OffsetTime.MIN); + assertSerializable(OffsetTime.MAX); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(9); // java.time.Ser.OFFSET_TIME_TYPE + } + byte[] bytes = baos.toByteArray(); + ByteArrayOutputStream baosTime = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baosTime) ) { + dos.writeByte(4); + dos.writeByte(22); + dos.writeByte(17); + dos.writeByte(59); + dos.writeInt(464_000_000); + } + byte[] bytesTime = baosTime.toByteArray(); + ByteArrayOutputStream baosOffset = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baosOffset) ) { + dos.writeByte(8); + dos.writeByte(4); // quarter hours stored: 3600 / 900 + } + byte[] bytesOffset = baosOffset.toByteArray(); + assertSerializedBySer(OffsetTime.of(22, 17, 59, 464_000_000, ZoneOffset.ofHours(1)), bytes, + bytesTime, bytesOffset); + } + + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKPeriodSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKPeriodSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.time.Period; + +/** + * Test serialization of Period. + */ +@Test +public class TCKPeriodSerialization extends AbstractTCKTest { + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(Period.ZERO); + assertSerializable(Period.ofDays(1)); + assertSerializable(Period.of(1, 2, 3)); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKYearMonthSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKYearMonthSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.time.YearMonth; + +/** + * Test serialization of YearMonth. + */ +@Test +public class TCKYearMonthSerialization extends AbstractTCKTest { + + private YearMonth TEST_2008_06; + + @BeforeMethod + public void setUp() { + TEST_2008_06 = YearMonth.of(2008, 6); + } + + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws IOException, ClassNotFoundException { + assertSerializable(TEST_2008_06); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(12); // java.time.temporal.Ser.YEAR_MONTH_TYPE + dos.writeInt(2012); + dos.writeByte(9); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(YearMonth.of(2012, 9), bytes); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKYearSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKYearSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.time.Year; + +/** + * Test Year serialization. + */ +@Test +public class TCKYearSerialization extends AbstractTCKTest { + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(Year.of(2)); + assertSerializable(Year.of(0)); + assertSerializable(Year.of(-2)); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(11); // java.time.temporal.Ser.YEAR_TYPE + dos.writeInt(2012); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(Year.of(2012), bytes); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKZoneIdSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKZoneIdSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.io.*; +import java.lang.reflect.Field; +import java.time.DateTimeException; +import java.time.ZoneId; +import java.time.zone.ZoneRulesException; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +/** + * Test serialization of ZoneId. + */ +@Test +public class TCKZoneIdSerialization extends AbstractTCKTest { + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(ZoneId.of("Europe/London")); + assertSerializable(ZoneId.of("America/Chicago")); + } + + @Test + public void test_serialization_format() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(7); + dos.writeUTF("Europe/London"); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(ZoneId.of("Europe/London"), bytes); + } + + @Test + public void test_deserialization_lenient_characters() throws Exception { + // an ID can be loaded without validation during deserialization + String id = "QWERTYUIOPASDFGHJKLZXCVBNM~/._+-"; + ZoneId deser = deserialize(id); + // getId, equals, hashCode, toString and normalized are OK + assertEquals(deser.getId(), id); + assertEquals(deser.toString(), id); + assertEquals(deser, deser); + assertEquals(deser.hashCode(), deser.hashCode()); + assertEquals(deser.normalized(), deser); + // getting the rules is not + try { + deser.getRules(); + fail(); + } catch (ZoneRulesException ex) { + // expected + } + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_deserialization_lenient_badCharacters() throws Exception { + // an ID can be loaded without validation during deserialization + // but there is a check to ensure the ID format is valid + deserialize("|!?"); + } + + @Test(dataProvider="offsetBasedValid") + public void test_deserialization_lenient_offsetNotAllowed_noPrefix(String input, String resolvedId) throws Exception { + ZoneId deserialized = deserialize(input); + assertEquals(deserialized, ZoneId.of(input)); + assertEquals(deserialized, ZoneId.of(resolvedId)); + } + + @Test(dataProvider="offsetBasedValidPrefix") + public void test_deserialization_lenient_offsetNotAllowed_prefixUTC(String input, String resolvedId, String offsetId) throws Exception { + ZoneId deserialized = deserialize("UTC" + input); + assertEquals(deserialized, ZoneId.of("UTC" + input)); + assertEquals(deserialized, ZoneId.of("UTC" + resolvedId)); + } + + @Test(dataProvider="offsetBasedValidPrefix") + public void test_deserialization_lenient_offsetNotAllowed_prefixGMT(String input, String resolvedId, String offsetId) throws Exception { + ZoneId deserialized = deserialize("GMT" + input); + assertEquals(deserialized, ZoneId.of("GMT" + input)); + assertEquals(deserialized, ZoneId.of("GMT" + resolvedId)); + } + + @Test(dataProvider="offsetBasedValidPrefix") + public void test_deserialization_lenient_offsetNotAllowed_prefixUT(String input, String resolvedId, String offsetId) throws Exception { + ZoneId deserialized = deserialize("UT" + input); + assertEquals(deserialized, ZoneId.of("UT" + input)); + assertEquals(deserialized, ZoneId.of("UT" + resolvedId)); + } + + private ZoneId deserialize(String id) throws Exception { + String serClass = ZoneId.class.getPackage().getName() + ".Ser"; + Class serCls = Class.forName(serClass); + Field field = serCls.getDeclaredField("serialVersionUID"); + field.setAccessible(true); + long serVer = (Long) field.get(null); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos)) { + dos.writeShort(ObjectStreamConstants.STREAM_MAGIC); + dos.writeShort(ObjectStreamConstants.STREAM_VERSION); + dos.writeByte(ObjectStreamConstants.TC_OBJECT); + dos.writeByte(ObjectStreamConstants.TC_CLASSDESC); + dos.writeUTF(serClass); + dos.writeLong(serVer); + dos.writeByte(ObjectStreamConstants.SC_EXTERNALIZABLE | ObjectStreamConstants.SC_BLOCK_DATA); + dos.writeShort(0); // number of fields + dos.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); // end of classdesc + dos.writeByte(ObjectStreamConstants.TC_NULL); // no superclasses + dos.writeByte(ObjectStreamConstants.TC_BLOCKDATA); + dos.writeByte(1 + 2 + id.length()); // length of data (1 byte + 2 bytes UTF length + 32 bytes UTF) + dos.writeByte(7); // ZoneId + dos.writeUTF(id); + dos.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); // end of blockdata + } + ZoneId deser = null; + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + deser = (ZoneId) ois.readObject(); + } + return deser; + } + + //----------------------------------------------------------------------- + // regular factory and .normalized() + //----------------------------------------------------------------------- + @DataProvider(name="offsetBasedValid") + Object[][] data_offsetBasedValid() { + return new Object[][] { + {"Z", "Z"}, + {"+0", "Z"}, + {"-0", "Z"}, + {"+00", "Z"}, + {"+0000", "Z"}, + {"+00:00", "Z"}, + {"+000000", "Z"}, + {"+00:00:00", "Z"}, + {"-00", "Z"}, + {"-0000", "Z"}, + {"-00:00", "Z"}, + {"-000000", "Z"}, + {"-00:00:00", "Z"}, + {"+5", "+05:00"}, + {"+01", "+01:00"}, + {"+0100", "+01:00"}, + {"+01:00", "+01:00"}, + {"+010000", "+01:00"}, + {"+01:00:00", "+01:00"}, + {"+12", "+12:00"}, + {"+1234", "+12:34"}, + {"+12:34", "+12:34"}, + {"+123456", "+12:34:56"}, + {"+12:34:56", "+12:34:56"}, + {"-02", "-02:00"}, + {"-5", "-05:00"}, + {"-0200", "-02:00"}, + {"-02:00", "-02:00"}, + {"-020000", "-02:00"}, + {"-02:00:00", "-02:00"}, + }; + } + + //----------------------------------------------------------------------- + @DataProvider(name="offsetBasedValidPrefix") + Object[][] data_offsetBasedValidPrefix() { + return new Object[][] { + {"", "", "Z"}, + {"+0", "", "Z"}, + {"-0", "", "Z"}, + {"+00", "", "Z"}, + {"+0000", "", "Z"}, + {"+00:00", "", "Z"}, + {"+000000", "", "Z"}, + {"+00:00:00", "", "Z"}, + {"-00", "", "Z"}, + {"-0000", "", "Z"}, + {"-00:00", "", "Z"}, + {"-000000", "", "Z"}, + {"-00:00:00", "", "Z"}, + {"+5", "+05:00", "+05:00"}, + {"+01", "+01:00", "+01:00"}, + {"+0100", "+01:00", "+01:00"}, + {"+01:00", "+01:00", "+01:00"}, + {"+010000", "+01:00", "+01:00"}, + {"+01:00:00", "+01:00", "+01:00"}, + {"+12", "+12:00", "+12:00"}, + {"+1234", "+12:34", "+12:34"}, + {"+12:34", "+12:34", "+12:34"}, + {"+123456", "+12:34:56", "+12:34:56"}, + {"+12:34:56", "+12:34:56", "+12:34:56"}, + {"-02", "-02:00", "-02:00"}, + {"-5", "-05:00", "-05:00"}, + {"-0200", "-02:00", "-02:00"}, + {"-02:00", "-02:00", "-02:00"}, + {"-020000", "-02:00", "-02:00"}, + {"-02:00:00", "-02:00", "-02:00"}, + }; + } + + + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKZoneOffsetSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKZoneOffsetSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.time.ZoneOffset; + +/** + * Test serialization of ZoneOffset. + */ +@Test +public class TCKZoneOffsetSerialization extends AbstractTCKTest { + + + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(ZoneOffset.of("+01:30")); + } + + @Test + public void test_serialization_format_quarterPositive() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(8); + dos.writeByte(6); // stored as quarter hours + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(ZoneOffset.ofHoursMinutes(1, 30), bytes); + } + + @Test + public void test_serialization_format_quarterNegative() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(8); + dos.writeByte(-10); // stored as quarter hours + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(ZoneOffset.ofHoursMinutes(-2, -30), bytes); + } + + @Test + public void test_serialization_format_full() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(8); + dos.writeByte(127); + dos.writeInt(53265); + } + byte[] bytes = baos.toByteArray(); + assertSerializedBySer(ZoneOffset.ofTotalSeconds(53265), bytes); + } + + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/serial/TCKZonedDateTimeSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/serial/TCKZonedDateTimeSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.serial; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +/** + * Test serialization of ZonedDateTime. + */ +@Test +public class TCKZonedDateTimeSerialization extends AbstractTCKTest { + + private static final ZoneOffset OFFSET_0100 = ZoneOffset.ofHours(1); + private static final ZoneId ZONE_0100 = OFFSET_0100; + private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris"); + private LocalDateTime TEST_LOCAL_2008_06_30_11_30_59_500; + private ZonedDateTime TEST_DATE_TIME; + + + @BeforeMethod + public void setUp() { + TEST_LOCAL_2008_06_30_11_30_59_500 = LocalDateTime.of(2008, 6, 30, 11, 30, 59, 500); + TEST_DATE_TIME = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100); + } + + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws ClassNotFoundException, IOException { + assertSerializable(TEST_DATE_TIME); + } + + @Test + public void test_serialization_format_zoneId() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(6); + dos.writeInt(2012); // date + dos.writeByte(9); + dos.writeByte(16); + dos.writeByte(22); // time + dos.writeByte(17); + dos.writeByte(59); + dos.writeInt(470_000_000); + dos.writeByte(4); // offset + dos.writeByte(7); // zoneId + dos.writeUTF("Europe/London"); + } + byte[] bytes = baos.toByteArray(); + ZonedDateTime zdt = LocalDateTime.of(2012, 9, 16, 22, 17, 59, 470_000_000).atZone(ZoneId.of("Europe/London")); + assertSerializedBySer(zdt, bytes); + } + + @Test + public void test_serialization_format_zoneOffset() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos) ) { + dos.writeByte(6); + dos.writeInt(2012); // date + dos.writeByte(9); + dos.writeByte(16); + dos.writeByte(22); // time + dos.writeByte(17); + dos.writeByte(59); + dos.writeInt(470_000_000); + dos.writeByte(4); // offset + dos.writeByte(8); // zoneId + dos.writeByte(4); + } + byte[] bytes = baos.toByteArray(); + ZonedDateTime zdt = LocalDateTime.of(2012, 9, 16, 22, 17, 59, 470_000_000).atZone(ZoneOffset.ofHours(1)); + assertSerializedBySer(zdt, bytes); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/temporal/TCKIsoFields.java --- a/jdk/test/java/time/tck/java/time/temporal/TCKIsoFields.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/temporal/TCKIsoFields.java Tue Oct 08 14:57:32 2013 -0700 @@ -70,11 +70,13 @@ import java.time.DayOfWeek; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; import java.time.format.ResolverStyle; import java.time.temporal.IsoFields; +import java.time.temporal.Temporal; import java.time.temporal.ValueRange; import org.testng.annotations.DataProvider; @@ -276,14 +278,21 @@ {LocalDate.of(2000, 1, 1), LocalDate.of(1998, 12, 31), -4}, {LocalDate.of(2000, 1, 1), LocalDate.of(1998, 10, 2), -4}, {LocalDate.of(2000, 1, 1), LocalDate.of(1998, 10, 1), -5}, + + {LocalDate.of(2000, 1, 1), LocalDateTime.of(2001, 4, 5, 0, 0), 5}, }; } @Test(dataProvider="quartersBetween") - public void test_quarters_between(LocalDate start, LocalDate end, long expected) { + public void test_quarters_between(LocalDate start, Temporal end, long expected) { assertEquals(IsoFields.QUARTER_YEARS.between(start, end), expected); } + @Test(dataProvider="quartersBetween") + public void test_quarters_between_until(LocalDate start, Temporal end, long expected) { + assertEquals(start.until(end, IsoFields.QUARTER_YEARS), expected); + } + //----------------------------------------------------------------------- //----------------------------------------------------------------------- //----------------------------------------------------------------------- diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/temporal/TCKJulianFields.java --- a/jdk/test/java/time/tck/java/time/temporal/TCKJulianFields.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/temporal/TCKJulianFields.java Tue Oct 08 14:57:32 2013 -0700 @@ -76,7 +76,7 @@ import tck.java.time.AbstractTCKTest; /** - * Test. + * Test Julian Fields. */ @Test public class TCKJulianFields extends AbstractTCKTest { @@ -86,16 +86,6 @@ private static final LocalDate NOV12_1945 = LocalDate.of(1945, 11, 12); private static final LocalDate JAN01_0001 = LocalDate.of(1, 1, 1); - //----------------------------------------------------------------------- - @DataProvider(name="julian_fields") - Object[][] julian_samples() { - return new Object[][] { - {JulianFields.JULIAN_DAY}, - {JulianFields.MODIFIED_JULIAN_DAY}, - {JulianFields.RATA_DIE}, - }; - } - @DataProvider(name="samples") Object[][] data_samples() { return new Object[][] { @@ -122,11 +112,6 @@ } //----------------------------------------------------------------------- - @Test(dataProvider="julian_fields") - public void test_serializable(TemporalField field) throws IOException, ClassNotFoundException { - assertSerializable(field); - } - public void test_basics() { assertEquals(JulianFields.JULIAN_DAY.isDateBased(), true); assertEquals(JulianFields.JULIAN_DAY.isTimeBased(), false); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/temporal/TCKWeekFields.java --- a/jdk/test/java/time/tck/java/time/temporal/TCKWeekFields.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/temporal/TCKWeekFields.java Tue Oct 08 14:57:32 2013 -0700 @@ -713,12 +713,6 @@ } } - //----------------------------------------------------------------------- - @Test(dataProvider="weekFields") - public void test_serializable_singleton(DayOfWeek firstDayOfWeek, int minDays) throws IOException, ClassNotFoundException { - WeekFields weekDef = WeekFields.of(firstDayOfWeek, minDays); - assertSerializableSame(weekDef); // spec state singleton - } //----------------------------------------------------------------------- @DataProvider(name="weekFields") diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/temporal/serial/TCKChronoFieldSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/temporal/serial/TCKChronoFieldSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2012, 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. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.temporal.serial; + +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; +import static java.time.temporal.ChronoField.AMPM_OF_DAY; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY; +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; +import static java.time.temporal.ChronoField.EPOCH_DAY; +import static java.time.temporal.ChronoField.HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.MICRO_OF_DAY; +import static java.time.temporal.ChronoField.MICRO_OF_SECOND; +import static java.time.temporal.ChronoField.MILLI_OF_DAY; +import static java.time.temporal.ChronoField.MILLI_OF_SECOND; +import static java.time.temporal.ChronoField.MINUTE_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; +import static java.time.temporal.ChronoField.SECOND_OF_DAY; +import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoField.ERA; + +import java.io.IOException; +import java.time.temporal.ChronoField; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import tck.java.time.AbstractTCKTest; + +/** + * Test serialization of ChronoField. + */ +@Test +public class TCKChronoFieldSerialization extends AbstractTCKTest { + + //----------------------------------------------------------------------- + // List of Fields + //----------------------------------------------------------------------- + @DataProvider(name="fieldBased") + Object[][] data_fieldBased() { + return new Object[][] { + {DAY_OF_WEEK}, + {ALIGNED_DAY_OF_WEEK_IN_MONTH}, + {ALIGNED_DAY_OF_WEEK_IN_YEAR}, + {DAY_OF_MONTH}, + {DAY_OF_YEAR}, + {EPOCH_DAY}, + {ALIGNED_WEEK_OF_MONTH}, + {ALIGNED_WEEK_OF_YEAR}, + {MONTH_OF_YEAR}, + {PROLEPTIC_MONTH}, + {YEAR_OF_ERA}, + {YEAR}, + {ERA}, + + {AMPM_OF_DAY}, + {CLOCK_HOUR_OF_DAY}, + {HOUR_OF_DAY}, + {CLOCK_HOUR_OF_AMPM}, + {HOUR_OF_AMPM}, + {MINUTE_OF_DAY}, + {MINUTE_OF_HOUR}, + {SECOND_OF_DAY}, + {SECOND_OF_MINUTE}, + {MILLI_OF_DAY}, + {MILLI_OF_SECOND}, + {MICRO_OF_DAY}, + {MICRO_OF_SECOND}, + {NANO_OF_DAY}, + {NANO_OF_SECOND}, + }; + } + + @Test(dataProvider = "fieldBased") + public void test_fieldSerializable(ChronoField field) throws IOException, ClassNotFoundException { + assertSerializableSame(field); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/temporal/serial/TCKChronoUnitSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/temporal/serial/TCKChronoUnitSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2012, 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. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.temporal.serial; + +import static java.time.temporal.ChronoUnit.CENTURIES; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.DECADES; +import static java.time.temporal.ChronoUnit.ERAS; +import static java.time.temporal.ChronoUnit.FOREVER; +import static java.time.temporal.ChronoUnit.HALF_DAYS; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MICROS; +import static java.time.temporal.ChronoUnit.MILLENNIA; +import static java.time.temporal.ChronoUnit.MILLIS; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.NANOS; +import static java.time.temporal.ChronoUnit.SECONDS; +import static java.time.temporal.ChronoUnit.WEEKS; +import static java.time.temporal.ChronoUnit.YEARS; + +import java.io.IOException; +import java.time.temporal.ChronoUnit; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import tck.java.time.AbstractTCKTest; + +/** + * Test. + */ +@Test +public class TCKChronoUnitSerialization extends AbstractTCKTest { + + //----------------------------------------------------------------------- + // ChronoUnits + //----------------------------------------------------------------------- + @DataProvider(name="chronoUnit") + Object[][] data_chronoUnit() { + return new Object[][] { + {FOREVER}, + {ERAS}, + {MILLENNIA}, + {CENTURIES}, + {DECADES}, + {YEARS}, + {MONTHS}, + {WEEKS}, + {DAYS}, + + {HALF_DAYS}, + {HOURS}, + {MINUTES}, + {SECONDS}, + {MICROS}, + {MILLIS}, + {NANOS}, + + }; + } + + @Test(dataProvider = "chronoUnit") + public void test_unitType(ChronoUnit unit) throws IOException, ClassNotFoundException { + assertSerializableSame(unit); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/temporal/serial/TCKJulianFieldsSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/temporal/serial/TCKJulianFieldsSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.temporal.serial; + +import java.io.IOException; +import java.time.temporal.JulianFields; +import java.time.temporal.TemporalField; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import tck.java.time.AbstractTCKTest; + +/** + * Test serialization of JulianFields + */ +@Test +public class TCKJulianFieldsSerialization extends AbstractTCKTest { + + //----------------------------------------------------------------------- + @DataProvider(name="julian_fields") + Object[][] julian_samples() { + return new Object[][] { + {JulianFields.JULIAN_DAY}, + {JulianFields.MODIFIED_JULIAN_DAY}, + {JulianFields.RATA_DIE}, + }; + } + + + //----------------------------------------------------------------------- + @Test(dataProvider="julian_fields") + public void test_serializable(TemporalField field) throws IOException, ClassNotFoundException { + assertSerializable(field); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/temporal/serial/TCKValueRangeSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/temporal/serial/TCKValueRangeSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.temporal.serial; + +import static org.testng.Assert.assertEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.time.temporal.ValueRange; + +import org.testng.annotations.Test; + +import tck.java.time.AbstractTCKTest; + +/** + * Test serialization of ValueRange. + */ +@Test +public class TCKValueRangeSerialization extends AbstractTCKTest { + + //----------------------------------------------------------------------- + // Serialization + //----------------------------------------------------------------------- + public void test_serialization() throws Exception { + ValueRange range = ValueRange.of(1, 2, 3, 4); + assertSerializable(range); + } + + + /** + * Verify Serialized bytes of a ValueRange. + * @throws IOException if thrown during serialization is an unexpected test tailure + */ + public void test_valueRangeSerialized() throws IOException { + byte[] expected = { + (byte)172, (byte)237, 0, 5, 115, 114, 0, 29, 106, 97, /* \u00ac \u00ed \u0000 \u0005 s r \u0000 \u001d j a */ + 118, 97, 46, 116, 105, 109, 101, 46, 116, 101, /* v a . t i m e . t e */ + 109, 112, 111, 114, 97, 108, 46, 86, 97, 108, /* m p o r a l . V a l */ + 117, 101, 82, 97, 110, 103, 101, (byte)154, 113, (byte)169, /* u e R a n g e \u009a q \u00a9 */ + 86, (byte)242, (byte)205, 90, (byte)184, 2, 0, 4, 74, 0, /* V \u00f2 \u00cd Z \u00b8 \u0002 \u0000 \u0004 J \u0000 */ + 10, 109, 97, 120, 76, 97, 114, 103, 101, 115, /* m a x L a r g e s */ + 116, 74, 0, 11, 109, 97, 120, 83, 109, 97, /* t J \u0000 \u000b m a x S m a */ + 108, 108, 101, 115, 116, 74, 0, 10, 109, 105,/* l l e s t J \u0000 m i */ + 110, 76, 97, 114, 103, 101, 115, 116, 74, 0, /* n L a r g e s t J \u0000 */ + 11, 109, 105, 110, 83, 109, 97, 108, 108, 101, /* \u000b m i n S m a l l e */ + 115, 116, 120, 112, 0, 0, 0, 0, 0, 0, /* s t x p \u0000 \u0000 \u0000 \u0000 \u0000 \u0000 */ + 0, 40, 0, 0, 0, 0, 0, 0, 0, 30, /* \u0000 ( \u0000 \u0000 \u0000 \u0000 \u0000 \u0000 \u0000 \u001e */ + 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, /* \u0000 \u0000 \u0000 \u0000 \u0000 \u0000 \u0000 \u0014 \u0000 \u0000 */ + 0, 0, 0, 0, 0, 10, /* \u0000 \u0000 \u0000 \u0000 \u0000 */ + }; + + ValueRange range = ValueRange.of(10, 20, 30, 40); + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos) ) { + oos.writeObject(range); + + byte[] actual = baos.toByteArray(); + assertEquals(actual, expected, "Serialized bytes incorrect"); + } + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/temporal/serial/TCKWeekFieldsSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/temporal/serial/TCKWeekFieldsSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2012, 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. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.temporal.serial; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.io.IOException; +import java.time.DayOfWeek; +import java.time.temporal.WeekFields; + +/** + * Test serialization of WeekFields. + */ +@Test +public class TCKWeekFieldsSerialization extends AbstractTCKTest { + + //----------------------------------------------------------------------- + @Test(dataProvider="weekFields") + public void test_serializable_singleton(DayOfWeek firstDayOfWeek, int minDays) throws IOException, ClassNotFoundException { + WeekFields weekDef = WeekFields.of(firstDayOfWeek, minDays); + assertSerializableSame(weekDef); // spec state singleton + } + + //----------------------------------------------------------------------- + @DataProvider(name="weekFields") + Object[][] data_weekFields() { + Object[][] objects = new Object[49][]; + int i = 0; + for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) { + for (int minDays = 1; minDays <= 7; minDays++) { + objects[i++] = new Object[] {firstDayOfWeek, minDays}; + } + } + return objects; + } + + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/zone/TCKFixedZoneRules.java --- a/jdk/test/java/time/tck/java/time/zone/TCKFixedZoneRules.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/zone/TCKFixedZoneRules.java Tue Oct 08 14:57:32 2013 -0700 @@ -107,25 +107,7 @@ //----------------------------------------------------------------------- // Basics //----------------------------------------------------------------------- - @Test(dataProvider="rules") - public void test_serialization(ZoneRules test, ZoneOffset expectedOffset) throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(test); - baos.close(); - byte[] bytes = baos.toByteArray(); - ByteArrayInputStream bais = new ByteArrayInputStream(bytes); - ObjectInputStream in = new ObjectInputStream(bais); - ZoneRules result = (ZoneRules) in.readObject(); - - assertEquals(result, test); - assertEquals(result.getClass(), test.getClass()); - } - - //----------------------------------------------------------------------- - // basics - //----------------------------------------------------------------------- @Test(dataProvider="rules") public void test_getOffset_Instant(ZoneRules test, ZoneOffset expectedOffset) { assertEquals(test.getOffset(INSTANT), expectedOffset); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransition.java --- a/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransition.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransition.java Tue Oct 08 14:57:32 2013 -0700 @@ -127,7 +127,6 @@ assertEquals(test.getOffsetBefore(), OFFSET_0200); assertEquals(test.getOffsetAfter(), OFFSET_0300); assertEquals(test.getDuration(), Duration.of(1, HOURS)); - assertSerializable(test); } @Test @@ -143,23 +142,8 @@ assertEquals(test.getOffsetBefore(), OFFSET_0300); assertEquals(test.getOffsetAfter(), OFFSET_0200); assertEquals(test.getDuration(), Duration.of(-1, HOURS)); - assertSerializable(test); } - //----------------------------------------------------------------------- - @Test - public void test_serialization_unusual1() throws Exception { - LocalDateTime ldt = LocalDateTime.of(Year.MAX_VALUE, 12, 31, 1, 31, 53); - ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, ZoneOffset.of("+02:04:56"), ZoneOffset.of("-10:02:34")); - assertSerializable(test); - } - - @Test - public void test_serialization_unusual2() throws Exception { - LocalDateTime ldt = LocalDateTime.of(Year.MIN_VALUE, 1, 1, 12, 1, 3); - ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, ZoneOffset.of("+02:04:56"), ZoneOffset.of("+10:02:34")); - assertSerializable(test); - } //----------------------------------------------------------------------- // isValidOffset() diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java --- a/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java Tue Oct 08 14:57:32 2013 -0700 @@ -173,7 +173,6 @@ assertEquals(test.getStandardOffset(), OFFSET_0200); assertEquals(test.getOffsetBefore(), OFFSET_0200); assertEquals(test.getOffsetAfter(), OFFSET_0300); - assertSerializable(test); } @Test @@ -190,7 +189,6 @@ assertEquals(test.getStandardOffset(), OFFSET_0200); assertEquals(test.getOffsetBefore(), OFFSET_0200); assertEquals(test.getOffsetAfter(), OFFSET_0300); - assertSerializable(test); } @Test @@ -207,34 +205,8 @@ assertEquals(test.getStandardOffset(), OFFSET_0200); assertEquals(test.getOffsetBefore(), OFFSET_0200); assertEquals(test.getOffsetAfter(), OFFSET_0300); - assertSerializable(test); - } - - @Test - public void test_serialization_unusualOffsets() throws Exception { - ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( - Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.STANDARD, - ZoneOffset.ofHoursMinutesSeconds(-12, -20, -50), - ZoneOffset.ofHoursMinutesSeconds(-4, -10, -34), - ZoneOffset.ofHours(-18)); - assertSerializable(test); } - @Test - public void test_serialization_endOfDay() throws Exception { - ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( - Month.MARCH, 20, DayOfWeek.FRIDAY, LocalTime.MIDNIGHT, true, TimeDefinition.UTC, - OFFSET_0200, OFFSET_0200, OFFSET_0300); - assertSerializable(test); - } - - @Test - public void test_serialization_unusualTime() throws Exception { - ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( - Month.MARCH, 20, DayOfWeek.WEDNESDAY, LocalTime.of(13, 34, 56), false, TimeDefinition.STANDARD, - OFFSET_0200, OFFSET_0200, OFFSET_0300); - assertSerializable(test); - } //----------------------------------------------------------------------- // createTransition() diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java --- a/jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java Tue Oct 08 14:57:32 2013 -0700 @@ -103,28 +103,7 @@ private static final int OVERLAP = 2; private static final int GAP = 0; - //----------------------------------------------------------------------- - // Basics - //----------------------------------------------------------------------- - public void test_serialization_loaded() throws Exception { - assertSerialization(europeLondon()); - assertSerialization(europeParis()); - assertSerialization(americaNewYork()); - } - private void assertSerialization(ZoneRules test) throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(test); - baos.close(); - byte[] bytes = baos.toByteArray(); - - ByteArrayInputStream bais = new ByteArrayInputStream(bytes); - ObjectInputStream in = new ObjectInputStream(bais); - ZoneRules result = (ZoneRules) in.readObject(); - - assertEquals(result, test); - } //----------------------------------------------------------------------- // Europe/London diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/zone/serial/TCKFixedZoneRulesSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/zone/serial/TCKFixedZoneRulesSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.zone.serial; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.time.ZoneOffset; +import java.time.zone.ZoneRules; + +import static org.testng.Assert.assertEquals; + +/** + * Test serialization of ZoneRules for fixed offset time-zones. + */ +@Test +public class TCKFixedZoneRulesSerialization { + + private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); + private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2); + private static final ZoneOffset OFFSET_M18 = ZoneOffset.ofHours(-18); + + private ZoneRules make(ZoneOffset offset) { + return offset.getRules(); + } + + @DataProvider(name="rules") + Object[][] data_rules() { + return new Object[][] { + {make(OFFSET_PONE), OFFSET_PONE}, + {make(OFFSET_PTWO), OFFSET_PTWO}, + {make(OFFSET_M18), OFFSET_M18}, + }; + } + + //----------------------------------------------------------------------- + // Basics + //----------------------------------------------------------------------- + @Test(dataProvider="rules") + public void test_serialization(ZoneRules test, ZoneOffset expectedOffset) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(baos); + out.writeObject(test); + baos.close(); + byte[] bytes = baos.toByteArray(); + + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + ObjectInputStream in = new ObjectInputStream(bais); + ZoneRules result = (ZoneRules) in.readObject(); + + assertEquals(result, test); + assertEquals(result.getClass(), test.getClass()); + } + + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/zone/serial/TCKZoneOffsetTransitionRuleSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/zone/serial/TCKZoneOffsetTransitionRuleSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.zone.serial; + +import java.time.DayOfWeek; +import java.time.LocalTime; +import java.time.Month; +import java.time.ZoneOffset; +import java.time.zone.ZoneOffsetTransitionRule; +import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition; + +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +/** + * Test ZoneOffsetTransitionRule serialization. + */ +@Test +public class TCKZoneOffsetTransitionRuleSerialization extends AbstractTCKTest { + + private static final LocalTime TIME_0100 = LocalTime.of(1, 0); + private static final ZoneOffset OFFSET_0200 = ZoneOffset.ofHours(2); + private static final ZoneOffset OFFSET_0300 = ZoneOffset.ofHours(3); + + + //----------------------------------------------------------------------- + // Test serialization + //----------------------------------------------------------------------- + @Test + public void test_serialization_unusualOffsets() throws Exception { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.STANDARD, + ZoneOffset.ofHoursMinutesSeconds(-12, -20, -50), + ZoneOffset.ofHoursMinutesSeconds(-4, -10, -34), + ZoneOffset.ofHours(-18)); + assertSerializable(test); + } + + @Test + public void test_serialization_endOfDay() throws Exception { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.FRIDAY, LocalTime.MIDNIGHT, true, TimeDefinition.UTC, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertSerializable(test); + } + + @Test + public void test_serialization_unusualTime() throws Exception { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.WEDNESDAY, LocalTime.of(13, 34, 56), false, TimeDefinition.STANDARD, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertSerializable(test); + } + + @Test + public void test_serialization_floatingWeek() throws Exception { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertSerializable(test); + } + + @Test + public void test_serialization_floatingWeekBackwards() throws Exception { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, -1, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertSerializable(test); + } + + @Test + public void test_serialization_fixedDate() throws Exception { + ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of( + Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.WALL, + OFFSET_0200, OFFSET_0200, OFFSET_0300); + assertSerializable(test); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/zone/serial/TCKZoneOffsetTransitionSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/zone/serial/TCKZoneOffsetTransitionSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.zone.serial; + +import static java.time.temporal.ChronoUnit.HOURS; + +import java.time.Duration; +import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; + +import java.time.LocalDateTime; +import java.time.Year; +import java.time.ZoneOffset; +import java.time.zone.ZoneOffsetTransition; + +/** + * Test serialization of ZoneOffsetTransition. + */ +@Test +public class TCKZoneOffsetTransitionSerialization extends AbstractTCKTest { + + private static final ZoneOffset OFFSET_0200 = ZoneOffset.ofHours(2); + private static final ZoneOffset OFFSET_0300 = ZoneOffset.ofHours(3); + + //----------------------------------------------------------------------- + @Test + public void test_serialization_unusual1() throws Exception { + LocalDateTime ldt = LocalDateTime.of(Year.MAX_VALUE, 12, 31, 1, 31, 53); + ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, ZoneOffset.of("+02:04:56"), ZoneOffset.of("-10:02:34")); + assertSerializable(test); + } + + @Test + public void test_serialization_unusual2() throws Exception { + LocalDateTime ldt = LocalDateTime.of(Year.MIN_VALUE, 1, 1, 12, 1, 3); + ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, ZoneOffset.of("+02:04:56"), ZoneOffset.of("+10:02:34")); + assertSerializable(test); + } + + @Test + public void test_serialization_gap() throws Exception { + LocalDateTime before = LocalDateTime.of(2010, 3, 31, 1, 0); + LocalDateTime after = LocalDateTime.of(2010, 3, 31, 2, 0); + ZoneOffsetTransition test = ZoneOffsetTransition.of(before, OFFSET_0200, OFFSET_0300); + assertSerializable(test); + } + + @Test + public void test_serialization_overlap() throws Exception { + LocalDateTime before = LocalDateTime.of(2010, 10, 31, 1, 0); + LocalDateTime after = LocalDateTime.of(2010, 10, 31, 0, 0); + ZoneOffsetTransition test = ZoneOffsetTransition.of(before, OFFSET_0300, OFFSET_0200); + assertSerializable(test); + } + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/tck/java/time/zone/serial/TCKZoneRulesSerialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/tck/java/time/zone/serial/TCKZoneRulesSerialization.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.zone.serial; + +import org.testng.annotations.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.time.ZoneId; +import java.time.zone.ZoneRules; + +import static org.testng.Assert.assertEquals; + +/** + * Test serialization of ZoneRules. + */ +@Test +public class TCKZoneRulesSerialization { + + public void test_serialization_loaded() throws Exception { + assertSerialization(europeLondon()); + assertSerialization(europeParis()); + assertSerialization(americaNewYork()); + } + + private void assertSerialization(ZoneRules test) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(baos); + out.writeObject(test); + baos.close(); + byte[] bytes = baos.toByteArray(); + + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + ObjectInputStream in = new ObjectInputStream(bais); + ZoneRules result = (ZoneRules) in.readObject(); + + assertEquals(result, test); + } + + //----------------------------------------------------------------------- + // Europe/London + //----------------------------------------------------------------------- + private ZoneRules europeLondon() { + return ZoneId.of("Europe/London").getRules(); + } + + + //----------------------------------------------------------------------- + // Europe/Paris + //----------------------------------------------------------------------- + private ZoneRules europeParis() { + return ZoneId.of("Europe/Paris").getRules(); + } + + //----------------------------------------------------------------------- + // America/New_York + //----------------------------------------------------------------------- + private ZoneRules americaNewYork() { + return ZoneId.of("America/New_York").getRules(); + } + + +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/test/java/time/AbstractTest.java --- a/jdk/test/java/time/test/java/time/AbstractTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/test/java/time/AbstractTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -63,11 +63,6 @@ import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -87,27 +82,6 @@ return true; } - protected static void assertSerializable(Object o) throws IOException, ClassNotFoundException { - Object deserialisedObject = writeThenRead(o); - assertEquals(deserialisedObject, o); - } - - protected static void assertSerializableAndSame(Object o) throws IOException, ClassNotFoundException { - Object deserialisedObject = writeThenRead(o); - assertSame(deserialisedObject, o); - } - - private static Object writeThenRead(Object o) throws IOException, ClassNotFoundException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (ObjectOutputStream oos = new ObjectOutputStream(baos) ) { - oos.writeObject(o); - } - - try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { - return ois.readObject(); - } - } - protected static void assertImmutable(Class cls) { assertTrue(Modifier.isPublic(cls.getModifiers())); assertTrue(Modifier.isFinal(cls.getModifiers())); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/test/java/time/TestDuration.java --- a/jdk/test/java/time/test/java/time/TestDuration.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/test/java/time/TestDuration.java Tue Oct 08 14:57:32 2013 -0700 @@ -63,11 +63,6 @@ import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; import java.time.Duration; import org.testng.annotations.Test; @@ -84,29 +79,6 @@ assertImmutable(Duration.class); } - //----------------------------------------------------------------------- - @Test - public void test_interfaces() { - assertTrue(Serializable.class.isAssignableFrom(Duration.class)); - assertTrue(Comparable.class.isAssignableFrom(Duration.class)); - } - - //----------------------------------------------------------------------- - // serialization - //----------------------------------------------------------------------- - @Test - public void test_deserializationSingleton() throws Exception { - Duration orginal = Duration.ZERO; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(baos); - out.writeObject(orginal); - out.close(); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - Duration ser = (Duration) in.readObject(); - assertSame(ser, Duration.ZERO); - } - @Test public void plus_zeroReturnsThis() { Duration t = Duration.ofSeconds(-1); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java --- a/jdk/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java Tue Oct 08 14:57:32 2013 -0700 @@ -26,9 +26,9 @@ package test.java.time.chrono; import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.YEAR; -import static java.time.temporal.ChronoField.DAY_OF_YEAR; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; @@ -39,12 +39,12 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.time.OffsetDateTime; -import java.time.Period; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.chrono.ChronoLocalDate; import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.ChronoPeriod; import java.time.chrono.ChronoZonedDateTime; import java.time.chrono.Chronology; import java.time.chrono.HijrahChronology; @@ -330,26 +330,26 @@ @DataProvider(name="datesForPeriod") Object[][] data_Period() { return new Object[][] { - {HijrahDate.of(1350, 5, 15), HijrahDate.of(1434, 7, 20), Period.of(84, 2, 5)}, - {HijrahDate.of(1403, 5, 28), HijrahDate.of(1434, 7, 20), Period.of(31, 1, 22)}, - {HijrahDate.of(1434, 7, 20), HijrahDate.of(1484, 2, 15), Period.of(49, 6, 24)}, - {HijrahDate.of(1500, 6, 12), HijrahDate.of(1450, 4, 21), Period.of(-50, -1, -20)}, - {HijrahDate.of(1549, 3, 11), HijrahDate.of(1550, 3, 10), Period.of(0, 11, 28)}, + {HijrahDate.of(1350, 5, 15), HijrahDate.of(1434, 7, 20), HijrahChronology.INSTANCE.period(84, 2, 5)}, + {HijrahDate.of(1403, 5, 28), HijrahDate.of(1434, 7, 20), HijrahChronology.INSTANCE.period(31, 1, 22)}, + {HijrahDate.of(1434, 7, 20), HijrahDate.of(1484, 2, 15), HijrahChronology.INSTANCE.period(49, 6, 24)}, + {HijrahDate.of(1500, 6, 12), HijrahDate.of(1450, 4, 21), HijrahChronology.INSTANCE.period(-50, -1, -20)}, + {HijrahDate.of(1549, 3, 11), HijrahDate.of(1550, 3, 10), HijrahChronology.INSTANCE.period(0, 11, 28)}, }; } // Test to get the Period between two given dates @Test(dataProvider="datesForPeriod") - public void test_until(HijrahDate h1, HijrahDate h2, Period p) { - Period period = h1.until(h2); + public void test_until(HijrahDate h1, HijrahDate h2, ChronoPeriod p) { + ChronoPeriod period = h1.until(h2); assertEquals(period, p); } // Test to get the Period between dates in different chronologies @Test(dataProvider="datesForPeriod") - public void test_periodUntilDiffChrono(HijrahDate h1, HijrahDate h2, Period p) { + public void test_periodUntilDiffChrono(HijrahDate h1, HijrahDate h2, ChronoPeriod p) { MinguoDate m = MinguoChronology.INSTANCE.date(h2); - Period period = h1.until(m); + ChronoPeriod period = h1.until(m); assertEquals(period, p); } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/time/test/java/time/temporal/TestDateTimeValueRange.java --- a/jdk/test/java/time/test/java/time/temporal/TestDateTimeValueRange.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/time/test/java/time/temporal/TestDateTimeValueRange.java Tue Oct 08 14:57:32 2013 -0700 @@ -88,19 +88,6 @@ } //----------------------------------------------------------------------- - // Serialization - //----------------------------------------------------------------------- - public void test_serialization() throws Exception { - Object obj = ValueRange.of(1, 2, 3, 4); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(obj); - oos.close(); - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())); - assertEquals(ois.readObject(), obj); - } - - //----------------------------------------------------------------------- // of(long,long) //----------------------------------------------------------------------- public void test_of_longlong() { diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/util/Arrays/ParallelPrefix.java --- a/jdk/test/java/util/Arrays/ParallelPrefix.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/util/Arrays/ParallelPrefix.java Tue Oct 08 14:57:32 2013 -0700 @@ -22,7 +22,7 @@ */ /** - * @test + * @test 8014076 8025067 * @summary unit test for Arrays.ParallelPrefix(). * @author Tristan Yan * @run testng ParallelPrefix @@ -54,30 +54,44 @@ private final static int LARGE_ARRAY_SIZE = 1 << 12; private final static int[] ARRAY_SIZE_COLLECTION = new int[]{ - SMALL_ARRAY_SIZE, THRESHOLD_ARRAY_SIZE,MEDIUM_ARRAY_SIZE, LARGE_ARRAY_SIZE}; + SMALL_ARRAY_SIZE, + THRESHOLD_ARRAY_SIZE, + MEDIUM_ARRAY_SIZE, + LARGE_ARRAY_SIZE + }; @DataProvider public static Object[][] intSet(){ - return genericData(size -> IntStream.range(0, size).toArray(), new IntBinaryOperator[]{Integer::sum, Integer::min}); + return genericData(size -> IntStream.range(0, size).toArray(), + new IntBinaryOperator[]{ + Integer::sum, + Integer::min}); } @DataProvider public static Object[][] longSet(){ - return genericData(size -> LongStream.range(0, size).toArray(), new LongBinaryOperator[]{Long::sum, Long::min}); + return genericData(size -> LongStream.range(0, size).toArray(), + new LongBinaryOperator[]{ + Long::sum, + Long::min}); } @DataProvider public static Object[][] doubleSet(){ return genericData(size -> IntStream.range(0, size).mapToDouble(i -> (double)i).toArray(), - new DoubleBinaryOperator[]{Double::sum, Double::min}); + new DoubleBinaryOperator[]{ + Double::sum, + Double::min}); } @DataProvider public static Object[][] stringSet(){ Function stringsFunc = size -> IntStream.range(0, size).mapToObj(Integer::toString).toArray(String[]::new); - BinaryOperator cancatBop = String::concat; - return genericData(stringsFunc, new BinaryOperator[]{cancatBop}); + BinaryOperator concat = String::concat; + return genericData(stringsFunc, + (BinaryOperator[]) new BinaryOperator[]{ + concat }); } private static Object[][] genericData(Function generateFunc, OPS[] ops) { @@ -161,5 +175,123 @@ Arrays.parallelPrefix(parallelRangeResult, op); assertEquals(parallelRangeResult, Arrays.copyOfRange(sequentialResult, fromIndex, toIndex)); } + + @Test + public void testNPEs() { + // null array + assertThrows( () -> Arrays.parallelPrefix((int[]) null, Integer::max), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix((long []) null, Long::max), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix((double []) null, Double::max), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix((String []) null, String::concat), + NullPointerException.class, "should throw NPE"); + + // null array w/ range + assertThrows( () -> Arrays.parallelPrefix((int[]) null, 0, 0, Integer::max), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix((long []) null, 0, 0, Long::max), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix((double []) null, 0, 0, Double::max), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix((String []) null, 0, 0, String::concat), + NullPointerException.class, "should throw NPE"); + + // null op + assertThrows( () -> Arrays.parallelPrefix(new int[] {}, null), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix(new long[] {}, null), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix(new double[] {}, null), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix(new String[] {}, null), + NullPointerException.class, "should throw NPE"); + + // null op w/ range + assertThrows( () -> Arrays.parallelPrefix(new int[] {}, 0, 0, null), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix(new long[] {}, 0, 0, null), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix(new double[] {}, 0, 0, null), + NullPointerException.class, "should throw NPE"); + assertThrows( () -> Arrays.parallelPrefix(new String[] {}, 0, 0, null), + NullPointerException.class, "should throw NPE"); + } + + @Test + public void testIAEs() { + assertThrows( () -> Arrays.parallelPrefix(new int[] {}, 1, 0, Integer::max), + IllegalArgumentException.class, "should throw IAE"); + assertThrows( () -> Arrays.parallelPrefix(new long[] {}, 1, 0, Long::max), + IllegalArgumentException.class, "should throw IAE"); + assertThrows( () -> Arrays.parallelPrefix(new double[] {}, 1, 0, Double::max), + IllegalArgumentException.class, "should throw IAE"); + assertThrows( () -> Arrays.parallelPrefix(new String[] {}, 1, 0, String::concat), + IllegalArgumentException.class, "should throw IAE"); + } + + @Test + public void testAIOBEs() { + // bad "fromIndex" + assertThrows( () -> Arrays.parallelPrefix(new int[] {}, -1, 0, Integer::max), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + assertThrows( () -> Arrays.parallelPrefix(new long[] {}, -1, 0, Long::max), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + assertThrows( () -> Arrays.parallelPrefix(new double[] {}, -1, 0, Double::max), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + assertThrows( () -> Arrays.parallelPrefix(new String[] {}, -1, 0, String::concat), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + + // bad "toIndex" + assertThrows( () -> Arrays.parallelPrefix(new int[] {}, 0, 1, Integer::max), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + assertThrows( () -> Arrays.parallelPrefix(new long[] {}, 0, 1, Long::max), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + assertThrows( () -> Arrays.parallelPrefix(new double[] {}, 0, 1, Double::max), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + assertThrows( () -> Arrays.parallelPrefix(new String[] {}, 0, 1, String::concat), + ArrayIndexOutOfBoundsException.class, "should throw AIOBE"); + } + + // "library" code + + public interface Thrower { + + public void run() throws T; + } + + + public static void assertThrows(Thrower thrower, Class throwable) { + assertThrows(thrower, throwable, null); + } + + public static void assertThrows(Thrower thrower, Class throwable, String message) { + Throwable thrown; + try { + thrower.run(); + thrown = null; + } catch (Throwable caught) { + thrown = caught; + } + + assertInstance(thrown, throwable, + ((null != message) ? message : "") + + " Failed to throw " + throwable.getCanonicalName()); + } + + public static void assertThrows(Class throwable, String message, Thrower... throwers) { + for(Thrower thrower : throwers) { + assertThrows(thrower, throwable, message); + } + } + + public static void assertInstance(Object actual, Class expected) { + assertInstance(expected.isInstance(actual), null); + } + + public static void assertInstance(Object actual, Class expected, String message) { + assertTrue(expected.isInstance(actual), message); + } } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/util/Calendar/Bug6902861.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/Calendar/Bug6902861.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 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. + * + * 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 6902861 + * @summary Test for a workaround when WEEK_OF_YEAR and YEAR are out of sync. + */ + +import java.util.*; +import static java.util.GregorianCalendar.*; + +public class Bug6902861 { + static int errors = 0; + + public static void main(String [] args) { + Locale loc = Locale.getDefault(); + try { + Locale.setDefault(Locale.GERMANY); + test(2010, JANUARY, 1, +1, 1); + test(2010, JANUARY, 1, +2, 2); + test(2010, JANUARY, 1, -1, 52); + test(2010, JANUARY, 1, -2, 51); + test(2008, DECEMBER, 31, +1, 1); + test(2008, DECEMBER, 31, +2, 2); + test(2008, DECEMBER, 31, -1, 52); + test(2008, DECEMBER, 31, -2, 51); + if (errors > 0) { + throw new RuntimeException("Failed"); + } + } finally { + Locale.setDefault(loc); + } + } + + static void test(int year, int month, int dayOfMonth, int amount, int expected) { + Calendar calendar = new GregorianCalendar(year, month, dayOfMonth); + int week = calendar.get(WEEK_OF_YEAR); // fix the date + calendar.roll(WEEK_OF_YEAR, amount); + int got = calendar.get(WEEK_OF_YEAR); + int y = calendar.get(YEAR); + if (got != expected || y != year) { + String date = String.format("%04d-%02d-%02d", year, month+1, dayOfMonth); + System.err.printf("%s: roll %+d: got: %d,%2d; expected: %d,%2d%n", + date, amount, y, got, year, expected); + errors++; + } + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/util/Collection/MOAT.java --- a/jdk/test/java/util/Collection/MOAT.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/util/Collection/MOAT.java Tue Oct 08 14:57:32 2013 -0700 @@ -207,8 +207,8 @@ new Fun(){void f(){ it.next(); }}); try { it.remove(); } - catch (IllegalStateException _) { pass(); } - catch (UnsupportedOperationException _) { pass(); } + catch (IllegalStateException ignored) { pass(); } + catch (UnsupportedOperationException ignored) { pass(); } catch (Throwable t) { unexpected(t); } if (rnd.nextBoolean()) @@ -280,9 +280,9 @@ testEmptyCollection(m.values()); try { check(! m.containsValue(null)); } - catch (NullPointerException _) { /* OK */ } + catch (NullPointerException ignored) { /* OK */ } try { check(! m.containsKey(null)); } - catch (NullPointerException _) { /* OK */ } + catch (NullPointerException ignored) { /* OK */ } check(! m.containsValue(1)); check(! m.containsKey(1)); } @@ -710,8 +710,8 @@ l.addAll(-1, Collections.emptyList()); fail("Expected IndexOutOfBoundsException not thrown"); } - catch (UnsupportedOperationException _) {/* OK */} - catch (IndexOutOfBoundsException _) {/* OK */} + catch (UnsupportedOperationException ignored) {/* OK */} + catch (IndexOutOfBoundsException ignored) {/* OK */} catch (Throwable t) { unexpected(t); } // equal(l instanceof Serializable, diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java --- a/jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java Tue Oct 08 14:57:32 2013 -0700 @@ -23,7 +23,7 @@ /** * @test - * @bug 8020156 8020009 8022326 8012913 8024405 + * @bug 8020156 8020009 8022326 8012913 8024405 8024408 * @run testng SpliteratorCharacteristics */ @@ -46,6 +46,7 @@ import java.util.Spliterators; import java.util.TreeMap; import java.util.TreeSet; +import java.util.WeakHashMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.ConcurrentSkipListSet; import java.util.function.Supplier; @@ -185,6 +186,11 @@ Spliterator.SIZED | Spliterator.DISTINCT); } + public void testWeakHashMap() { + assertMapCharacteristics(new WeakHashMap<>(), + Spliterator.DISTINCT); + } + public void testHashSet() { assertSetCharacteristics(new HashSet<>(), Spliterator.SIZED | Spliterator.DISTINCT); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/util/TreeMap/Clone.java --- a/jdk/test/java/util/TreeMap/Clone.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/util/TreeMap/Clone.java Tue Oct 08 14:57:32 2013 -0700 @@ -27,7 +27,6 @@ * @summary Verify that cloned TreeMap gets new keyset * @author david.buck@oracle.com * @run main/othervm Clone - * @run main/othervm -XX:+AggressiveOpts Clone */ import java.util.TreeMap; diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/util/stream/bootlib/java/util/stream/OpTestCase.java --- a/jdk/test/java/util/stream/bootlib/java/util/stream/OpTestCase.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/util/stream/bootlib/java/util/stream/OpTestCase.java Tue Oct 08 14:57:32 2013 -0700 @@ -30,7 +30,6 @@ import java.util.Collections; import java.util.EnumMap; import java.util.EnumSet; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -41,7 +40,6 @@ import java.util.function.Consumer; import java.util.function.Function; -import org.testng.Assert; import org.testng.annotations.Test; /** @@ -397,14 +395,68 @@ // Exercise terminal operations - static enum TerminalTestScenario { - SINGLE_SEQUENTIAL, - SINGLE_SEQUENTIAL_SHORT_CIRCUIT, - SINGLE_PARALLEL, - ALL_SEQUENTIAL, - ALL_SEQUENTIAL_SHORT_CIRCUIT, - ALL_PARALLEL, - ALL_PARALLEL_SEQUENTIAL, + interface BaseTerminalTestScenario> { + boolean requiresSingleStageSource(); + + boolean requiresParallelSource(); + + default R run(Function terminalF, S_OUT source, StreamShape shape) { + return terminalF.apply(source); + } + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + static enum TerminalTestScenario implements BaseTerminalTestScenario { + SINGLE_SEQUENTIAL(true, false), + + SINGLE_SEQUENTIAL_SHORT_CIRCUIT(true, false) { + @Override + public Object run(Function terminalF, BaseStream source, StreamShape shape) { + source = (BaseStream) chain(source, new ShortCircuitOp(shape)); + return terminalF.apply(source); + } + }, + + SINGLE_PARALLEL(true, true), + + ALL_SEQUENTIAL(false, false), + + ALL_SEQUENTIAL_SHORT_CIRCUIT(false, false) { + @Override + public Object run(Function terminalF, BaseStream source, StreamShape shape) { + source = (BaseStream) chain(source, new ShortCircuitOp(shape)); + return terminalF.apply(source); + } + }, + + ALL_PARALLEL(false, true), + + ALL_PARALLEL_SEQUENTIAL(false, false) { + @Override + public Object run(Function terminalF, BaseStream source, StreamShape shape) { + return terminalF.apply(source.sequential()); + } + }, + ; + + private final boolean requiresSingleStageSource; + private final boolean isParallel; + + TerminalTestScenario(boolean requiresSingleStageSource, boolean isParallel) { + this.requiresSingleStageSource = requiresSingleStageSource; + this.isParallel = isParallel; + } + + @Override + public boolean requiresSingleStageSource() { + return requiresSingleStageSource; + } + + @Override + public boolean requiresParallelSource() { + return isParallel; + } + } @SuppressWarnings({"rawtypes", "unchecked"}) @@ -415,8 +467,6 @@ R refResult; - Set testSet = EnumSet.allOf(TerminalTestScenario.class); - ResultAsserter resultAsserter = (act, exp, ord, par) -> LambdaTestHelpers.assertContentsEqual(act, exp); private ExerciseDataTerminalBuilder(TestData data, Function streamF, Function terminalF) { @@ -442,27 +492,6 @@ return this; } - public ExerciseDataTerminalBuilder without(TerminalTestScenario... tests) { - return without(Arrays.asList(tests)); - } - - public ExerciseDataTerminalBuilder without(Collection tests) { - testSet.removeAll(tests); - if (testSet.isEmpty()) { - throw new IllegalStateException("Terminal test scenario set is empty"); - } - return this; - } - - public ExerciseDataTerminalBuilder with(TerminalTestScenario... tests) { - return with(Arrays.asList(tests)); - } - - public ExerciseDataTerminalBuilder with(Collection tests) { - testSet.addAll(tests); - return this; - } - // Build method public R exercise() { @@ -471,70 +500,36 @@ boolean isOrdered = StreamOpFlag.ORDERED.isKnown(ap.getStreamFlags()); StreamShape shape = ap.getOutputShape(); + EnumSet tests = EnumSet.allOf(TerminalTestScenario.class); + // Sequentially collect the output that will be input to the terminal op Node node = ap.evaluateToArrayNode(size -> (U[]) new Object[size]); if (refResult == null) { - // Sequentially collect the output that will be input to the terminal op - refResult = terminalF.apply((S_OUT) createPipeline(shape, node.spliterator(), - StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED, - false)); - } else if (testSet.contains(TerminalTestScenario.SINGLE_SEQUENTIAL)) { - S_OUT source = (S_OUT) createPipeline(shape, node.spliterator(), - StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED, - false); - R result = terminalF.apply(source); - LambdaTestHelpers.launderAssertion(() -> resultAsserter.assertResult(result, refResult, isOrdered, false), - () -> String.format("Single sequential: %s != %s", refResult, result)); - } - - if (testSet.contains(TerminalTestScenario.SINGLE_SEQUENTIAL_SHORT_CIRCUIT)) { + // Induce the reference result S_OUT source = (S_OUT) createPipeline(shape, node.spliterator(), StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED, false); - // Force short-circuit - source = (S_OUT) chain(source, new ShortCircuitOp(shape)); - R result = terminalF.apply(source); - LambdaTestHelpers.launderAssertion(() -> resultAsserter.assertResult(result, refResult, isOrdered, false), - () -> String.format("Single sequential pull: %s != %s", refResult, result)); - } - if (testSet.contains(TerminalTestScenario.SINGLE_PARALLEL)) { - S_OUT source = (S_OUT) createPipeline(shape, node.spliterator(), - StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED, - true); - R result = terminalF.apply(source); - LambdaTestHelpers.launderAssertion(() -> resultAsserter.assertResult(result, refResult, isOrdered, true), - () -> String.format("Single parallel: %s != %s", refResult, result)); + refResult = (R) TerminalTestScenario.SINGLE_SEQUENTIAL.run(terminalF, source, shape); + tests.remove(TerminalTestScenario.SINGLE_SEQUENTIAL); } - if (testSet.contains(TerminalTestScenario.ALL_SEQUENTIAL)) { - // This may forEach or tryAdvance depending on the terminal op implementation - S_OUT source = streamF.apply(data.stream()); - R result = terminalF.apply(source); - LambdaTestHelpers.launderAssertion(() -> resultAsserter.assertResult(result, refResult, isOrdered, false), - () -> String.format("All sequential: %s != %s", refResult, result)); - } + for (BaseTerminalTestScenario test : tests) { + S_OUT source; + if (test.requiresSingleStageSource()) { + source = (S_OUT) createPipeline(shape, node.spliterator(), + StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED, + test.requiresParallelSource()); + } + else { + source = streamF.apply(test.requiresParallelSource() + ? data.parallelStream() : data.stream()); + } - if (testSet.contains(TerminalTestScenario.ALL_SEQUENTIAL_SHORT_CIRCUIT)) { - S_OUT source = streamF.apply(data.stream()); - // Force short-circuit - source = (S_OUT) chain(source, new ShortCircuitOp(shape)); - R result = terminalF.apply(source); - LambdaTestHelpers.launderAssertion(() -> resultAsserter.assertResult(result, refResult, isOrdered, false), - () -> String.format("All sequential pull: %s != %s", refResult, result)); - } + R result = (R) test.run(terminalF, source, shape); - if (testSet.contains(TerminalTestScenario.ALL_PARALLEL)) { - S_OUT source = streamF.apply(data.parallelStream()); - R result = terminalF.apply(source); - LambdaTestHelpers.launderAssertion(() -> resultAsserter.assertResult(result, refResult, isOrdered, true), - () -> String.format("All parallel: %s != %s", refResult, result)); - } - - if (testSet.contains(TerminalTestScenario.ALL_PARALLEL_SEQUENTIAL)) { - S_OUT source = streamF.apply(data.parallelStream()); - R result = terminalF.apply(source.sequential()); - LambdaTestHelpers.launderAssertion(() -> resultAsserter.assertResult(result, refResult, isOrdered, false), - () -> String.format("All parallel then sequential: %s != %s", refResult, result)); + LambdaTestHelpers.launderAssertion( + () -> resultAsserter.assertResult(result, refResult, isOrdered, test.requiresParallelSource()), + () -> String.format("%s: %s != %s", test, refResult, result)); } return refResult; @@ -596,10 +591,10 @@ // Test data - private class ShortCircuitOp implements StatelessTestOp { + static class ShortCircuitOp implements StatelessTestOp { private final StreamShape shape; - private ShortCircuitOp(StreamShape shape) { + ShortCircuitOp(StreamShape shape) { this.shape = shape; } diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ExplodeOpTest.java --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ExplodeOpTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ExplodeOpTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -64,6 +64,9 @@ result = exerciseOps(data, s -> s.flatMap(mfNull)); assertEquals(0, result.size()); + result = exerciseOps(data, s-> s.flatMap(e -> Stream.empty())); + assertEquals(0, result.size()); + exerciseOps(data, s -> s.flatMap(mfLt)); exerciseOps(data, s -> s.flatMap(integerRangeMapper)); exerciseOps(data, s -> s.flatMap((Integer e) -> IntStream.range(0, e).boxed().limit(10))); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ForEachOpTest.java --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ForEachOpTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ForEachOpTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -69,7 +69,7 @@ }; } - @Test + @Test(groups = { "serialization-hostile" }) public void testForEachOrdered() { List input = countTo(10000); TestData.OfRef data = TestData.Factory.ofCollection("[1, 10000]", input); @@ -116,7 +116,7 @@ // - @Test + @Test(groups = { "serialization-hostile" }) public void testIntForEachOrdered() { List input = countTo(10000); TestData.OfInt data = TestData.Factory.ofIntSupplier("[1, 10000]", @@ -164,7 +164,7 @@ // - @Test + @Test(groups = { "serialization-hostile" }) public void testLongForEachOrdered() { List input = countTo(10000); TestData.OfLong data = TestData.Factory.ofLongSupplier("[1, 10000]", @@ -212,7 +212,7 @@ // - @Test + @Test(groups = { "serialization-hostile" }) public void testDoubleForEachOrdered() { List input = countTo(10000); TestData.OfDouble data = TestData.Factory.ofDoubleSupplier("[1, 10000]", diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SliceOpTest.java --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SliceOpTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SliceOpTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -147,7 +147,8 @@ return Math.max(0, dataSize - skip); } - @Test(dataProvider = "StreamTestData", dataProviderClass = StreamTestDataProvider.class) + @Test(dataProvider = "StreamTestData", dataProviderClass = StreamTestDataProvider.class, + groups = { "serialization-hostile" }) public void testSkipOps(String name, TestData.OfRef data) { List skips = sizes(data.size()); @@ -169,7 +170,8 @@ } } - @Test(dataProvider = "StreamTestData", dataProviderClass = StreamTestDataProvider.class) + @Test(dataProvider = "StreamTestData", dataProviderClass = StreamTestDataProvider.class, + groups = { "serialization-hostile" }) public void testSkipLimitOps(String name, TestData.OfRef data) { List skips = sizes(data.size()); List limits = skips; @@ -242,7 +244,8 @@ testSkipLimitOps("testSkipLimitOpsWithNonSplittingSpliterator", data); } - @Test(dataProvider = "StreamTestData", dataProviderClass = StreamTestDataProvider.class) + @Test(dataProvider = "StreamTestData", dataProviderClass = StreamTestDataProvider.class, + groups = { "serialization-hostile" }) public void testLimitOps(String name, TestData.OfRef data) { List limits = sizes(data.size()); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SortedOpTest.java --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SortedOpTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SortedOpTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -26,6 +26,8 @@ import java.util.*; import java.util.Spliterators; +import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.*; import static java.util.stream.LambdaTestHelpers.*; @@ -37,6 +39,69 @@ */ @Test public class SortedOpTest extends OpTestCase { + + public void testRefStreamTooLarge() { + Function> f = s -> + // Clear the SORTED flag + s.mapToObj(i -> i) + .sorted(); + + testStreamTooLarge(f, Stream::findFirst); + } + + public void testIntStreamTooLarge() { + Function f = s -> + // Clear the SORTED flag + s.mapToInt(i -> (int) i) + .sorted(); + + testStreamTooLarge(f, IntStream::findFirst); + } + + public void testLongStreamTooLarge() { + Function f = s -> + // Clear the SORTED flag + s.map(i -> i) + .sorted(); + + testStreamTooLarge(f, LongStream::findFirst); + } + + public void testDoubleStreamTooLarge() { + Function f = s -> + // Clear the SORTED flag + s.mapToDouble(i -> (double) i) + .sorted(); + + testStreamTooLarge(f, DoubleStream::findFirst); + } + + > void testStreamTooLarge(Function s, + Function terminal) { + // Set up conditions for a large input > maximum array size + Supplier input = () -> LongStream.range(0, 1L + Integer.MAX_VALUE); + + // Transformation functions + List> transforms = Arrays.asList( + ls -> ls, + ls -> ls.parallel(), + // Clear the SIZED flag + ls -> ls.limit(Long.MAX_VALUE), + ls -> ls.limit(Long.MAX_VALUE).parallel()); + + for (Function transform : transforms) { + RuntimeException caught = null; + try { + terminal.apply(s.apply(transform.apply(input.get()))); + } catch (RuntimeException e) { + caught = e; + } + assertNotNull(caught, "Expected an instance of exception IllegalArgumentException but no exception thrown"); + assertTrue(caught instanceof IllegalArgumentException, + String.format("Expected an instance of exception IllegalArgumentException but got %s", caught)); + } + } + public void testSorted() { assertCountSum(countTo(0).stream().sorted(), 0, 0); assertCountSum(countTo(10).stream().sorted(), 10, 55); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamBuilderTest.java --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamBuilderTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamBuilderTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -97,7 +97,7 @@ checkISE(() -> sb.build()); } - @Test(dataProvider = "sizes") + @Test(dataProvider = "sizes", groups = { "serialization-hostile" }) public void testStreamBuilder(int size) { testStreamBuilder(size, (s) -> { Stream.Builder sb = Stream.builder(); @@ -159,7 +159,7 @@ checkISE(() -> sb.build()); } - @Test(dataProvider = "sizes") + @Test(dataProvider = "sizes", groups = { "serialization-hostile" }) public void testIntStreamBuilder(int size) { testIntStreamBuilder(size, (s) -> { IntStream.Builder sb = IntStream.builder(); @@ -221,7 +221,7 @@ checkISE(() -> sb.build()); } - @Test(dataProvider = "sizes") + @Test(dataProvider = "sizes", groups = { "serialization-hostile" }) public void testLongStreamBuilder(int size) { testLongStreamBuilder(size, (s) -> { LongStream.Builder sb = LongStream.builder(); @@ -282,7 +282,7 @@ checkISE(() -> sb.build()); } - @Test(dataProvider = "sizes") + @Test(dataProvider = "sizes", groups = { "serialization-hostile" }) public void testDoubleStreamBuilder(int size) { testDoubleStreamBuilder(size, (s) -> { DoubleStream.Builder sb = DoubleStream.builder(); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/TabulatorsTest.java --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/TabulatorsTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/TabulatorsTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -609,7 +609,7 @@ @Test(dataProvider = "StreamTestData", dataProviderClass = StreamTestDataProvider.class) public void testComposeFinisher(String name, TestData.OfRef data) throws ReflectiveOperationException { List asList = exerciseTerminalOps(data, s -> s.collect(toList())); - List asImmutableList = exerciseTerminalOps(data, s -> s.collect(collectingAndThen(toList(), Collections::unmodifiableList))); + List asImmutableList = exerciseTerminalOps(data, s -> s.collect(collectingAndThen(toList(), Collections::unmodifiableList))); assertEquals(asList, asImmutableList); try { asImmutableList.add(0); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ToArrayOpTest.java --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ToArrayOpTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ToArrayOpTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -165,7 +165,8 @@ }; } - @Test(dataProvider = "StreamTestData", dataProviderClass = StreamTestDataProvider.class) + @Test(dataProvider = "StreamTestData", dataProviderClass = StreamTestDataProvider.class, + groups = { "serialization-hostile" }) public void testStatefulOpPermutations(String name, TestData.OfRef data) { for (Function, Stream> f : statefulOpPermutations) { withData(data).terminal(f, s -> s.toArray()) diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/javax/xml/jaxp/parsers/8024707/TestFunc.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/xml/jaxp/parsers/8024707/TestFunc.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 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. + * + * 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 org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * bug 8024707 + */ + +public class TestFunc { + public static Node test( NodeList list ) { + return list.item(0); + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/javax/xml/jaxp/parsers/8024707/XSLT.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/xml/jaxp/parsers/8024707/XSLT.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 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. + * + * 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 8024707 + * @summary Test for XSLT extension function with 1 element sized nodelist + * @compile TestFunc.java XSLT.java + * @run main/othervm XSLT + * @author aleksej.efimov@oracle.com + */ + +import javax.xml.transform.*; +import javax.xml.transform.stream.*; +import java.io.ByteArrayOutputStream; + +public class XSLT { + static final String XMLTOTRANSFORM = "/in.xml"; + static final String XSLTRANSFORMER = "/test.xsl"; + static final String EXPECTEDRESULT = "inp1_1"; + + public static void main(String[] args) throws Exception { + ByteArrayOutputStream resStream = new ByteArrayOutputStream(); + TransformerFactory trf = TransformerFactory.newInstance(); + Transformer tr = trf.newTransformer( new StreamSource(System.getProperty("test.src", ".")+XSLTRANSFORMER)); + tr.transform( new StreamSource(System.getProperty("test.src", ".")+XMLTOTRANSFORM), new StreamResult(resStream)); + System.out.println("Transformation completed. Result:"+resStream.toString()); + if (!resStream.toString().equals(EXPECTEDRESULT)) + throw new RuntimeException("Incorrect transformation result"); + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/javax/xml/jaxp/parsers/8024707/in.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/xml/jaxp/parsers/8024707/in.xml Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,4 @@ + + +inp1_1 + diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/javax/xml/jaxp/parsers/8024707/test.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/xml/jaxp/parsers/8024707/test.xsl Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,10 @@ + + + + + + diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/javax/xml/ws/clientjar/TestService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/xml/ws/clientjar/TestService.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 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. + * + * 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.jws.WebService; + +@WebService(serviceName ="TestService", targetNamespace = "http://test/jaxws/sample/") +public class TestService { + public void foo() { + try { + bar(); + } catch (Exception e) { + throw new AssertionError(e); + } + } + + private void bar() { + // nothing done + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/javax/xml/ws/clientjar/TestWsImport.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/xml/ws/clientjar/TestWsImport.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 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. + * + * 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 8016271 + * @summary wsimport -clientjar does not create portable jar on windows due to hardcoded '\' + * @run main/othervm TestWsImport + */ + +import javax.xml.namespace.QName; +import javax.xml.ws.Endpoint; +import javax.xml.ws.Service; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.BufferedReader; +import java.io.File; +import java.net.InetSocketAddress; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.FileVisitResult; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import static java.nio.file.FileVisitResult.*; +import java.util.Enumeration; +import java.util.jar.JarFile; + +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpServer; + +public class TestWsImport { + + public static void main(String[] args) throws IOException { + + String javaHome = System.getProperty("java.home"); + if (javaHome.endsWith("jre")) { + javaHome = new File(javaHome).getParent(); + } + String wsimport = javaHome + File.separator + "bin" + File.separator + "wsimport"; + if (System.getProperty("os.name").startsWith("Windows")) { + wsimport = wsimport.concat(".exe"); + } + + Endpoint endpoint = Endpoint.create(new TestService()); + HttpServer httpServer = null; + try { + // Manually create HttpServer here using ephemeral address for port + // so as to not end up with attempt to bind to an in-use port + httpServer = HttpServer.create(new InetSocketAddress(0), 0); + HttpContext httpContext = httpServer.createContext("/hello"); + int port = httpServer.getAddress().getPort(); + System.out.println("port = " + port); + httpServer.start(); + endpoint.publish(httpContext); + String address = "http://localhost:" + port + "/hello"; + + Service service = Service.create(new URL(address + "?wsdl"), + new QName("http://test/jaxws/sample/", + "TestService")); + + String[] wsargs = { + wsimport, + "-p", + "wstest", + "-J-Djavax.xml.accessExternalSchema=all", + address + "?wsdl", + "-clientjar", + "wsjar.jar" + }; + ProcessBuilder pb = new ProcessBuilder(wsargs); + pb.redirectErrorStream(true); + Process p = pb.start(); + BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream())); + String s = r.readLine(); + while (s != null) { + System.out.println(s.trim()); + s = r.readLine(); + } + p.waitFor(); + p.destroy(); + + try (JarFile jarFile = new JarFile("wsjar.jar")) { + for (Enumeration em = jarFile.entries(); em.hasMoreElements();) { + String fileName = em.nextElement().toString(); + if (fileName.contains("\\")) { + throw new RuntimeException("\"\\\" character detected in jar file: " + fileName); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e.getMessage()); + } finally { + endpoint.stop(); + if (httpServer != null) { + httpServer.stop(0); + } + Path p = Paths.get("wsjar.jar"); + Files.deleteIfExists(p); + p = Paths.get("wstest"); + if (Files.exists(p)) { + try { + Files.walkFileTree(p, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) throws IOException { + + Files.delete(file); + return CONTINUE; + } + @Override + public FileVisitResult postVisitDirectory(Path dir, + IOException exc) throws IOException { + + if (exc == null) { + Files.delete(dir); + return CONTINUE; + } else { + throw exc; + } + } + }); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } + } + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/jdk/lambda/vm/DefaultMethodsTest.java --- a/jdk/test/jdk/lambda/vm/DefaultMethodsTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/jdk/lambda/vm/DefaultMethodsTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -387,37 +387,6 @@ } /** - * interface I { default int m(T t) { return 99; } } - * Class C implements I { public int m() { return 88; } } - * - * TEST: C c = new C(); c.m() == 88; - * TEST: I i = new C(); i.m() == 88; - */ - public void testSelfFill() { - // This test ensures that a concrete method overrides a default method - // that matches at the language-level, but has a different method - // signature due to erasure. - - // debugTest(); - - DefaultMethod dm = new DefaultMethod( - "int", "m", "return 99;", new MethodParameter("T", "t")); - ConcreteMethod cm = new ConcreteMethod( - "int", "m", "return 88;", AccessFlag.PUBLIC, - new MethodParameter("String", "s")); - - Interface I = new Interface("I", new TypeParameter("T"), dm); - Class C = new Class("C", I.with("String"), cm); - - AbstractMethod pm = new AbstractMethod( - "int", "m", new MethodParameter("T", "t")); - - assertInvokeVirtualEquals(new Integer(88), C, cm, "-1", "\"string\""); - assertInvokeInterfaceEquals( - new Integer(88), C, I.with("String"), pm, "\"string\""); - } - - /** * interface I { default int m() { return 99; } } * class C implements I {} * @@ -470,58 +439,6 @@ compiler.cleanup(); } - /** - * interface I { default int m(T t, V v, W w) { return 99; } } - * interface J extends I { int m(T t, V v, String w); } } - * interface K extends J { int m(T t, String v, String w); } } - * class C implements K { - * public int m(String t, String v, String w) { return 88; } - * } - * - * TEST: I i = new C(); i.m("A","B","C") == 88; - * TEST: J j = new C(); j.m("A","B","C") == 88; - * TEST: K k = new C(); k.m("A","B","C") == 88; - */ - public void testBridges() { - DefaultMethod dm = new DefaultMethod("int", stdMethodName, "return 99;", - new MethodParameter("T", "t"), new MethodParameter("V", "v"), - new MethodParameter("W", "w")); - - AbstractMethod pm0 = new AbstractMethod("int", stdMethodName, - new MethodParameter("T", "t"), new MethodParameter("V", "v"), - new MethodParameter("W", "w")); - - AbstractMethod pm1 = new AbstractMethod("int", stdMethodName, - new MethodParameter("T", "t"), new MethodParameter("V", "v"), - new MethodParameter("String", "w")); - - AbstractMethod pm2 = new AbstractMethod("int", stdMethodName, - new MethodParameter("T", "t"), new MethodParameter("String", "v"), - new MethodParameter("String", "w")); - - ConcreteMethod cm = new ConcreteMethod("int",stdMethodName,"return 88;", - AccessFlag.PUBLIC, - new MethodParameter("String", "t"), - new MethodParameter("String", "v"), - new MethodParameter("String", "w")); - - Interface I = new Interface("I", new TypeParameter("T"), - new TypeParameter("V"), new TypeParameter("W"), dm); - Interface J = new Interface("J", - new TypeParameter("T"), new TypeParameter("V"), - I.with("String", "T", "V"), pm1); - Interface K = new Interface("K", new TypeParameter("T"), - J.with("String", "T"), pm2); - Class C = new Class("C", K.with("String"), cm); - - String[] args = new String[] { "\"A\"", "\"B\"", "\"C\"" }; - assertInvokeInterfaceEquals(new Integer(88), C, - I.with("String", "String", "String"), pm0, args); - assertInvokeInterfaceEquals(new Integer(88), C, - J.with("String", "String"), pm1, args); - assertInvokeInterfaceEquals(new Integer(88), C, - K.with("String"), pm2, args); - } /** * interface J { default int m() { return 88; } } @@ -665,33 +582,6 @@ /** * interface I { default Integer m() { return new Integer(88); } } - * class C { Number m() { return new Integer(99); } } - * class D extends C implements I {} - * class S { Object foo() { return (new D()).m(); } // link sig: ()LInteger; - * TEST: S s = new S(); s.foo() == new Integer(99) - */ - public void testCovarBridge() { - Interface I = new Interface("I", new DefaultMethod( - "Integer", "m", "return new Integer(88);")); - Class C = new Class("C", new ConcreteMethod( - "Number", "m", "return new Integer(99);", AccessFlag.PUBLIC)); - Class D = new Class("D", I, C); - - ConcreteMethod DstubMethod = new ConcreteMethod( - "Integer", "m", "return null;", AccessFlag.PUBLIC); - Class Dstub = new Class("D", DstubMethod); - - ConcreteMethod toCall = new ConcreteMethod( - "Object", "foo", "return (new D()).m();", AccessFlag.PUBLIC); - Class S = new Class("S", D, toCall); - S.addCompilationDependency(Dstub); - S.addCompilationDependency(DstubMethod); - - assertInvokeVirtualEquals(new Integer(99), S, toCall, "null"); - } - - /** - * interface I { default Integer m() { return new Integer(88); } } * class C { int m() { return 99; } } * class D extends C implements I {} * class S { Object foo() { return (new D()).m(); } // link sig: ()LInteger; @@ -737,69 +627,6 @@ assertInvokeVirtualEquals(99, C); } - /** - * interface I { int m(T t, V v, W w); } - * interface J implements I { int m(T t, V v, String w); } - * interface K implements J { - * int m(T t, String v, String w); { return 99; } } - * class C implements K { - * public int m(Object t, Object v, String w) { return 77; } - * } - * TEST C = new C(); ((I)c).m(Object,Object,Object) == 99 - * TEST C = new C(); ((J)c).m(Object,Object,String) == 77 - * TEST C = new C(); ((K)c).m(Object,String,String) == 99 - * - * Test that a erased-signature-matching method does not implement - * non-language-level matching methods - */ - public void testNonConcreteFill() { - AbstractMethod ipm = new AbstractMethod("int", "m", - new MethodParameter("T", "t"), - new MethodParameter("V", "s"), - new MethodParameter("W", "w")); - Interface I = new Interface("I", - new TypeParameter("T"), - new TypeParameter("V"), - new TypeParameter("W"), ipm); - - AbstractMethod jpm = new AbstractMethod("int", "m", - new MethodParameter("T", "t"), - new MethodParameter("V", "s"), - new MethodParameter("String", "w")); - Interface J = new Interface("J", - new TypeParameter("T"), - new TypeParameter("V"), - I.with("T", "V", "String"), jpm); - - AbstractMethod kpm = new AbstractMethod("int", "m", - new MethodParameter("T", "t"), - new MethodParameter("String", "s"), - new MethodParameter("String", "w")); - Interface K = new Interface("K", - new TypeParameter("T"), - J.with("T", "String"), - new DefaultMethod("int", "m", "return 99;", - new MethodParameter("T", "t"), - new MethodParameter("String", "v"), - new MethodParameter("String", "w"))); - - Class C = new Class("C", - K.with("String"), - new ConcreteMethod("int", "m", "return 77;", - AccessFlag.PUBLIC, - new MethodParameter("Object", "t"), - new MethodParameter("Object", "v"), - new MethodParameter("String", "w"))); - - String a = "\"\""; - assertInvokeInterfaceEquals(99, C, - K.with("String"), kpm, a, a, a); - assertInvokeInterfaceEquals(77, C, - J.with("String", "String"), jpm, a, a, a); - assertInvokeInterfaceEquals(99, C, - I.with("String", "String", "String"), ipm, a, a, a); - } - public void testStrictfpDefault() { try { java.lang.Class.forName("vm.StrictfpDefault"); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/sun/management/jdp/JdpTest.sh --- a/jdk/test/sun/management/jdp/JdpTest.sh Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/sun/management/jdp/JdpTest.sh Tue Oct 08 14:57:32 2013 -0700 @@ -84,15 +84,29 @@ ${TESTJAVA}/bin/java -server $* -cp ${_testclasses} ${testappname} >> ${_logname} 2>&1 & _last_pid=$! - npid=`_get_pid` - if [ "${npid}" = "" ] - then - echo "ERROR: Test app not started. Please check machine resources before filing a bug." - if [ "${_jtreg}" = "yes" ] - then - exit 255 - fi - fi +# wait until VM is actually starts. +# please note, if vm doesn't start for some reason +# jtreg kills the test by timeout. Don't file a bug. + cnt=1 + while true + do + npid=`_get_pid` + if [ "${npid}" != "" ] + then + break + fi + if [ "${cnt}" = "10" ] + then + echo "ERROR: Test app not started. Please check machine resources before filing a bug." + if [ "${_jtreg}" = "yes" ] + then + exit 255 + fi + break + fi + cnt=`expr $cnt + 1` + sleep 1 + done } _get_pid(){ diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/sun/security/jgss/spnego/MechTokenMissing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/jgss/spnego/MechTokenMissing.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 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. + * + * 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 8024861 + * @summary Incomplete token triggers GSS-API NullPointerException + */ + +import org.ietf.jgss.GSSContext; +import org.ietf.jgss.GSSCredential; +import org.ietf.jgss.GSSException; +import org.ietf.jgss.GSSManager; + +public class MechTokenMissing { + public static void main(String[] args) throws Exception { + GSSCredential cred = null; + GSSContext ctx = GSSManager.getInstance().createContext(cred); + + String var = + /*0000*/ "60 1C 06 06 2B 06 01 05 05 02 A0 12 30 10 A0 0E " + + /*0010*/ "30 0C 06 0A 2B 06 01 04 01 82 37 02 02 0A "; + byte[] token = new byte[var.length()/3]; + for (int i=0; i 2) { + sniHostname = "test." + server; + sniMatcherPattern = ".*"; } kdc.addPrincipal(OneKDC.USER, OneKDC.PASS); @@ -98,15 +104,21 @@ // Add 3 versions of keys into keytab KeyTab ktab = KeyTab.create(OneKDC.KTAB); + String serviceName = null; + if (sniHostname != null) { + serviceName = "host/" + sniHostname; + } else { + serviceName = "host/" + server; + } PrincipalName service = new PrincipalName( - "host/" + server, PrincipalName.KRB_NT_SRV_HST); + serviceName, PrincipalName.KRB_NT_SRV_HST); ktab.addEntry(service, "pass1".toCharArray(), 1, true); ktab.addEntry(service, "pass2".toCharArray(), 2, true); ktab.addEntry(service, "pass3".toCharArray(), 3, true); ktab.save(); // and use the middle one as the real key - kdc.addPrincipal("host/" + server, "pass2".toCharArray()); + kdc.addPrincipal(serviceName, "pass2".toCharArray()); // JAAS config entry name ssl @@ -118,7 +130,7 @@ " com.sun.security.auth.module.Krb5LoginModule required\n" + (unbound ? " principal=*\n" : - " principal=\"host/" + server + "\"\n") + + " principal=\"" + serviceName + "\"\n") + " useKeyTab=true\n" + " keyTab=" + OneKDC.KTAB + "\n" + " isInitiator=false\n" + @@ -153,7 +165,7 @@ } c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); - c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); + c.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID); c.doAs(new JsseClientAction(), null); // Add another version of key, make sure it can be loaded @@ -161,10 +173,10 @@ ktab = KeyTab.getInstance(OneKDC.KTAB); ktab.addEntry(service, "pass4".toCharArray(), 4, true); ktab.save(); - kdc.addPrincipal("host/" + server, "pass4".toCharArray()); + kdc.addPrincipal(serviceName, "pass4".toCharArray()); c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); - c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); + c.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID); c.doAs(new JsseClientAction(), null); // Permission checking check. Please note this is highly @@ -199,6 +211,14 @@ sslSocket.setEnabledCipherSuites(enabledSuites); // Should check for exception if enabledSuites is not supported + if (sniHostname != null) { + List serverNames = new ArrayList<>(); + serverNames.add(new SNIHostName(sniHostname)); + SSLParameters params = sslSocket.getSSLParameters(); + params.setServerNames(serverNames); + sslSocket.setSSLParameters(params); + } + BufferedReader in = new BufferedReader(new InputStreamReader( sslSocket.getInputStream())); BufferedWriter out = new BufferedWriter(new OutputStreamWriter( @@ -242,6 +262,14 @@ sslServerSocket.setEnabledCipherSuites(enabledSuites); // Should check for exception if enabledSuites is not supported + if (sniMatcherPattern != null) { + List matchers = new ArrayList<>(); + matchers.add(SNIHostName.createSNIMatcher(sniMatcherPattern)); + SSLParameters params = sslServerSocket.getSSLParameters(); + params.setSNIMatchers(matchers); + sslServerSocket.setSSLParameters(params); + } + while (loopCount++ < LOOP_LIMIT) { System.out.println("Waiting for incoming connection..."); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/sun/security/pkcs11/KeyStore/SecretKeysBasic.sh --- a/jdk/test/sun/security/pkcs11/KeyStore/SecretKeysBasic.sh Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/sun/security/pkcs11/KeyStore/SecretKeysBasic.sh Tue Oct 08 14:57:32 2013 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2008, 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 @@ -143,7 +143,8 @@ cd ${TESTSRC} ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} \ -DDIR=${TESTSRC}${FS}BasicData${FS} \ - -classpath ${TESTCLASSES}${PS}${TESTSRC}${FS}loader.jar \ + -classpath \ + ${TESTCLASSES}${PS}${TESTCLASSES}${FS}..${PS}${TESTSRC}${FS}loader.jar \ -DCUSTOM_DB_DIR=${TESTCLASSES} \ -DCUSTOM_P11_CONFIG=${TESTSRC}${FS}BasicData${FS}p11-${token}.txt \ -DNO_DEFAULT=true \ diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/sun/security/provider/SecureRandom/StrongSecureRandom.java --- a/jdk/test/sun/security/provider/SecureRandom/StrongSecureRandom.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/sun/security/provider/SecureRandom/StrongSecureRandom.java Tue Oct 08 14:57:32 2013 -0700 @@ -120,7 +120,14 @@ private static void testStrongInstance(boolean expected) throws Exception { - boolean result = (SecureRandom.getStrongSecureRandom() != null); + boolean result; + + try { + SecureRandom.getInstanceStrong(); + result = true; + } catch (NoSuchAlgorithmException e) { + result = false; + } if (expected != result) { throw new Exception("Received: " + result); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/DHKeyExchange/DHEKeySizing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/DHKeyExchange/DHEKeySizing.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,477 @@ +/* + * Copyright (c) 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. + * + * 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. + */ + +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + +/* + * @test + * @bug 6956398 + * @summary make ephemeral DH key match the length of the certificate key + * @run main/othervm + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1318 75 + * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1318 75 + * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1318 75 + * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024 + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1318 75 + * + * @run main/othervm + * DHEKeySizing SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA true 292 75 + * + * @run main/othervm + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1510 139 + * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1414 107 + * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1894 267 + * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024 + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1510 139 + * + * @run main/othervm + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 484 139 + * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 388 107 + * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 484 139 + * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024 + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 484 139 + */ + +/* + * This is a simple hack to test key sizes of Diffie-Hellman key exchanging + * during SSL/TLS handshaking. + * + * The record length of DH ServerKeyExchange and ClientKeyExchange. + * ServerKeyExchange message are wrapped in ServerHello series messages, which + * contains ServerHello, Certificate and ServerKeyExchange message. + * + * struct { + * opaque dh_p<1..2^16-1>; + * opaque dh_g<1..2^16-1>; + * opaque dh_Ys<1..2^16-1>; + * } ServerDHParams; // Ephemeral DH parameters + * + * struct { + * select (PublicValueEncoding) { + * case implicit: struct { }; + * case explicit: opaque dh_Yc<1..2^16-1>; + * } dh_public; + * } ClientDiffieHellmanPublic; + * + * Fomr above structures, it is clear that if the DH key size increasing 128 + * bits (16 bytes), the ServerHello series messages increases 48 bytes + * (becuase dh_p, dh_g and dh_Ys each increase 16 bytes) and ClientKeyExchange + * increases 16 bytes (because of the size increasing of dh_Yc). + * + * Here is a summary of the record length in the test case. + * + * | ServerHello Series | ClientKeyExchange | ServerHello Anon + * 512-bit | 1318 bytes | 75 bytes | 292 bytes + * 768-bit | 1414 bytes | 107 bytes | 388 bytes + * 1024-bit | 1510 bytes | 139 bytes | 484 bytes + * 2048-bit | 1894 bytes | 267 bytes | 484 bytes + */ + +import javax.net.ssl.*; +import javax.net.ssl.SSLEngineResult.*; +import java.io.*; +import java.nio.*; +import java.security.KeyStore; +import java.security.KeyFactory; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.*; +import java.security.interfaces.*; +import java.util.Base64; + +public class DHEKeySizing { + + private static boolean debug = true; + + private SSLContext sslc; + private SSLEngine ssle1; // client + private SSLEngine ssle2; // server + + private ByteBuffer appOut1; // write side of ssle1 + private ByteBuffer appIn1; // read side of ssle1 + private ByteBuffer appOut2; // write side of ssle2 + private ByteBuffer appIn2; // read side of ssle2 + + private ByteBuffer oneToTwo; // "reliable" transport ssle1->ssle2 + private ByteBuffer twoToOne; // "reliable" transport ssle2->ssle1 + + /* + * Where do we find the keystores? + */ + // Certificates and key used in the test. + static String trustedCertStr = + "-----BEGIN CERTIFICATE-----\n" + + "MIIC8jCCAdqgAwIBAgIEUjkuRzANBgkqhkiG9w0BAQUFADA7MR0wGwYDVQQLExRT\n" + + "dW5KU1NFIFRlc3QgU2VyaXZjZTENMAsGA1UEChMESmF2YTELMAkGA1UEBhMCVVMw\n" + + "HhcNMTMwOTE4MDQzODMxWhcNMTMxMjE3MDQzODMxWjA7MR0wGwYDVQQLExRTdW5K\n" + + "U1NFIFRlc3QgU2VyaXZjZTENMAsGA1UEChMESmF2YTELMAkGA1UEBhMCVVMwggEi\n" + + "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCO+IGeaskJAvEcYc7pCl9neK3E\n" + + "a28fwWLtChufYNaC9hQfZlUdETWYjV7fZJVJKT/oLzdDNMWuVA0LKXArpI3thLNK\n" + + "QLXisdF9hKPlZRDazACL9kWUUtJ0FzpEySK4e8wW/z9FuU6e6iO19FbjxAfInJqk\n" + + "3EDiEhB5g73S2vtvPCxgq2DvWw9TDl/LIqdKG2JCS93koXCCaHmQ7MrIOqHPd+8r\n" + + "RbGpatXT9qyHKppUv9ATxVygO4rA794mgCFxpT+fkhz+NEB0twTkM65T1hnnOv5n\n" + + "ZIxkcjBggt85UlZtnP3b9P7SYxsWIa46Oc38Od2f3YejfVg6B+PqPgWNl3+/AgMB\n" + + "AAEwDQYJKoZIhvcNAQEFBQADggEBAAlrP6DFLRPSy0IgQhcI2i56tR/na8pezSte\n" + + "ZHcCdaCZPDy4UP8mpLJ9QCjEB5VJv8hPm4xdK7ULnKGOGHgYqDpV2ZHvQlhV1woQ\n" + + "TZGb/LM3c6kAs0j4j9KM2fq3iYUYexjIkS1KzsziflxMM6igS9BRMBR2LQyU+cYq\n" + + "YEsFzkF7Aj2ET4v/+tgot9mRr2NioJcaJkdsPDpMU3IKB1cczfu+OuLQ/GCG0Fqu\n" + + "6ijCeCqfnaAbemHbJeVZZ6Qgka3uC2YMntLBmLkhqEo1d9zGYLoh7oWL77y5ibQZ\n" + + "LK5/H/zikcu579TWjlDHcqL3arCwBcrtsjSaPrRSWMrWV/6c0qw=\n" + + "-----END CERTIFICATE-----"; + + // Private key in the format of PKCS#8 + static String targetPrivateKey = + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCO+IGeaskJAvEc\n" + + "Yc7pCl9neK3Ea28fwWLtChufYNaC9hQfZlUdETWYjV7fZJVJKT/oLzdDNMWuVA0L\n" + + "KXArpI3thLNKQLXisdF9hKPlZRDazACL9kWUUtJ0FzpEySK4e8wW/z9FuU6e6iO1\n" + + "9FbjxAfInJqk3EDiEhB5g73S2vtvPCxgq2DvWw9TDl/LIqdKG2JCS93koXCCaHmQ\n" + + "7MrIOqHPd+8rRbGpatXT9qyHKppUv9ATxVygO4rA794mgCFxpT+fkhz+NEB0twTk\n" + + "M65T1hnnOv5nZIxkcjBggt85UlZtnP3b9P7SYxsWIa46Oc38Od2f3YejfVg6B+Pq\n" + + "PgWNl3+/AgMBAAECggEAPdb5Ycc4m4A9QBSCRcRpzbyiFLKPh0HDg1n65q4hOtYr\n" + + "kAVYTVFTSF/lqGS+Ob3w2YIKujQKSUQrvCc5UHdFuHXMgxKIWbymK0+DAMb9SlYw\n" + + "6lkkcWp9gx9E4dnJ/df2SAAxovvrKMuHlL1SFASHhVtPfH2URvSfUaANLDXxyYOs\n" + + "8BX0Nr6wazhWjLjXo9yIGnKSvFfB8XisYcA78kEgas43zhmIGCDPqaYyyffOfRbx\n" + + "pM1KNwGmlN86iWR1CbwA/wwhcMySWQueS+s7cHbpRqZIYJF9jEeELiwi0vxjealS\n" + + "EMuHYedIRFMWaDIq9XyjrvXamHb0Z25jlXBNZHaM0QKBgQDE9adl+zAezR/n79vw\n" + + "0XiX2Fx1UEo3ApZHuoA2Q/PcBk+rlKqqQ3IwTcy6Wo648wK7v6Nq7w5nEWcsf0dU\n" + + "QA2Ng/AJEev/IfF34x7sKGYxtk1gcE0EuSBA3R+ocEZxnNw1Ryd5nUU24s8d4jCP\n" + + "Mkothnyaim+zE2raDlEtVc0CaQKBgQC509av+02Uq5oMjzbQp5PBJfQFjATOQT15\n" + + "eefYnVYurkQ1kcVfixkrO2ORhg4SjmI2Z5hJDgGtXdwgidpzkad+R2epS5qLMyno\n" + + "lQVpY6bMpEZ7Mos0yQygxnm8uNohEcTExOe+nP5fNJVpzBsGmfeyYOhnPQlf6oqf\n" + + "0cHizedb5wKBgQC/l5LyMil6HOGHlhzmIm3jj7VI7QR0hJC5T6N+phVml8ESUDjA\n" + + "DYHbmSKouISTRtkG14FY+RiSjCxH7bvuKazFV2289PETquogTA/9e8MFYqfcQwG4\n" + + "sXi9gBxWlnj/9a2EKiYtOB5nKLR/BlNkSHA93tAA6N+FXEMZwMmYhxk42QKBgAuY\n" + + "HQgD3PZOsqDf+qKQIhbmAFCsSMx5o5VFtuJ8BpmJA/Z3ruHkMuDQpsi4nX4o5hXQ\n" + + "5t6AAjjH52kcUMXvK40kdWJJtk3DFnVNfvXxYsHX6hHbuHXFqYUKfSP6QJnZmvZP\n" + + "9smcz/4usLfWJUWHK740b6upUkFqx9Vq5/b3s9y3AoGAdM5TW7LkkOFsdMGVAUzR\n" + + "9iXmCWElHTK2Pcp/3yqDBHSfiQx6Yp5ANyPnE9NBM0yauCfOyBB2oxLO4Rdv3Rqk\n" + + "9V9kyR/YAGr7dJaPcQ7pZX0OpkzgueAOJYPrx5VUzPYUtklYV1ycFZTfKlpFCxT+\n" + + "Ei6KUo0NXSdUIcB4yib1J10="; + + static char passphrase[] = "passphrase".toCharArray(); + + /* + * Majority of the test case is here, setup is done below. + */ + + private void createSSLEngines() throws Exception { + ssle1 = sslc.createSSLEngine("client", 1); + ssle1.setUseClientMode(true); + + ssle2 = sslc.createSSLEngine("server", 2); + ssle2.setUseClientMode(false); + } + + private boolean isHandshaking(SSLEngine e) { + return (e.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING); + } + + private void checkResult(ByteBuffer bbIn, ByteBuffer bbOut, + SSLEngineResult result, + Status status, HandshakeStatus hsStatus, + int consumed, int produced) + throws Exception { + + if ((status != null) && (result.getStatus() != status)) { + throw new Exception("Unexpected Status: need = " + status + + " got = " + result.getStatus()); + } + + if ((hsStatus != null) && (result.getHandshakeStatus() != hsStatus)) { + throw new Exception("Unexpected hsStatus: need = " + hsStatus + + " got = " + result.getHandshakeStatus()); + } + + if ((consumed != -1) && (consumed != result.bytesConsumed())) { + throw new Exception("Unexpected consumed: need = " + consumed + + " got = " + result.bytesConsumed()); + } + + if ((produced != -1) && (produced != result.bytesProduced())) { + throw new Exception("Unexpected produced: need = " + produced + + " got = " + result.bytesProduced()); + } + + if ((consumed != -1) && (bbIn.position() != result.bytesConsumed())) { + throw new Exception("Consumed " + bbIn.position() + + " != " + consumed); + } + + if ((produced != -1) && (bbOut.position() != result.bytesProduced())) { + throw new Exception("produced " + bbOut.position() + + " != " + produced); + } + } + + private void test(String cipherSuite, boolean exportable, + int lenServerKeyEx, int lenClientKeyEx) throws Exception { + + createSSLEngines(); + createBuffers(); + + SSLEngineResult result1; // ssle1's results from last operation + SSLEngineResult result2; // ssle2's results from last operation + + String[] suites = new String [] {cipherSuite}; + + ssle1.setEnabledCipherSuites(suites); + ssle2.setEnabledCipherSuites(suites); + + log("======================================"); + log("==================="); + log("client hello"); + result1 = ssle1.wrap(appOut1, oneToTwo); + checkResult(appOut1, oneToTwo, result1, + Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1); + oneToTwo.flip(); + + result2 = ssle2.unwrap(oneToTwo, appIn2); + checkResult(oneToTwo, appIn2, result2, + Status.OK, HandshakeStatus.NEED_TASK, result1.bytesProduced(), 0); + runDelegatedTasks(ssle2); + oneToTwo.compact(); + + log("==================="); + log("ServerHello"); + result2 = ssle2.wrap(appOut2, twoToOne); + checkResult(appOut2, twoToOne, result2, + Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1); + twoToOne.flip(); + + log("Message length of ServerHello series: " + twoToOne.remaining()); + if (lenServerKeyEx != twoToOne.remaining()) { + throw new Exception( + "Expected to generate ServerHello series messages of " + + lenServerKeyEx + " bytes, but not " + twoToOne.remaining()); + } + + result1 = ssle1.unwrap(twoToOne, appIn1); + checkResult(twoToOne, appIn1, result1, + Status.OK, HandshakeStatus.NEED_TASK, result2.bytesProduced(), 0); + runDelegatedTasks(ssle1); + twoToOne.compact(); + + log("==================="); + log("Key Exchange"); + result1 = ssle1.wrap(appOut1, oneToTwo); + checkResult(appOut1, oneToTwo, result1, + Status.OK, HandshakeStatus.NEED_WRAP, 0, -1); + oneToTwo.flip(); + + log("Message length of ClientKeyExchange: " + oneToTwo.remaining()); + if (lenClientKeyEx != oneToTwo.remaining()) { + throw new Exception( + "Expected to generate ClientKeyExchange message of " + + lenClientKeyEx + " bytes, but not " + oneToTwo.remaining()); + } + result2 = ssle2.unwrap(oneToTwo, appIn2); + checkResult(oneToTwo, appIn2, result2, + Status.OK, HandshakeStatus.NEED_TASK, result1.bytesProduced(), 0); + runDelegatedTasks(ssle2); + oneToTwo.compact(); + + log("==================="); + log("Client CCS"); + result1 = ssle1.wrap(appOut1, oneToTwo); + checkResult(appOut1, oneToTwo, result1, + Status.OK, HandshakeStatus.NEED_WRAP, 0, -1); + oneToTwo.flip(); + + result2 = ssle2.unwrap(oneToTwo, appIn2); + checkResult(oneToTwo, appIn2, result2, + Status.OK, HandshakeStatus.NEED_UNWRAP, + result1.bytesProduced(), 0); + oneToTwo.compact(); + + log("==================="); + log("Client Finished"); + result1 = ssle1.wrap(appOut1, oneToTwo); + checkResult(appOut1, oneToTwo, result1, + Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1); + oneToTwo.flip(); + + result2 = ssle2.unwrap(oneToTwo, appIn2); + checkResult(oneToTwo, appIn2, result2, + Status.OK, HandshakeStatus.NEED_WRAP, + result1.bytesProduced(), 0); + oneToTwo.compact(); + + log("==================="); + log("Server CCS"); + result2 = ssle2.wrap(appOut2, twoToOne); + checkResult(appOut2, twoToOne, result2, + Status.OK, HandshakeStatus.NEED_WRAP, 0, -1); + twoToOne.flip(); + + result1 = ssle1.unwrap(twoToOne, appIn1); + checkResult(twoToOne, appIn1, result1, + Status.OK, HandshakeStatus.NEED_UNWRAP, result2.bytesProduced(), 0); + twoToOne.compact(); + + log("==================="); + log("Server Finished"); + result2 = ssle2.wrap(appOut2, twoToOne); + checkResult(appOut2, twoToOne, result2, + Status.OK, HandshakeStatus.FINISHED, 0, -1); + twoToOne.flip(); + + result1 = ssle1.unwrap(twoToOne, appIn1); + checkResult(twoToOne, appIn1, result1, + Status.OK, HandshakeStatus.FINISHED, result2.bytesProduced(), 0); + twoToOne.compact(); + + log("==================="); + log("Check Session/Ciphers"); + String cs = ssle1.getSession().getCipherSuite(); + if (!cs.equals(suites[0])) { + throw new Exception("suites not equal: " + cs + "/" + suites[0]); + } + + cs = ssle2.getSession().getCipherSuite(); + if (!cs.equals(suites[0])) { + throw new Exception("suites not equal: " + cs + "/" + suites[0]); + } + + log("==================="); + log("Done with SSL/TLS handshaking"); + } + + public static void main(String args[]) throws Exception { + if (args.length != 4) { + System.out.println( + "Usage: java DHEKeySizing cipher-suite " + + "exportable(true|false)\n" + + " size-of-server-hello-record size-of-client-key-exchange"); + throw new Exception("Incorrect usage!"); + } + + (new DHEKeySizing()).test(args[0], + Boolean.parseBoolean(args[1]), + Integer.parseInt(args[2]), + Integer.parseInt(args[3])); + System.out.println("Test Passed."); + } + + /* + * ********************************************************** + * Majority of the test case is above, below is just setup stuff + * ********************************************************** + */ + + public DHEKeySizing() throws Exception { + sslc = getSSLContext(); + } + + /* + * Create an initialized SSLContext to use for this test. + */ + private SSLContext getSSLContext() throws Exception { + + // generate certificate from cert string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + // create a key store + KeyStore ts = KeyStore.getInstance("JKS"); + KeyStore ks = KeyStore.getInstance("JKS"); + ts.load(null, null); + ks.load(null, null); + + // import the trused cert + ByteArrayInputStream is = + new ByteArrayInputStream(trustedCertStr.getBytes()); + Certificate trusedCert = cf.generateCertificate(is); + is.close(); + ts.setCertificateEntry("rsa-trusted-2048", trusedCert); + + // generate the private key. + String keySpecStr = targetPrivateKey; + PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( + Base64.getMimeDecoder().decode(keySpecStr)); + KeyFactory kf = KeyFactory.getInstance("RSA"); + RSAPrivateKey priKey = (RSAPrivateKey)kf.generatePrivate(priKeySpec); + + Certificate[] chain = new Certificate[1]; + chain[0] = trusedCert; + + // import the key entry. + ks.setKeyEntry("rsa-key-2048", priKey, passphrase, chain); + + // create SSL context + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, passphrase); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(ts); + + SSLContext sslCtx = SSLContext.getInstance("TLS"); + sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + return sslCtx; + } + + private void createBuffers() { + // Size the buffers as appropriate. + + SSLSession session = ssle1.getSession(); + int appBufferMax = session.getApplicationBufferSize(); + int netBufferMax = session.getPacketBufferSize(); + + appIn1 = ByteBuffer.allocateDirect(appBufferMax + 50); + appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50); + + oneToTwo = ByteBuffer.allocateDirect(netBufferMax); + twoToOne = ByteBuffer.allocateDirect(netBufferMax); + + appOut1 = ByteBuffer.wrap("Hi Engine2, I'm SSLEngine1".getBytes()); + appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes()); + + log("AppOut1 = " + appOut1); + log("AppOut2 = " + appOut2); + log(""); + } + + private static void runDelegatedTasks(SSLEngine engine) throws Exception { + + Runnable runnable; + while ((runnable = engine.getDelegatedTask()) != null) { + log("running delegated task..."); + runnable.run(); + } + } + + private static void log(String str) { + if (debug) { + System.out.println(str); + } + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/sun/security/tools/keytool/StorePasswords.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/tools/keytool/StorePasswords.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,186 @@ +/* + * Copyright (c) 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. + * + * 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 8008296 + * @summary Store and retrieve user passwords using PKCS#12 keystore + */ + +import java.io.*; +import java.security.*; +import java.util.*; +import javax.crypto.*; +import javax.crypto.spec.*; + +/* + * Store and retrieve passwords protected by a selection of PBE algorithms, + * using a PKCS#12 keystore. + */ +public class StorePasswords { + + private static final String[] PBE_ALGORITHMS = new String[] { + "default PBE algorithm", + "PBEWithMD5AndDES", + "PBEWithSHA1AndDESede", + "PBEWithSHA1AndRC2_40", + "PBEWithSHA1AndRC2_128", + "PBEWithSHA1AndRC4_40", + "PBEWithSHA1AndRC4_128", + "PBEWithHmacSHA1AndAES_128", + "PBEWithHmacSHA224AndAES_128", + "PBEWithHmacSHA256AndAES_128", + "PBEWithHmacSHA384AndAES_128", + "PBEWithHmacSHA512AndAES_128", + "PBEWithHmacSHA1AndAES_256", + "PBEWithHmacSHA224AndAES_256", + "PBEWithHmacSHA256AndAES_256", + "PBEWithHmacSHA384AndAES_256", + "PBEWithHmacSHA512AndAES_256" + }; + + private static final String KEYSTORE = "mykeystore.p12"; + private static final char[] KEYSTORE_PWD = "changeit".toCharArray(); + private static final char[] ENTRY_PWD = "protectit".toCharArray(); + private static final char[] USER_PWD = "hello1".toCharArray(); + + public static void main(String[] args) throws Exception { + + new File(KEYSTORE).delete(); + + int storeCount = store(); + int recoverCount = recover(); + + if (recoverCount != storeCount) { + throw new Exception("Stored " + storeCount + " user passwords, " + + "recovered " + recoverCount + " user passwords"); + } + System.out.println("\nStored " + storeCount + " user passwords, " + + "recovered " + recoverCount + " user passwords"); + } + + private static int store() throws Exception { + int count = 0; + // Load an empty PKCS#12 keystore + KeyStore keystore = KeyStore.getInstance("PKCS12"); + System.out.println("\nLoading PKCS#12 keystore..."); + keystore.load(null, null); + + // Derive a PBE key from the password + PBEKeySpec keySpec = new PBEKeySpec(USER_PWD); + SecretKeyFactory factory = SecretKeyFactory.getInstance("PBE"); + SecretKey key = factory.generateSecret(keySpec); + PBEParameterSpec specWithEightByteSalt = + new PBEParameterSpec("NaClNaCl".getBytes(), 1024); + + // Store the user password in a keystore entry (for each algorithm) + for (String algorithm : PBE_ALGORITHMS) { + + try { + System.out.println("Storing user password '" + + new String(USER_PWD) + "' (protected by " + algorithm + + ")"); + + if (algorithm.equals("default PBE algorithm")) { + keystore.setKeyEntry( + "this entry is protected by " + algorithm, key, + ENTRY_PWD, null); + } else { + keystore.setEntry( + "this entry is protected by " + algorithm, + new KeyStore.SecretKeyEntry(key), + new KeyStore.PasswordProtection(ENTRY_PWD, algorithm, + null)); + } + count++; + + } catch (KeyStoreException e) { + Throwable inner = e.getCause(); + if (inner instanceof UnrecoverableKeyException) { + Throwable inner2 = inner.getCause(); + if (inner2 instanceof InvalidAlgorithmParameterException) { + System.out.println("...re-trying due to: " + + inner2.getMessage()); + + // Some PBE algorithms demand an 8-byte salt + keystore.setEntry( + "this entry is protected by " + algorithm, + new KeyStore.SecretKeyEntry(key), + new KeyStore.PasswordProtection(ENTRY_PWD, + algorithm, specWithEightByteSalt)); + count++; + + } else if (inner2 instanceof InvalidKeyException) { + System.out.println("...skipping due to: " + + inner2.getMessage()); + // Unsupported crypto keysize + continue; + } + } else { + throw e; + } + } + } + + // Store the PKCS#12 keystore + System.out.println("Storing PKCS#12 keystore to: " + KEYSTORE); + keystore.store(new FileOutputStream(KEYSTORE), KEYSTORE_PWD); + + return count; + } + + private static int recover() throws Exception { + int count = 0; + // Load the PKCS#12 keystore + KeyStore keystore = KeyStore.getInstance("PKCS12"); + System.out.println("\nLoading PKCS#12 keystore from: " + KEYSTORE); + keystore.load(new FileInputStream(KEYSTORE), KEYSTORE_PWD); + + SecretKey key; + SecretKeyFactory factory; + PBEKeySpec keySpec; + + // Retrieve each user password from the keystore + for (String algorithm : PBE_ALGORITHMS) { + key = (SecretKey) keystore.getKey("this entry is protected by " + + algorithm, ENTRY_PWD); + + if (key != null) { + count++; + factory = SecretKeyFactory.getInstance(key.getAlgorithm()); + keySpec = + (PBEKeySpec) factory.getKeySpec(key, PBEKeySpec.class); + char[] pwd = keySpec.getPassword(); + System.out.println("Recovered user password '" + + new String(pwd) + "' (protected by " + algorithm + ")"); + + if (!Arrays.equals(USER_PWD, pwd)) { + throw new Exception("Failed to recover the user password " + + "protected by " + algorithm); + } + } + } + + return count; + } +} diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/sun/security/tools/keytool/StorePasswordsByShell.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/tools/keytool/StorePasswordsByShell.sh Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,140 @@ +# +# Copyright (c) 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. +# +# 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 8008296 +# @summary confirm that keytool correctly imports user passwords +# +# @run shell StorePasswordsByShell.sh + +# set a few environment variables so that the shell-script can run stand-alone +# in the source directory +if [ "${TESTSRC}" = "" ] ; then + TESTSRC="." +fi + +if [ "${TESTCLASSES}" = "" ] ; then + TESTCLASSES="." +fi + +if [ "${TESTJAVA}" = "" ] ; then + echo "TESTJAVA not set. Test cannot execute." + echo "FAILED!!!" + exit 1 +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + SunOS ) + PATHSEP=":" + FILESEP="/" + ;; + Linux ) + PATHSEP=":" + FILESEP="/" + ;; + Darwin ) + PATHSEP=":" + FILESEP="/" + ;; + CYGWIN* ) + PATHSEP=";" + FILESEP="/" + ;; + Windows* ) + PATHSEP=";" + FILESEP="\\" + ;; + * ) + echo "Unrecognized system!" + exit 1; + ;; +esac + +PBE_ALGORITHMS="\ + default-PBE-algorithm \ + PBEWithMD5AndDES \ + PBEWithSHA1AndDESede \ + PBEWithSHA1AndRC2_40 \ + PBEWithSHA1AndRC2_128 + PBEWithSHA1AndRC4_40 \ + PBEWithSHA1AndRC4_128 \ + PBEWithHmacSHA1AndAES_128 \ + PBEWithHmacSHA224AndAES_128 \ + PBEWithHmacSHA256AndAES_128 \ + PBEWithHmacSHA384AndAES_128 \ + PBEWithHmacSHA512AndAES_128 \ + PBEWithHmacSHA1AndAES_256 \ + PBEWithHmacSHA224AndAES_256 \ + PBEWithHmacSHA256AndAES_256 \ + PBEWithHmacSHA384AndAES_256 \ + PBEWithHmacSHA512AndAES_256" + +USER_PWD="hello1\n" +ALIAS_PREFIX="this entry is protected by " +COUNTER=0 + +# cleanup +rm mykeystore.p12 > /dev/null 2>&1 + +echo +for i in $PBE_ALGORITHMS; do + + if [ $i = "default-PBE-algorithm" ]; then + KEYALG="" + else + KEYALG="-keyalg ${i}" + fi + + if [ $COUNTER -lt 5 ]; then + IMPORTPASSWORD="-importpassword" + else + IMPORTPASSWORD="-importpass" + fi + + echo "Storing user password (protected by ${i})" + echo "${USER_PWD}" | \ + ${TESTJAVA}${FILESEP}bin${FILESEP}keytool ${IMPORTPASSWORD} \ + -storetype pkcs12 -keystore mykeystore.p12 -storepass changeit \ + -alias "${ALIAS_PREFIX}${i}" ${KEYALG} > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo Error + else + echo OK + COUNTER=`expr ${COUNTER} + 1` + fi +done +echo + +COUNTER2=`${TESTJAVA}${FILESEP}bin${FILESEP}keytool -list -storetype pkcs12 \ + -keystore mykeystore.p12 -storepass changeit | grep -c "${ALIAS_PREFIX}"` + +RESULT="stored ${COUNTER} user passwords, detected ${COUNTER2} user passwords" +if [ $COUNTER -ne $COUNTER2 -o $COUNTER -lt 11 ]; then + echo "ERROR: $RESULT" + exit 1 +else + echo "OK: $RESULT" + exit 0 +fi diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/tools/launcher/DiacriticTest.java --- a/jdk/test/tools/launcher/DiacriticTest.java Tue Oct 08 14:53:14 2013 -0700 +++ b/jdk/test/tools/launcher/DiacriticTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -54,7 +54,13 @@ "}\n"; ArrayList content = new ArrayList<>(); content.add(source); - createFile(sourceFile, content); + try { + createFile(sourceFile, content); + } catch (java.nio.file.InvalidPathException ipe) { + System.out.println("The locale or file system is configured in a way " + + "that prevents file creation. Real testing impossible."); + return; + } HashMap env = new HashMap<>(); env.put("LC_CTYPE", "UTF-8"); diff -r 5f3e7611790a -r a7dcd7811f02 jdk/test/tools/launcher/I18NArgTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/launcher/I18NArgTest.java Tue Oct 08 14:57:32 2013 -0700 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 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. + * + * 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 8016110 + * @summary verify Japanese character in an argument are treated correctly + * @compile -XDignore.symbol.file I18NArgTest.java + * @run main I18NArgTest + */ +import java.io.IOException; + +public class I18NArgTest extends TestHelper { + public static void main(String... args) throws IOException { + if (!isWindows) { + return; + } + if (!"MS932".equals(System.getProperty("sun.jnu.encoding"))) { + System.err.println("MS932 encoding not set, test skipped"); + return; + } + if (args.length == 0) { + execTest(0x30bd); // MS932 Katakana SO, 0x835C + } else { + testCharacters(args); + } + } + static void execTest(int unicodeValue) { + String hexValue = Integer.toHexString(unicodeValue); + String unicodeStr = Character.toString((char)unicodeValue); + execTest("\"" + unicodeStr + "\"", hexValue); + execTest("\\" + unicodeStr + "\\", hexValue); + execTest(" " + unicodeStr + " ", hexValue); + execTest("'" + unicodeStr + "'", hexValue); + execTest("\t" + unicodeStr + "\t", hexValue); + execTest("*" + unicodeStr + "*", hexValue); + execTest("?" + unicodeStr + "?", hexValue); + + execTest("\"" + unicodeStr + unicodeStr + "\"", hexValue + hexValue); + execTest("\\" + unicodeStr + unicodeStr + "\\", hexValue + hexValue); + execTest(" " + unicodeStr + unicodeStr + " ", hexValue + hexValue); + execTest("'" + unicodeStr + unicodeStr + "'", hexValue + hexValue); + execTest("\t" + unicodeStr + unicodeStr + "\t", hexValue + hexValue); + execTest("*" + unicodeStr + unicodeStr + "*", hexValue + hexValue); + execTest("?" + unicodeStr + unicodeStr + "?", hexValue + hexValue); + + execTest("\"" + unicodeStr + "a" + unicodeStr + "\"", hexValue + "61" + hexValue); + execTest("\\" + unicodeStr + "a" + unicodeStr + "\\", hexValue + "61" + hexValue); + execTest(" " + unicodeStr + "a" + unicodeStr + " ", hexValue + "61"+ hexValue); + execTest("'" + unicodeStr + "a" + unicodeStr + "'", hexValue + "61"+ hexValue); + execTest("\t" + unicodeStr + "a" + unicodeStr + "\t", hexValue + "61"+ hexValue); + execTest("*" + unicodeStr + "a" + unicodeStr + "*", hexValue + "61"+ hexValue); + execTest("?" + unicodeStr + "a" + unicodeStr + "?", hexValue + "61"+ hexValue); + + execTest("\"" + unicodeStr + "\u00b1" + unicodeStr + "\"", hexValue + "b1" + hexValue); + execTest("\\" + unicodeStr + "\u00b1" + unicodeStr + "\\", hexValue + "b1" + hexValue); + execTest(" " + unicodeStr + "\u00b1" + unicodeStr + " ", hexValue + "b1"+ hexValue); + execTest("'" + unicodeStr + "\u00b1" + unicodeStr + "'", hexValue + "b1"+ hexValue); + execTest("\t" + unicodeStr + "\u00b1" + unicodeStr + "\t", hexValue + "b1"+ hexValue); + execTest("*" + unicodeStr + "\u00b1" + unicodeStr + "*", hexValue + "b1"+ hexValue); + execTest("?" + unicodeStr + "\u00b1" + unicodeStr + "?", hexValue + "b1"+ hexValue); + } + static void execTest(String unicodeStr, String hexValue) { + TestResult tr = doExec(javaCmd, + "-Dtest.src=" + TEST_SOURCES_DIR.getAbsolutePath(), + "-Dtest.classes=" + TEST_CLASSES_DIR.getAbsolutePath(), + "-cp", TEST_CLASSES_DIR.getAbsolutePath(), + "I18NArgTest", unicodeStr, hexValue); + System.out.println(tr.testOutput); + if (!tr.isOK()) { + System.err.println(tr); + throw new RuntimeException("test fails"); + } + } + static void testCharacters(String... args) { + String input = args[0]; + String expected = args[1]; + String hexValue = ""; + for (int i = 0; i < input.length(); i++) { + hexValue = hexValue.concat(Integer.toHexString((int)input.charAt(i))); + } + System.out.println("input:" + input); + System.out.println("expected:" + expected); + System.out.println("obtained:" + hexValue); + if (!hexValue.contains(expected)) { + String message = "Error: output does not contain expected value" + + "expected:" + expected + " obtained:" + hexValue; + throw new RuntimeException(message); + } + } +}

    lookup expressionmemberbehavior
    lookup expressionmemberbytecode behavior
    {@link java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)}{@code FT f;}{@code (T) this.f;}