Implement IcuZoneRulesProvider.
Implement IcuZoneRulesProvider to provide ZoneRules for java.time using
the data/API of ICU4J.
Modified artrun-testng to optionally take the name of the testng.xml
file and provide testng-time.xml file that lists all upstream tests we
imported. Also update artrun to correct list of boot dexjars.
Change ZoneRulesProvider.java to a non-JavaDoc file to avoid exposing it
as public API. Remove mention of ZoneRulesProvider from ZoneRules
JavaDoc. Removed TzdbZoneRulesProvider, which is not used on Android.
Bug: 28832222
Test: ran java.time testng changes (artrun-testng testng-time.xml) and
IcuZoneRulesProviderTest
Change-Id: Ic24454f443ac8000fc50c2c2bddd6f28fc25bc0e
diff --git a/luni/src/test/java/libcore/java/time/zone/IcuZoneRulesProviderTest.java b/luni/src/test/java/libcore/java/time/zone/IcuZoneRulesProviderTest.java
new file mode 100644
index 0000000..c3c0f50
--- /dev/null
+++ b/luni/src/test/java/libcore/java/time/zone/IcuZoneRulesProviderTest.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.java.time.zone;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import android.icu.util.BasicTimeZone;
+import android.icu.util.TimeZone;
+import android.icu.util.TimeZoneRule;
+import android.icu.util.TimeZoneTransition;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.Month;
+import java.time.ZoneOffset;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneRules;
+import java.time.zone.ZoneRulesProvider;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Test the {@link java.time.zone.IcuZoneRulesProvider}.
+ *
+ * It is indirectly tested via static methods in {@link ZoneRulesProvider} as all the relevant
+ * methods are protected. This test verifies that the rules returned by that provider behave
+ * equivalently to the ICU rules from which they are created.
+ */
+@RunWith(Parameterized.class)
+public class IcuZoneRulesProviderTest {
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Iterable<String> getZoneIds() {
+ Set<String> availableZoneIds = ZoneRulesProvider.getAvailableZoneIds();
+ assertFalse("no zones returned", availableZoneIds.isEmpty());
+ return availableZoneIds;
+ }
+
+ private final String zoneId;
+
+ public IcuZoneRulesProviderTest(final String zoneId) {
+ this.zoneId = zoneId;
+ }
+
+ /**
+ * Verifies that ICU and java.time return the same transitions before and after a pre-selected
+ * set of instants in time.
+ */
+ @Test
+ public void testTransitionsNearInstants() {
+ // An arbitrary set of instants at which to test the offsets in both implementations.
+ Instant[] instants = new Instant[] {
+ LocalDateTime.of(1900, Month.DECEMBER, 24, 12, 0).toInstant(ZoneOffset.UTC),
+ LocalDateTime.of(1970, Month.JANUARY, 1, 2, 3).toInstant(ZoneOffset.UTC),
+ LocalDateTime.of(1980, Month.FEBRUARY, 4, 5, 6).toInstant(ZoneOffset.UTC),
+ LocalDateTime.of(1990, Month.MARCH, 7, 8, 9).toInstant(ZoneOffset.UTC),
+ LocalDateTime.of(2000, Month.APRIL, 10, 11, 12).toInstant(ZoneOffset.UTC),
+ LocalDateTime.of(2016, Month.MAY, 13, 14, 15).toInstant(ZoneOffset.UTC),
+ LocalDateTime.of(2020, Month.JUNE, 16, 17, 18).toInstant(ZoneOffset.UTC),
+ LocalDateTime.of(2100, Month.JULY, 19, 20, 21).toInstant(ZoneOffset.UTC),
+ // yes, adding "now" makes the test time-dependent, but it also ensures that future
+ // updates don't break on the then-current date.
+ Instant.now()
+ };
+ // Coincidentally this test verifies that all zones can be converted to ZoneRules and
+ // don't violate any of the assumptions of IcuZoneRulesProvider.
+ ZoneRules rules = ZoneRulesProvider.getRules(zoneId, false);
+ BasicTimeZone timeZone = (BasicTimeZone) TimeZone.getTimeZone(zoneId);
+
+ int[] icuOffsets = new int[2];
+ for (Instant instant : instants) {
+ ZoneOffset offset = rules.getOffset(instant);
+ Duration daylightSavings = rules.getDaylightSavings(instant);
+ timeZone.getOffset(instant.toEpochMilli(), false, icuOffsets);
+
+ assertEquals("total offset for " + zoneId + " at " + instant,
+ icuOffsets[1] + icuOffsets[0], offset.getTotalSeconds() * 1000);
+ assertEquals("dst offset for " + zoneId + " at " + instant,
+ icuOffsets[1], daylightSavings.toMillis());
+
+ ZoneOffsetTransition jtTrans;
+ TimeZoneTransition icuTrans;
+
+ jtTrans = rules.nextTransition(instant);
+ icuTrans = timeZone.getNextTransition(instant.toEpochMilli(), false);
+ while (isIcuOnlyTransition(icuTrans)) {
+ icuTrans = timeZone.getNextTransition(icuTrans.getTime(), false);
+ }
+ assertEquivalent(icuTrans, jtTrans);
+
+ jtTrans = rules.previousTransition(instant);
+ icuTrans = timeZone.getPreviousTransition(instant.toEpochMilli(), false);
+ // Find previous "real" transition.
+ while (isIcuOnlyTransition(icuTrans)) {
+ icuTrans = timeZone.getPreviousTransition(icuTrans.getTime(), false);
+ }
+ assertEquivalent(icuTrans, jtTrans);
+ }
+ }
+
+ /**
+ * Verifies that ICU and java.time rules return the same transitions between 1900 and 2100.
+ */
+ @Test
+ public void testAllTransitions() {
+ final Instant start = LocalDateTime.of(1900, Month.JANUARY, 1, 12, 0)
+ .toInstant(ZoneOffset.UTC);
+ // Many timezones have ongoing DST changes, so they would generate transitions endlessly.
+ // Pick a far-future end date to stop comparing in that case.
+ final Instant end = LocalDateTime.of(2100, Month.DECEMBER, 31, 12, 0)
+ .toInstant(ZoneOffset.UTC);
+
+ ZoneRules rules = ZoneRulesProvider.getRules(zoneId, false);
+ BasicTimeZone timeZone = (BasicTimeZone) TimeZone.getTimeZone(zoneId);
+
+ Instant instant = start;
+ while (instant.isBefore(end)) {
+ ZoneOffsetTransition jtTrans;
+ TimeZoneTransition icuTrans;
+
+ jtTrans = rules.nextTransition(instant);
+ icuTrans = timeZone.getNextTransition(instant.toEpochMilli(), false);
+ while (isIcuOnlyTransition(icuTrans)) {
+ icuTrans = timeZone.getNextTransition(icuTrans.getTime(), false);
+ }
+ assertEquivalent(icuTrans, jtTrans);
+ if (jtTrans == null) {
+ break;
+ }
+ instant = jtTrans.getInstant();
+ }
+ }
+
+ /**
+ * Returns {@code true} iff this transition will only be returned by ICU code.
+ * ICU reports "no-op" transitions where the raw offset and the dst savings
+ * change by the same absolute value in opposite directions, java.time doesn't
+ * return them, so find the next "real" transition.
+ */
+ private static boolean isIcuOnlyTransition(TimeZoneTransition transition) {
+ if (transition == null) {
+ return false;
+ }
+ return transition.getFrom().getRawOffset() + transition.getFrom().getDSTSavings()
+ == transition.getTo().getRawOffset() + transition.getTo().getDSTSavings();
+ }
+
+ /**
+ * Asserts that the ICU {@link TimeZoneTransition} is equivalent to the java.time {@link
+ * ZoneOffsetTransition}.
+ */
+ private static void assertEquivalent(
+ TimeZoneTransition icuTransition, ZoneOffsetTransition jtTransition) {
+ if (icuTransition == null) {
+ assertNull(jtTransition);
+ return;
+ }
+ assertEquals("time of transition",
+ Instant.ofEpochMilli(icuTransition.getTime()), jtTransition.getInstant());
+ TimeZoneRule from = icuTransition.getFrom();
+ TimeZoneRule to = icuTransition.getTo();
+ assertEquals("offset before",
+ (from.getDSTSavings() + from.getRawOffset()) / 1000,
+ jtTransition.getOffsetBefore().getTotalSeconds());
+ assertEquals("offset after",
+ (to.getDSTSavings() + to.getRawOffset()) / 1000,
+ jtTransition.getOffsetAfter().getTotalSeconds());
+ }
+}
diff --git a/ojluni/src/main/java/java/time/zone/IcuZoneRulesProvider.java b/ojluni/src/main/java/java/time/zone/IcuZoneRulesProvider.java
new file mode 100644
index 0000000..e329eaf
--- /dev/null
+++ b/ojluni/src/main/java/java/time/zone/IcuZoneRulesProvider.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package java.time.zone;
+
+import android.icu.impl.OlsonTimeZone;
+import android.icu.util.AnnualTimeZoneRule;
+import android.icu.util.DateTimeRule;
+import android.icu.util.InitialTimeZoneRule;
+import android.icu.util.TimeZone;
+import android.icu.util.TimeZoneRule;
+import android.icu.util.TimeZoneTransition;
+import java.time.DayOfWeek;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneOffset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.NavigableMap;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
+import libcore.util.BasicLruCache;
+
+/**
+ * A ZoneRulesProvider that generates rules from ICU4J TimeZones.
+ * This provider ensures that classes in {@link java.time} use the same time zone information
+ * as ICU4J.
+ */
+public class IcuZoneRulesProvider extends ZoneRulesProvider {
+
+ // Arbitrary upper limit to number of transitions including the final rules.
+ private static final int MAX_TRANSITIONS = 10000;
+
+ private static final int SECONDS_IN_DAY = 24 * 60 * 60;
+
+ private final BasicLruCache<String, ZoneRules> cache = new ZoneRulesCache(8);
+
+ @Override
+ protected Set<String> provideZoneIds() {
+ return new HashSet<>(Arrays.asList(TimeZone.getAvailableIDs()));
+ }
+
+ @Override
+ protected ZoneRules provideRules(String zoneId, boolean forCaching) {
+ // Ignore forCaching, as this is a static provider.
+ return cache.get(zoneId);
+ }
+
+ @Override
+ protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
+ return new TreeMap<>(
+ Collections.singletonMap(TimeZone.getTZDataVersion(),
+ provideRules(zoneId, /* forCaching */ false)));
+ }
+
+ /*
+ * This implementation is only tested with OlsonTimeZone objects and depends on
+ * implementation details of that class:
+ *
+ * 0. TimeZone.getFrozenTimeZone() always returns an OlsonTimeZone object.
+ * 1. The first rule is always an InitialTimeZoneRule (guaranteed by spec).
+ * 2. AnnualTimeZoneRules are only used as "final rules".
+ * 3. The final rules are either 0 or 2 AnnualTimeZoneRules
+ * 4. The final rules have endYear set to MAX_YEAR.
+ * 5. Each transition generated by the rules changes either the raw offset, the total offset
+ * or both.
+ * 6. There is a non-immense number of transitions for any rule before the final rules apply
+ * (enforced via the arbitrary limit defined in MAX_TRANSITIONS).
+ *
+ * Assumptions #5 and #6 are not strictly required for this code to work, but hold for the
+ * the data and code at the time of implementation. If they were broken they would indicate
+ * an incomplete understanding of how ICU TimeZoneRules are used which would probably mean that
+ * this code needs to be updated.
+ *
+ * These assumptions are verified using the verify() method where appropriate.
+ */
+ protected static ZoneRules generateZoneRules(String zoneId) {
+ TimeZone timeZone = TimeZone.getFrozenTimeZone(zoneId);
+ // Assumption #0
+ verify(timeZone instanceof OlsonTimeZone, zoneId,
+ "Unexpected time zone class " + timeZone.getClass());
+ OlsonTimeZone tz = (OlsonTimeZone) timeZone;
+ TimeZoneRule[] rules = tz.getTimeZoneRules();
+ // Assumption #1
+ InitialTimeZoneRule initial = (InitialTimeZoneRule) rules[0];
+
+ ZoneOffset baseStandardOffset = millisToOffset(initial.getRawOffset());
+ ZoneOffset baseWallOffset =
+ millisToOffset((initial.getRawOffset() + initial.getDSTSavings()));
+
+ List<ZoneOffsetTransition> standardOffsetTransitionList = new ArrayList<>();
+ List<ZoneOffsetTransition> transitionList = new ArrayList<>();
+ List<ZoneOffsetTransitionRule> lastRules = new ArrayList<>();
+
+ int preLastDstSavings = 0;
+ AnnualTimeZoneRule last1 = null;
+ AnnualTimeZoneRule last2 = null;
+
+ TimeZoneTransition transition = tz.getNextTransition(Long.MIN_VALUE, false);
+ int transitionCount = 1;
+ // This loop has two possible exit conditions (in normal operation):
+ // 1. for zones that end with a static value and have no ongoing DST changes, it will exit
+ // via the normal condition (transition != null)
+ // 2. for zones with ongoing DST changes (represented by a "final zone" in ICU4J, and by
+ // "last rules" in java.time) the "break transitionLoop" will be used to exit the loop.
+ transitionLoop:
+ while (transition != null) {
+ TimeZoneRule from = transition.getFrom();
+ TimeZoneRule to = transition.getTo();
+ boolean hadEffect = false;
+ if (from.getRawOffset() != to.getRawOffset()) {
+ standardOffsetTransitionList.add(new ZoneOffsetTransition(
+ TimeUnit.MILLISECONDS.toSeconds(transition.getTime()),
+ millisToOffset(from.getRawOffset()),
+ millisToOffset(to.getRawOffset())));
+ hadEffect = true;
+ }
+ int fromTotalOffset = from.getRawOffset() + from.getDSTSavings();
+ int toTotalOffset = to.getRawOffset() + to.getDSTSavings();
+ if (fromTotalOffset != toTotalOffset) {
+ transitionList.add(new ZoneOffsetTransition(
+ TimeUnit.MILLISECONDS.toSeconds(transition.getTime()),
+ millisToOffset(fromTotalOffset),
+ millisToOffset(toTotalOffset)));
+ hadEffect = true;
+ }
+ // Assumption #5
+ verify(hadEffect, zoneId, "Transition changed neither total nor raw offset.");
+ if (to instanceof AnnualTimeZoneRule) {
+ // The presence of an AnnualTimeZoneRule is taken as an indication of a final rule.
+ if (last1 == null) {
+ preLastDstSavings = from.getDSTSavings();
+ last1 = (AnnualTimeZoneRule) to;
+ // Assumption #4
+ verify(last1.getEndYear() == AnnualTimeZoneRule.MAX_YEAR, zoneId,
+ "AnnualTimeZoneRule is not permanent.");
+ } else {
+ last2 = (AnnualTimeZoneRule) to;
+ // Assumption #4
+ verify(last2.getEndYear() == AnnualTimeZoneRule.MAX_YEAR, zoneId,
+ "AnnualTimeZoneRule is not permanent.");
+
+ // Assumption #3
+ transition = tz.getNextTransition(transition.getTime(), false);
+ verify(transition.getTo() == last1, zoneId,
+ "Unexpected rule after 2 AnnualTimeZoneRules.");
+ break transitionLoop;
+ }
+ } else {
+ // Assumption #2
+ verify(last1 == null, zoneId, "Unexpected rule after AnnualTimeZoneRule.");
+ }
+ verify(transitionCount <= MAX_TRANSITIONS, zoneId,
+ "More than " + MAX_TRANSITIONS + " transitions.");
+ transition = tz.getNextTransition(transition.getTime(), false);
+ transitionCount++;
+ }
+ if (last1 != null) {
+ // Assumption #3
+ verify(last2 != null, zoneId, "Only one AnnualTimeZoneRule.");
+ lastRules.add(toZoneOffsetTransitionRule(last1, preLastDstSavings));
+ lastRules.add(toZoneOffsetTransitionRule(last2, last1.getDSTSavings()));
+ }
+
+ return ZoneRules.of(baseStandardOffset, baseWallOffset, standardOffsetTransitionList,
+ transitionList, lastRules);
+ }
+
+ /**
+ * Verify an assumption about the zone rules.
+ *
+ * @param check
+ * {@code true} if the assumption holds, {@code false} otherwise.
+ * @param zoneId
+ * Zone ID for which to check.
+ * @param message
+ * Error description of a failed check.
+ * @throws ZoneRulesException
+ * If and only if {@code check} is {@code false}.
+ */
+ private static void verify(boolean check, String zoneId, String message) {
+ if (!check) {
+ throw new ZoneRulesException(
+ String.format("Failed verification of zone %s: %s", zoneId, message));
+ }
+ }
+
+ /**
+ * Transform an {@link AnnualTimeZoneRule} into an equivalent {@link ZoneOffsetTransitionRule}.
+ * This is only used for the "final rules".
+ *
+ * @param rule
+ * The rule to transform.
+ * @param dstSavingMillisBefore
+ * The DST offset before the first transition in milliseconds.
+ */
+ private static ZoneOffsetTransitionRule toZoneOffsetTransitionRule(
+ AnnualTimeZoneRule rule, int dstSavingMillisBefore) {
+ DateTimeRule dateTimeRule = rule.getRule();
+ // Calendar.JANUARY is 0, transform it into a proper Month.
+ Month month = Month.JANUARY.plus(dateTimeRule.getRuleMonth());
+ int dayOfMonthIndicator;
+ // Calendar.SUNDAY is 1, transform it into a proper DayOfWeek.
+ DayOfWeek dayOfWeek = DayOfWeek.SATURDAY.plus(dateTimeRule.getRuleDayOfWeek());
+ switch (dateTimeRule.getDateRuleType()) {
+ case DateTimeRule.DOM:
+ // Transition always on a specific day of the month.
+ dayOfMonthIndicator = dateTimeRule.getRuleDayOfMonth();
+ dayOfWeek = null;
+ break;
+ case DateTimeRule.DOW_GEQ_DOM:
+ // ICU representation matches java.time representation.
+ dayOfMonthIndicator = dateTimeRule.getRuleDayOfMonth();
+ break;
+ case DateTimeRule.DOW_LEQ_DOM:
+ // java.time uses a negative dayOfMonthIndicator to represent "Sun<=X" or "lastSun"
+ // rules. ICU uses this constant and the normal day. So "lastSun" in January would
+ // ruleDayOfMonth = 31 in ICU and dayOfMonthIndicator = -1 in java.time.
+ dayOfMonthIndicator = -month.maxLength() + dateTimeRule.getRuleDayOfMonth() - 1;
+ break;
+ case DateTimeRule.DOW:
+ // DOW is unspecified in the documentation and seems to never be used.
+ throw new ZoneRulesException("Date rule type DOW is unsupported");
+ default:
+ throw new ZoneRulesException(
+ "Unexpected date rule type: " + dateTimeRule.getDateRuleType());
+ }
+ // Cast to int is save, as input is int.
+ int secondOfDay = (int) TimeUnit.MILLISECONDS.toSeconds(dateTimeRule.getRuleMillisInDay());
+ LocalTime time;
+ boolean timeEndOfDay;
+ if (secondOfDay == SECONDS_IN_DAY) {
+ time = LocalTime.MIDNIGHT;
+ timeEndOfDay = true;
+ } else {
+ time = LocalTime.ofSecondOfDay(secondOfDay);
+ timeEndOfDay = false;
+ }
+ ZoneOffsetTransitionRule.TimeDefinition timeDefinition;
+ switch (dateTimeRule.getTimeRuleType()) {
+ case DateTimeRule.WALL_TIME:
+ timeDefinition = ZoneOffsetTransitionRule.TimeDefinition.WALL;
+ break;
+ case DateTimeRule.STANDARD_TIME:
+ timeDefinition = ZoneOffsetTransitionRule.TimeDefinition.STANDARD;
+ break;
+ case DateTimeRule.UTC_TIME:
+ timeDefinition = ZoneOffsetTransitionRule.TimeDefinition.UTC;
+ break;
+ default:
+ throw new ZoneRulesException(
+ "Unexpected time rule type " + dateTimeRule.getTimeRuleType());
+ }
+ ZoneOffset standardOffset = millisToOffset(rule.getRawOffset());
+ ZoneOffset offsetBefore = millisToOffset(rule.getRawOffset() + dstSavingMillisBefore);
+ ZoneOffset offsetAfter = millisToOffset(
+ rule.getRawOffset() + rule.getDSTSavings());
+ return ZoneOffsetTransitionRule.of(
+ month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition,
+ standardOffset, offsetBefore, offsetAfter);
+ }
+
+ private static ZoneOffset millisToOffset(int offset) {
+ // Cast to int is save, as input is int.
+ return ZoneOffset.ofTotalSeconds((int) TimeUnit.MILLISECONDS.toSeconds(offset));
+ }
+
+ private static class ZoneRulesCache extends BasicLruCache<String, ZoneRules> {
+
+ ZoneRulesCache(int maxSize) {
+ super(maxSize);
+ }
+
+ @Override
+ protected ZoneRules create(String zoneId) {
+ String canonicalId = TimeZone.getCanonicalID(zoneId);
+ if (!canonicalId.equals(zoneId)) {
+ // Return the same object as the canonical one, to avoid wasting space, but cache
+ // it under the non-cannonical name as well, to avoid future getCanonicalID calls.
+ return get(canonicalId);
+ }
+ return generateZoneRules(zoneId);
+ }
+ }
+}
diff --git a/ojluni/src/main/java/java/time/zone/TzdbZoneRulesProvider.java b/ojluni/src/main/java/java/time/zone/TzdbZoneRulesProvider.java
deleted file mode 100644
index 6a9d012..0000000
--- a/ojluni/src/main/java/java/time/zone/TzdbZoneRulesProvider.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of JSR-310 nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package java.time.zone;
-
-import java.io.ByteArrayInputStream;
-import java.io.BufferedInputStream;
-import java.io.DataInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.StreamCorruptedException;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.NavigableMap;
-import java.util.Objects;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Loads time-zone rules for 'TZDB'.
- *
- * @since 1.8
- */
-final class TzdbZoneRulesProvider extends ZoneRulesProvider {
-
- /**
- * All the regions that are available.
- */
- private List<String> regionIds;
- /**
- * Version Id of this tzdb rules
- */
- private String versionId;
- /**
- * Region to rules mapping
- */
- private final Map<String, Object> regionToRules = new ConcurrentHashMap<>();
-
- /**
- * Creates an instance.
- * Created by the {@code ServiceLoader}.
- *
- * @throws ZoneRulesException if unable to load
- */
- public TzdbZoneRulesProvider() {
- try {
- String libDir = System.getProperty("java.home") + File.separator + "lib";
- try (DataInputStream dis = new DataInputStream(
- new BufferedInputStream(new FileInputStream(
- new File(libDir, "tzdb.dat"))))) {
- load(dis);
- }
- } catch (Exception ex) {
- throw new ZoneRulesException("Unable to load TZDB time-zone rules", ex);
- }
- }
-
- @Override
- protected Set<String> provideZoneIds() {
- return new HashSet<>(regionIds);
- }
-
- @Override
- protected ZoneRules provideRules(String zoneId, boolean forCaching) {
- // forCaching flag is ignored because this is not a dynamic provider
- Object obj = regionToRules.get(zoneId);
- if (obj == null) {
- throw new ZoneRulesException("Unknown time-zone ID: " + zoneId);
- }
- try {
- if (obj instanceof byte[]) {
- byte[] bytes = (byte[]) obj;
- DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bytes));
- obj = Ser.read(dis);
- regionToRules.put(zoneId, obj);
- }
- return (ZoneRules) obj;
- } catch (Exception ex) {
- throw new ZoneRulesException("Invalid binary time-zone data: TZDB:" + zoneId + ", version: " + versionId, ex);
- }
- }
-
- @Override
- protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
- TreeMap<String, ZoneRules> map = new TreeMap<>();
- ZoneRules rules = getRules(zoneId, false);
- if (rules != null) {
- map.put(versionId, rules);
- }
- return map;
- }
-
- /**
- * Loads the rules from a DateInputStream, often in a jar file.
- *
- * @param dis the DateInputStream to load, not null
- * @throws Exception if an error occurs
- */
- private void load(DataInputStream dis) throws Exception {
- if (dis.readByte() != 1) {
- throw new StreamCorruptedException("File format not recognised");
- }
- // group
- String groupId = dis.readUTF();
- if ("TZDB".equals(groupId) == false) {
- throw new StreamCorruptedException("File format not recognised");
- }
- // versions
- int versionCount = dis.readShort();
- for (int i = 0; i < versionCount; i++) {
- versionId = dis.readUTF();
- }
- // regions
- int regionCount = dis.readShort();
- String[] regionArray = new String[regionCount];
- for (int i = 0; i < regionCount; i++) {
- regionArray[i] = dis.readUTF();
- }
- regionIds = Arrays.asList(regionArray);
- // rules
- int ruleCount = dis.readShort();
- Object[] ruleArray = new Object[ruleCount];
- for (int i = 0; i < ruleCount; i++) {
- byte[] bytes = new byte[dis.readShort()];
- dis.readFully(bytes);
- ruleArray[i] = bytes;
- }
- // link version-region-rules
- for (int i = 0; i < versionCount; i++) {
- int versionRegionCount = dis.readShort();
- regionToRules.clear();
- for (int j = 0; j < versionRegionCount; j++) {
- String region = regionArray[dis.readShort()];
- Object rule = ruleArray[dis.readShort() & 0xffff];
- regionToRules.put(region, rule);
- }
- }
- }
-
- @Override
- public String toString() {
- return "TZDB[" + versionId + "]";
- }
-}
diff --git a/ojluni/src/main/java/java/time/zone/ZoneRules.java b/ojluni/src/main/java/java/time/zone/ZoneRules.java
index 4719098..924f351 100644
--- a/ojluni/src/main/java/java/time/zone/ZoneRules.java
+++ b/ojluni/src/main/java/java/time/zone/ZoneRules.java
@@ -82,6 +82,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+// Android changed: remove mention of ZoneRulesProvider.
/**
* The rules defining how the zone offset varies for a single time-zone.
* <p>
@@ -90,7 +91,6 @@
* {@link ZoneOffsetTransitionRule} is used for future transitions that are based
* on the result of an algorithm.
* <p>
- * The rules are loaded via {@link ZoneRulesProvider} using a {@link ZoneId}.
* The same rules may be shared internally between multiple zone IDs.
* <p>
* Serializing an instance of {@code ZoneRules} will store the entire set of rules.
diff --git a/ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java b/ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java
index 9523664..9ef9f1a 100644
--- a/ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java
+++ b/ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java
@@ -138,53 +138,9 @@
private static final ConcurrentMap<String, ZoneRulesProvider> ZONES = new ConcurrentHashMap<>(512, 0.75f, 2);
static {
- // if the property java.time.zone.DefaultZoneRulesProvider is
- // set then its value is the class name of the default provider
- final List<ZoneRulesProvider> loaded = new ArrayList<>();
- AccessController.doPrivileged(new PrivilegedAction<Object>() {
- public Object run() {
- String prop = System.getProperty("java.time.zone.DefaultZoneRulesProvider");
- if (prop != null) {
- try {
- Class<?> c = Class.forName(prop, true, ClassLoader.getSystemClassLoader());
- ZoneRulesProvider provider = ZoneRulesProvider.class.cast(c.newInstance());
- registerProvider(provider);
- loaded.add(provider);
- } catch (Exception x) {
- throw new Error(x);
- }
- } else {
- registerProvider(new TzdbZoneRulesProvider());
- }
- return null;
- }
- });
-
- ServiceLoader<ZoneRulesProvider> sl = ServiceLoader.load(ZoneRulesProvider.class, ClassLoader.getSystemClassLoader());
- Iterator<ZoneRulesProvider> it = sl.iterator();
- while (it.hasNext()) {
- ZoneRulesProvider provider;
- try {
- provider = it.next();
- } catch (ServiceConfigurationError ex) {
- if (ex.getCause() instanceof SecurityException) {
- continue; // ignore the security exception, try the next provider
- }
- throw ex;
- }
- boolean found = false;
- for (ZoneRulesProvider p : loaded) {
- if (p.getClass() == provider.getClass()) {
- found = true;
- }
- }
- if (!found) {
- registerProvider0(provider);
- loaded.add(provider);
- }
- }
- // CopyOnWriteList could be slow if lots of providers and each added individually
- PROVIDERS.addAll(loaded);
+ // Android changed: use a single hard-coded provider.
+ ZoneRulesProvider provider = new IcuZoneRulesProvider();
+ registerProvider(provider);
}
//-------------------------------------------------------------------------
diff --git a/ojluni/src/test/artrun b/ojluni/src/test/artrun
index 3037adb..e9afd78 100755
--- a/ojluni/src/test/artrun
+++ b/ojluni/src/test/artrun
@@ -100,7 +100,6 @@
apache-xml-hostdex.jar
core-tests-hostdex.jar
core-libart-hostdex.jar
-core-lambda-stubs-hostdex.jar
conscrypt-hostdex.jar
core-ojtests-hostdex.jar # This is the *one* addition that makes our OJ tests actually run. The rest of these are standard jars on the bootclasspath.
core-oj-hostdex.jar
@@ -137,5 +136,3 @@
$DEBUG_OPTION \
"$@"
-
-temp_dir="$(mktemp -q -d -t "$(basename "$0").XXXXXX")"
diff --git a/ojluni/src/test/artrun-testng b/ojluni/src/test/artrun-testng
index f5aa95d..f6a7b71 100755
--- a/ojluni/src/test/artrun-testng
+++ b/ojluni/src/test/artrun-testng
@@ -16,4 +16,6 @@
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-$DIR/artrun -Xmx512m org.testng.TestNG -verbose 3 "$DIR/testng.xml"
+TESTNG_FILE=${1-testng.xml}
+
+$DIR/artrun -Xmx512m org.testng.TestNG -verbose 3 "$DIR/$TESTNG_FILE"
diff --git a/ojluni/src/test/testng-time.xml b/ojluni/src/test/testng-time.xml
new file mode 100644
index 0000000..c6cf3fd
--- /dev/null
+++ b/ojluni/src/test/testng-time.xml
@@ -0,0 +1,174 @@
+<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
+
+<suite name="OpenJDK8 test suite" verbose="1" allow-return-values="true" >
+ <test name="java.time test">
+ <classes>
+ <class name="tck.java.time.AbstractDateTimeTest" />
+ <class name="tck.java.time.AbstractTCKTest" />
+ <class name="tck.java.time.chrono.CopticChronology" />
+ <class name="tck.java.time.chrono.CopticDate" />
+ <class name="tck.java.time.chrono.CopticEra" />
+ <class name="tck.java.time.chrono.serial.TCKChronoLocalDateSerialization" />
+ <class name="tck.java.time.chrono.serial.TCKChronoLocalDateTimeSerialization" />
+ <class name="tck.java.time.chrono.serial.TCKChronologySerialization" />
+ <class name="tck.java.time.chrono.serial.TCKChronoZonedDateTimeSerialization" />
+ <class name="tck.java.time.chrono.serial.TCKCopticSerialization" />
+ <class name="tck.java.time.chrono.serial.TCKEraSerialization" />
+ <class name="tck.java.time.chrono.TCKChronoLocalDate" />
+ <class name="tck.java.time.chrono.TCKChronoLocalDateTime" />
+ <class name="tck.java.time.chrono.TCKChronology" />
+ <class name="tck.java.time.chrono.TCKChronoPeriod" />
+ <class name="tck.java.time.chrono.TCKChronoZonedDateTime" />
+ <class name="tck.java.time.chrono.TCKHijrahChronology" />
+ <class name="tck.java.time.chrono.TCKHijrahEra" />
+ <class name="tck.java.time.chrono.TCKIsoChronology" />
+ <class name="tck.java.time.chrono.TCKIsoEra" />
+ <class name="tck.java.time.chrono.TCKJapaneseChronology" />
+ <class name="tck.java.time.chrono.TCKJapaneseEra" />
+ <class name="tck.java.time.chrono.TCKMinguoChronology" />
+ <class name="tck.java.time.chrono.TCKMinguoEra" />
+ <class name="tck.java.time.chrono.TCKTestServiceLoader" />
+ <class name="tck.java.time.chrono.TCKThaiBuddhistChronology" />
+ <class name="tck.java.time.chrono.TCKThaiBuddhistEra" />
+ <class name="tck.java.time.format.TCKChronoPrinterParser" />
+ <class name="tck.java.time.format.TCKDateTimeFormatter" />
+ <class name="tck.java.time.format.TCKDateTimeFormatterBuilder" />
+ <class name="tck.java.time.format.TCKDateTimeFormatters" />
+ <class name="tck.java.time.format.TCKDateTimeParseResolver" />
+ <class name="tck.java.time.format.TCKDateTimeTextPrinting" />
+ <class name="tck.java.time.format.TCKFormatStyle" />
+ <class name="tck.java.time.format.TCKInstantPrinterParser" />
+ <class name="tck.java.time.format.TCKLocalizedFieldParser" />
+ <class name="tck.java.time.format.TCKLocalizedFieldPrinter" />
+ <class name="tck.java.time.format.TCKLocalizedPrinterParser" />
+ <class name="tck.java.time.format.TCKOffsetPrinterParser" />
+ <class name="tck.java.time.format.TCKPadPrinterParser" />
+ <class name="tck.java.time.format.TCKResolverStyle" />
+ <class name="tck.java.time.format.TCKSignStyle" />
+ <class name="tck.java.time.format.TCKTextStyle" />
+ <class name="tck.java.time.format.TCKZoneIdPrinterParser" />
+ <class name="tck.java.time.MockSimplePeriod" />
+ <class name="tck.java.time.serial.TCKClockSerialization" />
+ <class name="tck.java.time.serial.TCKDurationSerialization" />
+ <class name="tck.java.time.serial.TCKInstantSerialization" />
+ <class name="tck.java.time.serial.TCKLocalDateSerialization" />
+ <class name="tck.java.time.serial.TCKLocalDateTimeSerialization" />
+ <class name="tck.java.time.serial.TCKLocalTimeSerialization" />
+ <class name="tck.java.time.serial.TCKMonthDaySerialization" />
+ <class name="tck.java.time.serial.TCKOffsetDateTimeSerialization" />
+ <class name="tck.java.time.serial.TCKOffsetTimeSerialization" />
+ <class name="tck.java.time.serial.TCKPeriodSerialization" />
+ <class name="tck.java.time.serial.TCKYearMonthSerialization" />
+ <class name="tck.java.time.serial.TCKYearSerialization" />
+ <class name="tck.java.time.serial.TCKZonedDateTimeSerialization" />
+ <class name="tck.java.time.serial.TCKZoneIdSerialization" />
+ <class name="tck.java.time.serial.TCKZoneOffsetSerialization" />
+ <class name="tck.java.time.TCKClock" />
+ <class name="tck.java.time.TCKClock_Fixed" />
+ <class name="tck.java.time.TCKClock_Offset" />
+ <class name="tck.java.time.TCKClock_System" />
+ <class name="tck.java.time.TCKClock_Tick" />
+ <class name="tck.java.time.TCKDayOfWeek" />
+ <class name="tck.java.time.TCKDuration" />
+ <class name="tck.java.time.TCKInstant" />
+ <class name="tck.java.time.TCKLocalDate" />
+ <class name="tck.java.time.TCKLocalDateTime" />
+ <class name="tck.java.time.TCKLocalTime" />
+ <class name="tck.java.time.TCKMonth" />
+ <class name="tck.java.time.TCKMonthDay" />
+ <class name="tck.java.time.TCKOffsetDateTime" />
+ <class name="tck.java.time.TCKOffsetTime" />
+ <class name="tck.java.time.TCKPeriod" />
+ <class name="tck.java.time.TCKYear" />
+ <class name="tck.java.time.TCKYearMonth" />
+ <class name="tck.java.time.TCKZonedDateTime" />
+ <class name="tck.java.time.TCKZoneId" />
+ <class name="tck.java.time.TCKZoneOffset" />
+ <class name="tck.java.time.temporal.serial.TCKChronoFieldSerialization" />
+ <class name="tck.java.time.temporal.serial.TCKChronoUnitSerialization" />
+ <class name="tck.java.time.temporal.serial.TCKJulianFieldsSerialization" />
+ <class name="tck.java.time.temporal.serial.TCKValueRangeSerialization" />
+ <class name="tck.java.time.temporal.serial.TCKWeekFieldsSerialization" />
+ <class name="tck.java.time.temporal.TCKChronoField" />
+ <class name="tck.java.time.temporal.TCKChronoUnit" />
+ <class name="tck.java.time.temporal.TCKIsoFields" />
+ <class name="tck.java.time.temporal.TCKJulianFields" />
+ <class name="tck.java.time.temporal.TCKTemporalAdjusters" />
+ <class name="tck.java.time.temporal.TCKWeekFields" />
+ <class name="tck.java.time.TestIsoChronology" />
+ <class name="tck.java.time.zone.serial.TCKFixedZoneRulesSerialization" />
+ <class name="tck.java.time.zone.serial.TCKZoneOffsetTransitionRuleSerialization" />
+ <class name="tck.java.time.zone.serial.TCKZoneOffsetTransitionSerialization" />
+ <class name="tck.java.time.zone.serial.TCKZoneRulesSerialization" />
+ <class name="tck.java.time.zone.TCKFixedZoneRules" />
+ <class name="tck.java.time.zone.TCKZoneOffsetTransition" />
+ <class name="tck.java.time.zone.TCKZoneOffsetTransitionRule" />
+ <class name="tck.java.time.zone.TCKZoneRules" />
+ <class name="tck.java.time.zone.TCKZoneRulesProvider" />
+ <class name="test.java.time.AbstractTest" />
+ <class name="test.java.time.chrono.TestChronoLocalDate" />
+ <class name="test.java.time.chrono.TestChronologyPerf" />
+ <class name="test.java.time.chrono.TestIsoChronoImpl" />
+ <class name="test.java.time.chrono.TestJapaneseChronoImpl" />
+ <class name="test.java.time.chrono.TestJapaneseChronology" />
+ <class name="test.java.time.chrono.TestServiceLoader" />
+ <class name="test.java.time.chrono.TestThaiBuddhistChronoImpl" />
+ <class name="test.java.time.chrono.TestUmmAlQuraChronology" />
+ <class name="test.java.time.format.AbstractTestPrinterParser" />
+ <class name="test.java.time.format.MockIOExceptionAppendable" />
+ <class name="test.java.time.format.TestCharLiteralParser" />
+ <class name="test.java.time.format.TestCharLiteralPrinter" />
+ <class name="test.java.time.format.TestDateTimeFormatter" />
+ <class name="test.java.time.format.TestDateTimeFormatterBuilder" />
+ <class name="test.java.time.format.TestDateTimeParsing" />
+ <class name="test.java.time.format.TestDateTimeTextProvider" />
+ <class name="test.java.time.format.TestDecimalStyle" />
+ <class name="test.java.time.format.TestFractionPrinterParser" />
+ <class name="test.java.time.format.TestNonIsoFormatter" />
+ <class name="test.java.time.format.TestNumberParser" />
+ <class name="test.java.time.format.TestNumberPrinter" />
+ <class name="test.java.time.format.TestPadPrinterDecorator" />
+ <class name="test.java.time.format.TestReducedParser" />
+ <class name="test.java.time.format.TestReducedPrinter" />
+ <class name="test.java.time.format.TestSettingsParser" />
+ <class name="test.java.time.format.TestStringLiteralParser" />
+ <class name="test.java.time.format.TestStringLiteralPrinter" />
+ <class name="test.java.time.format.TestTextParser" />
+ <class name="test.java.time.format.TestTextPrinter" />
+ <class name="test.java.time.format.TestZoneOffsetParser" />
+ <class name="test.java.time.format.TestZoneOffsetPrinter" />
+ <class name="test.java.time.format.TestZoneTextPrinterParser" />
+ <class name="test.java.time.format.ZoneName" />
+ <class name="test.java.time.MockSimplePeriod" />
+ <class name="test.java.time.temporal.MockFieldNoValue" />
+ <class name="test.java.time.temporal.MockFieldValue" />
+ <class name="test.java.time.temporal.TestChronoField" />
+ <class name="test.java.time.temporal.TestChronoUnit" />
+ <class name="test.java.time.temporal.TestDateTimeBuilderCombinations" />
+ <class name="test.java.time.temporal.TestDateTimeValueRange" />
+ <class name="test.java.time.temporal.TestIsoWeekFields" />
+ <class name="test.java.time.temporal.TestJulianFields" />
+ <class name="test.java.time.TestClock_Fixed" />
+ <class name="test.java.time.TestClock_Offset" />
+ <class name="test.java.time.TestClock_System" />
+ <class name="test.java.time.TestClock_Tick" />
+ <class name="test.java.time.TestDuration" />
+ <class name="test.java.time.TestInstant" />
+ <class name="test.java.time.TestLocalDate" />
+ <class name="test.java.time.TestLocalDateTime" />
+ <class name="test.java.time.TestLocalTime" />
+ <class name="test.java.time.TestMonthDay" />
+ <class name="test.java.time.TestOffsetDateTime" />
+ <class name="test.java.time.TestOffsetDateTime_instants" />
+ <class name="test.java.time.TestOffsetTime" />
+ <class name="test.java.time.TestPeriod" />
+ <class name="test.java.time.TestYear" />
+ <class name="test.java.time.TestYearMonth" />
+ <class name="test.java.time.TestZonedDateTime" />
+ <class name="test.java.time.TestZoneId" />
+ <class name="test.java.time.TestZoneOffset" />
+ <class name="test.java.time.zone.TestFixedZoneRules" />
+ </classes>
+ </test>
+
+</suite>
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index 82a1c15..c38f3ed 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -812,11 +812,9 @@
ojluni/src/main/java/java/time/zone/Ser.java \
ojluni/src/main/java/java/time/zone/ZoneOffsetTransition.java \
ojluni/src/main/java/java/time/zone/ZoneRulesException.java \
- ojluni/src/main/java/java/time/zone/TzdbZoneRulesProvider.java \
ojluni/src/main/java/java/time/zone/ZoneOffsetTransitionRule.java \
ojluni/src/main/java/java/time/zone/ZoneRules.java \
ojluni/src/main/java/java/time/zone/package-info.java \
- ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java \
ojluni/src/main/java/java/time/OffsetTime.java \
ojluni/src/main/java/java/time/Year.java \
ojluni/src/main/java/java/time/Clock.java \
@@ -1339,6 +1337,8 @@
ojluni/src/main/java/com/sun/nio/file/ExtendedWatchEventModifier.java \
ojluni/src/main/java/com/sun/nio/file/SensitivityWatchEventModifier.java \
ojluni/src/main/java/java/beans/ChangeListenerMap.java \
+ ojluni/src/main/java/java/time/zone/IcuZoneRulesProvider.java \
+ ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java \
ojluni/src/main/java/sun/misc/FDBigInteger.java \
ojluni/src/main/java/sun/misc/FloatingDecimal.java \
ojluni/src/main/java/java/lang/invoke/LambdaConversionException.java \