Mercurial > hg > openjdk > jigsaw > jdk
changeset 7343:6f80a6584fb9
Merge
author | vinnie |
---|---|
date | Tue, 16 Apr 2013 01:44:58 -0700 |
parents | 5435f112e5ea (current diff) baaa706d7677 (diff) |
children | 29cbb4617c92 |
files | test/java/util/ComparatorsTest.java |
diffstat | 28 files changed, 1555 insertions(+), 726 deletions(-) [+] |
line wrap: on
line diff
--- a/make/java/java/mapfile-vers Fri Apr 12 10:42:50 2013 -0700 +++ b/make/java/java/mapfile-vers Tue Apr 16 01:44:58 2013 -0700 @@ -217,7 +217,7 @@ 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;
--- a/makefiles/mapfiles/libjava/mapfile-vers Fri Apr 12 10:42:50 2013 -0700 +++ b/makefiles/mapfiles/libjava/mapfile-vers Tue Apr 16 01:44:58 2013 -0700 @@ -217,7 +217,7 @@ 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;
--- a/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Fri Apr 12 10:42:50 2013 -0700 +++ b/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Tue Apr 16 01:44:58 2013 -0700 @@ -184,7 +184,7 @@ for (int i=0; i<markerInterfaces.length; i++) { interfaces[i+1] = markerInterfaces[i].getName().replace('.', '/'); } - cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL, + cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC, lambdaClassName, null, NAME_MAGIC_ACCESSOR_IMPL, interfaces);
--- a/src/share/classes/java/nio/file/attribute/FileTime.java Fri Apr 12 10:42:50 2013 -0700 +++ b/src/share/classes/java/nio/file/attribute/FileTime.java Tue Apr 16 01:44:58 2013 -0700 @@ -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; /** @@ -51,14 +49,22 @@ 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) @@ -66,27 +72,12 @@ 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 @@ * @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 @@ * @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 @@ * 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 @@ * @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 @@ */ @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 @@ @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 @@ */ @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; + sb.append('Z'); + valueAsString = sb.toString(); } - 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; - } + return valueAsString; } }
--- a/src/share/classes/java/util/ArrayList.java Fri Apr 12 10:42:50 2013 -0700 +++ b/src/share/classes/java/util/ArrayList.java Tue Apr 16 01:44:58 2013 -0700 @@ -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 @@ -105,8 +105,20 @@ private static final long serialVersionUID = 8683452581122892189L; /** + * Default initial capacity. + */ + private static final int DEFAULT_CAPACITY = 10; + + /** + * Shared empty array instance used for empty instances. + */ + private static final Object[] EMPTY_ELEMENTDATA = {}; + + /** * The array buffer into which the elements of the ArrayList are stored. - * The capacity of the ArrayList is the length of this array buffer. + * The capacity of the ArrayList is the length of this array buffer. Any + * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to + * DEFAULT_CAPACITY when the first element is added. */ private transient Object[] elementData; @@ -136,7 +148,8 @@ * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { - this(10); + super(); + this.elementData = EMPTY_ELEMENTDATA; } /** @@ -162,8 +175,7 @@ */ public void trimToSize() { modCount++; - int oldCapacity = elementData.length; - if (size < oldCapacity) { + if (size < elementData.length) { elementData = Arrays.copyOf(elementData, size); } } @@ -176,12 +188,29 @@ * @param minCapacity the desired minimum capacity */ public void ensureCapacity(int minCapacity) { - if (minCapacity > 0) - ensureCapacityInternal(minCapacity); + int minExpand = (elementData != EMPTY_ELEMENTDATA) + // any size if real element table + ? 0 + // larger than default for empty table. It's already supposed to be + // at default size. + : DEFAULT_CAPACITY; + + if (minCapacity > minExpand) { + ensureExplicitCapacity(minCapacity); + } } private void ensureCapacityInternal(int minCapacity) { + if (elementData == EMPTY_ELEMENTDATA) { + minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); + } + + ensureExplicitCapacity(minCapacity); + } + + private void ensureExplicitCapacity(int minCapacity) { modCount++; + // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); @@ -450,7 +479,7 @@ if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); - elementData[--size] = null; // Let gc do its work + elementData[--size] = null; // clear to let GC do its work return oldValue; } @@ -495,7 +524,7 @@ if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); - elementData[--size] = null; // Let gc do its work + elementData[--size] = null; // clear to let GC do its work } /** @@ -505,7 +534,7 @@ public void clear() { modCount++; - // Let gc do its work + // clear to let GC do its work for (int i = 0; i < size; i++) elementData[i] = null; @@ -586,10 +615,12 @@ System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved); - // Let gc do its work + // clear to let GC do its work int newSize = size - (toIndex-fromIndex); - while (size != newSize) - elementData[--size] = null; + for (int i = newSize; i < size; i++) { + elementData[i] = null; + } + size = newSize; } /** @@ -677,6 +708,7 @@ w += size - r; } if (w != size) { + // clear to let GC do its work for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; @@ -701,17 +733,17 @@ int expectedModCount = modCount; s.defaultWriteObject(); - // Write out array length - s.writeInt(elementData.length); + // Write out size as capacity for behavioural compatibility with clone() + s.writeInt(size); // Write out all elements in the proper order. - for (int i=0; i<size; i++) + for (int i=0; i<size; i++) { s.writeObject(elementData[i]); + } if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } - } /** @@ -720,16 +752,24 @@ */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + elementData = EMPTY_ELEMENTDATA; + // Read in size, and any hidden stuff s.defaultReadObject(); - // Read in array length and allocate array - int arrayLength = s.readInt(); - Object[] a = elementData = new Object[arrayLength]; + // Read in capacity + s.readInt(); // ignored + + if (size > 0) { + // be like clone(), allocate array based upon size not capacity + ensureCapacityInternal(size); - // Read in all elements in the proper order. - for (int i=0; i<size; i++) - a[i] = s.readObject(); + Object[] a = elementData; + // Read in all elements in the proper order. + for (int i=0; i<size; i++) { + a[i] = s.readObject(); + } + } } /**
--- a/src/share/classes/java/util/Comparators.java Fri Apr 12 10:42:50 2013 -0700 +++ b/src/share/classes/java/util/Comparators.java Tue Apr 16 01:44:58 2013 -0700 @@ -261,6 +261,7 @@ * according to the supplied {@code Comparator} */ public static<T> BinaryOperator<T> lesserOf(Comparator<? super T> comparator) { + Objects.requireNonNull(comparator); return (a, b) -> comparator.compare(a, b) <= 0 ? a : b; } @@ -274,6 +275,7 @@ * according to the supplied {@code Comparator} */ public static<T> BinaryOperator<T> greaterOf(Comparator<? super T> comparator) { + Objects.requireNonNull(comparator); return (a, b) -> comparator.compare(a, b) >= 0 ? a : b; } }
--- a/src/share/classes/java/util/HashMap.java Fri Apr 12 10:42:50 2013 -0700 +++ b/src/share/classes/java/util/HashMap.java Tue Apr 16 01:44:58 2013 -0700 @@ -129,7 +129,7 @@ /** * The default initial capacity - MUST be a power of two. */ - static final int DEFAULT_INITIAL_CAPACITY = 16; + static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 /** * The maximum capacity, used if a higher value is implicitly specified @@ -144,9 +144,14 @@ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** + * An empty table instance to share when the table is not inflated. + */ + static final Entry<?,?>[] EMPTY_TABLE = {}; + + /** * The table, resized as necessary. Length MUST Always be a power of two. */ - transient Entry<?,?>[] table; + transient Entry<?,?>[] table = EMPTY_TABLE; /** * The number of key-value mappings contained in this map. @@ -157,6 +162,8 @@ * The next size value at which to resize (capacity * load factor). * @serial */ + // If table == EMPTY_TABLE then this is the initial capacity at which the + // table will be created when inflated. int threshold; /** @@ -223,14 +230,8 @@ throw new IllegalArgumentException("Illegal load factor: " + loadFactor); - // Find a power of 2 >= initialCapacity - int capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; - this.loadFactor = loadFactor; - threshold = (int)Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); - table = new Entry<?,?>[capacity]; + threshold = initialCapacity; init(); } @@ -265,9 +266,33 @@ public HashMap(Map<? extends K, ? extends V> m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); + inflateTable(threshold); + putAllForCreate(m); } + private static int roundUpToPowerOf2(int number) { + // assert number >= 0 : "number must be non-negative"; + int rounded = number >= MAXIMUM_CAPACITY + ? MAXIMUM_CAPACITY + : (rounded = Integer.highestOneBit(number)) != 0 + ? (Integer.bitCount(number) > 1) ? rounded << 1 : rounded + : 1; + + return rounded; + } + + /** + * Inflates the table. + */ + private void inflateTable(int toSize) { + // Find a power of 2 >= toSize + int capacity = roundUpToPowerOf2(toSize); + + threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); + table = new Entry[capacity]; + } + // internal utilities /** @@ -305,6 +330,7 @@ * Returns index for hash code h. */ static int indexFor(int h, int length) { + // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2"; return h & (length-1); } @@ -369,6 +395,10 @@ */ @SuppressWarnings("unchecked") final Entry<K,V> getEntry(Object key) { + if (isEmpty()) { + return null; + } + int hash = (key == null) ? 0 : hash(key); for (Entry<?,?> e = table[indexFor(hash, table.length)]; e != null; @@ -381,7 +411,6 @@ return null; } - /** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the old @@ -395,6 +424,9 @@ * previously associated <tt>null</tt> with <tt>key</tt>.) */ public V put(K key, V value) { + if (table == EMPTY_TABLE) { + inflateTable(threshold); + } if (key == null) return putForNullKey(value); int hash = hash(key); @@ -529,6 +561,10 @@ if (numKeysToBeAdded == 0) return; + if (table == EMPTY_TABLE) { + inflateTable((int) Math.max(numKeysToBeAdded * loadFactor, threshold)); + } + /* * Expand the map if the map if the number of mappings to be added * is greater than or equal to threshold. This is conservative; the @@ -573,6 +609,9 @@ * for this key. */ final Entry<K,V> removeEntryForKey(Object key) { + if (isEmpty()) { + return null; + } int hash = (key == null) ? 0 : hash(key); int i = indexFor(hash, table.length); @SuppressWarnings("unchecked") @@ -605,7 +644,7 @@ * for matching. */ final Entry<K,V> removeMapping(Object o) { - if (!(o instanceof Map.Entry)) + if (isEmpty() || !(o instanceof Map.Entry)) return null; Map.Entry<?,?> entry = (Map.Entry<?,?>) o; @@ -641,9 +680,7 @@ */ public void clear() { modCount++; - Entry<?,?>[] tab = table; - for (int i = 0; i < tab.length; i++) - tab[i] = null; + Arrays.fill(table, null); size = 0; } @@ -693,7 +730,14 @@ } catch (CloneNotSupportedException e) { // assert false; } - result.table = new Entry<?,?>[table.length]; + if (result.table != EMPTY_TABLE) { + result.inflateTable(Math.min( + (int) Math.min( + size * Math.min(1 / loadFactor, 4.0f), + // we have limits... + HashMap.MAXIMUM_CAPACITY), + table.length)); + } result.entrySet = null; result.modCount = 0; result.size = 0; @@ -749,8 +793,7 @@ } public final int hashCode() { - return (key==null ? 0 : key.hashCode()) ^ - (value==null ? 0 : value.hashCode()); + return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue()); } public final String toString() { @@ -1017,14 +1060,15 @@ private void writeObject(java.io.ObjectOutputStream s) throws IOException { - Iterator<Map.Entry<K,V>> i = - (size > 0) ? entrySet0().iterator() : null; - // Write out the threshold, loadfactor, and any hidden stuff s.defaultWriteObject(); // Write out number of buckets - s.writeInt(table.length); + if (table==EMPTY_TABLE) { + s.writeInt(roundUpToPowerOf2(threshold)); + } else { + s.writeInt(table.length); + } // Write out size (number of Mappings) s.writeInt(size); @@ -1049,16 +1093,18 @@ { // Read in the threshold (ignored), loadfactor, and any hidden stuff s.defaultReadObject(); - if (loadFactor <= 0 || Float.isNaN(loadFactor)) + if (loadFactor <= 0 || Float.isNaN(loadFactor)) { throw new InvalidObjectException("Illegal load factor: " + loadFactor); + } - // set hashMask + // set other fields that need values Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET, sun.misc.Hashing.randomHashSeed(this)); + table = EMPTY_TABLE; - // Read in number of buckets and allocate the bucket array; - s.readInt(); // ignored + // Read in number of buckets + s.readInt(); // ignored. // Read number of mappings int mappings = s.readInt(); @@ -1066,23 +1112,21 @@ throw new InvalidObjectException("Illegal mappings count: " + mappings); - int initialCapacity = (int) Math.min( - // capacity chosen by number of mappings - // and desired load (if >= 0.25) - mappings * Math.min(1 / loadFactor, 4.0f), - // we have limits... - HashMap.MAXIMUM_CAPACITY); - int capacity = 1; - // find smallest power of two which holds all mappings - while (capacity < initialCapacity) { - capacity <<= 1; + // capacity chosen by number of mappings and desired load (if >= 0.25) + int capacity = (int) Math.min( + mappings * Math.min(1 / loadFactor, 4.0f), + // we have limits... + HashMap.MAXIMUM_CAPACITY); + + // allocate the bucket array; + if (mappings > 0) { + inflateTable(capacity); + } else { + threshold = capacity; } - table = new Entry<?,?>[capacity]; - threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); init(); // Give subclass a chance to do its thing. - // Read the keys and values, and put the mappings in the HashMap for (int i=0; i<mappings; i++) { @SuppressWarnings("unchecked")
--- a/src/share/classes/java/util/Objects.java Fri Apr 12 10:42:50 2013 -0700 +++ b/src/share/classes/java/util/Objects.java Tue Apr 16 01:44:58 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package java.util; +import java.util.function.Supplier; + /** * This class consists of {@code static} utility methods for operating * on objects. These utilities include {@code null}-safe or {@code @@ -226,4 +228,30 @@ throw new NullPointerException(message); return obj; } + + /** + * Checks that the specified object reference is not {@code null} and + * throws a customized {@link NullPointerException} if it is. + * + * <p>Unlike the method {@link requireNonNull(Object, String}, + * this method allows creation of the message to be deferred until + * after the null check is made. While this may confer a + * performance advantage in the non-null case, when deciding to + * call this method care should be taken that the costs of + * creating the message supplier are less than the cost of just + * creating the string message directly. + * + * @param obj the object reference to check for nullity + * @param messageSupplier supplier of the detail message to be + * used in the event that a {@code NullPointerException} is thrown + * @param <T> the type of the reference + * @return {@code obj} if not {@code null} + * @throws NullPointerException if {@code obj} is {@code null} + * @since 1.8 + */ + public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) { + if (obj == null) + throw new NullPointerException(messageSupplier.get()); + return obj; + } }
--- a/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java Fri Apr 12 10:42:50 2013 -0700 +++ b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java Tue Apr 16 01:44:58 2013 -0700 @@ -466,7 +466,10 @@ if (eSrc.type == Entry.NEW || eSrc.type == Entry.FILECH) { u.type = eSrc.type; // make it the same type - if (!deletesrc) { // if it's not "rename", just take the data + if (deletesrc) { // if it's a "rename", take the data + u.bytes = eSrc.bytes; + u.file = eSrc.file; + } else { // if it's not "rename", copy the data if (eSrc.bytes != null) u.bytes = Arrays.copyOf(eSrc.bytes, eSrc.bytes.length); else if (eSrc.file != null) { @@ -1118,7 +1121,7 @@ if (old != null) { removeFromTree(old); } - if (e.type == Entry.NEW || e.type == Entry.FILECH) { + if (e.type == Entry.NEW || e.type == Entry.FILECH || e.type == Entry.COPY) { IndexNode parent = inodes.get(LOOKUPKEY.as(getParent(e.name))); e.sibling = parent.child; parent.child = e; @@ -2326,12 +2329,12 @@ private void removeFromTree(IndexNode inode) { IndexNode parent = inodes.get(LOOKUPKEY.as(getParent(inode.name))); IndexNode child = parent.child; - if (child == inode) { + if (child.equals(inode)) { parent.child = child.sibling; } else { IndexNode last = child; while ((child = child.sibling) != null) { - if (child == inode) { + if (child.equals(inode)) { last.sibling = child.sibling; break; } else {
--- a/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h Fri Apr 12 10:42:50 2013 -0700 +++ b/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h Tue Apr 16 01:44:58 2013 -0700 @@ -143,9 +143,9 @@ * structure from the information present in a given Java Composite * object. */ -typedef JNIEXPORT void (JNICALL CompInfoFunc)(JNIEnv *env, - CompositeInfo *pCompInfo, - jobject Composite); +typedef void (JNICALL CompInfoFunc)(JNIEnv *env, + CompositeInfo *pCompInfo, + jobject Composite); /* * The additional information needed to implement a primitive that
--- a/src/share/npt/npt.h Fri Apr 12 10:42:50 2013 -0700 +++ b/src/share/npt/npt.h Tue Apr 16 01:44:58 2013 -0700 @@ -94,13 +94,13 @@ JNIEXPORT void JNICALL nptInitialize (NptEnv **pnpt, char *nptVersion, char *options); -typedef JNIEXPORT void (JNICALL *NptInitialize) - (NptEnv **pnpt, char *nptVersion, char *options); +typedef void (JNICALL *NptInitialize) + (NptEnv **pnpt, char *nptVersion, char *options); JNIEXPORT void JNICALL nptTerminate (NptEnv* npt, char *options); -typedef JNIEXPORT void (JNICALL *NptTerminate) - (NptEnv* npt, char *options); +typedef void (JNICALL *NptTerminate) + (NptEnv* npt, char *options); #ifdef __cplusplus } /* extern "C" */
--- a/src/solaris/classes/java/lang/UNIXProcess.java.bsd Fri Apr 12 10:42:50 2013 -0700 +++ b/src/solaris/classes/java/lang/UNIXProcess.java.bsd Tue Apr 16 01:44:58 2013 -0700 @@ -270,11 +270,10 @@ return !hasExited; } - /* This routine initializes JNI field offsets for the class */ - private static native void initIDs(); + private static native void init(); static { - initIDs(); + init(); } /**
--- a/src/solaris/classes/java/lang/UNIXProcess.java.linux Fri Apr 12 10:42:50 2013 -0700 +++ b/src/solaris/classes/java/lang/UNIXProcess.java.linux Tue Apr 16 01:44:58 2013 -0700 @@ -270,11 +270,10 @@ return !hasExited; } - /* This routine initializes JNI field offsets for the class */ - private static native void initIDs(); + private static native void init(); static { - initIDs(); + init(); } /**
--- a/src/solaris/classes/java/lang/UNIXProcess.java.solaris Fri Apr 12 10:42:50 2013 -0700 +++ b/src/solaris/classes/java/lang/UNIXProcess.java.solaris Tue Apr 16 01:44:58 2013 -0700 @@ -328,10 +328,9 @@ } - /* This routine initializes JNI field offsets for the class */ - private static native void initIDs(); + private static native void init(); static { - initIDs(); + init(); } }
--- a/src/solaris/javavm/export/jni_md.h Fri Apr 12 10:42:50 2013 -0700 +++ b/src/solaris/javavm/export/jni_md.h Tue Apr 16 01:44:58 2013 -0700 @@ -26,8 +26,17 @@ #ifndef _JAVASOFT_JNI_MD_H_ #define _JAVASOFT_JNI_MD_H_ -#define JNIEXPORT -#define JNIIMPORT +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif +#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) + #define JNIEXPORT __attribute__((visibility("default"))) + #define JNIIMPORT __attribute__((visibility("default"))) +#else + #define JNIEXPORT + #define JNIIMPORT +#endif + #define JNICALL typedef int jint;
--- a/src/solaris/native/java/lang/ProcessEnvironment_md.c Fri Apr 12 10:42:50 2013 -0700 +++ b/src/solaris/native/java/lang/ProcessEnvironment_md.c Tue Apr 16 01:44:58 2013 -0700 @@ -31,21 +31,24 @@ #ifdef __APPLE__ #include <crt_externs.h> #define environ (*_NSGetEnviron()) +#else +/* This is one of the rare times it's more portable to declare an + * external symbol explicitly, rather than via a system header. + * The declaration is standardized as part of UNIX98, but there is + * no standard (not even de-facto) header file where the + * declaration is to be found. See: + * http://www.opengroup.org/onlinepubs/009695399/functions/environ.html + * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html + * + * "All identifiers in this volume of IEEE Std 1003.1-2001, except + * environ, are defined in at least one of the headers" (!) + */ +extern char **environ; #endif JNIEXPORT jobjectArray JNICALL Java_java_lang_ProcessEnvironment_environ(JNIEnv *env, jclass ign) { - /* This is one of the rare times it's more portable to declare an - * external symbol explicitly, rather than via a system header. - * The declaration is standardized as part of UNIX98, but there is - * no standard (not even de-facto) header file where the - * declaration is to be found. See: - * http://www.opengroup.org/onlinepubs/007908799/xbd/envvar.html */ -#ifndef __APPLE__ - extern char ** environ; /* environ[i] looks like: VAR=VALUE\0 */ -#endif - jsize count = 0; jsize i, j; jobjectArray result;
--- a/src/solaris/native/java/lang/UNIXProcess_md.c Fri Apr 12 10:42:50 2013 -0700 +++ b/src/solaris/native/java/lang/UNIXProcess_md.c Tue Apr 16 01:44:58 2013 -0700 @@ -52,6 +52,19 @@ #ifdef __APPLE__ #include <crt_externs.h> #define environ (*_NSGetEnviron()) +#else +/* This is one of the rare times it's more portable to declare an + * external symbol explicitly, rather than via a system header. + * The declaration is standardized as part of UNIX98, but there is + * no standard (not even de-facto) header file where the + * declaration is to be found. See: + * http://www.opengroup.org/onlinepubs/009695399/functions/environ.html + * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html + * + * "All identifiers in this volume of IEEE Std 1003.1-2001, except + * environ, are defined in at least one of the headers" (!) + */ +extern char **environ; #endif /* @@ -152,19 +165,6 @@ } while((_result == -1) && (errno == EINTR)); \ } while(0) -/* This is one of the rare times it's more portable to declare an - * external symbol explicitly, rather than via a system header. - * The declaration is standardized as part of UNIX98, but there is - * no standard (not even de-facto) header file where the - * declaration is to be found. See: - * http://www.opengroup.org/onlinepubs/009695399/functions/environ.html - * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html - * - * "All identifiers in this volume of IEEE Std 1003.1-2001, except - * environ, are defined in at least one of the headers" (!) - */ -extern char **environ; - static void setSIGCHLDHandler(JNIEnv *env) @@ -241,52 +241,41 @@ } static const char * const * -splitPath(JNIEnv *env, const char *path) +effectivePathv(JNIEnv *env) { - const char *p, *q; - char **pathv; + char *p; int i; + const char *path = effectivePath(); int count = countOccurrences(path, ':') + 1; + size_t pathvsize = sizeof(const char *) * (count+1); + size_t pathsize = strlen(path) + 1; + const char **pathv = (const char **) xmalloc(env, pathvsize + pathsize); - pathv = NEW(char*, count+1); + if (pathv == NULL) + return NULL; + p = (char *) pathv + pathvsize; + memcpy(p, path, pathsize); + /* split PATH by replacing ':' with NULs; empty components => "." */ + for (i = 0; i < count; i++) { + char *q = p + strcspn(p, ":"); + pathv[i] = (p == q) ? "." : p; + *q = '\0'; + p = q + 1; + } pathv[count] = NULL; - for (p = path, i = 0; i < count; i++, p = q + 1) { - for (q = p; (*q != ':') && (*q != '\0'); q++) - ; - if (q == p) /* empty PATH component => "." */ - pathv[i] = "./"; - else { - int addSlash = ((*(q - 1)) != '/'); - pathv[i] = NEW(char, q - p + addSlash + 1); - memcpy(pathv[i], p, q - p); - if (addSlash) - pathv[i][q - p] = '/'; - pathv[i][q - p + addSlash] = '\0'; - } - } - return (const char * const *) pathv; + return pathv; } /** - * Cached value of JVM's effective PATH. + * The cached and split version of the JDK's effective PATH. * (We don't support putenv("PATH=...") in native code) */ -static const char *parentPath; - -/** - * Split, canonicalized version of parentPath - */ static const char * const *parentPathv; -static jfieldID field_exitcode; - JNIEXPORT void JNICALL -Java_java_lang_UNIXProcess_initIDs(JNIEnv *env, jclass clazz) +Java_java_lang_UNIXProcess_init(JNIEnv *env, jclass clazz) { - field_exitcode = (*env)->GetFieldID(env, clazz, "exitcode", "I"); - - parentPath = effectivePath(); - parentPathv = splitPath(env, parentPath); + parentPathv = effectivePathv(env); setSIGCHLDHandler(env); } @@ -486,6 +475,9 @@ } /* ASCII Decimal representation uses 2.4 times as many bits as binary. */ errmsg = NEW(char, strlen(format) + strlen(detail) + 3 * sizeof(errnum)); + if (errmsg == NULL) + return; + sprintf(errmsg, format, errnum, detail); s = JNU_NewStringPlatform(env, errmsg); if (s != NULL) { @@ -590,11 +582,13 @@ for (dirs = parentPathv; *dirs; dirs++) { const char * dir = *dirs; int dirlen = strlen(dir); - if (filelen + dirlen + 1 >= PATH_MAX) { + if (filelen + dirlen + 2 >= PATH_MAX) { errno = ENAMETOOLONG; continue; } memcpy(expanded_file, dir, dirlen); + if (expanded_file[dirlen - 1] != '/') + expanded_file[dirlen++] = '/'; memcpy(expanded_file + dirlen, file, filelen); expanded_file[dirlen + filelen] = '\0'; execve_with_shell_fallback(expanded_file, argv, envp);
--- a/src/solaris/native/sun/awt/awt_LoadLibrary.c Fri Apr 12 10:42:50 2013 -0700 +++ b/src/solaris/native/sun/awt/awt_LoadLibrary.c Tue Apr 16 01:44:58 2013 -0700 @@ -43,7 +43,7 @@ static void *awtHandle = NULL; -typedef JNIEXPORT jint JNICALL JNI_OnLoad_type(JavaVM *vm, void *reserved); +typedef jint JNICALL JNI_OnLoad_type(JavaVM *vm, void *reserved); /* Initialize the Java VM instance variable when the library is first loaded */ @@ -206,7 +206,7 @@ jobject frame, jstring jcommand) { /* type of the old backdoor function */ - typedef JNIEXPORT void JNICALL + typedef void JNICALL XsessionWMcommand_type(JNIEnv *env, jobject this, jobject frame, jstring jcommand); @@ -234,7 +234,7 @@ JNIEXPORT void JNICALL Java_sun_awt_motif_XsessionWMcommand_New(JNIEnv *env, jobjectArray jargv) { - typedef JNIEXPORT void JNICALL + typedef void JNICALL XsessionWMcommand_New_type(JNIEnv *env, jobjectArray jargv); static XsessionWMcommand_New_type *XsessionWMcommand = NULL;
--- a/test/demo/zipfs/ZipFSTester.java Fri Apr 12 10:42:50 2013 -0700 +++ b/test/demo/zipfs/ZipFSTester.java Tue Apr 16 01:44:58 2013 -0700 @@ -138,14 +138,31 @@ Path dst3 = Paths.get(tmpName + "_Tmp"); Files.move(dst2, dst3); checkEqual(src, dst3); + if (Files.exists(dst2)) + throw new RuntimeException("Failed!"); + + // copyback + move + Files.copy(dst3, dst); + Path dst4 = getPathWithParents(fs, tmpName + "_Tmp0"); + Files.move(dst, dst4); + checkEqual(src, dst4); // delete - if (Files.exists(dst2)) + Files.delete(dst4); + if (Files.exists(dst4)) throw new RuntimeException("Failed!"); Files.delete(dst3); if (Files.exists(dst3)) throw new RuntimeException("Failed!"); + // move (existing entry) + Path dst5 = fs.getPath("META-INF/MANIFEST.MF"); + if (Files.exists(dst5)) { + Path dst6 = fs.getPath("META-INF/MANIFEST.MF_TMP"); + Files.move(dst5, dst6); + walk(fs.getPath("/")); + } + // newInputStream on dir Path parent = dst2.getParent(); try {
--- a/test/demo/zipfs/basic.sh Fri Apr 12 10:42:50 2013 -0700 +++ b/test/demo/zipfs/basic.sh Tue Apr 16 01:44:58 2013 -0700 @@ -22,7 +22,7 @@ # # @test # @bug 6990846 7009092 7009085 7015391 7014948 7005986 7017840 7007596 -# 7157656 +# 7157656 8002390 # @summary Test ZipFileSystem demo # @build Basic PathOps ZipFSTester # @run shell basic.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/invoke/lambda/LambdaClassFinal.java Tue Apr 16 01:44:58 2013 -0700 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8012028 + * @summary Generated Lambda implementing class should be final + */ + +import java.lang.reflect.Modifier; +import java.io.Serializable; + +public class LambdaClassFinal { + + interface I { + void m(); + } + + interface Iser extends Serializable { + void m(); + } + + static void assertTrue(boolean cond) { + if (!cond) + throw new AssertionError(); + } + + public static void main(String[] args) throws Exception { + new LambdaClassFinal().test(); + } + + void test() throws Exception { + I lam = () -> { }; + assertTrue((lam.getClass().getModifiers() & Modifier.FINAL) != 0); + Iser slam = () -> { }; + assertTrue((slam.getClass().getModifiers() & Modifier.FINAL) != 0); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/invoke/lambda/LambdaClassSynthetic.java Tue Apr 16 01:44:58 2013 -0700 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8008941 + * @summary Generated Lambda implementing class should be synthetic + */ + +import java.lang.reflect.Modifier; +import java.io.Serializable; + +public class LambdaClassSynthetic { + + interface I { + void m(); + } + + interface Iser extends Serializable { + void m(); + } + + static void assertTrue(boolean cond) { + if (!cond) + throw new AssertionError(); + } + + public static void main(String[] args) throws Exception { + new LambdaClassFinal().test(); + } + + void test() throws Exception { + I lam = () -> { }; + assertTrue(lam.getClass().isSynthetic()); + Iser slam = () -> { }; + assertTrue(slam.getClass().isSynthetic()); + } +}
--- a/test/java/nio/file/attribute/FileTime/Basic.java Fri Apr 12 10:42:50 2013 -0700 +++ b/test/java/nio/file/attribute/FileTime/Basic.java Tue Apr 16 01:44:58 2013 -0700 @@ -22,14 +22,17 @@ */ /* @test - * @bug 6844313 + * @bug 6844313 8011647 * @summary Unit test for java.nio.file.FileTime */ + import java.nio.file.attribute.FileTime; +import java.time.Instant; import java.util.concurrent.TimeUnit; import static java.util.concurrent.TimeUnit.*; import java.util.Random; +import java.util.EnumSet; public class Basic { @@ -40,27 +43,59 @@ long tomorrowInDays = TimeUnit.DAYS.convert(now, MILLISECONDS) + 1; long yesterdayInDays = TimeUnit.DAYS.convert(now, MILLISECONDS) - 1; + Instant nowInstant = Instant.ofEpochMilli(now); + // equals eq(now, MILLISECONDS, now, MILLISECONDS); eq(now, MILLISECONDS, now*1000L, MICROSECONDS); neq(now, MILLISECONDS, 0, MILLISECONDS); neq(now, MILLISECONDS, 0, MICROSECONDS); + eq(nowInstant, now, MILLISECONDS); + eq(nowInstant, now*1000L, MICROSECONDS); + neq(nowInstant, 0, MILLISECONDS); + neq(nowInstant, 0, MICROSECONDS); + // compareTo cmp(now, MILLISECONDS, now, MILLISECONDS, 0); cmp(now, MILLISECONDS, now*1000L, MICROSECONDS, 0); cmp(now, MILLISECONDS, now-1234, MILLISECONDS, 1); cmp(now, MILLISECONDS, now+1234, MILLISECONDS, -1); + cmp(tomorrowInDays, DAYS, now, MILLISECONDS, 1); cmp(now, MILLISECONDS, tomorrowInDays, DAYS, -1); cmp(yesterdayInDays, DAYS, now, MILLISECONDS, -1); cmp(now, MILLISECONDS, yesterdayInDays, DAYS, 1); cmp(yesterdayInDays, DAYS, now, MILLISECONDS, -1); + cmp(Long.MAX_VALUE, DAYS, Long.MAX_VALUE, NANOSECONDS, 1); cmp(Long.MAX_VALUE, DAYS, Long.MIN_VALUE, NANOSECONDS, 1); cmp(Long.MIN_VALUE, DAYS, Long.MIN_VALUE, NANOSECONDS, -1); cmp(Long.MIN_VALUE, DAYS, Long.MAX_VALUE, NANOSECONDS, -1); + cmp(Instant.MIN, Long.MIN_VALUE, DAYS, 1); + cmp(Instant.MIN, Long.MIN_VALUE, HOURS, 1); + cmp(Instant.MIN, Long.MIN_VALUE, MINUTES, 1); + cmp(Instant.MIN, Long.MIN_VALUE, SECONDS, 1); + cmp(Instant.MIN, Instant.MIN.getEpochSecond() - 1, SECONDS, 1); + cmp(Instant.MIN, Instant.MIN.getEpochSecond() - 100, SECONDS, 1); + cmp(Instant.MIN, Instant.MIN.getEpochSecond(), SECONDS, 0); + + cmp(Instant.MAX, Long.MAX_VALUE, DAYS, -1); + cmp(Instant.MAX, Long.MAX_VALUE, HOURS, -1); + cmp(Instant.MAX, Long.MAX_VALUE, MINUTES, -1); + cmp(Instant.MAX, Long.MAX_VALUE, SECONDS, -1); + cmp(Instant.MAX, Instant.MAX.getEpochSecond() + 1, SECONDS, -1); + cmp(Instant.MAX, Instant.MAX.getEpochSecond() + 100, SECONDS, -1); + cmp(Instant.MAX, Instant.MAX.getEpochSecond(), SECONDS, 0); + + cmp(nowInstant, now, MILLISECONDS, 0); + cmp(nowInstant, now*1000L, MICROSECONDS, 0); + cmp(nowInstant, now-1234, MILLISECONDS, 1); + cmp(nowInstant, now+1234, MILLISECONDS, -1); + cmp(nowInstant, tomorrowInDays, DAYS, -1); + cmp(nowInstant, yesterdayInDays, DAYS, 1); + // to(TimeUnit) to(MILLISECONDS.convert(1, DAYS) - 1, MILLISECONDS); to(MILLISECONDS.convert(1, DAYS) + 0, MILLISECONDS); @@ -77,6 +112,64 @@ to(Long.MAX_VALUE, unit); } + // toInstant() + int N = 1000; + for (TimeUnit unit : EnumSet.allOf(TimeUnit.class)) { + for (int i = 0; i < N; i++) { + long value = rand.nextLong(); + FileTime ft = FileTime.from(value, unit); + Instant instant = ft.toInstant(); + if (instant != Instant.MIN && instant != Instant.MAX) { + eqTime(value, unit, instant); + } + } + } + for (TimeUnit unit : EnumSet.allOf(TimeUnit.class)) { + long value = Long.MIN_VALUE; + FileTime ft = FileTime.from(value, unit); + Instant instant = ft.toInstant(); + if (unit.compareTo(TimeUnit.SECONDS) < 0) { + eqTime(value, unit, instant); + } else if (!instant.equals(Instant.MIN)) { + throw new RuntimeException("should overflow to MIN"); + } + value = Long.MAX_VALUE; + ft = FileTime.from(value, unit); + instant = ft.toInstant(); + if (unit.compareTo(TimeUnit.SECONDS) < 0) { + eqTime(value, unit, instant); + } else if (!instant.equals(Instant.MAX)) { + throw new RuntimeException("should overflow to MAX"); + } + } + + // from(Instant) + final long MAX_SECOND = 31556889864403199L; + for (int i = 0; i < N; i++) { + long v = rand.nextLong(); + long secs = v % MAX_SECOND; + Instant instant = Instant.ofEpochSecond(secs, rand.nextInt(1000_000_000)); + FileTime ft = FileTime.from(instant); + if (!ft.toInstant().equals(instant) || ft.to(SECONDS) != secs) { + throw new RuntimeException("from(Instant) failed"); + } + long millis = v; + instant = Instant.ofEpochMilli(millis); + ft = FileTime.from(instant); + if (!ft.toInstant().equals(instant) || + ft.toMillis() != instant.toEpochMilli()) { + throw new RuntimeException("from(Instant) failed"); + } + long nanos = v; + ft = FileTime.from(nanos, NANOSECONDS); + secs = nanos / 1000_000_000; + nanos = nanos % 1000_000_000; + instant = Instant.ofEpochSecond(secs, nanos); + if (!ft.equals(FileTime.from(instant))) { + throw new RuntimeException("from(Instant) failed"); + } + } + // toString ts(1L, DAYS, "1970-01-02T00:00:00Z"); ts(1L, HOURS, "1970-01-01T01:00:00Z"); @@ -108,11 +201,18 @@ // NTFS epoch in usec. ts(-11644473600000000L, MICROSECONDS, "1601-01-01T00:00:00Z"); - // nulls + ts(Instant.MIN, "-1000000001-01-01T00:00:00Z"); + ts(Instant.MAX, "1000000000-12-31T23:59:59.999999999Z"); + try { FileTime.from(0L, null); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException npe) { } + try { + FileTime.from(null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException npe) { } + FileTime time = FileTime.fromMillis(now); if (time.equals(null)) throw new RuntimeException("should not be equal to null"); @@ -120,6 +220,39 @@ time.compareTo(null); throw new RuntimeException("NullPointerException expected"); } catch (NullPointerException npe) { } + + // Instant + toMilli() overflow + overflow(Long.MAX_VALUE, + FileTime.from(Instant.MAX).toMillis()); + overflow(Long.MAX_VALUE, + FileTime.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000 + 1)) + .toMillis()); + overflow(Long.MIN_VALUE, + FileTime.from(Instant.MIN).toMillis()); + overflow(Long.MIN_VALUE, + FileTime.from(Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1)) + .toMillis()); + + // Instant + to(TimeUnit) overflow + overflow(Long.MAX_VALUE, + FileTime.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000 + 1)) + .to(MILLISECONDS)); + overflow(Long.MAX_VALUE, + FileTime.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000, + MILLISECONDS.toNanos(1000))) + .to(MILLISECONDS)); + overflow(Long.MIN_VALUE, + FileTime.from(Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1)) + .to(MILLISECONDS)); + overflow(Long.MIN_VALUE, + FileTime.from(Instant.ofEpochSecond(Long.MIN_VALUE / 1000, + -MILLISECONDS.toNanos(1))) + .to(MILLISECONDS)); + } + + static void overflow(long minmax, long v) { + if (v != minmax) + throw new RuntimeException("saturates to Long.MIN/MAX_VALUE expected"); } static void cmp(long v1, TimeUnit u1, long v2, TimeUnit u2, int expected) { @@ -128,6 +261,12 @@ throw new RuntimeException("unexpected order"); } + static void cmp(Instant ins, long v2, TimeUnit u2, int expected) { + int result = FileTime.from(ins).compareTo(FileTime.from(v2, u2)); + if (result != expected) + throw new RuntimeException("unexpected order"); + } + static void eq(long v1, TimeUnit u1, long v2, TimeUnit u2) { FileTime t1 = FileTime.from(v1, u1); FileTime t2 = FileTime.from(v2, u2); @@ -137,6 +276,28 @@ throw new RuntimeException("hashCodes should be equal"); } + static void eq(Instant ins, long v2, TimeUnit u2) { + FileTime t1 = FileTime.from(ins); + FileTime t2 = FileTime.from(v2, u2); + if (!t1.equals(t2)) + throw new RuntimeException("not equal"); + if (t1.hashCode() != t2.hashCode()) + throw new RuntimeException("hashCodes should be equal"); + } + + static void eqTime(long value, TimeUnit unit, Instant instant) { + long secs = SECONDS.convert(value, unit); + long nanos = NANOSECONDS.convert(value - unit.convert(secs, SECONDS), unit); + if (nanos < 0) { // normalize nanoOfSecond to positive + secs -= 1; + nanos += 1000_000_000; + } + if (secs != instant.getEpochSecond() || (int)nanos != instant.getNano()) { + System.err.println(" ins=" + instant); + throw new RuntimeException("ft and instant are not the same time point"); + } + } + static void neq(long v1, TimeUnit u1, long v2, TimeUnit u2) { FileTime t1 = FileTime.from(v1, u1); FileTime t2 = FileTime.from(v2, u2); @@ -144,6 +305,13 @@ throw new RuntimeException("should not be equal"); } + static void neq(Instant ins, long v2, TimeUnit u2) { + FileTime t1 = FileTime.from(ins); + FileTime t2 = FileTime.from(v2, u2); + if (t1.equals(t2)) + throw new RuntimeException("should not be equal"); + } + static void to(long v, TimeUnit unit) { FileTime t = FileTime.from(v, unit); for (TimeUnit u: TimeUnit.values()) { @@ -164,4 +332,14 @@ throw new RuntimeException(); } } + + static void ts(Instant instant, String expected) { + String result = FileTime.from(instant).toString(); + if (!result.equals(expected)) { + System.err.format("FileTime.from(%s).toString() failed\n", instant); + System.err.format("Expected: %s\n", expected); + System.err.format(" Got: %s\n", result); + throw new RuntimeException(); + } + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/Comparators/BasicTest.java Tue Apr 16 01:44:58 2013 -0700 @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8001667 8010279 + * @run testng BasicTest + */ + +import java.util.Comparator; +import java.util.Comparators; +import java.util.AbstractMap; +import java.util.Map; +import org.testng.annotations.Test; + +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.ToIntFunction; +import java.util.function.ToLongFunction; +import java.util.function.ToDoubleFunction; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.fail; + +/** + * Unit tests for helper methods in Comparators + */ +@Test(groups = "unit") +public class BasicTest { + private static class Thing { + public final int intField; + public final long longField; + public final double doubleField; + public final String stringField; + + private Thing(int intField, long longField, double doubleField, String stringField) { + this.intField = intField; + this.longField = longField; + this.doubleField = doubleField; + this.stringField = stringField; + } + + public int getIntField() { + return intField; + } + + public long getLongField() { + return longField; + } + + public double getDoubleField() { + return doubleField; + } + + public String getStringField() { + return stringField; + } + } + + private final int[] intValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; + private final long[] longValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; + private final double[] doubleValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; + private final String[] stringValues = { "a", "a", "b", "b", "c", "c", "d", "d", "e", "e" }; + private final int[] comparisons = { 0, -1, 0, -1, 0, -1, 0, -1, 0 }; + + private<T> void assertComparisons(T[] things, Comparator<T> comp, int[] comparisons) { + for (int i=0; i<comparisons.length; i++) { + assertEquals(comparisons.length + 1, things.length); + assertEquals(comparisons[i], comp.compare(things[i], things[i+1])); + assertEquals(-comparisons[i], comp.compare(things[i+1], things[i])); + } + } + + public void testIntComparator() { + Thing[] things = new Thing[intValues.length]; + for (int i=0; i<intValues.length; i++) + things[i] = new Thing(intValues[i], 0L, 0.0, null); + Comparator<Thing> comp = Comparators.comparing(new ToIntFunction<BasicTest.Thing>() { + @Override + public int applyAsInt(Thing thing) { + return thing.getIntField(); + } + }); + + assertComparisons(things, comp, comparisons); + } + + public void testLongComparator() { + Thing[] things = new Thing[longValues.length]; + for (int i=0; i<longValues.length; i++) + things[i] = new Thing(0, longValues[i], 0.0, null); + Comparator<Thing> comp = Comparators.comparing(new ToLongFunction<BasicTest.Thing>() { + @Override + public long applyAsLong(Thing thing) { + return thing.getLongField(); + } + }); + + assertComparisons(things, comp, comparisons); + } + + public void testDoubleComparator() { + Thing[] things = new Thing[doubleValues.length]; + for (int i=0; i<doubleValues.length; i++) + things[i] = new Thing(0, 0L, doubleValues[i], null); + Comparator<Thing> comp = Comparators.comparing(new ToDoubleFunction<BasicTest.Thing>() { + @Override + public double applyAsDouble(Thing thing) { + return thing.getDoubleField(); + } + }); + + assertComparisons(things, comp, comparisons); + } + + public void testComparing() { + Thing[] things = new Thing[doubleValues.length]; + for (int i=0; i<doubleValues.length; i++) + things[i] = new Thing(0, 0L, 0.0, stringValues[i]); + Comparator<Thing> comp = Comparators.comparing(new Function<Thing, String>() { + @Override + public String apply(Thing thing) { + return thing.getStringField(); + } + }); + + assertComparisons(things, comp, comparisons); + } + + public void testNaturalOrderComparator() { + Comparator<String> comp = Comparators.naturalOrder(); + + assertComparisons(stringValues, comp, comparisons); + } + + public void testReverseComparator() { + Comparator<String> cmpr = Comparators.reverseOrder(); + Comparator<String> cmp = cmpr.reverseOrder(); + + assertEquals(cmp.reverseOrder(), cmpr); + assertEquals(0, cmp.compare("a", "a")); + assertEquals(0, cmpr.compare("a", "a")); + assertTrue(cmp.compare("a", "b") < 0); + assertTrue(cmpr.compare("a", "b") > 0); + assertTrue(cmp.compare("b", "a") > 0); + assertTrue(cmpr.compare("b", "a") < 0); + } + + public void testReverseComparator2() { + Comparator<String> cmp = (s1, s2) -> s1.length() - s2.length(); + Comparator<String> cmpr = cmp.reverseOrder(); + + assertEquals(cmpr.reverseOrder(), cmp); + assertEquals(0, cmp.compare("abc", "def")); + assertEquals(0, cmpr.compare("abc", "def")); + assertTrue(cmp.compare("abcd", "def") > 0); + assertTrue(cmpr.compare("abcd", "def") < 0); + assertTrue(cmp.compare("abc", "defg") < 0); + assertTrue(cmpr.compare("abc", "defg") > 0); + } + + @Test(expectedExceptions=NullPointerException.class) + public void testReverseComparatorNPE() { + Comparator<String> cmp = Comparators.reverseOrder(null); + } + + public void testComposeComparator() { + // Longer string in front + Comparator<String> first = (s1, s2) -> s2.length() - s1.length(); + Comparator<String> second = Comparators.naturalOrder(); + Comparator<String> composed = Comparators.compose(first, second); + + assertTrue(composed.compare("abcdefg", "abcdef") < 0); + assertTrue(composed.compare("abcdef", "abcdefg") > 0); + assertTrue(composed.compare("abcdef", "abcdef") == 0); + assertTrue(composed.compare("abcdef", "ghijkl") < 0); + assertTrue(composed.compare("ghijkl", "abcdefg") > 0); + } + + private <K, V> void assertPairComparison(K k1, V v1, K k2, V v2, + Comparator<Map.Entry<K, V>> ck, + Comparator<Map.Entry<K, V>> cv) { + final Map.Entry<K, V> p11 = new AbstractMap.SimpleImmutableEntry<>(k1, v1); + final Map.Entry<K, V> p12 = new AbstractMap.SimpleImmutableEntry<>(k1, v2); + final Map.Entry<K, V> p21 = new AbstractMap.SimpleImmutableEntry<>(k2, v1); + final Map.Entry<K, V> p22 = new AbstractMap.SimpleImmutableEntry<>(k2, v2); + + assertTrue(ck.compare(p11, p11) == 0); + assertTrue(ck.compare(p12, p11) == 0); + assertTrue(ck.compare(p11, p12) == 0); + assertTrue(ck.compare(p12, p22) < 0); + assertTrue(ck.compare(p12, p21) < 0); + assertTrue(ck.compare(p21, p11) > 0); + assertTrue(ck.compare(p21, p12) > 0); + + assertTrue(cv.compare(p11, p11) == 0); + assertTrue(cv.compare(p12, p11) > 0); + assertTrue(cv.compare(p11, p12) < 0); + assertTrue(cv.compare(p12, p22) == 0); + assertTrue(cv.compare(p12, p21) > 0); + assertTrue(cv.compare(p21, p11) == 0); + assertTrue(cv.compare(p21, p12) < 0); + + Comparator<Map.Entry<K, V>> cmp = Comparators.compose(ck, cv); + assertTrue(cmp.compare(p11, p11) == 0); + assertTrue(cmp.compare(p12, p11) > 0); + assertTrue(cmp.compare(p11, p12) < 0); + assertTrue(cmp.compare(p12, p22) < 0); + assertTrue(cmp.compare(p12, p21) < 0); + assertTrue(cmp.compare(p21, p11) > 0); + assertTrue(cmp.compare(p21, p12) > 0); + + cmp = Comparators.compose(cv, ck); + assertTrue(cmp.compare(p11, p11) == 0); + assertTrue(cmp.compare(p12, p11) > 0); + assertTrue(cmp.compare(p11, p12) < 0); + assertTrue(cmp.compare(p12, p22) < 0); + assertTrue(cmp.compare(p12, p21) > 0); + assertTrue(cmp.compare(p21, p11) > 0); + assertTrue(cmp.compare(p21, p12) < 0); + } + + public void testKVComparatorable() { + assertPairComparison(1, "ABC", 2, "XYZ", + Comparators.<Integer, String>naturalOrderKeys(), + Comparators.<Integer, String>naturalOrderValues()); + } + + private static class People { + final String firstName; + final String lastName; + final int age; + + People(String first, String last, int age) { + firstName = first; + lastName = last; + this.age = age; + } + + String getFirstName() { return firstName; } + String getLastName() { return lastName; } + int getAge() { return age; } + long getAgeAsLong() { return (long) age; }; + double getAgeAsDouble() { return (double) age; }; + } + + private final People people[] = { + new People("John", "Doe", 34), + new People("Mary", "Doe", 30), + new People("Maria", "Doe", 14), + new People("Jonah", "Doe", 10), + new People("John", "Cook", 54), + new People("Mary", "Cook", 50), + }; + + public void testKVComparators() { + // Comparator<People> cmp = Comparators.naturalOrder(); // Should fail to compiler as People is not comparable + // We can use simple comparator, but those have been tested above. + // Thus choose to do compose for some level of interation. + Comparator<People> cmp1 = Comparators.comparing((Function<People, String>) People::getFirstName); + Comparator<People> cmp2 = Comparators.comparing((Function<People, String>) People::getLastName); + Comparator<People> cmp = Comparators.compose(cmp1, cmp2); + + assertPairComparison(people[0], people[0], people[1], people[1], + Comparators.<People, People>byKey(cmp), + Comparators.<People, People>byValue(cmp)); + + } + + private <T> void assertComparison(Comparator<T> cmp, T less, T greater) { + assertTrue(cmp.compare(less, greater) < 0, "less"); + assertTrue(cmp.compare(less, less) == 0, "equal"); + assertTrue(cmp.compare(greater, less) > 0, "greater"); + } + + public void testComparatorDefaultMethods() { + Comparator<People> cmp = Comparators.comparing((Function<People, String>) People::getFirstName); + Comparator<People> cmp2 = Comparators.comparing((Function<People, String>) People::getLastName); + // reverseOrder + assertComparison(cmp.reverseOrder(), people[1], people[0]); + // thenComparing(Comparator) + assertComparison(cmp.thenComparing(cmp2), people[0], people[1]); + assertComparison(cmp.thenComparing(cmp2), people[4], people[0]); + // thenComparing(Function) + assertComparison(cmp.thenComparing(People::getLastName), people[0], people[1]); + assertComparison(cmp.thenComparing(People::getLastName), people[4], people[0]); + // thenComparing(ToIntFunction) + assertComparison(cmp.thenComparing(People::getAge), people[0], people[1]); + assertComparison(cmp.thenComparing(People::getAge), people[1], people[5]); + // thenComparing(ToLongFunction) + assertComparison(cmp.thenComparing(People::getAgeAsLong), people[0], people[1]); + assertComparison(cmp.thenComparing(People::getAgeAsLong), people[1], people[5]); + // thenComparing(ToDoubleFunction) + assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[0], people[1]); + assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[1], people[5]); + } + + public void testGreaterOf() { + // lesser + assertSame(Comparators.greaterOf(Comparators.comparing( + (Function<People, String>) People::getFirstName)) + .apply(people[0], people[1]), + people[1]); + // euqal + assertSame(Comparators.greaterOf(Comparators.comparing( + (Function<People, String>) People::getLastName)) + .apply(people[0], people[1]), + people[0]); + // greater + assertSame(Comparators.greaterOf(Comparators.comparing( + (ToIntFunction<People>) People::getAge)) + .apply(people[0], people[1]), + people[0]); + } + + public void testLesserOf() { + // lesser + assertSame(Comparators.lesserOf(Comparators.comparing( + (Function<People, String>) People::getFirstName)) + .apply(people[0], people[1]), + people[0]); + // euqal + assertSame(Comparators.lesserOf(Comparators.comparing( + (Function<People, String>) People::getLastName)) + .apply(people[0], people[1]), + people[0]); + // greater + assertSame(Comparators.lesserOf(Comparators.comparing( + (ToIntFunction<People>) People::getAge)) + .apply(people[0], people[1]), + people[1]); + } + + public void testNulls() { + try { + Comparators.<String>naturalOrder().compare("abc", (String) null); + fail("expected NPE with naturalOrder"); + } catch (NullPointerException npe) {} + try { + Comparators.<String>naturalOrder().compare((String) null, "abc"); + fail("expected NPE with naturalOrder"); + } catch (NullPointerException npe) {} + + try { + Comparators.<String>reverseOrder().compare("abc", (String) null); + fail("expected NPE with naturalOrder"); + } catch (NullPointerException npe) {} + try { + Comparators.<String>reverseOrder().compare((String) null, "abc"); + fail("expected NPE with naturalOrder"); + } catch (NullPointerException npe) {} + + try { + Comparator<Map.Entry<String, String>> cmp = Comparators.byKey(null); + fail("byKey(null) should throw NPE"); + } catch (NullPointerException npe) {} + + try { + Comparator<Map.Entry<String, String>> cmp = Comparators.byValue(null); + fail("byValue(null) should throw NPE"); + } catch (NullPointerException npe) {} + + try { + Comparator<People> cmp = Comparators.comparing((Function<People, String>) null); + fail("comparing(null) should throw NPE"); + } catch (NullPointerException npe) {} + try { + Comparator<People> cmp = Comparators.comparing((ToIntFunction<People>) null); + fail("comparing(null) should throw NPE"); + } catch (NullPointerException npe) {} + try { + Comparator<People> cmp = Comparators.comparing((ToLongFunction<People>) null); + fail("comparing(null) should throw NPE"); + } catch (NullPointerException npe) {} + try { + Comparator<People> cmp = Comparators.comparing((ToDoubleFunction<People>) null); + fail("comparing(null) should throw NPE"); + } catch (NullPointerException npe) {} + + try { + BinaryOperator<String> op = Comparators.lesserOf(null); + fail("lesserOf(null) should throw NPE"); + } catch (NullPointerException npe) {} + + try { + BinaryOperator<String> op = Comparators.greaterOf(null); + fail("lesserOf(null) should throw NPE"); + } catch (NullPointerException npe) {} + } +}
--- a/test/java/util/ComparatorsTest.java Fri Apr 12 10:42:50 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,353 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8001667 - * @run testng ComparatorsTest - */ - -import java.util.Comparator; -import java.util.Comparators; -import java.util.AbstractMap; -import java.util.Map; -import org.testng.annotations.Test; - -import java.util.function.Function; -import java.util.function.ToIntFunction; -import java.util.function.ToLongFunction; -import java.util.function.ToDoubleFunction; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertSame; - -/** - * Unit tests for helper methods in Comparators - */ -@Test(groups = "unit") -public class ComparatorsTest { - private static class Thing { - public final int intField; - public final long longField; - public final double doubleField; - public final String stringField; - - private Thing(int intField, long longField, double doubleField, String stringField) { - this.intField = intField; - this.longField = longField; - this.doubleField = doubleField; - this.stringField = stringField; - } - - public int getIntField() { - return intField; - } - - public long getLongField() { - return longField; - } - - public double getDoubleField() { - return doubleField; - } - - public String getStringField() { - return stringField; - } - } - - private final int[] intValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; - private final long[] longValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; - private final double[] doubleValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; - private final String[] stringValues = { "a", "a", "b", "b", "c", "c", "d", "d", "e", "e" }; - private final int[] comparisons = { 0, -1, 0, -1, 0, -1, 0, -1, 0 }; - - private<T> void assertComparisons(T[] things, Comparator<T> comp, int[] comparisons) { - for (int i=0; i<comparisons.length; i++) { - assertEquals(comparisons.length + 1, things.length); - assertEquals(comparisons[i], comp.compare(things[i], things[i+1])); - assertEquals(-comparisons[i], comp.compare(things[i+1], things[i])); - } - } - - public void testIntComparator() { - Thing[] things = new Thing[intValues.length]; - for (int i=0; i<intValues.length; i++) - things[i] = new Thing(intValues[i], 0L, 0.0, null); - Comparator<Thing> comp = Comparators.comparing(new ToIntFunction<ComparatorsTest.Thing>() { - @Override - public int applyAsInt(Thing thing) { - return thing.getIntField(); - } - }); - - assertComparisons(things, comp, comparisons); - } - - public void testLongComparator() { - Thing[] things = new Thing[longValues.length]; - for (int i=0; i<longValues.length; i++) - things[i] = new Thing(0, longValues[i], 0.0, null); - Comparator<Thing> comp = Comparators.comparing(new ToLongFunction<ComparatorsTest.Thing>() { - @Override - public long applyAsLong(Thing thing) { - return thing.getLongField(); - } - }); - - assertComparisons(things, comp, comparisons); - } - - public void testDoubleComparator() { - Thing[] things = new Thing[doubleValues.length]; - for (int i=0; i<doubleValues.length; i++) - things[i] = new Thing(0, 0L, doubleValues[i], null); - Comparator<Thing> comp = Comparators.comparing(new ToDoubleFunction<ComparatorsTest.Thing>() { - @Override - public double applyAsDouble(Thing thing) { - return thing.getDoubleField(); - } - }); - - assertComparisons(things, comp, comparisons); - } - - public void testComparing() { - Thing[] things = new Thing[doubleValues.length]; - for (int i=0; i<doubleValues.length; i++) - things[i] = new Thing(0, 0L, 0.0, stringValues[i]); - Comparator<Thing> comp = Comparators.comparing(new Function<Thing, String>() { - @Override - public String apply(Thing thing) { - return thing.getStringField(); - } - }); - - assertComparisons(things, comp, comparisons); - } - - public void testNaturalOrderComparator() { - Comparator<String> comp = Comparators.naturalOrder(); - - assertComparisons(stringValues, comp, comparisons); - } - - public void testReverseComparator() { - Comparator<String> cmpr = Comparators.reverseOrder(); - Comparator<String> cmp = cmpr.reverseOrder(); - - assertEquals(cmp.reverseOrder(), cmpr); - assertEquals(0, cmp.compare("a", "a")); - assertEquals(0, cmpr.compare("a", "a")); - assertTrue(cmp.compare("a", "b") < 0); - assertTrue(cmpr.compare("a", "b") > 0); - assertTrue(cmp.compare("b", "a") > 0); - assertTrue(cmpr.compare("b", "a") < 0); - } - - public void testReverseComparator2() { - Comparator<String> cmp = (s1, s2) -> s1.length() - s2.length(); - Comparator<String> cmpr = cmp.reverseOrder(); - - assertEquals(cmpr.reverseOrder(), cmp); - assertEquals(0, cmp.compare("abc", "def")); - assertEquals(0, cmpr.compare("abc", "def")); - assertTrue(cmp.compare("abcd", "def") > 0); - assertTrue(cmpr.compare("abcd", "def") < 0); - assertTrue(cmp.compare("abc", "defg") < 0); - assertTrue(cmpr.compare("abc", "defg") > 0); - } - - @Test(expectedExceptions=NullPointerException.class) - public void testReverseComparatorNPE() { - Comparator<String> cmp = Comparators.reverseOrder(null); - } - - public void testComposeComparator() { - // Longer string in front - Comparator<String> first = (s1, s2) -> s2.length() - s1.length(); - Comparator<String> second = Comparators.naturalOrder(); - Comparator<String> composed = Comparators.compose(first, second); - - assertTrue(composed.compare("abcdefg", "abcdef") < 0); - assertTrue(composed.compare("abcdef", "abcdefg") > 0); - assertTrue(composed.compare("abcdef", "abcdef") == 0); - assertTrue(composed.compare("abcdef", "ghijkl") < 0); - assertTrue(composed.compare("ghijkl", "abcdefg") > 0); - } - - private <K, V> void assertPairComparison(K k1, V v1, K k2, V v2, - Comparator<Map.Entry<K, V>> ck, - Comparator<Map.Entry<K, V>> cv) { - final Map.Entry<K, V> p11 = new AbstractMap.SimpleImmutableEntry<>(k1, v1); - final Map.Entry<K, V> p12 = new AbstractMap.SimpleImmutableEntry<>(k1, v2); - final Map.Entry<K, V> p21 = new AbstractMap.SimpleImmutableEntry<>(k2, v1); - final Map.Entry<K, V> p22 = new AbstractMap.SimpleImmutableEntry<>(k2, v2); - - assertTrue(ck.compare(p11, p11) == 0); - assertTrue(ck.compare(p12, p11) == 0); - assertTrue(ck.compare(p11, p12) == 0); - assertTrue(ck.compare(p12, p22) < 0); - assertTrue(ck.compare(p12, p21) < 0); - assertTrue(ck.compare(p21, p11) > 0); - assertTrue(ck.compare(p21, p12) > 0); - - assertTrue(cv.compare(p11, p11) == 0); - assertTrue(cv.compare(p12, p11) > 0); - assertTrue(cv.compare(p11, p12) < 0); - assertTrue(cv.compare(p12, p22) == 0); - assertTrue(cv.compare(p12, p21) > 0); - assertTrue(cv.compare(p21, p11) == 0); - assertTrue(cv.compare(p21, p12) < 0); - - Comparator<Map.Entry<K, V>> cmp = Comparators.compose(ck, cv); - assertTrue(cmp.compare(p11, p11) == 0); - assertTrue(cmp.compare(p12, p11) > 0); - assertTrue(cmp.compare(p11, p12) < 0); - assertTrue(cmp.compare(p12, p22) < 0); - assertTrue(cmp.compare(p12, p21) < 0); - assertTrue(cmp.compare(p21, p11) > 0); - assertTrue(cmp.compare(p21, p12) > 0); - - cmp = Comparators.compose(cv, ck); - assertTrue(cmp.compare(p11, p11) == 0); - assertTrue(cmp.compare(p12, p11) > 0); - assertTrue(cmp.compare(p11, p12) < 0); - assertTrue(cmp.compare(p12, p22) < 0); - assertTrue(cmp.compare(p12, p21) > 0); - assertTrue(cmp.compare(p21, p11) > 0); - assertTrue(cmp.compare(p21, p12) < 0); - } - - public void testKVComparatorable() { - assertPairComparison(1, "ABC", 2, "XYZ", - Comparators.<Integer, String>naturalOrderKeys(), - Comparators.<Integer, String>naturalOrderValues()); - } - - private static class People { - final String firstName; - final String lastName; - final int age; - - People(String first, String last, int age) { - firstName = first; - lastName = last; - this.age = age; - } - - String getFirstName() { return firstName; } - String getLastName() { return lastName; } - int getAge() { return age; } - long getAgeAsLong() { return (long) age; }; - double getAgeAsDouble() { return (double) age; }; - } - - private final People people[] = { - new People("John", "Doe", 34), - new People("Mary", "Doe", 30), - new People("Maria", "Doe", 14), - new People("Jonah", "Doe", 10), - new People("John", "Cook", 54), - new People("Mary", "Cook", 50), - }; - - public void testKVComparators() { - // Comparator<People> cmp = Comparators.naturalOrder(); // Should fail to compiler as People is not comparable - // We can use simple comparator, but those have been tested above. - // Thus choose to do compose for some level of interation. - Comparator<People> cmp1 = Comparators.comparing((Function<People, String>) People::getFirstName); - Comparator<People> cmp2 = Comparators.comparing((Function<People, String>) People::getLastName); - Comparator<People> cmp = Comparators.compose(cmp1, cmp2); - - assertPairComparison(people[0], people[0], people[1], people[1], - Comparators.<People, People>byKey(cmp), - Comparators.<People, People>byValue(cmp)); - - } - - private <T> void assertComparison(Comparator<T> cmp, T less, T greater) { - assertTrue(cmp.compare(less, greater) < 0, "less"); - assertTrue(cmp.compare(less, less) == 0, "equal"); - assertTrue(cmp.compare(greater, less) > 0, "greater"); - } - - public void testComparatorDefaultMethods() { - Comparator<People> cmp = Comparators.comparing((Function<People, String>) People::getFirstName); - Comparator<People> cmp2 = Comparators.comparing((Function<People, String>) People::getLastName); - // reverseOrder - assertComparison(cmp.reverseOrder(), people[1], people[0]); - // thenComparing(Comparator) - assertComparison(cmp.thenComparing(cmp2), people[0], people[1]); - assertComparison(cmp.thenComparing(cmp2), people[4], people[0]); - // thenComparing(Function) - assertComparison(cmp.thenComparing(People::getLastName), people[0], people[1]); - assertComparison(cmp.thenComparing(People::getLastName), people[4], people[0]); - // thenComparing(ToIntFunction) - assertComparison(cmp.thenComparing(People::getAge), people[0], people[1]); - assertComparison(cmp.thenComparing(People::getAge), people[1], people[5]); - // thenComparing(ToLongFunction) - assertComparison(cmp.thenComparing(People::getAgeAsLong), people[0], people[1]); - assertComparison(cmp.thenComparing(People::getAgeAsLong), people[1], people[5]); - // thenComparing(ToDoubleFunction) - assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[0], people[1]); - assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[1], people[5]); - } - - public void testGreaterOf() { - // lesser - assertSame(Comparators.greaterOf(Comparators.comparing( - (Function<People, String>) People::getFirstName)) - .apply(people[0], people[1]), - people[1]); - // euqal - assertSame(Comparators.greaterOf(Comparators.comparing( - (Function<People, String>) People::getLastName)) - .apply(people[0], people[1]), - people[0]); - // greater - assertSame(Comparators.greaterOf(Comparators.comparing( - (ToIntFunction<People>) People::getAge)) - .apply(people[0], people[1]), - people[0]); - } - - public void testLesserOf() { - // lesser - assertSame(Comparators.lesserOf(Comparators.comparing( - (Function<People, String>) People::getFirstName)) - .apply(people[0], people[1]), - people[0]); - // euqal - assertSame(Comparators.lesserOf(Comparators.comparing( - (Function<People, String>) People::getLastName)) - .apply(people[0], people[1]), - people[0]); - // greater - assertSame(Comparators.lesserOf(Comparators.comparing( - (ToIntFunction<People>) People::getAge)) - .apply(people[0], people[1]), - people[1]); - } -} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/Map/BasicSerialization.java Tue Apr 16 01:44:58 2013 -0700 @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8011200 + * @run testng BasicSerialization + * @summary Ensure Maps can be serialized and deserialized. + * @author Mike Duigou + */ +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ByteArrayInputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListMap; + +import org.testng.annotations.Test; +import org.testng.annotations.DataProvider; +import static org.testng.Assert.fail; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertSame; + +public class BasicSerialization { + + enum IntegerEnum { + + e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, + e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, + e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, + e30, e31, e32, e33, e34, e35, e36, e37, e38, e39, + e40, e41, e42, e43, e44, e45, e46, e47, e48, e49, + e50, e51, e52, e53, e54, e55, e56, e57, e58, e59, + e60, e61, e62, e63, e64, e65, e66, e67, e68, e69, + e70, e71, e72, e73, e74, e75, e76, e77, e78, e79, + e80, e81, e82, e83, e84, e85, e86, e87, e88, e89, + e90, e91, e92, e93, e94, e95, e96, e97, e98, e99, + EXTRA_KEY; + public static final int SIZE = values().length; + }; + private static final int TEST_SIZE = IntegerEnum.SIZE - 1; + /** + * Realized keys ensure that there is always a hard ref to all test objects. + */ + private static final IntegerEnum[] KEYS = new IntegerEnum[TEST_SIZE]; + /** + * Realized values ensure that there is always a hard ref to all test + * objects. + */ + private static final String[] VALUES = new String[TEST_SIZE]; + + static { + IntegerEnum[] keys = IntegerEnum.values(); + for (int each = 0; each < TEST_SIZE; each++) { + KEYS[each] = keys[each]; + VALUES[each] = keys[each].name(); + } + } + private static final IntegerEnum EXTRA_KEY = IntegerEnum.EXTRA_KEY; + private static final String EXTRA_VALUE = IntegerEnum.EXTRA_KEY.name(); + + public static <K, V> Map<K, V> mapClone(Map<K, V> map) { + Method cloneMethod; + + try { + cloneMethod = map.getClass().getMethod("clone", new Class[]{}); + } catch (NoSuchMethodException | SecurityException all) { + cloneMethod = null; + } + + if (null != cloneMethod) { + try { + Map<K, V> result = (Map<K, V>)cloneMethod.invoke(map, new Object[]{}); + return result; + } catch (Exception all) { + fail("clone() failed " + map.getClass().getSimpleName(), all); + return null; + } + } else { + Constructor<? extends Map> copyConstructor; + try { + copyConstructor = (Constructor<? extends Map>)map.getClass().getConstructor(new Class[]{Map.class}); + + Map<K, V> result = (Map<K, V>)copyConstructor.newInstance(new Object[]{map}); + + return result; + } catch (Exception all) { + return serialClone(map); + } + } + } + + @Test(dataProvider = "Map<IntegerEnum,String>") + public void testSerialization(String description, Map<IntegerEnum, String> map) { + Object foo = new Object(); + + Map<IntegerEnum, String> clone = mapClone(map); + Map<IntegerEnum, String> serialClone = serialClone(map); + + assertEquals(map, map, description + ":should equal self"); + assertEquals(clone, map, description + ":should equal clone"); + assertEquals(map, clone, description + ": should equal orginal map"); + assertEquals(serialClone, map, description + ": should equal deserialized clone"); + assertEquals(map, serialClone, description + ": should equal original map"); + assertEquals(serialClone, clone, description + ": deserialized clone should equal clone"); + assertEquals(clone, serialClone, description + ": clone should equal deserialized clone"); + + assertFalse(map.containsKey(EXTRA_KEY), description + ":unexpected key"); + assertFalse(clone.containsKey(EXTRA_KEY), description + ":unexpected key"); + assertFalse(serialClone.containsKey(EXTRA_KEY), description + ":unexpected key"); + map.put(EXTRA_KEY, EXTRA_VALUE); + clone.put(EXTRA_KEY, EXTRA_VALUE); + serialClone.put(EXTRA_KEY, EXTRA_VALUE); + assertTrue(map.containsKey(EXTRA_KEY), description + ":missing key"); + assertTrue(clone.containsKey(EXTRA_KEY), description + ":missing key"); + assertTrue(serialClone.containsKey(EXTRA_KEY), description + ":missing key"); + assertSame(map.get(EXTRA_KEY), EXTRA_VALUE, description + ":wrong value"); + assertSame(clone.get(EXTRA_KEY), EXTRA_VALUE, description + ":wrong value"); + assertSame(serialClone.get(EXTRA_KEY), EXTRA_VALUE, description + ":wrong value"); + + assertEquals(map, map, description + ":should equal self"); + assertEquals(clone, map, description + ":should equal clone"); + assertEquals(map, clone, description + ": should equal orginal map"); + assertEquals(serialClone, map, description + ": should equal deserialized clone"); + assertEquals(map, serialClone, description + ": should equal original map"); + assertEquals(serialClone, clone, description + ": deserialized clone should equal clone"); + assertEquals(clone, serialClone, description + ": clone should equal deserialized clone"); + } + + static byte[] serializedForm(Object obj) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + new ObjectOutputStream(baos).writeObject(obj); + return baos.toByteArray(); + } catch (IOException e) { + fail("Unexpected Exception", e); + return null; + } + } + + static Object readObject(byte[] bytes) throws IOException, ClassNotFoundException { + InputStream is = new ByteArrayInputStream(bytes); + return new ObjectInputStream(is).readObject(); + } + + @SuppressWarnings("unchecked") + static <T> T serialClone(T obj) { + try { + return (T)readObject(serializedForm(obj)); + } catch (IOException | ClassNotFoundException e) { + fail("Unexpected Exception", e); + return null; + } + } + + @DataProvider(name = "Map<IntegerEnum,String>", parallel = true) + private static Iterator<Object[]> makeMaps() { + return Arrays.asList( + // empty + new Object[]{"HashMap", new HashMap()}, + new Object[]{"LinkedHashMap", new LinkedHashMap()}, + new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(new HashMap(), IntegerEnum.class, String.class)}, + new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(new HashMap())}, + // null hostile + new Object[]{"EnumMap", new EnumMap(IntegerEnum.class)}, + new Object[]{"Hashtable", new Hashtable()}, + new Object[]{"TreeMap", new TreeMap()}, + new Object[]{"ConcurrentHashMap", new ConcurrentHashMap()}, + new Object[]{"ConcurrentSkipListMap", new ConcurrentSkipListMap()}, + new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(new ConcurrentHashMap(), IntegerEnum.class, String.class)}, + new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(new EnumMap(IntegerEnum.class))}, + // filled + new Object[]{"HashMap", fillMap(new HashMap())}, + new Object[]{"LinkedHashMap", fillMap(new LinkedHashMap())}, + new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(fillMap(new HashMap()), IntegerEnum.class, String.class)}, + new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(fillMap(new HashMap()))}, + // null hostile + new Object[]{"EnumMap", fillMap(new EnumMap(IntegerEnum.class))}, + new Object[]{"Hashtable", fillMap(new Hashtable())}, + new Object[]{"TreeMap", fillMap(new TreeMap())}, + new Object[]{"ConcurrentHashMap", fillMap(new ConcurrentHashMap())}, + new Object[]{"ConcurrentSkipListMap", fillMap(new ConcurrentSkipListMap())}, + new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(fillMap(new ConcurrentHashMap()), IntegerEnum.class, String.class)}, + new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(fillMap(new EnumMap(IntegerEnum.class)))}).iterator(); + } + + private static Map<IntegerEnum, String> fillMap(Map<IntegerEnum, String> result) { + for (int each = 0; each < TEST_SIZE; each++) { + result.put(KEYS[each], VALUES[each]); + } + + return result; + } +}
--- a/test/java/util/Objects/BasicObjectsTest.java Fri Apr 12 10:42:50 2013 -0700 +++ b/test/java/util/Objects/BasicObjectsTest.java Tue Apr 16 01:44:58 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,13 @@ /* * @test - * @bug 6797535 6889858 6891113 + * @bug 6797535 6889858 6891113 8011800 * @summary Basic tests for methods in java.util.Objects * @author Joseph D. Darcy */ import java.util.*; +import java.util.function.*; public class BasicObjectsTest { public static void main(String... args) { @@ -40,7 +41,7 @@ errors += testToString(); errors += testToString2(); errors += testCompare(); - errors += testNonNull(); + errors += testRequireNonNull(); if (errors > 0 ) throw new RuntimeException(); } @@ -158,49 +159,54 @@ return errors; } - private static int testNonNull() { + private static int testRequireNonNull() { int errors = 0; - String s; + + final String RNN_1 = "1-arg requireNonNull"; + final String RNN_2 = "2-arg requireNonNull"; + final String RNN_3 = "Supplier requireNonNull"; + + Function<String, String> rnn1 = s -> Objects.requireNonNull(s); + Function<String, String> rnn2 = s -> Objects.requireNonNull(s, "trousers"); + Function<String, String> rnn3 = s -> Objects.requireNonNull(s, () -> "trousers"); - // Test 1-arg variant + errors += testRNN_NonNull(rnn1, RNN_1); + errors += testRNN_NonNull(rnn2, RNN_2); + errors += testRNN_NonNull(rnn3, RNN_3); + + errors += testRNN_Null(rnn1, RNN_1, null); + errors += testRNN_Null(rnn2, RNN_2, "trousers"); + errors += testRNN_Null(rnn3, RNN_3, "trousers"); + return errors; + } + + private static int testRNN_NonNull(Function<String, String> testFunc, + String testFuncName) { + int errors = 0; try { - s = Objects.requireNonNull("pants"); + String s = testFunc.apply("pants"); if (s != "pants") { - System.err.printf("1-arg non-null failed to return its arg"); + System.err.printf(testFuncName + " failed to return its arg"); errors++; } } catch (NullPointerException e) { - System.err.printf("1-arg nonNull threw unexpected NPE"); + System.err.printf(testFuncName + " threw unexpected NPE"); errors++; } + return errors; + } + private static int testRNN_Null(Function<String, String> testFunc, + String testFuncName, + String expectedMessage) { + int errors = 0; try { - s = Objects.requireNonNull(null); - System.err.printf("1-arg nonNull failed to throw NPE"); + String s = testFunc.apply(null); + System.err.printf(testFuncName + " failed to throw NPE"); errors++; } catch (NullPointerException e) { - // Expected - } - - // Test 2-arg variant - try { - s = Objects.requireNonNull("pants", "trousers"); - if (s != "pants") { - System.err.printf("2-arg nonNull failed to return its arg"); - errors++; - } - } catch (NullPointerException e) { - System.err.printf("2-arg nonNull threw unexpected NPE"); - errors++; - } - - try { - s = Objects.requireNonNull(null, "pantaloons"); - System.err.printf("2-arg nonNull failed to throw NPE"); - errors++; - } catch (NullPointerException e) { - if (e.getMessage() != "pantaloons") { - System.err.printf("2-arg nonNull threw NPE w/ bad detail msg"); + if (e.getMessage() != expectedMessage) { + System.err.printf(testFuncName + " threw NPE w/ bad detail msg"); errors++; } }
--- a/test/java/util/concurrent/CompletableFuture/Basic.java Fri Apr 12 10:42:50 2013 -0700 +++ b/test/java/util/concurrent/CompletableFuture/Basic.java Tue Apr 16 01:44:58 2013 -0700 @@ -486,40 +486,40 @@ CompletableFuture<Integer> cf1 = supplyAsync(() -> 1); CompletableFuture<Integer> cf2 = supplyAsync(() -> 2); cf3 = cf1.applyToEither(cf2, (x) -> { check(x == 1 || x == 2); return x; }); + checkCompletedNormally(cf3, new Object[] {1, 2}); check(cf1.isDone() || cf2.isDone()); - checkCompletedNormally(cf3, new Object[] {1, 2}); cf1 = supplyAsync(() -> 1); cf2 = supplyAsync(() -> 2); cf3 = cf1.applyToEitherAsync(cf2, (x) -> { check(x == 1 || x == 2); return x; }); + checkCompletedNormally(cf3, new Object[] {1, 2}); check(cf1.isDone() || cf2.isDone()); - checkCompletedNormally(cf3, new Object[] {1, 2}); cf1 = supplyAsync(() -> 1); cf2 = supplyAsync(() -> 2); cf3 = cf1.applyToEitherAsync(cf2, (x) -> { check(x == 1 || x == 2); return x; }, executor); + checkCompletedNormally(cf3, new Object[] {1, 2}); check(cf1.isDone() || cf2.isDone()); - checkCompletedNormally(cf3, new Object[] {1, 2}); cf1 = supplyAsync(() -> { throw new RuntimeException(); }); cf2 = supplyAsync(() -> 2); cf3 = cf1.applyToEither(cf2, (x) -> { check(x == 2); return x; }); - check(cf1.isDone() || cf2.isDone()); try { check(cf3.join() == 1); } catch (CompletionException x) { pass(); } check(cf3.isDone()); + check(cf1.isDone() || cf2.isDone()); cf1 = supplyAsync(() -> 1); cf2 = supplyAsync(() -> { throw new RuntimeException(); }); cf3 = cf1.applyToEitherAsync(cf2, (x) -> { check(x == 1); return x; }); - check(cf1.isDone() || cf2.isDone()); try { check(cf3.join() == 1); } catch (CompletionException x) { pass(); } check(cf3.isDone()); + check(cf1.isDone() || cf2.isDone()); cf1 = supplyAsync(() -> { throw new RuntimeException(); }); cf2 = supplyAsync(() -> { throw new RuntimeException(); }); cf3 = cf1.applyToEitherAsync(cf2, (x) -> { fail(); return x; }); + checkCompletedExceptionally(cf3); check(cf1.isDone() || cf2.isDone()); - checkCompletedExceptionally(cf3); } catch (Throwable t) { unexpected(t); } //---------------------------------------------------------------- @@ -531,45 +531,45 @@ CompletableFuture<Integer> cf1 = supplyAsync(() -> 1); CompletableFuture<Integer> cf2 = supplyAsync(() -> 2); cf3 = cf1.acceptEither(cf2, (x) -> { check(x == 1 || x == 2); atomicInt.incrementAndGet(); }); + checkCompletedNormally(cf3, null); check(cf1.isDone() || cf2.isDone()); - checkCompletedNormally(cf3, null); check(atomicInt.get() == (before + 1)); before = atomicInt.get(); cf1 = supplyAsync(() -> 1); cf2 = supplyAsync(() -> 2); cf3 = cf1.acceptEitherAsync(cf2, (x) -> { check(x == 1 || x == 2); atomicInt.incrementAndGet(); }); + checkCompletedNormally(cf3, null); check(cf1.isDone() || cf2.isDone()); - checkCompletedNormally(cf3, null); check(atomicInt.get() == (before + 1)); before = atomicInt.get(); cf1 = supplyAsync(() -> 1); cf2 = supplyAsync(() -> 2); cf3 = cf2.acceptEitherAsync(cf1, (x) -> { check(x == 1 || x == 2); atomicInt.incrementAndGet(); }, executor); + checkCompletedNormally(cf3, null); check(cf1.isDone() || cf2.isDone()); - checkCompletedNormally(cf3, null); check(atomicInt.get() == (before + 1)); cf1 = supplyAsync(() -> { throw new RuntimeException(); }); cf2 = supplyAsync(() -> 2); cf3 = cf2.acceptEitherAsync(cf1, (x) -> { check(x == 2); }, executor); - check(cf1.isDone() || cf2.isDone()); try { check(cf3.join() == null); } catch (CompletionException x) { pass(); } check(cf3.isDone()); + check(cf1.isDone() || cf2.isDone()); cf1 = supplyAsync(() -> 1); cf2 = supplyAsync(() -> { throw new RuntimeException(); }); cf3 = cf2.acceptEitherAsync(cf1, (x) -> { check(x == 1); }); - check(cf1.isDone() || cf2.isDone()); try { check(cf3.join() == null); } catch (CompletionException x) { pass(); } check(cf3.isDone()); + check(cf1.isDone() || cf2.isDone()); cf1 = supplyAsync(() -> { throw new RuntimeException(); }); cf2 = supplyAsync(() -> { throw new RuntimeException(); }); cf3 = cf2.acceptEitherAsync(cf1, (x) -> { fail(); }); + checkCompletedExceptionally(cf3); check(cf1.isDone() || cf2.isDone()); - checkCompletedExceptionally(cf3); } catch (Throwable t) { unexpected(t); } //---------------------------------------------------------------- @@ -581,50 +581,50 @@ CompletableFuture<Void> cf1 = runAsync(() -> { }); CompletableFuture<Void> cf2 = runAsync(() -> { }); cf3 = cf1.runAfterEither(cf2, () -> { atomicInt.incrementAndGet(); }); + checkCompletedNormally(cf3, null); check(cf1.isDone() || cf2.isDone()); - checkCompletedNormally(cf3, null); check(atomicInt.get() == (before + 1)); before = atomicInt.get(); cf1 = runAsync(() -> { }); cf2 = runAsync(() -> { }); cf3 = cf1.runAfterEitherAsync(cf2, () -> { atomicInt.incrementAndGet(); }); + checkCompletedNormally(cf3, null); check(cf1.isDone() || cf2.isDone()); - checkCompletedNormally(cf3, null); check(atomicInt.get() == (before + 1)); before = atomicInt.get(); cf1 = runAsync(() -> { }); cf2 = runAsync(() -> { }); cf3 = cf2.runAfterEitherAsync(cf1, () -> { atomicInt.incrementAndGet(); }, executor); + checkCompletedNormally(cf3, null); check(cf1.isDone() || cf2.isDone()); - checkCompletedNormally(cf3, null); check(atomicInt.get() == (before + 1)); before = atomicInt.get(); cf1 = runAsync(() -> { throw new RuntimeException(); }); cf2 = runAsync(() -> { }); cf3 = cf2.runAfterEither(cf1, () -> { atomicInt.incrementAndGet(); }); - check(cf1.isDone() || cf2.isDone()); try { check(cf3.join() == null); } catch (CompletionException x) { pass(); } check(cf3.isDone()); + check(cf1.isDone() || cf2.isDone()); check(atomicInt.get() == (before + 1)); before = atomicInt.get(); cf1 = runAsync(() -> { }); cf2 = runAsync(() -> { throw new RuntimeException(); }); cf3 = cf1.runAfterEitherAsync(cf2, () -> { atomicInt.incrementAndGet(); }); - check(cf1.isDone() || cf2.isDone()); try { check(cf3.join() == null); } catch (CompletionException x) { pass(); } check(cf3.isDone()); + check(cf1.isDone() || cf2.isDone()); check(atomicInt.get() == (before + 1)); before = atomicInt.get(); cf1 = runAsync(() -> { throw new RuntimeException(); }); cf2 = runAsync(() -> { throw new RuntimeException(); }); cf3 = cf2.runAfterEitherAsync(cf1, () -> { atomicInt.incrementAndGet(); }, executor); + checkCompletedExceptionally(cf3); check(cf1.isDone() || cf2.isDone()); - checkCompletedExceptionally(cf3); check(atomicInt.get() == before); } catch (Throwable t) { unexpected(t); } @@ -670,16 +670,16 @@ //---------------------------------------------------------------- // anyOf tests //---------------------------------------------------------------- - //try { - // CompletableFuture<Object> cf3; - // for (int k=0; k < 10; k++){ - // CompletableFuture<Integer> cf1 = supplyAsync(() -> 1); - // CompletableFuture<Integer> cf2 = supplyAsync(() -> 2); - // cf3 = CompletableFuture.anyOf(cf1, cf2); - // check(cf1.isDone() || cf2.isDone()); - // checkCompletedNormally(cf3, new Object[] {1, 2}); - // } - //} catch (Throwable t) { unexpected(t); } + try { + CompletableFuture<Object> cf3; + for (int k=0; k < 10; k++){ + CompletableFuture<Integer> cf1 = supplyAsync(() -> 1); + CompletableFuture<Integer> cf2 = supplyAsync(() -> 2); + cf3 = CompletableFuture.anyOf(cf1, cf2); + checkCompletedNormally(cf3, new Object[] {1, 2}); + check(cf1.isDone() || cf2.isDone()); + } + } catch (Throwable t) { unexpected(t); } //---------------------------------------------------------------- // allOf tests