mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-04 23:48:33 +00:00
Merge
This commit is contained in:
commit
8afbe69644
@ -48,7 +48,6 @@ FILES_c = \
|
||||
Proxy.c \
|
||||
RandomAccessFile.c \
|
||||
RandomAccessFile_md.c \
|
||||
ResourceBundle.c \
|
||||
Runtime.c \
|
||||
SecurityManager.c \
|
||||
Shutdown.c \
|
||||
|
||||
@ -312,6 +312,12 @@ PROPS = content-types.properties
|
||||
#
|
||||
CAL_PROPS = calendars.properties
|
||||
|
||||
#
|
||||
# Rule to copy Hijrah-umalqura calendar properties file.
|
||||
#
|
||||
HIJRAH_UMALQURA_PROPS = hijrah-config-umalqura.properties
|
||||
|
||||
|
||||
#
|
||||
# Rule to copy tzmappings file on Windows
|
||||
#
|
||||
@ -324,7 +330,7 @@ $(TZMAP): $(TZMAPFILE)
|
||||
$(call chmod-file, 444)
|
||||
endif
|
||||
|
||||
build: $(LIBDIR)/$(PROPS) $(LIBDIR)/$(CAL_PROPS) $(TZMAP)
|
||||
build: $(LIBDIR)/$(PROPS) $(LIBDIR)/$(CAL_PROPS) $(LIBDIR)/$(HIJRAH_UMALQURA_PROPS) $(TZMAP)
|
||||
|
||||
$(LIBDIR)/$(PROPS): $(PLATFORM_SRC)/lib/$(PROPS)
|
||||
$(install-file)
|
||||
@ -332,6 +338,9 @@ $(LIBDIR)/$(PROPS): $(PLATFORM_SRC)/lib/$(PROPS)
|
||||
$(LIBDIR)/$(CAL_PROPS): $(SHARE_SRC)/lib/$(CAL_PROPS)
|
||||
$(install-file)
|
||||
|
||||
$(LIBDIR)/$(HIJRAH_UMALQURA_PROPS): $(SHARE_SRC)/lib/$(HIJRAH_UMALQURA_PROPS)
|
||||
$(install-file)
|
||||
|
||||
clean::
|
||||
$(RM) -r $(LIBDIR)/$(PROPS) $(TZMAP)
|
||||
|
||||
|
||||
@ -134,7 +134,6 @@ SUNWprivate_1.1 {
|
||||
Java_java_lang_ClassLoader_00024NativeLibrary_load;
|
||||
Java_java_lang_ClassLoader_00024NativeLibrary_unload;
|
||||
Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib;
|
||||
Java_java_lang_ClassLoader_getCaller;
|
||||
Java_java_lang_ClassLoader_registerNatives;
|
||||
Java_java_lang_Compiler_registerNatives;
|
||||
Java_java_lang_Double_longBitsToDouble;
|
||||
@ -217,7 +216,7 @@ SUNWprivate_1.1 {
|
||||
Java_java_lang_Throwable_fillInStackTrace;
|
||||
Java_java_lang_Throwable_getStackTraceDepth;
|
||||
Java_java_lang_Throwable_getStackTraceElement;
|
||||
Java_java_lang_UNIXProcess_initIDs;
|
||||
Java_java_lang_UNIXProcess_init;
|
||||
Java_java_lang_UNIXProcess_waitForProcessExit;
|
||||
Java_java_lang_UNIXProcess_forkAndExec;
|
||||
Java_java_lang_UNIXProcess_destroyProcess;
|
||||
@ -233,7 +232,6 @@ SUNWprivate_1.1 {
|
||||
Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2Ljava_security_AccessControlContext_2;
|
||||
Java_java_security_AccessController_getStackAccessControlContext;
|
||||
Java_java_security_AccessController_getInheritedAccessControlContext;
|
||||
Java_java_util_ResourceBundle_getClassContext;
|
||||
Java_java_util_TimeZone_getSystemTimeZoneID;
|
||||
Java_java_util_TimeZone_getSystemGMTOffsetID;
|
||||
Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8;
|
||||
|
||||
@ -73,7 +73,6 @@ text: .text%writeBytes;
|
||||
# Test Sleep
|
||||
# Test IntToString
|
||||
# Test LoadToolkit
|
||||
text: .text%Java_java_util_ResourceBundle_getClassContext;
|
||||
text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
|
||||
text: .text%JNU_GetEnv;
|
||||
text: .text%Java_java_io_UnixFileSystem_checkAccess;
|
||||
|
||||
@ -78,7 +78,6 @@ text: .text%writeBytes;
|
||||
# Test Sleep
|
||||
# Test IntToString
|
||||
# Test LoadToolkit
|
||||
text: .text%Java_java_util_ResourceBundle_getClassContext;
|
||||
text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
|
||||
text: .text%JNU_GetEnv;
|
||||
text: .text%Java_java_io_UnixFileSystem_checkAccess;
|
||||
|
||||
@ -74,7 +74,6 @@ text: .text%writeBytes;
|
||||
# Test Sleep
|
||||
# Test IntToString
|
||||
# Test LoadToolkit
|
||||
text: .text%Java_java_util_ResourceBundle_getClassContext;
|
||||
text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
|
||||
text: .text%JNU_GetEnv;
|
||||
text: .text%Java_java_io_UnixFileSystem_checkAccess;
|
||||
|
||||
@ -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
|
||||
@ -105,5 +105,7 @@ FILES_java = \
|
||||
sun/text/resources/CollationData.java \
|
||||
\
|
||||
sun/text/resources/FormatData.java \
|
||||
sun/text/resources/JavaTimeSupplementary.java \
|
||||
sun/text/resources/en/FormatData_en.java \
|
||||
sun/text/resources/en/FormatData_en_US.java
|
||||
sun/text/resources/en/FormatData_en_US.java \
|
||||
sun/text/resources/en/JavaTimeSupplementary_en.java \
|
||||
|
||||
@ -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
|
||||
@ -26,6 +26,7 @@
|
||||
FILES_java = \
|
||||
sun/util/resources/LocaleData.java \
|
||||
sun/util/resources/OpenListResourceBundle.java \
|
||||
sun/util/resources/ParallelListResourceBundle.java \
|
||||
sun/util/resources/LocaleNamesBundle.java \
|
||||
sun/util/resources/TimeZoneNamesBundle.java \
|
||||
sun/util/resources/TimeZoneNames.java \
|
||||
|
||||
@ -106,7 +106,21 @@ FILES_cpp_shared = \
|
||||
OpenTypeLayoutEngine.cpp \
|
||||
ThaiLayoutEngine.cpp \
|
||||
ScriptAndLanguageTags.cpp \
|
||||
FontInstanceAdapter.cpp
|
||||
FontInstanceAdapter.cpp \
|
||||
ContextualGlyphInsertionProc2.cpp \
|
||||
ContextualGlyphSubstProc2.cpp \
|
||||
GXLayoutEngine2.cpp \
|
||||
IndicRearrangementProcessor2.cpp \
|
||||
LigatureSubstProc2.cpp \
|
||||
MorphTables2.cpp \
|
||||
NonContextualGlyphSubstProc2.cpp \
|
||||
SegmentArrayProcessor2.cpp \
|
||||
SegmentSingleProcessor2.cpp \
|
||||
SimpleArrayProcessor2.cpp \
|
||||
SingleTableProcessor2.cpp \
|
||||
StateTableProcessor2.cpp \
|
||||
SubtableProcessor2.cpp \
|
||||
TrimmedArrayProcessor2.cpp
|
||||
|
||||
|
||||
ifeq ($(PLATFORM),windows)
|
||||
|
||||
@ -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
|
||||
@ -83,21 +83,17 @@ ifeq ($(PLATFORM), macosx)
|
||||
-framework JavaNativeFoundation
|
||||
else ifneq ($(PLATFORM), windows)
|
||||
CFLAGS += -DWITH_X11
|
||||
ifeq ($(PLATFORM), macosx))
|
||||
OTHER_LDLIBS += -liconv
|
||||
CPPFLAGS += -I$(OPENWIN_HOME)/include \
|
||||
-I$(OPENWIN_HOME)/include/X11/extensions
|
||||
OTHER_LDLIBS += -L$(OPENWIN_LIB) -lX11 -lXext $(LIBM) -pthread
|
||||
else
|
||||
CPPFLAGS += -I$(OPENWIN_HOME)/include -I$(OPENWIN_HOME)/include/X11/extensions
|
||||
OTHER_LDLIBS += -L$(OPENWIN_LIB) -lX11 -lXext $(LIBM) -lpthread
|
||||
endif
|
||||
CPPFLAGS += -I$(OPENWIN_HOME)/include -I$(OPENWIN_HOME)/include/X11/extensions
|
||||
OTHER_LDLIBS += -L$(OPENWIN_LIB) -lX11 -lXext $(LIBM) -lpthread
|
||||
else # PLATFORM
|
||||
CFLAGS += -DWITH_WIN32
|
||||
OTHER_LDLIBS += kernel32.lib user32.lib gdi32.lib delayimp.lib /DELAYLOAD:user32.dll
|
||||
#$(JVMLIB) $(OBJDIR)/../../jpeg/$(OBJDIRNAME)/jpeg$(SUFFIX).lib
|
||||
endif # PLATFORM
|
||||
|
||||
# Add giflib include path for all platforms
|
||||
CPPFLAGS += -I$(SHARE_SRC)/native/sun/awt/giflib
|
||||
|
||||
#
|
||||
# Add to ambient vpath to get files in a subdirectory
|
||||
#
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 1997, 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
|
||||
@ -227,5 +227,54 @@ FILES_java = \
|
||||
sun/util/resources/sv/TimeZoneNames_sv.java \
|
||||
sun/util/resources/zh/TimeZoneNames_zh_CN.java \
|
||||
sun/util/resources/zh/TimeZoneNames_zh_TW.java \
|
||||
sun/util/resources/zh/TimeZoneNames_zh_HK.java
|
||||
sun/util/resources/zh/TimeZoneNames_zh_HK.java \
|
||||
\
|
||||
sun/text/resources/ar/JavaTimeSupplementary_ar.java \
|
||||
sun/text/resources/be/JavaTimeSupplementary_be.java \
|
||||
sun/text/resources/bg/JavaTimeSupplementary_bg.java \
|
||||
sun/text/resources/ca/JavaTimeSupplementary_ca.java \
|
||||
sun/text/resources/cs/JavaTimeSupplementary_cs.java \
|
||||
sun/text/resources/da/JavaTimeSupplementary_da.java \
|
||||
sun/text/resources/de/JavaTimeSupplementary_de.java \
|
||||
sun/text/resources/el/JavaTimeSupplementary_el.java \
|
||||
sun/text/resources/en/JavaTimeSupplementary_en_GB.java \
|
||||
sun/text/resources/en/JavaTimeSupplementary_en_SG.java \
|
||||
sun/text/resources/es/JavaTimeSupplementary_es.java \
|
||||
sun/text/resources/et/JavaTimeSupplementary_et.java \
|
||||
sun/text/resources/fi/JavaTimeSupplementary_fi.java \
|
||||
sun/text/resources/fr/JavaTimeSupplementary_fr.java \
|
||||
sun/text/resources/ga/JavaTimeSupplementary_ga.java \
|
||||
sun/text/resources/hi/JavaTimeSupplementary_hi_IN.java \
|
||||
sun/text/resources/hr/JavaTimeSupplementary_hr.java \
|
||||
sun/text/resources/hu/JavaTimeSupplementary_hu.java \
|
||||
sun/text/resources/is/JavaTimeSupplementary_is.java \
|
||||
sun/text/resources/it/JavaTimeSupplementary_it.java \
|
||||
sun/text/resources/iw/JavaTimeSupplementary_iw.java \
|
||||
sun/text/resources/iw/JavaTimeSupplementary_iw_IL.java \
|
||||
sun/text/resources/ja/JavaTimeSupplementary_ja.java \
|
||||
sun/text/resources/ko/JavaTimeSupplementary_ko.java \
|
||||
sun/text/resources/lt/JavaTimeSupplementary_lt.java \
|
||||
sun/text/resources/lv/JavaTimeSupplementary_lv.java \
|
||||
sun/text/resources/mk/JavaTimeSupplementary_mk.java \
|
||||
sun/text/resources/ms/JavaTimeSupplementary_ms.java \
|
||||
sun/text/resources/mt/JavaTimeSupplementary_mt.java \
|
||||
sun/text/resources/nl/JavaTimeSupplementary_nl.java \
|
||||
sun/text/resources/no/JavaTimeSupplementary_no.java \
|
||||
sun/text/resources/pl/JavaTimeSupplementary_pl.java \
|
||||
sun/text/resources/pt/JavaTimeSupplementary_pt.java \
|
||||
sun/text/resources/pt/JavaTimeSupplementary_pt_PT.java \
|
||||
sun/text/resources/ro/JavaTimeSupplementary_ro.java \
|
||||
sun/text/resources/ru/JavaTimeSupplementary_ru.java \
|
||||
sun/text/resources/sk/JavaTimeSupplementary_sk.java \
|
||||
sun/text/resources/sl/JavaTimeSupplementary_sl.java \
|
||||
sun/text/resources/sq/JavaTimeSupplementary_sq.java \
|
||||
sun/text/resources/sr/JavaTimeSupplementary_sr.java \
|
||||
sun/text/resources/sr/JavaTimeSupplementary_sr_Latn.java \
|
||||
sun/text/resources/sv/JavaTimeSupplementary_sv.java \
|
||||
sun/text/resources/th/JavaTimeSupplementary_th.java \
|
||||
sun/text/resources/tr/JavaTimeSupplementary_tr.java \
|
||||
sun/text/resources/uk/JavaTimeSupplementary_uk.java \
|
||||
sun/text/resources/vi/JavaTimeSupplementary_vi.java \
|
||||
sun/text/resources/zh/JavaTimeSupplementary_zh.java \
|
||||
sun/text/resources/zh/JavaTimeSupplementary_zh_TW.java
|
||||
|
||||
|
||||
@ -42,7 +42,6 @@ BUILD_MANIFEST=true
|
||||
# Time zone data file creation
|
||||
#
|
||||
TZDATA_DIR := ../javazic/tzdata
|
||||
TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION))
|
||||
TZFILE := \
|
||||
africa antarctica asia australasia europe northamerica \
|
||||
pacificnew southamerica backward etcetera \
|
||||
@ -50,9 +49,7 @@ TZFILE := \
|
||||
|
||||
TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZFILE))
|
||||
|
||||
|
||||
|
||||
TZDB_JAR = tzdb.jar
|
||||
TZDB_DAT = $(LIBDIR)/tzdb.dat
|
||||
|
||||
#
|
||||
# Rules
|
||||
@ -62,13 +59,12 @@ include $(BUILDDIR)/common/Classes.gmk
|
||||
#
|
||||
# Add to the build rule
|
||||
#
|
||||
build: $(LIBDIR)/$(TZDB_JAR)
|
||||
build: $(TZDB_DAT)
|
||||
|
||||
$(LIBDIR)/$(TZDB_JAR): $(TZFILES)
|
||||
$(TZDB_DAT): $(TZFILES)
|
||||
$(prep-target)
|
||||
echo build tzdb from version $(TZDATA_VER)
|
||||
$(BOOT_JAVA_CMD) -jar $(BUILDTOOLJARDIR)/tzdb.jar \
|
||||
-version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(LIBDIR) $(TZFILE)
|
||||
-srcdir $(TZDATA_DIR) -dstfile $(TZDB_DAT) $(TZFILE)
|
||||
|
||||
clean clobber::
|
||||
$(RM) $(LIBDIR)/$(TZDB_JAR)
|
||||
$(RM) $(TZDB_DAT)
|
||||
|
||||
@ -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
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
package build.tools.cldrconverter;
|
||||
|
||||
import build.tools.cldrconverter.CLDRConverter.DraftType;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -88,7 +89,7 @@ abstract class AbstractLDMLHandler<V> extends DefaultHandler {
|
||||
}
|
||||
String draftValue = attributes.getValue("draft");
|
||||
if (draftValue != null) {
|
||||
return CLDRConverter.draftType > CLDRConverter.DRAFT_MAP.get(draftValue);
|
||||
return DraftType.getDefault().ordinal() > DraftType.forKeyword(draftValue).ordinal();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -266,6 +266,9 @@ class Bundle {
|
||||
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "DayNarrows");
|
||||
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "AmPmMarkers");
|
||||
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "narrow.AmPmMarkers");
|
||||
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "QuarterNames");
|
||||
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "QuarterAbbreviations");
|
||||
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "QuarterNarrows");
|
||||
|
||||
adjustEraNames(myMap, calendarType);
|
||||
|
||||
@ -484,25 +487,33 @@ class Bundle {
|
||||
for (String k : patternKeys) {
|
||||
if (myMap.containsKey(calendarPrefix + k)) {
|
||||
int len = patternKeys.length;
|
||||
List<String> rawPatterns = new ArrayList<>();
|
||||
List<String> patterns = new ArrayList<>();
|
||||
List<String> rawPatterns = new ArrayList<>(len);
|
||||
List<String> patterns = new ArrayList<>(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
String key = calendarPrefix + patternKeys[i];
|
||||
String pattern = (String) myMap.remove(key);
|
||||
if (pattern == null) {
|
||||
pattern = (String) parentsMap.remove(key);
|
||||
}
|
||||
rawPatterns.add(i, pattern);
|
||||
if (pattern != null) {
|
||||
rawPatterns.add(i, pattern);
|
||||
patterns.add(i, translateDateFormatLetters(calendarType, pattern));
|
||||
} else {
|
||||
patterns.add(i, null);
|
||||
}
|
||||
}
|
||||
// If patterns is empty or has any nulls, discard patterns.
|
||||
if (patterns.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (String p : patterns) {
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
String key = calendarPrefix + name;
|
||||
if (!rawPatterns.equals(patterns)) {
|
||||
myMap.put("cldr." + key, rawPatterns.toArray(new String[len]));
|
||||
myMap.put("java.time." + key, rawPatterns.toArray(new String[len]));
|
||||
}
|
||||
myMap.put(key, patterns.toArray(new String[len]));
|
||||
break;
|
||||
|
||||
@ -68,25 +68,43 @@ public class CLDRConverter {
|
||||
static MetaZonesParseHandler handlerMetaZones;
|
||||
private static BundleGenerator bundleGenerator;
|
||||
|
||||
static int draftType;
|
||||
private static final String DRAFT_UNCONFIRMED = "unconfirmed";
|
||||
private static final String DRAFT_PROVISIONAL = "provisional";
|
||||
private static final String DRAFT_CONTRIBUTED = "contributed";
|
||||
private static final String DRAFT_APPROVED = "approved";
|
||||
private static final String DRAFT_TRUE = "true";
|
||||
private static final String DRAFT_FALSE = "false";
|
||||
private static final String DRAFT_DEFAULT = DRAFT_APPROVED;
|
||||
static final Map<String, Integer> DRAFT_MAP = new HashMap<>();
|
||||
static enum DraftType {
|
||||
UNCONFIRMED,
|
||||
PROVISIONAL,
|
||||
CONTRIBUTED,
|
||||
APPROVED;
|
||||
|
||||
static {
|
||||
DRAFT_MAP.put(DRAFT_UNCONFIRMED, 0);
|
||||
DRAFT_MAP.put(DRAFT_PROVISIONAL, 1);
|
||||
DRAFT_MAP.put(DRAFT_CONTRIBUTED, 2);
|
||||
DRAFT_MAP.put(DRAFT_APPROVED, 3);
|
||||
DRAFT_MAP.put(DRAFT_TRUE, 0);
|
||||
DRAFT_MAP.put(DRAFT_FALSE, 2);
|
||||
draftType = DRAFT_MAP.get(DRAFT_DEFAULT);
|
||||
};
|
||||
private static final Map<String, DraftType> map = new HashMap<>();
|
||||
static {
|
||||
for (DraftType dt : values()) {
|
||||
map.put(dt.getKeyword(), dt);
|
||||
}
|
||||
}
|
||||
static private DraftType defaultType = CONTRIBUTED;
|
||||
|
||||
private final String keyword;
|
||||
|
||||
private DraftType() {
|
||||
keyword = this.name().toLowerCase(Locale.ROOT);
|
||||
|
||||
}
|
||||
|
||||
static DraftType forKeyword(String keyword) {
|
||||
return map.get(keyword);
|
||||
}
|
||||
|
||||
static DraftType getDefault() {
|
||||
return defaultType;
|
||||
}
|
||||
|
||||
static void setDefault(String keyword) {
|
||||
defaultType = Objects.requireNonNull(forKeyword(keyword));
|
||||
}
|
||||
|
||||
String getKeyword() {
|
||||
return keyword;
|
||||
}
|
||||
}
|
||||
|
||||
static boolean USE_UTF8 = false;
|
||||
private static boolean verbose;
|
||||
@ -106,7 +124,7 @@ public class CLDRConverter {
|
||||
case "-draft":
|
||||
String draftDataType = args[++i];
|
||||
try {
|
||||
draftType = DRAFT_MAP.get(draftDataType);
|
||||
DraftType.setDefault(draftDataType);
|
||||
} catch (NullPointerException e) {
|
||||
severe("Error: incorrect draft value: %s%n", draftDataType);
|
||||
System.exit(1);
|
||||
@ -525,7 +543,7 @@ public class CLDRConverter {
|
||||
"standalone.MonthNames",
|
||||
"MonthAbbreviations",
|
||||
"standalone.MonthAbbreviations",
|
||||
"MonthNarrow",
|
||||
"MonthNarrows",
|
||||
"standalone.MonthNarrows",
|
||||
"DayNames",
|
||||
"standalone.DayNames",
|
||||
@ -533,6 +551,12 @@ public class CLDRConverter {
|
||||
"standalone.DayAbbreviations",
|
||||
"DayNarrows",
|
||||
"standalone.DayNarrows",
|
||||
"QuarterNames",
|
||||
"standalone.QuarterNames",
|
||||
"QuarterAbbreviations",
|
||||
"standalone.QuarterAbbreviations",
|
||||
"QuarterNarrows",
|
||||
"standalone.QuarterNarrows",
|
||||
"AmPmMarkers",
|
||||
"narrow.AmPmMarkers",
|
||||
"long.Eras",
|
||||
@ -560,7 +584,7 @@ public class CLDRConverter {
|
||||
String prefix = calendarType.keyElementName();
|
||||
for (String element : FORMAT_DATA_ELEMENTS) {
|
||||
String key = prefix + element;
|
||||
copyIfPresent(map, "cldr." + key, formatData);
|
||||
copyIfPresent(map, "java.time." + key, formatData);
|
||||
copyIfPresent(map, key, formatData);
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,6 +356,44 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "quarterContext":
|
||||
{
|
||||
// for FormatData
|
||||
// need to keep stand-alone and format, to allow for inheritance in CLDR
|
||||
String type = attributes.getValue("type");
|
||||
if ("stand-alone".equals(type) || "format".equals(type)) {
|
||||
pushKeyContainer(qName, attributes, type);
|
||||
} else {
|
||||
pushIgnoredContainer(qName);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "quarterWidth":
|
||||
{
|
||||
// for FormatData
|
||||
// keep info about the context type so we can sort out inheritance later
|
||||
String prefix = (currentCalendarType == null) ? "" : currentCalendarType.keyElementName();
|
||||
switch (attributes.getValue("type")) {
|
||||
case "wide":
|
||||
pushStringArrayEntry(qName, attributes, prefix + "QuarterNames/" + getContainerKey(), 4);
|
||||
break;
|
||||
case "abbreviated":
|
||||
pushStringArrayEntry(qName, attributes, prefix + "QuarterAbbreviations/" + getContainerKey(), 4);
|
||||
break;
|
||||
case "narrow":
|
||||
pushStringArrayEntry(qName, attributes, prefix + "QuarterNarrows/" + getContainerKey(), 4);
|
||||
break;
|
||||
default:
|
||||
pushIgnoredContainer(qName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "quarter":
|
||||
// for FormatData
|
||||
// add to string array entry of quarterWidth element
|
||||
pushStringArrayElement(qName, attributes, Integer.parseInt(attributes.getValue("type")) - 1);
|
||||
break;
|
||||
|
||||
//
|
||||
// Time zone names
|
||||
|
||||
@ -58,12 +58,12 @@ package build.tools.tzdb;
|
||||
|
||||
import static build.tools.tzdb.Utils.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.ParsePosition;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -71,132 +71,131 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Scanner;
|
||||
import java.util.SortedMap;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.MatchResult;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A builder that can read the TZDB time-zone files and build {@code ZoneRules} instances.
|
||||
* A compiler that reads a set of TZDB time-zone files and builds a single
|
||||
* combined TZDB data file.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public final class TzdbZoneRulesCompiler {
|
||||
|
||||
private static final Matcher YEAR = Pattern.compile("(?i)(?<min>min)|(?<max>max)|(?<only>only)|(?<year>[0-9]+)").matcher("");
|
||||
private static final Matcher MONTH = Pattern.compile("(?i)(jan)|(feb)|(mar)|(apr)|(may)|(jun)|(jul)|(aug)|(sep)|(oct)|(nov)|(dec)").matcher("");
|
||||
private static final Matcher DOW = Pattern.compile("(?i)(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)").matcher("");
|
||||
private static final Matcher TIME = Pattern.compile("(?<neg>-)?+(?<hour>[0-9]{1,2})(:(?<minute>[0-5][0-9]))?+(:(?<second>[0-5][0-9]))?+").matcher("");
|
||||
|
||||
/**
|
||||
* Constant for MJD 1972-01-01.
|
||||
*/
|
||||
private static final long MJD_1972_01_01 = 41317L;
|
||||
|
||||
/**
|
||||
* Reads a set of TZDB files and builds a single combined data file.
|
||||
*
|
||||
* @param args the arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
new TzdbZoneRulesCompiler().compile(args);
|
||||
}
|
||||
|
||||
private void compile(String[] args) {
|
||||
if (args.length < 2) {
|
||||
outputHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
// parse args
|
||||
Path srcDir = null;
|
||||
Path dstFile = null;
|
||||
String version = null;
|
||||
File baseSrcDir = null;
|
||||
File dstDir = null;
|
||||
boolean verbose = false;
|
||||
|
||||
// parse options
|
||||
// parse args/options
|
||||
int i;
|
||||
for (i = 0; i < args.length; i++) {
|
||||
String arg = args[i];
|
||||
if (arg.startsWith("-") == false) {
|
||||
if (!arg.startsWith("-")) {
|
||||
break;
|
||||
}
|
||||
if ("-srcdir".equals(arg)) {
|
||||
if (baseSrcDir == null && ++i < args.length) {
|
||||
baseSrcDir = new File(args[i]);
|
||||
if (srcDir == null && ++i < args.length) {
|
||||
srcDir = Paths.get(args[i]);
|
||||
continue;
|
||||
}
|
||||
} else if ("-dstdir".equals(arg)) {
|
||||
if (dstDir == null && ++i < args.length) {
|
||||
dstDir = new File(args[i]);
|
||||
continue;
|
||||
}
|
||||
} else if ("-version".equals(arg)) {
|
||||
if (version == null && ++i < args.length) {
|
||||
version = args[i];
|
||||
} else if ("-dstfile".equals(arg)) {
|
||||
if (dstFile == null && ++i < args.length) {
|
||||
dstFile = Paths.get(args[i]);
|
||||
continue;
|
||||
}
|
||||
} else if ("-verbose".equals(arg)) {
|
||||
if (verbose == false) {
|
||||
if (!verbose) {
|
||||
verbose = true;
|
||||
continue;
|
||||
}
|
||||
} else if ("-help".equals(arg) == false) {
|
||||
} else if (!"-help".equals(arg)) {
|
||||
System.out.println("Unrecognised option: " + arg);
|
||||
}
|
||||
outputHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
// check source directory
|
||||
if (baseSrcDir == null) {
|
||||
System.out.println("Source directory must be specified using -srcdir: " + baseSrcDir);
|
||||
return;
|
||||
if (srcDir == null) {
|
||||
System.err.println("Source directory must be specified using -srcdir");
|
||||
System.exit(1);
|
||||
}
|
||||
if (baseSrcDir.isDirectory() == false) {
|
||||
System.out.println("Source does not exist or is not a directory: " + baseSrcDir);
|
||||
return;
|
||||
if (!Files.isDirectory(srcDir)) {
|
||||
System.err.println("Source does not exist or is not a directory: " + srcDir);
|
||||
System.exit(1);
|
||||
}
|
||||
dstDir = (dstDir != null ? dstDir : baseSrcDir);
|
||||
|
||||
// parse source file names
|
||||
List<String> srcFileNames = Arrays.asList(Arrays.copyOfRange(args, i, args.length));
|
||||
if (srcFileNames.isEmpty()) {
|
||||
System.out.println("Source filenames not specified, using default set");
|
||||
System.out.println("(africa antarctica asia australasia backward etcetera europe northamerica southamerica)");
|
||||
srcFileNames = Arrays.asList("africa", "antarctica", "asia", "australasia", "backward",
|
||||
"etcetera", "europe", "northamerica", "southamerica");
|
||||
if (i == args.length) {
|
||||
i = 0;
|
||||
args = new String[] {"africa", "antarctica", "asia", "australasia", "europe",
|
||||
"northamerica","southamerica", "backward", "etcetera" };
|
||||
System.out.println("Source filenames not specified, using default set ( ");
|
||||
for (String name : args) {
|
||||
System.out.printf(name + " ");
|
||||
}
|
||||
System.out.println(")");
|
||||
}
|
||||
|
||||
// find source directories to process
|
||||
List<File> srcDirs = new ArrayList<>();
|
||||
if (version != null) {
|
||||
// if the "version" specified, as in jdk repo, the "baseSrcDir" is
|
||||
// the "srcDir" that contains the tzdb data.
|
||||
srcDirs.add(baseSrcDir);
|
||||
} else {
|
||||
File[] dirs = baseSrcDir.listFiles();
|
||||
for (File dir : dirs) {
|
||||
if (dir.isDirectory() && dir.getName().matches("[12][0-9]{3}[A-Za-z0-9._-]+")) {
|
||||
srcDirs.add(dir);
|
||||
}
|
||||
// source files in this directory
|
||||
List<Path> srcFiles = new ArrayList<>();
|
||||
for (; i < args.length; i++) {
|
||||
Path file = srcDir.resolve(args[i]);
|
||||
if (Files.exists(file)) {
|
||||
srcFiles.add(file);
|
||||
} else {
|
||||
System.err.println("Source directory does not contain source file: " + args[i]);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
if (srcDirs.isEmpty()) {
|
||||
System.out.println("Source directory contains no valid source folders: " + baseSrcDir);
|
||||
return;
|
||||
// check destination file
|
||||
if (dstFile == null) {
|
||||
dstFile = srcDir.resolve("tzdb.dat");
|
||||
} else {
|
||||
Path parent = dstFile.getParent();
|
||||
if (parent != null && !Files.exists(parent)) {
|
||||
System.err.println("Destination directory does not exist: " + parent);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
// check destination directory
|
||||
if (dstDir.exists() == false && dstDir.mkdirs() == false) {
|
||||
System.out.println("Destination directory could not be created: " + dstDir);
|
||||
return;
|
||||
try {
|
||||
// get tzdb source version
|
||||
Matcher m = Pattern.compile("tzdata(?<ver>[0-9]{4}[A-z])")
|
||||
.matcher(new String(Files.readAllBytes(srcDir.resolve("VERSION")),
|
||||
"ISO-8859-1"));
|
||||
if (m.find()) {
|
||||
version = m.group("ver");
|
||||
} else {
|
||||
System.exit(1);
|
||||
System.err.println("Source directory does not contain file: VERSION");
|
||||
}
|
||||
printVerbose("Compiling TZDB version " + version);
|
||||
// parse source files
|
||||
for (Path file : srcFiles) {
|
||||
printVerbose("Parsing file: " + file);
|
||||
parseFile(file);
|
||||
}
|
||||
// build zone rules
|
||||
printVerbose("Building rules");
|
||||
buildZoneRules();
|
||||
// output to file
|
||||
printVerbose("Outputting tzdb file: " + dstFile);
|
||||
outputFile(dstFile, version, builtZones, links);
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Failed: " + ex.toString());
|
||||
ex.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
if (dstDir.isDirectory() == false) {
|
||||
System.out.println("Destination is not a directory: " + dstDir);
|
||||
return;
|
||||
}
|
||||
process(srcDirs, srcFileNames, dstDir, version, verbose);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@ -206,145 +205,35 @@ public final class TzdbZoneRulesCompiler {
|
||||
private static void outputHelp() {
|
||||
System.out.println("Usage: TzdbZoneRulesCompiler <options> <tzdb source filenames>");
|
||||
System.out.println("where options include:");
|
||||
System.out.println(" -srcdir <directory> Where to find source directories (required)");
|
||||
System.out.println(" -dstdir <directory> Where to output generated files (default srcdir)");
|
||||
System.out.println(" -version <version> Specify the version, such as 2009a (optional)");
|
||||
System.out.println(" -srcdir <directory> Where to find tzdb source directory (required)");
|
||||
System.out.println(" -dstfile <file> Where to output generated file (default srcdir/tzdb.dat)");
|
||||
System.out.println(" -help Print this usage message");
|
||||
System.out.println(" -verbose Output verbose information during compilation");
|
||||
System.out.println(" There must be one directory for each version in srcdir");
|
||||
System.out.println(" Each directory must have the name of the version, such as 2009a");
|
||||
System.out.println(" Each directory must contain the unpacked tzdb files, such as asia or europe");
|
||||
System.out.println(" Directories must match the regex [12][0-9][0-9][0-9][A-Za-z0-9._-]+");
|
||||
System.out.println(" There will be one jar file for each version and one combined jar in dstdir");
|
||||
System.out.println(" If the version is specified, only that version is processed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Process to create the jar files.
|
||||
*/
|
||||
private static void process(List<File> srcDirs, List<String> srcFileNames, File dstDir, String version, boolean verbose) {
|
||||
// build actual jar files
|
||||
Map<String, SortedMap<String, ZoneRules>> allBuiltZones = new TreeMap<>();
|
||||
Set<String> allRegionIds = new TreeSet<String>();
|
||||
Set<ZoneRules> allRules = new HashSet<ZoneRules>();
|
||||
Map<String, Map<String, String>> allLinks = new TreeMap<>();
|
||||
|
||||
for (File srcDir : srcDirs) {
|
||||
// source files in this directory
|
||||
List<File> srcFiles = new ArrayList<>();
|
||||
for (String srcFileName : srcFileNames) {
|
||||
File file = new File(srcDir, srcFileName);
|
||||
if (file.exists()) {
|
||||
srcFiles.add(file);
|
||||
}
|
||||
}
|
||||
if (srcFiles.isEmpty()) {
|
||||
continue; // nothing to process
|
||||
}
|
||||
|
||||
// compile
|
||||
String loopVersion = (srcDirs.size() == 1 && version != null)
|
||||
? version : srcDir.getName();
|
||||
TzdbZoneRulesCompiler compiler = new TzdbZoneRulesCompiler(loopVersion, srcFiles, verbose);
|
||||
try {
|
||||
// compile
|
||||
compiler.compile();
|
||||
SortedMap<String, ZoneRules> builtZones = compiler.getZones();
|
||||
|
||||
// output version-specific file
|
||||
File dstFile = version == null ? new File(dstDir, "tzdb" + loopVersion + ".jar")
|
||||
: new File(dstDir, "tzdb.jar");
|
||||
if (verbose) {
|
||||
System.out.println("Outputting file: " + dstFile);
|
||||
}
|
||||
outputFile(dstFile, loopVersion, builtZones, compiler.links);
|
||||
|
||||
// create totals
|
||||
allBuiltZones.put(loopVersion, builtZones);
|
||||
allRegionIds.addAll(builtZones.keySet());
|
||||
allRules.addAll(builtZones.values());
|
||||
allLinks.put(loopVersion, compiler.links);
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Failed: " + ex.toString());
|
||||
ex.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// output merged file
|
||||
if (version == null) {
|
||||
File dstFile = new File(dstDir, "tzdb-all.jar");
|
||||
if (verbose) {
|
||||
System.out.println("Outputting combined file: " + dstFile);
|
||||
}
|
||||
outputFile(dstFile, allBuiltZones, allRegionIds, allRules, allLinks);
|
||||
}
|
||||
System.out.println(" The source directory must contain the unpacked tzdb files, such as asia or europe");
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the file.
|
||||
*/
|
||||
private static void outputFile(File dstFile,
|
||||
String version,
|
||||
SortedMap<String, ZoneRules> builtZones,
|
||||
Map<String, String> links) {
|
||||
Map<String, SortedMap<String, ZoneRules>> loopAllBuiltZones = new TreeMap<>();
|
||||
loopAllBuiltZones.put(version, builtZones);
|
||||
Set<String> loopAllRegionIds = new TreeSet<String>(builtZones.keySet());
|
||||
Set<ZoneRules> loopAllRules = new HashSet<ZoneRules>(builtZones.values());
|
||||
Map<String, Map<String, String>> loopAllLinks = new TreeMap<>();
|
||||
loopAllLinks.put(version, links);
|
||||
outputFile(dstFile, loopAllBuiltZones, loopAllRegionIds, loopAllRules, loopAllLinks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the file.
|
||||
*/
|
||||
private static void outputFile(File dstFile,
|
||||
Map<String, SortedMap<String, ZoneRules>> allBuiltZones,
|
||||
Set<String> allRegionIds,
|
||||
Set<ZoneRules> allRules,
|
||||
Map<String, Map<String, String>> allLinks) {
|
||||
try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(dstFile))) {
|
||||
outputTZEntry(jos, allBuiltZones, allRegionIds, allRules, allLinks);
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Failed: " + ex.toString());
|
||||
ex.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the timezone entry in the JAR file.
|
||||
*/
|
||||
private static void outputTZEntry(JarOutputStream jos,
|
||||
Map<String, SortedMap<String, ZoneRules>> allBuiltZones,
|
||||
Set<String> allRegionIds,
|
||||
Set<ZoneRules> allRules,
|
||||
Map<String, Map<String, String>> allLinks) {
|
||||
// this format is not publicly specified
|
||||
try {
|
||||
jos.putNextEntry(new ZipEntry("TZDB.dat"));
|
||||
DataOutputStream out = new DataOutputStream(jos);
|
||||
|
||||
private void outputFile(Path dstFile, String version,
|
||||
SortedMap<String, ZoneRules> builtZones,
|
||||
Map<String, String> links) {
|
||||
try (DataOutputStream out = new DataOutputStream(Files.newOutputStream(dstFile))) {
|
||||
// file version
|
||||
out.writeByte(1);
|
||||
// group
|
||||
out.writeUTF("TZDB");
|
||||
// versions
|
||||
String[] versionArray = allBuiltZones.keySet().toArray(new String[allBuiltZones.size()]);
|
||||
out.writeShort(versionArray.length);
|
||||
for (String version : versionArray) {
|
||||
out.writeUTF(version);
|
||||
}
|
||||
out.writeShort(1);
|
||||
out.writeUTF(version);
|
||||
// regions
|
||||
String[] regionArray = allRegionIds.toArray(new String[allRegionIds.size()]);
|
||||
String[] regionArray = builtZones.keySet().toArray(new String[builtZones.size()]);
|
||||
out.writeShort(regionArray.length);
|
||||
for (String regionId : regionArray) {
|
||||
out.writeUTF(regionId);
|
||||
}
|
||||
// rules
|
||||
List<ZoneRules> rulesList = new ArrayList<>(allRules);
|
||||
// rules -- hashset -> remove the dup
|
||||
List<ZoneRules> rulesList = new ArrayList<>(new HashSet<>(builtZones.values()));
|
||||
out.writeShort(rulesList.size());
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
|
||||
for (ZoneRules rules : rulesList) {
|
||||
@ -357,27 +246,22 @@ public final class TzdbZoneRulesCompiler {
|
||||
out.write(bytes);
|
||||
}
|
||||
// link version-region-rules
|
||||
for (String version : allBuiltZones.keySet()) {
|
||||
out.writeShort(allBuiltZones.get(version).size());
|
||||
for (Map.Entry<String, ZoneRules> entry : allBuiltZones.get(version).entrySet()) {
|
||||
int regionIndex = Arrays.binarySearch(regionArray, entry.getKey());
|
||||
int rulesIndex = rulesList.indexOf(entry.getValue());
|
||||
out.writeShort(regionIndex);
|
||||
out.writeShort(rulesIndex);
|
||||
}
|
||||
out.writeShort(builtZones.size());
|
||||
for (Map.Entry<String, ZoneRules> entry : builtZones.entrySet()) {
|
||||
int regionIndex = Arrays.binarySearch(regionArray, entry.getKey());
|
||||
int rulesIndex = rulesList.indexOf(entry.getValue());
|
||||
out.writeShort(regionIndex);
|
||||
out.writeShort(rulesIndex);
|
||||
}
|
||||
// alias-region
|
||||
for (String version : allLinks.keySet()) {
|
||||
out.writeShort(allLinks.get(version).size());
|
||||
for (Map.Entry<String, String> entry : allLinks.get(version).entrySet()) {
|
||||
int aliasIndex = Arrays.binarySearch(regionArray, entry.getKey());
|
||||
int regionIndex = Arrays.binarySearch(regionArray, entry.getValue());
|
||||
out.writeShort(aliasIndex);
|
||||
out.writeShort(regionIndex);
|
||||
}
|
||||
out.writeShort(links.size());
|
||||
for (Map.Entry<String, String> entry : links.entrySet()) {
|
||||
int aliasIndex = Arrays.binarySearch(regionArray, entry.getKey());
|
||||
int regionIndex = Arrays.binarySearch(regionArray, entry.getValue());
|
||||
out.writeShort(aliasIndex);
|
||||
out.writeShort(regionIndex);
|
||||
}
|
||||
out.flush();
|
||||
jos.closeEntry();
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Failed: " + ex.toString());
|
||||
ex.printStackTrace();
|
||||
@ -385,76 +269,30 @@ public final class TzdbZoneRulesCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
private static final Pattern YEAR = Pattern.compile("(?i)(?<min>min)|(?<max>max)|(?<only>only)|(?<year>[0-9]+)");
|
||||
private static final Pattern MONTH = Pattern.compile("(?i)(jan)|(feb)|(mar)|(apr)|(may)|(jun)|(jul)|(aug)|(sep)|(oct)|(nov)|(dec)");
|
||||
private static final Matcher DOW = Pattern.compile("(?i)(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)").matcher("");
|
||||
private static final Matcher TIME = Pattern.compile("(?<neg>-)?+(?<hour>[0-9]{1,2})(:(?<minute>[0-5][0-9]))?+(:(?<second>[0-5][0-9]))?+").matcher("");
|
||||
|
||||
/** The TZDB rules. */
|
||||
private final Map<String, List<TZDBRule>> rules = new HashMap<>();
|
||||
|
||||
/** The TZDB zones. */
|
||||
private final Map<String, List<TZDBZone>> zones = new HashMap<>();
|
||||
/** The TZDB links. */
|
||||
|
||||
/** The TZDB links. */
|
||||
private final Map<String, String> links = new HashMap<>();
|
||||
|
||||
/** The built zones. */
|
||||
private final SortedMap<String, ZoneRules> builtZones = new TreeMap<>();
|
||||
|
||||
|
||||
/** The version to produce. */
|
||||
private final String version;
|
||||
|
||||
/** The source files. */
|
||||
|
||||
private final List<File> sourceFiles;
|
||||
|
||||
/** The version to produce. */
|
||||
private final boolean verbose;
|
||||
/** Whether to output verbose messages. */
|
||||
private boolean verbose;
|
||||
|
||||
/**
|
||||
* Creates an instance if you want to invoke the compiler manually.
|
||||
*
|
||||
* @param version the version, such as 2009a, not null
|
||||
* @param sourceFiles the list of source files, not empty, not null
|
||||
* @param verbose whether to output verbose messages
|
||||
* private contructor
|
||||
*/
|
||||
public TzdbZoneRulesCompiler(String version, List<File> sourceFiles, boolean verbose) {
|
||||
this.version = version;
|
||||
this.sourceFiles = sourceFiles;
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the rules file.
|
||||
* <p>
|
||||
* Use {@link #getZones()} to retrieve the parsed data.
|
||||
*
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
public void compile() throws Exception {
|
||||
printVerbose("Compiling TZDB version " + version);
|
||||
parseFiles();
|
||||
buildZoneRules();
|
||||
printVerbose("Compiled TZDB version " + version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parsed zone rules.
|
||||
*
|
||||
* @return the parsed zone rules, not null
|
||||
*/
|
||||
public SortedMap<String, ZoneRules> getZones() {
|
||||
return builtZones;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the source files.
|
||||
*
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
private void parseFiles() throws Exception {
|
||||
for (File file : sourceFiles) {
|
||||
printVerbose("Parsing file: " + file);
|
||||
parseFile(file);
|
||||
}
|
||||
private TzdbZoneRulesCompiler() {
|
||||
}
|
||||
|
||||
/**
|
||||
@ -463,14 +301,14 @@ public final class TzdbZoneRulesCompiler {
|
||||
* @param file the file being read, not null
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
private void parseFile(File file) throws Exception {
|
||||
private void parseFile(Path file) throws Exception {
|
||||
int lineNumber = 1;
|
||||
String line = null;
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
in = new BufferedReader(new FileReader(file));
|
||||
List<String> lines = Files.readAllLines(file, StandardCharsets.ISO_8859_1);
|
||||
List<TZDBZone> openZone = null;
|
||||
for ( ; (line = in.readLine()) != null; lineNumber++) {
|
||||
for (; lineNumber < lines.size(); lineNumber++) {
|
||||
line = lines.get(lineNumber);
|
||||
int index = line.indexOf('#'); // remove comments (doesn't handle # in quotes)
|
||||
if (index >= 0) {
|
||||
line = line.substring(0, index);
|
||||
@ -478,41 +316,43 @@ public final class TzdbZoneRulesCompiler {
|
||||
if (line.trim().length() == 0) { // ignore blank lines
|
||||
continue;
|
||||
}
|
||||
StringTokenizer st = new StringTokenizer(line, " \t");
|
||||
if (openZone != null && Character.isWhitespace(line.charAt(0)) && st.hasMoreTokens()) {
|
||||
if (parseZoneLine(st, openZone)) {
|
||||
Scanner s = new Scanner(line);
|
||||
if (openZone != null && Character.isWhitespace(line.charAt(0)) && s.hasNext()) {
|
||||
if (parseZoneLine(s, openZone)) {
|
||||
openZone = null;
|
||||
}
|
||||
} else {
|
||||
if (st.hasMoreTokens()) {
|
||||
String first = st.nextToken();
|
||||
if (s.hasNext()) {
|
||||
String first = s.next();
|
||||
if (first.equals("Zone")) {
|
||||
if (st.countTokens() < 3) {
|
||||
openZone = new ArrayList<>();
|
||||
try {
|
||||
zones.put(s.next(), openZone);
|
||||
if (parseZoneLine(s, openZone)) {
|
||||
openZone = null;
|
||||
}
|
||||
} catch (NoSuchElementException x) {
|
||||
printVerbose("Invalid Zone line in file: " + file + ", line: " + line);
|
||||
throw new IllegalArgumentException("Invalid Zone line");
|
||||
}
|
||||
openZone = new ArrayList<>();
|
||||
zones.put(st.nextToken(), openZone);
|
||||
if (parseZoneLine(st, openZone)) {
|
||||
openZone = null;
|
||||
}
|
||||
} else {
|
||||
openZone = null;
|
||||
if (first.equals("Rule")) {
|
||||
if (st.countTokens() < 9) {
|
||||
try {
|
||||
parseRuleLine(s);
|
||||
} catch (NoSuchElementException x) {
|
||||
printVerbose("Invalid Rule line in file: " + file + ", line: " + line);
|
||||
throw new IllegalArgumentException("Invalid Rule line");
|
||||
}
|
||||
parseRuleLine(st);
|
||||
|
||||
} else if (first.equals("Link")) {
|
||||
if (st.countTokens() < 2) {
|
||||
try {
|
||||
String realId = s.next();
|
||||
String aliasId = s.next();
|
||||
links.put(aliasId, realId);
|
||||
} catch (NoSuchElementException x) {
|
||||
printVerbose("Invalid Link line in file: " + file + ", line: " + line);
|
||||
throw new IllegalArgumentException("Invalid Link line");
|
||||
}
|
||||
String realId = st.nextToken();
|
||||
String aliasId = st.nextToken();
|
||||
links.put(aliasId, realId);
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown line");
|
||||
@ -522,52 +362,44 @@ public final class TzdbZoneRulesCompiler {
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new Exception("Failed while processing file '" + file + "' on line " + lineNumber + " '" + line + "'", ex);
|
||||
} finally {
|
||||
try {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// ignore NPE and IOE
|
||||
}
|
||||
throw new Exception("Failed while parsing file '" + file + "' on line " + lineNumber + " '" + line + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a Rule line.
|
||||
*
|
||||
* @param st the tokenizer, not null
|
||||
* @param s the line scanner, not null
|
||||
*/
|
||||
private void parseRuleLine(StringTokenizer st) {
|
||||
private void parseRuleLine(Scanner s) {
|
||||
TZDBRule rule = new TZDBRule();
|
||||
String name = st.nextToken();
|
||||
String name = s.next();
|
||||
if (rules.containsKey(name) == false) {
|
||||
rules.put(name, new ArrayList<TZDBRule>());
|
||||
}
|
||||
rules.get(name).add(rule);
|
||||
rule.startYear = parseYear(st.nextToken(), 0);
|
||||
rule.endYear = parseYear(st.nextToken(), rule.startYear);
|
||||
rule.startYear = parseYear(s, 0);
|
||||
rule.endYear = parseYear(s, rule.startYear);
|
||||
if (rule.startYear > rule.endYear) {
|
||||
throw new IllegalArgumentException("Year order invalid: " + rule.startYear + " > " + rule.endYear);
|
||||
}
|
||||
parseOptional(st.nextToken()); // type is unused
|
||||
parseMonthDayTime(st, rule);
|
||||
rule.savingsAmount = parsePeriod(st.nextToken());
|
||||
rule.text = parseOptional(st.nextToken());
|
||||
parseOptional(s.next()); // type is unused
|
||||
parseMonthDayTime(s, rule);
|
||||
rule.savingsAmount = parsePeriod(s.next());
|
||||
rule.text = parseOptional(s.next());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a Zone line.
|
||||
*
|
||||
* @param st the tokenizer, not null
|
||||
* @param s the line scanner, not null
|
||||
* @return true if the zone is complete
|
||||
*/
|
||||
private boolean parseZoneLine(StringTokenizer st, List<TZDBZone> zoneList) {
|
||||
private boolean parseZoneLine(Scanner s, List<TZDBZone> zoneList) {
|
||||
TZDBZone zone = new TZDBZone();
|
||||
zoneList.add(zone);
|
||||
zone.standardOffset = parseOffset(st.nextToken());
|
||||
String savingsRule = parseOptional(st.nextToken());
|
||||
zone.standardOffset = parseOffset(s.next());
|
||||
String savingsRule = parseOptional(s.next());
|
||||
if (savingsRule == null) {
|
||||
zone.fixedSavingsSecs = 0;
|
||||
zone.savingsRule = null;
|
||||
@ -580,11 +412,11 @@ public final class TzdbZoneRulesCompiler {
|
||||
zone.savingsRule = savingsRule;
|
||||
}
|
||||
}
|
||||
zone.text = st.nextToken();
|
||||
if (st.hasMoreTokens()) {
|
||||
zone.year = Integer.parseInt(st.nextToken());
|
||||
if (st.hasMoreTokens()) {
|
||||
parseMonthDayTime(st, zone);
|
||||
zone.text = s.next();
|
||||
if (s.hasNext()) {
|
||||
zone.year = Integer.parseInt(s.next());
|
||||
if (s.hasNext()) {
|
||||
parseMonthDayTime(s, zone);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
@ -595,13 +427,13 @@ public final class TzdbZoneRulesCompiler {
|
||||
/**
|
||||
* Parses a Rule line.
|
||||
*
|
||||
* @param st the tokenizer, not null
|
||||
* @param s the line scanner, not null
|
||||
* @param mdt the object to parse into, not null
|
||||
*/
|
||||
private void parseMonthDayTime(StringTokenizer st, TZDBMonthDayTime mdt) {
|
||||
mdt.month = parseMonth(st.nextToken());
|
||||
if (st.hasMoreTokens()) {
|
||||
String dayRule = st.nextToken();
|
||||
private void parseMonthDayTime(Scanner s, TZDBMonthDayTime mdt) {
|
||||
mdt.month = parseMonth(s);
|
||||
if (s.hasNext()) {
|
||||
String dayRule = s.next();
|
||||
if (dayRule.startsWith("last")) {
|
||||
mdt.dayOfMonth = -1;
|
||||
mdt.dayOfWeek = parseDayOfWeek(dayRule.substring(4));
|
||||
@ -621,8 +453,8 @@ public final class TzdbZoneRulesCompiler {
|
||||
}
|
||||
mdt.dayOfMonth = Integer.parseInt(dayRule);
|
||||
}
|
||||
if (st.hasMoreTokens()) {
|
||||
String timeStr = st.nextToken();
|
||||
if (s.hasNext()) {
|
||||
String timeStr = s.next();
|
||||
int secsOfDay = parseSecs(timeStr);
|
||||
if (secsOfDay == 86400) {
|
||||
mdt.endOfDay = true;
|
||||
@ -635,30 +467,43 @@ public final class TzdbZoneRulesCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
private int parseYear(String str, int defaultYear) {
|
||||
if (YEAR.reset(str).matches()) {
|
||||
if (YEAR.group("min") != null) {
|
||||
//return YEAR_MIN_VALUE;
|
||||
private int parseYear(Scanner s, int defaultYear) {
|
||||
if (s.hasNext(YEAR)) {
|
||||
s.next(YEAR);
|
||||
MatchResult mr = s.match();
|
||||
if (mr.group(1) != null) {
|
||||
return 1900; // systemv has min
|
||||
} else if (YEAR.group("max") != null) {
|
||||
} else if (mr.group(2) != null) {
|
||||
return YEAR_MAX_VALUE;
|
||||
} else if (YEAR.group("only") != null) {
|
||||
} else if (mr.group(3) != null) {
|
||||
return defaultYear;
|
||||
}
|
||||
return Integer.parseInt(YEAR.group("year"));
|
||||
return Integer.parseInt(mr.group(4));
|
||||
/*
|
||||
if (mr.group("min") != null) {
|
||||
//return YEAR_MIN_VALUE;
|
||||
return 1900; // systemv has min
|
||||
} else if (mr.group("max") != null) {
|
||||
return YEAR_MAX_VALUE;
|
||||
} else if (mr.group("only") != null) {
|
||||
return defaultYear;
|
||||
}
|
||||
return Integer.parseInt(mr.group("year"));
|
||||
*/
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown year: " + str);
|
||||
throw new IllegalArgumentException("Unknown year: " + s.next());
|
||||
}
|
||||
|
||||
private int parseMonth(String str) {
|
||||
if (MONTH.reset(str).matches()) {
|
||||
private int parseMonth(Scanner s) {
|
||||
if (s.hasNext(MONTH)) {
|
||||
s.next(MONTH);
|
||||
for (int moy = 1; moy < 13; moy++) {
|
||||
if (MONTH.group(moy) != null) {
|
||||
if (s.match().group(moy) != null) {
|
||||
return moy;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown month: " + str);
|
||||
throw new IllegalArgumentException("Unknown month: " + s.next());
|
||||
}
|
||||
|
||||
private int parseDayOfWeek(String str) {
|
||||
@ -729,7 +574,6 @@ public final class TzdbZoneRulesCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Build the rules, zones and links into real zones.
|
||||
*
|
||||
@ -744,8 +588,7 @@ public final class TzdbZoneRulesCompiler {
|
||||
for (TZDBZone tzdbZone : tzdbZones) {
|
||||
bld = tzdbZone.addToBuilder(bld, rules);
|
||||
}
|
||||
ZoneRules buildRules = bld.toRules(zoneId);
|
||||
builtZones.put(zoneId, buildRules);
|
||||
builtZones.put(zoneId, bld.toRules(zoneId));
|
||||
}
|
||||
|
||||
// build aliases
|
||||
@ -758,25 +601,25 @@ public final class TzdbZoneRulesCompiler {
|
||||
printVerbose("Relinking alias " + aliasId + " to " + realId);
|
||||
realRules = builtZones.get(realId);
|
||||
if (realRules == null) {
|
||||
throw new IllegalArgumentException("Alias '" + aliasId + "' links to invalid zone '" + realId + "' for '" + version + "'");
|
||||
throw new IllegalArgumentException("Alias '" + aliasId + "' links to invalid zone '" + realId);
|
||||
}
|
||||
links.put(aliasId, realId);
|
||||
|
||||
}
|
||||
builtZones.put(aliasId, realRules);
|
||||
}
|
||||
|
||||
// remove UTC and GMT
|
||||
//builtZones.remove("UTC");
|
||||
//builtZones.remove("GMT");
|
||||
//builtZones.remove("GMT0");
|
||||
// builtZones.remove("UTC");
|
||||
// builtZones.remove("GMT");
|
||||
// builtZones.remove("GMT0");
|
||||
builtZones.remove("GMT+0");
|
||||
builtZones.remove("GMT-0");
|
||||
links.remove("GMT+0");
|
||||
links.remove("GMT-0");
|
||||
// remove ROC, which is not supported in j.u.tz
|
||||
builtZones.remove("ROC");
|
||||
links.remove("ROC");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Prints a verbose message.
|
||||
*
|
||||
@ -788,7 +631,6 @@ public final class TzdbZoneRulesCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Class representing a month-day-time in the TZDB file.
|
||||
*/
|
||||
@ -893,5 +735,4 @@ public final class TzdbZoneRulesCompiler {
|
||||
return ldt;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -174,6 +174,13 @@ $(LIBDIR)/calendars.properties: $(CALENDARS_SRC)/calendars.properties
|
||||
|
||||
COPY_FILES += $(LIBDIR)/calendars.properties
|
||||
|
||||
$(LIBDIR)/hijrah-config-umalqura.properties: $(CALENDARS_SRC)/hijrah-config-umalqura.properties
|
||||
$(MKDIR) -p $(@D)
|
||||
$(RM) $@
|
||||
$(CP) $< $@
|
||||
|
||||
COPY_FILES += $(LIBDIR)/hijrah-config-umalqura.properties
|
||||
|
||||
##########################################################################################
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS),windows)
|
||||
|
||||
@ -73,11 +73,6 @@ $(eval $(call SetupArchive,BUILD_DNS_JAR,,\
|
||||
|
||||
##########################################################################################
|
||||
|
||||
$(IMAGES_OUTPUTDIR)/lib/tzdb.jar: $(JDK_OUTPUTDIR)/lib/tzdb.jar
|
||||
$(install-file)
|
||||
|
||||
##########################################################################################
|
||||
|
||||
LOCALEDATA_INCLUDE_LOCALES := ar be bg ca cs da de el es et fi fr ga hi hr hu in is it \
|
||||
iw ja ko lt lv mk ms mt nl no pl pt ro ru sk sl sq sr sv \
|
||||
th tr uk vi zh
|
||||
|
||||
@ -29,16 +29,13 @@ GENDATA_TZDB :=
|
||||
# Time zone data file creation
|
||||
#
|
||||
TZDATA_DIR := $(JDK_TOPDIR)/make/sun/javazic/tzdata
|
||||
TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION))
|
||||
TZDATA_TZFILE := africa antarctica asia australasia europe northamerica pacificnew southamerica backward etcetera gmt jdk11_backward
|
||||
TZDATA_TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZDATA_TZFILE))
|
||||
|
||||
GENDATA_TZDB_DST := $(JDK_OUTPUTDIR)/lib
|
||||
GENDATA_TZDB_JAR := tzdb.jar
|
||||
GENDATA_TZDB_DAT := $(JDK_OUTPUTDIR)/lib/tzdb.dat
|
||||
|
||||
$(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR) : $(TZDATA_TZFILES)
|
||||
$(RM) $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR)
|
||||
echo building tzdb from version $(TZDATA_VER)
|
||||
$(TOOL_TZDB) -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(GENDATA_TZDB_DST) $(TZDATA_TZFILE)
|
||||
$(GENDATA_TZDB_DAT) : $(TZDATA_TZFILES)
|
||||
$(RM) $(GENDATA_TZDB_DAT)
|
||||
$(TOOL_TZDB) -srcdir $(TZDATA_DIR) -dstfile $(GENDATA_TZDB_DAT) $(TZDATA_TZFILE)
|
||||
|
||||
GENDATA_TZDB += $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR)
|
||||
GENDATA_TZDB += $(GENDATA_TZDB_DAT)
|
||||
|
||||
@ -134,7 +134,6 @@ SUNWprivate_1.1 {
|
||||
Java_java_lang_ClassLoader_00024NativeLibrary_load;
|
||||
Java_java_lang_ClassLoader_00024NativeLibrary_unload;
|
||||
Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib;
|
||||
Java_java_lang_ClassLoader_getCaller;
|
||||
Java_java_lang_ClassLoader_registerNatives;
|
||||
Java_java_lang_Compiler_registerNatives;
|
||||
Java_java_lang_Double_longBitsToDouble;
|
||||
@ -217,7 +216,7 @@ SUNWprivate_1.1 {
|
||||
Java_java_lang_Throwable_fillInStackTrace;
|
||||
Java_java_lang_Throwable_getStackTraceDepth;
|
||||
Java_java_lang_Throwable_getStackTraceElement;
|
||||
Java_java_lang_UNIXProcess_initIDs;
|
||||
Java_java_lang_UNIXProcess_init;
|
||||
Java_java_lang_UNIXProcess_waitForProcessExit;
|
||||
Java_java_lang_UNIXProcess_forkAndExec;
|
||||
Java_java_lang_UNIXProcess_destroyProcess;
|
||||
@ -233,7 +232,6 @@ SUNWprivate_1.1 {
|
||||
Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2Ljava_security_AccessControlContext_2;
|
||||
Java_java_security_AccessController_getStackAccessControlContext;
|
||||
Java_java_security_AccessController_getInheritedAccessControlContext;
|
||||
Java_java_util_ResourceBundle_getClassContext;
|
||||
Java_java_util_TimeZone_getSystemTimeZoneID;
|
||||
Java_java_util_TimeZone_getSystemGMTOffsetID;
|
||||
Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8;
|
||||
|
||||
@ -78,7 +78,6 @@ text: .text%writeBytes;
|
||||
# Test Sleep
|
||||
# Test IntToString
|
||||
# Test LoadToolkit
|
||||
text: .text%Java_java_util_ResourceBundle_getClassContext;
|
||||
text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
|
||||
text: .text%JNU_GetEnv;
|
||||
text: .text%Java_java_io_UnixFileSystem_checkAccess;
|
||||
|
||||
@ -74,7 +74,6 @@ text: .text%writeBytes;
|
||||
# Test Sleep
|
||||
# Test IntToString
|
||||
# Test LoadToolkit
|
||||
text: .text%Java_java_util_ResourceBundle_getClassContext;
|
||||
text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
|
||||
text: .text%JNU_GetEnv;
|
||||
text: .text%Java_java_io_UnixFileSystem_checkAccess;
|
||||
|
||||
@ -73,7 +73,6 @@ text: .text%writeBytes;
|
||||
# Test Sleep
|
||||
# Test IntToString
|
||||
# Test LoadToolkit
|
||||
text: .text%Java_java_util_ResourceBundle_getClassContext;
|
||||
text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
|
||||
text: .text%JNU_GetEnv;
|
||||
text: .text%Java_java_io_UnixFileSystem_checkAccess;
|
||||
|
||||
@ -66,6 +66,7 @@ PROFILE_1_JRE_LIB_FILES := \
|
||||
ext/sunec.jar \
|
||||
ext/sunjce_provider.jar \
|
||||
ext/sunpkcs11.jar \
|
||||
hijrah-config-umalqura.properties \
|
||||
jce.jar \
|
||||
jsse.jar \
|
||||
logging.properties \
|
||||
@ -80,7 +81,7 @@ PROFILE_1_JRE_LIB_FILES := \
|
||||
security/java.security \
|
||||
security/local_policy.jar \
|
||||
security/trusted.libraries \
|
||||
tzdb.jar
|
||||
tzdb.dat
|
||||
|
||||
PROFILE_1_JRE_OTHER_FILES := \
|
||||
COPYRIGHT \
|
||||
@ -100,9 +101,7 @@ PROFILE_1_JRE_JAR_FILES := \
|
||||
resources.jar \
|
||||
rt.jar \
|
||||
security/US_export_policy.jar \
|
||||
security/local_policy.jar \
|
||||
tzdb.jar
|
||||
|
||||
security/local_policy.jar
|
||||
|
||||
PROFILE_2_JRE_BIN_FILES := \
|
||||
rmid$(EXE_SUFFIX) \
|
||||
|
||||
@ -170,7 +170,7 @@ public class LWWindowPeer
|
||||
setTitle(((Dialog) getTarget()).getTitle());
|
||||
}
|
||||
|
||||
setAlwaysOnTop(getTarget().isAlwaysOnTop());
|
||||
updateAlwaysOnTopState();
|
||||
updateMinimumSize();
|
||||
|
||||
final Shape shape = getTarget().getShape();
|
||||
@ -357,8 +357,8 @@ public class LWWindowPeer
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlwaysOnTop(boolean value) {
|
||||
platformWindow.setAlwaysOnTop(value);
|
||||
public void updateAlwaysOnTopState() {
|
||||
platformWindow.setAlwaysOnTop(getTarget().isAlwaysOnTop());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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
|
||||
@ -180,7 +180,7 @@ class CFileDialog implements FileDialogPeer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlwaysOnTop(boolean alwaysOnTop) {
|
||||
public void updateAlwaysOnTopState() {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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
|
||||
@ -87,7 +87,7 @@ public class CPrinterDialogPeer extends LWWindowPeer {
|
||||
}
|
||||
|
||||
// 1.6 peer method
|
||||
public void setAlwaysOnTop(boolean value) {
|
||||
public void updateAlwaysOnTopState() {
|
||||
// no-op, since we just show the native print dialog
|
||||
}
|
||||
|
||||
|
||||
@ -426,17 +426,13 @@ final class CipherCore {
|
||||
}
|
||||
}
|
||||
try {
|
||||
params = AlgorithmParameters.getInstance(algName, "SunJCE");
|
||||
params = AlgorithmParameters.getInstance(algName,
|
||||
SunJCE.getInstance());
|
||||
params.init(spec);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
// should never happen
|
||||
throw new RuntimeException("Cannot find " + algName +
|
||||
" AlgorithmParameters implementation in SunJCE provider");
|
||||
} catch (NoSuchProviderException nspe) {
|
||||
// should never happen
|
||||
throw new RuntimeException("Cannot find SunJCE provider");
|
||||
}
|
||||
try {
|
||||
params.init(spec);
|
||||
} catch (InvalidParameterSpecException ipse) {
|
||||
// should never happen
|
||||
throw new RuntimeException(spec.getClass() + " not supported");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2007, 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
|
||||
@ -169,7 +169,8 @@ public abstract class CipherWithWrappingSpi extends CipherSpi {
|
||||
|
||||
try {
|
||||
KeyFactory keyFactory =
|
||||
KeyFactory.getInstance(encodedKeyAlgorithm, "SunJCE");
|
||||
KeyFactory.getInstance(encodedKeyAlgorithm,
|
||||
SunJCE.getInstance());
|
||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
|
||||
key = keyFactory.generatePublic(keySpec);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
@ -191,8 +192,6 @@ public abstract class CipherWithWrappingSpi extends CipherSpi {
|
||||
}
|
||||
} catch (InvalidKeySpecException ikse) {
|
||||
// Should never happen.
|
||||
} catch (NoSuchProviderException nspe) {
|
||||
// Should never happen.
|
||||
}
|
||||
|
||||
return key;
|
||||
@ -215,7 +214,8 @@ public abstract class CipherWithWrappingSpi extends CipherSpi {
|
||||
|
||||
try {
|
||||
KeyFactory keyFactory =
|
||||
KeyFactory.getInstance(encodedKeyAlgorithm, "SunJCE");
|
||||
KeyFactory.getInstance(encodedKeyAlgorithm,
|
||||
SunJCE.getInstance());
|
||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
|
||||
return keyFactory.generatePrivate(keySpec);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
@ -237,8 +237,6 @@ public abstract class CipherWithWrappingSpi extends CipherSpi {
|
||||
}
|
||||
} catch (InvalidKeySpecException ikse) {
|
||||
// Should never happen.
|
||||
} catch (NoSuchProviderException nspe) {
|
||||
// Should never happen.
|
||||
}
|
||||
|
||||
return key;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2007, 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
|
||||
@ -30,7 +30,6 @@ import java.security.PublicKey;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
@ -66,7 +65,8 @@ final class ConstructKeys {
|
||||
|
||||
try {
|
||||
KeyFactory keyFactory =
|
||||
KeyFactory.getInstance(encodedKeyAlgorithm, "SunJCE");
|
||||
KeyFactory.getInstance(encodedKeyAlgorithm,
|
||||
SunJCE.getInstance());
|
||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
|
||||
key = keyFactory.generatePublic(keySpec);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
@ -94,8 +94,6 @@ final class ConstructKeys {
|
||||
new InvalidKeyException("Cannot construct public key");
|
||||
ike.initCause(ikse);
|
||||
throw ike;
|
||||
} catch (NoSuchProviderException nspe) {
|
||||
// Should never happen.
|
||||
}
|
||||
|
||||
return key;
|
||||
@ -118,7 +116,8 @@ final class ConstructKeys {
|
||||
|
||||
try {
|
||||
KeyFactory keyFactory =
|
||||
KeyFactory.getInstance(encodedKeyAlgorithm, "SunJCE");
|
||||
KeyFactory.getInstance(encodedKeyAlgorithm,
|
||||
SunJCE.getInstance());
|
||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
|
||||
return keyFactory.generatePrivate(keySpec);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
@ -146,8 +145,6 @@ final class ConstructKeys {
|
||||
new InvalidKeyException("Cannot construct private key");
|
||||
ike.initCause(ikse);
|
||||
throw ike;
|
||||
} catch (NoSuchProviderException nspe) {
|
||||
// Should never happen.
|
||||
}
|
||||
|
||||
return key;
|
||||
|
||||
@ -389,17 +389,13 @@ public final class DESedeWrapCipher extends CipherSpi {
|
||||
if (iv != null) {
|
||||
String algo = cipherKey.getAlgorithm();
|
||||
try {
|
||||
params = AlgorithmParameters.getInstance(algo, "SunJCE");
|
||||
params = AlgorithmParameters.getInstance(algo,
|
||||
SunJCE.getInstance());
|
||||
params.init(new IvParameterSpec(iv));
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
// should never happen
|
||||
throw new RuntimeException("Cannot find " + algo +
|
||||
" AlgorithmParameters implementation in SunJCE provider");
|
||||
} catch (NoSuchProviderException nspe) {
|
||||
// should never happen
|
||||
throw new RuntimeException("Cannot find SunJCE provider");
|
||||
}
|
||||
try {
|
||||
params.init(new IvParameterSpec(iv));
|
||||
} catch (InvalidParameterSpecException ipse) {
|
||||
// should never happen
|
||||
throw new RuntimeException("IvParameterSpec not supported");
|
||||
|
||||
@ -151,7 +151,8 @@ extends AlgorithmParameterGeneratorSpi {
|
||||
dhParamSpec = new DHParameterSpec(dsaParamSpec.getP(),
|
||||
dsaParamSpec.getG());
|
||||
}
|
||||
algParams = AlgorithmParameters.getInstance("DH", "SunJCE");
|
||||
algParams = AlgorithmParameters.getInstance("DH",
|
||||
SunJCE.getInstance());
|
||||
algParams.init(dhParamSpec);
|
||||
} catch (InvalidParameterSpecException e) {
|
||||
// this should never happen
|
||||
@ -159,11 +160,7 @@ extends AlgorithmParameterGeneratorSpi {
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// this should never happen, because we provide it
|
||||
throw new RuntimeException(e.getMessage());
|
||||
} catch (NoSuchProviderException e) {
|
||||
// this should never happen, because we provide it
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
|
||||
return algParams;
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,8 +81,6 @@ final class KeyProtector {
|
||||
// key protector
|
||||
private char[] password;
|
||||
|
||||
private static final Provider PROV = Security.getProvider("SunJCE");
|
||||
|
||||
KeyProtector(char[] password) {
|
||||
if (password == null) {
|
||||
throw new IllegalArgumentException("password can't be null");
|
||||
@ -119,7 +117,7 @@ final class KeyProtector {
|
||||
// wrap encrypted private key in EncryptedPrivateKeyInfo
|
||||
// (as defined in PKCS#8)
|
||||
AlgorithmParameters pbeParams =
|
||||
AlgorithmParameters.getInstance("PBE", PROV);
|
||||
AlgorithmParameters.getInstance("PBE", SunJCE.getInstance());
|
||||
pbeParams.init(pbeSpec);
|
||||
|
||||
AlgorithmId encrAlg = new AlgorithmId
|
||||
@ -299,7 +297,7 @@ final class KeyProtector {
|
||||
|
||||
PBEWithMD5AndTripleDESCipher cipherSpi;
|
||||
cipherSpi = new PBEWithMD5AndTripleDESCipher();
|
||||
cipher = new CipherForKeyProtector(cipherSpi, PROV,
|
||||
cipher = new CipherForKeyProtector(cipherSpi, SunJCE.getInstance(),
|
||||
"PBEWithMD5AndTripleDES");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, sKey, pbeSpec);
|
||||
return new SealedObjectForKeyProtector(key, cipher);
|
||||
@ -330,8 +328,9 @@ final class KeyProtector {
|
||||
}
|
||||
PBEWithMD5AndTripleDESCipher cipherSpi;
|
||||
cipherSpi = new PBEWithMD5AndTripleDESCipher();
|
||||
Cipher cipher = new CipherForKeyProtector(cipherSpi, PROV,
|
||||
"PBEWithMD5AndTripleDES");
|
||||
Cipher cipher = new CipherForKeyProtector(cipherSpi,
|
||||
SunJCE.getInstance(),
|
||||
"PBEWithMD5AndTripleDES");
|
||||
cipher.init(Cipher.DECRYPT_MODE, skey, params);
|
||||
return (Key)soForKeyProtector.getObject(cipher);
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
|
||||
@ -169,16 +169,12 @@ final class PBECipherCore {
|
||||
PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount);
|
||||
try {
|
||||
params = AlgorithmParameters.getInstance("PBEWithMD5And" +
|
||||
(algo.equalsIgnoreCase("DES")? "DES":"TripleDES"), "SunJCE");
|
||||
(algo.equalsIgnoreCase("DES")? "DES":"TripleDES"),
|
||||
SunJCE.getInstance());
|
||||
params.init(pbeSpec);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
// should never happen
|
||||
throw new RuntimeException("SunJCE called, but not configured");
|
||||
} catch (NoSuchProviderException nspe) {
|
||||
// should never happen
|
||||
throw new RuntimeException("SunJCE called, but not configured");
|
||||
}
|
||||
try {
|
||||
params.init(pbeSpec);
|
||||
} catch (InvalidParameterSpecException ipse) {
|
||||
// should never happen
|
||||
throw new RuntimeException("PBEParameterSpec not supported");
|
||||
|
||||
@ -169,16 +169,12 @@ final class PBES1Core {
|
||||
PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount);
|
||||
try {
|
||||
params = AlgorithmParameters.getInstance("PBEWithMD5And" +
|
||||
(algo.equalsIgnoreCase("DES")? "DES":"TripleDES"), "SunJCE");
|
||||
(algo.equalsIgnoreCase("DES")? "DES":"TripleDES"),
|
||||
SunJCE.getInstance());
|
||||
params.init(pbeSpec);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
// should never happen
|
||||
throw new RuntimeException("SunJCE called, but not configured");
|
||||
} catch (NoSuchProviderException nspe) {
|
||||
// should never happen
|
||||
throw new RuntimeException("SunJCE called, but not configured");
|
||||
}
|
||||
try {
|
||||
params.init(pbeSpec);
|
||||
} catch (InvalidParameterSpecException ipse) {
|
||||
// should never happen
|
||||
throw new RuntimeException("PBEParameterSpec not supported");
|
||||
|
||||
@ -25,11 +25,9 @@
|
||||
|
||||
package com.sun.crypto.provider;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.*;
|
||||
import java.security.spec.*;
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.interfaces.*;
|
||||
import javax.crypto.spec.*;
|
||||
|
||||
/**
|
||||
@ -145,16 +143,12 @@ abstract class PBES2Core extends CipherSpi {
|
||||
}
|
||||
PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount, ivSpec);
|
||||
try {
|
||||
params = AlgorithmParameters.getInstance(pbeAlgo, "SunJCE");
|
||||
params = AlgorithmParameters.getInstance(pbeAlgo,
|
||||
SunJCE.getInstance());
|
||||
params.init(pbeSpec);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
// should never happen
|
||||
throw new RuntimeException("SunJCE called, but not configured");
|
||||
} catch (NoSuchProviderException nspe) {
|
||||
// should never happen
|
||||
throw new RuntimeException("SunJCE called, but not configured");
|
||||
}
|
||||
try {
|
||||
params.init(pbeSpec);
|
||||
} catch (InvalidParameterSpecException ipse) {
|
||||
// should never happen
|
||||
throw new RuntimeException("PBEParameterSpec not supported");
|
||||
|
||||
@ -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.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -33,7 +33,6 @@ import java.util.Arrays;
|
||||
import java.security.KeyRep;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
@ -102,21 +101,16 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
|
||||
int keyLength = keySpec.getKeyLength();
|
||||
if (keyLength == 0) {
|
||||
throw new InvalidKeySpecException("Key length not found");
|
||||
} else if (keyLength == 0) {
|
||||
} else if (keyLength < 0) {
|
||||
throw new InvalidKeySpecException("Key length is negative");
|
||||
}
|
||||
try {
|
||||
this.prf = Mac.getInstance(prfAlgo, "SunJCE");
|
||||
this.prf = Mac.getInstance(prfAlgo, SunJCE.getInstance());
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
// not gonna happen; re-throw just in case
|
||||
InvalidKeySpecException ike = new InvalidKeySpecException();
|
||||
ike.initCause(nsae);
|
||||
throw ike;
|
||||
} catch (NoSuchProviderException nspe) {
|
||||
// Again, not gonna happen; re-throw just in case
|
||||
InvalidKeySpecException ike = new InvalidKeySpecException();
|
||||
ike.initCause(nspe);
|
||||
throw ike;
|
||||
}
|
||||
this.key = deriveKey(prf, passwdBytes, salt, iterCount, keyLength);
|
||||
}
|
||||
|
||||
@ -25,7 +25,6 @@
|
||||
|
||||
package com.sun.crypto.provider;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.spec.*;
|
||||
@ -232,14 +231,13 @@ final class PKCS12PBECipherCore {
|
||||
}
|
||||
PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount);
|
||||
try {
|
||||
params = AlgorithmParameters.getInstance(pbeAlgo, "SunJCE");
|
||||
} catch (GeneralSecurityException gse) {
|
||||
params = AlgorithmParameters.getInstance(pbeAlgo,
|
||||
SunJCE.getInstance());
|
||||
params.init(pbeSpec);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
// should never happen
|
||||
throw new RuntimeException(
|
||||
"SunJCE provider is not configured properly");
|
||||
}
|
||||
try {
|
||||
params.init(pbeSpec);
|
||||
} catch (InvalidParameterSpecException ipse) {
|
||||
// should never happen
|
||||
throw new RuntimeException("PBEParameterSpec not supported");
|
||||
|
||||
@ -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
|
||||
@ -178,16 +178,14 @@ public final class RSACipher extends CipherSpi {
|
||||
if (spec != null) {
|
||||
try {
|
||||
AlgorithmParameters params =
|
||||
AlgorithmParameters.getInstance("OAEP", "SunJCE");
|
||||
AlgorithmParameters.getInstance("OAEP",
|
||||
SunJCE.getInstance());
|
||||
params.init(spec);
|
||||
return params;
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
// should never happen
|
||||
throw new RuntimeException("Cannot find OAEP " +
|
||||
" AlgorithmParameters implementation in SunJCE provider");
|
||||
} catch (NoSuchProviderException nspe) {
|
||||
// should never happen
|
||||
throw new RuntimeException("Cannot find SunJCE provider");
|
||||
} catch (InvalidParameterSpecException ipse) {
|
||||
// should never happen
|
||||
throw new RuntimeException("OAEPParameterSpec not supported");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 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
|
||||
@ -46,14 +46,15 @@ final class SealedObjectForKeyProtector extends SealedObject {
|
||||
AlgorithmParameters params = null;
|
||||
if (super.encodedParams != null) {
|
||||
try {
|
||||
params = AlgorithmParameters.getInstance("PBE", "SunJCE");
|
||||
params = AlgorithmParameters.getInstance("PBE",
|
||||
SunJCE.getInstance());
|
||||
params.init(super.encodedParams);
|
||||
} catch (NoSuchProviderException nspe) {
|
||||
// eat.
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
//eat.
|
||||
} catch (IOException ioe) {
|
||||
//eat.
|
||||
throw new RuntimeException(
|
||||
"SunJCE provider is not configured properly");
|
||||
} catch (IOException io) {
|
||||
throw new RuntimeException("Parameter failure: "+
|
||||
io.getMessage());
|
||||
}
|
||||
}
|
||||
return params;
|
||||
|
||||
@ -91,6 +91,10 @@ public final class SunJCE extends Provider {
|
||||
/* Are we debugging? -- for developers */
|
||||
static final boolean debug = false;
|
||||
|
||||
// Instance of this provider, so we don't have to call the provider list
|
||||
// to find ourselves or run the risk of not being in the list.
|
||||
private static volatile SunJCE instance = null;
|
||||
|
||||
// lazy initialize SecureRandom to avoid potential recursion if Sun
|
||||
// provider has not been installed yet
|
||||
private static class SecureRandomHolder {
|
||||
@ -770,5 +774,17 @@ public final class SunJCE extends Provider {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
if (instance == null) {
|
||||
instance = this;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the instance of this class or create one if needed.
|
||||
static SunJCE getInstance() {
|
||||
if (instance == null) {
|
||||
return new SunJCE();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -165,16 +165,18 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
|
||||
// partition keyblock into individual secrets
|
||||
|
||||
int ofs = 0;
|
||||
byte[] tmp = new byte[macLength];
|
||||
if (macLength != 0) {
|
||||
byte[] tmp = new byte[macLength];
|
||||
|
||||
// mac keys
|
||||
System.arraycopy(keyBlock, ofs, tmp, 0, macLength);
|
||||
ofs += macLength;
|
||||
clientMacKey = new SecretKeySpec(tmp, "Mac");
|
||||
// mac keys
|
||||
System.arraycopy(keyBlock, ofs, tmp, 0, macLength);
|
||||
ofs += macLength;
|
||||
clientMacKey = new SecretKeySpec(tmp, "Mac");
|
||||
|
||||
System.arraycopy(keyBlock, ofs, tmp, 0, macLength);
|
||||
ofs += macLength;
|
||||
serverMacKey = new SecretKeySpec(tmp, "Mac");
|
||||
System.arraycopy(keyBlock, ofs, tmp, 0, macLength);
|
||||
ofs += macLength;
|
||||
serverMacKey = new SecretKeySpec(tmp, "Mac");
|
||||
}
|
||||
|
||||
if (keyLength == 0) { // SSL_RSA_WITH_NULL_* ciphersuites
|
||||
return new TlsKeyMaterialSpec(clientMacKey, serverMacKey);
|
||||
@ -198,7 +200,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
|
||||
|
||||
// IV keys if needed.
|
||||
if (ivLength != 0) {
|
||||
tmp = new byte[ivLength];
|
||||
byte[] tmp = new byte[ivLength];
|
||||
|
||||
System.arraycopy(keyBlock, ofs, tmp, 0, ivLength);
|
||||
ofs += ivLength;
|
||||
@ -220,8 +222,8 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
|
||||
// TLS 1.0
|
||||
byte[] seed = concat(clientRandom, serverRandom);
|
||||
|
||||
tmp = doTLS10PRF(clientKeyBytes, LABEL_CLIENT_WRITE_KEY, seed,
|
||||
expandedKeyLength, md5, sha);
|
||||
byte[] tmp = doTLS10PRF(clientKeyBytes,
|
||||
LABEL_CLIENT_WRITE_KEY, seed, expandedKeyLength, md5, sha);
|
||||
clientCipherKey = new SecretKeySpec(tmp, alg);
|
||||
|
||||
tmp = doTLS10PRF(serverKeyBytes, LABEL_SERVER_WRITE_KEY, seed,
|
||||
@ -239,7 +241,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
|
||||
}
|
||||
} else {
|
||||
// SSLv3
|
||||
tmp = new byte[expandedKeyLength];
|
||||
byte[] tmp = new byte[expandedKeyLength];
|
||||
|
||||
md5.update(clientKeyBytes);
|
||||
md5.update(clientRandom);
|
||||
|
||||
@ -243,12 +243,17 @@ public class JPEGImageReader extends ImageReader {
|
||||
* sending warnings to listeners.
|
||||
*/
|
||||
protected void warningOccurred(int code) {
|
||||
if ((code < 0) || (code > MAX_WARNING)){
|
||||
throw new InternalError("Invalid warning index");
|
||||
cbLock.lock();
|
||||
try {
|
||||
if ((code < 0) || (code > MAX_WARNING)){
|
||||
throw new InternalError("Invalid warning index");
|
||||
}
|
||||
processWarningOccurred
|
||||
("com.sun.imageio.plugins.jpeg.JPEGImageReaderResources",
|
||||
Integer.toString(code));
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
processWarningOccurred
|
||||
("com.sun.imageio.plugins.jpeg.JPEGImageReaderResources",
|
||||
Integer.toString(code));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -265,7 +270,12 @@ public class JPEGImageReader extends ImageReader {
|
||||
* library warnings from being printed to stderr.
|
||||
*/
|
||||
protected void warningWithMessage(String msg) {
|
||||
processWarningOccurred(msg);
|
||||
cbLock.lock();
|
||||
try {
|
||||
processWarningOccurred(msg);
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void setInput(Object input,
|
||||
@ -274,18 +284,55 @@ public class JPEGImageReader extends ImageReader {
|
||||
{
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
|
||||
super.setInput(input, seekForwardOnly, ignoreMetadata);
|
||||
this.ignoreMetadata = ignoreMetadata;
|
||||
resetInternalState();
|
||||
iis = (ImageInputStream) input; // Always works
|
||||
setSource(structPointer, iis);
|
||||
setSource(structPointer);
|
||||
} finally {
|
||||
clearThreadLock();
|
||||
}
|
||||
}
|
||||
|
||||
private native void setSource(long structPointer,
|
||||
ImageInputStream source);
|
||||
/**
|
||||
* This method is called from native code in order to fill
|
||||
* native input buffer.
|
||||
*
|
||||
* We block any attempt to change the reading state during this
|
||||
* method, in order to prevent a corruption of the native decoder
|
||||
* state.
|
||||
*
|
||||
* @return number of bytes read from the stream.
|
||||
*/
|
||||
private int readInputData(byte[] buf, int off, int len) throws IOException {
|
||||
cbLock.lock();
|
||||
try {
|
||||
return iis.read(buf, off, len);
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from the native code in order to
|
||||
* skip requested number of bytes in the input stream.
|
||||
*
|
||||
* @param n
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private long skipInputBytes(long n) throws IOException {
|
||||
cbLock.lock();
|
||||
try {
|
||||
return iis.skipBytes(n);
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private native void setSource(long structPointer);
|
||||
|
||||
private void checkTablesOnly() throws IOException {
|
||||
if (debug) {
|
||||
@ -337,6 +384,8 @@ public class JPEGImageReader extends ImageReader {
|
||||
public int getNumImages(boolean allowSearch) throws IOException {
|
||||
setThreadLock();
|
||||
try { // locked thread
|
||||
cbLock.check();
|
||||
|
||||
return getNumImagesOnThread(allowSearch);
|
||||
} finally {
|
||||
clearThreadLock();
|
||||
@ -536,8 +585,13 @@ public class JPEGImageReader extends ImageReader {
|
||||
if (debug) {
|
||||
System.out.println("pushing back " + num + " bytes");
|
||||
}
|
||||
iis.seek(iis.getStreamPosition()-num);
|
||||
// The buffer is clear after this, so no need to set haveSeeked.
|
||||
cbLock.lock();
|
||||
try {
|
||||
iis.seek(iis.getStreamPosition()-num);
|
||||
// The buffer is clear after this, so no need to set haveSeeked.
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -644,7 +698,12 @@ public class JPEGImageReader extends ImageReader {
|
||||
* Ignore this profile.
|
||||
*/
|
||||
iccCS = null;
|
||||
warningOccurred(WARNING_IGNORE_INVALID_ICC);
|
||||
cbLock.lock();
|
||||
try {
|
||||
warningOccurred(WARNING_IGNORE_INVALID_ICC);
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -653,6 +712,7 @@ public class JPEGImageReader extends ImageReader {
|
||||
setThreadLock();
|
||||
try {
|
||||
if (currentImage != imageIndex) {
|
||||
cbLock.check();
|
||||
readHeader(imageIndex, true);
|
||||
}
|
||||
return width;
|
||||
@ -665,6 +725,7 @@ public class JPEGImageReader extends ImageReader {
|
||||
setThreadLock();
|
||||
try {
|
||||
if (currentImage != imageIndex) {
|
||||
cbLock.check();
|
||||
readHeader(imageIndex, true);
|
||||
}
|
||||
return height;
|
||||
@ -693,6 +754,8 @@ public class JPEGImageReader extends ImageReader {
|
||||
setThreadLock();
|
||||
try {
|
||||
if (currentImage != imageIndex) {
|
||||
cbLock.check();
|
||||
|
||||
readHeader(imageIndex, true);
|
||||
}
|
||||
|
||||
@ -716,6 +779,7 @@ public class JPEGImageReader extends ImageReader {
|
||||
private Iterator getImageTypesOnThread(int imageIndex)
|
||||
throws IOException {
|
||||
if (currentImage != imageIndex) {
|
||||
cbLock.check();
|
||||
readHeader(imageIndex, true);
|
||||
}
|
||||
|
||||
@ -931,6 +995,7 @@ public class JPEGImageReader extends ImageReader {
|
||||
setThreadLock();
|
||||
try {
|
||||
if (!tablesOnlyChecked) {
|
||||
cbLock.check();
|
||||
checkTablesOnly();
|
||||
}
|
||||
return streamMetadata;
|
||||
@ -951,6 +1016,8 @@ public class JPEGImageReader extends ImageReader {
|
||||
return imageMetadata;
|
||||
}
|
||||
|
||||
cbLock.check();
|
||||
|
||||
gotoImage(imageIndex);
|
||||
|
||||
imageMetadata = new JPEGMetadata(false, false, iis, this);
|
||||
@ -967,6 +1034,7 @@ public class JPEGImageReader extends ImageReader {
|
||||
throws IOException {
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
try {
|
||||
readInternal(imageIndex, param, false);
|
||||
} catch (RuntimeException e) {
|
||||
@ -1196,58 +1264,63 @@ public class JPEGImageReader extends ImageReader {
|
||||
}
|
||||
target.setRect(destROI.x, destROI.y + y, raster);
|
||||
|
||||
processImageUpdate(image,
|
||||
destROI.x, destROI.y+y,
|
||||
raster.getWidth(), 1,
|
||||
1, 1,
|
||||
destinationBands);
|
||||
if ((y > 0) && (y%progInterval == 0)) {
|
||||
int height = target.getHeight()-1;
|
||||
float percentOfPass = ((float)y)/height;
|
||||
if (progressive) {
|
||||
if (knownPassCount != UNKNOWN) {
|
||||
processImageProgress((pass + percentOfPass)*100.0F
|
||||
/ knownPassCount);
|
||||
} else if (maxProgressivePass != Integer.MAX_VALUE) {
|
||||
// Use the range of allowed progressive passes
|
||||
processImageProgress((pass + percentOfPass)*100.0F
|
||||
/ (maxProgressivePass - minProgressivePass + 1));
|
||||
} else {
|
||||
// Assume there are a minimum of MIN_ESTIMATED_PASSES
|
||||
// and that there is always one more pass
|
||||
// Compute the percentage as the percentage at the end
|
||||
// of the previous pass, plus the percentage of this
|
||||
// pass scaled to be the percentage of the total remaining,
|
||||
// assuming a minimum of MIN_ESTIMATED_PASSES passes and
|
||||
// that there is always one more pass. This is monotonic
|
||||
// and asymptotic to 1.0, which is what we need.
|
||||
int remainingPasses = // including this one
|
||||
Math.max(2, MIN_ESTIMATED_PASSES-pass);
|
||||
int totalPasses = pass + remainingPasses-1;
|
||||
progInterval = Math.max(height/20*totalPasses,
|
||||
totalPasses);
|
||||
if (y%progInterval == 0) {
|
||||
percentToDate = previousPassPercentage +
|
||||
(1.0F - previousPassPercentage)
|
||||
* (percentOfPass)/remainingPasses;
|
||||
if (debug) {
|
||||
System.out.print("pass= " + pass);
|
||||
System.out.print(", y= " + y);
|
||||
System.out.print(", progInt= " + progInterval);
|
||||
System.out.print(", % of pass: " + percentOfPass);
|
||||
System.out.print(", rem. passes: "
|
||||
+ remainingPasses);
|
||||
System.out.print(", prev%: "
|
||||
+ previousPassPercentage);
|
||||
System.out.print(", %ToDate: " + percentToDate);
|
||||
System.out.print(" ");
|
||||
cbLock.lock();
|
||||
try {
|
||||
processImageUpdate(image,
|
||||
destROI.x, destROI.y+y,
|
||||
raster.getWidth(), 1,
|
||||
1, 1,
|
||||
destinationBands);
|
||||
if ((y > 0) && (y%progInterval == 0)) {
|
||||
int height = target.getHeight()-1;
|
||||
float percentOfPass = ((float)y)/height;
|
||||
if (progressive) {
|
||||
if (knownPassCount != UNKNOWN) {
|
||||
processImageProgress((pass + percentOfPass)*100.0F
|
||||
/ knownPassCount);
|
||||
} else if (maxProgressivePass != Integer.MAX_VALUE) {
|
||||
// Use the range of allowed progressive passes
|
||||
processImageProgress((pass + percentOfPass)*100.0F
|
||||
/ (maxProgressivePass - minProgressivePass + 1));
|
||||
} else {
|
||||
// Assume there are a minimum of MIN_ESTIMATED_PASSES
|
||||
// and that there is always one more pass
|
||||
// Compute the percentage as the percentage at the end
|
||||
// of the previous pass, plus the percentage of this
|
||||
// pass scaled to be the percentage of the total remaining,
|
||||
// assuming a minimum of MIN_ESTIMATED_PASSES passes and
|
||||
// that there is always one more pass. This is monotonic
|
||||
// and asymptotic to 1.0, which is what we need.
|
||||
int remainingPasses = // including this one
|
||||
Math.max(2, MIN_ESTIMATED_PASSES-pass);
|
||||
int totalPasses = pass + remainingPasses-1;
|
||||
progInterval = Math.max(height/20*totalPasses,
|
||||
totalPasses);
|
||||
if (y%progInterval == 0) {
|
||||
percentToDate = previousPassPercentage +
|
||||
(1.0F - previousPassPercentage)
|
||||
* (percentOfPass)/remainingPasses;
|
||||
if (debug) {
|
||||
System.out.print("pass= " + pass);
|
||||
System.out.print(", y= " + y);
|
||||
System.out.print(", progInt= " + progInterval);
|
||||
System.out.print(", % of pass: " + percentOfPass);
|
||||
System.out.print(", rem. passes: "
|
||||
+ remainingPasses);
|
||||
System.out.print(", prev%: "
|
||||
+ previousPassPercentage);
|
||||
System.out.print(", %ToDate: " + percentToDate);
|
||||
System.out.print(" ");
|
||||
}
|
||||
processImageProgress(percentToDate*100.0F);
|
||||
}
|
||||
processImageProgress(percentToDate*100.0F);
|
||||
}
|
||||
} else {
|
||||
processImageProgress(percentOfPass * 100.0F);
|
||||
}
|
||||
} else {
|
||||
processImageProgress(percentOfPass * 100.0F);
|
||||
}
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1260,33 +1333,58 @@ public class JPEGImageReader extends ImageReader {
|
||||
}
|
||||
|
||||
private void passStarted (int pass) {
|
||||
this.pass = pass;
|
||||
previousPassPercentage = percentToDate;
|
||||
processPassStarted(image,
|
||||
pass,
|
||||
minProgressivePass,
|
||||
maxProgressivePass,
|
||||
0, 0,
|
||||
1,1,
|
||||
destinationBands);
|
||||
cbLock.lock();
|
||||
try {
|
||||
this.pass = pass;
|
||||
previousPassPercentage = percentToDate;
|
||||
processPassStarted(image,
|
||||
pass,
|
||||
minProgressivePass,
|
||||
maxProgressivePass,
|
||||
0, 0,
|
||||
1,1,
|
||||
destinationBands);
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void passComplete () {
|
||||
processPassComplete(image);
|
||||
cbLock.lock();
|
||||
try {
|
||||
processPassComplete(image);
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void thumbnailStarted(int thumbnailIndex) {
|
||||
processThumbnailStarted(currentImage, thumbnailIndex);
|
||||
cbLock.lock();
|
||||
try {
|
||||
processThumbnailStarted(currentImage, thumbnailIndex);
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// Provide access to protected superclass method
|
||||
void thumbnailProgress(float percentageDone) {
|
||||
processThumbnailProgress(percentageDone);
|
||||
cbLock.lock();
|
||||
try {
|
||||
processThumbnailProgress(percentageDone);
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// Provide access to protected superclass method
|
||||
void thumbnailComplete() {
|
||||
processThumbnailComplete();
|
||||
cbLock.lock();
|
||||
try {
|
||||
processThumbnailComplete();
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1310,6 +1408,11 @@ public class JPEGImageReader extends ImageReader {
|
||||
public void abort() {
|
||||
setThreadLock();
|
||||
try {
|
||||
/**
|
||||
* NB: we do not check the call back lock here,
|
||||
* we allow to abort the reader any time.
|
||||
*/
|
||||
|
||||
super.abort();
|
||||
abortRead(structPointer);
|
||||
} finally {
|
||||
@ -1332,6 +1435,7 @@ public class JPEGImageReader extends ImageReader {
|
||||
setThreadLock();
|
||||
Raster retval = null;
|
||||
try {
|
||||
cbLock.check();
|
||||
/*
|
||||
* This could be further optimized by not resetting the dest.
|
||||
* offset and creating a translated raster in readInternal()
|
||||
@ -1371,6 +1475,8 @@ public class JPEGImageReader extends ImageReader {
|
||||
public int getNumThumbnails(int imageIndex) throws IOException {
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
|
||||
getImageMetadata(imageIndex); // checks iis state for us
|
||||
// Now check the jfif segments
|
||||
JFIFMarkerSegment jfif =
|
||||
@ -1391,6 +1497,8 @@ public class JPEGImageReader extends ImageReader {
|
||||
throws IOException {
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
|
||||
if ((thumbnailIndex < 0)
|
||||
|| (thumbnailIndex >= getNumThumbnails(imageIndex))) {
|
||||
throw new IndexOutOfBoundsException("No such thumbnail");
|
||||
@ -1409,6 +1517,8 @@ public class JPEGImageReader extends ImageReader {
|
||||
throws IOException {
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
|
||||
if ((thumbnailIndex < 0)
|
||||
|| (thumbnailIndex >= getNumThumbnails(imageIndex))) {
|
||||
throw new IndexOutOfBoundsException("No such thumbnail");
|
||||
@ -1428,6 +1538,8 @@ public class JPEGImageReader extends ImageReader {
|
||||
throws IOException {
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
|
||||
if ((thumbnailIndex < 0)
|
||||
|| (thumbnailIndex >= getNumThumbnails(imageIndex))) {
|
||||
throw new IndexOutOfBoundsException("No such thumbnail");
|
||||
@ -1468,6 +1580,7 @@ public class JPEGImageReader extends ImageReader {
|
||||
public void reset() {
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
super.reset();
|
||||
} finally {
|
||||
clearThreadLock();
|
||||
@ -1479,6 +1592,8 @@ public class JPEGImageReader extends ImageReader {
|
||||
public void dispose() {
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
|
||||
if (structPointer != 0) {
|
||||
disposerRecord.dispose();
|
||||
structPointer = 0;
|
||||
@ -1540,6 +1655,36 @@ public class JPEGImageReader extends ImageReader {
|
||||
theThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
private CallBackLock cbLock = new CallBackLock();
|
||||
|
||||
private static class CallBackLock {
|
||||
|
||||
private State lockState;
|
||||
|
||||
CallBackLock() {
|
||||
lockState = State.Unlocked;
|
||||
}
|
||||
|
||||
void check() {
|
||||
if (lockState != State.Unlocked) {
|
||||
throw new IllegalStateException("Access to the reader is not allowed");
|
||||
}
|
||||
}
|
||||
|
||||
private void lock() {
|
||||
lockState = State.Locked;
|
||||
}
|
||||
|
||||
private void unlock() {
|
||||
lockState = State.Unlocked;
|
||||
}
|
||||
|
||||
private static enum State {
|
||||
Unlocked,
|
||||
Locked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -183,8 +183,7 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
initWriterIDs(ImageOutputStream.class,
|
||||
JPEGQTable.class,
|
||||
initWriterIDs(JPEGQTable.class,
|
||||
JPEGHuffmanTable.class);
|
||||
}
|
||||
|
||||
@ -200,11 +199,13 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
public void setOutput(Object output) {
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
|
||||
super.setOutput(output); // validates output
|
||||
resetInternalState();
|
||||
ios = (ImageOutputStream) output; // so this will always work
|
||||
// Set the native destination
|
||||
setDest(structPointer, ios);
|
||||
setDest(structPointer);
|
||||
} finally {
|
||||
clearThreadLock();
|
||||
}
|
||||
@ -359,6 +360,8 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
ImageWriteParam param) throws IOException {
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
|
||||
writeOnThread(streamMetadata, image, param);
|
||||
} finally {
|
||||
clearThreadLock();
|
||||
@ -1082,13 +1085,18 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
haveMetadata,
|
||||
restartInterval);
|
||||
|
||||
if (aborted) {
|
||||
processWriteAborted();
|
||||
} else {
|
||||
processImageComplete();
|
||||
}
|
||||
cbLock.lock();
|
||||
try {
|
||||
if (aborted) {
|
||||
processWriteAborted();
|
||||
} else {
|
||||
processImageComplete();
|
||||
}
|
||||
|
||||
ios.flush();
|
||||
ios.flush();
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
currentImage++; // After a successful write
|
||||
}
|
||||
|
||||
@ -1096,6 +1104,8 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
throws IOException {
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
|
||||
prepareWriteSequenceOnThread(streamMetadata);
|
||||
} finally {
|
||||
clearThreadLock();
|
||||
@ -1175,6 +1185,8 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
throws IOException {
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
|
||||
if (sequencePrepared == false) {
|
||||
throw new IllegalStateException("sequencePrepared not called!");
|
||||
}
|
||||
@ -1188,6 +1200,8 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
public void endWriteSequence() throws IOException {
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
|
||||
if (sequencePrepared == false) {
|
||||
throw new IllegalStateException("sequencePrepared not called!");
|
||||
}
|
||||
@ -1200,6 +1214,10 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
public synchronized void abort() {
|
||||
setThreadLock();
|
||||
try {
|
||||
/**
|
||||
* NB: we do not check the call back lock here, we allow to abort
|
||||
* the reader any time.
|
||||
*/
|
||||
super.abort();
|
||||
abortWrite(structPointer);
|
||||
} finally {
|
||||
@ -1223,6 +1241,8 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
public void reset() {
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
|
||||
super.reset();
|
||||
} finally {
|
||||
clearThreadLock();
|
||||
@ -1232,6 +1252,8 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
public void dispose() {
|
||||
setThreadLock();
|
||||
try {
|
||||
cbLock.check();
|
||||
|
||||
if (structPointer != 0) {
|
||||
disposerRecord.dispose();
|
||||
structPointer = 0;
|
||||
@ -1251,13 +1273,18 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
* sending warnings to listeners.
|
||||
*/
|
||||
void warningOccurred(int code) {
|
||||
if ((code < 0) || (code > MAX_WARNING)){
|
||||
throw new InternalError("Invalid warning index");
|
||||
cbLock.lock();
|
||||
try {
|
||||
if ((code < 0) || (code > MAX_WARNING)){
|
||||
throw new InternalError("Invalid warning index");
|
||||
}
|
||||
processWarningOccurred
|
||||
(currentImage,
|
||||
"com.sun.imageio.plugins.jpeg.JPEGImageWriterResources",
|
||||
Integer.toString(code));
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
processWarningOccurred
|
||||
(currentImage,
|
||||
"com.sun.imageio.plugins.jpeg.JPEGImageWriterResources",
|
||||
Integer.toString(code));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1274,21 +1301,41 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
* library warnings from being printed to stderr.
|
||||
*/
|
||||
void warningWithMessage(String msg) {
|
||||
processWarningOccurred(currentImage, msg);
|
||||
cbLock.lock();
|
||||
try {
|
||||
processWarningOccurred(currentImage, msg);
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void thumbnailStarted(int thumbnailIndex) {
|
||||
processThumbnailStarted(currentImage, thumbnailIndex);
|
||||
cbLock.lock();
|
||||
try {
|
||||
processThumbnailStarted(currentImage, thumbnailIndex);
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// Provide access to protected superclass method
|
||||
void thumbnailProgress(float percentageDone) {
|
||||
processThumbnailProgress(percentageDone);
|
||||
cbLock.lock();
|
||||
try {
|
||||
processThumbnailProgress(percentageDone);
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// Provide access to protected superclass method
|
||||
void thumbnailComplete() {
|
||||
processThumbnailComplete();
|
||||
cbLock.lock();
|
||||
try {
|
||||
processThumbnailComplete();
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
///////// End of Package-access API
|
||||
@ -1615,16 +1662,14 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
////////////// Native methods and callbacks
|
||||
|
||||
/** Sets up static native structures. */
|
||||
private static native void initWriterIDs(Class iosClass,
|
||||
Class qTableClass,
|
||||
private static native void initWriterIDs(Class qTableClass,
|
||||
Class huffClass);
|
||||
|
||||
/** Sets up per-writer native structure and returns a pointer to it. */
|
||||
private native long initJPEGImageWriter();
|
||||
|
||||
/** Sets up native structures for output stream */
|
||||
private native void setDest(long structPointer,
|
||||
ImageOutputStream ios);
|
||||
private native void setDest(long structPointer);
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the write was aborted.
|
||||
@ -1749,7 +1794,12 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
}
|
||||
raster.setRect(sourceLine);
|
||||
if ((y > 7) && (y%8 == 0)) { // Every 8 scanlines
|
||||
processImageProgress((float) y / (float) sourceHeight * 100.0F);
|
||||
cbLock.lock();
|
||||
try {
|
||||
processImageProgress((float) y / (float) sourceHeight * 100.0F);
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1777,6 +1827,25 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from native code in order to write encoder
|
||||
* output to the destination.
|
||||
*
|
||||
* We block any attempt to change the writer state during this
|
||||
* method, in order to prevent a corruption of the native encoder
|
||||
* state.
|
||||
*/
|
||||
private void writeOutputData(byte[] data, int offset, int len)
|
||||
throws IOException
|
||||
{
|
||||
cbLock.lock();
|
||||
try {
|
||||
ios.write(data, offset, len);
|
||||
} finally {
|
||||
cbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private Thread theThread = null;
|
||||
private int theLockCount = 0;
|
||||
|
||||
@ -1811,4 +1880,34 @@ public class JPEGImageWriter extends ImageWriter {
|
||||
theThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
private CallBackLock cbLock = new CallBackLock();
|
||||
|
||||
private static class CallBackLock {
|
||||
|
||||
private State lockState;
|
||||
|
||||
CallBackLock() {
|
||||
lockState = State.Unlocked;
|
||||
}
|
||||
|
||||
void check() {
|
||||
if (lockState != State.Unlocked) {
|
||||
throw new IllegalStateException("Access to the writer is not allowed");
|
||||
}
|
||||
}
|
||||
|
||||
private void lock() {
|
||||
lockState = State.Locked;
|
||||
}
|
||||
|
||||
private void unlock() {
|
||||
lockState = State.Unlocked;
|
||||
}
|
||||
|
||||
private static enum State {
|
||||
Unlocked,
|
||||
Locked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2008, 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
|
||||
@ -32,6 +32,7 @@ import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.Permission;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
@ -213,7 +214,6 @@ public class MBeanInstantiator {
|
||||
|
||||
Object moi;
|
||||
|
||||
|
||||
// ------------------------------
|
||||
// ------------------------------
|
||||
Constructor<?> cons = findConstructor(theClass, null);
|
||||
@ -224,6 +224,7 @@ public class MBeanInstantiator {
|
||||
// Instantiate the new object
|
||||
try {
|
||||
ReflectUtil.checkPackageAccess(theClass);
|
||||
ensureClassAccess(theClass);
|
||||
moi= cons.newInstance();
|
||||
} catch (InvocationTargetException e) {
|
||||
// Wrap the exception.
|
||||
@ -270,7 +271,6 @@ public class MBeanInstantiator {
|
||||
checkMBeanPermission(theClass, null, null, "instantiate");
|
||||
|
||||
// Instantiate the new object
|
||||
|
||||
// ------------------------------
|
||||
// ------------------------------
|
||||
final Class<?>[] tab;
|
||||
@ -300,6 +300,7 @@ public class MBeanInstantiator {
|
||||
}
|
||||
try {
|
||||
ReflectUtil.checkPackageAccess(theClass);
|
||||
ensureClassAccess(theClass);
|
||||
moi = cons.newInstance(params);
|
||||
}
|
||||
catch (NoSuchMethodError error) {
|
||||
@ -741,4 +742,13 @@ public class MBeanInstantiator {
|
||||
sm.checkPermission(perm);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ensureClassAccess(Class clazz)
|
||||
throws IllegalAccessException
|
||||
{
|
||||
int mod = clazz.getModifiers();
|
||||
if (!Modifier.isPublic(mod)) {
|
||||
throw new IllegalAccessException("Class is not public and can't be instantiated");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice
|
||||
// from simultaneous creation and destruction
|
||||
// reduces possibility of deadlock, compared to
|
||||
// synchronizing to the class instance
|
||||
private Object traRecLock = new Object();
|
||||
private final Object traRecLock = new Object();
|
||||
|
||||
// DEVICE ATTRIBUTES
|
||||
|
||||
@ -474,7 +474,7 @@ abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice
|
||||
This is necessary for Receivers retrieved via MidiSystem.getReceiver()
|
||||
(which opens the device implicitely).
|
||||
*/
|
||||
protected abstract class AbstractReceiver implements MidiDeviceReceiver {
|
||||
abstract class AbstractReceiver implements MidiDeviceReceiver {
|
||||
private boolean open = true;
|
||||
|
||||
|
||||
@ -483,24 +483,24 @@ abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice
|
||||
Receiver. Therefore, subclasses should not override this method.
|
||||
Instead, they should implement implSend().
|
||||
*/
|
||||
public synchronized void send(MidiMessage message, long timeStamp) {
|
||||
if (open) {
|
||||
implSend(message, timeStamp);
|
||||
} else {
|
||||
@Override
|
||||
public final synchronized void send(final MidiMessage message,
|
||||
final long timeStamp) {
|
||||
if (!open) {
|
||||
throw new IllegalStateException("Receiver is not open");
|
||||
}
|
||||
implSend(message, timeStamp);
|
||||
}
|
||||
|
||||
|
||||
protected abstract void implSend(MidiMessage message, long timeStamp);
|
||||
|
||||
abstract void implSend(MidiMessage message, long timeStamp);
|
||||
|
||||
/** Close the Receiver.
|
||||
* Here, the call to the magic method closeInternal() takes place.
|
||||
* Therefore, subclasses that override this method must call
|
||||
* 'super.close()'.
|
||||
*/
|
||||
public void close() {
|
||||
@Override
|
||||
public final void close() {
|
||||
open = false;
|
||||
synchronized (AbstractMidiDevice.this.traRecLock) {
|
||||
AbstractMidiDevice.this.getReceiverList().remove(this);
|
||||
@ -508,11 +508,12 @@ abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice
|
||||
AbstractMidiDevice.this.closeInternal(this);
|
||||
}
|
||||
|
||||
public MidiDevice getMidiDevice() {
|
||||
@Override
|
||||
public final MidiDevice getMidiDevice() {
|
||||
return AbstractMidiDevice.this;
|
||||
}
|
||||
|
||||
protected boolean isOpen() {
|
||||
final boolean isOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ import javax.sound.midi.*;
|
||||
*
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
class FastShortMessage extends ShortMessage {
|
||||
final class FastShortMessage extends ShortMessage {
|
||||
private int packedMsg;
|
||||
|
||||
public FastShortMessage(int packedMsg) throws InvalidMidiDataException {
|
||||
|
||||
@ -32,7 +32,7 @@ import javax.sound.midi.*;
|
||||
*
|
||||
* @author Florian Bomers
|
||||
*/
|
||||
class FastSysexMessage extends SysexMessage {
|
||||
final class FastSysexMessage extends SysexMessage {
|
||||
|
||||
FastSysexMessage(byte[] data) throws InvalidMidiDataException {
|
||||
super(data);
|
||||
|
||||
@ -103,9 +103,9 @@ class MidiOutDevice extends AbstractMidiDevice {
|
||||
|
||||
class MidiOutReceiver extends AbstractReceiver {
|
||||
|
||||
protected void implSend(MidiMessage message, long timeStamp) {
|
||||
int length = message.getLength();
|
||||
int status = message.getStatus();
|
||||
void implSend(final MidiMessage message, final long timeStamp) {
|
||||
final int length = message.getLength();
|
||||
final int status = message.getStatus();
|
||||
if (length <= 3 && status != 0xF0 && status != 0xF7) {
|
||||
int packedMsg;
|
||||
if (message instanceof ShortMessage) {
|
||||
@ -140,11 +140,15 @@ class MidiOutDevice extends AbstractMidiDevice {
|
||||
}
|
||||
nSendShortMessage(id, packedMsg, timeStamp);
|
||||
} else {
|
||||
final byte[] data;
|
||||
if (message instanceof FastSysexMessage) {
|
||||
nSendLongMessage(id, ((FastSysexMessage) message).getReadOnlyMessage(),
|
||||
length, timeStamp);
|
||||
data = ((FastSysexMessage) message).getReadOnlyMessage();
|
||||
} else {
|
||||
nSendLongMessage(id, message.getMessage(), length, timeStamp);
|
||||
data = message.getMessage();
|
||||
}
|
||||
final int dataLength = Math.min(length, data.length);
|
||||
if (dataLength > 0) {
|
||||
nSendLongMessage(id, data, dataLength, timeStamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1026,7 +1026,7 @@ class RealTimeSequencer extends AbstractMidiDevice implements Sequencer, AutoCon
|
||||
|
||||
class SequencerReceiver extends AbstractReceiver {
|
||||
|
||||
protected void implSend(MidiMessage message, long timeStamp) {
|
||||
void implSend(MidiMessage message, long timeStamp) {
|
||||
if (recording) {
|
||||
long tickPos = 0;
|
||||
|
||||
|
||||
@ -851,6 +851,11 @@ public class EventSetImpl extends ArrayList<Event> implements EventSet {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<Event> spliterator() {
|
||||
return Spliterators.spliterator(this, Spliterator.DISTINCT);
|
||||
}
|
||||
|
||||
/* below make this unmodifiable */
|
||||
|
||||
public boolean add(Event o){
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 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
|
||||
@ -2234,7 +2234,7 @@ public class Window extends Container implements Accessible {
|
||||
WindowPeer peer = (WindowPeer)this.peer;
|
||||
synchronized(getTreeLock()) {
|
||||
if (peer != null) {
|
||||
peer.setAlwaysOnTop(alwaysOnTop);
|
||||
peer.updateAlwaysOnTopState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 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,15 +53,14 @@ public interface WindowPeer extends ContainerPeer {
|
||||
void toBack();
|
||||
|
||||
/**
|
||||
* Sets if the window should always stay on top of all other windows or
|
||||
* not.
|
||||
*
|
||||
* @param alwaysOnTop if the window should always stay on top of all other
|
||||
* windows or not
|
||||
* Updates the window's always-on-top state.
|
||||
* Sets if the window should always stay
|
||||
* on top of all other windows or not.
|
||||
*
|
||||
* @see Window#getAlwaysOnTop()
|
||||
* @see Window#setAlwaysOnTop(boolean)
|
||||
*/
|
||||
void setAlwaysOnTop(boolean alwaysOnTop);
|
||||
void updateAlwaysOnTopState();
|
||||
|
||||
/**
|
||||
* Updates the window's focusable state.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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
|
||||
@ -29,7 +29,6 @@ import com.sun.beans.finder.BeanInfoFinder;
|
||||
import com.sun.beans.finder.PropertyEditorFinder;
|
||||
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
@ -42,7 +41,7 @@ import java.util.WeakHashMap;
|
||||
*/
|
||||
final class ThreadGroupContext {
|
||||
|
||||
private static final Map<ThreadGroup, ThreadGroupContext> contexts = new WeakHashMap<>();
|
||||
private static final WeakIdentityMap<ThreadGroupContext> contexts = new WeakIdentityMap<>();
|
||||
|
||||
/**
|
||||
* Returns the appropriate {@code AppContext} for the caller,
|
||||
@ -69,6 +68,8 @@ final class ThreadGroupContext {
|
||||
private BeanInfoFinder beanInfoFinder;
|
||||
private PropertyEditorFinder propertyEditorFinder;
|
||||
|
||||
private ThreadGroupContext() {
|
||||
}
|
||||
|
||||
boolean isDesignTime() {
|
||||
return this.isDesignTime;
|
||||
|
||||
181
jdk/src/share/classes/java/beans/WeakIdentityMap.java
Normal file
181
jdk/src/share/classes/java/beans/WeakIdentityMap.java
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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.beans;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* Hash table based mapping, which uses weak references to store keys
|
||||
* and reference-equality in place of object-equality to compare them.
|
||||
* An entry will automatically be removed when its key is no longer
|
||||
* in ordinary use. Both null values and the null key are supported.
|
||||
*
|
||||
* @see java.util.IdentityHashMap
|
||||
* @see java.util.WeakHashMap
|
||||
*/
|
||||
final class WeakIdentityMap<T> {
|
||||
|
||||
private static final int MAXIMUM_CAPACITY = 1 << 30; // it MUST be a power of two
|
||||
private static final Object NULL = new Object(); // special object for null key
|
||||
|
||||
private final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
|
||||
|
||||
private Entry<T>[] table = newTable(1<<3); // table's length MUST be a power of two
|
||||
private int threshold = 6; // the next size value at which to resize
|
||||
private int size = 0; // the number of key-value mappings
|
||||
|
||||
public T get(Object key) {
|
||||
removeStaleEntries();
|
||||
if (key == null) {
|
||||
key = NULL;
|
||||
}
|
||||
int hash = key.hashCode();
|
||||
int index = getIndex(this.table, hash);
|
||||
for (Entry<T> entry = this.table[index]; entry != null; entry = entry.next) {
|
||||
if (entry.isMatched(key, hash)) {
|
||||
return entry.value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public T put(Object key, T value) {
|
||||
removeStaleEntries();
|
||||
if (key == null) {
|
||||
key = NULL;
|
||||
}
|
||||
int hash = key.hashCode();
|
||||
int index = getIndex(this.table, hash);
|
||||
for (Entry<T> entry = this.table[index]; entry != null; entry = entry.next) {
|
||||
if (entry.isMatched(key, hash)) {
|
||||
T oldValue = entry.value;
|
||||
entry.value = value;
|
||||
return oldValue;
|
||||
}
|
||||
}
|
||||
this.table[index] = new Entry<T>(key, hash, value, this.queue, this.table[index]);
|
||||
if (++this.size >= this.threshold) {
|
||||
if (this.table.length == MAXIMUM_CAPACITY) {
|
||||
this.threshold = Integer.MAX_VALUE;
|
||||
}
|
||||
else {
|
||||
removeStaleEntries();
|
||||
Entry<T>[] table = newTable(this.table.length * 2);
|
||||
transfer(this.table, table);
|
||||
|
||||
// If ignoring null elements and processing ref queue caused massive
|
||||
// shrinkage, then restore old table. This should be rare, but avoids
|
||||
// unbounded expansion of garbage-filled tables.
|
||||
if (this.size >= this.threshold / 2) {
|
||||
this.table = table;
|
||||
this.threshold *= 2;
|
||||
}
|
||||
else {
|
||||
transfer(table, this.table);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void removeStaleEntries() {
|
||||
for (Object ref = this.queue.poll(); ref != null; ref = this.queue.poll()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Entry<T> entry = (Entry<T>) ref;
|
||||
int index = getIndex(this.table, entry.hash);
|
||||
|
||||
Entry<T> prev = this.table[index];
|
||||
Entry<T> current = prev;
|
||||
while (current != null) {
|
||||
Entry<T> next = current.next;
|
||||
if (current == entry) {
|
||||
if (prev == entry) {
|
||||
this.table[index] = next;
|
||||
}
|
||||
else {
|
||||
prev.next = next;
|
||||
}
|
||||
entry.value = null; // Help GC
|
||||
entry.next = null; // Help GC
|
||||
this.size--;
|
||||
break;
|
||||
}
|
||||
prev = current;
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void transfer(Entry<T>[] oldTable, Entry<T>[] newTable) {
|
||||
for (int i = 0; i < oldTable.length; i++) {
|
||||
Entry<T> entry = oldTable[i];
|
||||
oldTable[i] = null;
|
||||
while (entry != null) {
|
||||
Entry<T> next = entry.next;
|
||||
Object key = entry.get();
|
||||
if (key == null) {
|
||||
entry.value = null; // Help GC
|
||||
entry.next = null; // Help GC
|
||||
this.size--;
|
||||
}
|
||||
else {
|
||||
int index = getIndex(newTable, entry.hash);
|
||||
entry.next = newTable[index];
|
||||
newTable[index] = entry;
|
||||
}
|
||||
entry = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Entry<T>[] newTable(int length) {
|
||||
return (Entry<T>[]) new Entry<?>[length];
|
||||
}
|
||||
|
||||
private static int getIndex(Entry<?>[] table, int hash) {
|
||||
return hash & (table.length - 1);
|
||||
}
|
||||
|
||||
private static class Entry<T> extends WeakReference<Object> {
|
||||
private final int hash;
|
||||
private T value;
|
||||
private Entry<T> next;
|
||||
|
||||
Entry(Object key, int hash, T value, ReferenceQueue<Object> queue, Entry<T> next) {
|
||||
super(key, queue);
|
||||
this.hash = hash;
|
||||
this.value = value;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
boolean isMatched(Object key, int hash) {
|
||||
return (this.hash == hash) && (key == get());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -41,6 +41,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import static java.io.ObjectStreamClass.processQueue;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
|
||||
/**
|
||||
* An ObjectInputStream deserializes primitive data and objects previously
|
||||
@ -1519,6 +1520,12 @@ public class ObjectInputStream
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCustomSubclass() {
|
||||
// Return true if this class is a custom subclass of ObjectInputStream
|
||||
return getClass().getClassLoader()
|
||||
!= ObjectInputStream.class.getClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in and returns class descriptor for a dynamic proxy class. Sets
|
||||
* passHandle to proxy class descriptor's assigned handle. If proxy class
|
||||
@ -1548,6 +1555,15 @@ public class ObjectInputStream
|
||||
try {
|
||||
if ((cl = resolveProxyClass(ifaces)) == null) {
|
||||
resolveEx = new ClassNotFoundException("null class");
|
||||
} else if (!Proxy.isProxyClass(cl)) {
|
||||
throw new InvalidClassException("Not a proxy");
|
||||
} else {
|
||||
// ReflectUtil.checkProxyPackageAccess makes a test
|
||||
// equivalent to isCustomSubclass so there's no need
|
||||
// to condition this call to isCustomSubclass == true here.
|
||||
ReflectUtil.checkProxyPackageAccess(
|
||||
getClass().getClassLoader(),
|
||||
cl.getInterfaces());
|
||||
}
|
||||
} catch (ClassNotFoundException ex) {
|
||||
resolveEx = ex;
|
||||
@ -1589,9 +1605,12 @@ public class ObjectInputStream
|
||||
Class<?> cl = null;
|
||||
ClassNotFoundException resolveEx = null;
|
||||
bin.setBlockDataMode(true);
|
||||
final boolean checksRequired = isCustomSubclass();
|
||||
try {
|
||||
if ((cl = resolveClass(readDesc)) == null) {
|
||||
resolveEx = new ClassNotFoundException("null class");
|
||||
} else if (checksRequired) {
|
||||
ReflectUtil.checkPackageAccess(cl);
|
||||
}
|
||||
} catch (ClassNotFoundException ex) {
|
||||
resolveEx = ex;
|
||||
|
||||
@ -53,6 +53,7 @@ import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import sun.misc.Unsafe;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.ConstantPool;
|
||||
import sun.reflect.Reflection;
|
||||
import sun.reflect.ReflectionFactory;
|
||||
@ -250,9 +251,11 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* by this method fails
|
||||
* @exception ClassNotFoundException if the class cannot be located
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static Class<?> forName(String className)
|
||||
throws ClassNotFoundException {
|
||||
return forName0(className, true, ClassLoader.getCallerClassLoader());
|
||||
return forName0(className, true,
|
||||
ClassLoader.getClassLoader(Reflection.getCallerClass()));
|
||||
}
|
||||
|
||||
|
||||
@ -317,6 +320,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* @see java.lang.ClassLoader
|
||||
* @since 1.2
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static Class<?> forName(String name, boolean initialize,
|
||||
ClassLoader loader)
|
||||
throws ClassNotFoundException
|
||||
@ -324,7 +328,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
if (sun.misc.VM.isSystemDomainLoader(loader)) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
ClassLoader ccl = ClassLoader.getCallerClassLoader();
|
||||
ClassLoader ccl = ClassLoader.getClassLoader(Reflection.getCallerClass());
|
||||
if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
|
||||
sm.checkPermission(
|
||||
SecurityConstants.GET_CLASSLOADER_PERMISSION);
|
||||
@ -386,18 +390,14 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* </ul>
|
||||
*
|
||||
*/
|
||||
@CallerSensitive
|
||||
public T newInstance()
|
||||
throws InstantiationException, IllegalAccessException
|
||||
{
|
||||
if (System.getSecurityManager() != null) {
|
||||
checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false);
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
|
||||
}
|
||||
return newInstance0();
|
||||
}
|
||||
|
||||
private T newInstance0()
|
||||
throws InstantiationException, IllegalAccessException
|
||||
{
|
||||
// NOTE: the following code may not be strictly correct under
|
||||
// the current Java memory model.
|
||||
|
||||
@ -432,7 +432,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
// Security check (same as in java.lang.reflect.Constructor)
|
||||
int modifiers = tmpConstructor.getModifiers();
|
||||
if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass(3);
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
if (newInstanceCallerCache != caller) {
|
||||
Reflection.ensureMemberAccess(caller, this, null, modifiers);
|
||||
newInstanceCallerCache = caller;
|
||||
@ -674,16 +674,14 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* @see SecurityManager#checkPermission
|
||||
* @see java.lang.RuntimePermission
|
||||
*/
|
||||
@CallerSensitive
|
||||
public ClassLoader getClassLoader() {
|
||||
ClassLoader cl = getClassLoader0();
|
||||
if (cl == null)
|
||||
return null;
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
ClassLoader ccl = ClassLoader.getCallerClassLoader();
|
||||
if (ClassLoader.needsClassLoaderPermissionCheck(ccl, cl)) {
|
||||
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
|
||||
}
|
||||
ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
|
||||
}
|
||||
return cl;
|
||||
}
|
||||
@ -1392,11 +1390,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Class<?>[] getClasses() {
|
||||
// be very careful not to change the stack depth of this
|
||||
// checkMemberAccess call for security reasons
|
||||
// see java.lang.SecurityManager.checkMemberAccess
|
||||
checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false);
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
|
||||
|
||||
// Privileged so this implementation can look at DECLARED classes,
|
||||
// something the caller might not have privilege to do. The code here
|
||||
@ -1467,11 +1463,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Field[] getFields() throws SecurityException {
|
||||
// be very careful not to change the stack depth of this
|
||||
// checkMemberAccess call for security reasons
|
||||
// see java.lang.SecurityManager.checkMemberAccess
|
||||
checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
return copyFields(privateGetPublicFields(null));
|
||||
}
|
||||
|
||||
@ -1518,11 +1512,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Method[] getMethods() throws SecurityException {
|
||||
// be very careful not to change the stack depth of this
|
||||
// checkMemberAccess call for security reasons
|
||||
// see java.lang.SecurityManager.checkMemberAccess
|
||||
checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
return copyMethods(privateGetPublicMethods());
|
||||
}
|
||||
|
||||
@ -1567,11 +1559,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Constructor<?>[] getConstructors() throws SecurityException {
|
||||
// be very careful not to change the stack depth of this
|
||||
// checkMemberAccess call for security reasons
|
||||
// see java.lang.SecurityManager.checkMemberAccess
|
||||
checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
return copyConstructors(privateGetDeclaredConstructors(true));
|
||||
}
|
||||
|
||||
@ -1625,12 +1615,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Field getField(String name)
|
||||
throws NoSuchFieldException, SecurityException {
|
||||
// be very careful not to change the stack depth of this
|
||||
// checkMemberAccess call for security reasons
|
||||
// see java.lang.SecurityManager.checkMemberAccess
|
||||
checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
Field field = getField0(name);
|
||||
if (field == null) {
|
||||
throw new NoSuchFieldException(name);
|
||||
@ -1710,12 +1698,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Method getMethod(String name, Class<?>... parameterTypes)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
// be very careful not to change the stack depth of this
|
||||
// checkMemberAccess call for security reasons
|
||||
// see java.lang.SecurityManager.checkMemberAccess
|
||||
checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
Method method = getMethod0(name, parameterTypes);
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
|
||||
@ -1764,12 +1750,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Constructor<T> getConstructor(Class<?>... parameterTypes)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
// be very careful not to change the stack depth of this
|
||||
// checkMemberAccess call for security reasons
|
||||
// see java.lang.SecurityManager.checkMemberAccess
|
||||
checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true);
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
return getConstructor0(parameterTypes, Member.PUBLIC);
|
||||
}
|
||||
|
||||
@ -1807,11 +1791,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Class<?>[] getDeclaredClasses() throws SecurityException {
|
||||
// be very careful not to change the stack depth of this
|
||||
// checkMemberAccess call for security reasons
|
||||
// see java.lang.SecurityManager.checkMemberAccess
|
||||
checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), false);
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), false);
|
||||
return getDeclaredClasses0();
|
||||
}
|
||||
|
||||
@ -1851,11 +1833,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Field[] getDeclaredFields() throws SecurityException {
|
||||
// be very careful not to change the stack depth of this
|
||||
// checkMemberAccess call for security reasons
|
||||
// see java.lang.SecurityManager.checkMemberAccess
|
||||
checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
return copyFields(privateGetDeclaredFields(false));
|
||||
}
|
||||
|
||||
@ -1899,11 +1879,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Method[] getDeclaredMethods() throws SecurityException {
|
||||
// be very careful not to change the stack depth of this
|
||||
// checkMemberAccess call for security reasons
|
||||
// see java.lang.SecurityManager.checkMemberAccess
|
||||
checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
return copyMethods(privateGetDeclaredMethods(false));
|
||||
}
|
||||
|
||||
@ -1944,11 +1922,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Constructor<?>[] getDeclaredConstructors() throws SecurityException {
|
||||
// be very careful not to change the stack depth of this
|
||||
// checkMemberAccess call for security reasons
|
||||
// see java.lang.SecurityManager.checkMemberAccess
|
||||
checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
return copyConstructors(privateGetDeclaredConstructors(false));
|
||||
}
|
||||
|
||||
@ -1987,12 +1963,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Field getDeclaredField(String name)
|
||||
throws NoSuchFieldException, SecurityException {
|
||||
// be very careful not to change the stack depth of this
|
||||
// checkMemberAccess call for security reasons
|
||||
// see java.lang.SecurityManager.checkMemberAccess
|
||||
checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
Field field = searchFields(privateGetDeclaredFields(false), name);
|
||||
if (field == null) {
|
||||
throw new NoSuchFieldException(name);
|
||||
@ -2042,12 +2016,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
// be very careful not to change the stack depth of this
|
||||
// checkMemberAccess call for security reasons
|
||||
// see java.lang.SecurityManager.checkMemberAccess
|
||||
checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
|
||||
@ -2092,12 +2064,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* @since JDK1.1
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
// be very careful not to change the stack depth of this
|
||||
// checkMemberAccess call for security reasons
|
||||
// see java.lang.SecurityManager.checkMemberAccess
|
||||
checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true);
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
return getConstructor0(parameterTypes, Member.DECLARED);
|
||||
}
|
||||
|
||||
@ -2255,23 +2225,40 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*/
|
||||
static native Class<?> getPrimitiveClass(String name);
|
||||
|
||||
private static boolean isCheckMemberAccessOverridden(SecurityManager smgr) {
|
||||
if (smgr.getClass() == SecurityManager.class) return false;
|
||||
|
||||
Class<?>[] paramTypes = new Class<?>[] {Class.class, int.class};
|
||||
return smgr.getClass().getMethod0("checkMemberAccess", paramTypes).
|
||||
getDeclaringClass() != SecurityManager.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if client is allowed to access members. If access is denied,
|
||||
* throw a SecurityException.
|
||||
*
|
||||
* Be very careful not to change the stack depth of this checkMemberAccess
|
||||
* call for security reasons.
|
||||
* See java.lang.SecurityManager.checkMemberAccess.
|
||||
*
|
||||
* <p> Default policy: allow all clients access with normal Java access
|
||||
* control.
|
||||
*/
|
||||
private void checkMemberAccess(int which, ClassLoader ccl, boolean checkProxyInterfaces) {
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
private void checkMemberAccess(int which, Class<?> caller, boolean checkProxyInterfaces) {
|
||||
final SecurityManager s = System.getSecurityManager();
|
||||
if (s != null) {
|
||||
s.checkMemberAccess(this, which);
|
||||
ClassLoader cl = getClassLoader0();
|
||||
final ClassLoader ccl = ClassLoader.getClassLoader(caller);
|
||||
final ClassLoader cl = getClassLoader0();
|
||||
if (!isCheckMemberAccessOverridden(s)) {
|
||||
// Inlined SecurityManager.checkMemberAccess
|
||||
if (which != Member.PUBLIC) {
|
||||
if (ccl != cl) {
|
||||
s.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Don't refactor; otherwise break the stack depth for
|
||||
// checkMemberAccess of subclasses of SecurityManager as specified.
|
||||
s.checkMemberAccess(this, which);
|
||||
}
|
||||
|
||||
|
||||
if (ReflectUtil.needsPackageAccessCheck(ccl, cl)) {
|
||||
String name = this.getName();
|
||||
int i = name.lastIndexOf('.');
|
||||
|
||||
@ -55,6 +55,7 @@ import sun.misc.CompoundEnumeration;
|
||||
import sun.misc.Resource;
|
||||
import sun.misc.URLClassPath;
|
||||
import sun.misc.VM;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.Reflection;
|
||||
import sun.security.util.SecurityConstants;
|
||||
|
||||
@ -1159,11 +1160,6 @@ public abstract class ClassLoader {
|
||||
return java.util.Collections.emptyEnumeration();
|
||||
}
|
||||
|
||||
// index 0: java.lang.ClassLoader.class
|
||||
// index 1: the immediate caller of index 0.
|
||||
// index 2: the immediate caller of index 1.
|
||||
private static native Class<? extends ClassLoader> getCaller(int index);
|
||||
|
||||
/**
|
||||
* Registers the caller as parallel capable.</p>
|
||||
* The registration succeeds if and only if all of the following
|
||||
@ -1179,8 +1175,11 @@ public abstract class ClassLoader {
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
@CallerSensitive
|
||||
protected static boolean registerAsParallelCapable() {
|
||||
return ParallelLoaders.register(getCaller(1));
|
||||
Class<? extends ClassLoader> callerClass =
|
||||
Reflection.getCallerClass().asSubclass(ClassLoader.class);
|
||||
return ParallelLoaders.register(callerClass);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1340,15 +1339,13 @@ public abstract class ClassLoader {
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
@CallerSensitive
|
||||
public final ClassLoader getParent() {
|
||||
if (parent == null)
|
||||
return null;
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
ClassLoader ccl = getCallerClassLoader();
|
||||
if (needsClassLoaderPermissionCheck(ccl, this)) {
|
||||
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
|
||||
}
|
||||
checkClassLoaderPermission(this, Reflection.getCallerClass());
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
@ -1408,6 +1405,7 @@ public abstract class ClassLoader {
|
||||
*
|
||||
* @revised 1.4
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static ClassLoader getSystemClassLoader() {
|
||||
initSystemClassLoader();
|
||||
if (scl == null) {
|
||||
@ -1415,10 +1413,7 @@ public abstract class ClassLoader {
|
||||
}
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
ClassLoader ccl = getCallerClassLoader();
|
||||
if (needsClassLoaderPermissionCheck(ccl, scl)) {
|
||||
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
|
||||
}
|
||||
checkClassLoaderPermission(scl, Reflection.getCallerClass());
|
||||
}
|
||||
return scl;
|
||||
}
|
||||
@ -1471,8 +1466,8 @@ public abstract class ClassLoader {
|
||||
// class loader 'from' is same as class loader 'to' or an ancestor
|
||||
// of 'to'. The class loader in a system domain can access
|
||||
// any class loader.
|
||||
static boolean needsClassLoaderPermissionCheck(ClassLoader from,
|
||||
ClassLoader to)
|
||||
private static boolean needsClassLoaderPermissionCheck(ClassLoader from,
|
||||
ClassLoader to)
|
||||
{
|
||||
if (from == to)
|
||||
return false;
|
||||
@ -1483,13 +1478,8 @@ public abstract class ClassLoader {
|
||||
return !to.isAncestor(from);
|
||||
}
|
||||
|
||||
// Returns the invoker's class loader, or null if none.
|
||||
// NOTE: This must always be invoked when there is exactly one intervening
|
||||
// frame from the core libraries on the stack between this method's
|
||||
// invocation and the desired invoker.
|
||||
static ClassLoader getCallerClassLoader() {
|
||||
// NOTE use of more generic Reflection.getCallerClass()
|
||||
Class<?> caller = Reflection.getCallerClass(3);
|
||||
// Returns the class's class loader, or null if none.
|
||||
static ClassLoader getClassLoader(Class<?> caller) {
|
||||
// This can be null if the VM is requesting it
|
||||
if (caller == null) {
|
||||
return null;
|
||||
@ -1498,6 +1488,17 @@ public abstract class ClassLoader {
|
||||
return caller.getClassLoader0();
|
||||
}
|
||||
|
||||
static void checkClassLoaderPermission(ClassLoader cl, Class<?> caller) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
// caller can be null if the VM is requesting it
|
||||
ClassLoader ccl = getClassLoader(caller);
|
||||
if (needsClassLoaderPermissionCheck(ccl, cl)) {
|
||||
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The class loader for the system
|
||||
// @GuardedBy("ClassLoader.class")
|
||||
private static ClassLoader scl;
|
||||
|
||||
@ -22,26 +22,55 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Implementing this interface allows an object to be the target of
|
||||
* the "foreach" statement.
|
||||
* the "for-each loop" statement. See
|
||||
* <strong>
|
||||
* <a href="{@docRoot}/../technotes/guides/language/foreach.html">For-each Loop</a>
|
||||
* </strong>
|
||||
*
|
||||
* @param <T> the type of elements returned by the iterator
|
||||
*
|
||||
* @since 1.5
|
||||
* @jls 14.14.2 The enhanced for statement
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Iterable<T> {
|
||||
|
||||
/**
|
||||
* Returns an iterator over a set of elements of type T.
|
||||
* Returns an iterator over elements of type {@code T}.
|
||||
*
|
||||
* @return an Iterator.
|
||||
*/
|
||||
Iterator<T> iterator();
|
||||
|
||||
/**
|
||||
* Performs the given action on the contents of the {@code Iterable}, in the
|
||||
* order elements occur when iterating, until all elements have been
|
||||
* processed or the action throws an exception. Errors or runtime
|
||||
* exceptions thrown by the action are relayed to the caller.
|
||||
*
|
||||
* @implSpec
|
||||
* <p>The default implementation behaves as if:
|
||||
* <pre>{@code
|
||||
* for (T t : this)
|
||||
* action.accept(t);
|
||||
* }</pre>
|
||||
*
|
||||
* @param action The action to be performed for each element
|
||||
* @throws NullPointerException if the specified action is null
|
||||
* @since 1.8
|
||||
*/
|
||||
default void forEach(Consumer<? super T> action) {
|
||||
Objects.requireNonNull(action);
|
||||
for (T t : this) {
|
||||
action.accept(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -479,7 +479,7 @@ public final class Long extends Number implements Comparable<Long> {
|
||||
* of the string as a type indicator, as would be permitted in
|
||||
* Java programming language source code - except that either
|
||||
* {@code L} or {@code l} may appear as a digit for a
|
||||
* radix greater than 22.
|
||||
* radix greater than or equal to 22.
|
||||
*
|
||||
* <p>An exception of type {@code NumberFormatException} is
|
||||
* thrown if any of the following situations occurs:
|
||||
|
||||
@ -49,6 +49,8 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
import sun.net.www.ParseUtil;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.Reflection;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
@ -273,8 +275,9 @@ public class Package implements java.lang.reflect.AnnotatedElement {
|
||||
* @return the package of the requested name. It may be null if no package
|
||||
* information is available from the archive or codebase.
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static Package getPackage(String name) {
|
||||
ClassLoader l = ClassLoader.getCallerClassLoader();
|
||||
ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass());
|
||||
if (l != null) {
|
||||
return l.getPackage(name);
|
||||
} else {
|
||||
@ -294,8 +297,9 @@ public class Package implements java.lang.reflect.AnnotatedElement {
|
||||
* @return a new array of packages known to the callers {@code ClassLoader}
|
||||
* instance. An zero length array is returned if none are known.
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static Package[] getPackages() {
|
||||
ClassLoader l = ClassLoader.getCallerClassLoader();
|
||||
ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass());
|
||||
if (l != null) {
|
||||
return l.getPackages();
|
||||
} else {
|
||||
|
||||
@ -30,6 +30,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.security.AccessControlException;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -1024,13 +1025,24 @@ public final class ProcessBuilder
|
||||
redirects,
|
||||
redirectErrorStream);
|
||||
} catch (IOException e) {
|
||||
String exceptionInfo = ": " + e.getMessage();
|
||||
Throwable cause = e;
|
||||
if (security != null) {
|
||||
// Can not disclose the fail reason for read-protected files.
|
||||
try {
|
||||
security.checkRead(prog);
|
||||
} catch (AccessControlException ace) {
|
||||
exceptionInfo = "";
|
||||
cause = ace;
|
||||
}
|
||||
}
|
||||
// It's much easier for us to create a high-quality error
|
||||
// message than the low-level C code which found the problem.
|
||||
throw new IOException(
|
||||
"Cannot run program \"" + prog + "\""
|
||||
+ (dir == null ? "" : " (in directory \"" + dir + "\")")
|
||||
+ ": " + e.getMessage(),
|
||||
e);
|
||||
+ exceptionInfo,
|
||||
cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,6 +27,8 @@ package java.lang;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.StringTokenizer;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.Reflection;
|
||||
|
||||
/**
|
||||
* Every Java application has a single instance of class
|
||||
@ -790,8 +792,9 @@ public class Runtime {
|
||||
* @see java.lang.SecurityException
|
||||
* @see java.lang.SecurityManager#checkLink(java.lang.String)
|
||||
*/
|
||||
@CallerSensitive
|
||||
public void load(String filename) {
|
||||
load0(System.getCallerClass(), filename);
|
||||
load0(Reflection.getCallerClass(), filename);
|
||||
}
|
||||
|
||||
synchronized void load0(Class<?> fromClass, String filename) {
|
||||
@ -850,8 +853,9 @@ public class Runtime {
|
||||
* @see java.lang.SecurityException
|
||||
* @see java.lang.SecurityManager#checkLink(java.lang.String)
|
||||
*/
|
||||
@CallerSensitive
|
||||
public void loadLibrary(String libname) {
|
||||
loadLibrary0(System.getCallerClass(), libname);
|
||||
loadLibrary0(Reflection.getCallerClass(), libname);
|
||||
}
|
||||
|
||||
synchronized void loadLibrary0(Class<?> fromClass, String libname) {
|
||||
|
||||
@ -36,10 +36,10 @@ import java.net.SocketPermission;
|
||||
import java.net.NetPermission;
|
||||
import java.util.Hashtable;
|
||||
import java.net.InetAddress;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.URL;
|
||||
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.security.util.SecurityConstants;
|
||||
|
||||
/**
|
||||
@ -1679,6 +1679,7 @@ class SecurityManager {
|
||||
* @since JDK1.1
|
||||
* @see #checkPermission(java.security.Permission) checkPermission
|
||||
*/
|
||||
@CallerSensitive
|
||||
public void checkMemberAccess(Class<?> clazz, int which) {
|
||||
if (clazz == null) {
|
||||
throw new NullPointerException("class can't be null");
|
||||
|
||||
@ -35,6 +35,7 @@ import java.security.AllPermission;
|
||||
import java.nio.channels.Channel;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import sun.nio.ch.Interruptible;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.Reflection;
|
||||
import sun.security.util.SecurityConstants;
|
||||
import sun.reflect.annotation.AnnotationType;
|
||||
@ -1072,8 +1073,9 @@ public final class System {
|
||||
* @see java.lang.Runtime#load(java.lang.String)
|
||||
* @see java.lang.SecurityManager#checkLink(java.lang.String)
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static void load(String filename) {
|
||||
Runtime.getRuntime().load0(getCallerClass(), filename);
|
||||
Runtime.getRuntime().load0(Reflection.getCallerClass(), filename);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1107,8 +1109,9 @@ public final class System {
|
||||
* @see java.lang.Runtime#loadLibrary(java.lang.String)
|
||||
* @see java.lang.SecurityManager#checkLink(java.lang.String)
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static void loadLibrary(String libname) {
|
||||
Runtime.getRuntime().loadLibrary0(getCallerClass(), libname);
|
||||
Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1245,10 +1248,4 @@ public final class System {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* returns the class of the caller. */
|
||||
static Class<?> getCallerClass() {
|
||||
// NOTE use of more generic Reflection.getCallerClass()
|
||||
return Reflection.getCallerClass(3);
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,6 +37,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import sun.nio.ch.Interruptible;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.Reflection;
|
||||
import sun.security.util.SecurityConstants;
|
||||
|
||||
|
||||
@ -1443,15 +1445,14 @@ class Thread implements Runnable {
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
@CallerSensitive
|
||||
public ClassLoader getContextClassLoader() {
|
||||
if (contextClassLoader == null)
|
||||
return null;
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
ClassLoader ccl = ClassLoader.getCallerClassLoader();
|
||||
if (ClassLoader.needsClassLoaderPermissionCheck(ccl, contextClassLoader)) {
|
||||
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
|
||||
}
|
||||
ClassLoader.checkClassLoaderPermission(contextClassLoader,
|
||||
Reflection.getCallerClass());
|
||||
}
|
||||
return contextClassLoader;
|
||||
}
|
||||
|
||||
@ -709,7 +709,9 @@ import jdk.internal.org.objectweb.asm.Type;
|
||||
InvokerBytecodeGenerator.maybeDump(className, classFile);
|
||||
Class<? extends BoundMethodHandle> bmhClass =
|
||||
//UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
|
||||
UNSAFE.defineClass(className, classFile, 0, classFile.length).asSubclass(BoundMethodHandle.class);
|
||||
UNSAFE.defineClass(className, classFile, 0, classFile.length,
|
||||
BoundMethodHandle.class.getClassLoader(), null)
|
||||
.asSubclass(BoundMethodHandle.class);
|
||||
UNSAFE.ensureClassInitialized(bmhClass);
|
||||
|
||||
return bmhClass;
|
||||
|
||||
@ -184,7 +184,7 @@ import java.security.PrivilegedAction;
|
||||
for (int i=0; i<markerInterfaces.length; i++) {
|
||||
interfaces[i+1] = markerInterfaces[i].getName().replace('.', '/');
|
||||
}
|
||||
cw.visit(CLASSFILE_VERSION, ACC_SUPER,
|
||||
cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
|
||||
lambdaClassName, null,
|
||||
NAME_MAGIC_ACCESSOR_IMPL, interfaces);
|
||||
|
||||
|
||||
@ -391,10 +391,11 @@ import java.util.Objects;
|
||||
|
||||
// private flags, not part of RECOGNIZED_MODIFIERS:
|
||||
static final int
|
||||
IS_METHOD = MN_IS_METHOD, // method (not constructor)
|
||||
IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
|
||||
IS_FIELD = MN_IS_FIELD, // field
|
||||
IS_TYPE = MN_IS_TYPE; // nested type
|
||||
IS_METHOD = MN_IS_METHOD, // method (not constructor)
|
||||
IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
|
||||
IS_FIELD = MN_IS_FIELD, // field
|
||||
IS_TYPE = MN_IS_TYPE, // nested type
|
||||
CALLER_SENSITIVE = MN_CALLER_SENSITIVE; // @CallerSensitive annotation detected
|
||||
|
||||
static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
|
||||
static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
|
||||
@ -430,6 +431,10 @@ import java.util.Objects;
|
||||
public boolean isPackage() {
|
||||
return !testAnyFlags(ALL_ACCESS);
|
||||
}
|
||||
/** Query whether this member has a CallerSensitive annotation. */
|
||||
public boolean isCallerSensitive() {
|
||||
return testAllFlags(CALLER_SENSITIVE);
|
||||
}
|
||||
|
||||
/** Utility method to query whether this member is accessible from a given lookup class. */
|
||||
public boolean isAccessibleFrom(Class<?> lookupClass) {
|
||||
|
||||
@ -34,6 +34,8 @@ import sun.invoke.empty.Empty;
|
||||
import sun.invoke.util.ValueConversions;
|
||||
import sun.invoke.util.VerifyType;
|
||||
import sun.invoke.util.Wrapper;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.Reflection;
|
||||
import static java.lang.invoke.LambdaForm.*;
|
||||
import static java.lang.invoke.MethodHandleStatics.*;
|
||||
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
@ -891,9 +893,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
}
|
||||
}
|
||||
|
||||
@CallerSensitive
|
||||
private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) {
|
||||
final int FRAME_COUNT_ARG = 2; // [0] Reflection [1] BindCaller [2] Expected
|
||||
Class<?> actual = sun.reflect.Reflection.getCallerClass(FRAME_COUNT_ARG);
|
||||
// This method is called via MH_checkCallerClass and so it's
|
||||
// correct to ask for the immediate caller here.
|
||||
Class<?> actual = Reflection.getCallerClass();
|
||||
if (actual != expected && actual != expected2)
|
||||
throw new InternalError("found "+actual.getName()+", expected "+expected.getName()
|
||||
+(expected == expected2 ? "" : ", or else "+expected2.getName()));
|
||||
|
||||
@ -26,7 +26,6 @@
|
||||
package java.lang.invoke;
|
||||
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import static java.lang.invoke.MethodHandleNatives.Constants.*;
|
||||
import static java.lang.invoke.MethodHandleStatics.*;
|
||||
@ -34,7 +33,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
|
||||
/**
|
||||
* The JVM interface for the method handles package is all here.
|
||||
* This is an interface internal and private to an implemetantion of JSR 292.
|
||||
* This is an interface internal and private to an implementation of JSR 292.
|
||||
* <em>This class is not part of the JSR 292 standard.</em>
|
||||
* @author jrose
|
||||
*/
|
||||
@ -101,6 +100,7 @@ class MethodHandleNatives {
|
||||
MN_IS_CONSTRUCTOR = 0x00020000, // constructor
|
||||
MN_IS_FIELD = 0x00040000, // field
|
||||
MN_IS_TYPE = 0x00080000, // nested type
|
||||
MN_CALLER_SENSITIVE = 0x00100000, // @CallerSensitive annotation detected
|
||||
MN_REFERENCE_KIND_SHIFT = 24, // refKind
|
||||
MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT,
|
||||
// The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers:
|
||||
@ -391,129 +391,24 @@ class MethodHandleNatives {
|
||||
* I.e., does it call Reflection.getCallerClass or a similer method
|
||||
* to ask about the identity of its caller?
|
||||
*/
|
||||
// FIXME: Replace this pattern match by an annotation @sun.reflect.CallerSensitive.
|
||||
static boolean isCallerSensitive(MemberName mem) {
|
||||
if (!mem.isInvocable()) return false; // fields are not caller sensitive
|
||||
|
||||
return mem.isCallerSensitive() || canBeCalledVirtual(mem);
|
||||
}
|
||||
|
||||
static boolean canBeCalledVirtual(MemberName mem) {
|
||||
assert(mem.isInvocable());
|
||||
Class<?> defc = mem.getDeclaringClass();
|
||||
switch (mem.getName()) {
|
||||
case "doPrivileged":
|
||||
case "doPrivilegedWithCombiner":
|
||||
return defc == java.security.AccessController.class;
|
||||
case "checkMemberAccess":
|
||||
return canBeCalledVirtual(mem, java.lang.SecurityManager.class);
|
||||
case "getUnsafe":
|
||||
return defc == sun.misc.Unsafe.class;
|
||||
case "lookup":
|
||||
return defc == java.lang.invoke.MethodHandles.class;
|
||||
case "findStatic":
|
||||
case "findVirtual":
|
||||
case "findConstructor":
|
||||
case "findSpecial":
|
||||
case "findGetter":
|
||||
case "findSetter":
|
||||
case "findStaticGetter":
|
||||
case "findStaticSetter":
|
||||
case "bind":
|
||||
case "unreflect":
|
||||
case "unreflectSpecial":
|
||||
case "unreflectConstructor":
|
||||
case "unreflectGetter":
|
||||
case "unreflectSetter":
|
||||
return defc == java.lang.invoke.MethodHandles.Lookup.class;
|
||||
case "invoke":
|
||||
return defc == java.lang.reflect.Method.class;
|
||||
case "get":
|
||||
case "getBoolean":
|
||||
case "getByte":
|
||||
case "getChar":
|
||||
case "getShort":
|
||||
case "getInt":
|
||||
case "getLong":
|
||||
case "getFloat":
|
||||
case "getDouble":
|
||||
case "set":
|
||||
case "setBoolean":
|
||||
case "setByte":
|
||||
case "setChar":
|
||||
case "setShort":
|
||||
case "setInt":
|
||||
case "setLong":
|
||||
case "setFloat":
|
||||
case "setDouble":
|
||||
return defc == java.lang.reflect.Field.class;
|
||||
case "newInstance":
|
||||
if (defc == java.lang.reflect.Constructor.class) return true;
|
||||
if (defc == java.lang.Class.class) return true;
|
||||
break;
|
||||
case "forName":
|
||||
case "getClassLoader":
|
||||
case "getClasses":
|
||||
case "getFields":
|
||||
case "getMethods":
|
||||
case "getConstructors":
|
||||
case "getDeclaredClasses":
|
||||
case "getDeclaredFields":
|
||||
case "getDeclaredMethods":
|
||||
case "getDeclaredConstructors":
|
||||
case "getField":
|
||||
case "getMethod":
|
||||
case "getConstructor":
|
||||
case "getDeclaredField":
|
||||
case "getDeclaredMethod":
|
||||
case "getDeclaredConstructor":
|
||||
return defc == java.lang.Class.class;
|
||||
case "getConnection":
|
||||
case "getDriver":
|
||||
case "getDrivers":
|
||||
case "deregisterDriver":
|
||||
return defc == getClass("java.sql.DriverManager");
|
||||
case "newUpdater":
|
||||
if (defc == java.util.concurrent.atomic.AtomicIntegerFieldUpdater.class) return true;
|
||||
if (defc == java.util.concurrent.atomic.AtomicLongFieldUpdater.class) return true;
|
||||
if (defc == java.util.concurrent.atomic.AtomicReferenceFieldUpdater.class) return true;
|
||||
break;
|
||||
case "getContextClassLoader":
|
||||
return canBeCalledVirtual(mem, java.lang.Thread.class);
|
||||
case "getPackage":
|
||||
case "getPackages":
|
||||
return defc == java.lang.Package.class;
|
||||
case "getParent":
|
||||
case "getSystemClassLoader":
|
||||
return defc == java.lang.ClassLoader.class;
|
||||
case "load":
|
||||
case "loadLibrary":
|
||||
if (defc == java.lang.Runtime.class) return true;
|
||||
if (defc == java.lang.System.class) return true;
|
||||
break;
|
||||
case "getCallerClass":
|
||||
if (defc == sun.reflect.Reflection.class) return true;
|
||||
if (defc == java.lang.System.class) return true;
|
||||
break;
|
||||
case "getCallerClassLoader":
|
||||
return defc == java.lang.ClassLoader.class;
|
||||
case "registerAsParallelCapable":
|
||||
return canBeCalledVirtual(mem, java.lang.ClassLoader.class);
|
||||
case "getProxyClass":
|
||||
case "newProxyInstance":
|
||||
return defc == java.lang.reflect.Proxy.class;
|
||||
case "asInterfaceInstance":
|
||||
return defc == java.lang.invoke.MethodHandleProxies.class;
|
||||
case "getBundle":
|
||||
case "clearCache":
|
||||
return defc == java.util.ResourceBundle.class;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// avoid static dependency to a class in other modules
|
||||
private static Class<?> getClass(String cn) {
|
||||
try {
|
||||
return Class.forName(cn, false,
|
||||
MethodHandleNatives.class.getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
static boolean canBeCalledVirtual(MemberName symbolicRef, Class<?> definingClass) {
|
||||
Class<?> symbolicRefClass = symbolicRef.getDeclaringClass();
|
||||
if (symbolicRefClass == definingClass) return true;
|
||||
|
||||
@ -30,6 +30,7 @@ import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import sun.invoke.WrapperInstance;
|
||||
import java.util.ArrayList;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.Reflection;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
|
||||
@ -137,14 +138,14 @@ public class MethodHandleProxies {
|
||||
// entry points, must be covered by hand-written or automatically
|
||||
// generated adapter classes.
|
||||
//
|
||||
@CallerSensitive
|
||||
public static
|
||||
<T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
|
||||
if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
|
||||
throw new IllegalArgumentException("not a public interface: "+intfc.getName());
|
||||
final MethodHandle mh;
|
||||
if (System.getSecurityManager() != null) {
|
||||
final int CALLER_FRAME = 2; // 0: Reflection, 1: asInterfaceInstance, 2: caller
|
||||
final Class<?> caller = Reflection.getCallerClass(CALLER_FRAME);
|
||||
final Class<?> caller = Reflection.getCallerClass();
|
||||
final ClassLoader ccl = caller != null ? caller.getClassLoader() : null;
|
||||
ReflectUtil.checkProxyPackageAccess(ccl, intfc);
|
||||
mh = ccl != null ? bindCaller(target, caller) : target;
|
||||
|
||||
@ -26,13 +26,17 @@
|
||||
package java.lang.invoke;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import sun.invoke.util.ValueConversions;
|
||||
import sun.invoke.util.VerifyAccess;
|
||||
import sun.invoke.util.Wrapper;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import sun.invoke.util.ValueConversions;
|
||||
import sun.invoke.util.VerifyAccess;
|
||||
import sun.invoke.util.Wrapper;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.Reflection;
|
||||
import sun.security.util.SecurityConstants;
|
||||
import static java.lang.invoke.MethodHandleStatics.*;
|
||||
import static java.lang.invoke.MethodHandleNatives.Constants.*;
|
||||
|
||||
@ -65,8 +69,9 @@ public class MethodHandles {
|
||||
* This lookup object is a <em>capability</em> which may be delegated to trusted agents.
|
||||
* Do not store it in place where untrusted code can access it.
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static Lookup lookup() {
|
||||
return new Lookup();
|
||||
return new Lookup(Reflection.getCallerClass());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -416,18 +421,11 @@ public class MethodHandles {
|
||||
* for method handle creation.
|
||||
* Must be called by from a method in this package,
|
||||
* which in turn is called by a method not in this package.
|
||||
* <p>
|
||||
* Also, don't make it private, lest javac interpose
|
||||
* an access$N method.
|
||||
*/
|
||||
Lookup() {
|
||||
this(getCallerClassAtEntryPoint(false), ALL_MODES);
|
||||
// make sure we haven't accidentally picked up a privileged class:
|
||||
checkUnprivilegedlookupClass(lookupClass);
|
||||
}
|
||||
|
||||
Lookup(Class<?> lookupClass) {
|
||||
this(lookupClass, ALL_MODES);
|
||||
// make sure we haven't accidentally picked up a privileged class:
|
||||
checkUnprivilegedlookupClass(lookupClass);
|
||||
}
|
||||
|
||||
private Lookup(Class<?> lookupClass, int allowedModes) {
|
||||
@ -554,20 +552,6 @@ public class MethodHandles {
|
||||
}
|
||||
}
|
||||
|
||||
/* Obtain the external caller class, when called from Lookup.<init> or a first-level subroutine. */
|
||||
private static Class<?> getCallerClassAtEntryPoint(boolean inSubroutine) {
|
||||
final int CALLER_DEPTH = 4;
|
||||
// Stack for the constructor entry point (inSubroutine=false):
|
||||
// 0: Reflection.getCC, 1: getCallerClassAtEntryPoint,
|
||||
// 2: Lookup.<init>, 3: MethodHandles.*, 4: caller
|
||||
// The stack is slightly different for a subroutine of a Lookup.find* method:
|
||||
// 2: Lookup.*, 3: Lookup.find*.*, 4: caller
|
||||
// Note: This should be the only use of getCallerClass in this file.
|
||||
assert(Reflection.getCallerClass(CALLER_DEPTH-2) == Lookup.class);
|
||||
assert(Reflection.getCallerClass(CALLER_DEPTH-1) == (inSubroutine ? Lookup.class : MethodHandles.class));
|
||||
return Reflection.getCallerClass(CALLER_DEPTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a method handle for a static method.
|
||||
* The type of the method handle will be that of the method.
|
||||
@ -594,12 +578,14 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public
|
||||
MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
|
||||
MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
|
||||
checkSecurityManager(refc, method); // stack walk magic: do not refactor
|
||||
Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
|
||||
return getDirectMethod(REF_invokeStatic, refc, method, callerClass);
|
||||
Class<?> callerClass = Reflection.getCallerClass();
|
||||
checkSecurityManager(refc, method, callerClass);
|
||||
return getDirectMethod(REF_invokeStatic, refc, method,
|
||||
findBoundCallerClass(method, callerClass));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -645,6 +631,7 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
|
||||
if (refc == MethodHandle.class) {
|
||||
MethodHandle mh = findVirtualForMH(name, type);
|
||||
@ -652,9 +639,10 @@ public class MethodHandles {
|
||||
}
|
||||
byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
|
||||
MemberName method = resolveOrFail(refKind, refc, name, type);
|
||||
checkSecurityManager(refc, method); // stack walk magic: do not refactor
|
||||
Class<?> callerClass = findBoundCallerClass(method);
|
||||
return getDirectMethod(refKind, refc, method, callerClass);
|
||||
Class<?> callerClass = Reflection.getCallerClass();
|
||||
checkSecurityManager(refc, method, callerClass);
|
||||
return getDirectMethod(refKind, refc, method,
|
||||
findBoundCallerClass(method, callerClass));
|
||||
}
|
||||
private MethodHandle findVirtualForMH(String name, MethodType type) {
|
||||
// these names require special lookups because of the implicit MethodType argument
|
||||
@ -691,10 +679,11 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
|
||||
String name = "<init>";
|
||||
MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
|
||||
checkSecurityManager(refc, ctor); // stack walk magic: do not refactor
|
||||
checkSecurityManager(refc, ctor, Reflection.getCallerClass());
|
||||
return getDirectConstructor(refc, ctor);
|
||||
}
|
||||
|
||||
@ -732,14 +721,16 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle findSpecial(Class<?> refc, String name, MethodType type,
|
||||
Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
|
||||
checkSpecialCaller(specialCaller);
|
||||
Lookup specialLookup = this.in(specialCaller);
|
||||
MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
|
||||
checkSecurityManager(refc, method); // stack walk magic: do not refactor
|
||||
Class<?> callerClass = findBoundCallerClass(method);
|
||||
return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, callerClass);
|
||||
Class<?> callerClass = Reflection.getCallerClass();
|
||||
checkSecurityManager(refc, method, callerClass);
|
||||
return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method,
|
||||
findBoundCallerClass(method, callerClass));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -759,9 +750,10 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
|
||||
MemberName field = resolveOrFail(REF_getField, refc, name, type);
|
||||
checkSecurityManager(refc, field); // stack walk magic: do not refactor
|
||||
checkSecurityManager(refc, field, Reflection.getCallerClass());
|
||||
return getDirectField(REF_getField, refc, field);
|
||||
}
|
||||
|
||||
@ -782,9 +774,10 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
|
||||
MemberName field = resolveOrFail(REF_putField, refc, name, type);
|
||||
checkSecurityManager(refc, field); // stack walk magic: do not refactor
|
||||
checkSecurityManager(refc, field, Reflection.getCallerClass());
|
||||
return getDirectField(REF_putField, refc, field);
|
||||
}
|
||||
|
||||
@ -804,9 +797,10 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
|
||||
MemberName field = resolveOrFail(REF_getStatic, refc, name, type);
|
||||
checkSecurityManager(refc, field); // stack walk magic: do not refactor
|
||||
checkSecurityManager(refc, field, Reflection.getCallerClass());
|
||||
return getDirectField(REF_getStatic, refc, field);
|
||||
}
|
||||
|
||||
@ -826,9 +820,10 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
|
||||
MemberName field = resolveOrFail(REF_putStatic, refc, name, type);
|
||||
checkSecurityManager(refc, field); // stack walk magic: do not refactor
|
||||
checkSecurityManager(refc, field, Reflection.getCallerClass());
|
||||
return getDirectField(REF_putStatic, refc, field);
|
||||
}
|
||||
|
||||
@ -878,12 +873,14 @@ return mh1;
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
|
||||
Class<? extends Object> refc = receiver.getClass(); // may get NPE
|
||||
MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
|
||||
checkSecurityManager(refc, method); // stack walk magic: do not refactor
|
||||
Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
|
||||
MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, callerClass);
|
||||
Class<?> callerClass = Reflection.getCallerClass();
|
||||
checkSecurityManager(refc, method, callerClass);
|
||||
MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method,
|
||||
findBoundCallerClass(method, callerClass));
|
||||
return mh.bindReceiver(receiver).setVarargs(method);
|
||||
}
|
||||
|
||||
@ -908,13 +905,14 @@ return mh1;
|
||||
* is set and {@code asVarargsCollector} fails
|
||||
* @throws NullPointerException if the argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle unreflect(Method m) throws IllegalAccessException {
|
||||
MemberName method = new MemberName(m);
|
||||
byte refKind = method.getReferenceKind();
|
||||
if (refKind == REF_invokeSpecial)
|
||||
refKind = REF_invokeVirtual;
|
||||
assert(method.isMethod());
|
||||
Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
|
||||
Class<?> callerClass = findBoundCallerClass(method, Reflection.getCallerClass());
|
||||
Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
|
||||
return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, callerClass);
|
||||
}
|
||||
@ -940,12 +938,13 @@ return mh1;
|
||||
* is set and {@code asVarargsCollector} fails
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
|
||||
checkSpecialCaller(specialCaller);
|
||||
Lookup specialLookup = this.in(specialCaller);
|
||||
MemberName method = new MemberName(m, true);
|
||||
assert(method.isMethod());
|
||||
Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
|
||||
Class<?> callerClass = findBoundCallerClass(method, Reflection.getCallerClass());
|
||||
// ignore m.isAccessible: this is a new kind of access
|
||||
return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, callerClass);
|
||||
}
|
||||
@ -1050,20 +1049,35 @@ return mh1;
|
||||
* If this lookup object has private access, then the caller class is the lookupClass.
|
||||
* Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual).
|
||||
* This is the same caller class as is used by checkSecurityManager.
|
||||
* This function performs stack walk magic: do not refactor it.
|
||||
*/
|
||||
Class<?> findBoundCallerClass(MemberName m) {
|
||||
Class<?> findBoundCallerClass(MemberName m, Class<?> callerAtEntryPoint) {
|
||||
Class<?> callerClass = null;
|
||||
if (MethodHandleNatives.isCallerSensitive(m)) {
|
||||
// Do not refactor this to a more "logical" place, since it is stack walk magic.
|
||||
// Note that this is the same expression as in Step 2 below in checkSecurityManager.
|
||||
callerClass = ((allowedModes & PRIVATE) != 0
|
||||
? lookupClass // for strong access modes, no extra check
|
||||
// next line does stack walk magic; do not refactor:
|
||||
: getCallerClassAtEntryPoint(true));
|
||||
: callerAtEntryPoint);
|
||||
}
|
||||
return callerClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a security manager has an overridden
|
||||
* SecurityManager.checkMemberAccess method.
|
||||
*/
|
||||
private boolean isCheckMemberAccessOverridden(SecurityManager sm) {
|
||||
final Class<? extends SecurityManager> cls = sm.getClass();
|
||||
if (cls == SecurityManager.class) return false;
|
||||
|
||||
try {
|
||||
return cls.getMethod("checkMemberAccess", Class.class, int.class).
|
||||
getDeclaringClass() != SecurityManager.class;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new InternalError("should not reach here");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>.
|
||||
* Determines a trustable caller class to compare with refc, the symbolic reference class.
|
||||
@ -1071,46 +1085,55 @@ return mh1;
|
||||
* Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual).
|
||||
* This function performs stack walk magic: do not refactor it.
|
||||
*/
|
||||
void checkSecurityManager(Class<?> refc, MemberName m) {
|
||||
void checkSecurityManager(Class<?> refc, MemberName m, Class<?> caller) {
|
||||
SecurityManager smgr = System.getSecurityManager();
|
||||
if (smgr == null) return;
|
||||
if (allowedModes == TRUSTED) return;
|
||||
|
||||
final boolean overridden = isCheckMemberAccessOverridden(smgr);
|
||||
// Step 1:
|
||||
smgr.checkMemberAccess(refc, Member.PUBLIC);
|
||||
{
|
||||
// Default policy is to allow Member.PUBLIC; no need to check
|
||||
// permission if SecurityManager is the default implementation
|
||||
final int which = Member.PUBLIC;
|
||||
final Class<?> clazz = refc;
|
||||
if (overridden) {
|
||||
// Don't refactor; otherwise break the stack depth for
|
||||
// checkMemberAccess of subclasses of SecurityManager as specified.
|
||||
smgr.checkMemberAccess(clazz, which);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2:
|
||||
Class<?> callerClass = ((allowedModes & PRIVATE) != 0
|
||||
? lookupClass // for strong access modes, no extra check
|
||||
// next line does stack walk magic; do not refactor:
|
||||
: getCallerClassAtEntryPoint(true));
|
||||
: caller);
|
||||
if (!VerifyAccess.classLoaderIsAncestor(lookupClass, refc) ||
|
||||
(callerClass != lookupClass &&
|
||||
!VerifyAccess.classLoaderIsAncestor(callerClass, refc)))
|
||||
smgr.checkPackageAccess(VerifyAccess.getPackageName(refc));
|
||||
|
||||
// Step 3:
|
||||
if (m.isPublic()) return;
|
||||
Class<?> defc = m.getDeclaringClass();
|
||||
smgr.checkMemberAccess(defc, Member.DECLARED); // STACK WALK HERE
|
||||
{
|
||||
// Inline SecurityManager.checkMemberAccess
|
||||
final int which = Member.DECLARED;
|
||||
final Class<?> clazz = defc;
|
||||
if (!overridden) {
|
||||
if (caller.getClassLoader() != clazz.getClassLoader()) {
|
||||
smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
|
||||
}
|
||||
} else {
|
||||
// Don't refactor; otherwise break the stack depth for
|
||||
// checkMemberAccess of subclasses of SecurityManager as specified.
|
||||
smgr.checkMemberAccess(clazz, which);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4:
|
||||
if (defc != refc)
|
||||
smgr.checkPackageAccess(VerifyAccess.getPackageName(defc));
|
||||
|
||||
// Comment from SM.checkMemberAccess, where which=DECLARED:
|
||||
/*
|
||||
* stack depth of 4 should be the caller of one of the
|
||||
* methods in java.lang.Class that invoke checkMember
|
||||
* access. The stack should look like:
|
||||
*
|
||||
* someCaller [3]
|
||||
* java.lang.Class.someReflectionAPI [2]
|
||||
* java.lang.Class.checkMemberAccess [1]
|
||||
* SecurityManager.checkMemberAccess [0]
|
||||
*
|
||||
*/
|
||||
// For us it is this stack:
|
||||
// someCaller [3]
|
||||
// Lookup.findSomeMember [2]
|
||||
// Lookup.checkSecurityManager [1]
|
||||
// SecurityManager.checkMemberAccess [0]
|
||||
}
|
||||
|
||||
void checkMethod(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
|
||||
@ -1237,6 +1260,30 @@ return mh1;
|
||||
checkMethod(refKind, refc, method);
|
||||
if (method.isMethodHandleInvoke())
|
||||
return fakeMethodHandleInvoke(method);
|
||||
|
||||
Class<?> refcAsSuper;
|
||||
if (refKind == REF_invokeSpecial &&
|
||||
refc != lookupClass() &&
|
||||
refc != (refcAsSuper = lookupClass().getSuperclass()) &&
|
||||
refc.isAssignableFrom(lookupClass())) {
|
||||
assert(!method.getName().equals("<init>")); // not this code path
|
||||
// Per JVMS 6.5, desc. of invokespecial instruction:
|
||||
// If the method is in a superclass of the LC,
|
||||
// and if our original search was above LC.super,
|
||||
// repeat the search (symbolic lookup) from LC.super.
|
||||
// FIXME: MemberName.resolve should handle this instead.
|
||||
MemberName m2 = new MemberName(refcAsSuper,
|
||||
method.getName(),
|
||||
method.getMethodType(),
|
||||
REF_invokeSpecial);
|
||||
m2 = IMPL_NAMES.resolveOrNull(refKind, m2, lookupClassOrNull());
|
||||
if (m2 == null) throw new InternalError(method.toString());
|
||||
method = m2;
|
||||
refc = refcAsSuper;
|
||||
// redo basic checks
|
||||
checkMethod(refKind, refc, method);
|
||||
}
|
||||
|
||||
MethodHandle mh = DirectMethodHandle.make(refKind, refc, method);
|
||||
mh = maybeBindCaller(method, mh, callerClass);
|
||||
mh = mh.setVarargs(method);
|
||||
|
||||
@ -38,9 +38,9 @@ final class Finalizer extends FinalReference { /* Package-private; must be in
|
||||
*/
|
||||
static native void invokeFinalizeMethod(Object o) throws Throwable;
|
||||
|
||||
static private ReferenceQueue queue = new ReferenceQueue();
|
||||
static private Finalizer unfinalized = null;
|
||||
static private Object lock = new Object();
|
||||
private static ReferenceQueue queue = new ReferenceQueue();
|
||||
private static Finalizer unfinalized = null;
|
||||
private static final Object lock = new Object();
|
||||
|
||||
private Finalizer
|
||||
next = null,
|
||||
@ -142,7 +142,11 @@ final class Finalizer extends FinalReference { /* Package-private; must be in
|
||||
/* Called by Runtime.runFinalization() */
|
||||
static void runFinalization() {
|
||||
forkSecondaryFinalizer(new Runnable() {
|
||||
private volatile boolean running;
|
||||
public void run() {
|
||||
if (running)
|
||||
return;
|
||||
running = true;
|
||||
for (;;) {
|
||||
Finalizer f = (Finalizer)queue.poll();
|
||||
if (f == null) break;
|
||||
@ -155,7 +159,11 @@ final class Finalizer extends FinalReference { /* Package-private; must be in
|
||||
/* Invoked by java.lang.Shutdown */
|
||||
static void runAllFinalizers() {
|
||||
forkSecondaryFinalizer(new Runnable() {
|
||||
private volatile boolean running;
|
||||
public void run() {
|
||||
if (running)
|
||||
return;
|
||||
running = true;
|
||||
for (;;) {
|
||||
Finalizer f;
|
||||
synchronized (lock) {
|
||||
@ -168,10 +176,14 @@ final class Finalizer extends FinalReference { /* Package-private; must be in
|
||||
}
|
||||
|
||||
private static class FinalizerThread extends Thread {
|
||||
private volatile boolean running;
|
||||
FinalizerThread(ThreadGroup g) {
|
||||
super(g, "Finalizer");
|
||||
}
|
||||
public void run() {
|
||||
if (running)
|
||||
return;
|
||||
running = true;
|
||||
for (;;) {
|
||||
try {
|
||||
Finalizer f = (Finalizer)queue.remove();
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
package java.lang.reflect;
|
||||
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.ConstructorAccessor;
|
||||
import sun.reflect.Reflection;
|
||||
import sun.reflect.generics.repository.ConstructorRepository;
|
||||
@ -392,14 +393,14 @@ public final class Constructor<T> extends Executable {
|
||||
* @exception ExceptionInInitializerError if the initialization provoked
|
||||
* by this method fails.
|
||||
*/
|
||||
@CallerSensitive
|
||||
public T newInstance(Object ... initargs)
|
||||
throws InstantiationException, IllegalAccessException,
|
||||
IllegalArgumentException, InvocationTargetException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass(2);
|
||||
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, null, modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
package java.lang.reflect;
|
||||
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.FieldAccessor;
|
||||
import sun.reflect.Reflection;
|
||||
import sun.reflect.generics.repository.FieldRepository;
|
||||
@ -376,9 +377,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* @exception ExceptionInInitializerError if the initialization provoked
|
||||
* by this method fails.
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Object get(Object obj)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
return getFieldAccessor(obj).get(obj);
|
||||
}
|
||||
|
||||
@ -404,9 +412,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#get
|
||||
*/
|
||||
@CallerSensitive
|
||||
public boolean getBoolean(Object obj)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
return getFieldAccessor(obj).getBoolean(obj);
|
||||
}
|
||||
|
||||
@ -432,9 +447,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#get
|
||||
*/
|
||||
@CallerSensitive
|
||||
public byte getByte(Object obj)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
return getFieldAccessor(obj).getByte(obj);
|
||||
}
|
||||
|
||||
@ -462,9 +484,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#get
|
||||
*/
|
||||
@CallerSensitive
|
||||
public char getChar(Object obj)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
return getFieldAccessor(obj).getChar(obj);
|
||||
}
|
||||
|
||||
@ -492,9 +521,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#get
|
||||
*/
|
||||
@CallerSensitive
|
||||
public short getShort(Object obj)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
return getFieldAccessor(obj).getShort(obj);
|
||||
}
|
||||
|
||||
@ -522,9 +558,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#get
|
||||
*/
|
||||
@CallerSensitive
|
||||
public int getInt(Object obj)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
return getFieldAccessor(obj).getInt(obj);
|
||||
}
|
||||
|
||||
@ -552,9 +595,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#get
|
||||
*/
|
||||
@CallerSensitive
|
||||
public long getLong(Object obj)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
return getFieldAccessor(obj).getLong(obj);
|
||||
}
|
||||
|
||||
@ -582,9 +632,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#get
|
||||
*/
|
||||
@CallerSensitive
|
||||
public float getFloat(Object obj)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
return getFieldAccessor(obj).getFloat(obj);
|
||||
}
|
||||
|
||||
@ -612,9 +669,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#get
|
||||
*/
|
||||
@CallerSensitive
|
||||
public double getDouble(Object obj)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
return getFieldAccessor(obj).getDouble(obj);
|
||||
}
|
||||
|
||||
@ -684,9 +748,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* @exception ExceptionInInitializerError if the initialization provoked
|
||||
* by this method fails.
|
||||
*/
|
||||
@CallerSensitive
|
||||
public void set(Object obj, Object value)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
getFieldAccessor(obj).set(obj, value);
|
||||
}
|
||||
|
||||
@ -714,9 +785,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#set
|
||||
*/
|
||||
@CallerSensitive
|
||||
public void setBoolean(Object obj, boolean z)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
getFieldAccessor(obj).setBoolean(obj, z);
|
||||
}
|
||||
|
||||
@ -744,9 +822,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#set
|
||||
*/
|
||||
@CallerSensitive
|
||||
public void setByte(Object obj, byte b)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
getFieldAccessor(obj).setByte(obj, b);
|
||||
}
|
||||
|
||||
@ -774,9 +859,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#set
|
||||
*/
|
||||
@CallerSensitive
|
||||
public void setChar(Object obj, char c)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
getFieldAccessor(obj).setChar(obj, c);
|
||||
}
|
||||
|
||||
@ -804,9 +896,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#set
|
||||
*/
|
||||
@CallerSensitive
|
||||
public void setShort(Object obj, short s)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
getFieldAccessor(obj).setShort(obj, s);
|
||||
}
|
||||
|
||||
@ -834,9 +933,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#set
|
||||
*/
|
||||
@CallerSensitive
|
||||
public void setInt(Object obj, int i)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
getFieldAccessor(obj).setInt(obj, i);
|
||||
}
|
||||
|
||||
@ -864,9 +970,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#set
|
||||
*/
|
||||
@CallerSensitive
|
||||
public void setLong(Object obj, long l)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
getFieldAccessor(obj).setLong(obj, l);
|
||||
}
|
||||
|
||||
@ -894,9 +1007,16 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#set
|
||||
*/
|
||||
@CallerSensitive
|
||||
public void setFloat(Object obj, float f)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
getFieldAccessor(obj).setFloat(obj, f);
|
||||
}
|
||||
|
||||
@ -924,20 +1044,26 @@ class Field extends AccessibleObject implements Member {
|
||||
* by this method fails.
|
||||
* @see Field#set
|
||||
*/
|
||||
@CallerSensitive
|
||||
public void setDouble(Object obj, double d)
|
||||
throws IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
getFieldAccessor(obj).setDouble(obj, d);
|
||||
}
|
||||
|
||||
// Convenience routine which performs security checks
|
||||
// security check is done before calling this method
|
||||
private FieldAccessor getFieldAccessor(Object obj)
|
||||
throws IllegalAccessException
|
||||
{
|
||||
doSecurityCheck(obj);
|
||||
boolean ov = override;
|
||||
FieldAccessor a = (ov)? overrideFieldAccessor : fieldAccessor;
|
||||
return (a != null)? a : acquireFieldAccessor(ov);
|
||||
FieldAccessor a = (ov) ? overrideFieldAccessor : fieldAccessor;
|
||||
return (a != null) ? a : acquireFieldAccessor(ov);
|
||||
}
|
||||
|
||||
// NOTE that there is no synchronization used here. It is correct
|
||||
@ -982,19 +1108,6 @@ class Field extends AccessibleObject implements Member {
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: be very careful if you change the stack depth of this
|
||||
// routine. The depth of the "getCallerClass" call is hardwired so
|
||||
// that the compiler can have an easier time if this gets inlined.
|
||||
private void doSecurityCheck(Object obj) throws IllegalAccessException {
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass(4);
|
||||
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NullPointerException {@inheritDoc}
|
||||
* @since 1.5
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
package java.lang.reflect;
|
||||
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.MethodAccessor;
|
||||
import sun.reflect.Reflection;
|
||||
import sun.reflect.generics.repository.MethodRepository;
|
||||
@ -472,14 +473,14 @@ public final class Method extends Executable {
|
||||
* @exception ExceptionInInitializerError if the initialization
|
||||
* provoked by this method fails.
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Object invoke(Object obj, Object... args)
|
||||
throws IllegalAccessException, IllegalArgumentException,
|
||||
InvocationTargetException
|
||||
{
|
||||
if (!override) {
|
||||
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
|
||||
Class<?> caller = Reflection.getCallerClass(1);
|
||||
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
checkAccess(caller, clazz, obj, modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,7 +28,6 @@ package java.lang.reflect;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.security.AccessController;
|
||||
import java.security.Permission;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -39,6 +38,8 @@ import java.util.Set;
|
||||
import java.util.List;
|
||||
import java.util.WeakHashMap;
|
||||
import sun.misc.ProxyGenerator;
|
||||
import sun.misc.VM;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.Reflection;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
import sun.security.util.SecurityConstants;
|
||||
@ -51,16 +52,14 @@ import sun.security.util.SecurityConstants;
|
||||
* <p>To create a proxy for some interface {@code Foo}:
|
||||
* <pre>
|
||||
* InvocationHandler handler = new MyInvocationHandler(...);
|
||||
* Class proxyClass = Proxy.getProxyClass(
|
||||
* Foo.class.getClassLoader(), new Class[] { Foo.class });
|
||||
* Foo f = (Foo) proxyClass.
|
||||
* getConstructor(new Class[] { InvocationHandler.class }).
|
||||
* newInstance(new Object[] { handler });
|
||||
* Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
|
||||
* Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
|
||||
* newInstance(handler);
|
||||
* </pre>
|
||||
* or more simply:
|
||||
* <pre>
|
||||
* Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
|
||||
* new Class[] { Foo.class },
|
||||
* new Class<?>[] { Foo.class },
|
||||
* handler);
|
||||
* </pre>
|
||||
*
|
||||
@ -89,7 +88,11 @@ import sun.security.util.SecurityConstants;
|
||||
* <p>A proxy class has the following properties:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Proxy classes are public, final, and not abstract.
|
||||
* <li>Proxy classes are <em>public, final, and not abstract</em> if
|
||||
* all proxy interfaces are public.</li>
|
||||
*
|
||||
* <li>Proxy classes are <em>non-public, final, and not abstract</em> if
|
||||
* any of the proxy interfaces is non-public.</li>
|
||||
*
|
||||
* <li>The unqualified name of a proxy class is unspecified. The space
|
||||
* of class names that begin with the string {@code "$Proxy"}
|
||||
@ -271,76 +274,17 @@ public class Proxy implements java.io.Serializable {
|
||||
* @param h the invocation handler for this proxy instance
|
||||
*/
|
||||
protected Proxy(InvocationHandler h) {
|
||||
doNewInstanceCheck();
|
||||
this.h = h;
|
||||
}
|
||||
|
||||
private static class ProxyAccessHelper {
|
||||
// The permission is implementation specific.
|
||||
static final Permission PROXY_PERMISSION =
|
||||
new ReflectPermission("proxyConstructorNewInstance");
|
||||
// These system properties are defined to provide a short-term
|
||||
// workaround if customers need to disable the new security checks.
|
||||
static final boolean allowNewInstance;
|
||||
static final boolean allowNullLoader;
|
||||
static {
|
||||
allowNewInstance = getBooleanProperty("sun.reflect.proxy.allowsNewInstance");
|
||||
allowNullLoader = getBooleanProperty("sun.reflect.proxy.allowsNullLoader");
|
||||
}
|
||||
|
||||
private static boolean getBooleanProperty(final String key) {
|
||||
String s = AccessController.doPrivileged(new PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
return System.getProperty(key);
|
||||
}
|
||||
});
|
||||
return Boolean.valueOf(s);
|
||||
}
|
||||
|
||||
static boolean needsNewInstanceCheck(Class<?> proxyClass) {
|
||||
if (!Proxy.isProxyClass(proxyClass) || allowNewInstance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (proxyClass.getName().startsWith(ReflectUtil.PROXY_PACKAGE + ".")) {
|
||||
// all proxy interfaces are public
|
||||
return false;
|
||||
}
|
||||
for (Class<?> intf : proxyClass.getInterfaces()) {
|
||||
if (!Modifier.isPublic(intf.getModifiers())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Access check on a proxy class that implements any non-public interface.
|
||||
*
|
||||
* @throws SecurityException if a security manager exists, and
|
||||
* the caller does not have the permission.
|
||||
*/
|
||||
private void doNewInstanceCheck() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
Class<?> proxyClass = this.getClass();
|
||||
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(proxyClass)) {
|
||||
try {
|
||||
sm.checkPermission(ProxyAccessHelper.PROXY_PERMISSION);
|
||||
} catch (SecurityException e) {
|
||||
throw new SecurityException("Not allowed to construct a Proxy "
|
||||
+ "instance that implements a non-public interface", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code java.lang.Class} object for a proxy class
|
||||
* given a class loader and an array of interfaces. The proxy class
|
||||
* will be defined by the specified class loader and will implement
|
||||
* all of the supplied interfaces. If a proxy class for the same
|
||||
* permutation of interfaces has already been defined by the class
|
||||
* loader, then the existing proxy class will be returned; otherwise,
|
||||
* all of the supplied interfaces. If any of the given interfaces
|
||||
* is non-public, the proxy class will be non-public. If a proxy class
|
||||
* for the same permutation of interfaces has already been defined by the
|
||||
* class loader, then the existing proxy class will be returned; otherwise,
|
||||
* a proxy class for those interfaces will be generated dynamically
|
||||
* and defined by the class loader.
|
||||
*
|
||||
@ -405,31 +349,40 @@ public class Proxy implements java.io.Serializable {
|
||||
* @throws IllegalArgumentException if any of the restrictions on the
|
||||
* parameters that may be passed to {@code getProxyClass}
|
||||
* are violated
|
||||
* @throws SecurityException if a security manager, <em>s</em>, is present
|
||||
* and any of the following conditions is met:
|
||||
* <ul>
|
||||
* <li> the given {@code loader} is {@code null} and
|
||||
* the caller's class loader is not {@code null} and the
|
||||
* invocation of {@link SecurityManager#checkPermission
|
||||
* s.checkPermission} with
|
||||
* {@code RuntimePermission("getClassLoader")} permission
|
||||
* denies access.</li>
|
||||
* <li> the caller's class loader is not the same as or an
|
||||
* ancestor of the class loader for the current class and
|
||||
* invocation of {@link SecurityManager#checkPackageAccess
|
||||
* s.checkPackageAccess()} denies access to any one of the
|
||||
* given proxy interfaces.</li>
|
||||
* </ul>
|
||||
|
||||
* @throws NullPointerException if the {@code interfaces} array
|
||||
* argument or any of its elements are {@code null}
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static Class<?> getProxyClass(ClassLoader loader,
|
||||
Class<?>... interfaces)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
return getProxyClass0(loader, interfaces); // stack walk magic: do not refactor
|
||||
}
|
||||
|
||||
private static void checkProxyLoader(ClassLoader ccl,
|
||||
ClassLoader loader)
|
||||
{
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
if (loader == null && ccl != null) {
|
||||
if (!ProxyAccessHelper.allowNullLoader) {
|
||||
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
|
||||
}
|
||||
}
|
||||
checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
|
||||
}
|
||||
|
||||
return getProxyClass0(loader, interfaces);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a proxy class (caller-sensitive).
|
||||
* Check permissions required to create a Proxy class.
|
||||
*
|
||||
* To define a proxy class, it performs the access checks as in
|
||||
* Class.forName (VM will invoke ClassLoader.checkPackageAccess):
|
||||
@ -446,17 +399,26 @@ public class Proxy implements java.io.Serializable {
|
||||
* will throw IllegalAccessError when the generated proxy class is
|
||||
* being defined via the defineClass0 method.
|
||||
*/
|
||||
private static Class<?> getProxyClass0(ClassLoader loader,
|
||||
Class<?>... interfaces) {
|
||||
private static void checkProxyAccess(Class<?> caller,
|
||||
ClassLoader loader,
|
||||
Class<?>... interfaces)
|
||||
{
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
final int CALLER_FRAME = 3; // 0: Reflection, 1: getProxyClass0 2: Proxy 3: caller
|
||||
final Class<?> caller = Reflection.getCallerClass(CALLER_FRAME);
|
||||
final ClassLoader ccl = caller.getClassLoader();
|
||||
checkProxyLoader(ccl, loader);
|
||||
ClassLoader ccl = caller.getClassLoader();
|
||||
if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
|
||||
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
|
||||
}
|
||||
ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a proxy class. Must call the checkProxyAccess method
|
||||
* to perform permission checks before calling this.
|
||||
*/
|
||||
private static Class<?> getProxyClass0(ClassLoader loader,
|
||||
Class<?>... interfaces) {
|
||||
if (interfaces.length > 65535) {
|
||||
throw new IllegalArgumentException("interface limit exceeded");
|
||||
}
|
||||
@ -587,6 +549,7 @@ public class Proxy implements java.io.Serializable {
|
||||
|
||||
try {
|
||||
String proxyPkg = null; // package to define proxy class in
|
||||
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
|
||||
|
||||
/*
|
||||
* Record the package of a non-public proxy interface so that the
|
||||
@ -596,6 +559,7 @@ public class Proxy implements java.io.Serializable {
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
int flags = interfaces[i].getModifiers();
|
||||
if (!Modifier.isPublic(flags)) {
|
||||
accessFlags = Modifier.FINAL;
|
||||
String name = interfaces[i].getName();
|
||||
int n = name.lastIndexOf('.');
|
||||
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
|
||||
@ -631,7 +595,7 @@ public class Proxy implements java.io.Serializable {
|
||||
* Generate the specified proxy class.
|
||||
*/
|
||||
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
|
||||
proxyName, interfaces);
|
||||
proxyName, interfaces, accessFlags);
|
||||
try {
|
||||
proxyClass = defineClass0(loader, proxyName,
|
||||
proxyClassFile, 0, proxyClassFile.length);
|
||||
@ -672,12 +636,7 @@ public class Proxy implements java.io.Serializable {
|
||||
/**
|
||||
* Returns an instance of a proxy class for the specified interfaces
|
||||
* that dispatches method invocations to the specified invocation
|
||||
* handler. This method is equivalent to:
|
||||
* <pre>
|
||||
* Proxy.getProxyClass(loader, interfaces).
|
||||
* getConstructor(new Class[] { InvocationHandler.class }).
|
||||
* newInstance(new Object[] { handler });
|
||||
* </pre>
|
||||
* handler.
|
||||
*
|
||||
* <p>{@code Proxy.newProxyInstance} throws
|
||||
* {@code IllegalArgumentException} for the same reasons that
|
||||
@ -693,11 +652,33 @@ public class Proxy implements java.io.Serializable {
|
||||
* @throws IllegalArgumentException if any of the restrictions on the
|
||||
* parameters that may be passed to {@code getProxyClass}
|
||||
* are violated
|
||||
* @throws SecurityException if a security manager, <em>s</em>, is present
|
||||
* and any of the following conditions is met:
|
||||
* <ul>
|
||||
* <li> the given {@code loader} is {@code null} and
|
||||
* the caller's class loader is not {@code null} and the
|
||||
* invocation of {@link SecurityManager#checkPermission
|
||||
* s.checkPermission} with
|
||||
* {@code RuntimePermission("getClassLoader")} permission
|
||||
* denies access;</li>
|
||||
* <li> the caller's class loader is not the same as or an
|
||||
* ancestor of the class loader for the current class and
|
||||
* invocation of {@link SecurityManager#checkPackageAccess
|
||||
* s.checkPackageAccess()} denies access to any one of the
|
||||
* given proxy interfaces.</li>
|
||||
* <li> any of the given proxy interfaces is non-public and the
|
||||
* caller class is not in the same {@linkplain Package runtime package}
|
||||
* as the non-public interface and the invocation of
|
||||
* {@link SecurityManager#checkPermission s.checkPermission} with
|
||||
* {@code ReflectPermission("newProxyInPackage.{package name}")}
|
||||
* permission denies access.</li>
|
||||
* </ul>
|
||||
* @throws NullPointerException if the {@code interfaces} array
|
||||
* argument or any of its elements are {@code null}, or
|
||||
* if the invocation handler, {@code h}, is
|
||||
* {@code null}
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static Object newProxyInstance(ClassLoader loader,
|
||||
Class<?>[] interfaces,
|
||||
InvocationHandler h)
|
||||
@ -707,34 +688,75 @@ public class Proxy implements java.io.Serializable {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up or generate the designated proxy class.
|
||||
*/
|
||||
Class<?> cl = getProxyClass0(loader, interfaces); // stack walk magic: do not refactor
|
||||
Class<?> cl = getProxyClass0(loader, interfaces);
|
||||
|
||||
/*
|
||||
* Invoke its constructor with the designated invocation handler.
|
||||
*/
|
||||
try {
|
||||
if (sm != null) {
|
||||
checkNewProxyPermission(Reflection.getCallerClass(), cl);
|
||||
}
|
||||
|
||||
final Constructor<?> cons = cl.getConstructor(constructorParams);
|
||||
final InvocationHandler ih = h;
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
|
||||
// create proxy instance with doPrivilege as the proxy class may
|
||||
// implement non-public interfaces that requires a special permission
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
public Object run() {
|
||||
return newInstance(cons, ih);
|
||||
if (!Modifier.isPublic(cl.getModifiers())) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
cons.setAccessible(true);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
return cons.newInstance(new Object[]{h});
|
||||
} catch (IllegalAccessException|InstantiationException e) {
|
||||
throw new InternalError(e.toString(), e);
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable t = e.getCause();
|
||||
if (t instanceof RuntimeException) {
|
||||
throw (RuntimeException) t;
|
||||
} else {
|
||||
return newInstance(cons, ih);
|
||||
throw new InternalError(t.toString(), t);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new InternalError(e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkNewProxyPermission(Class<?> caller, Class<?> proxyClass) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
String pcn = proxyClass.getName();
|
||||
if (pcn.startsWith(ReflectUtil.PROXY_PACKAGE + ".")) {
|
||||
// all proxy interfaces are public
|
||||
return;
|
||||
}
|
||||
|
||||
ClassLoader ccl = caller.getClassLoader();
|
||||
ClassLoader pcl = proxyClass.getClassLoader();
|
||||
|
||||
// do permission check if the caller is in a different runtime package
|
||||
// of the proxy class
|
||||
int n = pcn.lastIndexOf('.');
|
||||
String pkg = (n == -1) ? "" : pcn.substring(0, n);
|
||||
|
||||
n = caller.getName().lastIndexOf('.');
|
||||
String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n);
|
||||
|
||||
if (pcl != ccl || !pkg.equals(callerPkg)) {
|
||||
sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
|
||||
try {
|
||||
return cons.newInstance(new Object[] {h} );
|
||||
|
||||
@ -26,12 +26,7 @@
|
||||
package java.lang.reflect;
|
||||
|
||||
/**
|
||||
* The Permission class for reflective operations. A
|
||||
* ReflectPermission is a <em>named permission</em> and has no
|
||||
* actions. The only name currently defined is {@code suppressAccessChecks},
|
||||
* which allows suppressing the standard Java language access checks
|
||||
* -- for public, default (package) access, protected, and private
|
||||
* members -- performed by reflected objects at their point of use.
|
||||
* The Permission class for reflective operations.
|
||||
* <P>
|
||||
* The following table
|
||||
* provides a summary description of what the permission allows,
|
||||
@ -47,11 +42,21 @@ package java.lang.reflect;
|
||||
*
|
||||
* <tr>
|
||||
* <td>suppressAccessChecks</td>
|
||||
* <td>ability to access
|
||||
* fields and invoke methods in a class. Note that this includes
|
||||
* not only public, but protected and private fields and methods as well.</td>
|
||||
* <td>ability to suppress the standard Java language access checks
|
||||
* on fields and methods in a class; allow access not only public members
|
||||
* but also allow access to default (package) access, protected,
|
||||
* and private members.</td>
|
||||
* <td>This is dangerous in that information (possibly confidential) and
|
||||
* methods normally unavailable would be accessible to malicious code.</td>
|
||||
* methods normally unavailable would be accessible to malicious code.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>newProxyInPackage.{package name}</td>
|
||||
* <td>ability to create a proxy instance in the specified package of which
|
||||
* the non-public interface that the proxy class implements.</td>
|
||||
* <td>This gives code access to classes in packages to which it normally
|
||||
* does not have access and the dynamic proxy class is in the system
|
||||
* protection domain. Malicious code may use these classes to
|
||||
* help in its attempt to compromise security in the system.</td>
|
||||
* </tr>
|
||||
*
|
||||
* </table>
|
||||
@ -63,6 +68,7 @@ package java.lang.reflect;
|
||||
* @see Field#set
|
||||
* @see Method#invoke
|
||||
* @see Constructor#newInstance
|
||||
* @see Proxy#newProxyInstance
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
@ -122,7 +122,7 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl
|
||||
* not connected already.
|
||||
*/
|
||||
protected void disconnect() {
|
||||
disconnect0(connectedAddress.family);
|
||||
disconnect0(connectedAddress.holder().getFamily());
|
||||
connected = false;
|
||||
connectedAddress = null;
|
||||
connectedPort = -1;
|
||||
|
||||
@ -100,27 +100,28 @@ class Inet4Address extends InetAddress {
|
||||
|
||||
Inet4Address() {
|
||||
super();
|
||||
hostName = null;
|
||||
address = 0;
|
||||
family = IPv4;
|
||||
holder().hostName = null;
|
||||
holder().address = 0;
|
||||
holder().family = IPv4;
|
||||
}
|
||||
|
||||
Inet4Address(String hostName, byte addr[]) {
|
||||
this.hostName = hostName;
|
||||
this.family = IPv4;
|
||||
holder().hostName = hostName;
|
||||
holder().family = IPv4;
|
||||
if (addr != null) {
|
||||
if (addr.length == INADDRSZ) {
|
||||
address = addr[3] & 0xFF;
|
||||
int address = addr[3] & 0xFF;
|
||||
address |= ((addr[2] << 8) & 0xFF00);
|
||||
address |= ((addr[1] << 16) & 0xFF0000);
|
||||
address |= ((addr[0] << 24) & 0xFF000000);
|
||||
holder().address = address;
|
||||
}
|
||||
}
|
||||
}
|
||||
Inet4Address(String hostName, int address) {
|
||||
this.hostName = hostName;
|
||||
this.family = IPv4;
|
||||
this.address = address;
|
||||
holder().hostName = hostName;
|
||||
holder().family = IPv4;
|
||||
holder().address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,8 +135,8 @@ class Inet4Address extends InetAddress {
|
||||
private Object writeReplace() throws ObjectStreamException {
|
||||
// will replace the to be serialized 'this' object
|
||||
InetAddress inet = new InetAddress();
|
||||
inet.hostName = this.hostName;
|
||||
inet.address = this.address;
|
||||
inet.holder().hostName = holder().getHostName();
|
||||
inet.holder().address = holder().getAddress();
|
||||
|
||||
/**
|
||||
* Prior to 1.4 an InetAddress was created with a family
|
||||
@ -143,7 +144,7 @@ class Inet4Address extends InetAddress {
|
||||
* For compatibility reasons we must therefore write the
|
||||
* the InetAddress with this family.
|
||||
*/
|
||||
inet.family = 2;
|
||||
inet.holder().family = 2;
|
||||
|
||||
return inet;
|
||||
}
|
||||
@ -157,7 +158,7 @@ class Inet4Address extends InetAddress {
|
||||
* @since JDK1.1
|
||||
*/
|
||||
public boolean isMulticastAddress() {
|
||||
return ((address & 0xf0000000) == 0xe0000000);
|
||||
return ((holder().getAddress() & 0xf0000000) == 0xe0000000);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -167,7 +168,7 @@ class Inet4Address extends InetAddress {
|
||||
* @since 1.4
|
||||
*/
|
||||
public boolean isAnyLocalAddress() {
|
||||
return address == 0;
|
||||
return holder().getAddress() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -195,6 +196,7 @@ class Inet4Address extends InetAddress {
|
||||
// defined in "Documenting Special Use IPv4 Address Blocks
|
||||
// that have been Registered with IANA" by Bill Manning
|
||||
// draft-manning-dsua-06.txt
|
||||
int address = holder().getAddress();
|
||||
return (((address >>> 24) & 0xFF) == 169)
|
||||
&& (((address >>> 16) & 0xFF) == 254);
|
||||
}
|
||||
@ -211,6 +213,7 @@ class Inet4Address extends InetAddress {
|
||||
// 10/8 prefix
|
||||
// 172.16/12 prefix
|
||||
// 192.168/16 prefix
|
||||
int address = holder().getAddress();
|
||||
return (((address >>> 24) & 0xFF) == 10)
|
||||
|| ((((address >>> 24) & 0xFF) == 172)
|
||||
&& (((address >>> 16) & 0xF0) == 16))
|
||||
@ -257,6 +260,7 @@ class Inet4Address extends InetAddress {
|
||||
*/
|
||||
public boolean isMCLinkLocal() {
|
||||
// 224.0.0/24 prefix and ttl == 1
|
||||
int address = holder().getAddress();
|
||||
return (((address >>> 24) & 0xFF) == 224)
|
||||
&& (((address >>> 16) & 0xFF) == 0)
|
||||
&& (((address >>> 8) & 0xFF) == 0);
|
||||
@ -272,6 +276,7 @@ class Inet4Address extends InetAddress {
|
||||
*/
|
||||
public boolean isMCSiteLocal() {
|
||||
// 239.255/16 prefix or ttl < 32
|
||||
int address = holder().getAddress();
|
||||
return (((address >>> 24) & 0xFF) == 239)
|
||||
&& (((address >>> 16) & 0xFF) == 255);
|
||||
}
|
||||
@ -287,6 +292,7 @@ class Inet4Address extends InetAddress {
|
||||
*/
|
||||
public boolean isMCOrgLocal() {
|
||||
// 239.192 - 239.195
|
||||
int address = holder().getAddress();
|
||||
return (((address >>> 24) & 0xFF) == 239)
|
||||
&& (((address >>> 16) & 0xFF) >= 192)
|
||||
&& (((address >>> 16) & 0xFF) <= 195);
|
||||
@ -300,6 +306,7 @@ class Inet4Address extends InetAddress {
|
||||
* @return the raw IP address of this object.
|
||||
*/
|
||||
public byte[] getAddress() {
|
||||
int address = holder().getAddress();
|
||||
byte[] addr = new byte[INADDRSZ];
|
||||
|
||||
addr[0] = (byte) ((address >>> 24) & 0xFF);
|
||||
@ -325,7 +332,7 @@ class Inet4Address extends InetAddress {
|
||||
* @return a hash code value for this IP address.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return address;
|
||||
return holder().getAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -346,7 +353,7 @@ class Inet4Address extends InetAddress {
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
return (obj != null) && (obj instanceof Inet4Address) &&
|
||||
(((InetAddress)obj).address == address);
|
||||
(((InetAddress)obj).holder().getAddress() == holder().getAddress());
|
||||
}
|
||||
|
||||
// Utilities
|
||||
|
||||
@ -40,7 +40,7 @@ class Inet4AddressImpl implements InetAddressImpl {
|
||||
public synchronized InetAddress anyLocalAddress() {
|
||||
if (anyLocalAddress == null) {
|
||||
anyLocalAddress = new Inet4Address(); // {0x00,0x00,0x00,0x00}
|
||||
anyLocalAddress.hostName = "0.0.0.0";
|
||||
anyLocalAddress.holder().hostName = "0.0.0.0";
|
||||
}
|
||||
return anyLocalAddress;
|
||||
}
|
||||
|
||||
@ -210,18 +210,18 @@ class Inet6Address extends InetAddress {
|
||||
|
||||
Inet6Address() {
|
||||
super();
|
||||
hostName = null;
|
||||
holder().hostName = null;
|
||||
ipaddress = new byte[INADDRSZ];
|
||||
family = IPv6;
|
||||
holder().family = IPv6;
|
||||
}
|
||||
|
||||
/* checking of value for scope_id should be done by caller
|
||||
* scope_id must be >= 0, or -1 to indicate not being set
|
||||
*/
|
||||
Inet6Address(String hostName, byte addr[], int scope_id) {
|
||||
this.hostName = hostName;
|
||||
holder().hostName = hostName;
|
||||
if (addr.length == INADDRSZ) { // normal IPv6 address
|
||||
family = IPv6;
|
||||
holder().family = IPv6;
|
||||
ipaddress = addr.clone();
|
||||
}
|
||||
if (scope_id >= 0) {
|
||||
@ -335,9 +335,9 @@ class Inet6Address extends InetAddress {
|
||||
private void initif(String hostName, byte addr[],NetworkInterface nif)
|
||||
throws UnknownHostException
|
||||
{
|
||||
this.hostName = hostName;
|
||||
holder().hostName = hostName;
|
||||
if (addr.length == INADDRSZ) { // normal IPv6 address
|
||||
family = IPv6;
|
||||
holder().family = IPv6;
|
||||
ipaddress = addr.clone();
|
||||
}
|
||||
if (nif != null) {
|
||||
@ -420,6 +420,11 @@ class Inet6Address extends InetAddress {
|
||||
*/
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
if (getClass().getClassLoader() != null) {
|
||||
throw new SecurityException ("invalid address type");
|
||||
}
|
||||
|
||||
s.defaultReadObject();
|
||||
|
||||
if (ifname != null && !ifname.equals("")) {
|
||||
@ -447,7 +452,7 @@ class Inet6Address extends InetAddress {
|
||||
ipaddress.length);
|
||||
}
|
||||
|
||||
if (family != IPv6) {
|
||||
if (holder().getFamily() != IPv6) {
|
||||
throw new InvalidObjectException("invalid address family type");
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ class Inet6AddressImpl implements InetAddressImpl {
|
||||
if (anyLocalAddress == null) {
|
||||
if (InetAddress.preferIPv6Address) {
|
||||
anyLocalAddress = new Inet6Address();
|
||||
anyLocalAddress.hostName = "::";
|
||||
anyLocalAddress.holder().hostName = "::";
|
||||
} else {
|
||||
anyLocalAddress = (new Inet4AddressImpl()).anyLocalAddress();
|
||||
}
|
||||
|
||||
@ -35,8 +35,12 @@ import java.util.ArrayList;
|
||||
import java.util.ServiceLoader;
|
||||
import java.security.AccessController;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.ObjectStreamField;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectInputStream.GetField;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectOutputStream.PutField;
|
||||
import sun.security.action.*;
|
||||
import sun.net.InetAddressCachePolicy;
|
||||
import sun.net.util.IPAddressUtil;
|
||||
@ -199,25 +203,48 @@ class InetAddress implements java.io.Serializable {
|
||||
/* Specify address family preference */
|
||||
static transient boolean preferIPv6Address = false;
|
||||
|
||||
/**
|
||||
* @serial
|
||||
*/
|
||||
String hostName;
|
||||
static class InetAddressHolder {
|
||||
|
||||
/**
|
||||
* Holds a 32-bit IPv4 address.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
int address;
|
||||
InetAddressHolder() {}
|
||||
|
||||
/**
|
||||
* Specifies the address family type, for instance, '1' for IPv4
|
||||
* addresses, and '2' for IPv6 addresses.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
int family;
|
||||
InetAddressHolder(String hostName, int address, int family) {
|
||||
this.hostName = hostName;
|
||||
this.address = address;
|
||||
this.family = family;
|
||||
}
|
||||
|
||||
String hostName;
|
||||
|
||||
String getHostName() {
|
||||
return hostName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds a 32-bit IPv4 address.
|
||||
*/
|
||||
int address;
|
||||
|
||||
int getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the address family type, for instance, '1' for IPv4
|
||||
* addresses, and '2' for IPv6 addresses.
|
||||
*/
|
||||
int family;
|
||||
|
||||
int getFamily() {
|
||||
return family;
|
||||
}
|
||||
}
|
||||
|
||||
/* Used to store the serializable fields of InetAddress */
|
||||
private final transient InetAddressHolder holder;
|
||||
|
||||
InetAddressHolder holder() {
|
||||
return holder;
|
||||
}
|
||||
|
||||
/* Used to store the name service provider */
|
||||
private static List<NameService> nameServices = null;
|
||||
@ -251,6 +278,7 @@ class InetAddress implements java.io.Serializable {
|
||||
* put in the address cache, since it is not created by name.
|
||||
*/
|
||||
InetAddress() {
|
||||
holder = new InetAddressHolder();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -263,7 +291,7 @@ class InetAddress implements java.io.Serializable {
|
||||
*/
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
// will replace the deserialized 'this' object
|
||||
return new Inet4Address(this.hostName, this.address);
|
||||
return new Inet4Address(holder().getHostName(), holder().getAddress());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -500,10 +528,10 @@ class InetAddress implements java.io.Serializable {
|
||||
* @see SecurityManager#checkConnect
|
||||
*/
|
||||
String getHostName(boolean check) {
|
||||
if (hostName == null) {
|
||||
hostName = InetAddress.getHostFromNameService(this, check);
|
||||
if (holder().getHostName() == null) {
|
||||
holder().hostName = InetAddress.getHostFromNameService(this, check);
|
||||
}
|
||||
return hostName;
|
||||
return holder().getHostName();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -666,6 +694,7 @@ class InetAddress implements java.io.Serializable {
|
||||
* @return a string representation of this IP address.
|
||||
*/
|
||||
public String toString() {
|
||||
String hostName = holder().getHostName();
|
||||
return ((hostName != null) ? hostName : "")
|
||||
+ "/" + getHostAddress();
|
||||
}
|
||||
@ -1522,14 +1551,58 @@ class InetAddress implements java.io.Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
private static final long FIELDS_OFFSET;
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
|
||||
static {
|
||||
try {
|
||||
sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
|
||||
FIELDS_OFFSET = unsafe.objectFieldOffset(
|
||||
InetAddress.class.getDeclaredField("holder")
|
||||
);
|
||||
UNSAFE = unsafe;
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void readObject (ObjectInputStream s) throws
|
||||
IOException, ClassNotFoundException {
|
||||
s.defaultReadObject ();
|
||||
if (getClass().getClassLoader() != null) {
|
||||
hostName = null;
|
||||
address = 0;
|
||||
throw new SecurityException ("invalid address type");
|
||||
}
|
||||
GetField gf = s.readFields();
|
||||
String host = (String)gf.get("hostName", null);
|
||||
int address= gf.get("address", 0);
|
||||
int family= gf.get("family", 0);
|
||||
InetAddressHolder h = new InetAddressHolder(host, address, family);
|
||||
UNSAFE.putObject(this, FIELDS_OFFSET, h);
|
||||
}
|
||||
|
||||
/* needed because the serializable fields no longer exist */
|
||||
|
||||
/**
|
||||
* @serialField hostName String
|
||||
* @serialField address int
|
||||
* @serialField family int
|
||||
*/
|
||||
private static final ObjectStreamField[] serialPersistentFields = {
|
||||
new ObjectStreamField("hostName", String.class),
|
||||
new ObjectStreamField("address", int.class),
|
||||
new ObjectStreamField("family", int.class),
|
||||
};
|
||||
|
||||
private void writeObject (ObjectOutputStream s) throws
|
||||
IOException {
|
||||
if (getClass().getClassLoader() != null) {
|
||||
throw new SecurityException ("invalid address type");
|
||||
}
|
||||
PutField pf = s.putFields();
|
||||
pf.put("hostName", holder().getHostName());
|
||||
pf.put("address", holder().getAddress());
|
||||
pf.put("family", holder().getFamily());
|
||||
s.writeFields();
|
||||
s.flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -87,8 +87,8 @@ public class InetSocketAddress
|
||||
if (hostname != null)
|
||||
return hostname;
|
||||
if (addr != null) {
|
||||
if (addr.hostName != null)
|
||||
return addr.hostName;
|
||||
if (addr.holder().getHostName() != null)
|
||||
return addr.holder().getHostName();
|
||||
else
|
||||
return addr.getHostAddress();
|
||||
}
|
||||
|
||||
@ -25,12 +25,10 @@
|
||||
|
||||
package java.nio.file.attribute;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Date;
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@ -50,43 +48,36 @@ import java.util.concurrent.TimeUnit;
|
||||
public final class FileTime
|
||||
implements Comparable<FileTime>
|
||||
{
|
||||
/**
|
||||
* The unit of granularity to interpret the value. Null if
|
||||
* this {@code FileTime} is converted from an {@code Instant},
|
||||
* the {@code value} and {@code unit} pair will not be used
|
||||
* in this scenario.
|
||||
*/
|
||||
private final TimeUnit unit;
|
||||
|
||||
/**
|
||||
* The value since the epoch; can be negative.
|
||||
*/
|
||||
private final long value;
|
||||
|
||||
/**
|
||||
* The unit of granularity to interpret the value.
|
||||
* The value as Instant (created lazily, if not from an instant)
|
||||
*/
|
||||
private final TimeUnit unit;
|
||||
private Instant instant;
|
||||
|
||||
/**
|
||||
* The value return by toString (created lazily)
|
||||
*/
|
||||
private String valueAsString;
|
||||
|
||||
/**
|
||||
* The value in days and excess nanos (created lazily)
|
||||
*/
|
||||
private DaysAndNanos daysAndNanos;
|
||||
|
||||
/**
|
||||
* Returns a DaysAndNanos object representing the value.
|
||||
*/
|
||||
private DaysAndNanos asDaysAndNanos() {
|
||||
if (daysAndNanos == null)
|
||||
daysAndNanos = new DaysAndNanos(value, unit);
|
||||
return daysAndNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of this class.
|
||||
*/
|
||||
private FileTime(long value, TimeUnit unit) {
|
||||
if (unit == null)
|
||||
throw new NullPointerException();
|
||||
private FileTime(long value, TimeUnit unit, Instant instant) {
|
||||
this.value = value;
|
||||
this.unit = unit;
|
||||
this.instant = instant;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,7 +93,8 @@ public final class FileTime
|
||||
* @return a {@code FileTime} representing the given value
|
||||
*/
|
||||
public static FileTime from(long value, TimeUnit unit) {
|
||||
return new FileTime(value, unit);
|
||||
Objects.requireNonNull(unit, "unit");
|
||||
return new FileTime(value, unit, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,7 +107,22 @@ public final class FileTime
|
||||
* @return a {@code FileTime} representing the given value
|
||||
*/
|
||||
public static FileTime fromMillis(long value) {
|
||||
return new FileTime(value, TimeUnit.MILLISECONDS);
|
||||
return new FileTime(value, TimeUnit.MILLISECONDS, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code FileTime} representing the same point of time value
|
||||
* on the time-line as the provided {@code Instant} object.
|
||||
*
|
||||
* @param instant
|
||||
* the instant to convert
|
||||
* @return a {@code FileTime} representing the same point on the time-line
|
||||
* as the provided instant
|
||||
* @since 1.8
|
||||
*/
|
||||
public static FileTime from(Instant instant) {
|
||||
Objects.requireNonNull(instant, "instant");
|
||||
return new FileTime(0, null, instant);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,7 +139,22 @@ public final class FileTime
|
||||
* since the epoch (1970-01-01T00:00:00Z); can be negative
|
||||
*/
|
||||
public long to(TimeUnit unit) {
|
||||
return unit.convert(this.value, this.unit);
|
||||
Objects.requireNonNull(unit, "unit");
|
||||
if (this.unit != null) {
|
||||
return unit.convert(this.value, this.unit);
|
||||
} else {
|
||||
long secs = unit.convert(instant.getEpochSecond(), TimeUnit.SECONDS);
|
||||
if (secs == Long.MIN_VALUE || secs == Long.MAX_VALUE) {
|
||||
return secs;
|
||||
}
|
||||
long nanos = unit.convert(instant.getNano(), TimeUnit.NANOSECONDS);
|
||||
long r = secs + nanos;
|
||||
// Math.addExact() variant
|
||||
if (((secs ^ r) & (nanos ^ r)) < 0) {
|
||||
return (secs < 0) ? Long.MIN_VALUE : Long.MAX_VALUE;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,7 +167,110 @@ public final class FileTime
|
||||
* @return the value in milliseconds, since the epoch (1970-01-01T00:00:00Z)
|
||||
*/
|
||||
public long toMillis() {
|
||||
return unit.toMillis(value);
|
||||
if (unit != null) {
|
||||
return unit.toMillis(value);
|
||||
} else {
|
||||
long secs = instant.getEpochSecond();
|
||||
int nanos = instant.getNano();
|
||||
// Math.multiplyExact() variant
|
||||
long r = secs * 1000;
|
||||
long ax = Math.abs(secs);
|
||||
if (((ax | 1000) >>> 31 != 0)) {
|
||||
if ((r / 1000) != secs) {
|
||||
return (secs < 0) ? Long.MIN_VALUE : Long.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return r + nanos / 1000_000;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Time unit constants for conversion.
|
||||
*/
|
||||
private static final long HOURS_PER_DAY = 24L;
|
||||
private static final long MINUTES_PER_HOUR = 60L;
|
||||
private static final long SECONDS_PER_MINUTE = 60L;
|
||||
private static final long SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
|
||||
private static final long SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
|
||||
private static final long MILLIS_PER_SECOND = 1000L;
|
||||
private static final long MICROS_PER_SECOND = 1000_000L;
|
||||
private static final long NANOS_PER_SECOND = 1000_000_000L;
|
||||
private static final int NANOS_PER_MILLI = 1000_000;
|
||||
private static final int NANOS_PER_MICRO = 1000;
|
||||
// The epoch second of Instant.MIN.
|
||||
private static final long MIN_SECOND = -31557014167219200L;
|
||||
// The epoch second of Instant.MAX.
|
||||
private static final long MAX_SECOND = 31556889864403199L;
|
||||
|
||||
/*
|
||||
* Scale d by m, checking for overflow.
|
||||
*/
|
||||
private static long scale(long d, long m, long over) {
|
||||
if (d > over) return Long.MAX_VALUE;
|
||||
if (d < -over) return Long.MIN_VALUE;
|
||||
return d * m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this {@code FileTime} object to an {@code Instant}.
|
||||
*
|
||||
* <p> The conversion creates an {@code Instant} that represents the
|
||||
* same point on the time-line as this {@code FileTime}.
|
||||
*
|
||||
* <p> {@code FileTime} can store points on the time-line further in the
|
||||
* future and further in the past than {@code Instant}. Conversion
|
||||
* from such further time points saturates to {@link Instant.MIN} if
|
||||
* earlier than {@code Instant.MIN} or {@link Instant.MAX} if later
|
||||
* than {@code Instant.MAX}.
|
||||
*
|
||||
* @return an instant representing the same point on the time-line as
|
||||
* this {@code FileTime} object
|
||||
* @since 1.8
|
||||
*/
|
||||
public Instant toInstant() {
|
||||
if (instant == null) {
|
||||
long secs = 0L;
|
||||
int nanos = 0;
|
||||
switch (unit) {
|
||||
case DAYS:
|
||||
secs = scale(value, SECONDS_PER_DAY,
|
||||
Long.MAX_VALUE/SECONDS_PER_DAY);
|
||||
break;
|
||||
case HOURS:
|
||||
secs = scale(value, SECONDS_PER_HOUR,
|
||||
Long.MAX_VALUE/SECONDS_PER_HOUR);
|
||||
break;
|
||||
case MINUTES:
|
||||
secs = scale(value, SECONDS_PER_MINUTE,
|
||||
Long.MAX_VALUE/SECONDS_PER_MINUTE);
|
||||
break;
|
||||
case SECONDS:
|
||||
secs = value;
|
||||
break;
|
||||
case MILLISECONDS:
|
||||
secs = Math.floorDiv(value, MILLIS_PER_SECOND);
|
||||
nanos = (int)Math.floorMod(value, MILLIS_PER_SECOND)
|
||||
* NANOS_PER_MILLI;
|
||||
break;
|
||||
case MICROSECONDS:
|
||||
secs = Math.floorDiv(value, MICROS_PER_SECOND);
|
||||
nanos = (int)Math.floorMod(value, MICROS_PER_SECOND)
|
||||
* NANOS_PER_MICRO;
|
||||
break;
|
||||
case NANOSECONDS:
|
||||
secs = Math.floorDiv(value, NANOS_PER_SECOND);
|
||||
nanos = (int)Math.floorMod(value, NANOS_PER_SECOND);
|
||||
break;
|
||||
default : throw new AssertionError("Unit not handled");
|
||||
}
|
||||
if (secs <= MIN_SECOND)
|
||||
instant = Instant.MIN;
|
||||
else if (secs >= MAX_SECOND)
|
||||
instant = Instant.MAX;
|
||||
else
|
||||
instant = Instant.ofEpochSecond(secs, nanos);
|
||||
}
|
||||
return instant;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,8 +301,25 @@ public final class FileTime
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// hashcode of days/nanos representation to satisfy contract with equals
|
||||
return asDaysAndNanos().hashCode();
|
||||
// hashcode of instant representation to satisfy contract with equals
|
||||
return toInstant().hashCode();
|
||||
}
|
||||
|
||||
private long toDays() {
|
||||
if (unit != null) {
|
||||
return unit.toDays(value);
|
||||
} else {
|
||||
return TimeUnit.SECONDS.toDays(toInstant().getEpochSecond());
|
||||
}
|
||||
}
|
||||
|
||||
private long toExcessNanos(long days) {
|
||||
if (unit != null) {
|
||||
return unit.toNanos(value - unit.convert(days, TimeUnit.DAYS));
|
||||
} else {
|
||||
return TimeUnit.SECONDS.toNanos(toInstant().getEpochSecond()
|
||||
- TimeUnit.DAYS.toSeconds(days));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -194,14 +336,52 @@ public final class FileTime
|
||||
@Override
|
||||
public int compareTo(FileTime other) {
|
||||
// same granularity
|
||||
if (unit == other.unit) {
|
||||
return (value < other.value) ? -1 : (value == other.value ? 0 : 1);
|
||||
if (unit != null && unit == other.unit) {
|
||||
return Long.compare(value, other.value);
|
||||
} else {
|
||||
// compare using days/nanos representation when unit differs
|
||||
return asDaysAndNanos().compareTo(other.asDaysAndNanos());
|
||||
// compare using instant representation when unit differs
|
||||
long secs = toInstant().getEpochSecond();
|
||||
long secsOther = other.toInstant().getEpochSecond();
|
||||
int cmp = Long.compare(secs, secsOther);
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
cmp = Long.compare(toInstant().getNano(), other.toInstant().getNano());
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
if (secs != MAX_SECOND && secs != MIN_SECOND) {
|
||||
return 0;
|
||||
}
|
||||
// if both this and other's Instant reps are MIN/MAX,
|
||||
// use daysSinceEpoch and nanosOfDays, which will not
|
||||
// saturate during calculation.
|
||||
long days = toDays();
|
||||
long daysOther = other.toDays();
|
||||
if (days == daysOther) {
|
||||
return Long.compare(toExcessNanos(days), other.toExcessNanos(daysOther));
|
||||
}
|
||||
return Long.compare(days, daysOther);
|
||||
}
|
||||
}
|
||||
|
||||
// days in a 400 year cycle = 146097
|
||||
// days in a 10,000 year cycle = 146097 * 25
|
||||
// seconds per day = 86400
|
||||
private static final long DAYS_PER_10000_YEARS = 146097L * 25L;
|
||||
private static final long SECONDS_PER_10000_YEARS = 146097L * 25L * 86400L;
|
||||
private static final long SECONDS_0000_TO_1970 = ((146097L * 5L) - (30L * 365L + 7L)) * 86400L;
|
||||
|
||||
// append year/month/day/hour/minute/second/nano with width and 0 padding
|
||||
private StringBuilder append(StringBuilder sb, int w, int d) {
|
||||
while (w > 0) {
|
||||
sb.append((char)(d/w + '0'));
|
||||
d = d % w;
|
||||
w /= 10;
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string representation of this {@code FileTime}. The string
|
||||
* is returned in the <a
|
||||
@ -229,135 +409,67 @@ public final class FileTime
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
String v = valueAsString;
|
||||
if (v == null) {
|
||||
// overflow saturates to Long.MIN_VALUE or Long.MAX_VALUE so this
|
||||
// limits the range:
|
||||
// [-292275056-05-16T16:47:04.192Z,292278994-08-17T07:12:55.807Z]
|
||||
long ms = toMillis();
|
||||
|
||||
// nothing to do when seconds/minutes/hours/days
|
||||
String fractionAsString = "";
|
||||
if (unit.compareTo(TimeUnit.SECONDS) < 0) {
|
||||
long fraction = asDaysAndNanos().fractionOfSecondInNanos();
|
||||
if (fraction != 0L) {
|
||||
// fraction must be positive
|
||||
if (fraction < 0L) {
|
||||
final long MAX_FRACTION_PLUS_1 = 1000L * 1000L * 1000L;
|
||||
fraction += MAX_FRACTION_PLUS_1;
|
||||
if (ms != Long.MIN_VALUE) ms--;
|
||||
}
|
||||
|
||||
// convert to String, adding leading zeros as required and
|
||||
// stripping any trailing zeros
|
||||
String s = Long.toString(fraction);
|
||||
int len = s.length();
|
||||
int width = 9 - len;
|
||||
StringBuilder sb = new StringBuilder(".");
|
||||
while (width-- > 0) {
|
||||
sb.append('0');
|
||||
}
|
||||
if (s.charAt(len-1) == '0') {
|
||||
// drop trailing zeros
|
||||
len--;
|
||||
while (s.charAt(len-1) == '0')
|
||||
len--;
|
||||
sb.append(s.substring(0, len));
|
||||
} else {
|
||||
sb.append(s);
|
||||
}
|
||||
fractionAsString = sb.toString();
|
||||
if (valueAsString == null) {
|
||||
long secs = 0L;
|
||||
int nanos = 0;
|
||||
if (instant == null && unit.compareTo(TimeUnit.SECONDS) >= 0) {
|
||||
secs = unit.toSeconds(value);
|
||||
} else {
|
||||
secs = toInstant().getEpochSecond();
|
||||
nanos = toInstant().getNano();
|
||||
}
|
||||
LocalDateTime ldt;
|
||||
int year = 0;
|
||||
if (secs >= -SECONDS_0000_TO_1970) {
|
||||
// current era
|
||||
long zeroSecs = secs - SECONDS_PER_10000_YEARS + SECONDS_0000_TO_1970;
|
||||
long hi = Math.floorDiv(zeroSecs, SECONDS_PER_10000_YEARS) + 1;
|
||||
long lo = Math.floorMod(zeroSecs, SECONDS_PER_10000_YEARS);
|
||||
ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, nanos, ZoneOffset.UTC);
|
||||
year = ldt.getYear() + (int)hi * 10000;
|
||||
} else {
|
||||
// before current era
|
||||
long zeroSecs = secs + SECONDS_0000_TO_1970;
|
||||
long hi = zeroSecs / SECONDS_PER_10000_YEARS;
|
||||
long lo = zeroSecs % SECONDS_PER_10000_YEARS;
|
||||
ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, nanos, ZoneOffset.UTC);
|
||||
year = ldt.getYear() + (int)hi * 10000;
|
||||
}
|
||||
if (year <= 0) {
|
||||
year = year - 1;
|
||||
}
|
||||
int fraction = ldt.getNano();
|
||||
StringBuilder sb = new StringBuilder(64);
|
||||
sb.append(year < 0 ? "-" : "");
|
||||
year = Math.abs(year);
|
||||
if (year < 10000) {
|
||||
append(sb, 1000, Math.abs(year));
|
||||
} else {
|
||||
sb.append(String.valueOf(year));
|
||||
}
|
||||
sb.append('-');
|
||||
append(sb, 10, ldt.getMonthValue());
|
||||
sb.append('-');
|
||||
append(sb, 10, ldt.getDayOfMonth());
|
||||
sb.append('T');
|
||||
append(sb, 10, ldt.getHour());
|
||||
sb.append(':');
|
||||
append(sb, 10, ldt.getMinute());
|
||||
sb.append(':');
|
||||
append(sb, 10, ldt.getSecond());
|
||||
if (fraction != 0) {
|
||||
sb.append('.');
|
||||
// adding leading zeros and stripping any trailing zeros
|
||||
int w = 100_000_000;
|
||||
while (fraction % 10 == 0) {
|
||||
fraction /= 10;
|
||||
w /= 10;
|
||||
}
|
||||
append(sb, w, fraction);
|
||||
}
|
||||
|
||||
// create calendar to use with formatter.
|
||||
GregorianCalendar cal =
|
||||
new GregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.ROOT);
|
||||
if (value < 0L)
|
||||
cal.setGregorianChange(new Date(Long.MIN_VALUE));
|
||||
cal.setTimeInMillis(ms);
|
||||
|
||||
// years are negative before common era
|
||||
String sign = (cal.get(Calendar.ERA) == GregorianCalendar.BC) ? "-" : "";
|
||||
|
||||
// [-]YYYY-MM-DDThh:mm:ss[.s]Z
|
||||
v = new Formatter(Locale.ROOT)
|
||||
.format("%s%tFT%tR:%tS%sZ", sign, cal, cal, cal, fractionAsString)
|
||||
.toString();
|
||||
valueAsString = v;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a FileTime's value as two longs: the number of days since
|
||||
* the epoch, and the excess (in nanoseconds). This is used for comparing
|
||||
* values with different units of granularity.
|
||||
*/
|
||||
private static class DaysAndNanos implements Comparable<DaysAndNanos> {
|
||||
// constants for conversion
|
||||
private static final long C0 = 1L;
|
||||
private static final long C1 = C0 * 24L;
|
||||
private static final long C2 = C1 * 60L;
|
||||
private static final long C3 = C2 * 60L;
|
||||
private static final long C4 = C3 * 1000L;
|
||||
private static final long C5 = C4 * 1000L;
|
||||
private static final long C6 = C5 * 1000L;
|
||||
|
||||
/**
|
||||
* The value (in days) since the epoch; can be negative.
|
||||
*/
|
||||
private final long days;
|
||||
|
||||
/**
|
||||
* The excess (in nanoseconds); can be negative if days <= 0.
|
||||
*/
|
||||
private final long excessNanos;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of this class.
|
||||
*/
|
||||
DaysAndNanos(long value, TimeUnit unit) {
|
||||
long scale;
|
||||
switch (unit) {
|
||||
case DAYS : scale = C0; break;
|
||||
case HOURS : scale = C1; break;
|
||||
case MINUTES : scale = C2; break;
|
||||
case SECONDS : scale = C3; break;
|
||||
case MILLISECONDS : scale = C4; break;
|
||||
case MICROSECONDS : scale = C5; break;
|
||||
case NANOSECONDS : scale = C6; break;
|
||||
default : throw new AssertionError("Unit not handled");
|
||||
}
|
||||
this.days = unit.toDays(value);
|
||||
this.excessNanos = unit.toNanos(value - (this.days * scale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fraction of a second, in nanoseconds.
|
||||
*/
|
||||
long fractionOfSecondInNanos() {
|
||||
return excessNanos % (1000L * 1000L * 1000L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (obj instanceof DaysAndNanos) ?
|
||||
compareTo((DaysAndNanos)obj) == 0 : false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int)(days ^ (days >>> 32) ^
|
||||
excessNanos ^ (excessNanos >>> 32));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(DaysAndNanos other) {
|
||||
if (this.days != other.days)
|
||||
return (this.days < other.days) ? -1 : 1;
|
||||
return (this.excessNanos < other.excessNanos) ? -1 :
|
||||
(this.excessNanos == other.excessNanos) ? 0 : 1;
|
||||
sb.append('Z');
|
||||
valueAsString = sb.toString();
|
||||
}
|
||||
return valueAsString;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -120,6 +120,13 @@ public class LogStream extends PrintStream {
|
||||
*/
|
||||
@Deprecated
|
||||
public static synchronized void setDefaultStream(PrintStream newDefault) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
|
||||
if (sm != null) {
|
||||
sm.checkPermission(
|
||||
new java.util.logging.LoggingPermission("control", null));
|
||||
}
|
||||
|
||||
defaultStream = newDefault;
|
||||
}
|
||||
|
||||
|
||||
@ -26,6 +26,8 @@
|
||||
package java.security;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.Reflection;
|
||||
|
||||
/**
|
||||
* <p> The AccessController class is used for access control operations
|
||||
@ -264,6 +266,7 @@ public final class AccessController {
|
||||
* @see java.security.DomainCombiner
|
||||
*/
|
||||
|
||||
@CallerSensitive
|
||||
public static native <T> T doPrivileged(PrivilegedAction<T> action);
|
||||
|
||||
/**
|
||||
@ -288,14 +291,15 @@ public final class AccessController {
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) {
|
||||
|
||||
AccessControlContext acc = getStackAccessControlContext();
|
||||
if (acc == null) {
|
||||
return AccessController.doPrivileged(action);
|
||||
}
|
||||
DomainCombiner dc = acc.getAssignedCombiner();
|
||||
return AccessController.doPrivileged(action, preserveCombiner(dc));
|
||||
return AccessController.doPrivileged(action,
|
||||
preserveCombiner(dc, Reflection.getCallerClass()));
|
||||
}
|
||||
|
||||
|
||||
@ -326,6 +330,7 @@ public final class AccessController {
|
||||
* @see #doPrivileged(PrivilegedAction)
|
||||
* @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static native <T> T doPrivileged(PrivilegedAction<T> action,
|
||||
AccessControlContext context);
|
||||
|
||||
@ -353,6 +358,7 @@ public final class AccessController {
|
||||
* @see #doPrivilegedWithCombiner(PrivilegedExceptionAction)
|
||||
* @see java.security.DomainCombiner
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static native <T> T
|
||||
doPrivileged(PrivilegedExceptionAction<T> action)
|
||||
throws PrivilegedActionException;
|
||||
@ -383,34 +389,29 @@ public final class AccessController {
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public static <T> T doPrivilegedWithCombiner
|
||||
(PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
|
||||
|
||||
@CallerSensitive
|
||||
public static <T> T doPrivilegedWithCombiner(PrivilegedExceptionAction<T> action)
|
||||
throws PrivilegedActionException
|
||||
{
|
||||
AccessControlContext acc = getStackAccessControlContext();
|
||||
if (acc == null) {
|
||||
return AccessController.doPrivileged(action);
|
||||
}
|
||||
DomainCombiner dc = acc.getAssignedCombiner();
|
||||
return AccessController.doPrivileged(action, preserveCombiner(dc));
|
||||
return AccessController.doPrivileged(action,
|
||||
preserveCombiner(dc, Reflection.getCallerClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* preserve the combiner across the doPrivileged call
|
||||
*/
|
||||
private static AccessControlContext preserveCombiner
|
||||
(DomainCombiner combiner) {
|
||||
|
||||
/**
|
||||
* callerClass[0] = Reflection.getCallerClass
|
||||
* callerClass[1] = AccessController.preserveCombiner
|
||||
* callerClass[2] = AccessController.doPrivileged
|
||||
* callerClass[3] = caller
|
||||
*/
|
||||
final Class<?> callerClass = sun.reflect.Reflection.getCallerClass(3);
|
||||
private static AccessControlContext preserveCombiner(DomainCombiner combiner,
|
||||
Class<?> caller)
|
||||
{
|
||||
ProtectionDomain callerPd = doPrivileged
|
||||
(new PrivilegedAction<ProtectionDomain>() {
|
||||
public ProtectionDomain run() {
|
||||
return callerClass.getProtectionDomain();
|
||||
return caller.getProtectionDomain();
|
||||
}
|
||||
});
|
||||
|
||||
@ -455,6 +456,7 @@ public final class AccessController {
|
||||
* @see #doPrivileged(PrivilegedAction)
|
||||
* @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static native <T> T
|
||||
doPrivileged(PrivilegedExceptionAction<T> action,
|
||||
AccessControlContext context)
|
||||
|
||||
@ -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
|
||||
@ -26,6 +26,7 @@
|
||||
package java.security;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.*;
|
||||
|
||||
import java.security.Provider.Service;
|
||||
|
||||
@ -79,7 +80,7 @@ import sun.security.jca.GetInstance.Instance;
|
||||
*
|
||||
* Note: Depending on the implementation, the <code>generateSeed</code> and
|
||||
* <code>nextBytes</code> methods may block as entropy is being gathered,
|
||||
* for example, if they need to read from /dev/random on various unix-like
|
||||
* for example, if they need to read from /dev/random on various Unix-like
|
||||
* operating systems.
|
||||
*
|
||||
* @see java.security.SecureRandomSpi
|
||||
@ -428,6 +429,7 @@ public class SecureRandom extends java.util.Random {
|
||||
*
|
||||
* @see #getSeed
|
||||
*/
|
||||
@Override
|
||||
public void setSeed(long seed) {
|
||||
/*
|
||||
* Ignore call from super constructor (as well as any other calls
|
||||
@ -450,7 +452,7 @@ public class SecureRandom extends java.util.Random {
|
||||
*
|
||||
* @param bytes the array to be filled in with random bytes.
|
||||
*/
|
||||
|
||||
@Override
|
||||
synchronized public void nextBytes(byte[] bytes) {
|
||||
secureRandomSpi.engineNextBytes(bytes);
|
||||
}
|
||||
@ -469,14 +471,16 @@ public class SecureRandom extends java.util.Random {
|
||||
* @return an <code>int</code> containing the user-specified number
|
||||
* of pseudo-random bits (right justified, with leading zeros).
|
||||
*/
|
||||
@Override
|
||||
final protected int next(int numBits) {
|
||||
int numBytes = (numBits+7)/8;
|
||||
byte b[] = new byte[numBytes];
|
||||
int next = 0;
|
||||
|
||||
nextBytes(b);
|
||||
for (int i = 0; i < numBytes; i++)
|
||||
for (int i = 0; i < numBytes; i++) {
|
||||
next = (next << 8) + (b[i] & 0xFF);
|
||||
}
|
||||
|
||||
return next >>> (numBytes*8 - numBits);
|
||||
}
|
||||
@ -499,8 +503,9 @@ public class SecureRandom extends java.util.Random {
|
||||
* @see #setSeed
|
||||
*/
|
||||
public static byte[] getSeed(int numBytes) {
|
||||
if (seedGenerator == null)
|
||||
if (seedGenerator == null) {
|
||||
seedGenerator = new SecureRandom();
|
||||
}
|
||||
return seedGenerator.generateSeed(numBytes);
|
||||
}
|
||||
|
||||
@ -549,6 +554,104 @@ public class SecureRandom extends java.util.Random {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lazily initialize since Pattern.compile() is heavy.
|
||||
* Effective Java (2nd Edition), Item 71.
|
||||
*/
|
||||
private static final class StrongPatternHolder {
|
||||
/*
|
||||
* Entries are alg:prov separated by ,
|
||||
* Allow for prepended/appended whitespace between entries.
|
||||
*
|
||||
* Capture groups:
|
||||
* 1 - alg
|
||||
* 2 - :prov (optional)
|
||||
* 3 - prov (optional)
|
||||
* 4 - ,nextEntry (optional)
|
||||
* 5 - nextEntry (optional)
|
||||
*/
|
||||
private static Pattern pattern =
|
||||
Pattern.compile(
|
||||
"\\s*([\\S&&[^:,]]*)(\\:([\\S&&[^,]]*))?\\s*(\\,(.*))?");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code SecureRandom} object that was selected by using
|
||||
* the algorithms/providers specified in the {@code
|
||||
* securerandom.strongAlgorithms} Security property.
|
||||
* <p>
|
||||
* 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
|
||||
* include a list of known strong {@code SecureRandom}
|
||||
* implementations in the {@code securerandom.strongAlgorithms}
|
||||
* Security property.
|
||||
*
|
||||
* <pre>
|
||||
* 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);
|
||||
* </pre>
|
||||
*
|
||||
* @return a strong {@code SecureRandom} implementation as indicated
|
||||
* by the {@code securerandom.strongAlgorithms} Security property, or
|
||||
* null if none are available.
|
||||
*
|
||||
* @see Security#getProperty(String)
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public static SecureRandom getStrongSecureRandom() {
|
||||
|
||||
String property = AccessController.doPrivileged(
|
||||
new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
return Security.getProperty(
|
||||
"securerandom.strongAlgorithms");
|
||||
}
|
||||
});
|
||||
|
||||
if ((property == null) || (property.length() == 0)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String remainder = property;
|
||||
while (remainder != null) {
|
||||
Matcher m;
|
||||
if ((m = StrongPatternHolder.pattern.matcher(
|
||||
remainder)).matches()) {
|
||||
|
||||
String alg = m.group(1);
|
||||
String prov = m.group(3);
|
||||
|
||||
try {
|
||||
if (prov == null) {
|
||||
return SecureRandom.getInstance(alg);
|
||||
} else {
|
||||
return SecureRandom.getInstance(alg, prov);
|
||||
}
|
||||
} catch (NoSuchAlgorithmException |
|
||||
NoSuchProviderException e) {
|
||||
}
|
||||
remainder = m.group(5);
|
||||
} else {
|
||||
remainder = null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Declare serialVersionUID to be compatible with JDK1.1
|
||||
static final long serialVersionUID = 4940670005562187L;
|
||||
|
||||
|
||||
@ -30,6 +30,7 @@ import java.util.ServiceLoader;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.Reflection;
|
||||
|
||||
|
||||
@ -192,14 +193,11 @@ public class DriverManager {
|
||||
* has been exceeded and has at least tried to cancel the
|
||||
* current database connection attempt
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static Connection getConnection(String url,
|
||||
java.util.Properties info) throws SQLException {
|
||||
|
||||
// Gets the classloader of the code that called this method, may
|
||||
// be null.
|
||||
ClassLoader callerCL = DriverManager.getCallerClassLoader();
|
||||
|
||||
return (getConnection(url, info, callerCL));
|
||||
return (getConnection(url, info, Reflection.getCallerClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,14 +224,11 @@ public class DriverManager {
|
||||
* has been exceeded and has at least tried to cancel the
|
||||
* current database connection attempt
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static Connection getConnection(String url,
|
||||
String user, String password) throws SQLException {
|
||||
java.util.Properties info = new java.util.Properties();
|
||||
|
||||
// Gets the classloader of the code that called this method, may
|
||||
// be null.
|
||||
ClassLoader callerCL = DriverManager.getCallerClassLoader();
|
||||
|
||||
if (user != null) {
|
||||
info.put("user", user);
|
||||
}
|
||||
@ -241,7 +236,7 @@ public class DriverManager {
|
||||
info.put("password", password);
|
||||
}
|
||||
|
||||
return (getConnection(url, info, callerCL));
|
||||
return (getConnection(url, info, Reflection.getCallerClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -259,16 +254,12 @@ public class DriverManager {
|
||||
* has been exceeded and has at least tried to cancel the
|
||||
* current database connection attempt
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static Connection getConnection(String url)
|
||||
throws SQLException {
|
||||
|
||||
java.util.Properties info = new java.util.Properties();
|
||||
|
||||
// Gets the classloader of the code that called this method, may
|
||||
// be null.
|
||||
ClassLoader callerCL = DriverManager.getCallerClassLoader();
|
||||
|
||||
return (getConnection(url, info, callerCL));
|
||||
return (getConnection(url, info, Reflection.getCallerClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -282,21 +273,20 @@ public class DriverManager {
|
||||
* that can connect to the given URL
|
||||
* @exception SQLException if a database access error occurs
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static Driver getDriver(String url)
|
||||
throws SQLException {
|
||||
|
||||
println("DriverManager.getDriver(\"" + url + "\")");
|
||||
|
||||
// Gets the classloader of the code that called this method, may
|
||||
// be null.
|
||||
ClassLoader callerCL = DriverManager.getCallerClassLoader();
|
||||
Class<?> callerClass = Reflection.getCallerClass();
|
||||
|
||||
// Walk through the loaded registeredDrivers attempting to locate someone
|
||||
// who understands the given URL.
|
||||
for (DriverInfo aDriver : registeredDrivers) {
|
||||
// If the caller does not have permission to load the driver then
|
||||
// skip it.
|
||||
if(isDriverAllowed(aDriver.driver, callerCL)) {
|
||||
if(isDriverAllowed(aDriver.driver, callerClass)) {
|
||||
try {
|
||||
if(aDriver.driver.acceptsURL(url)) {
|
||||
// Success!
|
||||
@ -350,20 +340,18 @@ public class DriverManager {
|
||||
* @param driver the JDBC Driver to drop
|
||||
* @exception SQLException if a database access error occurs
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static synchronized void deregisterDriver(Driver driver)
|
||||
throws SQLException {
|
||||
if (driver == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Gets the classloader of the code that called this method,
|
||||
// may be null.
|
||||
ClassLoader callerCL = DriverManager.getCallerClassLoader();
|
||||
println("DriverManager.deregisterDriver: " + driver);
|
||||
|
||||
DriverInfo aDriver = new DriverInfo(driver);
|
||||
if(registeredDrivers.contains(aDriver)) {
|
||||
if (isDriverAllowed(driver, callerCL)) {
|
||||
if (isDriverAllowed(driver, Reflection.getCallerClass())) {
|
||||
registeredDrivers.remove(aDriver);
|
||||
} else {
|
||||
// If the caller does not have permission to load the driver then
|
||||
@ -384,18 +372,17 @@ public class DriverManager {
|
||||
*
|
||||
* @return the list of JDBC Drivers loaded by the caller's class loader
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static java.util.Enumeration<Driver> getDrivers() {
|
||||
java.util.Vector<Driver> result = new java.util.Vector<>();
|
||||
|
||||
// Gets the classloader of the code that called this method, may
|
||||
// be null.
|
||||
ClassLoader callerCL = DriverManager.getCallerClassLoader();
|
||||
Class<?> callerClass = Reflection.getCallerClass();
|
||||
|
||||
// Walk through the loaded registeredDrivers.
|
||||
for(DriverInfo aDriver : registeredDrivers) {
|
||||
// If the caller does not have permission to load the driver then
|
||||
// skip it.
|
||||
if(isDriverAllowed(aDriver.driver, callerCL)) {
|
||||
if(isDriverAllowed(aDriver.driver, callerClass)) {
|
||||
result.addElement(aDriver.driver);
|
||||
} else {
|
||||
println(" skipping: " + aDriver.getClass().getName());
|
||||
@ -493,17 +480,13 @@ public class DriverManager {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
// Internal method used to get the caller's class loader.
|
||||
// Replaces the call to the native method
|
||||
private static ClassLoader getCallerClassLoader() {
|
||||
Class<?> cc = Reflection.getCallerClass(3);
|
||||
ClassLoader cl = (cc != null) ? cc.getClassLoader() : null;
|
||||
return cl;
|
||||
}
|
||||
|
||||
|
||||
// Indicates whether the class object that would be created if the code calling
|
||||
// DriverManager is accessible.
|
||||
private static boolean isDriverAllowed(Driver driver, Class<?> caller) {
|
||||
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
|
||||
return isDriverAllowed(driver, callerCL);
|
||||
}
|
||||
|
||||
private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
|
||||
boolean result = false;
|
||||
if(driver != null) {
|
||||
@ -556,7 +539,7 @@ public class DriverManager {
|
||||
*/
|
||||
try{
|
||||
while(driversIterator.hasNext()) {
|
||||
println(" Loading done by the java.util.ServiceLoader : "+driversIterator.next());
|
||||
driversIterator.next();
|
||||
}
|
||||
} catch(Throwable t) {
|
||||
// Do nothing
|
||||
@ -586,18 +569,19 @@ public class DriverManager {
|
||||
|
||||
// Worker method called by the public getConnection() methods.
|
||||
private static Connection getConnection(
|
||||
String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
|
||||
String url, java.util.Properties info, Class<?> caller) throws SQLException {
|
||||
/*
|
||||
* When callerCl is null, we should check the application's
|
||||
* (which is invoking this class indirectly)
|
||||
* classloader, so that the JDBC driver class outside rt.jar
|
||||
* can be loaded from here.
|
||||
*/
|
||||
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
|
||||
synchronized(DriverManager.class) {
|
||||
// synchronize loading of the correct classloader.
|
||||
if(callerCL == null) {
|
||||
callerCL = Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
// synchronize loading of the correct classloader.
|
||||
if (callerCL == null) {
|
||||
callerCL = Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
}
|
||||
|
||||
if(url == null) {
|
||||
|
||||
@ -61,13 +61,13 @@
|
||||
*/
|
||||
package java.time;
|
||||
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import static java.time.temporal.ChronoField.DAY_OF_WEEK;
|
||||
import static java.time.temporal.ChronoUnit.DAYS;
|
||||
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.format.TextStyle;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.Queries;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
@ -259,7 +259,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
|
||||
* <p>
|
||||
* If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the
|
||||
* range of the day-of-week, from 1 to 7, will be returned.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
|
||||
@ -269,6 +269,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
|
||||
* @param field the field to query the range for, not null
|
||||
* @return the range of valid values for the field, not null
|
||||
* @throws DateTimeException if the range for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
*/
|
||||
@Override
|
||||
public ValueRange range(TemporalField field) {
|
||||
@ -288,7 +289,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
|
||||
* <p>
|
||||
* If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the
|
||||
* value of the day-of-week, from 1 to 7, will be returned.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
@ -297,7 +298,10 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
|
||||
*
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field, within the valid range of values
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws DateTimeException if a value for the field cannot be obtained or
|
||||
* the value is outside the range of valid values for the field
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported or
|
||||
* the range of values exceeds an {@code int}
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -317,7 +321,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
|
||||
* <p>
|
||||
* If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the
|
||||
* value of the day-of-week, from 1 to 7, will be returned.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
@ -327,6 +331,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -334,7 +339,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
|
||||
if (field == DAY_OF_WEEK) {
|
||||
return getValue();
|
||||
} else if (field instanceof ChronoField) {
|
||||
throw new DateTimeException("Unsupported field: " + field.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
|
||||
}
|
||||
return field.getFrom(this);
|
||||
}
|
||||
@ -393,7 +398,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <R> R query(TemporalQuery<R> query) {
|
||||
if (query == Queries.precision()) {
|
||||
if (query == TemporalQuery.precision()) {
|
||||
return (R) DAYS;
|
||||
}
|
||||
return TemporalAccessor.super.query(query);
|
||||
@ -409,8 +414,8 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
|
||||
* passing {@link ChronoField#DAY_OF_WEEK} as the field.
|
||||
* Note that this adjusts forwards or backwards within a Monday to Sunday week.
|
||||
* See {@link WeekFields#dayOfWeek} for localized week start days.
|
||||
* See {@link java.time.temporal.Adjusters Adjusters} for other adjusters
|
||||
* with more control, such as {@code next(MONDAY)}.
|
||||
* See {@code TemporalAdjuster} for other adjusters with more control,
|
||||
* such as {@code next(MONDAY)}.
|
||||
* <p>
|
||||
* In most cases, it is clearer to reverse the calling pattern by using
|
||||
* {@link Temporal#with(TemporalAdjuster)}:
|
||||
|
||||
@ -85,6 +85,7 @@ 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.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -302,31 +303,32 @@ public final class Duration
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains a {@code Duration} representing the duration between two instants.
|
||||
* Obtains an instance of {@code Duration} from a temporal amount.
|
||||
* <p>
|
||||
* This calculates the duration between two temporal objects of the same type.
|
||||
* The difference in seconds is calculated using
|
||||
* {@link Temporal#periodUntil(Temporal, TemporalUnit)}.
|
||||
* The difference in nanoseconds is calculated using by querying the
|
||||
* {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field.
|
||||
* This obtains a duration 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 duration.
|
||||
* <p>
|
||||
* The result of this method can be a negative period if the end is before the start.
|
||||
* To guarantee to obtain a positive duration call {@link #abs()} on the result.
|
||||
* The conversion loops around the set of units from the amount and uses
|
||||
* the {@linkplain TemporalUnit#getDuration() duration} of the unit to
|
||||
* calculate the total {@code Duration}.
|
||||
* Only a subset of units are accepted by this method. The unit must either
|
||||
* have an {@linkplain TemporalUnit#isDurationEstimated() exact duration}
|
||||
* or be {@link ChronoUnit#DAYS} which is treated as 24 hours.
|
||||
* If any other units are found then an exception is thrown.
|
||||
*
|
||||
* @param startInclusive the start instant, inclusive, not null
|
||||
* @param endExclusive the end instant, exclusive, not null
|
||||
* @return a {@code Duration}, not null
|
||||
* @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration}
|
||||
* @param amount the temporal amount to convert, not null
|
||||
* @return the equivalent duration, not null
|
||||
* @throws DateTimeException if unable to convert to a {@code Duration}
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
public static Duration between(Temporal startInclusive, Temporal endExclusive) {
|
||||
long secs = startInclusive.periodUntil(endExclusive, SECONDS);
|
||||
long nanos;
|
||||
try {
|
||||
nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND);
|
||||
} catch (DateTimeException ex) {
|
||||
nanos = 0;
|
||||
public static Duration from(TemporalAmount amount) {
|
||||
Objects.requireNonNull(amount, "amount");
|
||||
Duration duration = ZERO;
|
||||
for (TemporalUnit unit : amount.getUnits()) {
|
||||
duration = duration.plus(amount.get(unit), unit);
|
||||
}
|
||||
return ofSeconds(secs, nanos);
|
||||
return duration;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -360,14 +362,14 @@ public final class Duration
|
||||
* <p>
|
||||
* Examples:
|
||||
* <pre>
|
||||
* "PT20.345S" -> parses as "20.345 seconds"
|
||||
* "PT15M" -> parses as "15 minutes" (where a minute is 60 seconds)
|
||||
* "PT10H" -> parses as "10 hours" (where an hour is 3600 seconds)
|
||||
* "P2D" -> parses as "2 days" (where a day is 24 hours or 86400 seconds)
|
||||
* "P2DT3H4M" -> parses as "2 days, 3 hours and 4 minutes"
|
||||
* "P-6H3M" -> parses as "-6 hours and +3 minutes"
|
||||
* "-P6H3M" -> parses as "-6 hours and -3 minutes"
|
||||
* "-P-6H+3M" -> parses as "+6 hours and -3 minutes"
|
||||
* "PT20.345S" -- parses as "20.345 seconds"
|
||||
* "PT15M" -- parses as "15 minutes" (where a minute is 60 seconds)
|
||||
* "PT10H" -- parses as "10 hours" (where an hour is 3600 seconds)
|
||||
* "P2D" -- parses as "2 days" (where a day is 24 hours or 86400 seconds)
|
||||
* "P2DT3H4M" -- parses as "2 days, 3 hours and 4 minutes"
|
||||
* "P-6H3M" -- parses as "-6 hours and +3 minutes"
|
||||
* "-P6H3M" -- parses as "-6 hours and -3 minutes"
|
||||
* "-P-6H+3M" -- parses as "+6 hours and -3 minutes"
|
||||
* </pre>
|
||||
*
|
||||
* @param text the text to parse, not null
|
||||
@ -437,6 +439,44 @@ public final class Duration
|
||||
return ofSeconds(seconds, nanos);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains a {@code Duration} representing the duration between two instants.
|
||||
* <p>
|
||||
* This calculates the duration between two temporal objects of the same type.
|
||||
* 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.
|
||||
* <p>
|
||||
* The result of this method can be a negative period if the end is before the start.
|
||||
* To guarantee to obtain a positive duration call {@link #abs()} on the result.
|
||||
*
|
||||
* @param startInclusive the start instant, inclusive, not null
|
||||
* @param endExclusive the end instant, exclusive, not null
|
||||
* @return a {@code Duration}, not null
|
||||
* @throws DateTimeException if the seconds between the temporals cannot be obtained
|
||||
* @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration}
|
||||
*/
|
||||
public static Duration between(Temporal startInclusive, Temporal endExclusive) {
|
||||
try {
|
||||
return ofNanos(startInclusive.periodUntil(endExclusive, NANOS));
|
||||
} catch (DateTimeException | ArithmeticException ex) {
|
||||
long secs = startInclusive.periodUntil(endExclusive, SECONDS);
|
||||
long nanos;
|
||||
try {
|
||||
nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND);
|
||||
if (secs > 0 && nanos < 0) {
|
||||
secs++;
|
||||
} else if (secs < 0 && nanos > 0) {
|
||||
secs--;
|
||||
}
|
||||
} catch (DateTimeException ex2) {
|
||||
nanos = 0;
|
||||
}
|
||||
return ofSeconds(secs, nanos);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code Duration} using seconds and nanoseconds.
|
||||
@ -474,6 +514,7 @@ public final class Duration
|
||||
* @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
|
||||
public long get(TemporalUnit unit) {
|
||||
@ -482,7 +523,7 @@ public final class Duration
|
||||
} else if (unit == NANOS) {
|
||||
return nanos;
|
||||
} else {
|
||||
throw new DateTimeException("Unsupported unit: " + unit.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@ -637,6 +678,7 @@ public final class Duration
|
||||
* @param amountToAdd the amount of the period, measured in terms of the unit, positive or negative
|
||||
* @param unit the unit that the period is measured in, must have an exact duration, not null
|
||||
* @return a {@code Duration} based on this duration with the specified duration added, not null
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
public Duration plus(long amountToAdd, TemporalUnit unit) {
|
||||
@ -645,7 +687,7 @@ public final class Duration
|
||||
return plus(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY), 0);
|
||||
}
|
||||
if (unit.isDurationEstimated()) {
|
||||
throw new DateTimeException("Unit must not have an estimated duration");
|
||||
throw new UnsupportedTemporalTypeException("Unit must not have an estimated duration");
|
||||
}
|
||||
if (amountToAdd == 0) {
|
||||
return this;
|
||||
@ -1130,9 +1172,9 @@ public final class Duration
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
public long toNanos() {
|
||||
long millis = Math.multiplyExact(seconds, NANOS_PER_SECOND);
|
||||
millis = Math.addExact(millis, nanos);
|
||||
return millis;
|
||||
long totalNanos = Math.multiplyExact(seconds, NANOS_PER_SECOND);
|
||||
totalNanos = Math.addExact(totalNanos, nanos);
|
||||
return totalNanos;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -1199,10 +1241,10 @@ public final class Duration
|
||||
* <p>
|
||||
* Examples:
|
||||
* <pre>
|
||||
* "20.345 seconds" -> "PT20.345S
|
||||
* "15 minutes" (15 * 60 seconds) -> "PT15M"
|
||||
* "10 hours" (10 * 3600 seconds) -> "PT10H"
|
||||
* "2 days" (2 * 86400 seconds) -> "PT48H"
|
||||
* "20.345 seconds" -- "PT20.345S
|
||||
* "15 minutes" (15 * 60 seconds) -- "PT15M"
|
||||
* "10 hours" (10 * 3600 seconds) -- "PT10H"
|
||||
* "2 days" (2 * 86400 seconds) -- "PT48H"
|
||||
* </pre>
|
||||
* Note that multiples of 24 hours are not output as days to avoid confusion
|
||||
* with {@code Period}.
|
||||
|
||||
@ -81,7 +81,6 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.Queries;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
@ -89,6 +88,7 @@ import java.time.temporal.TemporalAmount;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Objects;
|
||||
|
||||
@ -148,6 +148,8 @@ import java.util.Objects;
|
||||
* <li>other times during the day will be broadly in line with the agreed international civil time</li>
|
||||
* <li>the day will be divided into exactly 86400 subdivisions, referred to as "seconds"</li>
|
||||
* <li>the Java "second" may differ from an SI second</li>
|
||||
* <li>a well-defined algorithm must be specified to map each second in the accurate agreed
|
||||
* international civil time to each "second" in this time-scale</li>
|
||||
* </ul><p>
|
||||
* Agreed international civil time is the base time-scale agreed by international convention,
|
||||
* which in 2012 is UTC (with leap-seconds).
|
||||
@ -155,6 +157,14 @@ import java.util.Objects;
|
||||
* In 2012, the definition of the Java time-scale is the same as UTC for all days except
|
||||
* those where a leap-second occurs. On days where a leap-second does occur, the time-scale
|
||||
* effectively eliminates the leap-second, maintaining the fiction of 86400 seconds in the day.
|
||||
* The approved well-defined algorithm to eliminate leap-seconds is specified as
|
||||
* <a href="http://www.cl.cam.ac.uk/~mgk25/time/utc-sls/">UTC-SLS</a>.
|
||||
* <p>
|
||||
* UTC-SLS is a simple algorithm that smoothes the leap-second over the last 1000 seconds of
|
||||
* the day, making each of the last 1000 seconds 1/1000th longer or shorter than an SI second.
|
||||
* Implementations built on an accurate leap-second aware time source should use UTC-SLS.
|
||||
* Use of a different algorithm risks confusion and misinterpretation of instants around a
|
||||
* leap-second and is discouraged.
|
||||
* <p>
|
||||
* The main benefit of always dividing the day into 86400 subdivisions is that it matches the
|
||||
* expectations of most users of the API. The alternative is to force every user to understand
|
||||
@ -163,16 +173,10 @@ import java.util.Objects;
|
||||
* Most applications also do not have a problem with a second being a very small amount longer or
|
||||
* shorter than a real SI second during a leap-second.
|
||||
* <p>
|
||||
* If an application does have access to an accurate clock that reports leap-seconds, then the
|
||||
* recommended technique to implement the Java time-scale is to use the UTC-SLS convention.
|
||||
* <a href="http://www.cl.cam.ac.uk/~mgk25/time/utc-sls/">UTC-SLS</a> effectively smoothes the
|
||||
* leap-second over the last 1000 seconds of the day, making each of the last 1000 "seconds"
|
||||
* 1/1000th longer or shorter than a real SI second.
|
||||
* <p>
|
||||
* One final problem is the definition of the agreed international civil time before the
|
||||
* introduction of modern UTC in 1972. This includes the Java epoch of {@code 1970-01-01}.
|
||||
* It is intended that instants before 1972 be interpreted based on the solar day divided
|
||||
* into 86400 subdivisions.
|
||||
* into 86400 subdivisions, as per the principles of UT1.
|
||||
* <p>
|
||||
* The Java time-scale is used for all date-time classes.
|
||||
* This includes {@code Instant}, {@code LocalDate}, {@code LocalTime}, {@code OffsetDateTime},
|
||||
@ -210,7 +214,7 @@ public final class Instant
|
||||
*/
|
||||
public static final Instant MIN = Instant.ofEpochSecond(MIN_SECOND, 0);
|
||||
/**
|
||||
* The minimum supported {@code Instant}, '-1000000000-01-01T00:00Z'.
|
||||
* The maximum supported {@code Instant}, '1000000000-12-31T23:59:59.999999999Z'.
|
||||
* This could be used by an application as a "far future" instant.
|
||||
* <p>
|
||||
* This is one year later than the maximum {@code LocalDateTime}.
|
||||
@ -292,9 +296,9 @@ public final class Instant
|
||||
* to ensure that the stored nanosecond is in the range 0 to 999,999,999.
|
||||
* For example, the following will result in the exactly the same instant:
|
||||
* <pre>
|
||||
* Instant.ofSeconds(3, 1);
|
||||
* Instant.ofSeconds(4, -999_999_999);
|
||||
* Instant.ofSeconds(2, 1000_000_001);
|
||||
* Instant.ofEpochSecond(3, 1);
|
||||
* Instant.ofEpochSecond(4, -999_999_999);
|
||||
* Instant.ofEpochSecond(2, 1000_000_001);
|
||||
* </pre>
|
||||
*
|
||||
* @param epochSecond the number of seconds from 1970-01-01T00:00:00Z
|
||||
@ -441,7 +445,7 @@ public final class Instant
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return
|
||||
* appropriate range instances.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
|
||||
@ -451,6 +455,7 @@ public final class Instant
|
||||
* @param field the field to query the range for, not null
|
||||
* @return the range of valid values for the field, not null
|
||||
* @throws DateTimeException if the range for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
*/
|
||||
@Override // override for Javadoc
|
||||
public ValueRange range(TemporalField field) {
|
||||
@ -469,7 +474,7 @@ public final class Instant
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return valid
|
||||
* values based on this date-time, except {@code INSTANT_SECONDS} which is too
|
||||
* large to fit in an {@code int} and throws a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
@ -478,7 +483,10 @@ public final class Instant
|
||||
*
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws DateTimeException if a value for the field cannot be obtained or
|
||||
* the value is outside the range of valid values for the field
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported or
|
||||
* the range of values exceeds an {@code int}
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override // override for Javadoc and performance
|
||||
@ -490,7 +498,7 @@ public final class Instant
|
||||
case MILLI_OF_SECOND: return nanos / 1000_000;
|
||||
case INSTANT_SECONDS: INSTANT_SECONDS.checkValidIntValue(seconds);
|
||||
}
|
||||
throw new DateTimeException("Unsupported field: " + field.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
|
||||
}
|
||||
return range(field).checkValidIntValue(field.getFrom(this), field);
|
||||
}
|
||||
@ -505,7 +513,7 @@ public final class Instant
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return valid
|
||||
* values based on this date-time.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
@ -515,6 +523,7 @@ public final class Instant
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -526,7 +535,7 @@ public final class Instant
|
||||
case MILLI_OF_SECOND: return nanos / 1000_000;
|
||||
case INSTANT_SECONDS: return seconds;
|
||||
}
|
||||
throw new DateTimeException("Unsupported field: " + field.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
|
||||
}
|
||||
return field.getFrom(this);
|
||||
}
|
||||
@ -610,7 +619,7 @@ public final class Instant
|
||||
* In all cases, if the new value is outside the valid range of values for the field
|
||||
* then a {@code DateTimeException} will be thrown.
|
||||
* <p>
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
|
||||
@ -623,6 +632,7 @@ public final class Instant
|
||||
* @param newValue the new value of the field in the result
|
||||
* @return an {@code Instant} based on {@code this} with the specified field set, not null
|
||||
* @throws DateTimeException if the field cannot be set
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -642,7 +652,7 @@ public final class Instant
|
||||
case NANO_OF_SECOND: return (newValue != nanos ? create(seconds, (int) newValue) : this);
|
||||
case INSTANT_SECONDS: return (newValue != seconds ? create(newValue, nanos) : this);
|
||||
}
|
||||
throw new DateTimeException("Unsupported field: " + field.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
|
||||
}
|
||||
return field.adjustInto(this, newValue);
|
||||
}
|
||||
@ -668,6 +678,7 @@ public final class Instant
|
||||
* @param unit the unit to truncate to, not null
|
||||
* @return an {@code Instant} based on this instant with the time truncated, not null
|
||||
* @throws DateTimeException if the unit is invalid for truncation
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
*/
|
||||
public Instant truncatedTo(TemporalUnit unit) {
|
||||
if (unit == ChronoUnit.NANOS) {
|
||||
@ -675,11 +686,11 @@ public final class Instant
|
||||
}
|
||||
Duration unitDur = unit.getDuration();
|
||||
if (unitDur.getSeconds() > LocalTime.SECONDS_PER_DAY) {
|
||||
throw new DateTimeException("Unit is too large to be used for truncation");
|
||||
throw new UnsupportedTemporalTypeException("Unit is too large to be used for truncation");
|
||||
}
|
||||
long dur = unitDur.toNanos();
|
||||
if ((LocalTime.NANOS_PER_DAY % dur) != 0) {
|
||||
throw new DateTimeException("Unit must divide into a standard day without remainder");
|
||||
throw new UnsupportedTemporalTypeException("Unit must divide into a standard day without remainder");
|
||||
}
|
||||
long nod = (seconds % LocalTime.SECONDS_PER_DAY) * LocalTime.NANOS_PER_SECOND + nanos;
|
||||
long result = (nod / dur) * dur;
|
||||
@ -754,7 +765,7 @@ public final class Instant
|
||||
* multiplied by 86,400 (24 hours).
|
||||
* </ul>
|
||||
* <p>
|
||||
* All other {@code ChronoUnit} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoUnit}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
|
||||
@ -767,6 +778,7 @@ public final class Instant
|
||||
* @param unit the unit of the amount to add, not null
|
||||
* @return an {@code Instant} based on this instant with the specified amount added, not null
|
||||
* @throws DateTimeException if the addition cannot be made
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -782,7 +794,7 @@ public final class Instant
|
||||
case HALF_DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY / 2));
|
||||
case DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY));
|
||||
}
|
||||
throw new DateTimeException("Unsupported unit: " + unit.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
|
||||
}
|
||||
return unit.addTo(this, amountToAdd);
|
||||
}
|
||||
@ -894,6 +906,7 @@ public final class Instant
|
||||
* @param unit the unit of the amount to subtract, not null
|
||||
* @return an {@code Instant} based on this instant with the specified amount subtracted, not null
|
||||
* @throws DateTimeException if the subtraction cannot be made
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -975,11 +988,12 @@ public final class Instant
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <R> R query(TemporalQuery<R> query) {
|
||||
if (query == Queries.precision()) {
|
||||
if (query == TemporalQuery.precision()) {
|
||||
return (R) NANOS;
|
||||
}
|
||||
// inline TemporalAccessor.super.query(query) as an optimization
|
||||
if (query == Queries.chronology() || query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) {
|
||||
if (query == TemporalQuery.chronology() || query == TemporalQuery.zoneId() ||
|
||||
query == TemporalQuery.zone() || query == TemporalQuery.offset()) {
|
||||
return null;
|
||||
}
|
||||
return query.queryFrom(this);
|
||||
@ -1028,14 +1042,15 @@ public final class Instant
|
||||
* For example, the period in days between two dates can be calculated
|
||||
* using {@code startInstant.periodUntil(endInstant, SECONDS)}.
|
||||
* <p>
|
||||
* This method operates in association with {@link TemporalUnit#between}.
|
||||
* The result of this method is a {@code long} representing the amount of
|
||||
* the specified unit. By contrast, the result of {@code between} is an
|
||||
* object that can be used directly in addition/subtraction:
|
||||
* There are two equivalent ways of using this method.
|
||||
* The first is to invoke this method.
|
||||
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
|
||||
* <pre>
|
||||
* long period = start.periodUntil(end, SECONDS); // this method
|
||||
* dateTime.plus(SECONDS.between(start, end)); // use in plus/minus
|
||||
* // these two lines are equivalent
|
||||
* amount = start.periodUntil(end, SECONDS);
|
||||
* amount = SECONDS.between(start, end);
|
||||
* </pre>
|
||||
* The choice should be made based on which makes the code more readable.
|
||||
* <p>
|
||||
* The calculation is implemented in this method for {@link ChronoUnit}.
|
||||
* The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
|
||||
@ -1053,6 +1068,7 @@ public final class Instant
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the amount of the period between this date and the end date
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -1074,18 +1090,26 @@ public final class Instant
|
||||
case HALF_DAYS: return secondsUntil(end) / (12 * SECONDS_PER_HOUR);
|
||||
case DAYS: return secondsUntil(end) / (SECONDS_PER_DAY);
|
||||
}
|
||||
throw new DateTimeException("Unsupported unit: " + unit.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
|
||||
}
|
||||
return unit.between(this, endInstant);
|
||||
}
|
||||
|
||||
private long nanosUntil(Instant end) {
|
||||
long secs = Math.multiplyExact(secondsUntil(end), NANOS_PER_SECOND);
|
||||
return Math.addExact(secs, end.nanos - nanos);
|
||||
long secsDiff = Math.subtractExact(end.seconds, seconds);
|
||||
long totalNanos = Math.multiplyExact(secsDiff, NANOS_PER_SECOND);
|
||||
return Math.addExact(totalNanos, end.nanos - nanos);
|
||||
}
|
||||
|
||||
private long secondsUntil(Instant end) {
|
||||
return Math.subtractExact(end.seconds, seconds);
|
||||
long secsDiff = Math.subtractExact(end.seconds, seconds);
|
||||
long nanosDiff = end.nanos - nanos;
|
||||
if (secsDiff > 0 && nanosDiff < 0) {
|
||||
secsDiff--;
|
||||
} else if (secsDiff < 0 && nanosDiff > 0) {
|
||||
secsDiff++;
|
||||
}
|
||||
return secsDiff;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@ -69,9 +69,9 @@ 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.EPOCH_DAY;
|
||||
import static java.time.temporal.ChronoField.EPOCH_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;
|
||||
|
||||
import java.io.DataInput;
|
||||
@ -87,7 +87,6 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.Queries;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
@ -95,6 +94,7 @@ import java.time.temporal.TemporalAmount;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.time.zone.ZoneOffsetTransition;
|
||||
import java.time.zone.ZoneRules;
|
||||
@ -238,7 +238,7 @@ public final class LocalDate
|
||||
YEAR.checkValidValue(year);
|
||||
Objects.requireNonNull(month, "month");
|
||||
DAY_OF_MONTH.checkValidValue(dayOfMonth);
|
||||
return create(year, month, dayOfMonth);
|
||||
return create(year, month.getValue(), dayOfMonth);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -258,7 +258,7 @@ public final class LocalDate
|
||||
YEAR.checkValidValue(year);
|
||||
MONTH_OF_YEAR.checkValidValue(month);
|
||||
DAY_OF_MONTH.checkValidValue(dayOfMonth);
|
||||
return create(year, Month.of(month), dayOfMonth);
|
||||
return create(year, month, dayOfMonth);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -287,7 +287,7 @@ public final class LocalDate
|
||||
moy = moy.plus(1);
|
||||
}
|
||||
int dom = dayOfYear - moy.firstDayOfYear(leap) + 1;
|
||||
return create(year, moy, dom);
|
||||
return new LocalDate(year, moy.getValue(), dom);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -342,7 +342,7 @@ public final class LocalDate
|
||||
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
|
||||
* which this factory converts to an instance of {@code LocalDate}.
|
||||
* <p>
|
||||
* The conversion uses the {@link Queries#localDate()} query, which relies
|
||||
* The conversion uses the {@link TemporalQuery#localDate()} query, which relies
|
||||
* on extracting the {@link ChronoField#EPOCH_DAY EPOCH_DAY} field.
|
||||
* <p>
|
||||
* This method matches the signature of the functional interface {@link TemporalQuery}
|
||||
@ -353,7 +353,7 @@ public final class LocalDate
|
||||
* @throws DateTimeException if unable to convert to a {@code LocalDate}
|
||||
*/
|
||||
public static LocalDate from(TemporalAccessor temporal) {
|
||||
LocalDate date = temporal.query(Queries.localDate());
|
||||
LocalDate date = temporal.query(TemporalQuery.localDate());
|
||||
if (date == null) {
|
||||
throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " + temporal.getClass());
|
||||
}
|
||||
@ -395,20 +395,34 @@ public final class LocalDate
|
||||
* Creates a local date from the year, month and day fields.
|
||||
*
|
||||
* @param year the year to represent, validated from MIN_YEAR to MAX_YEAR
|
||||
* @param month the month-of-year to represent, validated not null
|
||||
* @param month the month-of-year to represent, from 1 to 12, validated
|
||||
* @param dayOfMonth the day-of-month to represent, validated from 1 to 31
|
||||
* @return the local date, not null
|
||||
* @throws DateTimeException if the day-of-month is invalid for the month-year
|
||||
*/
|
||||
private static LocalDate create(int year, Month month, int dayOfMonth) {
|
||||
if (dayOfMonth > 28 && dayOfMonth > month.length(IsoChronology.INSTANCE.isLeapYear(year))) {
|
||||
if (dayOfMonth == 29) {
|
||||
throw new DateTimeException("Invalid date 'February 29' as '" + year + "' is not a leap year");
|
||||
} else {
|
||||
throw new DateTimeException("Invalid date '" + month.name() + " " + dayOfMonth + "'");
|
||||
private static LocalDate create(int year, int month, int dayOfMonth) {
|
||||
if (dayOfMonth > 28) {
|
||||
int dom = 31;
|
||||
switch (month) {
|
||||
case 2:
|
||||
dom = (IsoChronology.INSTANCE.isLeapYear(year) ? 29 : 28);
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
case 9:
|
||||
case 11:
|
||||
dom = 30;
|
||||
break;
|
||||
}
|
||||
if (dayOfMonth > dom) {
|
||||
if (dayOfMonth == 29) {
|
||||
throw new DateTimeException("Invalid date 'February 29' as '" + year + "' is not a leap year");
|
||||
} else {
|
||||
throw new DateTimeException("Invalid date '" + Month.of(month).name() + " " + dayOfMonth + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
return new LocalDate(year, month.getValue(), dayOfMonth);
|
||||
return new LocalDate(year, month, dayOfMonth);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -431,7 +445,7 @@ public final class LocalDate
|
||||
day = Math.min(day, 30);
|
||||
break;
|
||||
}
|
||||
return LocalDate.of(year, month, day);
|
||||
return new LocalDate(year, month, day);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -467,7 +481,7 @@ public final class LocalDate
|
||||
* <li>{@code ALIGNED_WEEK_OF_MONTH}
|
||||
* <li>{@code ALIGNED_WEEK_OF_YEAR}
|
||||
* <li>{@code MONTH_OF_YEAR}
|
||||
* <li>{@code EPOCH_MONTH}
|
||||
* <li>{@code PROLEPTIC_MONTH}
|
||||
* <li>{@code YEAR_OF_ERA}
|
||||
* <li>{@code YEAR}
|
||||
* <li>{@code ERA}
|
||||
@ -498,7 +512,7 @@ public final class LocalDate
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return
|
||||
* appropriate range instances.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
|
||||
@ -508,12 +522,13 @@ public final class LocalDate
|
||||
* @param field the field to query the range for, not null
|
||||
* @return the range of valid values for the field, not null
|
||||
* @throws DateTimeException if the range for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
*/
|
||||
@Override
|
||||
public ValueRange range(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
if (f.isDateField()) {
|
||||
if (f.isDateBased()) {
|
||||
switch (f) {
|
||||
case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
|
||||
case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
|
||||
@ -523,7 +538,7 @@ public final class LocalDate
|
||||
}
|
||||
return field.range();
|
||||
}
|
||||
throw new DateTimeException("Unsupported field: " + field.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
|
||||
}
|
||||
return field.rangeRefinedBy(this);
|
||||
}
|
||||
@ -538,9 +553,9 @@ public final class LocalDate
|
||||
* <p>
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return valid
|
||||
* values based on this date, except {@code EPOCH_DAY} and {@code EPOCH_MONTH}
|
||||
* values based on this date, except {@code EPOCH_DAY} and {@code PROLEPTIC_MONTH}
|
||||
* which are too large to fit in an {@code int} and throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
@ -549,7 +564,10 @@ public final class LocalDate
|
||||
*
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws DateTimeException if a value for the field cannot be obtained or
|
||||
* the value is outside the range of valid values for the field
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported or
|
||||
* the range of values exceeds an {@code int}
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override // override for Javadoc and performance
|
||||
@ -570,7 +588,7 @@ public final class LocalDate
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return valid
|
||||
* values based on this date.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
@ -580,6 +598,7 @@ public final class LocalDate
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -588,8 +607,8 @@ public final class LocalDate
|
||||
if (field == EPOCH_DAY) {
|
||||
return toEpochDay();
|
||||
}
|
||||
if (field == EPOCH_MONTH) {
|
||||
return getEpochMonth();
|
||||
if (field == PROLEPTIC_MONTH) {
|
||||
return getProlepticMonth();
|
||||
}
|
||||
return get0(field);
|
||||
}
|
||||
@ -603,20 +622,20 @@ public final class LocalDate
|
||||
case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1;
|
||||
case DAY_OF_MONTH: return day;
|
||||
case DAY_OF_YEAR: return getDayOfYear();
|
||||
case EPOCH_DAY: throw new DateTimeException("Field too large for an int: " + field);
|
||||
case EPOCH_DAY: throw new UnsupportedTemporalTypeException("Invalid field 'EpochDay' for get() method, use getLong() instead");
|
||||
case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1;
|
||||
case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
|
||||
case MONTH_OF_YEAR: return month;
|
||||
case EPOCH_MONTH: throw new DateTimeException("Field too large for an int: " + field);
|
||||
case PROLEPTIC_MONTH: throw new UnsupportedTemporalTypeException("Invalid field 'ProlepticMonth' for get() method, use getLong() instead");
|
||||
case YEAR_OF_ERA: return (year >= 1 ? year : 1 - year);
|
||||
case YEAR: return year;
|
||||
case ERA: return (year >= 1 ? 1 : 0);
|
||||
}
|
||||
throw new DateTimeException("Unsupported field: " + field.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
|
||||
}
|
||||
|
||||
private long getEpochMonth() {
|
||||
return ((year - 1970) * 12L) + (month - 1);
|
||||
private long getProlepticMonth() {
|
||||
return (year * 12L + month - 1);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -626,7 +645,7 @@ public final class LocalDate
|
||||
* 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 todays's rules for leap years are applied for all time.
|
||||
* system, in which today's rules for leap years are applied for all time.
|
||||
*
|
||||
* @return the ISO chronology, not null
|
||||
*/
|
||||
@ -810,7 +829,7 @@ public final class LocalDate
|
||||
* <p>
|
||||
* A simple adjuster might simply set the one of the fields, such as the year field.
|
||||
* A more complex adjuster might set the date to the last day of the month.
|
||||
* A selection of common adjustments is provided in {@link java.time.temporal.Adjusters}.
|
||||
* A selection of common adjustments is provided in {@link TemporalAdjuster}.
|
||||
* These include finding the "last day of the month" and "next Wednesday".
|
||||
* Key date-time classes also implement the {@code TemporalAdjuster} interface,
|
||||
* such as {@link Month} and {@link java.time.MonthDay MonthDay}.
|
||||
@ -908,8 +927,8 @@ public final class LocalDate
|
||||
* The year will be unchanged. The day-of-month will also be unchanged,
|
||||
* unless it would be invalid for the new month and year. In that case, the
|
||||
* day-of-month is adjusted to the maximum valid value for the new month and year.
|
||||
* <li>{@code EPOCH_MONTH} -
|
||||
* Returns a {@code LocalDate} with the specified epoch-month.
|
||||
* <li>{@code PROLEPTIC_MONTH} -
|
||||
* Returns a {@code LocalDate} with the specified proleptic-month.
|
||||
* The day-of-month will be unchanged, unless it would be invalid for the new month
|
||||
* and year. In that case, the day-of-month is adjusted to the maximum valid value
|
||||
* for the new month and year.
|
||||
@ -933,7 +952,7 @@ public final class LocalDate
|
||||
* In all cases, if the new value is outside the valid range of values for the field
|
||||
* then a {@code DateTimeException} will be thrown.
|
||||
* <p>
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
|
||||
@ -946,6 +965,7 @@ public final class LocalDate
|
||||
* @param newValue the new value of the field in the result
|
||||
* @return a {@code LocalDate} based on {@code this} with the specified field set, not null
|
||||
* @throws DateTimeException if the field cannot be set
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -963,12 +983,12 @@ public final class LocalDate
|
||||
case ALIGNED_WEEK_OF_MONTH: return plusWeeks(newValue - getLong(ALIGNED_WEEK_OF_MONTH));
|
||||
case ALIGNED_WEEK_OF_YEAR: return plusWeeks(newValue - getLong(ALIGNED_WEEK_OF_YEAR));
|
||||
case MONTH_OF_YEAR: return withMonth((int) newValue);
|
||||
case EPOCH_MONTH: return plusMonths(newValue - getLong(EPOCH_MONTH));
|
||||
case PROLEPTIC_MONTH: return plusMonths(newValue - getProlepticMonth());
|
||||
case YEAR_OF_ERA: return withYear((int) (year >= 1 ? newValue : 1 - newValue));
|
||||
case YEAR: return withYear((int) newValue);
|
||||
case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year));
|
||||
}
|
||||
throw new DateTimeException("Unsupported field: " + field.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
|
||||
}
|
||||
return field.adjustInto(this, newValue);
|
||||
}
|
||||
@ -1137,7 +1157,7 @@ public final class LocalDate
|
||||
* valid value for the new month and year.
|
||||
* </ul>
|
||||
* <p>
|
||||
* All other {@code ChronoUnit} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoUnit}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
|
||||
@ -1150,6 +1170,7 @@ public final class LocalDate
|
||||
* @param unit the unit of the amount to add, not null
|
||||
* @return a {@code LocalDate} based on this date with the specified amount added, not null
|
||||
* @throws DateTimeException if the addition cannot be made
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -1166,7 +1187,7 @@ public final class LocalDate
|
||||
case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
|
||||
case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
|
||||
}
|
||||
throw new DateTimeException("Unsupported unit: " + unit.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
|
||||
}
|
||||
return unit.addTo(this, amountToAdd);
|
||||
}
|
||||
@ -1315,6 +1336,7 @@ public final class LocalDate
|
||||
* @param unit the unit of the amount to subtract, not null
|
||||
* @return a {@code LocalDate} based on this date with the specified amount subtracted, not null
|
||||
* @throws DateTimeException if the subtraction cannot be made
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -1431,7 +1453,7 @@ public final class LocalDate
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <R> R query(TemporalQuery<R> query) {
|
||||
if (query == Queries.localDate()) {
|
||||
if (query == TemporalQuery.localDate()) {
|
||||
return (R) this;
|
||||
}
|
||||
return ChronoLocalDate.super.query(query);
|
||||
@ -1508,10 +1530,12 @@ public final class LocalDate
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the amount of the period between this date and the end date
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
public long periodUntil(Temporal endDate, TemporalUnit unit) {
|
||||
Objects.requireNonNull(unit, "unit");
|
||||
if (endDate instanceof LocalDate == false) {
|
||||
Objects.requireNonNull(endDate, "endDate");
|
||||
throw new DateTimeException("Unable to calculate period between objects of two different types");
|
||||
@ -1528,7 +1552,7 @@ public final class LocalDate
|
||||
case MILLENNIA: return monthsUntil(end) / 12000;
|
||||
case ERAS: return end.getLong(ERA) - getLong(ERA);
|
||||
}
|
||||
throw new DateTimeException("Unsupported unit: " + unit.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
|
||||
}
|
||||
return unit.between(this, endDate);
|
||||
}
|
||||
@ -1538,8 +1562,8 @@ public final class LocalDate
|
||||
}
|
||||
|
||||
private long monthsUntil(LocalDate end) {
|
||||
long packed1 = getEpochMonth() * 32L + getDayOfMonth(); // no overflow
|
||||
long packed2 = end.getEpochMonth() * 32L + end.getDayOfMonth(); // no overflow
|
||||
long packed1 = getProlepticMonth() * 32L + getDayOfMonth(); // no overflow
|
||||
long packed2 = end.getProlepticMonth() * 32L + end.getDayOfMonth(); // no overflow
|
||||
return (packed2 - packed1) / 32;
|
||||
}
|
||||
|
||||
@ -1549,6 +1573,7 @@ public final class LocalDate
|
||||
* This calculates the period between two dates in terms of years, months and days.
|
||||
* 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.
|
||||
* <p>
|
||||
* The calculation is performed using the ISO calendar system.
|
||||
* If necessary, the input date will be converted to ISO.
|
||||
@ -1561,9 +1586,6 @@ public final class LocalDate
|
||||
* than or equal to the start day-of-month.
|
||||
* For example, from {@code 2010-01-15} to {@code 2011-03-18} is "1 year, 2 months and 3 days".
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* There are two equivalent ways of using this method.
|
||||
* The first is to invoke this method.
|
||||
* The second is to use {@link Period#between(LocalDate, LocalDate)}:
|
||||
@ -1580,7 +1602,7 @@ public final class LocalDate
|
||||
@Override
|
||||
public Period periodUntil(ChronoLocalDate<?> endDate) {
|
||||
LocalDate end = LocalDate.from(endDate);
|
||||
long totalMonths = end.getEpochMonth() - this.getEpochMonth(); // safe
|
||||
long totalMonths = end.getProlepticMonth() - this.getProlepticMonth(); // safe
|
||||
int days = end.day - this.day;
|
||||
if (totalMonths > 0 && days < 0) {
|
||||
totalMonths--;
|
||||
@ -1595,6 +1617,21 @@ public final class LocalDate
|
||||
return Period.of(Math.toIntExact(years), months, days);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats this date using the specified formatter.
|
||||
* <p>
|
||||
* This date will be passed to the formatter to produce a string.
|
||||
*
|
||||
* @param formatter the formatter to use, not null
|
||||
* @return the formatted date string, not null
|
||||
* @throws DateTimeException if an error occurs during printing
|
||||
*/
|
||||
@Override // override for Javadoc and performance
|
||||
public String format(DateTimeFormatter formatter) {
|
||||
Objects.requireNonNull(formatter, "formatter");
|
||||
return formatter.format(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Combines this date with a time to create a {@code LocalDateTime}.
|
||||
@ -1800,7 +1837,7 @@ public final class LocalDate
|
||||
* This method only considers the position of the two dates on the local time-line.
|
||||
* It does not take into account the chronology, or calendar system.
|
||||
* This is different from the comparison in {@link #compareTo(ChronoLocalDate)},
|
||||
* but is the same approach as {@link #DATE_COMPARATOR}.
|
||||
* but is the same approach as {@link ChronoLocalDate#timeLineOrder()}.
|
||||
*
|
||||
* @param other the other date to compare to, not null
|
||||
* @return true if this date is after the specified date
|
||||
@ -1829,7 +1866,7 @@ public final class LocalDate
|
||||
* This method only considers the position of the two dates on the local time-line.
|
||||
* It does not take into account the chronology, or calendar system.
|
||||
* This is different from the comparison in {@link #compareTo(ChronoLocalDate)},
|
||||
* but is the same approach as {@link #DATE_COMPARATOR}.
|
||||
* but is the same approach as {@link ChronoLocalDate#timeLineOrder()}.
|
||||
*
|
||||
* @param other the other date to compare to, not null
|
||||
* @return true if this date is before the specified date
|
||||
@ -1858,7 +1895,7 @@ public final class LocalDate
|
||||
* This method only considers the position of the two dates on the local time-line.
|
||||
* It does not take into account the chronology, or calendar system.
|
||||
* This is different from the comparison in {@link #compareTo(ChronoLocalDate)}
|
||||
* but is the same approach as {@link #DATE_COMPARATOR}.
|
||||
* but is the same approach as {@link ChronoLocalDate#timeLineOrder()}.
|
||||
*
|
||||
* @param other the other date to compare to, not null
|
||||
* @return true if this date is equal to the specified date
|
||||
@ -1912,7 +1949,7 @@ public final class LocalDate
|
||||
/**
|
||||
* Outputs this date as a {@code String}, such as {@code 2007-12-03}.
|
||||
* <p>
|
||||
* The output will be in the ISO-8601 format {@code yyyy-MM-dd}.
|
||||
* The output will be in the ISO-8601 format {@code uuuu-MM-dd}.
|
||||
*
|
||||
* @return a string representation of this date, not null
|
||||
*/
|
||||
@ -1942,21 +1979,6 @@ public final class LocalDate
|
||||
.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs this date as a {@code String} using the formatter.
|
||||
* <p>
|
||||
* This date will be passed to the formatter
|
||||
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
|
||||
*
|
||||
* @param formatter the formatter to use, not null
|
||||
* @return the formatted date string, not null
|
||||
* @throws DateTimeException if an error occurs during printing
|
||||
*/
|
||||
@Override // override for Javadoc
|
||||
public String toString(DateTimeFormatter formatter) {
|
||||
return ChronoLocalDate.super.toString(formatter);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Writes the object using a
|
||||
|
||||
@ -79,12 +79,10 @@ import java.io.InvalidObjectException;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.time.chrono.ChronoLocalDateTime;
|
||||
import java.time.chrono.IsoChronology;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.Queries;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
@ -92,6 +90,7 @@ import java.time.temporal.TemporalAmount;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.time.zone.ZoneRules;
|
||||
import java.util.Objects;
|
||||
@ -546,7 +545,7 @@ public final class LocalDateTime
|
||||
* <li>{@code ALIGNED_WEEK_OF_MONTH}
|
||||
* <li>{@code ALIGNED_WEEK_OF_YEAR}
|
||||
* <li>{@code MONTH_OF_YEAR}
|
||||
* <li>{@code EPOCH_MONTH}
|
||||
* <li>{@code PROLEPTIC_MONTH}
|
||||
* <li>{@code YEAR_OF_ERA}
|
||||
* <li>{@code YEAR}
|
||||
* <li>{@code ERA}
|
||||
@ -565,7 +564,7 @@ public final class LocalDateTime
|
||||
public boolean isSupported(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
return f.isDateField() || f.isTimeField();
|
||||
return f.isDateBased() || f.isTimeBased();
|
||||
}
|
||||
return field != null && field.isSupportedBy(this);
|
||||
}
|
||||
@ -581,7 +580,7 @@ public final class LocalDateTime
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return
|
||||
* appropriate range instances.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
|
||||
@ -591,12 +590,13 @@ public final class LocalDateTime
|
||||
* @param field the field to query the range for, not null
|
||||
* @return the range of valid values for the field, not null
|
||||
* @throws DateTimeException if the range for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
*/
|
||||
@Override
|
||||
public ValueRange range(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
return (f.isTimeField() ? time.range(field) : date.range(field));
|
||||
return (f.isTimeBased() ? time.range(field) : date.range(field));
|
||||
}
|
||||
return field.rangeRefinedBy(this);
|
||||
}
|
||||
@ -612,9 +612,9 @@ public final class LocalDateTime
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return valid
|
||||
* values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY},
|
||||
* {@code EPOCH_DAY} and {@code EPOCH_MONTH} which are too large to fit in
|
||||
* {@code EPOCH_DAY} and {@code PROLEPTIC_MONTH} which are too large to fit in
|
||||
* an {@code int} and throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
@ -623,14 +623,17 @@ public final class LocalDateTime
|
||||
*
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws DateTimeException if a value for the field cannot be obtained or
|
||||
* the value is outside the range of valid values for the field
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported or
|
||||
* the range of values exceeds an {@code int}
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
public int get(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
return (f.isTimeField() ? time.get(field) : date.get(field));
|
||||
return (f.isTimeBased() ? time.get(field) : date.get(field));
|
||||
}
|
||||
return ChronoLocalDateTime.super.get(field);
|
||||
}
|
||||
@ -645,7 +648,7 @@ public final class LocalDateTime
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return valid
|
||||
* values based on this date-time.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
@ -655,13 +658,14 @@ public final class LocalDateTime
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
public long getLong(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
return (f.isTimeField() ? time.getLong(field) : date.getLong(field));
|
||||
return (f.isTimeBased() ? time.getLong(field) : date.getLong(field));
|
||||
}
|
||||
return field.getFrom(this);
|
||||
}
|
||||
@ -822,7 +826,7 @@ public final class LocalDateTime
|
||||
* <p>
|
||||
* A simple adjuster might simply set the one of the fields, such as the year field.
|
||||
* A more complex adjuster might set the date to the last day of the month.
|
||||
* A selection of common adjustments is provided in {@link java.time.temporal.Adjusters}.
|
||||
* A selection of common adjustments is provided in {@link TemporalAdjuster}.
|
||||
* These include finding the "last day of the month" and "next Wednesday".
|
||||
* Key date-time classes also implement the {@code TemporalAdjuster} interface,
|
||||
* such as {@link Month} and {@link java.time.MonthDay MonthDay}.
|
||||
@ -886,7 +890,7 @@ public final class LocalDateTime
|
||||
* The {@link #isSupported(TemporalField) supported fields} will behave as per
|
||||
* the matching method on {@link LocalDate#with(TemporalField, long) LocalDate}
|
||||
* or {@link LocalTime#with(TemporalField, long) LocalTime}.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
|
||||
@ -899,13 +903,14 @@ public final class LocalDateTime
|
||||
* @param newValue the new value of the field in the result
|
||||
* @return a {@code LocalDateTime} based on {@code this} with the specified field set, not null
|
||||
* @throws DateTimeException if the field cannot be set
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
public LocalDateTime with(TemporalField field, long newValue) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
if (f.isTimeField()) {
|
||||
if (f.isTimeBased()) {
|
||||
return with(date, time.with(field, newValue));
|
||||
} else {
|
||||
return with(date.with(field, newValue), time);
|
||||
@ -1052,6 +1057,7 @@ public final class LocalDateTime
|
||||
* @param unit the unit to truncate to, not null
|
||||
* @return a {@code LocalDateTime} based on this date-time with the time truncated, not null
|
||||
* @throws DateTimeException if unable to truncate
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
*/
|
||||
public LocalDateTime truncatedTo(TemporalUnit unit) {
|
||||
return with(date, time.truncatedTo(unit));
|
||||
@ -1106,6 +1112,7 @@ public final class LocalDateTime
|
||||
* @param unit the unit of the amount to add, not null
|
||||
* @return a {@code LocalDateTime} based on this date-time with the specified amount added, not null
|
||||
* @throws DateTimeException if the addition cannot be made
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -1312,6 +1319,7 @@ public final class LocalDateTime
|
||||
* @param unit the unit of the amount to subtract, not null
|
||||
* @return a {@code LocalDateTime} based on this date-time with the specified amount subtracted, not null
|
||||
* @throws DateTimeException if the subtraction cannot be made
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -1517,7 +1525,7 @@ public final class LocalDateTime
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override // override for Javadoc
|
||||
public <R> R query(TemporalQuery<R> query) {
|
||||
if (query == Queries.localDate()) {
|
||||
if (query == TemporalQuery.localDate()) {
|
||||
return (R) date;
|
||||
}
|
||||
return ChronoLocalDateTime.super.query(query);
|
||||
@ -1597,6 +1605,7 @@ public final class LocalDateTime
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the amount of the period between this date-time and the end date-time
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -1610,31 +1619,79 @@ public final class LocalDateTime
|
||||
ChronoUnit f = (ChronoUnit) unit;
|
||||
if (f.isTimeUnit()) {
|
||||
long amount = date.daysUntil(end.date);
|
||||
switch (f) {
|
||||
case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break;
|
||||
case MICROS: amount = Math.multiplyExact(amount, MICROS_PER_DAY); break;
|
||||
case MILLIS: amount = Math.multiplyExact(amount, MILLIS_PER_DAY); break;
|
||||
case SECONDS: amount = Math.multiplyExact(amount, SECONDS_PER_DAY); break;
|
||||
case MINUTES: amount = Math.multiplyExact(amount, MINUTES_PER_DAY); break;
|
||||
case HOURS: amount = Math.multiplyExact(amount, HOURS_PER_DAY); break;
|
||||
case HALF_DAYS: amount = Math.multiplyExact(amount, 2); break;
|
||||
if (amount == 0) {
|
||||
return time.periodUntil(end.time, unit);
|
||||
}
|
||||
return Math.addExact(amount, time.periodUntil(end.time, unit));
|
||||
long timePart = end.time.toNanoOfDay() - time.toNanoOfDay();
|
||||
if (amount > 0) {
|
||||
amount--; // safe
|
||||
timePart += NANOS_PER_DAY; // safe
|
||||
} else {
|
||||
amount++; // safe
|
||||
timePart -= NANOS_PER_DAY; // safe
|
||||
}
|
||||
switch (f) {
|
||||
case NANOS:
|
||||
amount = Math.multiplyExact(amount, NANOS_PER_DAY);
|
||||
break;
|
||||
case MICROS:
|
||||
amount = Math.multiplyExact(amount, MICROS_PER_DAY);
|
||||
timePart = timePart / 1000;
|
||||
break;
|
||||
case MILLIS:
|
||||
amount = Math.multiplyExact(amount, MILLIS_PER_DAY);
|
||||
timePart = timePart / 1_000_000;
|
||||
break;
|
||||
case SECONDS:
|
||||
amount = Math.multiplyExact(amount, SECONDS_PER_DAY);
|
||||
timePart = timePart / NANOS_PER_SECOND;
|
||||
break;
|
||||
case MINUTES:
|
||||
amount = Math.multiplyExact(amount, MINUTES_PER_DAY);
|
||||
timePart = timePart / NANOS_PER_MINUTE;
|
||||
break;
|
||||
case HOURS:
|
||||
amount = Math.multiplyExact(amount, HOURS_PER_DAY);
|
||||
timePart = timePart / NANOS_PER_HOUR;
|
||||
break;
|
||||
case HALF_DAYS:
|
||||
amount = Math.multiplyExact(amount, 2);
|
||||
timePart = timePart / (NANOS_PER_HOUR * 12);
|
||||
break;
|
||||
}
|
||||
return Math.addExact(amount, timePart);
|
||||
}
|
||||
LocalDate endDate = end.date;
|
||||
if (end.time.isBefore(time)) {
|
||||
if (endDate.isAfter(date) && end.time.isBefore(time)) {
|
||||
endDate = endDate.minusDays(1);
|
||||
} else if (endDate.isBefore(date) && end.time.isAfter(time)) {
|
||||
endDate = endDate.plusDays(1);
|
||||
}
|
||||
return date.periodUntil(endDate, unit);
|
||||
}
|
||||
return unit.between(this, endDateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats this date-time using the specified formatter.
|
||||
* <p>
|
||||
* This date-time will be passed to the formatter to produce a string.
|
||||
*
|
||||
* @param formatter the formatter to use, not null
|
||||
* @return the formatted date-time string, not null
|
||||
* @throws DateTimeException if an error occurs during printing
|
||||
*/
|
||||
@Override // override for Javadoc and performance
|
||||
public String format(DateTimeFormatter formatter) {
|
||||
Objects.requireNonNull(formatter, "formatter");
|
||||
return formatter.format(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Combines this time with a date to create an {@code OffsetTime}.
|
||||
* Combines this date-time with an offset to create an {@code OffsetDateTime}.
|
||||
* <p>
|
||||
* This returns an {@code OffsetTime} formed from this time at the specified offset.
|
||||
* This returns an {@code OffsetDateTime} formed from this date-time at the specified offset.
|
||||
* All possible combinations of date-time and offset are valid.
|
||||
*
|
||||
* @param offset the offset to combine with, not null
|
||||
@ -1645,7 +1702,7 @@ public final class LocalDateTime
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines this time with a time-zone to create a {@code ZonedDateTime}.
|
||||
* Combines this date-time with a time-zone to create a {@code ZonedDateTime}.
|
||||
* <p>
|
||||
* This returns a {@code ZonedDateTime} formed from this date-time at the
|
||||
* specified time-zone. The result will match this date-time as closely as possible.
|
||||
@ -1725,7 +1782,7 @@ public final class LocalDateTime
|
||||
* This method only considers the position of the two date-times on the local time-line.
|
||||
* It does not take into account the chronology, or calendar system.
|
||||
* This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
|
||||
* but is the same approach as {@link #DATE_TIME_COMPARATOR}.
|
||||
* but is the same approach as {@link ChronoLocalDateTime#timeLineOrder()}.
|
||||
*
|
||||
* @param other the other date-time to compare to, not null
|
||||
* @return true if this date-time is after the specified date-time
|
||||
@ -1754,7 +1811,7 @@ public final class LocalDateTime
|
||||
* This method only considers the position of the two date-times on the local time-line.
|
||||
* It does not take into account the chronology, or calendar system.
|
||||
* This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
|
||||
* but is the same approach as {@link #DATE_TIME_COMPARATOR}.
|
||||
* but is the same approach as {@link ChronoLocalDateTime#timeLineOrder()}.
|
||||
*
|
||||
* @param other the other date-time to compare to, not null
|
||||
* @return true if this date-time is before the specified date-time
|
||||
@ -1783,7 +1840,7 @@ public final class LocalDateTime
|
||||
* This method only considers the position of the two date-times on the local time-line.
|
||||
* It does not take into account the chronology, or calendar system.
|
||||
* This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
|
||||
* but is the same approach as {@link #DATE_TIME_COMPARATOR}.
|
||||
* but is the same approach as {@link ChronoLocalDateTime#timeLineOrder()}.
|
||||
*
|
||||
* @param other the other date-time to compare to, not null
|
||||
* @return true if this date-time is equal to the specified date-time
|
||||
@ -1834,11 +1891,11 @@ public final class LocalDateTime
|
||||
* <p>
|
||||
* The output will be one of the following ISO-8601 formats:
|
||||
* <p><ul>
|
||||
* <li>{@code yyyy-MM-dd'T'HH:mm}</li>
|
||||
* <li>{@code yyyy-MM-dd'T'HH:mm:ss}</li>
|
||||
* <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSS}</li>
|
||||
* <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSSSS}</li>
|
||||
* <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS}</li>
|
||||
* <li>{@code uuuu-MM-dd'T'HH:mm}</li>
|
||||
* <li>{@code uuuu-MM-dd'T'HH:mm:ss}</li>
|
||||
* <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSS}</li>
|
||||
* <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSS}</li>
|
||||
* <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS}</li>
|
||||
* </ul><p>
|
||||
* The format used will be the shortest that outputs the full value of
|
||||
* the time where the omitted parts are implied to be zero.
|
||||
@ -1850,21 +1907,6 @@ public final class LocalDateTime
|
||||
return date.toString() + 'T' + time.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs this date-time as a {@code String} using the formatter.
|
||||
* <p>
|
||||
* This date-time will be passed to the formatter
|
||||
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
|
||||
*
|
||||
* @param formatter the formatter to use, not null
|
||||
* @return the formatted date-time string, not null
|
||||
* @throws DateTimeException if an error occurs during printing
|
||||
*/
|
||||
@Override // override for Javadoc
|
||||
public String toString(DateTimeFormatter formatter) {
|
||||
return ChronoLocalDateTime.super.toString(formatter);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Writes the object using a
|
||||
|
||||
@ -80,7 +80,6 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.Queries;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
@ -88,6 +87,7 @@ import java.time.temporal.TemporalAmount;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Objects;
|
||||
|
||||
@ -383,7 +383,7 @@ public final class LocalTime
|
||||
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
|
||||
* which this factory converts to an instance of {@code LocalTime}.
|
||||
* <p>
|
||||
* The conversion uses the {@link Queries#localTime()} query, which relies
|
||||
* The conversion uses the {@link TemporalQuery#localTime()} query, which relies
|
||||
* on extracting the {@link ChronoField#NANO_OF_DAY NANO_OF_DAY} field.
|
||||
* <p>
|
||||
* This method matches the signature of the functional interface {@link TemporalQuery}
|
||||
@ -394,7 +394,7 @@ public final class LocalTime
|
||||
* @throws DateTimeException if unable to convert to a {@code LocalTime}
|
||||
*/
|
||||
public static LocalTime from(TemporalAccessor temporal) {
|
||||
LocalTime time = temporal.query(Queries.localTime());
|
||||
LocalTime time = temporal.query(TemporalQuery.localTime());
|
||||
if (time == null) {
|
||||
throw new DateTimeException("Unable to obtain LocalTime from TemporalAccessor: " + temporal.getClass());
|
||||
}
|
||||
@ -505,7 +505,7 @@ public final class LocalTime
|
||||
@Override
|
||||
public boolean isSupported(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
return ((ChronoField) field).isTimeField();
|
||||
return field.isTimeBased();
|
||||
}
|
||||
return field != null && field.isSupportedBy(this);
|
||||
}
|
||||
@ -521,7 +521,7 @@ public final class LocalTime
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return
|
||||
* appropriate range instances.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
|
||||
@ -531,6 +531,7 @@ public final class LocalTime
|
||||
* @param field the field to query the range for, not null
|
||||
* @return the range of valid values for the field, not null
|
||||
* @throws DateTimeException if the range for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
*/
|
||||
@Override // override for Javadoc
|
||||
public ValueRange range(TemporalField field) {
|
||||
@ -549,7 +550,7 @@ public final class LocalTime
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return valid
|
||||
* values based on this time, except {@code NANO_OF_DAY} and {@code MICRO_OF_DAY}
|
||||
* which are too large to fit in an {@code int} and throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
@ -558,7 +559,10 @@ public final class LocalTime
|
||||
*
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws DateTimeException if a value for the field cannot be obtained or
|
||||
* the value is outside the range of valid values for the field
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported or
|
||||
* the range of values exceeds an {@code int}
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override // override for Javadoc and performance
|
||||
@ -579,7 +583,7 @@ public final class LocalTime
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return valid
|
||||
* values based on this time.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
@ -589,6 +593,7 @@ public final class LocalTime
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -608,9 +613,9 @@ public final class LocalTime
|
||||
private int get0(TemporalField field) {
|
||||
switch ((ChronoField) field) {
|
||||
case NANO_OF_SECOND: return nano;
|
||||
case NANO_OF_DAY: throw new DateTimeException("Field too large for an int: " + field);
|
||||
case NANO_OF_DAY: throw new UnsupportedTemporalTypeException("Invalid field 'NanoOfDay' for get() method, use getLong() instead");
|
||||
case MICRO_OF_SECOND: return nano / 1000;
|
||||
case MICRO_OF_DAY: throw new DateTimeException("Field too large for an int: " + field);
|
||||
case MICRO_OF_DAY: throw new UnsupportedTemporalTypeException("Invalid field 'MicroOfDay' for get() method, use getLong() instead");
|
||||
case MILLI_OF_SECOND: return nano / 1000_000;
|
||||
case MILLI_OF_DAY: return (int) (toNanoOfDay() / 1000_000);
|
||||
case SECOND_OF_MINUTE: return second;
|
||||
@ -623,7 +628,7 @@ public final class LocalTime
|
||||
case CLOCK_HOUR_OF_DAY: return (hour == 0 ? 24 : hour);
|
||||
case AMPM_OF_DAY: return hour / 12;
|
||||
}
|
||||
throw new DateTimeException("Unsupported field: " + field.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -760,7 +765,7 @@ public final class LocalTime
|
||||
* In all cases, if the new value is outside the valid range of values for the field
|
||||
* then a {@code DateTimeException} will be thrown.
|
||||
* <p>
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
|
||||
@ -773,6 +778,7 @@ public final class LocalTime
|
||||
* @param newValue the new value of the field in the result
|
||||
* @return a {@code LocalTime} based on {@code this} with the specified field set, not null
|
||||
* @throws DateTimeException if the field cannot be set
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -797,7 +803,7 @@ public final class LocalTime
|
||||
case CLOCK_HOUR_OF_DAY: return withHour((int) (newValue == 24 ? 0 : newValue));
|
||||
case AMPM_OF_DAY: return plusHours((newValue - (hour / 12)) * 12);
|
||||
}
|
||||
throw new DateTimeException("Unsupported field: " + field.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
|
||||
}
|
||||
return field.adjustInto(this, newValue);
|
||||
}
|
||||
@ -890,6 +896,7 @@ public final class LocalTime
|
||||
* @param unit the unit to truncate to, not null
|
||||
* @return a {@code LocalTime} based on this time with the time truncated, not null
|
||||
* @throws DateTimeException if unable to truncate
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
*/
|
||||
public LocalTime truncatedTo(TemporalUnit unit) {
|
||||
if (unit == ChronoUnit.NANOS) {
|
||||
@ -897,11 +904,11 @@ public final class LocalTime
|
||||
}
|
||||
Duration unitDur = unit.getDuration();
|
||||
if (unitDur.getSeconds() > SECONDS_PER_DAY) {
|
||||
throw new DateTimeException("Unit is too large to be used for truncation");
|
||||
throw new UnsupportedTemporalTypeException("Unit is too large to be used for truncation");
|
||||
}
|
||||
long dur = unitDur.toNanos();
|
||||
if ((NANOS_PER_DAY % dur) != 0) {
|
||||
throw new DateTimeException("Unit must divide into a standard day without remainder");
|
||||
throw new UnsupportedTemporalTypeException("Unit must divide into a standard day without remainder");
|
||||
}
|
||||
long nod = toNanoOfDay();
|
||||
return ofNanoOfDay((nod / dur) * dur);
|
||||
@ -972,7 +979,7 @@ public final class LocalTime
|
||||
* This returns {@code this} time.
|
||||
* </ul>
|
||||
* <p>
|
||||
* All other {@code ChronoUnit} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoUnit}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
|
||||
@ -985,6 +992,7 @@ public final class LocalTime
|
||||
* @param unit the unit of the amount to add, not null
|
||||
* @return a {@code LocalTime} based on this time with the specified amount added, not null
|
||||
* @throws DateTimeException if the addition cannot be made
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -1001,7 +1009,7 @@ public final class LocalTime
|
||||
case HALF_DAYS: return plusHours((amountToAdd % 2) * 12);
|
||||
case DAYS: return this;
|
||||
}
|
||||
throw new DateTimeException("Unsupported unit: " + unit.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
|
||||
}
|
||||
return unit.addTo(this, amountToAdd);
|
||||
}
|
||||
@ -1147,6 +1155,7 @@ public final class LocalTime
|
||||
* @param unit the unit of the amount to subtract, not null
|
||||
* @return a {@code LocalTime} based on this time with the specified amount subtracted, not null
|
||||
* @throws DateTimeException if the subtraction cannot be made
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -1237,13 +1246,14 @@ public final class LocalTime
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <R> R query(TemporalQuery<R> query) {
|
||||
if (query == Queries.chronology() || query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) {
|
||||
if (query == TemporalQuery.chronology() || query == TemporalQuery.zoneId() ||
|
||||
query == TemporalQuery.zone() || query == TemporalQuery.offset()) {
|
||||
return null;
|
||||
} else if (query == Queries.localTime()) {
|
||||
} else if (query == TemporalQuery.localTime()) {
|
||||
return (R) this;
|
||||
} else if (query == Queries.localDate()) {
|
||||
} else if (query == TemporalQuery.localDate()) {
|
||||
return null;
|
||||
} else if (query == Queries.precision()) {
|
||||
} else if (query == TemporalQuery.precision()) {
|
||||
return (R) NANOS;
|
||||
}
|
||||
// inline TemporalAccessor.super.query(query) as an optimization
|
||||
@ -1322,6 +1332,7 @@ public final class LocalTime
|
||||
* @param unit the unit to measure the period in, not null
|
||||
* @return the amount of the period between this time and the end time
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -1342,11 +1353,25 @@ public final class LocalTime
|
||||
case HOURS: return nanosUntil / NANOS_PER_HOUR;
|
||||
case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR);
|
||||
}
|
||||
throw new DateTimeException("Unsupported unit: " + unit.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
|
||||
}
|
||||
return unit.between(this, endTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats this time using the specified formatter.
|
||||
* <p>
|
||||
* This time will be passed to the formatter to produce a string.
|
||||
*
|
||||
* @param formatter the formatter to use, not null
|
||||
* @return the formatted time string, not null
|
||||
* @throws DateTimeException if an error occurs during printing
|
||||
*/
|
||||
public String format(DateTimeFormatter formatter) {
|
||||
Objects.requireNonNull(formatter, "formatter");
|
||||
return formatter.format(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Combines this time with a date to create a {@code LocalDateTime}.
|
||||
@ -1362,7 +1387,7 @@ public final class LocalTime
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines this time with a date to create an {@code OffsetTime}.
|
||||
* Combines this time with an offset to create an {@code OffsetTime}.
|
||||
* <p>
|
||||
* This returns an {@code OffsetTime} formed from this time at the specified offset.
|
||||
* All possible combinations of time and offset are valid.
|
||||
@ -1533,21 +1558,6 @@ public final class LocalTime
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs this time as a {@code String} using the formatter.
|
||||
* <p>
|
||||
* This time will be passed to the formatter
|
||||
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
|
||||
*
|
||||
* @param formatter the formatter to use, not null
|
||||
* @return the formatted time string, not null
|
||||
* @throws DateTimeException if an error occurs during printing
|
||||
*/
|
||||
public String toString(DateTimeFormatter formatter) {
|
||||
Objects.requireNonNull(formatter, "formatter");
|
||||
return formatter.format(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Writes the object using a
|
||||
|
||||
@ -61,6 +61,7 @@
|
||||
*/
|
||||
package java.time;
|
||||
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
|
||||
import static java.time.temporal.ChronoUnit.MONTHS;
|
||||
|
||||
@ -69,7 +70,6 @@ import java.time.chrono.IsoChronology;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.format.TextStyle;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.Queries;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
@ -290,7 +290,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
|
||||
* <p>
|
||||
* If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
|
||||
* range of the month-of-year, from 1 to 12, will be returned.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
|
||||
@ -300,6 +300,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
|
||||
* @param field the field to query the range for, not null
|
||||
* @return the range of valid values for the field, not null
|
||||
* @throws DateTimeException if the range for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
*/
|
||||
@Override
|
||||
public ValueRange range(TemporalField field) {
|
||||
@ -319,7 +320,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
|
||||
* <p>
|
||||
* If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
|
||||
* value of the month-of-year, from 1 to 12, will be returned.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
@ -328,7 +329,10 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
|
||||
*
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field, within the valid range of values
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws DateTimeException if a value for the field cannot be obtained or
|
||||
* the value is outside the range of valid values for the field
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported or
|
||||
* the range of values exceeds an {@code int}
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -348,7 +352,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
|
||||
* <p>
|
||||
* If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
|
||||
* value of the month-of-year, from 1 to 12, will be returned.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
@ -358,6 +362,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -365,7 +370,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
|
||||
if (field == MONTH_OF_YEAR) {
|
||||
return getValue();
|
||||
} else if (field instanceof ChronoField) {
|
||||
throw new DateTimeException("Unsupported field: " + field.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
|
||||
}
|
||||
return field.getFrom(this);
|
||||
}
|
||||
@ -554,9 +559,9 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <R> R query(TemporalQuery<R> query) {
|
||||
if (query == Queries.chronology()) {
|
||||
if (query == TemporalQuery.chronology()) {
|
||||
return (R) IsoChronology.INSTANCE;
|
||||
} else if (query == Queries.precision()) {
|
||||
} else if (query == TemporalQuery.precision()) {
|
||||
return (R) MONTHS;
|
||||
}
|
||||
return TemporalAccessor.super.query(query);
|
||||
|
||||
@ -76,12 +76,12 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.Queries;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Objects;
|
||||
|
||||
@ -354,7 +354,7 @@ public final class MonthDay
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return
|
||||
* appropriate range instances.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
|
||||
@ -364,6 +364,7 @@ public final class MonthDay
|
||||
* @param field the field to query the range for, not null
|
||||
* @return the range of valid values for the field, not null
|
||||
* @throws DateTimeException if the range for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
*/
|
||||
@Override
|
||||
public ValueRange range(TemporalField field) {
|
||||
@ -386,7 +387,7 @@ public final class MonthDay
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return valid
|
||||
* values based on this month-day.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
@ -395,7 +396,10 @@ public final class MonthDay
|
||||
*
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws DateTimeException if a value for the field cannot be obtained or
|
||||
* the value is outside the range of valid values for the field
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported or
|
||||
* the range of values exceeds an {@code int}
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override // override for Javadoc
|
||||
@ -413,7 +417,7 @@ public final class MonthDay
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@link #isSupported(TemporalField) supported fields} will return valid
|
||||
* values based on this month-day.
|
||||
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
@ -423,6 +427,7 @@ public final class MonthDay
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
@ -433,7 +438,7 @@ public final class MonthDay
|
||||
case DAY_OF_MONTH: return day;
|
||||
case MONTH_OF_YEAR: return month;
|
||||
}
|
||||
throw new DateTimeException("Unsupported field: " + field.getName());
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
|
||||
}
|
||||
return field.getFrom(this);
|
||||
}
|
||||
@ -575,7 +580,7 @@ public final class MonthDay
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <R> R query(TemporalQuery<R> query) {
|
||||
if (query == Queries.chronology()) {
|
||||
if (query == TemporalQuery.chronology()) {
|
||||
return (R) IsoChronology.INSTANCE;
|
||||
}
|
||||
return TemporalAccessor.super.query(query);
|
||||
@ -617,6 +622,20 @@ public final class MonthDay
|
||||
return temporal.with(DAY_OF_MONTH, Math.min(temporal.range(DAY_OF_MONTH).getMaximum(), day));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats this month-day using the specified formatter.
|
||||
* <p>
|
||||
* This month-day will be passed to the formatter to produce a string.
|
||||
*
|
||||
* @param formatter the formatter to use, not null
|
||||
* @return the formatted month-day string, not null
|
||||
* @throws DateTimeException if an error occurs during printing
|
||||
*/
|
||||
public String format(DateTimeFormatter formatter) {
|
||||
Objects.requireNonNull(formatter, "formatter");
|
||||
return formatter.format(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Combines this month-day with a year to create a {@code LocalDate}.
|
||||
@ -722,21 +741,6 @@ public final class MonthDay
|
||||
.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs this month-day as a {@code String} using the formatter.
|
||||
* <p>
|
||||
* This month-day will be passed to the formatter
|
||||
* {@link DateTimeFormatter#format(TemporalAccessor) format method}.
|
||||
*
|
||||
* @param formatter the formatter to use, not null
|
||||
* @return the formatted month-day string, not null
|
||||
* @throws DateTimeException if an error occurs during printing
|
||||
*/
|
||||
public String toString(DateTimeFormatter formatter) {
|
||||
Objects.requireNonNull(formatter, "formatter");
|
||||
return formatter.format(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Writes the object using a
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user