* Specifically, execution proceeds as if by the following steps,
* although the methods are not guaranteed to be called if the JVM
@@ -590,10 +608,10 @@ public abstract class MethodHandle {
* or forced to null if the return type is void.
*
* Unlike the signature polymorphic methods {@code invokeExact} and {@code invoke},
* {@code invokeWithArguments} can be accessed normally via the Core Reflection API and JNI.
@@ -626,7 +644,7 @@ public abstract class MethodHandle {
*
+ * If, when the adapter is called, the supplied array argument does
+ * not have the correct number of elements, the adapter will throw
+ * an {@link IllegalArgumentException} instead of invoking the target.
+ *
* Here are some simple examples of array-spreading method handles:
*
{@code
MethodHandle equals = publicLookup()
@@ -782,6 +818,12 @@ assert(!(boolean) equals.invokeExact("me", (Object)"thee"));
MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
+// try to spread from anything but a 2-array:
+for (int n = 0; n <= 10; n++) {
+ Object[] badArityArgs = (n == 2 ? null : new Object[n]);
+ try { assert((boolean) eq2.invokeExact(badArityArgs) && false); }
+ catch (IllegalArgumentException ex) { } // OK
+}
// spread both arguments from a String array:
MethodHandle eq2s = equals.asSpreader(String[].class, 2);
assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));
@@ -815,10 +857,12 @@ assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray
* @return a new method handle which spreads its final array argument,
* before calling the original method handle
* @throws NullPointerException if {@code arrayType} is a null reference
- * @throws IllegalArgumentException if {@code arrayType} is not an array type
- * @throws IllegalArgumentException if target does not have at least
+ * @throws IllegalArgumentException if {@code arrayType} is not an array type,
+ * or if target does not have at least
* {@code arrayLength} parameter types,
- * or if {@code arrayLength} is negative
+ * or if {@code arrayLength} is negative,
+ * or if the resulting method handle's type would have
+ * too many parameters
* @throws WrongMethodTypeException if the implied {@code asType} call fails
* @see #asCollector
*/
@@ -931,7 +975,9 @@ assertEquals("[123]", (String) longsToString.invokeExact((long)123));
* @throws NullPointerException if {@code arrayType} is a null reference
* @throws IllegalArgumentException if {@code arrayType} is not an array type
* or {@code arrayType} is not assignable to this method handle's trailing parameter type,
- * or {@code arrayLength} is not a legal array size
+ * or {@code arrayLength} is not a legal array size,
+ * or the resulting method handle's type would have
+ * too many parameters
* @throws WrongMethodTypeException if the implied {@code asType} call fails
* @see #asSpreader
* @see #asVarargsCollector
@@ -1226,9 +1272,9 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
* starting with the string {@code "MethodHandle"} and
* ending with the string representation of the method handle's type.
* In other words, this method returns a string equal to the value of:
- *
+ * {@code
* "MethodHandle" + type().toString()
- *
+ * }
*
* (Note: Future releases of this API may add further information
* to the string representation.
@@ -1284,6 +1330,11 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
return null; // DMH returns DMH.member
}
+ /*non-public*/
+ Class> internalCallerClass() {
+ return null; // caller-bound MH for @CallerSensitive method returns caller
+ }
+
/*non-public*/
MethodHandle withInternalMemberName(MemberName member) {
if (member != null) {
@@ -1434,7 +1485,6 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
* Threads may continue running the old form indefinitely,
* but it is likely that the new one will be preferred for new executions.
* Use with discretion.
- * @param newForm
*/
/*non-public*/
void updateForm(LambdaForm newForm) {
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
index 5ab7f7adb7b..0d6ed2da06a 100644
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
@@ -314,13 +314,13 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static class AsVarargsCollector extends MethodHandle {
private final MethodHandle target;
private final Class> arrayType;
- private MethodHandle cache;
+ private /*@Stable*/ MethodHandle asCollectorCache;
AsVarargsCollector(MethodHandle target, MethodType type, Class> arrayType) {
super(type, reinvokerForm(target));
this.target = target;
this.arrayType = arrayType;
- this.cache = target.asCollector(arrayType, 0);
+ this.asCollectorCache = target.asCollector(arrayType, 0);
}
@Override MethodHandle reinvokerTarget() { return target; }
@@ -336,18 +336,19 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
@Override
- public MethodHandle asType(MethodType newType) {
+ public MethodHandle asTypeUncached(MethodType newType) {
MethodType type = this.type();
int collectArg = type.parameterCount() - 1;
int newArity = newType.parameterCount();
if (newArity == collectArg+1 &&
type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) {
// if arity and trailing parameter are compatible, do normal thing
- return asFixedArity().asType(newType);
+ return asTypeCache = asFixedArity().asType(newType);
}
// check cache
- if (cache.type().parameterCount() == newArity)
- return cache.asType(newType);
+ MethodHandle acc = asCollectorCache;
+ if (acc != null && acc.type().parameterCount() == newArity)
+ return asTypeCache = acc.asType(newType);
// build and cache a collector
int arrayLength = newArity - collectArg;
MethodHandle collector;
@@ -357,8 +358,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} catch (IllegalArgumentException ex) {
throw new WrongMethodTypeException("cannot build collector", ex);
}
- cache = collector;
- return collector.asType(newType);
+ asCollectorCache = collector;
+ return asTypeCache = collector.asType(newType);
}
@Override
@@ -380,6 +381,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MemberName internalMemberName() {
return asFixedArity().internalMemberName();
}
+ @Override
+ Class> internalCallerClass() {
+ return asFixedArity().internalCallerClass();
+ }
/*non-public*/
@Override
@@ -435,7 +440,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
// Spread the array.
MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType);
Name array = names[argIndex];
- names[nameCursor++] = new Name(NF_checkSpreadArgument, array, spreadArgCount);
+ names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount);
for (int j = 0; j < spreadArgCount; i++, j++) {
indexes[i] = nameCursor;
names[nameCursor++] = new Name(aload, array, j);
@@ -459,14 +464,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
static void checkSpreadArgument(Object av, int n) {
- // FIXME: regression test for bug 7141637 erroneously expects an NPE, and other tests may expect IAE
- // but the actual exception raised by an arity mismatch should be WMTE
- final boolean RAISE_RANDOM_EXCEPTIONS = true; // FIXME: delete in JSR 292 M1
if (av == null) {
if (n == 0) return;
- int len;
- if (RAISE_RANDOM_EXCEPTIONS)
- len = ((Object[])av).length; // throw NPE; but delete this after tests are fixed
} else if (av instanceof Object[]) {
int len = ((Object[])av).length;
if (len == n) return;
@@ -475,19 +474,23 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
if (len == n) return;
}
// fall through to error:
- if (RAISE_RANDOM_EXCEPTIONS)
- throw newIllegalArgumentException("Array is not of length "+n);
- throw new WrongMethodTypeException("Array is not of length "+n);
+ throw newIllegalArgumentException("array is not of length "+n);
}
- private static final NamedFunction NF_checkSpreadArgument;
- static {
- try {
- NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
- .getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
- NF_checkSpreadArgument.resolve();
- } catch (ReflectiveOperationException ex) {
- throw newInternalError(ex);
+ /**
+ * Pre-initialized NamedFunctions for bootstrapping purposes.
+ * Factored in an inner class to delay initialization until first usage.
+ */
+ private static class Lazy {
+ static final NamedFunction NF_checkSpreadArgument;
+ static {
+ try {
+ NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
+ .getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
+ NF_checkSpreadArgument.resolve();
+ } catch (ReflectiveOperationException ex) {
+ throw newInternalError(ex);
+ }
}
}
@@ -832,7 +835,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle vamh = prepareForInvoker(mh);
// Cache the result of makeInjectedInvoker once per argument class.
MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
- return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName());
+ return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass);
}
private static MethodHandle makeInjectedInvoker(Class> hostClass) {
@@ -887,10 +890,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
// Undo the adapter effect of prepareForInvoker:
- private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, MemberName member) {
+ private static MethodHandle restoreToType(MethodHandle vamh, MethodType type,
+ MemberName member,
+ Class> hostClass) {
MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
mh = mh.asType(type);
- mh = mh.withInternalMemberName(member);
+ mh = new WrappedMember(mh, type, member, hostClass);
return mh;
}
@@ -959,11 +964,13 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static class WrappedMember extends MethodHandle {
private final MethodHandle target;
private final MemberName member;
+ private final Class> callerClass;
- private WrappedMember(MethodHandle target, MethodType type, MemberName member) {
+ private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class> callerClass) {
super(type, reinvokerForm(target));
this.target = target;
this.member = member;
+ this.callerClass = callerClass;
}
@Override
@@ -971,23 +978,33 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return target;
}
@Override
+ public MethodHandle asTypeUncached(MethodType newType) {
+ // This MH is an alias for target, except for the MemberName
+ // Drop the MemberName if there is any conversion.
+ return asTypeCache = target.asType(newType);
+ }
+ @Override
MemberName internalMemberName() {
return member;
}
@Override
+ Class> internalCallerClass() {
+ return callerClass;
+ }
+ @Override
boolean isInvokeSpecial() {
return target.isInvokeSpecial();
}
@Override
MethodHandle viewAsType(MethodType newType) {
- return new WrappedMember(target, newType, member);
+ return new WrappedMember(target, newType, member, callerClass);
}
}
static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) {
if (member.equals(target.internalMemberName()))
return target;
- return new WrappedMember(target, target.type(), member);
+ return new WrappedMember(target, target.type(), member, null);
}
}
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java
index 72fd8e91035..d63db84b421 100644
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java
@@ -32,9 +32,10 @@ import java.lang.invoke.MethodHandles.Lookup;
import static java.lang.invoke.MethodHandleStatics.*;
/**
- * A symbolic reference obtained by cracking a method handle into its consitutent symbolic parts.
+ * A symbolic reference obtained by cracking a direct method handle
+ * into its consitutent symbolic parts.
* To crack a direct method handle, call {@link Lookup#revealDirect Lookup.revealDirect}.
- *
+ *
Direct Method Handles
* A direct method handle represents a method, constructor, or field without
* any intervening argument bindings or other transformations.
* The method, constructor, or field referred to by a direct method handle is called
@@ -56,11 +57,25 @@ import static java.lang.invoke.MethodHandleStatics.*;
* or {@link Lookup#unreflectSetter Lookup.unreflectSetter}
* to convert a {@link Field} into a method handle.
*
- * In all of these cases, it is possible to crack the resulting direct method handle
+ *
+ * Restrictions on Cracking
+ * Given a suitable {@code Lookup} object, it is possible to crack any direct method handle
* to recover a symbolic reference for the underlying method, constructor, or field.
* Cracking must be done via a {@code Lookup} object equivalent to that which created
* the target method handle, or which has enough access permissions to recreate
* an equivalent method handle.
+ *
+ * If the underlying method is caller sensitive,
+ * the direct method handle will have been "bound" to a particular caller class, the
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#lookupClass() lookup class}
+ * of the lookup object used to create it.
+ * Cracking this method handle with a different lookup class will fail
+ * even if the underlying method is public (like {@code Class.forName}).
+ *
+ * The requirement of lookup object matching provides a "fast fail" behavior
+ * for programs which may otherwise trust erroneous revelation of a method
+ * handle with symbolic information (or caller binding) from an unexpected scope.
+ * Use {@link java.lang.invoke.MethodHandles#reflectAs} to override this limitation.
*
*
Reference kinds
* The Lookup Factory Methods
@@ -190,7 +205,7 @@ interface MethodHandleInfo {
* @return the Java language modifiers for underlying member,
* or -1 if the member cannot be accessed
* @see Modifier
- * @see reflectAs
+ * @see #reflectAs
*/
public int getModifiers();
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
index 4f83e82158c..56cb245e6ae 100644
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -233,20 +233,19 @@ class MethodHandleNatives {
}
static String refKindName(byte refKind) {
assert(refKindIsValid(refKind));
- return REFERENCE_KIND_NAME[refKind];
+ switch (refKind) {
+ case REF_getField: return "getField";
+ case REF_getStatic: return "getStatic";
+ case REF_putField: return "putField";
+ case REF_putStatic: return "putStatic";
+ case REF_invokeVirtual: return "invokeVirtual";
+ case REF_invokeStatic: return "invokeStatic";
+ case REF_invokeSpecial: return "invokeSpecial";
+ case REF_newInvokeSpecial: return "newInvokeSpecial";
+ case REF_invokeInterface: return "invokeInterface";
+ default: return "REF_???";
+ }
}
- private static String[] REFERENCE_KIND_NAME = {
- null,
- "getField",
- "getStatic",
- "putField",
- "putStatic",
- "invokeVirtual",
- "invokeStatic",
- "invokeSpecial",
- "newInvokeSpecial",
- "invokeInterface"
- };
private static native int getNamedCon(int which, Object[] name);
static boolean verifyConstants() {
@@ -294,12 +293,18 @@ class MethodHandleNatives {
Class> caller = (Class>)callerObj;
String name = nameObj.toString().intern();
MethodType type = (MethodType)typeObj;
- appendixResult[0] = CallSite.makeSite(bootstrapMethod,
+ CallSite callSite = CallSite.makeSite(bootstrapMethod,
name,
type,
staticArguments,
caller);
- return Invokers.linkToCallSiteMethod(type);
+ if (callSite instanceof ConstantCallSite) {
+ appendixResult[0] = callSite.dynamicInvoker();
+ return Invokers.linkToTargetMethod(type);
+ } else {
+ appendixResult[0] = callSite;
+ return Invokers.linkToCallSiteMethod(type);
+ }
}
/**
@@ -388,12 +393,7 @@ class MethodHandleNatives {
Object[] appendixResult) {
try {
if (defc == MethodHandle.class && refKind == REF_invokeVirtual) {
- switch (name) {
- case "invoke":
- return Invokers.genericInvokerMethod(fixMethodType(callerClass, type), appendixResult);
- case "invokeExact":
- return Invokers.exactInvokerMethod(fixMethodType(callerClass, type), appendixResult);
- }
+ return Invokers.methodHandleInvokeLinkerMethod(name, fixMethodType(callerClass, type), appendixResult);
}
} catch (Throwable ex) {
if (ex instanceof LinkageError)
@@ -440,13 +440,33 @@ class MethodHandleNatives {
Lookup lookup = IMPL_LOOKUP.in(callerClass);
assert(refKindIsValid(refKind));
return lookup.linkMethodHandleConstant((byte) refKind, defc, name, type);
+ } catch (IllegalAccessException ex) {
+ Error err = new IllegalAccessError(ex.getMessage());
+ throw initCauseFrom(err, ex);
+ } catch (NoSuchMethodException ex) {
+ Error err = new NoSuchMethodError(ex.getMessage());
+ throw initCauseFrom(err, ex);
+ } catch (NoSuchFieldException ex) {
+ Error err = new NoSuchFieldError(ex.getMessage());
+ throw initCauseFrom(err, ex);
} catch (ReflectiveOperationException ex) {
Error err = new IncompatibleClassChangeError();
- err.initCause(ex);
- throw err;
+ throw initCauseFrom(err, ex);
}
}
+ /**
+ * Use best possible cause for err.initCause(), substituting the
+ * cause for err itself if the cause has the same (or better) type.
+ */
+ static private Error initCauseFrom(Error err, Exception ex) {
+ Throwable th = ex.getCause();
+ if (err.getClass().isInstance(th))
+ return (Error) th;
+ err.initCause(th == null ? ex : th);
+ return err;
+ }
+
/**
* Is this method a caller-sensitive method?
* I.e., does it call Reflection.getCallerClass or a similer method
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java
index 246160cabaf..13b1d21acd4 100644
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java
@@ -107,6 +107,11 @@ public class MethodHandleProxies {
* such as abstract classes with single abstract methods.
* Future versions of this API may also equip wrapper instances
* with one or more additional public "marker" interfaces.
+ *
+ * If a security manager is installed, this method is caller sensitive.
+ * During any invocation of the target method handle via the returned wrapper,
+ * the original creator of the wrapper (the caller) will be visible
+ * to context checks requested by the security manager.
*
* @param the desired type of the wrapper, a single-method interface
* @param intfc a class object representing {@code T}
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java
index f0f9447e001..369d14b21f4 100644
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java
@@ -39,6 +39,7 @@ import sun.reflect.misc.ReflectUtil;
import sun.security.util.SecurityConstants;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
+import java.util.concurrent.ConcurrentHashMap;
import sun.security.util.SecurityConstants;
/**
@@ -48,7 +49,6 @@ import sun.security.util.SecurityConstants;
* Lookup methods which help create method handles for methods and fields.
* Combinator methods, which combine or transform pre-existing method handles into new ones.
* Other factory methods to create method handles that emulate other common JVM operations or control flow patterns.
- * Wrapper methods which can convert between method handles and interface types.
*
*
* @author John Rose, JSR 292 EG
@@ -65,12 +65,25 @@ public class MethodHandles {
//// Method handle creation from ordinary methods.
/**
- * Returns a {@link Lookup lookup object} on the caller,
- * which has the capability to access any method handle that the caller has access to,
- * including direct method handles to private fields and methods.
+ * Returns a {@link Lookup lookup object} with
+ * full capabilities to emulate all supported bytecode behaviors of the caller.
+ * These capabilities include private access to the caller.
+ * Factory methods on the lookup object can create
+ * direct method handles
+ * for any member that the caller has access to via bytecodes,
+ * including protected and private fields and methods.
* This lookup object is a capability which may be delegated to trusted agents.
* Do not store it in place where untrusted code can access it.
- * @return a lookup object for the caller of this method
+ *
+ * This method is caller sensitive, which means that it may return different
+ * values to different callers.
+ *
+ * For any given caller class {@code C}, the lookup object returned by this call
+ * has equivalent capabilities to any lookup object
+ * supplied by the JVM to the bootstrap method of an
+ * invokedynamic instruction
+ * executing in the same caller class {@code C}.
+ * @return a lookup object for the caller of this method, with private access
*/
@CallerSensitive
public static Lookup lookup() {
@@ -84,11 +97,17 @@ public class MethodHandles {
*
* As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
* of this lookup object will be {@link java.lang.Object}.
- *
+ *
+ *
+ * Discussion:
* The lookup class can be changed to any other class {@code C} using an expression of the form
- * {@linkplain Lookup#in publicLookup().in(C.class)}.
+ * {@link Lookup#in publicLookup().in(C.class)}.
* Since all classes have equal access to public names,
* such a change would confer no new access rights.
+ * A public lookup object is always subject to
+ * security manager checks.
+ * Also, it cannot access
+ * caller sensitive methods.
* @return a lookup object which is trusted minimally
*/
public static Lookup publicLookup() {
@@ -96,7 +115,8 @@ public class MethodHandles {
}
/**
- * Performs an unchecked "crack" of a direct method handle.
+ * Performs an unchecked "crack" of a
+ * direct method handle.
* The result is as if the user had obtained a lookup object capable enough
* to crack the target method handle, called
* {@link java.lang.invoke.MethodHandles.Lookup#revealDirect Lookup.revealDirect}
@@ -149,10 +169,17 @@ public class MethodHandles {
*
Lookup Factory Methods
* The factory methods on a {@code Lookup} object correspond to all major
* use cases for methods, constructors, and fields.
+ * Each method handle created by a factory method is the functional
+ * equivalent of a particular bytecode behavior.
+ * (Bytecode behaviors are described in section 5.4.3.5 of the Java Virtual Machine Specification.)
* Here is a summary of the correspondence between these factory methods and
* the behavior the resulting method handles:
*
- * | lookup expression | member | behavior |
+ *
+ * | lookup expression |
+ * member |
+ * bytecode behavior |
+ *
*
* | {@link java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)} |
* {@code FT f;} | {@code (T) this.f;} |
@@ -228,10 +255,12 @@ public class MethodHandles {
* In cases where the given member is of variable arity (i.e., a method or constructor)
* the returned method handle will also be of {@linkplain MethodHandle#asVarargsCollector variable arity}.
* In all other cases, the returned method handle will be of fixed arity.
- *
+ *
+ * Discussion:
* The equivalence between looked-up method handles and underlying
- * class members can break down in a few ways:
- *
+ * class members and bytecode behaviors
+ * can break down in a few ways:
+ *
* - If {@code C} is not symbolically accessible from the lookup class's loader,
* the lookup can still succeed, even when there is no equivalent
* Java expression or bytecoded constant.
@@ -241,9 +270,13 @@ public class MethodHandles {
* For example, lookups for {@code MethodHandle.invokeExact} and
* {@code MethodHandle.invoke} will always succeed, regardless of requested type.
*
- If there is a security manager installed, it can forbid the lookup
- * on various grounds (see below).
- * By contrast, the {@code ldc} instruction is not subject to
- * security manager checks.
+ * on various grounds (see below).
+ * By contrast, the {@code ldc} instruction on a {@code CONSTANT_MethodHandle}
+ * constant is not subject to security manager checks.
+ *
- If the looked-up method has a
+ * very large arity,
+ * the method handle creation may fail, due to the method handle
+ * type having too many parameters.
*
*
* Access checking
@@ -271,7 +304,8 @@ public class MethodHandles {
* A lookup can fail, because
* the containing class is not accessible to the lookup class, or
* because the desired class member is missing, or because the
- * desired class member is not accessible to the lookup class.
+ * desired class member is not accessible to the lookup class, or
+ * because the lookup object is not trusted enough to access the member.
* In any of these cases, a {@code ReflectiveOperationException} will be
* thrown from the attempted lookup. The exact class will be one of
* the following:
@@ -282,11 +316,23 @@ public class MethodHandles {
*
*
* In general, the conditions under which a method handle may be
- * looked up for a method {@code M} are exactly equivalent to the conditions
- * under which the lookup class could have compiled and resolved a call to {@code M}.
+ * looked up for a method {@code M} are no more restrictive than the conditions
+ * under which the lookup class could have compiled, verified, and resolved a call to {@code M}.
+ * Where the JVM would raise exceptions like {@code NoSuchMethodError},
+ * a method handle lookup will generally raise a corresponding
+ * checked exception, such as {@code NoSuchMethodException}.
* And the effect of invoking the method handle resulting from the lookup
- * is exactly equivalent to executing the compiled and resolved call to {@code M}.
+ * is exactly equivalent
+ * to executing the compiled, verified, and resolved call to {@code M}.
* The same point is true of fields and constructors.
+ *
+ * Discussion:
+ * Access checks only apply to named and reflected methods,
+ * constructors, and fields.
+ * Other method handle creation methods, such as
+ * {@link MethodHandle#asType MethodHandle.asType},
+ * do not require any access checks, and are used
+ * independently of any {@code Lookup} object.
*
* If the desired member is {@code protected}, the usual JVM rules apply,
* including the requirement that the lookup class must be either be in the
@@ -300,6 +346,18 @@ public class MethodHandles {
* (which will necessarily be a superclass of the lookup class)
* to the lookup class itself.
*
+ * The JVM imposes a similar requirement on {@code invokespecial} instruction,
+ * that the receiver argument must match both the resolved method and
+ * the current class. Again, this requirement is enforced by narrowing the
+ * type of the leading parameter to the resulting method handle.
+ * (See the Java Virtual Machine Specification, section 4.10.1.9.)
+ *
+ * The JVM represents constructors and static initializer blocks as internal methods
+ * with special names ({@code ""} and {@code ""}).
+ * The internal syntax of invocation instructions allows them to refer to such internal
+ * methods as if they were normal methods, but the JVM bytecode verifier rejects them.
+ * A lookup of such an internal method will produce a {@code NoSuchMethodException}.
+ *
* In some cases, access between nested classes is obtained by the Java compiler by creating
* an wrapper method to access a private method of another class
* in the same top-level declaration.
@@ -313,6 +371,43 @@ public class MethodHandles {
* which can transform a lookup on {@code C.E} into one on any of those other
* classes, without special elevation of privilege.
*
+ * The accesses permitted to a given lookup object may be limited,
+ * according to its set of {@link #lookupModes lookupModes},
+ * to a subset of members normally accessible to the lookup class.
+ * For example, the {@link MethodHandles#publicLookup publicLookup}
+ * method produces a lookup object which is only allowed to access
+ * public members in public classes.
+ * The caller sensitive method {@link MethodHandles#lookup lookup}
+ * produces a lookup object with full capabilities relative to
+ * its caller class, to emulate all supported bytecode behaviors.
+ * Also, the {@link Lookup#in Lookup.in} method may produce a lookup object
+ * with fewer access modes than the original lookup object.
+ *
+ *
+ *
+ * Discussion of private access:
+ * We say that a lookup has private access
+ * if its {@linkplain #lookupModes lookup modes}
+ * include the possibility of accessing {@code private} members.
+ * As documented in the relevant methods elsewhere,
+ * only lookups with private access possess the following capabilities:
+ *
+ * - access private fields, methods, and constructors of the lookup class
+ *
- create method handles which invoke caller sensitive methods,
+ * such as {@code Class.forName}
+ *
- create method handles which {@link Lookup#findSpecial emulate invokespecial} instructions
+ *
- avoid package access checks
+ * for classes accessible to the lookup class
+ *
- create {@link Lookup#in delegated lookup objects} which have private access to other classes
+ * within the same package member
+ *
+ *
+ * Each of these permissions is a consequence of the fact that a lookup object
+ * with private access can be securely traced back to an originating class,
+ * whose bytecode behaviors and Java language access permissions
+ * can be reliably determined and emulated by method handles.
+ *
+ *
Security manager interactions
* Although bytecode instructions can only refer to classes in
* a related class loader, this API can search for methods in any
* class, as long as a reference to its {@code Class} object is
@@ -325,16 +420,6 @@ public class MethodHandles {
* and the Core Reflection API
* (as found on {@link java.lang.Class Class}).
*
- * Access checks only apply to named and reflected methods,
- * constructors, and fields.
- * Other method handle creation methods, such as
- * {@link MethodHandle#asType MethodHandle.asType},
- * do not require any access checks, and are done
- * with static methods of {@link MethodHandles},
- * independently of any {@code Lookup} object.
- *
- *
Security manager interactions
- *
* If a security manager is present, member lookups are subject to
* additional checks.
* From one to three calls are made to the security manager.
@@ -347,26 +432,79 @@ public class MethodHandles {
* member is actually defined.
* The value {@code lookc} is defined as not present
* if the current lookup object does not have
- * {@linkplain java.lang.invoke.MethodHandles.Lookup#PRIVATE private access}.
+ * private access.
* The calls are made according to the following rules:
*
- * - If {@code lookc} is not present, or if its class loader is not
+ *
- Step 1:
+ * If {@code lookc} is not present, or if its class loader is not
* the same as or an ancestor of the class loader of {@code refc},
* then {@link SecurityManager#checkPackageAccess
* smgr.checkPackageAccess(refcPkg)} is called,
* where {@code refcPkg} is the package of {@code refc}.
- *
- If the retrieved member is not public and
+ *
- Step 2:
+ * If the retrieved member is not public and
* {@code lookc} is not present, then
* {@link SecurityManager#checkPermission smgr.checkPermission}
* with {@code RuntimePermission("accessDeclaredMembers")} is called.
- *
- If the retrieved member is not public,
+ *
- Step 3:
+ * If the retrieved member is not public,
+ * and if {@code lookc} is not present,
* and if {@code defc} and {@code refc} are different,
* then {@link SecurityManager#checkPackageAccess
* smgr.checkPackageAccess(defcPkg)} is called,
* where {@code defcPkg} is the package of {@code defc}.
*
+ * Security checks are performed after other access checks have passed.
+ * Therefore, the above rules presuppose a member that is public,
+ * or else that is being accessed from a lookup class that has
+ * rights to access the member.
+ *
+ * Caller sensitive methods
+ * A small number of Java methods have a special property called caller sensitivity.
+ * A caller-sensitive method can behave differently depending on the
+ * identity of its immediate caller.
+ *
+ * If a method handle for a caller-sensitive method is requested,
+ * the general rules for bytecode behaviors apply,
+ * but they take account of the lookup class in a special way.
+ * The resulting method handle behaves as if it were called
+ * from an instruction contained in the lookup class,
+ * so that the caller-sensitive method detects the lookup class.
+ * (By contrast, the invoker of the method handle is disregarded.)
+ * Thus, in the case of caller-sensitive methods,
+ * different lookup classes may give rise to
+ * differently behaving method handles.
+ *
+ * In cases where the lookup object is
+ * {@link MethodHandles#publicLookup() publicLookup()},
+ * or some other lookup object without
+ * private access,
+ * the lookup class is disregarded.
+ * In such cases, no caller-sensitive method handle can be created,
+ * access is forbidden, and the lookup fails with an
+ * {@code IllegalAccessException}.
+ *
+ * Discussion:
+ * For example, the caller-sensitive method
+ * {@link java.lang.Class#forName(String) Class.forName(x)}
+ * can return varying classes or throw varying exceptions,
+ * depending on the class loader of the class that calls it.
+ * A public lookup of {@code Class.forName} will fail, because
+ * there is no reasonable way to determine its bytecode behavior.
+ *
+ * If an application caches method handles for broad sharing,
+ * it should use {@code publicLookup()} to create them.
+ * If there is a lookup of {@code Class.forName}, it will fail,
+ * and the application must take appropriate action in that case.
+ * It may be that a later lookup, perhaps during the invocation of a
+ * bootstrap method, can incorporate the specific identity
+ * of the caller, making the method accessible.
+ *
+ * The function {@code MethodHandles.lookup} is caller sensitive
+ * so that there can be a secure foundation for lookups.
+ * Nearly all other methods in the JSR 292 API rely on lookup
+ * objects to check access requests.
*/
- // FIXME in MR1: clarify that the bytecode behavior of a caller-ID method (like Class.forName) is relative to the lookupClass used to create the method handle, not the dynamic caller of the method handle
public static final
class Lookup {
/** The class on behalf of whom the lookup is being performed. */
@@ -592,13 +730,23 @@ public class MethodHandles {
* (Since static methods do not take receivers, there is no
* additional receiver argument inserted into the method handle type,
* as there would be with {@link #findVirtual findVirtual} or {@link #findSpecial findSpecial}.)
- * The method and all its argument types must be accessible to the lookup class.
- * If the method's class has not yet been initialized, that is done
- * immediately, before the method handle is returned.
+ * The method and all its argument types must be accessible to the lookup object.
*
* The returned method handle will have
* {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
* the method's variable arity modifier bit ({@code 0x0080}) is set.
+ *
+ * If the returned method handle is invoked, the method's class will
+ * be initialized, if it has not already been initialized.
+ *
Example:
+ *
{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,
+ "asList", methodType(List.class, Object[].class));
+assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
+ * }
* @param refc the class from which the method is accessed
* @param name the name of the method
* @param type the type of the method
@@ -615,7 +763,6 @@ public class MethodHandles {
public
MethodHandle findStatic(Class> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
- checkSecurityManager(refc, method);
return getDirectMethod(REF_invokeStatic, refc, method, findBoundCallerClass(method));
}
@@ -623,7 +770,7 @@ public class MethodHandles {
* Produces a method handle for a virtual method.
* The type of the method handle will be that of the method,
* with the receiver type (usually {@code refc}) prepended.
- * The method and all its argument types must be accessible to the lookup class.
+ * The method and all its argument types must be accessible to the lookup object.
*
* When called, the handle will treat the first argument as a receiver
* and dispatch on the receiver's type to determine which method
@@ -640,7 +787,7 @@ public class MethodHandles {
* {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
* the method's variable arity modifier bit ({@code 0x0080}) is set.
*
- * Because of the general equivalence between {@code invokevirtual}
+ * Because of the general equivalence between {@code invokevirtual}
* instructions and method handles produced by {@code findVirtual},
* if the class is {@code MethodHandle} and the name string is
* {@code invokeExact} or {@code invoke}, the resulting
@@ -649,6 +796,34 @@ public class MethodHandles {
* {@link java.lang.invoke.MethodHandles#invoker MethodHandles.invoker}
* with the same {@code type} argument.
*
+ * Example:
+ *
{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle MH_concat = publicLookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class,
+ "hashCode", methodType(int.class));
+MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class,
+ "hashCode", methodType(int.class));
+assertEquals("xy", (String) MH_concat.invokeExact("x", "y"));
+assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy"));
+assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy"));
+// interface method:
+MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class,
+ "subSequence", methodType(CharSequence.class, int.class, int.class));
+assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString());
+// constructor "internal method" must be accessed differently:
+MethodType MT_newString = methodType(void.class); //()V for new String()
+try { assertEquals("impossible", lookup()
+ .findVirtual(String.class, "", MT_newString));
+ } catch (NoSuchMethodException ex) { } // OK
+MethodHandle MH_newString = publicLookup()
+ .findConstructor(String.class, MT_newString);
+assertEquals("", (String) MH_newString.invokeExact());
+ * }
+ *
* @param refc the class or interface from which the method is accessed
* @param name the name of the method
* @param type the type of the method, with the receiver argument omitted
@@ -669,7 +844,6 @@ public class MethodHandles {
}
byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
MemberName method = resolveOrFail(refKind, refc, name, type);
- checkSecurityManager(refc, method);
return getDirectMethod(refKind, refc, method, findBoundCallerClass(method));
}
private MethodHandle findVirtualForMH(String name, MethodType type) {
@@ -687,16 +861,35 @@ public class MethodHandles {
* the constructor of the specified type.
* The parameter types of the method handle will be those of the constructor,
* while the return type will be a reference to the constructor's class.
- * The constructor and all its argument types must be accessible to the lookup class.
- * If the constructor's class has not yet been initialized, that is done
- * immediately, before the method handle is returned.
+ * The constructor and all its argument types must be accessible to the lookup object.
*
- * Note: The requested type must have a return type of {@code void}.
- * This is consistent with the JVM's treatment of constructor type descriptors.
+ * The requested type must have a return type of {@code void}.
+ * (This is consistent with the JVM's treatment of constructor type descriptors.)
*
* The returned method handle will have
* {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
* the constructor's variable arity modifier bit ({@code 0x0080}) is set.
+ *
+ * If the returned method handle is invoked, the constructor's class will
+ * be initialized, if it has not already been initialized.
+ *
Example:
+ *
{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle MH_newArrayList = publicLookup().findConstructor(
+ ArrayList.class, methodType(void.class, Collection.class));
+Collection orig = Arrays.asList("x", "y");
+Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
+assert(orig != copy);
+assertEquals(orig, copy);
+// a variable-arity constructor:
+MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
+ ProcessBuilder.class, methodType(void.class, String[].class));
+ProcessBuilder pb = (ProcessBuilder)
+ MH_newProcessBuilder.invoke("x", "y", "z");
+assertEquals("[x, y, z]", pb.command().toString());
+ * }
* @param refc the class or interface from which the method is accessed
* @param type the type of the method, with the receiver argument omitted, and a void return type
* @return the desired method handle
@@ -711,31 +904,68 @@ public class MethodHandles {
public MethodHandle findConstructor(Class> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
String name = "";
MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
- checkSecurityManager(refc, ctor);
return getDirectConstructor(refc, ctor);
}
/**
- * Produces an early-bound method handle for a virtual method,
- * as if called from an {@code invokespecial}
- * instruction from {@code caller}.
+ * Produces an early-bound method handle for a virtual method.
+ * It will bypass checks for overriding methods on the receiver,
+ * as if called from an {@code invokespecial}
+ * instruction from within the explicitly specified {@code specialCaller}.
* The type of the method handle will be that of the method,
- * with a suitably restricted receiver type (such as {@code caller}) prepended.
+ * with a suitably restricted receiver type prepended.
+ * (The receiver type will be {@code specialCaller} or a subtype.)
* The method and all its argument types must be accessible
- * to the caller.
+ * to the lookup object.
*
- * When called, the handle will treat the first argument as a receiver,
- * but will not dispatch on the receiver's type.
- * (This direct invocation action is identical with that performed by an
- * {@code invokespecial} instruction.)
- *
- * If the explicitly specified caller class is not identical with the
- * lookup class, or if this lookup object does not have private access
+ * Before method resolution,
+ * if the explicitly specified caller class is not identical with the
+ * lookup class, or if this lookup object does not have
+ * private access
* privileges, the access fails.
*
* The returned method handle will have
* {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
* the method's variable arity modifier bit ({@code 0x0080}) is set.
+ *
+ * (Note: JVM internal methods named {@code ""} are not visible to this API,
+ * even though the {@code invokespecial} instruction can refer to them
+ * in special circumstances. Use {@link #findConstructor findConstructor}
+ * to access instance initialization methods in a safe manner.)
+ *
Example:
+ *
{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+static class Listie extends ArrayList {
+ public String toString() { return "[wee Listie]"; }
+ static Lookup lookup() { return MethodHandles.lookup(); }
+}
+...
+// no access to constructor via invokeSpecial:
+MethodHandle MH_newListie = Listie.lookup()
+ .findConstructor(Listie.class, methodType(void.class));
+Listie l = (Listie) MH_newListie.invokeExact();
+try { assertEquals("impossible", Listie.lookup().findSpecial(
+ Listie.class, "", methodType(void.class), Listie.class));
+ } catch (NoSuchMethodException ex) { } // OK
+// access to super and self methods via invokeSpecial:
+MethodHandle MH_super = Listie.lookup().findSpecial(
+ ArrayList.class, "toString" , methodType(String.class), Listie.class);
+MethodHandle MH_this = Listie.lookup().findSpecial(
+ Listie.class, "toString" , methodType(String.class), Listie.class);
+MethodHandle MH_duper = Listie.lookup().findSpecial(
+ Object.class, "toString" , methodType(String.class), Listie.class);
+assertEquals("[]", (String) MH_super.invokeExact(l));
+assertEquals(""+l, (String) MH_this.invokeExact(l));
+assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method
+try { assertEquals("inaccessible", Listie.lookup().findSpecial(
+ String.class, "toString", methodType(String.class), Listie.class));
+ } catch (IllegalAccessException ex) { } // OK
+Listie subl = new Listie() { public String toString() { return "[subclass]"; } };
+assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
+ * }
+ *
* @param refc the class or interface from which the method is accessed
* @param name the name of the method (which must not be "<init>")
* @param type the type of the method, with the receiver argument omitted
@@ -754,7 +984,6 @@ public class MethodHandles {
checkSpecialCaller(specialCaller);
Lookup specialLookup = this.in(specialCaller);
MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
- checkSecurityManager(refc, method);
return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
}
@@ -777,7 +1006,6 @@ public class MethodHandles {
*/
public MethodHandle findGetter(Class> refc, String name, Class> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_getField, refc, name, type);
- checkSecurityManager(refc, field);
return getDirectField(REF_getField, refc, field);
}
@@ -800,7 +1028,6 @@ public class MethodHandles {
*/
public MethodHandle findSetter(Class> refc, String name, Class> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_putField, refc, name, type);
- checkSecurityManager(refc, field);
return getDirectField(REF_putField, refc, field);
}
@@ -810,6 +1037,9 @@ public class MethodHandles {
* value type.
* The method handle will take no arguments.
* Access checking is performed immediately on behalf of the lookup class.
+ *
+ * If the returned method handle is invoked, the field's class will
+ * be initialized, if it has not already been initialized.
* @param refc the class or interface from which the method is accessed
* @param name the field's name
* @param type the field's type
@@ -822,7 +1052,6 @@ public class MethodHandles {
*/
public MethodHandle findStaticGetter(Class> refc, String name, Class> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_getStatic, refc, name, type);
- checkSecurityManager(refc, field);
return getDirectField(REF_getStatic, refc, field);
}
@@ -832,6 +1061,9 @@ public class MethodHandles {
* The method handle will take a single
* argument, of the field's value type, the value to be stored.
* Access checking is performed immediately on behalf of the lookup class.
+ *
+ * If the returned method handle is invoked, the field's class will
+ * be initialized, if it has not already been initialized.
* @param refc the class or interface from which the method is accessed
* @param name the field's name
* @param type the field's type
@@ -844,7 +1076,6 @@ public class MethodHandles {
*/
public MethodHandle findStaticSetter(Class> refc, String name, Class> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_putStatic, refc, name, type);
- checkSecurityManager(refc, field);
return getDirectField(REF_putStatic, refc, field);
}
@@ -852,7 +1083,7 @@ public class MethodHandles {
* Produces an early-bound method handle for a non-static method.
* The receiver must have a supertype {@code defc} in which a method
* of the given name and type is accessible to the lookup class.
- * The method and all its argument types must be accessible to the lookup class.
+ * The method and all its argument types must be accessible to the lookup object.
* The type of the method handle will be that of the method,
* without any insertion of an additional receiver parameter.
* The given receiver will be bound into the method handle,
@@ -867,17 +1098,17 @@ public class MethodHandles {
* the given receiver value will be bound to it.)
*
* This is equivalent to the following code:
- *
+ * {@code
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
-MethodHandle mh0 = lookup().{@link #findVirtual findVirtual}(defc, name, type);
-MethodHandle mh1 = mh0.{@link MethodHandle#bindTo bindTo}(receiver);
+MethodHandle mh0 = lookup().findVirtual(defc, name, type);
+MethodHandle mh1 = mh0.bindTo(receiver);
MethodType mt1 = mh1.type();
if (mh0.isVarargsCollector())
mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1));
return mh1;
- *
+ * }
* where {@code defc} is either {@code receiver.getClass()} or a super
* type of that class, in which the requested method is accessible
* to the lookup class.
@@ -893,17 +1124,19 @@ return mh1;
* @exception SecurityException if a security manager is present and it
* refuses access
* @throws NullPointerException if any argument is null
+ * @see MethodHandle#bindTo
+ * @see #findVirtual
*/
public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
Class extends Object> refc = receiver.getClass(); // may get NPE
MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
- checkSecurityManager(refc, method);
MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
return mh.bindReceiver(receiver).setVarargs(method);
}
/**
- * Makes a direct method handle to m, if the lookup class has permission.
+ * Makes a direct method handle
+ * to m, if the lookup class has permission.
* If m is non-static, the receiver argument is treated as an initial argument.
* If m is virtual, overriding is respected on every call.
* Unlike the Core Reflection API, exceptions are not wrapped.
@@ -916,6 +1149,10 @@ return mh1;
* The returned method handle will have
* {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
* the method's variable arity modifier bit ({@code 0x0080}) is set.
+ *
+ * If m is static, and
+ * if the returned method handle is invoked, the method's class will
+ * be initialized, if it has not already been initialized.
* @param m the reflected method
* @return a method handle which can invoke the reflected method
* @throws IllegalAccessException if access checking fails
@@ -934,7 +1171,7 @@ return mh1;
refKind = REF_invokeVirtual;
assert(method.isMethod());
Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
- return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
+ return lookup.getDirectMethodNoSecurityManager(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
}
private MethodHandle unreflectForMH(Method m) {
// these names require special lookups because they throw UnsupportedOperationException
@@ -946,13 +1183,21 @@ return mh1;
/**
* Produces a method handle for a reflected method.
* It will bypass checks for overriding methods on the receiver,
- * as if by a {@code invokespecial} instruction from within the {@code specialCaller}.
+ * as if called from an {@code invokespecial}
+ * instruction from within the explicitly specified {@code specialCaller}.
* The type of the method handle will be that of the method,
- * with the special caller type prepended (and not the receiver of the method).
+ * with a suitably restricted receiver type prepended.
+ * (The receiver type will be {@code specialCaller} or a subtype.)
* If the method's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class,
* as if {@code invokespecial} instruction were being linked.
*
+ * Before method resolution,
+ * if the explicitly specified caller class is not identical with the
+ * lookup class, or if this lookup object does not have
+ * private access
+ * privileges, the access fails.
+ *
* The returned method handle will have
* {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
* the method's variable arity modifier bit ({@code 0x0080}) is set.
@@ -970,7 +1215,7 @@ return mh1;
MemberName method = new MemberName(m, true);
assert(method.isMethod());
// ignore m.isAccessible: this is a new kind of access
- return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, findBoundCallerClass(method));
+ return specialLookup.getDirectMethodNoSecurityManager(REF_invokeSpecial, method.getDeclaringClass(), method, findBoundCallerClass(method));
}
/**
@@ -987,6 +1232,9 @@ return mh1;
* The returned method handle will have
* {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
* the constructor's variable arity modifier bit ({@code 0x0080}) is set.
+ *
+ * If the returned method handle is invoked, the constructor's class will
+ * be initialized, if it has not already been initialized.
* @param c the reflected constructor
* @return a method handle which can invoke the reflected constructor
* @throws IllegalAccessException if access checking fails
@@ -994,12 +1242,11 @@ return mh1;
* is set and {@code asVarargsCollector} fails
* @throws NullPointerException if the argument is null
*/
- @SuppressWarnings("rawtypes") // Will be Constructor> after JSR 292 MR
- public MethodHandle unreflectConstructor(Constructor c) throws IllegalAccessException {
+ public MethodHandle unreflectConstructor(Constructor> c) throws IllegalAccessException {
MemberName ctor = new MemberName(c);
assert(ctor.isConstructor());
Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
- return lookup.getDirectConstructor(ctor.getDeclaringClass(), ctor);
+ return lookup.getDirectConstructorNoSecurityManager(ctor.getDeclaringClass(), ctor);
}
/**
@@ -1011,6 +1258,10 @@ return mh1;
* the field.
* If the field's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
+ *
+ * If the field is static, and
+ * if the returned method handle is invoked, the field's class will
+ * be initialized, if it has not already been initialized.
* @param f the reflected field
* @return a method handle which can load values from the reflected field
* @throws IllegalAccessException if access checking fails
@@ -1025,7 +1276,7 @@ return mh1;
? MethodHandleNatives.refKindIsSetter(field.getReferenceKind())
: MethodHandleNatives.refKindIsGetter(field.getReferenceKind()));
Lookup lookup = f.isAccessible() ? IMPL_LOOKUP : this;
- return lookup.getDirectField(field.getReferenceKind(), f.getDeclaringClass(), field);
+ return lookup.getDirectFieldNoSecurityManager(field.getReferenceKind(), f.getDeclaringClass(), field);
}
/**
@@ -1037,6 +1288,10 @@ return mh1;
* the field, and the value to be stored.
* If the field's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
+ *
+ * If the field is static, and
+ * if the returned method handle is invoked, the field's class will
+ * be initialized, if it has not already been initialized.
* @param f the reflected field
* @return a method handle which can store values into the reflected field
* @throws IllegalAccessException if access checking fails
@@ -1047,17 +1302,21 @@ return mh1;
}
/**
- * Cracks a direct method handle created by this lookup object or a similar one.
+ * Cracks a direct method handle
+ * created by this lookup object or a similar one.
* Security and access checks are performed to ensure that this lookup object
* is capable of reproducing the target method handle.
* This means that the cracking may fail if target is a direct method handle
* but was created by an unrelated lookup object.
+ * This can happen if the method handle is caller sensitive
+ * and was created by a lookup object for a different class.
* @param target a direct method handle to crack into symbolic reference components
* @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
* @exception SecurityException if a security manager is present and it
* refuses access
* @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails
* @exception NullPointerException if the target is {@code null}
+ * @see MethodHandleInfo
* @since 1.8
*/
public MethodHandleInfo revealDirect(MethodHandle target) {
@@ -1077,11 +1336,16 @@ return mh1;
refKind = REF_invokeInterface;
// Check SM permissions and member access before cracking.
try {
- checkSecurityManager(defc, member);
checkAccess(refKind, defc, member);
+ checkSecurityManager(defc, member);
} catch (IllegalAccessException ex) {
throw new IllegalArgumentException(ex);
}
+ if (allowedModes != TRUSTED && member.isCallerSensitive()) {
+ Class> callerClass = target.internalCallerClass();
+ if (!hasPrivateAccess() || callerClass != lookupClass())
+ throw new IllegalArgumentException("method handle is caller sensitive: "+callerClass);
+ }
// Produce the handle to the results.
return new InfoFromMemberName(this, member, refKind);
}
@@ -1090,24 +1354,43 @@ return mh1;
MemberName resolveOrFail(byte refKind, Class> refc, String name, Class> type) throws NoSuchFieldException, IllegalAccessException {
checkSymbolicClass(refc); // do this before attempting to resolve
- name.getClass(); type.getClass(); // NPE
+ name.getClass(); // NPE
+ type.getClass(); // NPE
return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(),
NoSuchFieldException.class);
}
MemberName resolveOrFail(byte refKind, Class> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
checkSymbolicClass(refc); // do this before attempting to resolve
- name.getClass(); type.getClass(); // NPE
+ name.getClass(); // NPE
+ type.getClass(); // NPE
+ checkMethodName(refKind, name); // NPE check on name
return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(),
NoSuchMethodException.class);
}
+ MemberName resolveOrFail(byte refKind, MemberName member) throws ReflectiveOperationException {
+ checkSymbolicClass(member.getDeclaringClass()); // do this before attempting to resolve
+ member.getName().getClass(); // NPE
+ member.getType().getClass(); // NPE
+ return IMPL_NAMES.resolveOrFail(refKind, member, lookupClassOrNull(),
+ ReflectiveOperationException.class);
+ }
+
void checkSymbolicClass(Class> refc) throws IllegalAccessException {
+ refc.getClass(); // NPE
Class> caller = lookupClassOrNull();
if (caller != null && !VerifyAccess.isClassAccessible(refc, caller, allowedModes))
throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this);
}
+ /** Check name for an illegal leading "<" character. */
+ void checkMethodName(byte refKind, String name) throws NoSuchMethodException {
+ if (name.startsWith("<") && refKind != REF_newInvokeSpecial)
+ throw new NoSuchMethodException("illegal method name: "+name);
+ }
+
+
/**
* Find my trustable caller class if m is a caller sensitive method.
* If this lookup object has private access, then the caller class is the lookupClass.
@@ -1116,8 +1399,8 @@ return mh1;
Class> findBoundCallerClass(MemberName m) throws IllegalAccessException {
Class> callerClass = null;
if (MethodHandleNatives.isCallerSensitive(m)) {
- // Only full-power lookup is allowed to resolve caller-sensitive methods
- if (isFullPowerLookup()) {
+ // Only lookups with private access are allowed to resolve caller-sensitive methods
+ if (hasPrivateAccess()) {
callerClass = lookupClass;
} else {
throw new IllegalAccessException("Attempt to lookup caller-sensitive method using restricted lookup object");
@@ -1126,7 +1409,7 @@ return mh1;
return callerClass;
}
- private boolean isFullPowerLookup() {
+ private boolean hasPrivateAccess() {
return (allowedModes & PRIVATE) != 0;
}
@@ -1141,22 +1424,21 @@ return mh1;
if (allowedModes == TRUSTED) return;
// Step 1:
- if (!isFullPowerLookup() ||
+ boolean fullPowerLookup = hasPrivateAccess();
+ if (!fullPowerLookup ||
!VerifyAccess.classLoaderIsAncestor(lookupClass, refc)) {
ReflectUtil.checkPackageAccess(refc);
}
// Step 2:
if (m.isPublic()) return;
- Class> defc = m.getDeclaringClass();
- {
- if (!isFullPowerLookup()) {
- smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
- }
+ if (!fullPowerLookup) {
+ smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
}
// Step 3:
- if (defc != refc) {
+ Class> defc = m.getDeclaringClass();
+ if (!fullPowerLookup && defc != refc) {
ReflectUtil.checkPackageAccess(defc);
}
}
@@ -1185,6 +1467,7 @@ return mh1;
throw m.makeAccessException(message, this);
}
+ /** Check public/protected/private bits on the symbolic reference class and its member. */
void checkAccess(byte refKind, Class> refc, MemberName m) throws IllegalAccessException {
assert(m.referenceKindIsConsistentWith(refKind) &&
MethodHandleNatives.refKindIsValid(refKind) &&
@@ -1192,6 +1475,26 @@ return mh1;
int allowedModes = this.allowedModes;
if (allowedModes == TRUSTED) return;
int mods = m.getModifiers();
+ if (Modifier.isProtected(mods) &&
+ refKind == REF_invokeVirtual &&
+ m.getDeclaringClass() == Object.class &&
+ m.getName().equals("clone") &&
+ refc.isArray()) {
+ // The JVM does this hack also.
+ // (See ClassVerifier::verify_invoke_instructions
+ // and LinkResolver::check_method_accessability.)
+ // Because the JVM does not allow separate methods on array types,
+ // there is no separate method for int[].clone.
+ // All arrays simply inherit Object.clone.
+ // But for access checking logic, we make Object.clone
+ // (normally protected) appear to be public.
+ // Later on, when the DirectMethodHandle is created,
+ // its leading argument will be restricted to the
+ // requested array type.
+ // N.B. The return type is not adjusted, because
+ // that is *not* the bytecode behavior.
+ mods ^= Modifier.PROTECTED | Modifier.PUBLIC;
+ }
if (Modifier.isFinal(mods) &&
MethodHandleNatives.refKindIsSetter(refKind))
throw m.makeAccessException("unexpected set of a final field", this);
@@ -1239,7 +1542,7 @@ return mh1;
private void checkSpecialCaller(Class> specialCaller) throws IllegalAccessException {
int allowedModes = this.allowedModes;
if (allowedModes == TRUSTED) return;
- if ((allowedModes & PRIVATE) == 0
+ if (!hasPrivateAccess()
|| (specialCaller != lookupClass()
&& !(ALLOW_NESTMATE_ACCESS &&
VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))))
@@ -1271,18 +1574,32 @@ return mh1;
return mh.viewAsType(narrowType);
}
+ /** Check access and get the requested method. */
private MethodHandle getDirectMethod(byte refKind, Class> refc, MemberName method, Class> callerClass) throws IllegalAccessException {
- return getDirectMethodCommon(refKind, refc, method,
- (refKind == REF_invokeSpecial ||
- (MethodHandleNatives.refKindHasReceiver(refKind) &&
- restrictProtectedReceiver(method))), callerClass);
+ final boolean doRestrict = true;
+ final boolean checkSecurity = true;
+ return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass);
}
+ /** Check access and get the requested method, eliding receiver narrowing rules. */
private MethodHandle getDirectMethodNoRestrict(byte refKind, Class> refc, MemberName method, Class> callerClass) throws IllegalAccessException {
- return getDirectMethodCommon(refKind, refc, method, false, callerClass);
+ final boolean doRestrict = false;
+ final boolean checkSecurity = true;
+ return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass);
}
+ /** Check access and get the requested method, eliding security manager checks. */
+ private MethodHandle getDirectMethodNoSecurityManager(byte refKind, Class> refc, MemberName method, Class> callerClass) throws IllegalAccessException {
+ final boolean doRestrict = true;
+ final boolean checkSecurity = false; // not needed for reflection or for linking CONSTANT_MH constants
+ return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass);
+ }
+ /** Common code for all methods; do not call directly except from immediately above. */
private MethodHandle getDirectMethodCommon(byte refKind, Class> refc, MemberName method,
+ boolean checkSecurity,
boolean doRestrict, Class> callerClass) throws IllegalAccessException {
checkMethod(refKind, refc, method);
+ // Optionally check with the security manager; this isn't needed for unreflect* calls.
+ if (checkSecurity)
+ checkSecurityManager(refc, method);
assert(!method.isMethodHandleInvoke());
Class> refcAsSuper;
@@ -1312,7 +1629,11 @@ return mh1;
MethodHandle mh = DirectMethodHandle.make(refKind, refc, method);
mh = maybeBindCaller(method, mh, callerClass);
mh = mh.setVarargs(method);
- if (doRestrict)
+ // Optionally narrow the receiver argument to refc using restrictReceiver.
+ if (doRestrict &&
+ (refKind == REF_invokeSpecial ||
+ (MethodHandleNatives.refKindHasReceiver(refKind) &&
+ restrictProtectedReceiver(method))))
mh = restrictReceiver(method, mh, lookupClass());
return mh;
}
@@ -1322,14 +1643,29 @@ return mh1;
if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))
return mh;
Class> hostClass = lookupClass;
- if ((allowedModes & PRIVATE) == 0) // caller must use full-power lookup
+ if (!hasPrivateAccess()) // caller must have private access
hostClass = callerClass; // callerClass came from a security manager style stack walk
MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass);
// Note: caller will apply varargs after this step happens.
return cbmh;
}
+ /** Check access and get the requested field. */
private MethodHandle getDirectField(byte refKind, Class> refc, MemberName field) throws IllegalAccessException {
+ final boolean checkSecurity = true;
+ return getDirectFieldCommon(refKind, refc, field, checkSecurity);
+ }
+ /** Check access and get the requested field, eliding security manager checks. */
+ private MethodHandle getDirectFieldNoSecurityManager(byte refKind, Class> refc, MemberName field) throws IllegalAccessException {
+ final boolean checkSecurity = false; // not needed for reflection or for linking CONSTANT_MH constants
+ return getDirectFieldCommon(refKind, refc, field, checkSecurity);
+ }
+ /** Common code for all fields; do not call directly except from immediately above. */
+ private MethodHandle getDirectFieldCommon(byte refKind, Class> refc, MemberName field,
+ boolean checkSecurity) throws IllegalAccessException {
checkField(refKind, refc, field);
+ // Optionally check with the security manager; this isn't needed for unreflect* calls.
+ if (checkSecurity)
+ checkSecurityManager(refc, field);
MethodHandle mh = DirectMethodHandle.make(refc, field);
boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) &&
restrictProtectedReceiver(field));
@@ -1337,9 +1673,24 @@ return mh1;
mh = restrictReceiver(field, mh, lookupClass());
return mh;
}
+ /** Check access and get the requested constructor. */
private MethodHandle getDirectConstructor(Class> refc, MemberName ctor) throws IllegalAccessException {
+ final boolean checkSecurity = true;
+ return getDirectConstructorCommon(refc, ctor, checkSecurity);
+ }
+ /** Check access and get the requested constructor, eliding security manager checks. */
+ private MethodHandle getDirectConstructorNoSecurityManager(Class> refc, MemberName ctor) throws IllegalAccessException {
+ final boolean checkSecurity = false; // not needed for reflection or for linking CONSTANT_MH constants
+ return getDirectConstructorCommon(refc, ctor, checkSecurity);
+ }
+ /** Common code for all constructors; do not call directly except from immediately above. */
+ private MethodHandle getDirectConstructorCommon(Class> refc, MemberName ctor,
+ boolean checkSecurity) throws IllegalAccessException {
assert(ctor.isConstructor());
checkAccess(REF_newInvokeSpecial, refc, ctor);
+ // Optionally check with the security manager; this isn't needed for unreflect* calls.
+ if (checkSecurity)
+ checkSecurityManager(refc, ctor);
assert(!MethodHandleNatives.isCallerSensitive(ctor)); // maybeBindCaller not relevant here
return DirectMethodHandle.make(ctor).setVarargs(ctor);
}
@@ -1348,29 +1699,75 @@ return mh1;
*/
/*non-public*/
MethodHandle linkMethodHandleConstant(byte refKind, Class> defc, String name, Object type) throws ReflectiveOperationException {
- MemberName resolved = null;
- if (type instanceof MemberName) {
- resolved = (MemberName) type;
- if (!resolved.isResolved()) throw new InternalError("unresolved MemberName");
- assert(name == null || name.equals(resolved.getName()));
+ if (!(type instanceof Class || type instanceof MethodType))
+ throw new InternalError("unresolved MemberName");
+ MemberName member = new MemberName(refKind, defc, name, type);
+ MethodHandle mh = LOOKASIDE_TABLE.get(member);
+ if (mh != null) {
+ checkSymbolicClass(defc);
+ return mh;
}
+ MemberName resolved = resolveOrFail(refKind, member);
+ mh = getDirectMethodForConstant(refKind, defc, resolved);
+ if (mh instanceof DirectMethodHandle
+ && canBeCached(refKind, defc, resolved)) {
+ MemberName key = mh.internalMemberName();
+ if (key != null) {
+ key = key.asNormalOriginal();
+ }
+ if (member.equals(key)) { // better safe than sorry
+ LOOKASIDE_TABLE.put(key, (DirectMethodHandle) mh);
+ }
+ }
+ return mh;
+ }
+ private
+ boolean canBeCached(byte refKind, Class> defc, MemberName member) {
+ if (refKind == REF_invokeSpecial) {
+ return false;
+ }
+ if (!Modifier.isPublic(defc.getModifiers()) ||
+ !Modifier.isPublic(member.getDeclaringClass().getModifiers()) ||
+ !member.isPublic() ||
+ member.isCallerSensitive()) {
+ return false;
+ }
+ ClassLoader loader = defc.getClassLoader();
+ if (!sun.misc.VM.isSystemDomainLoader(loader)) {
+ ClassLoader sysl = ClassLoader.getSystemClassLoader();
+ boolean found = false;
+ while (sysl != null) {
+ if (loader == sysl) { found = true; break; }
+ sysl = sysl.getParent();
+ }
+ if (!found) {
+ return false;
+ }
+ }
+ try {
+ MemberName resolved2 = publicLookup().resolveOrFail(refKind,
+ new MemberName(refKind, defc, member.getName(), member.getType()));
+ checkSecurityManager(defc, resolved2);
+ } catch (ReflectiveOperationException | SecurityException ex) {
+ return false;
+ }
+ return true;
+ }
+ private
+ MethodHandle getDirectMethodForConstant(byte refKind, Class> defc, MemberName member)
+ throws ReflectiveOperationException {
if (MethodHandleNatives.refKindIsField(refKind)) {
- MemberName field = (resolved != null) ? resolved
- : resolveOrFail(refKind, defc, name, (Class>) type);
- return getDirectField(refKind, defc, field);
+ return getDirectFieldNoSecurityManager(refKind, defc, member);
} else if (MethodHandleNatives.refKindIsMethod(refKind)) {
- MemberName method = (resolved != null) ? resolved
- : resolveOrFail(refKind, defc, name, (MethodType) type);
- return getDirectMethod(refKind, defc, method, lookupClass);
+ return getDirectMethodNoSecurityManager(refKind, defc, member, lookupClass);
} else if (refKind == REF_newInvokeSpecial) {
- assert(name == null || name.equals(""));
- MemberName ctor = (resolved != null) ? resolved
- : resolveOrFail(REF_newInvokeSpecial, defc, name, (MethodType) type);
- return getDirectConstructor(defc, ctor);
+ return getDirectConstructorNoSecurityManager(defc, member);
}
// oops
- throw new ReflectiveOperationException("bad MethodHandle constant #"+refKind+" "+name+" : "+type);
+ throw newIllegalArgumentException("bad MethodHandle constant #"+member);
}
+
+ static ConcurrentHashMap LOOKASIDE_TABLE = new ConcurrentHashMap<>();
}
/**
@@ -1430,22 +1827,26 @@ return mh1;
*
* Before invoking its target, the invoker will spread the final array, apply
* reference casts as necessary, and unbox and widen primitive arguments.
+ * If, when the invoker is called, the supplied array argument does
+ * not have the correct number of elements, the invoker will throw
+ * an {@link IllegalArgumentException} instead of invoking the target.
*
* This method is equivalent to the following code (though it may be more efficient):
- *
+ * {@code
MethodHandle invoker = MethodHandles.invoker(type);
int spreadArgCount = type.parameterCount() - leadingArgCount;
invoker = invoker.asSpreader(Object[].class, spreadArgCount);
return invoker;
- *
- *
+ * }
* This method throws no reflective or security exceptions.
* @param type the desired target type
* @param leadingArgCount number of fixed arguments, to be passed unchanged to the target
* @return a method handle suitable for invoking any method handle of the given type
* @throws NullPointerException if {@code type} is null
* @throws IllegalArgumentException if {@code leadingArgCount} is not in
- * the range from 0 to {@code type.parameterCount()} inclusive
+ * the range from 0 to {@code type.parameterCount()} inclusive,
+ * or if the resulting method handle's type would have
+ * too many parameters
*/
static public
MethodHandle spreadInvoker(MethodType type, int leadingArgCount) {
@@ -1462,9 +1863,7 @@ return invoker;
* an additional leading argument of type {@code MethodHandle}.
*
* This method is equivalent to the following code (though it may be more efficient):
- *
-publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
- *
+ * {@code publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)}
*
*
* Discussion:
@@ -1479,7 +1878,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
* If spreading, collecting, or other argument transformations are required,
* they can be applied once to the invoker {@code X} and reused on many {@code M}
* method handle values, as long as they are compatible with the type of {@code X}.
- *
+ *
* (Note: The invoker method is not available via the Core Reflection API.
* An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
* on the declared {@code invokeExact} or {@code invoke} method will raise an
@@ -1488,6 +1887,8 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
* This method throws no reflective or security exceptions.
* @param type the desired target type
* @return a method handle suitable for invoking any method handle of the given type
+ * @throws IllegalArgumentException if the resulting method handle's type would have
+ * too many parameters
*/
static public
MethodHandle exactInvoker(MethodType type) {
@@ -1508,19 +1909,25 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
* If the target is a {@linkplain MethodHandle#asVarargsCollector variable arity method handle},
* the required arity conversion will be made, again as if by {@link MethodHandle#asType asType}.
*
- * A {@linkplain MethodType#genericMethodType general method type},
+ * This method is equivalent to the following code (though it may be more efficient):
+ * {@code publicLookup().findVirtual(MethodHandle.class, "invoke", type)}
+ *
+ * Discussion:
+ * A {@linkplain MethodType#genericMethodType general method type} is one which
* mentions only {@code Object} arguments and return values.
* An invoker for such a type is capable of calling any method handle
* of the same arity as the general type.
- *
- * This method is equivalent to the following code (though it may be more efficient):
- *
-publicLookup().findVirtual(MethodHandle.class, "invoke", type)
- *
+ *
+ * (Note: The invoker method is not available via the Core Reflection API.
+ * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
+ * on the declared {@code invokeExact} or {@code invoke} method will raise an
+ * {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)
*
* This method throws no reflective or security exceptions.
* @param type the desired target type
* @return a method handle suitable for invoking any method handle convertible to the given type
+ * @throws IllegalArgumentException if the resulting method handle's type would have
+ * too many parameters
*/
static public
MethodHandle invoker(MethodType type) {
@@ -1801,7 +2208,7 @@ assert((int)twice.invokeExact(21) == 42);
* they will come after.
*
* Example:
- *
+ * {@code
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
@@ -1812,11 +2219,11 @@ MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class)
MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
assertEquals(bigType, d0.type());
assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
- *
+ * }
*
* This method is also equivalent to the following code:
*
- * {@link #dropArguments(MethodHandle,int,Class...) dropArguments}(target, pos, valueTypes.toArray(new Class[0]))
+ * {@link #dropArguments(MethodHandle,int,Class...) dropArguments}{@code (target, pos, valueTypes.toArray(new Class[0]))}
*
* @param target the method handle to invoke after the arguments are dropped
* @param valueTypes the type(s) of the argument(s) to drop
@@ -1859,7 +2266,7 @@ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
* they will come after.
*
* Example:
- *
+ * {@code
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
@@ -1874,11 +2281,11 @@ MethodHandle d2 = dropArguments(cat, 2, String.class);
assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
- *
+ * }
*
* This method is also equivalent to the following code:
*
- * {@link #dropArguments(MethodHandle,int,List) dropArguments}(target, pos, Arrays.asList(valueTypes))
+ * {@link #dropArguments(MethodHandle,int,List) dropArguments}{@code (target, pos, Arrays.asList(valueTypes))}
*
* @param target the method handle to invoke after the arguments are dropped
* @param valueTypes the type(s) of the argument(s) to drop
@@ -1889,7 +2296,8 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
* or if the {@code valueTypes} array or any of its elements is null
* @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
* or if {@code pos} is negative or greater than the arity of the target,
- * or if the new method handle's type would have too many parameters
+ * or if the new method handle's type would have
+ * too many parameters
*/
public static
MethodHandle dropArguments(MethodHandle target, int pos, Class>... valueTypes) {
@@ -1923,8 +2331,8 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
* It is an error if there are elements of {@code filters}
* (null or not)
* which do not correspond to argument positions in the target.
- * Example:
- *
+ * Example:
+ *
{@code
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
@@ -1939,15 +2347,15 @@ MethodHandle f1 = filterArguments(cat, 1, upcase);
assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
- *
+ * }
* Here is pseudocode for the resulting adapter:
- *
+ * {@code
* V target(P... p, A[i]... a[i], B... b);
* A[i] filter[i](V[i]);
* T adapter(P... p, V[i]... v[i], B... b) {
* return target(p..., f[i](v[i])..., b...);
* }
- *
+ * }
*
* @param target the method handle to invoke after arguments are filtered
* @param pos the position of the first argument to filter
@@ -1957,7 +2365,9 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
* or if the {@code filters} array is null
* @throws IllegalArgumentException if a non-null element of {@code filters}
* does not match a corresponding argument type of target as described above,
- * or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()}
+ * or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()},
+ * or if the resulting method handle's type would have
+ * too many parameters
*/
public static
MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
@@ -1989,15 +2399,120 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
}
- // FIXME: Make this public in M1.
- /*non-public*/ static
- MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle collector) {
+ /**
+ * Adapts a target method handle by pre-processing
+ * a sub-sequence of its arguments with a filter (another method handle).
+ * The pre-processed arguments are replaced by the result (if any) of the
+ * filter function.
+ * The target is then called on the modified (usually shortened) argument list.
+ *
+ * If the filter returns a value, the target must accept that value as
+ * its argument in position {@code pos}, preceded and/or followed by
+ * any arguments not passed to the filter.
+ * If the filter returns void, the target must accept all arguments
+ * not passed to the filter.
+ * No arguments are reordered, and a result returned from the filter
+ * replaces (in order) the whole subsequence of arguments originally
+ * passed to the adapter.
+ *
+ * The argument types (if any) of the filter
+ * replace zero or one argument types of the target, at position {@code pos},
+ * in the resulting adapted method handle.
+ * The return type of the filter (if any) must be identical to the
+ * argument type of the target at position {@code pos}, and that target argument
+ * is supplied by the return value of the filter.
+ *
+ * In all cases, {@code pos} must be greater than or equal to zero, and
+ * {@code pos} must also be less than or equal to the target's arity.
+ *
Example:
+ *
{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle deepToString = publicLookup()
+ .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
+
+MethodHandle ts1 = deepToString.asCollector(String[].class, 1);
+assertEquals("[strange]", (String) ts1.invokeExact("strange"));
+
+MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
+assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));
+
+MethodHandle ts3 = deepToString.asCollector(String[].class, 3);
+MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);
+assertEquals("[top, [up, down], strange]",
+ (String) ts3_ts2.invokeExact("top", "up", "down", "strange"));
+
+MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);
+assertEquals("[top, [up, down], [strange]]",
+ (String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));
+
+MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);
+assertEquals("[top, [[up, down, strange], charm], bottom]",
+ (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
+ * }
+ * Here is pseudocode for the resulting adapter:
+ *
{@code
+ * T target(A...,V,C...);
+ * V filter(B...);
+ * T adapter(A... a,B... b,C... c) {
+ * V v = filter(b...);
+ * return target(a...,v,c...);
+ * }
+ * // and if the filter has no arguments:
+ * T target2(A...,V,C...);
+ * V filter2();
+ * T adapter2(A... a,C... c) {
+ * V v = filter2();
+ * return target2(a...,v,c...);
+ * }
+ * // and if the filter has a void return:
+ * T target3(A...,C...);
+ * void filter3(B...);
+ * void adapter3(A... a,B... b,C... c) {
+ * filter3(b...);
+ * return target3(a...,c...);
+ * }
+ * }
+ *
+ * A collection adapter {@code collectArguments(mh, 0, coll)} is equivalent to
+ * one which first "folds" the affected arguments, and then drops them, in separate
+ * steps as follows:
+ *
{@code
+ * mh = MethodHandles.dropArguments(mh, 1, coll.type().parameterList()); //step 2
+ * mh = MethodHandles.foldArguments(mh, coll); //step 1
+ * }
+ * If the target method handle consumes no arguments besides than the result
+ * (if any) of the filter {@code coll}, then {@code collectArguments(mh, 0, coll)}
+ * is equivalent to {@code filterReturnValue(coll, mh)}.
+ * If the filter method handle {@code coll} consumes one argument and produces
+ * a non-void result, then {@code collectArguments(mh, N, coll)}
+ * is equivalent to {@code filterArguments(mh, N, coll)}.
+ * Other equivalences are possible but would require argument permutation.
+ *
+ * @param target the method handle to invoke after filtering the subsequence of arguments
+ * @param pos the position of the first adapter argument to pass to the filter,
+ * and/or the target argument which receives the result of the filter
+ * @param filter method handle to call on the subsequence of arguments
+ * @return method handle which incorporates the specified argument subsequence filtering logic
+ * @throws NullPointerException if either argument is null
+ * @throws IllegalArgumentException if the return type of {@code filter}
+ * is non-void and is not the same as the {@code pos} argument of the target,
+ * or if {@code pos} is not between 0 and the target's arity, inclusive,
+ * or if the resulting method handle's type would have
+ * too many parameters
+ * @see MethodHandles#foldArguments
+ * @see MethodHandles#filterArguments
+ * @see MethodHandles#filterReturnValue
+ */
+ public static
+ MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
MethodType targetType = target.type();
- MethodType filterType = collector.type();
+ MethodType filterType = filter.type();
if (filterType.returnType() != void.class &&
filterType.returnType() != targetType.parameterType(pos))
throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
- return MethodHandleImpl.makeCollectArguments(target, collector, pos, false);
+ return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
}
/**
@@ -2014,8 +2529,8 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
* in the resulting adapted method handle.
* The argument type of the filter (if any) must be identical to the
* return type of the target.
- * Example:
- *
+ * Example:
+ *
{@code
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
@@ -2026,9 +2541,9 @@ MethodHandle length = lookup().findVirtual(String.class,
System.out.println((String) cat.invokeExact("x", "y")); // xy
MethodHandle f0 = filterReturnValue(cat, length);
System.out.println((int) f0.invokeExact("x", "y")); // 2
- *
+ * }
* Here is pseudocode for the resulting adapter:
- *
+ * {@code
* V target(A...);
* T filter(V);
* T adapter(A... a) {
@@ -2049,7 +2564,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
* V v = target3(a...);
* filter3(v);
* }
- *
+ * }
* @param target the method handle to invoke before filtering the return value
* @param filter method handle to call on the return value
* @return method handle which incorporates the specified return value filtering logic
@@ -2105,8 +2620,8 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
* consider using {@link MethodHandle#asCollector asCollector} instead, since those
* arguments will not need to be live on the stack on entry to the
* target.)
- * Example:
- *
+ * Example:
+ *
{@code
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
@@ -2119,9 +2634,9 @@ assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
MethodHandle catTrace = foldArguments(cat, trace);
// also prints "boo":
assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
- *
+ * }
* Here is pseudocode for the resulting adapter:
- *
+ * {@code
* // there are N arguments in A...
* T target(V, A[N]..., B...);
* V combiner(A...);
@@ -2136,7 +2651,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* combiner2(a...);
* return target2(a..., b...);
* }
- *
+ * }
* @param target the method handle to invoke after arguments are combined
* @param combiner method handle to call initially on the incoming arguments
* @return method handle which incorporates the specified argument folding logic
@@ -2179,7 +2694,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* of the test must be boolean, and the test is allowed
* to have fewer arguments than the other two method handles.
* Here is pseudocode for the resulting adapter:
- *
+ * {@code
* boolean test(A...);
* T target(A...,B...);
* T fallback(A...,B...);
@@ -2189,7 +2704,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* else
* return fallback(a..., b...);
* }
- *
+ * }
* Note that the test arguments ({@code a...} in the pseudocode) cannot
* be modified by execution of the test, and so are passed unchanged
* from the caller to the target or fallback as appropriate.
@@ -2241,7 +2756,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* (similarly to the predicate in {@link #guardWithTest guardWithTest}).
* Also, the handler must have an extra leading parameter of {@code exType} or a supertype.
* Here is pseudocode for the resulting adapter:
- *
+ * {@code
* T target(A..., B...);
* T handler(ExType, A...);
* T adapter(A... a, B... b) {
@@ -2251,7 +2766,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* return handler(ex, a...);
* }
* }
- *
+ * }
* Note that the saved arguments ({@code a...} in the pseudocode) cannot
* be modified by execution of the target, and so are passed unchanged
* from the caller to the handler, if the handler is invoked.
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodType.java b/jdk/src/share/classes/java/lang/invoke/MethodType.java
index f55479f1345..5a73037afdb 100644
--- a/jdk/src/share/classes/java/lang/invoke/MethodType.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodType.java
@@ -77,7 +77,8 @@ import sun.invoke.util.VerifyType;
* A method type may be loaded by an {@code ldc} instruction which refers
* to a suitable {@code CONSTANT_MethodType} constant pool entry.
* The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
- * For more details, see the package summary.
+ * (For full details on method type constants,
+ * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
*
* When the JVM materializes a {@code MethodType} from a descriptor string,
* all classes named in the descriptor must be accessible, and will be loaded.
@@ -94,9 +95,9 @@ class MethodType implements java.io.Serializable {
private final Class>[] ptypes;
// The remaining fields are caches of various sorts:
- private MethodTypeForm form; // erased form, plus cached data about primitives
- private MethodType wrapAlt; // alternative wrapped/unwrapped version
- private Invokers invokers; // cache of handy higher-order adapters
+ private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
+ private @Stable MethodType wrapAlt; // alternative wrapped/unwrapped version
+ private @Stable Invokers invokers; // cache of handy higher-order adapters
/**
* Check the given parameters for validity and store them into the final fields.
@@ -940,10 +941,10 @@ class MethodType implements java.io.Serializable {
* Instead, the return type and parameter type arrays are written directly
* from the {@code writeObject} method, using two calls to {@code s.writeObject}
* as follows:
- *
+ * {@code
s.writeObject(this.returnType());
s.writeObject(this.parameterArray());
- *
+ * }
*
* The deserialized field values are checked as if they were
* provided to the factory method {@link #methodType(Class,Class[]) methodType}.
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java b/jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java
index 1106e97baa3..09a07b1877f 100644
--- a/jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java
@@ -28,6 +28,7 @@ package java.lang.invoke;
import sun.invoke.util.Wrapper;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
+ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Shared information for a group of method types, which differ
@@ -51,12 +52,13 @@ final class MethodTypeForm {
final MethodType basicType; // the canonical erasure, with primitives simplified
// Cached adapter information:
- /*lazy*/ MethodHandle genericInvoker; // JVM hook for inexact invoke
- /*lazy*/ MethodHandle basicInvoker; // cached instance of MH.invokeBasic
- /*lazy*/ MethodHandle namedFunctionInvoker; // cached helper for LF.NamedFunction
+ @Stable String typeString; // argument type signature characters
+ @Stable MethodHandle genericInvoker; // JVM hook for inexact invoke
+ @Stable MethodHandle basicInvoker; // cached instance of MH.invokeBasic
+ @Stable MethodHandle namedFunctionInvoker; // cached helper for LF.NamedFunction
// Cached lambda form information, for basic types only:
- final LambdaForm[] lambdaForms;
+ final @Stable LambdaForm[] lambdaForms;
// Indexes into lambdaForms:
static final int
LF_INVVIRTUAL = 0, // DMH invokeVirtual
@@ -73,7 +75,8 @@ final class MethodTypeForm {
LF_GEN_LINKER = 11,
LF_GEN_INVOKER = 12,
LF_CS_LINKER = 13, // linkToCallSite_CS
- LF_LIMIT = 14;
+ LF_MH_LINKER = 14, // linkToCallSite_MH
+ LF_LIMIT = 15;
public MethodType erasedType() {
return erasedType;
@@ -96,11 +99,24 @@ final class MethodTypeForm {
assert(erasedType == basicType) : "erasedType: " + erasedType + " != basicType: " + basicType; // primitives must be flattened also
MethodHandle invoker = basicInvoker;
if (invoker != null) return invoker;
- invoker = basicType.invokers().makeBasicInvoker();
+ invoker = DirectMethodHandle.make(invokeBasicMethod(basicType));
basicInvoker = invoker;
return invoker;
}
+ // This next one is called from LambdaForm.NamedFunction..
+ /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
+ assert(basicType == basicType.basicType());
+ try {
+ // Do approximately the same as this public API call:
+ // Lookup.findVirtual(MethodHandle.class, name, type);
+ // But bypass access and corner case checks, since we know exactly what we need.
+ return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
+ } catch (ReflectiveOperationException ex) {
+ throw newInternalError("JVM cannot find invoker for "+basicType, ex);
+ }
+ }
+
/**
* Build an MTF for a given type, which must have all references erased to Object.
* This MTF will stand for that type and all un-erased variations.
diff --git a/jdk/src/share/classes/java/lang/invoke/MutableCallSite.java b/jdk/src/share/classes/java/lang/invoke/MutableCallSite.java
index 37bd4641484..746c8d64e5c 100644
--- a/jdk/src/share/classes/java/lang/invoke/MutableCallSite.java
+++ b/jdk/src/share/classes/java/lang/invoke/MutableCallSite.java
@@ -38,7 +38,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* Here is an example of a mutable call site which introduces a
* state variable into a method handle chain.
*
- *
+ * {@code
MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
MethodHandle MH_name = name.dynamicInvoker();
MethodType MT_str1 = MethodType.methodType(String.class);
@@ -50,10 +50,10 @@ assertEquals("ROCKY", (String) worker1.invokeExact());
name.setTarget(MethodHandles.constant(String.class, "Fred"));
assertEquals("FRED", (String) worker1.invokeExact());
// (mutation can be continued indefinitely)
- *
+ * }
*
* The same call site may be used in several places at once.
- *
+ * {@code
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
MethodHandle MH_cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
@@ -63,7 +63,7 @@ assertEquals("Fred, dear?", (String) worker2.invokeExact());
name.setTarget(MethodHandles.constant(String.class, "Wilma"));
assertEquals("WILMA", (String) worker1.invokeExact());
assertEquals("Wilma, dear?", (String) worker2.invokeExact());
- *
+ * }
*
* Non-synchronization of target values:
* A write to a mutable call site's target does not force other threads
diff --git a/jdk/src/share/classes/java/lang/invoke/Stable.java b/jdk/src/share/classes/java/lang/invoke/Stable.java
new file mode 100644
index 00000000000..67a3b4fb67a
--- /dev/null
+++ b/jdk/src/share/classes/java/lang/invoke/Stable.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import java.lang.annotation.*;
+
+/**
+ * A field may be annotated as stable if all of its component variables
+ * changes value at most once.
+ * A field's value counts as its component value.
+ * If the field is typed as an array, then all the non-null components
+ * of the array, of depth up to the rank of the field's array type,
+ * also count as component values.
+ * By extension, any variable (either array or field) which has annotated
+ * as stable is called a stable variable, and its non-null or non-zero
+ * value is called a stable value.
+ *
+ * Since all fields begin with a default value of null for references
+ * (resp., zero for primitives), it follows that this annotation indicates
+ * that the first non-null (resp., non-zero) value stored in the field
+ * will never be changed.
+ *
+ * If the field is not of an array type, there are no array elements,
+ * then the value indicated as stable is simply the value of the field.
+ * If the dynamic type of the field value is an array but the static type
+ * is not, the components of the array are not regarded as stable.
+ *
+ * If the field is an array type, then both the field value and
+ * all the components of the field value (if the field value is non-null)
+ * are indicated to be stable.
+ * If the field type is an array type with rank {@code N > 1},
+ * then each component of the field value (if the field value is non-null),
+ * is regarded as a stable array of rank {@code N-1}.
+ *
+ * Fields which are declared {@code final} may also be annotated as stable.
+ * Since final fields already behave as stable values, such an annotation
+ * indicates no additional information, unless the type of the field is
+ * an array type.
+ *
+ * It is (currently) undefined what happens if a field annotated as stable
+ * is given a third value. In practice, if the JVM relies on this annotation
+ * to promote a field reference to a constant, it may be that the Java memory
+ * model would appear to be broken, if such a constant (the second value of the field)
+ * is used as the value of the field even after the field value has changed.
+ */
+/* package-private */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@interface Stable {
+}
diff --git a/jdk/src/share/classes/java/lang/invoke/SwitchPoint.java b/jdk/src/share/classes/java/lang/invoke/SwitchPoint.java
index 65fd1dabfc6..290f9f01779 100644
--- a/jdk/src/share/classes/java/lang/invoke/SwitchPoint.java
+++ b/jdk/src/share/classes/java/lang/invoke/SwitchPoint.java
@@ -55,7 +55,7 @@ package java.lang.invoke;
* At that point {@code guardWithTest} may ignore {@code T} and return {@code F}.
*
* Here is an example of a switch point in action:
- *
+ * {@code
MethodHandle MH_strcat = MethodHandles.lookup()
.findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
SwitchPoint spt = new SwitchPoint();
@@ -68,7 +68,7 @@ assertEquals("method", (String) worker.invokeExact("met", "hod"));
SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
assert(spt.hasBeenInvalidated());
assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
- *
+ * }
*
* Discussion:
* Switch points are useful without subclassing. They may also be subclassed.
@@ -82,7 +82,7 @@ assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
* Implementation Note:
* A switch point behaves as if implemented on top of {@link MutableCallSite},
* approximately as follows:
- *
+ * {@code
public class SwitchPoint {
private static final MethodHandle
K_true = MethodHandles.constant(boolean.class, true),
@@ -106,7 +106,7 @@ public class SwitchPoint {
MutableCallSite.syncAll(mcss.toArray(new MutableCallSite[0]));
}
}
- *
+ * }
* @author Remi Forax, JSR 292 EG
*/
public class SwitchPoint {
diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java
index e84a3360fdd..f92b51d6ff6 100644
--- a/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java
@@ -27,17 +27,18 @@ package java.lang.reflect;
/**
- * AnnotatedArrayType represents the use of an array type, whose component
- * type may itself represent the annotated use of a type.
+ * {@code AnnotatedArrayType} represents the potentially annotated use of an
+ * array type, whose component type may itself represent the annotated use of a
+ * type.
*
* @since 1.8
*/
public interface AnnotatedArrayType extends AnnotatedType {
/**
- * Returns the annotated generic component type of this array type.
+ * Returns the potentially annotated generic component type of this array type.
*
- * @return the annotated generic component type of this array type
+ * @return the potentially annotated generic component type of this array type
*/
AnnotatedType getAnnotatedGenericComponentType();
}
diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java
index 4fa089e318c..f1d43c9528e 100644
--- a/jdk/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java
@@ -26,17 +26,18 @@
package java.lang.reflect;
/**
- * AnnotatedParameterizedType represents the use of a parameterized type,
- * whose type arguments may themselves represent annotated uses of types.
+ * {@code AnnotatedParameterizedType} represents the potentially annotated use
+ * of a parameterized type, whose type arguments may themselves represent
+ * annotated uses of types.
*
* @since 1.8
*/
public interface AnnotatedParameterizedType extends AnnotatedType {
/**
- * Returns the annotated actual type arguments of this parameterized type.
+ * Returns the potentially annotated actual type arguments of this parameterized type.
*
- * @return the annotated actual type arguments of this parameterized type
+ * @return the potentially annotated actual type arguments of this parameterized type
*/
AnnotatedType[] getAnnotatedActualTypeArguments();
}
diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedType.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedType.java
index d1ee79f14f4..12d0bfc17bb 100644
--- a/jdk/src/share/classes/java/lang/reflect/AnnotatedType.java
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedType.java
@@ -26,10 +26,10 @@
package java.lang.reflect;
/**
- * AnnotatedType represents the annotated use of a type in the program
- * currently running in this VM. The use may be of any type in the Java
- * programming language, including an array type, a parameterized type, a type
- * variable, or a wildcard type.
+ * {@code AnnotatedType} represents the potentially annotated use of a type in
+ * the program currently running in this VM. The use may be of any type in the
+ * Java programming language, including an array type, a parameterized type, a
+ * type variable, or a wildcard type.
*
* @since 1.8
*/
diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java
index 3580a14442f..7a39bae492d 100644
--- a/jdk/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java
@@ -26,18 +26,18 @@
package java.lang.reflect;
/**
- * AnnotatedTypeVariable represents the use of a type variable, whose
- * declaration may have bounds which themselves represent annotated uses of
- * types.
+ * {@code AnnotatedTypeVariable} represents the potentially annotated use of a
+ * type variable, whose declaration may have bounds which themselves represent
+ * annotated uses of types.
*
* @since 1.8
*/
public interface AnnotatedTypeVariable extends AnnotatedType {
/**
- * Returns the annotated bounds of this type variable.
+ * Returns the potentially annotated bounds of this type variable.
*
- * @return the annotated bounds of this type variable
+ * @return the potentially annotated bounds of this type variable
*/
AnnotatedType[] getAnnotatedBounds();
}
diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java
index c357eb9d0bc..2d15f6c9770 100644
--- a/jdk/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java
@@ -26,24 +26,25 @@
package java.lang.reflect;
/**
- * AnnotatedWildcardType represents the use of a wildcard type argument, whose
- * upper or lower bounds may themselves represent annotated uses of types.
+ * {@code AnnotatedWildcardType} represents the potentially annotated use of a
+ * wildcard type argument, whose upper or lower bounds may themselves represent
+ * annotated uses of types.
*
* @since 1.8
*/
public interface AnnotatedWildcardType extends AnnotatedType {
/**
- * Returns the annotated lower bounds of this wildcard type.
+ * Returns the potentially annotated lower bounds of this wildcard type.
*
- * @return the annotated lower bounds of this wildcard type
+ * @return the potentially annotated lower bounds of this wildcard type
*/
AnnotatedType[] getAnnotatedLowerBounds();
/**
- * Returns the annotated upper bounds of this wildcard type.
+ * Returns the potentially annotated upper bounds of this wildcard type.
*
- * @return the annotated upper bounds of this wildcard type
+ * @return the potentially annotated upper bounds of this wildcard type
*/
AnnotatedType[] getAnnotatedUpperBounds();
}
diff --git a/jdk/src/share/classes/java/lang/reflect/Constructor.java b/jdk/src/share/classes/java/lang/reflect/Constructor.java
index 0ed60dc375b..202a7368fb1 100644
--- a/jdk/src/share/classes/java/lang/reflect/Constructor.java
+++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java
@@ -67,8 +67,6 @@ public final class Constructor extends Executable {
private transient ConstructorRepository genericInfo;
private byte[] annotations;
private byte[] parameterAnnotations;
- // This is set by the vm at Constructor creation
- private byte[] typeAnnotations;
// Generics infrastructure
// Accessor for factory
@@ -141,8 +139,6 @@ public final class Constructor extends Executable {
res.root = this;
// Might as well eagerly propagate this if already present
res.constructorAccessor = constructorAccessor;
-
- res.typeAnnotations = typeAnnotations;
return res;
}
@@ -155,10 +151,6 @@ public final class Constructor extends Executable {
byte[] getAnnotationBytes() {
return annotations;
}
- @Override
- byte[] getTypeAnnotationBytes() {
- return typeAnnotations;
- }
/**
* {@inheritDoc}
diff --git a/jdk/src/share/classes/java/lang/reflect/Executable.java b/jdk/src/share/classes/java/lang/reflect/Executable.java
index 9d41a0217db..c92c9a57f78 100644
--- a/jdk/src/share/classes/java/lang/reflect/Executable.java
+++ b/jdk/src/share/classes/java/lang/reflect/Executable.java
@@ -51,7 +51,6 @@ public abstract class Executable extends AccessibleObject
* Accessor method to allow code sharing
*/
abstract byte[] getAnnotationBytes();
- abstract byte[] getTypeAnnotationBytes();
/**
* Does the Executable have generic information.
@@ -287,12 +286,14 @@ public abstract class Executable extends AccessibleObject
* this object. Returns an array of length 0 if the executable
* has no parameters.
*
- * The parameters of the underlying executable do not necessarily
+ * The parameters of the underlying executable do not necessarily
* have unique names, or names that are legal identifiers in the
* Java programming language (JLS 3.8).
*
+ * @throws MalformedParametersException if the class file contains
+ * a MethodParameters attribute that is improperly formatted.
* @return an array of {@code Parameter} objects representing all
- * the parameters to the executable this object represents
+ * the parameters to the executable this object represents.
*/
public Parameter[] getParameters() {
// TODO: This may eventually need to be guarded by security
@@ -316,6 +317,30 @@ public abstract class Executable extends AccessibleObject
return out;
}
+ private void verifyParameters(final Parameter[] parameters) {
+ final int mask = Modifier.FINAL | Modifier.SYNTHETIC | Modifier.MANDATED;
+
+ if (getParameterTypes().length != parameters.length)
+ throw new MalformedParametersException("Wrong number of parameters in MethodParameters attribute");
+
+ for (Parameter parameter : parameters) {
+ final String name = parameter.getRealName();
+ final int mods = parameter.getModifiers();
+
+ if (name != null) {
+ if (name.isEmpty() || name.indexOf('.') != -1 ||
+ name.indexOf(';') != -1 || name.indexOf('[') != -1 ||
+ name.indexOf('/') != -1) {
+ throw new MalformedParametersException("Invalid parameter name \"" + name + "\"");
+ }
+ }
+
+ if (mods != (mods & mask)) {
+ throw new MalformedParametersException("Invalid parameter modifiers");
+ }
+ }
+ }
+
private Parameter[] privateGetParameters() {
// Use tmp to avoid multiple writes to a volatile.
Parameter[] tmp = parameters;
@@ -323,7 +348,12 @@ public abstract class Executable extends AccessibleObject
if (tmp == null) {
// Otherwise, go to the JVM to get them
- tmp = getParameters0();
+ try {
+ tmp = getParameters0();
+ } catch(IllegalArgumentException e) {
+ // Rethrow ClassFormatErrors
+ throw new MalformedParametersException("Invalid constant pool index");
+ }
// If we get back nothing, then synthesize parameters
if (tmp == null) {
@@ -331,6 +361,7 @@ public abstract class Executable extends AccessibleObject
tmp = synthesizeAllParams();
} else {
hasRealParameterData = true;
+ verifyParameters(tmp);
}
parameters = tmp;
@@ -352,6 +383,12 @@ public abstract class Executable extends AccessibleObject
private transient volatile Parameter[] parameters;
private native Parameter[] getParameters0();
+ private native byte[] getTypeAnnotationBytes0();
+
+ // Needed by reflectaccess
+ byte[] getTypeAnnotationBytes() {
+ return getTypeAnnotationBytes0();
+ }
/**
* Returns an array of {@code Class} objects that represent the
@@ -514,18 +551,20 @@ public abstract class Executable extends AccessibleObject
}
/**
- * Returns an AnnotatedType object that represents the use of a type to
+ * Returns an {@code AnnotatedType} object that represents the use of a type to
* specify the return type of the method/constructor represented by this
* Executable.
*
- * If this Executable represents a constructor, the AnnotatedType object
- * represents the type of the constructed object.
+ * If this {@code Executable} object represents a constructor, the {@code
+ * AnnotatedType} object represents the type of the constructed object.
*
- * If this Executable represents a method, the AnnotatedType object
- * represents the use of a type to specify the return type of the method.
+ * If this {@code Executable} object represents a method, the {@code
+ * AnnotatedType} object represents the use of a type to specify the return
+ * type of the method.
+ *
+ * @return an object representing the return type of the method
+ * or constructor represented by this {@code Executable}
*
- * @return an object representing the return type of this method
- * or constructor
* @since 1.8
*/
public abstract AnnotatedType getAnnotatedReturnType();
@@ -539,7 +578,7 @@ public abstract class Executable extends AccessibleObject
* @since 1.8
*/
AnnotatedType getAnnotatedReturnType0(Type returnType) {
- return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(),
+ return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
this,
@@ -549,25 +588,30 @@ public abstract class Executable extends AccessibleObject
}
/**
- * Returns an AnnotatedType object that represents the use of a type to
- * specify the receiver type of the method/constructor represented by this
- * Executable. The receiver type of a method/constructor is available only
- * if the method/constructor declares a formal parameter called 'this'.
+ * Returns an {@code AnnotatedType} object that represents the use of a
+ * type to specify the receiver type of the method/constructor represented
+ * by this Executable object. The receiver type of a method/constructor is
+ * available only if the method/constructor has a receiver
+ * parameter (JLS 8.4.1).
*
- * Returns null if this Executable represents a constructor or instance
- * method that either declares no formal parameter called 'this', or
- * declares a formal parameter called 'this' with no annotations on its
- * type.
+ * If this {@code Executable} object represents a constructor or instance
+ * method that does not have a receiver parameter, or has a receiver
+ * parameter with no annotations on its type, then the return value is an
+ * {@code AnnotatedType} object representing an element with no
+ * annotations.
*
- * Returns null if this Executable represents a static method.
+ * If this {@code Executable} object represents a static method, then the
+ * return value is null.
*
- * @return an object representing the receiver type of the
- * method or constructor represented by this Executable
+ * @return an object representing the receiver type of the method or
+ * constructor represented by this {@code Executable}
*
* @since 1.8
*/
public AnnotatedType getAnnotatedReceiverType() {
- return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(),
+ if (Modifier.isStatic(this.getModifiers()))
+ return null;
+ return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
this,
@@ -577,8 +621,8 @@ public abstract class Executable extends AccessibleObject
}
/**
- * Returns an array of AnnotatedType objects that represent the use of
- * types to specify formal parameter types of the method/constructor
+ * Returns an array of {@code AnnotatedType} objects that represent the use
+ * of types to specify formal parameter types of the method/constructor
* represented by this Executable. The order of the objects in the array
* corresponds to the order of the formal parameter types in the
* declaration of the method/constructor.
@@ -587,12 +631,13 @@ public abstract class Executable extends AccessibleObject
* parameters.
*
* @return an array of objects representing the types of the
- * formal parameters of this method or constructor
+ * formal parameters of the method or constructor represented by this
+ * {@code Executable}
*
* @since 1.8
*/
public AnnotatedType[] getAnnotatedParameterTypes() {
- return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes(),
+ return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes0(),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
this,
@@ -602,8 +647,8 @@ public abstract class Executable extends AccessibleObject
}
/**
- * Returns an array of AnnotatedType objects that represent the use of
- * types to specify the declared exceptions of the method/constructor
+ * Returns an array of {@code AnnotatedType} objects that represent the use
+ * of types to specify the declared exceptions of the method/constructor
* represented by this Executable. The order of the objects in the array
* corresponds to the order of the exception types in the declaration of
* the method/constructor.
@@ -612,12 +657,13 @@ public abstract class Executable extends AccessibleObject
* exceptions.
*
* @return an array of objects representing the declared
- * exceptions of this method or constructor
+ * exceptions of the method or constructor represented by this {@code
+ * Executable}
*
* @since 1.8
*/
public AnnotatedType[] getAnnotatedExceptionTypes() {
- return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes(),
+ return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes0(),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
this,
diff --git a/jdk/src/share/classes/java/lang/reflect/Field.java b/jdk/src/share/classes/java/lang/reflect/Field.java
index 4052e06e804..e84b6b242d3 100644
--- a/jdk/src/share/classes/java/lang/reflect/Field.java
+++ b/jdk/src/share/classes/java/lang/reflect/Field.java
@@ -82,8 +82,6 @@ class Field extends AccessibleObject implements Member {
// currently only two levels deep (i.e., one root Field and
// potentially many Field objects pointing to it.)
private Field root;
- // This is set by the vm at Field creation
- private byte[] typeAnnotations;
// Generics infrastructure
@@ -149,7 +147,6 @@ class Field extends AccessibleObject implements Member {
res.fieldAccessor = fieldAccessor;
res.overrideFieldAccessor = overrideFieldAccessor;
- res.typeAnnotations = typeAnnotations;
return res;
}
@@ -1148,6 +1145,8 @@ class Field extends AccessibleObject implements Member {
return declaredAnnotations;
}
+ private native byte[] getTypeAnnotationBytes0();
+
/**
* Returns an AnnotatedType object that represents the use of a type to specify
* the declared type of the field represented by this Field.
@@ -1157,7 +1156,7 @@ class Field extends AccessibleObject implements Member {
* @since 1.8
*/
public AnnotatedType getAnnotatedType() {
- return TypeAnnotationParser.buildAnnotatedType(typeAnnotations,
+ return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
this,
diff --git a/jdk/src/share/classes/java/lang/reflect/MalformedParametersException.java b/jdk/src/share/classes/java/lang/reflect/MalformedParametersException.java
new file mode 100644
index 00000000000..c68600b412a
--- /dev/null
+++ b/jdk/src/share/classes/java/lang/reflect/MalformedParametersException.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * Thrown when {@link java.lang.reflect.Executable#getParameters the
+ * java.lang.reflect package} attempts to read method parameters from
+ * a class file and determines that one or more parameters are
+ * malformed.
+ *
+ *
The following is a list of conditions under which this exception
+ * can be thrown:
+ *
+ * - The number of parameters (parameter_count) is wrong for the method
+ *
- A constant pool index is out of bounds.
+ *
- A constant pool index does not refer to a UTF-8 entry
+ *
- A parameter's name is "", or contains an illegal character
+ *
- The flags field contains an illegal flag (something other than
+ * FINAL, SYNTHETIC, or MANDATED)
+ *
+ *
+ * See {@link java.lang.reflect.Executable#getParameters} for more
+ * information.
+ *
+ * @see java.lang.reflect.Executable#getParameters
+ * @since 1.8
+ */
+public class MalformedParametersException extends RuntimeException {
+
+ private static final long serialVersionUID = 20130919L;
+
+ public MalformedParametersException() {}
+
+ public MalformedParametersException(String reason) {
+ super(reason);
+ }
+}
diff --git a/jdk/src/share/classes/java/lang/reflect/Method.java b/jdk/src/share/classes/java/lang/reflect/Method.java
index 7c7abe43dff..b046a7a1d3d 100644
--- a/jdk/src/share/classes/java/lang/reflect/Method.java
+++ b/jdk/src/share/classes/java/lang/reflect/Method.java
@@ -80,8 +80,6 @@ public final class Method extends Executable {
// currently only two levels deep (i.e., one root Method and
// potentially many Method objects pointing to it.)
private Method root;
- // This is set by the vm at Method creation
- private byte[] typeAnnotations;
// Generics infrastructure
private String getGenericSignature() {return signature;}
@@ -152,8 +150,6 @@ public final class Method extends Executable {
res.root = this;
// Might as well eagerly propagate this if already present
res.methodAccessor = methodAccessor;
-
- res.typeAnnotations = typeAnnotations;
return res;
}
@@ -166,10 +162,6 @@ public final class Method extends Executable {
byte[] getAnnotationBytes() {
return annotations;
}
- @Override
- byte[] getTypeAnnotationBytes() {
- return typeAnnotations;
- }
/**
* {@inheritDoc}
diff --git a/jdk/src/share/classes/java/lang/reflect/Parameter.java b/jdk/src/share/classes/java/lang/reflect/Parameter.java
index 0568d9ee2e0..2285819c27b 100644
--- a/jdk/src/share/classes/java/lang/reflect/Parameter.java
+++ b/jdk/src/share/classes/java/lang/reflect/Parameter.java
@@ -104,7 +104,7 @@ public final class Parameter implements AnnotatedElement {
* to the class file.
*/
public boolean isNamePresent() {
- return executable.hasRealParameterData();
+ return executable.hasRealParameterData() && name != null;
}
/**
@@ -182,6 +182,11 @@ public final class Parameter implements AnnotatedElement {
return name;
}
+ // Package-private accessor to the real name field.
+ String getRealName() {
+ return name;
+ }
+
/**
* Returns a {@code Type} object that identifies the parameterized
* type for the parameter represented by this {@code Parameter}
diff --git a/jdk/src/share/classes/java/net/URI.java b/jdk/src/share/classes/java/net/URI.java
index 77c2f7a178f..71c4f6dc5de 100644
--- a/jdk/src/share/classes/java/net/URI.java
+++ b/jdk/src/share/classes/java/net/URI.java
@@ -188,7 +188,7 @@ import java.lang.NullPointerException; // for javadoc
* URI
*
*
- * {@code http://java.sun.com/j2se/1.3/docs/guide/collections/designfaq.html#28}
+ * {@code http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28}
*
*
* Resolving the relative URI
@@ -227,7 +227,7 @@ import java.lang.NullPointerException; // for javadoc
* possible. For example, relativizing the URI
*
*
- * {@code http://java.sun.com/j2se/1.3/docs/guide/index.html}
+ * {@code http://docs.oracle.com/javase/1.3/docs/guide/index.html}
*
*
* against the base URI
diff --git a/jdk/src/share/classes/java/nio/file/Files.java b/jdk/src/share/classes/java/nio/file/Files.java
index f084040c179..01629442af4 100644
--- a/jdk/src/share/classes/java/nio/file/Files.java
+++ b/jdk/src/share/classes/java/nio/file/Files.java
@@ -2128,7 +2128,7 @@ public final class Files {
/**
* Tests whether a file is a symbolic link.
*
- * Where is it required to distinguish an I/O exception from the case
+ *
Where it is required to distinguish an I/O exception from the case
* that the file is not a symbolic link then the file attributes can be
* read with the {@link #readAttributes(Path,Class,LinkOption[])
* readAttributes} method and the file type tested with the {@link
@@ -2164,7 +2164,7 @@ public final class Files {
* of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS
* NOFOLLOW_LINKS} is present then symbolic links are not followed.
*
- *
Where is it required to distinguish an I/O exception from the case
+ *
Where it is required to distinguish an I/O exception from the case
* that the file is not a directory then the file attributes can be
* read with the {@link #readAttributes(Path,Class,LinkOption[])
* readAttributes} method and the file type tested with the {@link
@@ -2201,7 +2201,7 @@ public final class Files {
* of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS
* NOFOLLOW_LINKS} is present then symbolic links are not followed.
*
- *
Where is it required to distinguish an I/O exception from the case
+ *
Where it is required to distinguish an I/O exception from the case
* that the file is not a regular file then the file attributes can be
* read with the {@link #readAttributes(Path,Class,LinkOption[])
* readAttributes} method and the file type tested with the {@link
@@ -3082,13 +3082,13 @@ public final class Files {
* method is invoked to check read access to the file.
*/
public static byte[] readAllBytes(Path path) throws IOException {
- try (FileChannel fc = FileChannel.open(path);
- InputStream is = Channels.newInputStream(fc)) {
- long size = fc.size();
+ try (SeekableByteChannel sbc = Files.newByteChannel(path);
+ InputStream in = Channels.newInputStream(sbc)) {
+ long size = sbc.size();
if (size > (long)MAX_BUFFER_SIZE)
throw new OutOfMemoryError("Required array size too large");
- return read(is, (int)size);
+ return read(in, (int)size);
}
}
diff --git a/jdk/src/share/classes/java/nio/file/Path.java b/jdk/src/share/classes/java/nio/file/Path.java
index 39afd4d4255..2bcc9aa3512 100644
--- a/jdk/src/share/classes/java/nio/file/Path.java
+++ b/jdk/src/share/classes/java/nio/file/Path.java
@@ -315,7 +315,7 @@ public interface Path
* and parent directory. In such file systems all occurrences of "{@code .}"
* are considered redundant. If a "{@code ..}" is preceded by a
* non-"{@code ..}" name then both names are considered redundant (the
- * process to identify such names is repeated until is it no longer
+ * process to identify such names is repeated until it is no longer
* applicable).
*
*
This method does not access the file system; the path may not locate
diff --git a/jdk/src/share/classes/java/security/SecureRandom.java b/jdk/src/share/classes/java/security/SecureRandom.java
index 5afec7b0797..b9ae7220b38 100644
--- a/jdk/src/share/classes/java/security/SecureRandom.java
+++ b/jdk/src/share/classes/java/security/SecureRandom.java
@@ -578,39 +578,30 @@ public class SecureRandom extends java.util.Random {
/**
* Returns a {@code SecureRandom} object that was selected by using
* the algorithms/providers specified in the {@code
- * securerandom.strongAlgorithms} Security property.
+ * securerandom.strongAlgorithms} {@link Security} property.
*
* Some situations require strong random values, such as when
* creating high-value/long-lived secrets like RSA public/private
* keys. To help guide applications in selecting a suitable strong
- * {@code SecureRandom} implementation, Java distributions should
+ * {@code SecureRandom} implementation, Java distributions
* include a list of known strong {@code SecureRandom}
* implementations in the {@code securerandom.strongAlgorithms}
* Security property.
- *
- *
- * SecureRandom sr = SecureRandom.getStrongSecureRandom();
- *
- * if (sr == null) {
- * // Decide if this is a problem, and whether to recover.
- * sr = new SecureRandom();
- * if (!goodEnough(sr)) {
- * return;
- * }
- * }
- *
- * keyPairGenerator.initialize(2048, sr);
- *
+ *
+ * Every implementation of the Java platform is required to
+ * support at least one strong {@code SecureRandom} implementation.
*
* @return a strong {@code SecureRandom} implementation as indicated
- * by the {@code securerandom.strongAlgorithms} Security property, or
- * null if none are available.
+ * by the {@code securerandom.strongAlgorithms} Security property
+ *
+ * @throws NoSuchAlgorithmException if no algorithm is available
*
* @see Security#getProperty(String)
*
* @since 1.8
*/
- public static SecureRandom getStrongSecureRandom() {
+ public static SecureRandom getInstanceStrong()
+ throws NoSuchAlgorithmException {
String property = AccessController.doPrivileged(
new PrivilegedAction() {
@@ -622,7 +613,8 @@ public class SecureRandom extends java.util.Random {
});
if ((property == null) || (property.length() == 0)) {
- return null;
+ throw new NoSuchAlgorithmException(
+ "Null/empty securerandom.strongAlgorithms Security Property");
}
String remainder = property;
@@ -649,7 +641,8 @@ public class SecureRandom extends java.util.Random {
}
}
- return null;
+ throw new NoSuchAlgorithmException(
+ "No strong SecureRandom impls available: " + property);
}
// Declare serialVersionUID to be compatible with JDK1.1
diff --git a/jdk/src/share/classes/java/text/DecimalFormat.java b/jdk/src/share/classes/java/text/DecimalFormat.java
index c22e47212bb..f89fd151749 100644
--- a/jdk/src/share/classes/java/text/DecimalFormat.java
+++ b/jdk/src/share/classes/java/text/DecimalFormat.java
@@ -371,7 +371,7 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter;
* }
* }
*
- * @see Java Tutorial
+ * @see Java Tutorial
* @see NumberFormat
* @see DecimalFormatSymbols
* @see ParsePosition
diff --git a/jdk/src/share/classes/java/text/SimpleDateFormat.java b/jdk/src/share/classes/java/text/SimpleDateFormat.java
index 5472b0a70d3..fa9f673b8b8 100644
--- a/jdk/src/share/classes/java/text/SimpleDateFormat.java
+++ b/jdk/src/share/classes/java/text/SimpleDateFormat.java
@@ -412,7 +412,7 @@ import sun.util.locale.provider.LocaleProviderAdapter;
* If multiple threads access a format concurrently, it must be synchronized
* externally.
*
- * @see Java Tutorial
+ * @see Java Tutorial
* @see java.util.Calendar
* @see java.util.TimeZone
* @see DateFormat
diff --git a/jdk/src/share/classes/java/time/Duration.java b/jdk/src/share/classes/java/time/Duration.java
index ce2ba7781b0..896a2990eaa 100644
--- a/jdk/src/share/classes/java/time/Duration.java
+++ b/jdk/src/share/classes/java/time/Duration.java
@@ -441,9 +441,13 @@ public final class Duration
//-----------------------------------------------------------------------
/**
- * Obtains a {@code Duration} representing the duration between two instants.
+ * Obtains a {@code Duration} representing the duration between two temporal objects.
+ *
+ * This calculates the duration between two temporal objects. If the objects
+ * are of different types, then the duration is calculated based on the type
+ * of the first object. For example, if the first argument is a {@code LocalTime}
+ * then the second argument is converted to a {@code LocalTime}.
*
- * This calculates the duration between two temporal objects of the same type.
* The specified temporal objects must support the {@link ChronoUnit#SECONDS SECONDS} unit.
* For full accuracy, either the {@link ChronoUnit#NANOS NANOS} unit or the
* {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field should be supported.
diff --git a/jdk/src/share/classes/java/time/Instant.java b/jdk/src/share/classes/java/time/Instant.java
index 9d74e29f91a..0e22c7bf972 100644
--- a/jdk/src/share/classes/java/time/Instant.java
+++ b/jdk/src/share/classes/java/time/Instant.java
@@ -362,6 +362,10 @@ public final class Instant
* @throws DateTimeException if unable to convert to an {@code Instant}
*/
public static Instant from(TemporalAccessor temporal) {
+ if (temporal instanceof Instant) {
+ return (Instant) temporal;
+ }
+ Objects.requireNonNull(temporal, "temporal");
long instantSecs = temporal.getLong(INSTANT_SECONDS);
int nanoOfSecond = temporal.get(NANO_OF_SECOND);
return Instant.ofEpochSecond(instantSecs, nanoOfSecond);
@@ -370,7 +374,7 @@ public final class Instant
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code Instant} from a text string such as
- * {@code 2007-12-03T10:15:30:00}.
+ * {@code 2007-12-03T10:15:30.00Z}.
*
* The string must represent a valid instant in UTC and is parsed using
* {@link DateTimeFormatter#ISO_INSTANT}.
@@ -1091,7 +1095,8 @@ public final class Instant
* The result will be negative if the end is before the start.
* The calculation returns a whole number, representing the number of
* complete units between the two instants.
- * The {@code Temporal} passed to this method must be an {@code Instant}.
+ * The {@code Temporal} passed to this method is converted to a
+ * {@code Instant} using {@link #from(TemporalAccessor)}.
* For example, the amount in days between two dates can be calculated
* using {@code startInstant.until(endInstant, SECONDS)}.
*
@@ -1112,25 +1117,22 @@ public final class Instant
*
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
- * passing {@code this} as the first argument and the input temporal as
- * the second argument.
+ * passing {@code this} as the first argument and the converted input temporal
+ * as the second argument.
*
* This instance is immutable and unaffected by this method call.
*
- * @param endInstant the end date, which must be an {@code Instant}, not null
+ * @param endExclusive the end date, exclusive, which is converted to an {@code Instant}, not null
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this instant and the end instant
- * @throws DateTimeException if the amount cannot be calculated
+ * @throws DateTimeException if the amount cannot be calculated, or the end
+ * temporal cannot be converted to an {@code Instant}
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
- public long until(Temporal endInstant, TemporalUnit unit) {
- if (endInstant instanceof Instant == false) {
- Objects.requireNonNull(endInstant, "endInstant");
- throw new DateTimeException("Unable to calculate amount as objects are of two different types");
- }
- Instant end = (Instant) endInstant;
+ public long until(Temporal endExclusive, TemporalUnit unit) {
+ Instant end = Instant.from(endExclusive);
if (unit instanceof ChronoUnit) {
ChronoUnit f = (ChronoUnit) unit;
switch (f) {
@@ -1145,7 +1147,7 @@ public final class Instant
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
- return unit.between(this, endInstant);
+ return unit.between(this, end);
}
private long nanosUntil(Instant end) {
diff --git a/jdk/src/share/classes/java/time/LocalDate.java b/jdk/src/share/classes/java/time/LocalDate.java
index 3005658366a..f388959aa63 100644
--- a/jdk/src/share/classes/java/time/LocalDate.java
+++ b/jdk/src/share/classes/java/time/LocalDate.java
@@ -353,6 +353,7 @@ public final class LocalDate
* @throws DateTimeException if unable to convert to a {@code LocalDate}
*/
public static LocalDate from(TemporalAccessor temporal) {
+ Objects.requireNonNull(temporal, "temporal");
LocalDate date = temporal.query(TemporalQuery.localDate());
if (date == null) {
throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " + temporal.getClass());
@@ -1125,6 +1126,11 @@ public final class LocalDate
*/
@Override
public LocalDate plus(TemporalAmount amountToAdd) {
+ if (amountToAdd instanceof Period) {
+ Period periodToAdd = (Period) amountToAdd;
+ return plusMonths(periodToAdd.toTotalMonths()).plusDays(periodToAdd.getDays());
+ }
+ Objects.requireNonNull(amountToAdd, "amountToAdd");
return (LocalDate) amountToAdd.addTo(this);
}
@@ -1353,6 +1359,11 @@ public final class LocalDate
*/
@Override
public LocalDate minus(TemporalAmount amountToSubtract) {
+ if (amountToSubtract instanceof Period) {
+ Period periodToSubtract = (Period) amountToSubtract;
+ return minusMonths(periodToSubtract.toTotalMonths()).minusDays(periodToSubtract.getDays());
+ }
+ Objects.requireNonNull(amountToSubtract, "amountToSubtract");
return (LocalDate) amountToSubtract.subtractFrom(this);
}
@@ -1531,7 +1542,8 @@ public final class LocalDate
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified date.
* The result will be negative if the end is before the start.
- * The {@code Temporal} passed to this method must be a {@code LocalDate}.
+ * The {@code Temporal} passed to this method is converted to a
+ * {@code LocalDate} using {@link #from(TemporalAccessor)}.
* For example, the amount in days between two dates can be calculated
* using {@code startDate.until(endDate, DAYS)}.
*
@@ -1557,26 +1569,22 @@ public final class LocalDate
*
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
- * passing {@code this} as the first argument and the input temporal as
- * the second argument.
+ * passing {@code this} as the first argument and the converted input temporal
+ * as the second argument.
*
* This instance is immutable and unaffected by this method call.
*
- * @param endDate the end date, which must be a {@code LocalDate}, not null
+ * @param endExclusive the end date, exclusive, which is converted to a {@code LocalDate}, not null
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this date and the end date
- * @throws DateTimeException if the amount cannot be calculated
+ * @throws DateTimeException if the amount cannot be calculated, or the end
+ * temporal cannot be converted to a {@code LocalDate}
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
- public long until(Temporal endDate, TemporalUnit unit) {
- Objects.requireNonNull(unit, "unit");
- if (endDate instanceof LocalDate == false) {
- Objects.requireNonNull(endDate, "endDate");
- throw new DateTimeException("Unable to calculate amount as objects are of two different types");
- }
- LocalDate end = (LocalDate) endDate;
+ public long until(Temporal endExclusive, TemporalUnit unit) {
+ LocalDate end = LocalDate.from(endExclusive);
if (unit instanceof ChronoUnit) {
switch ((ChronoUnit) unit) {
case DAYS: return daysUntil(end);
@@ -1590,7 +1598,7 @@ public final class LocalDate
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
- return unit.between(this, endDate);
+ return unit.between(this, end);
}
long daysUntil(LocalDate end) {
@@ -1632,12 +1640,12 @@ public final class LocalDate
*
* The choice should be made based on which makes the code more readable.
*
- * @param endDate the end date, exclusive, which may be in any chronology, not null
+ * @param endDateExclusive the end date, exclusive, which may be in any chronology, not null
* @return the period between this date and the end date, not null
*/
@Override
- public Period until(ChronoLocalDate endDate) {
- LocalDate end = LocalDate.from(endDate);
+ public Period until(ChronoLocalDate endDateExclusive) {
+ LocalDate end = LocalDate.from(endDateExclusive);
long totalMonths = end.getProlepticMonth() - this.getProlepticMonth(); // safe
int days = end.day - this.day;
if (totalMonths > 0 && days < 0) {
diff --git a/jdk/src/share/classes/java/time/LocalDateTime.java b/jdk/src/share/classes/java/time/LocalDateTime.java
index de8b246d6bb..aed44dd4bfe 100644
--- a/jdk/src/share/classes/java/time/LocalDateTime.java
+++ b/jdk/src/share/classes/java/time/LocalDateTime.java
@@ -1129,6 +1129,11 @@ public final class LocalDateTime
*/
@Override
public LocalDateTime plus(TemporalAmount amountToAdd) {
+ if (amountToAdd instanceof Period) {
+ Period periodToAdd = (Period) amountToAdd;
+ return with(date.plus(periodToAdd), time);
+ }
+ Objects.requireNonNull(amountToAdd, "amountToAdd");
return (LocalDateTime) amountToAdd.addTo(this);
}
@@ -1343,6 +1348,11 @@ public final class LocalDateTime
*/
@Override
public LocalDateTime minus(TemporalAmount amountToSubtract) {
+ if (amountToSubtract instanceof Period) {
+ Period periodToSubtract = (Period) amountToSubtract;
+ return with(date.minus(periodToSubtract), time);
+ }
+ Objects.requireNonNull(amountToSubtract, "amountToSubtract");
return (LocalDateTime) amountToSubtract.subtractFrom(this);
}
@@ -1611,7 +1621,8 @@ public final class LocalDateTime
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified date-time.
* The result will be negative if the end is before the start.
- * The {@code Temporal} passed to this method must be a {@code LocalDateTime}.
+ * The {@code Temporal} passed to this method is converted to a
+ * {@code LocalDateTime} using {@link #from(TemporalAccessor)}.
* For example, the amount in days between two date-times can be calculated
* using {@code startDateTime.until(endDateTime, DAYS)}.
*
@@ -1639,25 +1650,22 @@ public final class LocalDateTime
*
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
- * passing {@code this} as the first argument and the input temporal as
- * the second argument.
+ * passing {@code this} as the first argument and the converted input temporal
+ * as the second argument.
*
* This instance is immutable and unaffected by this method call.
*
- * @param endDateTime the end date-time, which must be a {@code LocalDateTime}, not null
+ * @param endExclusive the end date, exclusive, which is converted to a {@code LocalDateTime}, not null
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this date-time and the end date-time
- * @throws DateTimeException if the amount cannot be calculated
+ * @throws DateTimeException if the amount cannot be calculated, or the end
+ * temporal cannot be converted to a {@code LocalDateTime}
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
- public long until(Temporal endDateTime, TemporalUnit unit) {
- if (endDateTime instanceof LocalDateTime == false) {
- Objects.requireNonNull(endDateTime, "endDateTime");
- throw new DateTimeException("Unable to calculate amount as objects are of two different types");
- }
- LocalDateTime end = (LocalDateTime) endDateTime;
+ public long until(Temporal endExclusive, TemporalUnit unit) {
+ LocalDateTime end = LocalDateTime.from(endExclusive);
if (unit instanceof ChronoUnit) {
if (unit.isTimeBased()) {
long amount = date.daysUntil(end.date);
@@ -1711,7 +1719,7 @@ public final class LocalDateTime
}
return date.until(endDate, unit);
}
- return unit.between(this, endDateTime);
+ return unit.between(this, end);
}
/**
diff --git a/jdk/src/share/classes/java/time/LocalTime.java b/jdk/src/share/classes/java/time/LocalTime.java
index a6270db19cf..77ab2c7f286 100644
--- a/jdk/src/share/classes/java/time/LocalTime.java
+++ b/jdk/src/share/classes/java/time/LocalTime.java
@@ -394,6 +394,7 @@ public final class LocalTime
* @throws DateTimeException if unable to convert to a {@code LocalTime}
*/
public static LocalTime from(TemporalAccessor temporal) {
+ Objects.requireNonNull(temporal, "temporal");
LocalTime time = temporal.query(TemporalQuery.localTime());
if (time == null) {
throw new DateTimeException("Unable to obtain LocalTime from TemporalAccessor: " + temporal.getClass());
@@ -1330,7 +1331,8 @@ public final class LocalTime
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified time.
* The result will be negative if the end is before the start.
- * The {@code Temporal} passed to this method must be a {@code LocalTime}.
+ * The {@code Temporal} passed to this method is converted to a
+ * {@code LocalTime} using {@link #from(TemporalAccessor)}.
* For example, the amount in hours between two times can be calculated
* using {@code startTime.until(endTime, HOURS)}.
*
@@ -1356,25 +1358,22 @@ public final class LocalTime
*
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
- * passing {@code this} as the first argument and the input temporal as
- * the second argument.
+ * passing {@code this} as the first argument and the converted input temporal
+ * as the second argument.
*
* This instance is immutable and unaffected by this method call.
*
- * @param endTime the end time, which must be a {@code LocalTime}, not null
+ * @param endExclusive the end time, exclusive, which is converted to a {@code LocalTime}, not null
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this time and the end time
- * @throws DateTimeException if the amount cannot be calculated
+ * @throws DateTimeException if the amount cannot be calculated, or the end
+ * temporal cannot be converted to a {@code LocalTime}
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
- public long until(Temporal endTime, TemporalUnit unit) {
- if (endTime instanceof LocalTime == false) {
- Objects.requireNonNull(endTime, "endTime");
- throw new DateTimeException("Unable to calculate amount as objects are of two different types");
- }
- LocalTime end = (LocalTime) endTime;
+ public long until(Temporal endExclusive, TemporalUnit unit) {
+ LocalTime end = LocalTime.from(endExclusive);
if (unit instanceof ChronoUnit) {
long nanosUntil = end.toNanoOfDay() - toNanoOfDay(); // no overflow
switch ((ChronoUnit) unit) {
@@ -1388,7 +1387,7 @@ public final class LocalTime
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
- return unit.between(this, endTime);
+ return unit.between(this, end);
}
/**
diff --git a/jdk/src/share/classes/java/time/MonthDay.java b/jdk/src/share/classes/java/time/MonthDay.java
index 22807822f2b..67f5d4fa87f 100644
--- a/jdk/src/share/classes/java/time/MonthDay.java
+++ b/jdk/src/share/classes/java/time/MonthDay.java
@@ -246,7 +246,8 @@ public final class MonthDay
*
* The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and
* {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} fields.
- * The extraction is only permitted if the date-time has an ISO chronology.
+ * The extraction is only permitted if the temporal object has an ISO
+ * chronology, or can be converted to a {@code LocalDate}.
*
* This method matches the signature of the functional interface {@link TemporalQuery}
* allowing it to be used in queries via method reference, {@code MonthDay::from}.
diff --git a/jdk/src/share/classes/java/time/OffsetDateTime.java b/jdk/src/share/classes/java/time/OffsetDateTime.java
index f894e53e46f..410c7f3a747 100644
--- a/jdk/src/share/classes/java/time/OffsetDateTime.java
+++ b/jdk/src/share/classes/java/time/OffsetDateTime.java
@@ -1592,7 +1592,8 @@ public final class OffsetDateTime
* For example, the period in days between two date-times can be calculated
* using {@code startDateTime.until(endDateTime, DAYS)}.
*
- * The {@code Temporal} passed to this method must be an {@code OffsetDateTime}.
+ * The {@code Temporal} passed to this method is converted to a
+ * {@code OffsetDateTime} using {@link #from(TemporalAccessor)}.
* If the offset differs between the two date-times, the specified
* end date-time is normalized to have the same offset as this date-time.
*
@@ -1620,30 +1621,27 @@ public final class OffsetDateTime
*
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
- * passing {@code this} as the first argument and the input temporal as
- * the second argument.
+ * passing {@code this} as the first argument and the converted input temporal
+ * as the second argument.
*
* This instance is immutable and unaffected by this method call.
*
- * @param endDateTime the end date-time, which must be an {@code OffsetDateTime}, not null
+ * @param endExclusive the end date, exclusive, which is converted to an {@code OffsetDateTime}, not null
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this date-time and the end date-time
- * @throws DateTimeException if the amount cannot be calculated
+ * @throws DateTimeException if the amount cannot be calculated, or the end
+ * temporal cannot be converted to an {@code OffsetDateTime}
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
- public long until(Temporal endDateTime, TemporalUnit unit) {
- if (endDateTime instanceof OffsetDateTime == false) {
- Objects.requireNonNull(endDateTime, "endDateTime");
- throw new DateTimeException("Unable to calculate amount as objects are of two different types");
- }
+ public long until(Temporal endExclusive, TemporalUnit unit) {
+ OffsetDateTime end = OffsetDateTime.from(endExclusive);
if (unit instanceof ChronoUnit) {
- OffsetDateTime end = (OffsetDateTime) endDateTime;
end = end.withOffsetSameInstant(offset);
return dateTime.until(end.dateTime, unit);
}
- return unit.between(this, endDateTime);
+ return unit.between(this, end);
}
/**
diff --git a/jdk/src/share/classes/java/time/OffsetTime.java b/jdk/src/share/classes/java/time/OffsetTime.java
index 6c67ef82bb1..a8dbf8a7a56 100644
--- a/jdk/src/share/classes/java/time/OffsetTime.java
+++ b/jdk/src/share/classes/java/time/OffsetTime.java
@@ -1124,7 +1124,8 @@ public final class OffsetTime
* For example, the period in hours between two times can be calculated
* using {@code startTime.until(endTime, HOURS)}.
*
- * The {@code Temporal} passed to this method must be an {@code OffsetTime}.
+ * The {@code Temporal} passed to this method is converted to a
+ * {@code OffsetTime} using {@link #from(TemporalAccessor)}.
* If the offset differs between the two times, then the specified
* end time is normalized to have the same offset as this time.
*
@@ -1150,26 +1151,23 @@ public final class OffsetTime
*
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
- * passing {@code this} as the first argument and the input temporal as
- * the second argument.
+ * passing {@code this} as the first argument and the converted input temporal
+ * as the second argument.
*
* This instance is immutable and unaffected by this method call.
*
- * @param endTime the end time, which must be an {@code OffsetTime}, not null
+ * @param endExclusive the end date, exclusive, which is converted to an {@code OffsetTime}, not null
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this time and the end time
- * @throws DateTimeException if the amount cannot be calculated
+ * @throws DateTimeException if the amount cannot be calculated, or the end
+ * temporal cannot be converted to an {@code OffsetTime}
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
- public long until(Temporal endTime, TemporalUnit unit) {
- if (endTime instanceof OffsetTime == false) {
- Objects.requireNonNull(endTime, "endTime");
- throw new DateTimeException("Unable to calculate amount as objects are of two different types");
- }
+ public long until(Temporal endExclusive, TemporalUnit unit) {
+ OffsetTime end = OffsetTime.from(endExclusive);
if (unit instanceof ChronoUnit) {
- OffsetTime end = (OffsetTime) endTime;
long nanosUntil = end.toEpochNano() - toEpochNano(); // no overflow
switch ((ChronoUnit) unit) {
case NANOS: return nanosUntil;
@@ -1182,7 +1180,7 @@ public final class OffsetTime
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
- return unit.between(this, endTime);
+ return unit.between(this, end);
}
/**
diff --git a/jdk/src/share/classes/java/time/Period.java b/jdk/src/share/classes/java/time/Period.java
index 161ce49e565..bd272a9913e 100644
--- a/jdk/src/share/classes/java/time/Period.java
+++ b/jdk/src/share/classes/java/time/Period.java
@@ -61,7 +61,6 @@
*/
package java.time;
-import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.MONTHS;
import static java.time.temporal.ChronoUnit.YEARS;
@@ -70,17 +69,19 @@ import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
-import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.ChronoPeriod;
import java.time.chrono.Chronology;
+import java.time.chrono.IsoChronology;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
-import java.time.temporal.ValueRange;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -89,12 +90,13 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
- * A date-based amount of time, such as '2 years, 3 months and 4 days'.
+ * A date-based amount of time in the ISO-8601 calendar system,
+ * such as '2 years, 3 months and 4 days'.
*
* This class models a quantity or amount of time in terms of years, months and days.
* See {@link Duration} for the time-based equivalent to this class.
*
- * Durations and period differ in their treatment of daylight savings time
+ * Durations and periods differ in their treatment of daylight savings time
* when added to {@link ZonedDateTime}. A {@code Duration} will add an exact
* number of seconds, thus a duration of one day is always exactly 24 hours.
* By contrast, a {@code Period} will add a conceptual day, trying to maintain
@@ -110,14 +112,12 @@ import java.util.regex.Pattern;
* {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
* All three fields are always present, but may be set to zero.
*
- * The period may be used with any calendar system.
- * The meaning of a "year" or "month" is only applied when the object is added to a date.
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
*
* The period is modeled as a directed amount of time, meaning that individual parts of the
* period may be negative.
- *
- * The months and years fields may be {@linkplain #normalized() normalized}.
- * The normalization assumes a 12 month year, so is not appropriate for all calendar systems.
*
* @implSpec
* This class is immutable and thread-safe.
@@ -125,7 +125,7 @@ import java.util.regex.Pattern;
* @since 1.8
*/
public final class Period
- implements TemporalAmount, Serializable {
+ implements ChronoPeriod, Serializable {
/**
* A constant for a period of zero.
@@ -140,6 +140,7 @@ public final class Period
*/
private final static Pattern PATTERN =
Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?", Pattern.CASE_INSENSITIVE);
+
/**
* The set of supported units.
*/
@@ -234,12 +235,14 @@ public final class Period
*
* This obtains a period based on the specified amount.
* A {@code TemporalAmount} represents an amount of time, which may be
- * date-based or time-based, which this factory extracts to a period.
+ * date-based or time-based, which this factory extracts to a {@code Period}.
*
* The conversion loops around the set of units from the amount and uses
* the {@link ChronoUnit#YEARS YEARS}, {@link ChronoUnit#MONTHS MONTHS}
* and {@link ChronoUnit#DAYS DAYS} units to create a period.
* If any other units are found then an exception is thrown.
+ *
+ * If the amount is a {@code ChronoPeriod} then it must use the ISO chronology.
*
* @param amount the temporal amount to convert, not null
* @return the equivalent period, not null
@@ -247,6 +250,14 @@ public final class Period
* @throws ArithmeticException if the amount of years, months or days exceeds an int
*/
public static Period from(TemporalAmount amount) {
+ if (amount instanceof Period) {
+ return (Period) amount;
+ }
+ if (amount instanceof ChronoPeriod) {
+ if (IsoChronology.INSTANCE.equals(((ChronoPeriod) amount).getChronology()) == false) {
+ throw new DateTimeException("Period requires ISO chronology: " + amount);
+ }
+ }
Objects.requireNonNull(amount, "amount");
int years = 0;
int months = 0;
@@ -358,13 +369,13 @@ public final class Period
* The result of this method can be a negative period if the end is before the start.
* The negative sign will be the same in each of year, month and day.
*
- * @param startDate the start date, inclusive, not null
- * @param endDate the end date, exclusive, not null
+ * @param startDateInclusive the start date, inclusive, not null
+ * @param endDateExclusive the end date, exclusive, not null
* @return the period between this date and the end date, not null
* @see ChronoLocalDate#until(ChronoLocalDate)
*/
- public static Period between(LocalDate startDate, LocalDate endDate) {
- return startDate.until(endDate);
+ public static Period between(LocalDate startDateInclusive, LocalDate endDateExclusive) {
+ return startDateInclusive.until(endDateExclusive);
}
//-----------------------------------------------------------------------
@@ -439,6 +450,21 @@ public final class Period
return SUPPORTED_UNITS;
}
+ /**
+ * Gets the chronology of this period, which is the ISO calendar system.
+ *
+ * The {@code Chronology} represents the calendar system in use.
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
+ *
+ * @return the ISO chronology, not null
+ */
+ @Override
+ public IsoChronology getChronology() {
+ return IsoChronology.INSTANCE;
+ }
+
//-----------------------------------------------------------------------
/**
* Checks if all three units of this period are zero.
@@ -468,7 +494,7 @@ public final class Period
*
* This returns the years unit.
*
- * The months unit is not normalized with the years unit.
+ * The months unit is not automatically normalized with the years unit.
* This means that a period of "15 months" is different to a period
* of "1 year and 3 months".
*
@@ -483,7 +509,7 @@ public final class Period
*
* This returns the months unit.
*
- * The months unit is not normalized with the years unit.
+ * The months unit is not automatically normalized with the years unit.
* This means that a period of "15 months" is different to a period
* of "1 year and 3 months".
*
@@ -511,7 +537,7 @@ public final class Period
* This sets the amount of the years unit in a copy of this period.
* The months and days units are unaffected.
*
- * The months unit is not normalized with the years unit.
+ * The months unit is not automatically normalized with the years unit.
* This means that a period of "15 months" is different to a period
* of "1 year and 3 months".
*
@@ -533,7 +559,7 @@ public final class Period
* This sets the amount of the months unit in a copy of this period.
* The years and days units are unaffected.
*
- * The months unit is not normalized with the years unit.
+ * The months unit is not automatically normalized with the years unit.
* This means that a period of "15 months" is different to a period
* of "1 year and 3 months".
*
@@ -572,21 +598,28 @@ public final class Period
* Returns a copy of this period with the specified period added.
*
* This operates separately on the years, months and days.
+ * No normalization is performed.
*
* For example, "1 year, 6 months and 3 days" plus "2 years, 2 months and 2 days"
* returns "3 years, 8 months and 5 days".
*
+ * The specified amount is typically an instance of {@code Period}.
+ * Other types are interpreted using {@link Period#from(TemporalAmount)}.
+ *
* This instance is immutable and unaffected by this method call.
*
* @param amountToAdd the period to add, not null
* @return a {@code Period} based on this period with the requested period added, not null
+ * @throws DateTimeException if the specified amount has a non-ISO chronology or
+ * contains an invalid unit
* @throws ArithmeticException if numeric overflow occurs
*/
- public Period plus(Period amountToAdd) {
+ public Period plus(TemporalAmount amountToAdd) {
+ Period isoAmount = Period.from(amountToAdd);
return create(
- Math.addExact(years, amountToAdd.years),
- Math.addExact(months, amountToAdd.months),
- Math.addExact(days, amountToAdd.days));
+ Math.addExact(years, isoAmount.years),
+ Math.addExact(months, isoAmount.months),
+ Math.addExact(days, isoAmount.days));
}
/**
@@ -654,21 +687,28 @@ public final class Period
* Returns a copy of this period with the specified period subtracted.
*
* This operates separately on the years, months and days.
+ * No normalization is performed.
*
* For example, "1 year, 6 months and 3 days" minus "2 years, 2 months and 2 days"
* returns "-1 years, 4 months and 1 day".
*
+ * The specified amount is typically an instance of {@code Period}.
+ * Other types are interpreted using {@link Period#from(TemporalAmount)}.
+ *
* This instance is immutable and unaffected by this method call.
*
* @param amountToSubtract the period to subtract, not null
* @return a {@code Period} based on this period with the requested period subtracted, not null
+ * @throws DateTimeException if the specified amount has a non-ISO chronology or
+ * contains an invalid unit
* @throws ArithmeticException if numeric overflow occurs
*/
- public Period minus(Period amountToSubtract) {
+ public Period minus(TemporalAmount amountToSubtract) {
+ Period isoAmount = Period.from(amountToSubtract);
return create(
- Math.subtractExact(years, amountToSubtract.years),
- Math.subtractExact(months, amountToSubtract.months),
- Math.subtractExact(days, amountToSubtract.days));
+ Math.subtractExact(years, isoAmount.years),
+ Math.subtractExact(months, isoAmount.months),
+ Math.subtractExact(days, isoAmount.days));
}
/**
@@ -766,8 +806,7 @@ public final class Period
//-----------------------------------------------------------------------
/**
- * Returns a copy of this period with the years and months normalized
- * using a 12 month year.
+ * Returns a copy of this period with the years and months normalized.
*
* This normalizes the years and months units, leaving the days unit unchanged.
* The months unit is adjusted to have an absolute value less than 11,
@@ -778,8 +817,6 @@ public final class Period
* For example, a period of "1 year and -25 months" will be normalized to
* "-1 year and -1 month".
*
- * This normalization uses a 12 month year which is not valid for all calendar systems.
- *
* This instance is immutable and unaffected by this method call.
*
* @return a {@code Period} based on this period with excess months normalized to years, not null
@@ -796,13 +833,11 @@ public final class Period
}
/**
- * Gets the total number of months in this period using a 12 month year.
+ * Gets the total number of months in this period.
*
* This returns the total number of months in the period by multiplying the
* number of years by 12 and adding the number of months.
*
- * This uses a 12 month year which is not valid for all calendar systems.
- *
* This instance is immutable and unaffected by this method call.
*
* @return the total number of months in the period, may be negative
@@ -817,6 +852,7 @@ public final class Period
*
* This returns a temporal object of the same observable type as the input
* with this period added.
+ * If the temporal has a chronology, it must be the ISO chronology.
*
* In most cases, it is clearer to reverse the calling pattern by using
* {@link Temporal#plus(TemporalAmount)}.
@@ -826,10 +862,17 @@ public final class Period
* dateTime = dateTime.plus(thisPeriod);
*
*
- * The calculation will add the years, then months, then days.
- * Only non-zero amounts will be added.
- * If the date-time has a calendar system with a fixed number of months in a
- * year, then the years and months will be combined before being added.
+ * The calculation operates as follows.
+ * First, the chronology of the temporal is checked to ensure it is ISO chronology or null.
+ * Second, if the months are zero, the years are added if non-zero, otherwise
+ * the combination of years and months is added if non-zero.
+ * Finally, any days are added.
+ *
+ * This approach ensures that a partial period can be added to a partial date.
+ * For example, a period of years and/or months can be added to a {@code YearMonth},
+ * but a period including days cannot.
+ * The approach also adds years and months together when necessary, which ensures
+ * correct behaviour at the end of the month.
*
* This instance is immutable and unaffected by this method call.
*
@@ -840,18 +883,15 @@ public final class Period
*/
@Override
public Temporal addTo(Temporal temporal) {
- Objects.requireNonNull(temporal, "temporal");
- if ((years | months) != 0) {
- long monthRange = monthRange(temporal);
- if (monthRange >= 0) {
- temporal = temporal.plus(years * monthRange + months, MONTHS);
- } else {
- if (years != 0) {
- temporal = temporal.plus(years, YEARS);
- }
- if (months != 0) {
- temporal = temporal.plus(months, MONTHS);
- }
+ validateChrono(temporal);
+ if (months == 0) {
+ if (years != 0) {
+ temporal = temporal.plus(years, YEARS);
+ }
+ } else {
+ long totalMonths = toTotalMonths();
+ if (totalMonths != 0) {
+ temporal = temporal.plus(totalMonths, MONTHS);
}
}
if (days != 0) {
@@ -865,6 +905,7 @@ public final class Period
*
* This returns a temporal object of the same observable type as the input
* with this period subtracted.
+ * If the temporal has a chronology, it must be the ISO chronology.
*
* In most cases, it is clearer to reverse the calling pattern by using
* {@link Temporal#minus(TemporalAmount)}.
@@ -874,10 +915,17 @@ public final class Period
* dateTime = dateTime.minus(thisPeriod);
*
*
- * The calculation will subtract the years, then months, then days.
- * Only non-zero amounts will be subtracted.
- * If the date-time has a calendar system with a fixed number of months in a
- * year, then the years and months will be combined before being subtracted.
+ * The calculation operates as follows.
+ * First, the chronology of the temporal is checked to ensure it is ISO chronology or null.
+ * Second, if the months are zero, the years are subtracted if non-zero, otherwise
+ * the combination of years and months is subtracted if non-zero.
+ * Finally, any days are subtracted.
+ *
+ * This approach ensures that a partial period can be subtracted from a partial date.
+ * For example, a period of years and/or months can be subtracted from a {@code YearMonth},
+ * but a period including days cannot.
+ * The approach also subtracts years and months together when necessary, which ensures
+ * correct behaviour at the end of the month.
*
* This instance is immutable and unaffected by this method call.
*
@@ -888,18 +936,15 @@ public final class Period
*/
@Override
public Temporal subtractFrom(Temporal temporal) {
- Objects.requireNonNull(temporal, "temporal");
- if ((years | months) != 0) {
- long monthRange = monthRange(temporal);
- if (monthRange >= 0) {
- temporal = temporal.minus(years * monthRange + months, MONTHS);
- } else {
- if (years != 0) {
- temporal = temporal.minus(years, YEARS);
- }
- if (months != 0) {
- temporal = temporal.minus(months, MONTHS);
- }
+ validateChrono(temporal);
+ if (months == 0) {
+ if (years != 0) {
+ temporal = temporal.minus(years, YEARS);
+ }
+ } else {
+ long totalMonths = toTotalMonths();
+ if (totalMonths != 0) {
+ temporal = temporal.minus(totalMonths, MONTHS);
}
}
if (days != 0) {
@@ -909,26 +954,21 @@ public final class Period
}
/**
- * Calculates the range of months based on the temporal.
- *
- * @param temporal the temporal, not null
- * @return the month range, negative if not fixed range
+ * Validates that the temporal has the correct chronology.
*/
- private long monthRange(Temporal temporal) {
- if (temporal.isSupported(MONTH_OF_YEAR)) {
- ValueRange startRange = Chronology.from(temporal).range(MONTH_OF_YEAR);
- if (startRange.isFixed() && startRange.isIntValue()) {
- return startRange.getMaximum() - startRange.getMinimum() + 1;
- }
+ private void validateChrono(TemporalAccessor temporal) {
+ Objects.requireNonNull(temporal, "temporal");
+ Chronology temporalChrono = temporal.query(TemporalQuery.chronology());
+ if (temporalChrono != null && IsoChronology.INSTANCE.equals(temporalChrono) == false) {
+ throw new DateTimeException("Chronology mismatch, expected: ISO, actual: " + temporalChrono.getId());
}
- return -1;
}
//-----------------------------------------------------------------------
/**
* Checks if this period is equal to another period.
*
- * The comparison is based on the amounts held in the period.
+ * The comparison is based on the type {@code Period} and each of the three amounts.
* To be equal, the years, months and days units must be individually equal.
* Note that this means that a period of "15 Months" is not equal to a period
* of "1 Year and 3 Months".
diff --git a/jdk/src/share/classes/java/time/Year.java b/jdk/src/share/classes/java/time/Year.java
index f51bda69664..377dfd5185a 100644
--- a/jdk/src/share/classes/java/time/Year.java
+++ b/jdk/src/share/classes/java/time/Year.java
@@ -242,6 +242,7 @@ public final class Year
if (temporal instanceof Year) {
return (Year) temporal;
}
+ Objects.requireNonNull(temporal, "temporal");
try {
if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) {
temporal = LocalDate.from(temporal);
@@ -859,7 +860,8 @@ public final class Year
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified year.
* The result will be negative if the end is before the start.
- * The {@code Temporal} passed to this method must be a {@code Year}.
+ * The {@code Temporal} passed to this method is converted to a
+ * {@code Year} using {@link #from(TemporalAccessor)}.
* For example, the period in decades between two year can be calculated
* using {@code startYear.until(endYear, DECADES)}.
*
@@ -885,25 +887,22 @@ public final class Year
*
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
- * passing {@code this} as the first argument and the input temporal as
- * the second argument.
+ * passing {@code this} as the first argument and the converted input temporal
+ * as the second argument.
*
* This instance is immutable and unaffected by this method call.
*
- * @param endYear the end year, which must be a {@code Year}, not null
+ * @param endExclusive the end date, exclusive, which is converted to a {@code Year}, not null
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this year and the end year
- * @throws DateTimeException if the amount cannot be calculated
+ * @throws DateTimeException if the amount cannot be calculated, or the end
+ * temporal cannot be converted to a {@code Year}
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
- public long until(Temporal endYear, TemporalUnit unit) {
- if (endYear instanceof Year == false) {
- Objects.requireNonNull(endYear, "endYear");
- throw new DateTimeException("Unable to calculate amount as objects are of two different types");
- }
- Year end = (Year) endYear;
+ public long until(Temporal endExclusive, TemporalUnit unit) {
+ Year end = Year.from(endExclusive);
if (unit instanceof ChronoUnit) {
long yearsUntil = ((long) end.year) - year; // no overflow
switch ((ChronoUnit) unit) {
@@ -915,7 +914,7 @@ public final class Year
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
- return unit.between(this, endYear);
+ return unit.between(this, end);
}
/**
diff --git a/jdk/src/share/classes/java/time/YearMonth.java b/jdk/src/share/classes/java/time/YearMonth.java
index 541676117eb..223c90ab0f0 100644
--- a/jdk/src/share/classes/java/time/YearMonth.java
+++ b/jdk/src/share/classes/java/time/YearMonth.java
@@ -245,6 +245,7 @@ public final class YearMonth
if (temporal instanceof YearMonth) {
return (YearMonth) temporal;
}
+ Objects.requireNonNull(temporal, "temporal");
try {
if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) {
temporal = LocalDate.from(temporal);
@@ -992,7 +993,8 @@ public final class YearMonth
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified year-month.
* The result will be negative if the end is before the start.
- * The {@code Temporal} passed to this method must be a {@code YearMonth}.
+ * The {@code Temporal} passed to this method is converted to a
+ * {@code YearMonth} using {@link #from(TemporalAccessor)}.
* For example, the period in years between two year-months can be calculated
* using {@code startYearMonth.until(endYearMonth, YEARS)}.
*
@@ -1018,25 +1020,22 @@ public final class YearMonth
*
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
- * passing {@code this} as the first argument and the input temporal as
- * the second argument.
+ * passing {@code this} as the first argument and the converted input temporal
+ * as the second argument.
*
* This instance is immutable and unaffected by this method call.
*
- * @param endYearMonth the end year-month, which must be a {@code YearMonth}, not null
+ * @param endExclusive the end date, exclusive, which is converted to a {@code YearMonth}, not null
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this year-month and the end year-month
- * @throws DateTimeException if the amount cannot be calculated
+ * @throws DateTimeException if the amount cannot be calculated, or the end
+ * temporal cannot be converted to a {@code YearMonth}
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
- public long until(Temporal endYearMonth, TemporalUnit unit) {
- if (endYearMonth instanceof YearMonth == false) {
- Objects.requireNonNull(endYearMonth, "endYearMonth");
- throw new DateTimeException("Unable to calculate amount as objects are of two different types");
- }
- YearMonth end = (YearMonth) endYearMonth;
+ public long until(Temporal endExclusive, TemporalUnit unit) {
+ YearMonth end = YearMonth.from(endExclusive);
if (unit instanceof ChronoUnit) {
long monthsUntil = end.getProlepticMonth() - getProlepticMonth(); // no overflow
switch ((ChronoUnit) unit) {
@@ -1049,7 +1048,7 @@ public final class YearMonth
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
- return unit.between(this, endYearMonth);
+ return unit.between(this, end);
}
/**
diff --git a/jdk/src/share/classes/java/time/ZoneOffset.java b/jdk/src/share/classes/java/time/ZoneOffset.java
index 2d63a978d8c..3475e5f4db3 100644
--- a/jdk/src/share/classes/java/time/ZoneOffset.java
+++ b/jdk/src/share/classes/java/time/ZoneOffset.java
@@ -333,6 +333,7 @@ public final class ZoneOffset
* @throws DateTimeException if unable to convert to an {@code ZoneOffset}
*/
public static ZoneOffset from(TemporalAccessor temporal) {
+ Objects.requireNonNull(temporal, "temporal");
ZoneOffset offset = temporal.query(TemporalQuery.offset());
if (offset == null) {
throw new DateTimeException("Unable to obtain ZoneOffset from TemporalAccessor: " + temporal.getClass());
diff --git a/jdk/src/share/classes/java/time/ZonedDateTime.java b/jdk/src/share/classes/java/time/ZonedDateTime.java
index 251ca888a14..1114ab4edd3 100644
--- a/jdk/src/share/classes/java/time/ZonedDateTime.java
+++ b/jdk/src/share/classes/java/time/ZonedDateTime.java
@@ -1540,6 +1540,11 @@ public final class ZonedDateTime
*/
@Override
public ZonedDateTime plus(TemporalAmount amountToAdd) {
+ if (amountToAdd instanceof Period) {
+ Period periodToAdd = (Period) amountToAdd;
+ return resolveLocal(dateTime.plus(periodToAdd));
+ }
+ Objects.requireNonNull(amountToAdd, "amountToAdd");
return (ZonedDateTime) amountToAdd.addTo(this);
}
@@ -1787,6 +1792,11 @@ public final class ZonedDateTime
*/
@Override
public ZonedDateTime minus(TemporalAmount amountToSubtract) {
+ if (amountToSubtract instanceof Period) {
+ Period periodToSubtract = (Period) amountToSubtract;
+ return resolveLocal(dateTime.minus(periodToSubtract));
+ }
+ Objects.requireNonNull(amountToSubtract, "amountToSubtract");
return (ZonedDateTime) amountToSubtract.subtractFrom(this);
}
@@ -2034,7 +2044,8 @@ public final class ZonedDateTime
* For example, the period in days between two date-times can be calculated
* using {@code startDateTime.until(endDateTime, DAYS)}.
*
- * The {@code Temporal} passed to this method must be a {@code ZonedDateTime}.
+ * The {@code Temporal} passed to this method is converted to a
+ * {@code ZonedDateTime} using {@link #from(TemporalAccessor)}.
* If the time-zone differs between the two zoned date-times, the specified
* end date-time is normalized to have the same zone as this date-time.
*
@@ -2076,26 +2087,23 @@ public final class ZonedDateTime
*
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
- * passing {@code this} as the first argument and the input temporal as
- * the second argument.
+ * passing {@code this} as the first argument and the converted input temporal
+ * as the second argument.
*
* This instance is immutable and unaffected by this method call.
*
- * @param endDateTime the end date-time, which must be a {@code ZonedDateTime}, not null
+ * @param endExclusive the end date, exclusive, which is converted to a {@code ZonedDateTime}, not null
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this date-time and the end date-time
- * @throws DateTimeException if the amount cannot be calculated
+ * @throws DateTimeException if the amount cannot be calculated, or the end
+ * temporal cannot be converted to a {@code ZonedDateTime}
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
- public long until(Temporal endDateTime, TemporalUnit unit) {
- if (endDateTime instanceof ZonedDateTime == false) {
- Objects.requireNonNull(endDateTime, "endDateTime");
- throw new DateTimeException("Unable to calculate amount as objects are of two different types");
- }
+ public long until(Temporal endExclusive, TemporalUnit unit) {
+ ZonedDateTime end = ZonedDateTime.from(endExclusive);
if (unit instanceof ChronoUnit) {
- ZonedDateTime end = (ZonedDateTime) endDateTime;
end = end.withZoneSameInstant(zone);
if (unit.isDateBased()) {
return dateTime.until(end.dateTime, unit);
@@ -2103,7 +2111,7 @@ public final class ZonedDateTime
return toOffsetDateTime().until(end.toOffsetDateTime(), unit);
}
}
- return unit.between(this, endDateTime);
+ return unit.between(this, end);
}
/**
diff --git a/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java b/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java
index 923e8960b0f..58e4f5d5250 100644
--- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java
+++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java
@@ -69,7 +69,6 @@ import static java.time.temporal.ChronoUnit.DAYS;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalTime;
-import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
@@ -292,6 +291,7 @@ public interface ChronoLocalDate
if (temporal instanceof ChronoLocalDate) {
return (ChronoLocalDate) temporal;
}
+ Objects.requireNonNull(temporal, "temporal");
Chronology chrono = temporal.query(TemporalQuery.chronology());
if (chrono == null) {
throw new DateTimeException("Unable to obtain ChronoLocalDate from TemporalAccessor: " + temporal.getClass());
@@ -428,7 +428,7 @@ public interface ChronoLocalDate
*/
@Override
default ChronoLocalDate with(TemporalAdjuster adjuster) {
- return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.with(adjuster));
+ return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.with(adjuster));
}
/**
@@ -442,7 +442,7 @@ public interface ChronoLocalDate
if (field instanceof ChronoField) {
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
- return ChronoDateImpl.ensureValid(getChronology(), field.adjustInto(this, newValue));
+ return ChronoLocalDateImpl.ensureValid(getChronology(), field.adjustInto(this, newValue));
}
/**
@@ -452,7 +452,7 @@ public interface ChronoLocalDate
*/
@Override
default ChronoLocalDate plus(TemporalAmount amount) {
- return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.plus(amount));
+ return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.plus(amount));
}
/**
@@ -465,7 +465,7 @@ public interface ChronoLocalDate
if (unit instanceof ChronoUnit) {
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
- return ChronoDateImpl.ensureValid(getChronology(), unit.addTo(this, amountToAdd));
+ return ChronoLocalDateImpl.ensureValid(getChronology(), unit.addTo(this, amountToAdd));
}
/**
@@ -475,7 +475,7 @@ public interface ChronoLocalDate
*/
@Override
default ChronoLocalDate minus(TemporalAmount amount) {
- return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.minus(amount));
+ return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.minus(amount));
}
/**
@@ -486,7 +486,7 @@ public interface ChronoLocalDate
*/
@Override
default ChronoLocalDate minus(long amountToSubtract, TemporalUnit unit) {
- return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit));
+ return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit));
}
//-----------------------------------------------------------------------
@@ -561,8 +561,8 @@ public interface ChronoLocalDate
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified date.
* The result will be negative if the end is before the start.
- * The {@code Temporal} passed to this method must be a
- * {@code ChronoLocalDate} in the same chronology.
+ * The {@code Temporal} passed to this method is converted to a
+ * {@code ChronoLocalDate} using {@link Chronology#date(TemporalAccessor)}.
* The calculation returns a whole number, representing the number of
* complete units between the two dates.
* For example, the amount in days between two dates can be calculated
@@ -586,25 +586,30 @@ public interface ChronoLocalDate
*
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
- * passing {@code this} as the first argument and the input temporal as
+ * passing {@code this} as the first argument and the converted input temporal as
* the second argument.
*
* This instance is immutable and unaffected by this method call.
*
- * @param endDate the end date, which must be a {@code ChronoLocalDate}
- * in the same chronology, not null
+ * @param endExclusive the end date, exclusive, which is converted to a
+ * {@code ChronoLocalDate} in the same chronology, not null
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this date and the end date
- * @throws DateTimeException if the amount cannot be calculated
+ * @throws DateTimeException if the amount cannot be calculated, or the end
+ * temporal cannot be converted to a {@code ChronoLocalDate}
+ * @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override // override for Javadoc
- long until(Temporal endDate, TemporalUnit unit);
+ long until(Temporal endExclusive, TemporalUnit unit);
/**
- * Calculates the period between this date and another date as a {@code Period}.
+ * Calculates the period between this date and another date as a {@code ChronoPeriod}.
+ *
+ * This calculates the period between two dates. All supplied chronologies
+ * calculate the period using years, months and days, however the
+ * {@code ChronoPeriod} API allows the period to be represented using other units.
*
- * This calculates the period between two dates in terms of years, months and days.
* The start and end points are {@code this} and the specified date.
* The result will be negative if the end is before the start.
* The negative sign will be the same in each of year, month and day.
@@ -614,12 +619,12 @@ public interface ChronoLocalDate
*
* This instance is immutable and unaffected by this method call.
*
- * @param endDate the end date, exclusive, which may be in any chronology, not null
+ * @param endDateExclusive the end date, exclusive, which may be in any chronology, not null
* @return the period between this date and the end date, not null
* @throws DateTimeException if the period cannot be calculated
* @throws ArithmeticException if numeric overflow occurs
*/
- Period until(ChronoLocalDate endDate);
+ ChronoPeriod until(ChronoLocalDate endDateExclusive);
/**
* Formats this date using the specified formatter.
diff --git a/jdk/src/share/classes/java/time/chrono/ChronoDateImpl.java b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateImpl.java
similarity index 92%
rename from jdk/src/share/classes/java/time/chrono/ChronoDateImpl.java
rename to jdk/src/share/classes/java/time/chrono/ChronoLocalDateImpl.java
index 99ba58f05b9..6cb115d393e 100644
--- a/jdk/src/share/classes/java/time/chrono/ChronoDateImpl.java
+++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateImpl.java
@@ -140,7 +140,7 @@ import java.util.Objects;
* @param the ChronoLocalDate of this date-time
* @since 1.8
*/
-abstract class ChronoDateImpl
+abstract class ChronoLocalDateImpl
implements ChronoLocalDate, Temporal, TemporalAdjuster, Serializable {
/**
@@ -170,7 +170,7 @@ abstract class ChronoDateImpl
/**
* Creates an instance.
*/
- ChronoDateImpl() {
+ ChronoLocalDateImpl() {
}
@Override
@@ -309,7 +309,7 @@ abstract class ChronoDateImpl
*/
@SuppressWarnings("unchecked")
D minusYears(long yearsToSubtract) {
- return (yearsToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusYears(Long.MAX_VALUE)).plusYears(1) : plusYears(-yearsToSubtract));
+ return (yearsToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl)plusYears(Long.MAX_VALUE)).plusYears(1) : plusYears(-yearsToSubtract));
}
/**
@@ -330,7 +330,7 @@ abstract class ChronoDateImpl
*/
@SuppressWarnings("unchecked")
D minusMonths(long monthsToSubtract) {
- return (monthsToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusMonths(Long.MAX_VALUE)).plusMonths(1) : plusMonths(-monthsToSubtract));
+ return (monthsToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl)plusMonths(Long.MAX_VALUE)).plusMonths(1) : plusMonths(-monthsToSubtract));
}
/**
@@ -350,7 +350,7 @@ abstract class ChronoDateImpl
*/
@SuppressWarnings("unchecked")
D minusWeeks(long weeksToSubtract) {
- return (weeksToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusWeeks(Long.MAX_VALUE)).plusWeeks(1) : plusWeeks(-weeksToSubtract));
+ return (weeksToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl)plusWeeks(Long.MAX_VALUE)).plusWeeks(1) : plusWeeks(-weeksToSubtract));
}
/**
@@ -368,26 +368,14 @@ abstract class ChronoDateImpl
*/
@SuppressWarnings("unchecked")
D minusDays(long daysToSubtract) {
- return (daysToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusDays(Long.MAX_VALUE)).plusDays(1) : plusDays(-daysToSubtract));
+ return (daysToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl)plusDays(Long.MAX_VALUE)).plusDays(1) : plusDays(-daysToSubtract));
}
//-----------------------------------------------------------------------
- /**
- * {@inheritDoc}
- * @throws DateTimeException {@inheritDoc}
- * @throws ArithmeticException {@inheritDoc}
- */
@Override
- public long until(Temporal endDateTime, TemporalUnit unit) {
- Objects.requireNonNull(endDateTime, "endDateTime");
- Objects.requireNonNull(unit, "unit");
- if (endDateTime instanceof ChronoLocalDate == false) {
- throw new DateTimeException("Unable to calculate amount as objects are of two different types");
- }
- ChronoLocalDate end = (ChronoLocalDate) endDateTime;
- if (getChronology().equals(end.getChronology()) == false) {
- throw new DateTimeException("Unable to calculate amount as objects have different chronologies");
- }
+ public long until(Temporal endExclusive, TemporalUnit unit) {
+ Objects.requireNonNull(endExclusive, "endExclusive");
+ ChronoLocalDate end = getChronology().date(endExclusive);
if (unit instanceof ChronoUnit) {
switch ((ChronoUnit) unit) {
case DAYS: return daysUntil(end);
@@ -401,7 +389,8 @@ abstract class ChronoDateImpl
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
- return unit.between(this, endDateTime);
+ Objects.requireNonNull(unit, "unit");
+ return unit.between(this, end);
}
private long daysUntil(ChronoLocalDate end) {
@@ -411,7 +400,7 @@ abstract class ChronoDateImpl
private long monthsUntil(ChronoLocalDate end) {
ValueRange range = getChronology().range(MONTH_OF_YEAR);
if (range.getMaximum() != 12) {
- throw new IllegalStateException("ChronoDateImpl only supports Chronologies with 12 months per year");
+ throw new IllegalStateException("ChronoLocalDateImpl only supports Chronologies with 12 months per year");
}
long packed1 = getLong(PROLEPTIC_MONTH) * 32L + get(DAY_OF_MONTH); // no overflow
long packed2 = end.getLong(PROLEPTIC_MONTH) * 32L + end.get(DAY_OF_MONTH); // no overflow
diff --git a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java
index be93f0e036a..4c2ddfd31a7 100644
--- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java
+++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java
@@ -165,6 +165,7 @@ public interface ChronoLocalDateTime
if (temporal instanceof ChronoLocalDateTime) {
return (ChronoLocalDateTime>) temporal;
}
+ Objects.requireNonNull(temporal, "temporal");
Chronology chrono = temporal.query(TemporalQuery.chronology());
if (chrono == null) {
throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " + temporal.getClass());
@@ -173,6 +174,18 @@ public interface ChronoLocalDateTime
}
//-----------------------------------------------------------------------
+ /**
+ * Gets the chronology of this date-time.
+ *
+ * The {@code Chronology} represents the calendar system in use.
+ * The era and other fields in {@link ChronoField} are defined by the chronology.
+ *
+ * @return the chronology, not null
+ */
+ default Chronology getChronology() {
+ return toLocalDate().getChronology();
+ }
+
/**
* Gets the local date part of this date-time.
*
@@ -250,7 +263,7 @@ public interface ChronoLocalDateTime
*/
@Override
default ChronoLocalDateTime with(TemporalAdjuster adjuster) {
- return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.with(adjuster));
+ return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.with(adjuster));
}
/**
@@ -268,7 +281,7 @@ public interface ChronoLocalDateTime
*/
@Override
default ChronoLocalDateTime plus(TemporalAmount amount) {
- return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.plus(amount));
+ return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.plus(amount));
}
/**
@@ -286,7 +299,7 @@ public interface ChronoLocalDateTime
*/
@Override
default ChronoLocalDateTime minus(TemporalAmount amount) {
- return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amount));
+ return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amount));
}
/**
@@ -296,7 +309,7 @@ public interface ChronoLocalDateTime
*/
@Override
default ChronoLocalDateTime minus(long amountToSubtract, TemporalUnit unit) {
- return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amountToSubtract, unit));
+ return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit));
}
//-----------------------------------------------------------------------
@@ -326,7 +339,7 @@ public interface ChronoLocalDateTime
} else if (query == TemporalQuery.localTime()) {
return (R) toLocalTime();
} else if (query == TemporalQuery.chronology()) {
- return (R) toLocalDate().getChronology();
+ return (R) getChronology();
} else if (query == TemporalQuery.precision()) {
return (R) NANOS;
}
@@ -488,7 +501,7 @@ public interface ChronoLocalDateTime
if (cmp == 0) {
cmp = toLocalTime().compareTo(other.toLocalTime());
if (cmp == 0) {
- cmp = toLocalDate().getChronology().compareTo(other.toLocalDate().getChronology());
+ cmp = getChronology().compareTo(other.getChronology());
}
}
return cmp;
diff --git a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java
index cd7f04e4798..e33e82ebab2 100644
--- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java
+++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java
@@ -69,7 +69,6 @@ import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.ObjectStreamException;
import java.io.Serializable;
-import java.time.DateTimeException;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.ChronoField;
@@ -187,9 +186,9 @@ final class ChronoLocalDateTimeImpl
static ChronoLocalDateTimeImpl ensureValid(Chronology chrono, Temporal temporal) {
@SuppressWarnings("unchecked")
ChronoLocalDateTimeImpl other = (ChronoLocalDateTimeImpl) temporal;
- if (chrono.equals(other.toLocalDate().getChronology()) == false) {
+ if (chrono.equals(other.getChronology()) == false) {
throw new ClassCastException("Chronology mismatch, required: " + chrono.getId()
- + ", actual: " + other.toLocalDate().getChronology().getId());
+ + ", actual: " + other.getChronology().getId());
}
return other;
}
@@ -220,7 +219,7 @@ final class ChronoLocalDateTimeImpl
return this;
}
// Validate that the new Temporal is a ChronoLocalDate (and not something else)
- D cd = ChronoDateImpl.ensureValid(date.getChronology(), newDate);
+ D cd = ChronoLocalDateImpl.ensureValid(date.getChronology(), newDate);
return new ChronoLocalDateTimeImpl<>(cd, newTime);
}
@@ -369,15 +368,10 @@ final class ChronoLocalDateTimeImpl
//-----------------------------------------------------------------------
@Override
- public long until(Temporal endDateTime, TemporalUnit unit) {
- if (endDateTime instanceof ChronoLocalDateTime == false) {
- throw new DateTimeException("Unable to calculate amount as objects are of two different types");
- }
+ public long until(Temporal endExclusive, TemporalUnit unit) {
+ Objects.requireNonNull(endExclusive, "endExclusive");
@SuppressWarnings("unchecked")
- ChronoLocalDateTime end = (ChronoLocalDateTime) endDateTime;
- if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) {
- throw new DateTimeException("Unable to calculate amount as objects have different chronologies");
- }
+ ChronoLocalDateTime end = (ChronoLocalDateTime) getChronology().localDateTime(endExclusive);
if (unit instanceof ChronoUnit) {
if (unit.isTimeBased()) {
long amount = end.getLong(EPOCH_DAY) - date.getLong(EPOCH_DAY);
@@ -398,7 +392,8 @@ final class ChronoLocalDateTimeImpl
}
return date.until(endDate, unit);
}
- return unit.between(this, endDateTime);
+ Objects.requireNonNull(unit, "unit");
+ return unit.between(this, end);
}
//-----------------------------------------------------------------------
diff --git a/jdk/src/share/classes/java/time/chrono/ChronoPeriod.java b/jdk/src/share/classes/java/time/chrono/ChronoPeriod.java
new file mode 100644
index 00000000000..0ac1d395143
--- /dev/null
+++ b/jdk/src/share/classes/java/time/chrono/ChronoPeriod.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import java.time.DateTimeException;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A date-based amount of time, such as '3 years, 4 months and 5 days' in an
+ * arbitrary chronology, intended for advanced globalization use cases.
+ *
+ * This interface models a date-based amount of time in a calendar system.
+ * While most calendar systems use years, months and days, some do not.
+ * Therefore, this interface operates solely in terms of a set of supported
+ * units that are defined by the {@code Chronology}.
+ * The set of supported units is fixed for a given chronology.
+ * The amount of a supported unit may be set to zero.
+ *
+ * The period is modeled as a directed amount of time, meaning that individual
+ * parts of the period may be negative.
+ *
+ * @implSpec
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Subclasses should be Serializable wherever possible.
+ *
+ * @since 1.8
+ */
+public interface ChronoPeriod
+ extends TemporalAmount {
+
+ /**
+ * Obtains a {@code ChronoPeriod} consisting of amount of time between two dates.
+ *
+ * The start date is included, but the end date is not.
+ * The period is calculated using {@link ChronoLocalDate#until(ChronoLocalDate)}.
+ * As such, the calculation is chronology specific.
+ *
+ * The chronology of the first date is used.
+ * The chronology of the second date is ignored, with the date being converted
+ * to the target chronology system before the calculation starts.
+ *
+ * The result of this method can be a negative period if the end is before the start.
+ * In most cases, the positive/negative sign will be the same in each of the supported fields.
+ *
+ * @param startDateInclusive the start date, inclusive, specifying the chronology of the calculation, not null
+ * @param endDateExclusive the end date, exclusive, in any chronology, not null
+ * @return the period between this date and the end date, not null
+ * @see ChronoLocalDate#until(ChronoLocalDate)
+ */
+ public static ChronoPeriod between(ChronoLocalDate startDateInclusive, ChronoLocalDate endDateExclusive) {
+ Objects.requireNonNull(startDateInclusive, "startDateInclusive");
+ Objects.requireNonNull(endDateExclusive, "endDateExclusive");
+ return startDateInclusive.until(endDateExclusive);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the value of the requested unit.
+ *
+ * The supported units are chronology specific.
+ * They will typically be {@link ChronoUnit#YEARS YEARS},
+ * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
+ * Requesting an unsupported unit will throw an exception.
+ *
+ * @param unit the {@code TemporalUnit} for which to return the value
+ * @return the long value of the unit
+ * @throws DateTimeException if the unit is not supported
+ * @throws UnsupportedTemporalTypeException if the unit is not supported
+ */
+ @Override
+ long get(TemporalUnit unit);
+
+ /**
+ * Gets the set of units supported by this period.
+ *
+ * The supported units are chronology specific.
+ * They will typically be {@link ChronoUnit#YEARS YEARS},
+ * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
+ * They are returned in order from largest to smallest.
+ *
+ * This set can be used in conjunction with {@link #get(TemporalUnit)}
+ * to access the entire state of the period.
+ *
+ * @return a list containing the supported units, not null
+ */
+ @Override
+ List getUnits();
+
+ /**
+ * Gets the chronology that defines the meaning of the supported units.
+ *
+ * The period is defined by the chronology.
+ * It controls the supported units and restricts addition/subtraction
+ * to {@code ChronoLocalDate} instances of the same chronology.
+ *
+ * @return the chronology defining the period, not null
+ */
+ Chronology getChronology();
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if all the supported units of this period are zero.
+ *
+ * @return true if this period is zero-length
+ */
+ default boolean isZero() {
+ for (TemporalUnit unit : getUnits()) {
+ if (get(unit) != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks if any of the supported units of this period are negative.
+ *
+ * @return true if any unit of this period is negative
+ */
+ default boolean isNegative() {
+ for (TemporalUnit unit : getUnits()) {
+ if (get(unit) < 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this period with the specified period added.
+ *
+ * If the specified amount is a {@code ChronoPeriod} then it must have
+ * the same chronology as this period. Implementations may choose to
+ * accept or reject other {@code TemporalAmount} implementations.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amountToAdd the period to add, not null
+ * @return a {@code ChronoPeriod} based on this period with the requested period added, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ ChronoPeriod plus(TemporalAmount amountToAdd);
+
+ /**
+ * Returns a copy of this period with the specified period subtracted.
+ *
+ * If the specified amount is a {@code ChronoPeriod} then it must have
+ * the same chronology as this period. Implementations may choose to
+ * accept or reject other {@code TemporalAmount} implementations.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amountToSubtract the period to subtract, not null
+ * @return a {@code ChronoPeriod} based on this period with the requested period subtracted, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ ChronoPeriod minus(TemporalAmount amountToSubtract);
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a new instance with each amount in this period in this period
+ * multiplied by the specified scalar.
+ *
+ * This returns a period with each supported unit individually multiplied.
+ * For example, a period of "2 years, -3 months and 4 days" multiplied by
+ * 3 will return "6 years, -9 months and 12 days".
+ * No normalization is performed.
+ *
+ * @param scalar the scalar to multiply by, not null
+ * @return a {@code ChronoPeriod} based on this period with the amounts multiplied
+ * by the scalar, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ ChronoPeriod multipliedBy(int scalar);
+
+ /**
+ * Returns a new instance with each amount in this period negated.
+ *
+ * This returns a period with each supported unit individually negated.
+ * For example, a period of "2 years, -3 months and 4 days" will be
+ * negated to "-2 years, 3 months and -4 days".
+ * No normalization is performed.
+ *
+ * @return a {@code ChronoPeriod} based on this period with the amounts negated, not null
+ * @throws ArithmeticException if numeric overflow occurs, which only happens if
+ * one of the units has the value {@code Long.MIN_VALUE}
+ */
+ default ChronoPeriod negated() {
+ return multipliedBy(-1);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this period with the amounts of each unit normalized.
+ *
+ * The process of normalization is specific to each calendar system.
+ * For example, in the ISO calendar system, the years and months are
+ * normalized but the days are not, such that "15 months" would be
+ * normalized to "1 year and 3 months".
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @return a {@code ChronoPeriod} based on this period with the amounts of each
+ * unit normalized, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ ChronoPeriod normalized();
+
+ //-------------------------------------------------------------------------
+ /**
+ * Adds this period to the specified temporal object.
+ *
+ * This returns a temporal object of the same observable type as the input
+ * with this period added.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#plus(TemporalAmount)}.
+ *
+ * // these two lines are equivalent, but the second approach is recommended
+ * dateTime = thisPeriod.addTo(dateTime);
+ * dateTime = dateTime.plus(thisPeriod);
+ *
+ *
+ * The specified temporal must have the same chronology as this period.
+ * This returns a temporal with the non-zero supported units added.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param temporal the temporal object to adjust, not null
+ * @return an object of the same type with the adjustment made, not null
+ * @throws DateTimeException if unable to add
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ Temporal addTo(Temporal temporal);
+
+ /**
+ * Subtracts this period from the specified temporal object.
+ *
+ * This returns a temporal object of the same observable type as the input
+ * with this period subtracted.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#minus(TemporalAmount)}.
+ *
+ * // these two lines are equivalent, but the second approach is recommended
+ * dateTime = thisPeriod.subtractFrom(dateTime);
+ * dateTime = dateTime.minus(thisPeriod);
+ *
+ *
+ * The specified temporal must have the same chronology as this period.
+ * This returns a temporal with the non-zero supported units subtracted.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param temporal the temporal object to adjust, not null
+ * @return an object of the same type with the adjustment made, not null
+ * @throws DateTimeException if unable to subtract
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ Temporal subtractFrom(Temporal temporal);
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if this period is equal to another period, including the chronology.
+ *
+ * Compares this period with another ensuring that the type, each amount and
+ * the chronology are the same.
+ * Note that this means that a period of "15 Months" is not equal to a period
+ * of "1 Year and 3 Months".
+ *
+ * @param obj the object to check, null returns false
+ * @return true if this is equal to the other period
+ */
+ @Override
+ boolean equals(Object obj);
+
+ /**
+ * A hash code for this period.
+ *
+ * @return a suitable hash code
+ */
+ @Override
+ int hashCode();
+
+ //-----------------------------------------------------------------------
+ /**
+ * Outputs this period as a {@code String}.
+ *
+ * The output will include the period amounts and chronology.
+ *
+ * @return a string representation of this period, not null
+ */
+ @Override
+ String toString();
+
+}
diff --git a/jdk/src/share/classes/java/time/chrono/ChronoPeriodImpl.java b/jdk/src/share/classes/java/time/chrono/ChronoPeriodImpl.java
new file mode 100644
index 00000000000..d301adb2d03
--- /dev/null
+++ b/jdk/src/share/classes/java/time/chrono/ChronoPeriodImpl.java
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A period expressed in terms of a standard year-month-day calendar system.
+ *
+ * This class is used by applications seeking to handle dates in non-ISO calendar systems.
+ * For example, the Japanese, Minguo, Thai Buddhist and others.
+ *
+ * @implSpec
+ * This class is immutable nad thread-safe.
+ *
+ * @since 1.8
+ */
+final class ChronoPeriodImpl
+ implements ChronoPeriod, Serializable {
+ // this class is only used by JDK chronology implementations and makes assumptions based on that fact
+
+ /**
+ * Serialization version.
+ */
+ private static final long serialVersionUID = 57387258289L;
+
+ /**
+ * The set of supported units.
+ */
+ private final static List SUPPORTED_UNITS =
+ Collections.unmodifiableList(Arrays.asList(YEARS, MONTHS, DAYS));
+
+ /**
+ * The chronology.
+ */
+ private final Chronology chrono;
+ /**
+ * The number of years.
+ */
+ final int years;
+ /**
+ * The number of months.
+ */
+ final int months;
+ /**
+ * The number of days.
+ */
+ final int days;
+
+ /**
+ * Creates an instance.
+ */
+ ChronoPeriodImpl(Chronology chrono, int years, int months, int days) {
+ Objects.requireNonNull(chrono, "chrono");
+ this.chrono = chrono;
+ this.years = years;
+ this.months = months;
+ this.days = days;
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public long get(TemporalUnit unit) {
+ if (unit == ChronoUnit.YEARS) {
+ return years;
+ } else if (unit == ChronoUnit.MONTHS) {
+ return months;
+ } else if (unit == ChronoUnit.DAYS) {
+ return days;
+ } else {
+ throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+ }
+ }
+
+ @Override
+ public List getUnits() {
+ return ChronoPeriodImpl.SUPPORTED_UNITS;
+ }
+
+ @Override
+ public Chronology getChronology() {
+ return chrono;
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public boolean isZero() {
+ return years == 0 && months == 0 && days == 0;
+ }
+
+ @Override
+ public boolean isNegative() {
+ return years < 0 || months < 0 || days < 0;
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public ChronoPeriod plus(TemporalAmount amountToAdd) {
+ ChronoPeriodImpl amount = validateAmount(amountToAdd);
+ return new ChronoPeriodImpl(
+ chrono,
+ Math.addExact(years, amount.years),
+ Math.addExact(months, amount.months),
+ Math.addExact(days, amount.days));
+ }
+
+ @Override
+ public ChronoPeriod minus(TemporalAmount amountToSubtract) {
+ ChronoPeriodImpl amount = validateAmount(amountToSubtract);
+ return new ChronoPeriodImpl(
+ chrono,
+ Math.subtractExact(years, amount.years),
+ Math.subtractExact(months, amount.months),
+ Math.subtractExact(days, amount.days));
+ }
+
+ /**
+ * Obtains an instance of {@code ChronoPeriodImpl} from a temporal amount.
+ *
+ * @param amount the temporal amount to convert, not null
+ * @return the period, not null
+ */
+ private ChronoPeriodImpl validateAmount(TemporalAmount amount) {
+ Objects.requireNonNull(amount, "amount");
+ if (amount instanceof ChronoPeriodImpl == false) {
+ throw new DateTimeException("Unable to obtain ChronoPeriod from TemporalAmount: " + amount.getClass());
+ }
+ ChronoPeriodImpl period = (ChronoPeriodImpl) amount;
+ if (chrono.equals(period.getChronology()) == false) {
+ throw new ClassCastException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + period.getChronology().getId());
+ }
+ return period;
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public ChronoPeriod multipliedBy(int scalar) {
+ if (this.isZero() || scalar == 1) {
+ return this;
+ }
+ return new ChronoPeriodImpl(
+ chrono,
+ Math.multiplyExact(years, scalar),
+ Math.multiplyExact(months, scalar),
+ Math.multiplyExact(days, scalar));
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public ChronoPeriod normalized() {
+ long monthRange = monthRange();
+ if (monthRange > 0) {
+ long totalMonths = years * monthRange + months;
+ long splitYears = totalMonths / monthRange;
+ int splitMonths = (int) (totalMonths % monthRange); // no overflow
+ if (splitYears == years && splitMonths == months) {
+ return this;
+ }
+ return new ChronoPeriodImpl(chrono, Math.toIntExact(splitYears), splitMonths, days);
+
+ }
+ return this;
+ }
+
+ /**
+ * Calculates the range of months.
+ *
+ * @return the month range, -1 if not fixed range
+ */
+ private long monthRange() {
+ ValueRange startRange = chrono.range(MONTH_OF_YEAR);
+ if (startRange.isFixed() && startRange.isIntValue()) {
+ return startRange.getMaximum() - startRange.getMinimum() + 1;
+ }
+ return -1;
+ }
+
+ //-------------------------------------------------------------------------
+ @Override
+ public Temporal addTo(Temporal temporal) {
+ validateChrono(temporal);
+ if (months == 0) {
+ if (years != 0) {
+ temporal = temporal.plus(years, YEARS);
+ }
+ } else {
+ long monthRange = monthRange();
+ if (monthRange > 0) {
+ temporal = temporal.plus(years * monthRange + months, MONTHS);
+ } else {
+ if (years != 0) {
+ temporal = temporal.plus(years, YEARS);
+ }
+ temporal = temporal.plus(months, MONTHS);
+ }
+ }
+ if (days != 0) {
+ temporal = temporal.plus(days, DAYS);
+ }
+ return temporal;
+ }
+
+
+
+ @Override
+ public Temporal subtractFrom(Temporal temporal) {
+ validateChrono(temporal);
+ if (months == 0) {
+ if (years != 0) {
+ temporal = temporal.minus(years, YEARS);
+ }
+ } else {
+ long monthRange = monthRange();
+ if (monthRange > 0) {
+ temporal = temporal.minus(years * monthRange + months, MONTHS);
+ } else {
+ if (years != 0) {
+ temporal = temporal.minus(years, YEARS);
+ }
+ temporal = temporal.minus(months, MONTHS);
+ }
+ }
+ if (days != 0) {
+ temporal = temporal.minus(days, DAYS);
+ }
+ return temporal;
+ }
+
+ /**
+ * Validates that the temporal has the correct chronology.
+ */
+ private void validateChrono(TemporalAccessor temporal) {
+ Objects.requireNonNull(temporal, "temporal");
+ Chronology temporalChrono = temporal.query(TemporalQuery.chronology());
+ if (temporalChrono != null && chrono.equals(temporalChrono) == false) {
+ throw new DateTimeException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + temporalChrono.getId());
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof ChronoPeriodImpl) {
+ ChronoPeriodImpl other = (ChronoPeriodImpl) obj;
+ return years == other.years && months == other.months &&
+ days == other.days && chrono.equals(other.chrono);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return (years + Integer.rotateLeft(months, 8) + Integer.rotateLeft(days, 16)) ^ chrono.hashCode();
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public String toString() {
+ if (isZero()) {
+ return getChronology().toString() + " P0D";
+ } else {
+ StringBuilder buf = new StringBuilder();
+ buf.append(getChronology().toString()).append(' ').append('P');
+ if (years != 0) {
+ buf.append(years).append('Y');
+ }
+ if (months != 0) {
+ buf.append(months).append('M');
+ }
+ if (days != 0) {
+ buf.append(days).append('D');
+ }
+ return buf.toString();
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Writes the Chronology using a
+ * dedicated serialized form.
+ *
+ * out.writeByte(12); // identifies this as a ChronoPeriodImpl
+ * out.writeUTF(getId()); // the chronology
+ * out.writeInt(years);
+ * out.writeInt(months);
+ * out.writeInt(days);
+ *
+ *
+ * @return the instance of {@code Ser}, not null
+ */
+ protected Object writeReplace() {
+ return new Ser(Ser.CHRONO_PERIOD_TYPE, this);
+ }
+
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws ObjectStreamException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ void writeExternal(DataOutput out) throws IOException {
+ out.writeUTF(chrono.getId());
+ out.writeInt(years);
+ out.writeInt(months);
+ out.writeInt(days);
+ }
+
+ static ChronoPeriodImpl readExternal(DataInput in) throws IOException {
+ Chronology chrono = Chronology.of(in.readUTF());
+ int years = in.readInt();
+ int months = in.readInt();
+ int days = in.readInt();
+ return new ChronoPeriodImpl(chrono, years, months, days);
+ }
+
+}
diff --git a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java
index dd911fcd789..033ab997fdd 100644
--- a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java
+++ b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java
@@ -166,6 +166,7 @@ public interface ChronoZonedDateTime
if (temporal instanceof ChronoZonedDateTime) {
return (ChronoZonedDateTime>) temporal;
}
+ Objects.requireNonNull(temporal, "temporal");
Chronology chrono = temporal.query(TemporalQuery.chronology());
if (chrono == null) {
throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " + temporal.getClass());
@@ -245,6 +246,18 @@ public interface ChronoZonedDateTime
*/
ChronoLocalDateTime toLocalDateTime();
+ /**
+ * Gets the chronology of this date-time.
+ *
+ * The {@code Chronology} represents the calendar system in use.
+ * The era and other fields in {@link ChronoField} are defined by the chronology.
+ *
+ * @return the chronology, not null
+ */
+ default Chronology getChronology() {
+ return toLocalDate().getChronology();
+ }
+
/**
* Gets the zone offset, such as '+01:00'.
*
@@ -397,7 +410,7 @@ public interface ChronoZonedDateTime
*/
@Override
default ChronoZonedDateTime with(TemporalAdjuster adjuster) {
- return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.with(adjuster));
+ return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.with(adjuster));
}
/**
@@ -415,7 +428,7 @@ public interface ChronoZonedDateTime
*/
@Override
default ChronoZonedDateTime plus(TemporalAmount amount) {
- return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.plus(amount));
+ return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.plus(amount));
}
/**
@@ -433,7 +446,7 @@ public interface ChronoZonedDateTime
*/
@Override
default ChronoZonedDateTime minus(TemporalAmount amount) {
- return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amount));
+ return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amount));
}
/**
@@ -443,7 +456,7 @@ public interface ChronoZonedDateTime
*/
@Override
default ChronoZonedDateTime minus(long amountToSubtract, TemporalUnit unit) {
- return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amountToSubtract, unit));
+ return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit));
}
//-----------------------------------------------------------------------
@@ -475,7 +488,7 @@ public interface ChronoZonedDateTime
} else if (query == TemporalQuery.localTime()) {
return (R) toLocalTime();
} else if (query == TemporalQuery.chronology()) {
- return (R) toLocalDate().getChronology();
+ return (R) getChronology();
} else if (query == TemporalQuery.precision()) {
return (R) NANOS;
}
@@ -562,7 +575,7 @@ public interface ChronoZonedDateTime
if (cmp == 0) {
cmp = getZone().getId().compareTo(other.getZone().getId());
if (cmp == 0) {
- cmp = toLocalDate().getChronology().compareTo(other.toLocalDate().getChronology());
+ cmp = getChronology().compareTo(other.getChronology());
}
}
}
diff --git a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java
index 1cc7b5b5786..5222db367f2 100644
--- a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java
+++ b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java
@@ -69,7 +69,6 @@ import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.ObjectStreamException;
import java.io.Serializable;
-import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
@@ -186,7 +185,7 @@ final class ChronoZonedDateTimeImpl
*/
@SuppressWarnings("unchecked")
private ChronoZonedDateTimeImpl create(Instant instant, ZoneId zone) {
- return (ChronoZonedDateTimeImpl)ofInstant(toLocalDate().getChronology(), instant, zone);
+ return (ChronoZonedDateTimeImpl)ofInstant(getChronology(), instant, zone);
}
/**
@@ -201,9 +200,9 @@ final class ChronoZonedDateTimeImpl
static ChronoZonedDateTimeImpl ensureValid(Chronology chrono, Temporal temporal) {
@SuppressWarnings("unchecked")
ChronoZonedDateTimeImpl other = (ChronoZonedDateTimeImpl) temporal;
- if (chrono.equals(other.toLocalDate().getChronology()) == false) {
+ if (chrono.equals(other.getChronology()) == false) {
throw new ClassCastException("Chronology mismatch, required: " + chrono.getId()
- + ", actual: " + other.toLocalDate().getChronology().getId());
+ + ", actual: " + other.getChronology().getId());
}
return other;
}
@@ -234,7 +233,7 @@ final class ChronoZonedDateTimeImpl
if (trans != null && trans.isOverlap()) {
ZoneOffset earlierOffset = trans.getOffsetBefore();
if (earlierOffset.equals(offset) == false) {
- return new ChronoZonedDateTimeImpl(dateTime, earlierOffset, zone);
+ return new ChronoZonedDateTimeImpl<>(dateTime, earlierOffset, zone);
}
}
return this;
@@ -246,7 +245,7 @@ final class ChronoZonedDateTimeImpl
if (trans != null) {
ZoneOffset offset = trans.getOffsetAfter();
if (offset.equals(getOffset()) == false) {
- return new ChronoZonedDateTimeImpl(dateTime, offset, zone);
+ return new ChronoZonedDateTimeImpl<>(dateTime, offset, zone);
}
}
return this;
@@ -294,7 +293,7 @@ final class ChronoZonedDateTimeImpl
}
return ofBest(dateTime.with(field, newValue), zone, offset);
}
- return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), field.adjustInto(this, newValue));
+ return ChronoZonedDateTimeImpl.ensureValid(getChronology(), field.adjustInto(this, newValue));
}
//-----------------------------------------------------------------------
@@ -303,25 +302,21 @@ final class ChronoZonedDateTimeImpl
if (unit instanceof ChronoUnit) {
return with(dateTime.plus(amountToAdd, unit));
}
- return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), unit.addTo(this, amountToAdd)); /// TODO: Generics replacement Risk!
+ return ChronoZonedDateTimeImpl.ensureValid(getChronology(), unit.addTo(this, amountToAdd)); /// TODO: Generics replacement Risk!
}
//-----------------------------------------------------------------------
@Override
- public long until(Temporal endDateTime, TemporalUnit unit) {
- if (endDateTime instanceof ChronoZonedDateTime == false) {
- throw new DateTimeException("Unable to calculate amount as objects are of two different types");
- }
+ public long until(Temporal endExclusive, TemporalUnit unit) {
+ Objects.requireNonNull(endExclusive, "endExclusive");
@SuppressWarnings("unchecked")
- ChronoZonedDateTime end = (ChronoZonedDateTime) endDateTime;
- if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) {
- throw new DateTimeException("Unable to calculate amount as objects have different chronologies");
- }
+ ChronoZonedDateTime end = (ChronoZonedDateTime) getChronology().zonedDateTime(endExclusive);
if (unit instanceof ChronoUnit) {
end = end.withZoneSameInstant(offset);
return dateTime.until(end.toLocalDateTime(), unit);
}
- return unit.between(this, endDateTime);
+ Objects.requireNonNull(unit, "unit");
+ return unit.between(this, end);
}
//-----------------------------------------------------------------------
diff --git a/jdk/src/share/classes/java/time/chrono/Chronology.java b/jdk/src/share/classes/java/time/chrono/Chronology.java
index 36c9d31c3fd..ed40f4138f0 100644
--- a/jdk/src/share/classes/java/time/chrono/Chronology.java
+++ b/jdk/src/share/classes/java/time/chrono/Chronology.java
@@ -91,14 +91,11 @@ import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
-import java.time.Month;
-import java.time.Year;
import java.time.ZoneId;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.ResolverStyle;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
-import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalField;
@@ -1190,6 +1187,38 @@ public abstract class Chronology implements Comparable {
fieldValues.put(field, value);
}
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains a period for this chronology based on years, months and days.
+ *
+ * This returns a period tied to this chronology using the specified
+ * years, months and days. All supplied chronologies use periods
+ * based on years, months and days, however the {@code ChronoPeriod} API
+ * allows the period to be represented using other units.
+ *
+ * @implSpec
+ * The default implementation returns an implementation class suitable
+ * for most calendar systems. It is based solely on the three units.
+ * Normalization, addition and subtraction derive the number of months
+ * in a year from the {@link #range(ChronoField)}. If the number of
+ * months within a year is fixed, then the calculation approach for
+ * addition, subtraction and normalization is slightly different.
+ *
+ * If implementing an unusual calendar system that is not based on
+ * years, months and days, or where you want direct control, then
+ * the {@code ChronoPeriod} interface must be directly implemented.
+ *
+ * The returned period is immutable and thread-safe.
+ *
+ * @param years the number of years, may be negative
+ * @param months the number of years, may be negative
+ * @param days the number of years, may be negative
+ * @return the period in terms of this chronology, not null
+ */
+ public ChronoPeriod period(int years, int months, int days) {
+ return new ChronoPeriodImpl(this, years, months, days);
+ }
+
//-----------------------------------------------------------------------
/**
* Compares this chronology to another chronology.
diff --git a/jdk/src/share/classes/java/time/chrono/HijrahDate.java b/jdk/src/share/classes/java/time/chrono/HijrahDate.java
index 8e385c9470b..d2c9929316c 100644
--- a/jdk/src/share/classes/java/time/chrono/HijrahDate.java
+++ b/jdk/src/share/classes/java/time/chrono/HijrahDate.java
@@ -73,7 +73,6 @@ import java.time.Clock;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalTime;
-import java.time.Period;
import java.time.ZoneId;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
@@ -109,7 +108,7 @@ import java.time.temporal.ValueRange;
* @since 1.8
*/
public final class HijrahDate
- extends ChronoDateImpl
+ extends ChronoLocalDateImpl
implements ChronoLocalDate, Serializable {
/**
@@ -582,7 +581,7 @@ public final class HijrahDate
}
@Override
- public Period until(ChronoLocalDate endDate) {
+ public ChronoPeriod until(ChronoLocalDate endDate) {
// TODO: untested
HijrahDate end = getChronology().date(endDate);
long totalMonths = (end.prolepticYear - this.prolepticYear) * 12 + (end.monthOfYear - this.monthOfYear); // safe
@@ -597,7 +596,7 @@ public final class HijrahDate
}
long years = totalMonths / 12; // safe
int months = (int) (totalMonths % 12); // safe
- return Period.of(Math.toIntExact(years), months, days);
+ return getChronology().period(Math.toIntExact(years), months, days);
}
//-----------------------------------------------------------------------
diff --git a/jdk/src/share/classes/java/time/chrono/IsoChronology.java b/jdk/src/share/classes/java/time/chrono/IsoChronology.java
index 2012e64e04d..9638f6eea4f 100644
--- a/jdk/src/share/classes/java/time/chrono/IsoChronology.java
+++ b/jdk/src/share/classes/java/time/chrono/IsoChronology.java
@@ -77,6 +77,7 @@ import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
+import java.time.Period;
import java.time.Year;
import java.time.ZoneId;
import java.time.ZonedDateTime;
@@ -565,6 +566,24 @@ public final class IsoChronology extends Chronology implements Serializable {
return field.range();
}
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains a period for this chronology based on years, months and days.
+ *
+ * This returns a period tied to the ISO chronology using the specified
+ * years, months and days. See {@link Period} for further details.
+ *
+ * @param years the number of years, may be negative
+ * @param months the number of years, may be negative
+ * @param days the number of years, may be negative
+ * @return the period in terms of this chronology, not null
+ * @return the ISO period, not null
+ */
+ @Override // override with covariant return type
+ public Period period(int years, int months, int days) {
+ return Period.of(years, months, days);
+ }
+
//-----------------------------------------------------------------------
/**
* Writes the Chronology using a
diff --git a/jdk/src/share/classes/java/time/chrono/JapaneseDate.java b/jdk/src/share/classes/java/time/chrono/JapaneseDate.java
index 24ad7a921c0..ae4708dbaff 100644
--- a/jdk/src/share/classes/java/time/chrono/JapaneseDate.java
+++ b/jdk/src/share/classes/java/time/chrono/JapaneseDate.java
@@ -61,10 +61,8 @@ import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
-import static java.time.temporal.ChronoField.DAY_OF_YEAR;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoField.YEAR;
-import static java.time.temporal.ChronoField.YEAR_OF_ERA;
import java.io.DataInput;
import java.io.DataOutput;
@@ -76,7 +74,6 @@ import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
-import java.time.Year;
import java.time.ZoneId;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
@@ -119,7 +116,7 @@ import sun.util.calendar.LocalGregorianCalendar;
* @since 1.8
*/
public final class JapaneseDate
- extends ChronoDateImpl
+ extends ChronoLocalDateImpl
implements ChronoLocalDate, Serializable {
/**
@@ -662,8 +659,9 @@ public final class JapaneseDate
}
@Override
- public Period until(ChronoLocalDate endDate) {
- return isoDate.until(endDate);
+ public ChronoPeriod until(ChronoLocalDate endDate) {
+ Period period = isoDate.until(endDate);
+ return getChronology().period(period.getYears(), period.getMonths(), period.getDays());
}
@Override // override for performance
diff --git a/jdk/src/share/classes/java/time/chrono/MinguoDate.java b/jdk/src/share/classes/java/time/chrono/MinguoDate.java
index 16585e7e992..42e0dab0da5 100644
--- a/jdk/src/share/classes/java/time/chrono/MinguoDate.java
+++ b/jdk/src/share/classes/java/time/chrono/MinguoDate.java
@@ -96,7 +96,7 @@ import java.util.Objects;
* @since 1.8
*/
public final class MinguoDate
- extends ChronoDateImpl
+ extends ChronoLocalDateImpl
implements ChronoLocalDate, Serializable {
/**
@@ -421,8 +421,9 @@ public final class MinguoDate
}
@Override
- public Period until(ChronoLocalDate endDate) {
- return isoDate.until(endDate);
+ public ChronoPeriod until(ChronoLocalDate endDate) {
+ Period period = isoDate.until(endDate);
+ return getChronology().period(period.getYears(), period.getMonths(), period.getDays());
}
@Override // override for performance
diff --git a/jdk/src/share/classes/java/time/chrono/Ser.java b/jdk/src/share/classes/java/time/chrono/Ser.java
index cc99f481f8c..5a4e3c12623 100644
--- a/jdk/src/share/classes/java/time/chrono/Ser.java
+++ b/jdk/src/share/classes/java/time/chrono/Ser.java
@@ -104,6 +104,7 @@ final class Ser implements Externalizable {
static final byte HIJRAH_DATE_TYPE = 6;
static final byte MINGUO_DATE_TYPE = 7;
static final byte THAIBUDDHIST_DATE_TYPE = 8;
+ static final byte CHRONO_PERIOD_TYPE = 9;
/** The type being serialized. */
private byte type;
@@ -183,6 +184,9 @@ final class Ser implements Externalizable {
case THAIBUDDHIST_DATE_TYPE:
((ThaiBuddhistDate) object).writeExternal(out);
break;
+ case CHRONO_PERIOD_TYPE:
+ ((ChronoPeriodImpl) object).writeExternal(out);
+ break;
default:
throw new InvalidClassException("Unknown serialized type");
}
@@ -235,6 +239,7 @@ final class Ser implements Externalizable {
case HIJRAH_DATE_TYPE: return HijrahDate.readExternal(in);
case MINGUO_DATE_TYPE: return MinguoDate.readExternal(in);
case THAIBUDDHIST_DATE_TYPE: return ThaiBuddhistDate.readExternal(in);
+ case CHRONO_PERIOD_TYPE: return ChronoPeriodImpl.readExternal(in);
default: throw new StreamCorruptedException("Unknown serialized type");
}
}
diff --git a/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java
index 3d8f4078cc9..89895c8ac48 100644
--- a/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java
+++ b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java
@@ -96,7 +96,7 @@ import java.util.Objects;
* @since 1.8
*/
public final class ThaiBuddhistDate
- extends ChronoDateImpl
+ extends ChronoLocalDateImpl
implements ChronoLocalDate, Serializable {
/**
@@ -421,8 +421,9 @@ public final class ThaiBuddhistDate
}
@Override
- public Period until(ChronoLocalDate endDate) {
- return isoDate.until(endDate);
+ public ChronoPeriod until(ChronoLocalDate endDate) {
+ Period period = isoDate.until(endDate);
+ return getChronology().period(period.getYears(), period.getMonths(), period.getDays());
}
@Override // override for performance
diff --git a/jdk/src/share/classes/java/time/format/Parsed.java b/jdk/src/share/classes/java/time/format/Parsed.java
index 42223d6c1d9..7413467826d 100644
--- a/jdk/src/share/classes/java/time/format/Parsed.java
+++ b/jdk/src/share/classes/java/time/format/Parsed.java
@@ -83,6 +83,8 @@ import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.ChronoLocalDateTime;
+import java.time.chrono.ChronoZonedDateTime;
import java.time.chrono.Chronology;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
@@ -260,11 +262,34 @@ final class Parsed implements TemporalAccessor {
while (changedCount < 50) {
for (Map.Entry entry : fieldValues.entrySet()) {
TemporalField targetField = entry.getKey();
- ChronoLocalDate resolvedDate = targetField.resolve(fieldValues, chrono, zone, resolverStyle);
- if (resolvedDate != null) {
- updateCheckConflict(resolvedDate);
- changedCount++;
- continue outer; // have to restart to avoid concurrent modification
+ TemporalAccessor resolvedObject = targetField.resolve(fieldValues, chrono, zone, resolverStyle);
+ if (resolvedObject != null) {
+ if (resolvedObject instanceof ChronoZonedDateTime) {
+ ChronoZonedDateTime czdt = (ChronoZonedDateTime) resolvedObject;
+ if (zone.equals(czdt.getZone()) == false) {
+ throw new DateTimeException("ChronoZonedDateTime must use the effective parsed zone: " + zone);
+ }
+ resolvedObject = czdt.toLocalDateTime();
+ }
+ if (resolvedObject instanceof ChronoLocalDateTime) {
+ ChronoLocalDateTime cldt = (ChronoLocalDateTime) resolvedObject;
+ updateCheckConflict(cldt.toLocalTime(), Period.ZERO);
+ updateCheckConflict(cldt.toLocalDate());
+ changedCount++;
+ continue outer; // have to restart to avoid concurrent modification
+ }
+ if (resolvedObject instanceof ChronoLocalDate) {
+ updateCheckConflict((ChronoLocalDate) resolvedObject);
+ changedCount++;
+ continue outer; // have to restart to avoid concurrent modification
+ }
+ if (resolvedObject instanceof LocalTime) {
+ updateCheckConflict((LocalTime) resolvedObject, Period.ZERO);
+ changedCount++;
+ continue outer; // have to restart to avoid concurrent modification
+ }
+ throw new DateTimeException("Method resolveFields() can only return ChronoZonedDateTime," +
+ "ChronoLocalDateTime, ChronoLocalDate or LocalTime");
} else if (fieldValues.containsKey(targetField) == false) {
changedCount++;
continue outer; // have to restart to avoid concurrent modification
@@ -302,7 +327,10 @@ final class Parsed implements TemporalAccessor {
if (cld != null && date.equals(cld) == false) {
throw new DateTimeException("Conflict found: Fields resolved to two different dates: " + date + " " + cld);
}
- } else {
+ } else if (cld != null) {
+ if (chrono.equals(cld.getChronology()) == false) {
+ throw new DateTimeException("ChronoLocalDate must use the effective parsed chronology: " + chrono);
+ }
date = cld;
}
}
diff --git a/jdk/src/share/classes/java/time/temporal/ChronoUnit.java b/jdk/src/share/classes/java/time/temporal/ChronoUnit.java
index 19a37e46f4c..c7043272398 100644
--- a/jdk/src/share/classes/java/time/temporal/ChronoUnit.java
+++ b/jdk/src/share/classes/java/time/temporal/ChronoUnit.java
@@ -268,8 +268,8 @@ public enum ChronoUnit implements TemporalUnit {
//-----------------------------------------------------------------------
@Override
- public long between(Temporal temporal1, Temporal temporal2) {
- return temporal1.until(temporal2, this);
+ public long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive) {
+ return temporal1Inclusive.until(temporal2Exclusive, this);
}
//-----------------------------------------------------------------------
diff --git a/jdk/src/share/classes/java/time/temporal/IsoFields.java b/jdk/src/share/classes/java/time/temporal/IsoFields.java
index eae057afb2a..bb19c299875 100644
--- a/jdk/src/share/classes/java/time/temporal/IsoFields.java
+++ b/jdk/src/share/classes/java/time/temporal/IsoFields.java
@@ -684,13 +684,16 @@ public final class IsoFields {
}
@Override
- public long between(Temporal temporal1, Temporal temporal2) {
+ public long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive) {
+ if (temporal1Inclusive.getClass() != temporal2Exclusive.getClass()) {
+ return temporal1Inclusive.until(temporal2Exclusive, this);
+ }
switch(this) {
case WEEK_BASED_YEARS:
- return Math.subtractExact(temporal2.getLong(WEEK_BASED_YEAR),
- temporal1.getLong(WEEK_BASED_YEAR));
+ return Math.subtractExact(temporal2Exclusive.getLong(WEEK_BASED_YEAR),
+ temporal1Inclusive.getLong(WEEK_BASED_YEAR));
case QUARTER_YEARS:
- return temporal1.until(temporal2, MONTHS) / 3;
+ return temporal1Inclusive.until(temporal2Exclusive, MONTHS) / 3;
default:
throw new IllegalStateException("Unreachable");
}
diff --git a/jdk/src/share/classes/java/time/temporal/Temporal.java b/jdk/src/share/classes/java/time/temporal/Temporal.java
index af8424c1560..9931c46f4f1 100644
--- a/jdk/src/share/classes/java/time/temporal/Temporal.java
+++ b/jdk/src/share/classes/java/time/temporal/Temporal.java
@@ -170,7 +170,8 @@ public interface Temporal extends TemporalAccessor {
*
*
* @implSpec
- * Implementations must not alter either this object.
+ *
+ * Implementations must not alter either this object or the specified temporal object.
* Instead, an adjusted copy of the original must be returned.
* This provides equivalent, safe behavior for immutable and mutable implementations.
*
@@ -209,7 +210,7 @@ public interface Temporal extends TemporalAccessor {
* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
* passing {@code this} as the first argument.
*
- * Implementations must not alter either this object or the specified temporal object.
+ * Implementations must not alter this object.
* Instead, an adjusted copy of the original must be returned.
* This provides equivalent, safe behavior for immutable and mutable implementations.
*
@@ -232,16 +233,17 @@ public interface Temporal extends TemporalAccessor {
*
* Some example code indicating how and why this method is used:
*
- * date = date.plus(period); // add a Period instance
- * date = date.plus(duration); // add a Duration instance
- * date = date.plus(workingDays(6)); // example user-written workingDays method
+ * date = date.plus(period); // add a Period instance
+ * date = date.plus(duration); // add a Duration instance
+ * date = date.plus(workingDays(6)); // example user-written workingDays method
*
*
* Note that calling {@code plus} followed by {@code minus} is not guaranteed to
* return the same date-time.
*
* @implSpec
- * Implementations must not alter either this object.
+ *
+ * Implementations must not alter either this object or the specified temporal object.
* Instead, an adjusted copy of the original must be returned.
* This provides equivalent, safe behavior for immutable and mutable implementations.
*
@@ -280,7 +282,7 @@ public interface Temporal extends TemporalAccessor {
* is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
* passing {@code this} as the first argument.
*
- * Implementations must not alter either this object or the specified temporal object.
+ * Implementations must not alter this object.
* Instead, an adjusted copy of the original must be returned.
* This provides equivalent, safe behavior for immutable and mutable implementations.
*
@@ -303,16 +305,17 @@ public interface Temporal extends TemporalAccessor {
*
* Some example code indicating how and why this method is used:
*
- * date = date.minus(period); // subtract a Period instance
- * date = date.minus(duration); // subtract a Duration instance
- * date = date.minus(workingDays(6)); // example user-written workingDays method
+ * date = date.minus(period); // subtract a Period instance
+ * date = date.minus(duration); // subtract a Duration instance
+ * date = date.minus(workingDays(6)); // example user-written workingDays method
*
*
* Note that calling {@code plus} followed by {@code minus} is not guaranteed to
* return the same date-time.
*
* @implSpec
- * Implementations must not alter either this object.
+ *
+ * Implementations must not alter either this object or the specified temporal object.
* Instead, an adjusted copy of the original must be returned.
* This provides equivalent, safe behavior for immutable and mutable implementations.
*
@@ -345,7 +348,7 @@ public interface Temporal extends TemporalAccessor {
* @implSpec
* Implementations must behave in a manor equivalent to the default method behavior.
*
- * Implementations must not alter either this object or the specified temporal object.
+ * Implementations must not alter this object.
* Instead, an adjusted copy of the original must be returned.
* This provides equivalent, safe behavior for immutable and mutable implementations.
*
@@ -371,8 +374,9 @@ public interface Temporal extends TemporalAccessor {
* Calculates the amount of time until another temporal in terms of the specified unit.
*
* This calculates the amount of time between two temporal objects
- * of the same type in terms of a single {@code TemporalUnit}.
+ * in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified temporal.
+ * The end point is converted to be of the same type as the start point if different.
* The result will be negative if the end is before the start.
* For example, the period in hours between two temporal objects can be
* calculated using {@code startTime.until(endTime, HOURS)}.
@@ -409,31 +413,36 @@ public interface Temporal extends TemporalAccessor {
*
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
- * passing {@code this} as the first argument and the input temporal as
+ * passing {@code this} as the first argument and the converted input temporal as
* the second argument.
*
- * In summary, implementations must behave in a manner equivalent to this code:
+ * In summary, implementations must behave in a manner equivalent to this pseudo-code:
*
- * // check input temporal is the same type as this class
+ * // convert the end temporal to the same type as this class
* if (unit instanceof ChronoUnit) {
* // if unit is supported, then calculate and return result
* // else throw UnsupportedTemporalTypeException for unsupported units
* }
- * return unit.between(this, endTemporal);
+ * return unit.between(this, convertedEndTemporal);
*
*
+ * Note that the unit's {@code between} method must only be invoked if the
+ * two temporal objects have exactly the same type evaluated by {@code getClass()}.
+ *
* Implementations must ensure that no observable state is altered when this
* read-only method is invoked.
*
- * @param endTemporal the end temporal, of the same type as this object, not null
+ * @param endExclusive the end temporal, exclusive, converted to be of the
+ * same type as this object, not null
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this temporal object and the specified one
* in terms of the unit; positive if the specified object is later than this one,
* negative if it is earlier than this one
- * @throws DateTimeException if the amount cannot be calculated
+ * @throws DateTimeException if the amount cannot be calculated, or the end
+ * temporal cannot be converted to the same type as this temporal
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
- long until(Temporal endTemporal, TemporalUnit unit);
+ long until(Temporal endExclusive, TemporalUnit unit);
}
diff --git a/jdk/src/share/classes/java/time/temporal/TemporalField.java b/jdk/src/share/classes/java/time/temporal/TemporalField.java
index e4d6b407783..e757734510c 100644
--- a/jdk/src/share/classes/java/time/temporal/TemporalField.java
+++ b/jdk/src/share/classes/java/time/temporal/TemporalField.java
@@ -63,7 +63,6 @@ package java.time.temporal;
import java.time.DateTimeException;
import java.time.ZoneId;
-import java.time.chrono.ChronoLocalDate;
import java.time.chrono.Chronology;
import java.time.format.ResolverStyle;
import java.util.Locale;
@@ -350,6 +349,10 @@ public interface TemporalField {
* be acceptable for the date fields to be resolved into other {@code ChronoField}
* instances that can produce a date, such as {@code EPOCH_DAY}.
*
+ * Not all {@code TemporalAccessor} implementations are accepted as return values.
+ * Implementations must accept {@code ChronoLocalDate}, {@code ChronoLocalDateTime},
+ * {@code ChronoZonedDateTime} and {@code LocalTime}.
+ *
* The zone is not normally required for resolution, but is provided for completeness.
*
* The default implementation must return null.
@@ -358,13 +361,13 @@ public interface TemporalField {
* @param chronology the effective chronology, not null
* @param zone the effective zone, not null
* @param resolverStyle the requested type of resolve, not null
- * @return the resolved date; null if resolving only changed the map,
- * or no resolve occurred
+ * @return the resolved temporal object; null if resolving only
+ * changed the map, or no resolve occurred
* @throws ArithmeticException if numeric overflow occurs
* @throws DateTimeException if resolving results in an error. This must not be thrown
* by querying a field on the temporal without first checking if it is supported
*/
- default ChronoLocalDate resolve(
+ default TemporalAccessor resolve(
Map fieldValues, Chronology chronology,
ZoneId zone, ResolverStyle resolverStyle) {
return null;
diff --git a/jdk/src/share/classes/java/time/temporal/TemporalUnit.java b/jdk/src/share/classes/java/time/temporal/TemporalUnit.java
index 05577d713f8..1c41afa0593 100644
--- a/jdk/src/share/classes/java/time/temporal/TemporalUnit.java
+++ b/jdk/src/share/classes/java/time/temporal/TemporalUnit.java
@@ -231,7 +231,9 @@ public interface TemporalUnit {
* Calculates the amount of time between two temporal objects.
*
* This calculates the amount in terms of this unit. The start and end
- * points are supplied as temporal objects and must be of the same type.
+ * points are supplied as temporal objects and must be of compatible types.
+ * The implementation will convert the second type to be an instance of the
+ * first type before the calculating the amount.
* The result will be negative if the end is before the start.
* For example, the amount in hours between two temporal objects can be
* calculated using {@code HOURS.between(startTime, endTime)}.
@@ -264,15 +266,22 @@ public interface TemporalUnit {
* If the unit is not supported an {@code UnsupportedTemporalTypeException} must be thrown.
* Implementations must not alter the specified temporal objects.
*
- * @param temporal1 the base temporal object, not null
- * @param temporal2 the other temporal object, not null
- * @return the amount of time between temporal1 and temporal2 in terms of this unit;
- * positive if temporal2 is later than temporal1, negative if earlier
- * @throws DateTimeException if the amount cannot be calculated
+ * @implSpec
+ * Implementations must begin by checking to if the two temporals have the
+ * same type using {@code getClass()}. If they do not, then the result must be
+ * obtained by calling {@code temporal1Inclusive.until(temporal2Exclusive, this)}.
+ *
+ * @param temporal1Inclusive the base temporal object, not null
+ * @param temporal2Exclusive the other temporal object, exclusive, not null
+ * @return the amount of time between temporal1Inclusive and temporal2Exclusive
+ * in terms of this unit; positive if temporal2Exclusive is later than
+ * temporal1Inclusive, negative if earlier
+ * @throws DateTimeException if the amount cannot be calculated, or the end
+ * temporal cannot be converted to the same type as the start temporal
* @throws UnsupportedTemporalTypeException if the unit is not supported by the temporal
* @throws ArithmeticException if numeric overflow occurs
*/
- long between(Temporal temporal1, Temporal temporal2);
+ long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive);
//-----------------------------------------------------------------------
/**
diff --git a/jdk/src/share/classes/java/time/temporal/ValueRange.java b/jdk/src/share/classes/java/time/temporal/ValueRange.java
index e003f114adc..a48abafbf10 100644
--- a/jdk/src/share/classes/java/time/temporal/ValueRange.java
+++ b/jdk/src/share/classes/java/time/temporal/ValueRange.java
@@ -61,6 +61,7 @@
*/
package java.time.temporal;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.DateTimeException;
@@ -337,6 +338,21 @@ public final class ValueRange implements Serializable {
}
}
+ /**
+ * Return the ValueRange for the serialized values.
+ * The values are validated according to the constraints of the {@link #of}
+ * factory method.
+ * @return the ValueRange for the serialized fields
+ * @throws InvalidObjectException if the serialized object has invalid values
+ */
+ private Object readResolve() throws InvalidObjectException {
+ try {
+ return of(minSmallest, minLargest, maxSmallest, maxLargest);
+ } catch (IllegalArgumentException iae) {
+ throw new InvalidObjectException("Invalid serialized ValueRange: " + iae.getMessage());
+ }
+ }
+
//-----------------------------------------------------------------------
/**
* Checks if this range is equal to another range.
diff --git a/jdk/src/share/classes/java/util/Arrays.java b/jdk/src/share/classes/java/util/Arrays.java
index 47c99ef7f82..43463a5aff6 100644
--- a/jdk/src/share/classes/java/util/Arrays.java
+++ b/jdk/src/share/classes/java/util/Arrays.java
@@ -1583,6 +1583,7 @@ public class Arrays {
* @since 1.8
*/
public static void parallelPrefix(T[] array, BinaryOperator op) {
+ Objects.requireNonNull(op);
if (array.length > 0)
new ArrayPrefixHelpers.CumulateTask<>
(null, op, array, 0, array.length).invoke();
@@ -1606,6 +1607,7 @@ public class Arrays {
*/
public static void parallelPrefix(T[] array, int fromIndex,
int toIndex, BinaryOperator op) {
+ Objects.requireNonNull(op);
rangeCheck(array.length, fromIndex, toIndex);
if (fromIndex < toIndex)
new ArrayPrefixHelpers.CumulateTask<>
@@ -1627,6 +1629,7 @@ public class Arrays {
* @since 1.8
*/
public static void parallelPrefix(long[] array, LongBinaryOperator op) {
+ Objects.requireNonNull(op);
if (array.length > 0)
new ArrayPrefixHelpers.LongCumulateTask
(null, op, array, 0, array.length).invoke();
@@ -1649,6 +1652,7 @@ public class Arrays {
*/
public static void parallelPrefix(long[] array, int fromIndex,
int toIndex, LongBinaryOperator op) {
+ Objects.requireNonNull(op);
rangeCheck(array.length, fromIndex, toIndex);
if (fromIndex < toIndex)
new ArrayPrefixHelpers.LongCumulateTask
@@ -1673,6 +1677,7 @@ public class Arrays {
* @since 1.8
*/
public static void parallelPrefix(double[] array, DoubleBinaryOperator op) {
+ Objects.requireNonNull(op);
if (array.length > 0)
new ArrayPrefixHelpers.DoubleCumulateTask
(null, op, array, 0, array.length).invoke();
@@ -1695,6 +1700,7 @@ public class Arrays {
*/
public static void parallelPrefix(double[] array, int fromIndex,
int toIndex, DoubleBinaryOperator op) {
+ Objects.requireNonNull(op);
rangeCheck(array.length, fromIndex, toIndex);
if (fromIndex < toIndex)
new ArrayPrefixHelpers.DoubleCumulateTask
@@ -1716,6 +1722,7 @@ public class Arrays {
* @since 1.8
*/
public static void parallelPrefix(int[] array, IntBinaryOperator op) {
+ Objects.requireNonNull(op);
if (array.length > 0)
new ArrayPrefixHelpers.IntCumulateTask
(null, op, array, 0, array.length).invoke();
@@ -1738,6 +1745,7 @@ public class Arrays {
*/
public static void parallelPrefix(int[] array, int fromIndex,
int toIndex, IntBinaryOperator op) {
+ Objects.requireNonNull(op);
rangeCheck(array.length, fromIndex, toIndex);
if (fromIndex < toIndex)
new ArrayPrefixHelpers.IntCumulateTask
diff --git a/jdk/src/share/classes/java/util/Calendar.java b/jdk/src/share/classes/java/util/Calendar.java
index 076b59db52c..03342411d0b 100644
--- a/jdk/src/share/classes/java/util/Calendar.java
+++ b/jdk/src/share/classes/java/util/Calendar.java
@@ -1937,7 +1937,7 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableYEAR, MONTH,
- * DAY_OF_MONTH, HOUR, MINUTE, and
+ * DAY_OF_MONTH, HOUR_OF_DAY, MINUTE, and
* SECOND.
* Previous values of other fields are retained. If this is not desired,
* call {@link #clear()} first.
diff --git a/jdk/src/share/classes/java/util/Collection.java b/jdk/src/share/classes/java/util/Collection.java
index dba273e6885..2ae88727a06 100644
--- a/jdk/src/share/classes/java/util/Collection.java
+++ b/jdk/src/share/classes/java/util/Collection.java
@@ -104,6 +104,13 @@ import java.util.stream.StreamSupport;
* the specified behavior of underlying {@link Object} methods wherever the
* implementor deems it appropriate.
*
+ * Some collection operations which perform recursive traversal of the
+ * collection may fail with an exception for self-referential instances where
+ * the collection directly or indirectly contains itself. This includes the
+ * {@code clone()}, {@code equals()}, {@code hashCode()} and {@code toString()}
+ * methods. Implementations may optionally handle the self-referential scenario,
+ * however most current implementations do not do so.
+ *
*
This interface is a member of the
*
* Java Collections Framework.
@@ -379,8 +386,8 @@ public interface Collection extends Iterable {
/**
* Removes all of the elements of this collection that satisfy the given
- * predicate. Errors or runtime exceptions thrown by the predicate are
- * relayed to the caller.
+ * predicate. Errors or runtime exceptions thrown during iteration or by
+ * the predicate are relayed to the caller.
*
* @implSpec
* The default implementation traverses all elements of the collection using
@@ -393,9 +400,10 @@ public interface Collection extends Iterable {
* removed
* @return {@code true} if any elements were removed
* @throws NullPointerException if the specified filter is null
- * @throws UnsupportedOperationException if the {@code remove}
- * method is not supported by this collection's
- * {@link #iterator}
+ * @throws UnsupportedOperationException if elements cannot be removed
+ * from this collection. Implementations may throw this exception if a
+ * matching element cannot be removed or if, in general, removal is not
+ * supported.
* @since 1.8
*/
default boolean removeIf(Predicate super E> filter) {
@@ -502,12 +510,10 @@ public interface Collection extends Iterable {
/**
* Creates a {@link Spliterator} over the elements in this collection.
*
- * The returned {@code Spliterator} must report the characteristic
- * {@link Spliterator#SIZED}; implementations should document any additional
- * characteristic values reported by the returned spliterator. If
- * this collection contains no elements then the returned spliterator is
- * only required to report {@link Spliterator#SIZED} and is not required to
- * report additional characteristic values (if any).
+ * Implementations should document characteristic values reported by the
+ * spliterator. Such characteristic values are not required to be reported
+ * if the spliterator reports {@link Spliterator#SIZED} and this collection
+ * contains no elements.
*
*
The default implementation should be overridden by subclasses that
* can return a more efficient spliterator. In order to
@@ -533,9 +539,11 @@ public interface Collection extends Iterable {
* late-binding spliterator
* from the collections's {@code Iterator}. The spliterator inherits the
* fail-fast properties of the collection's iterator.
+ *
+ * The created {@code Spliterator} reports {@link Spliterator#SIZED}.
*
* @implNote
- * The returned {@code Spliterator} additionally reports
+ * The created {@code Spliterator} additionally reports
* {@link Spliterator#SUBSIZED}.
*
*
If a spliterator covers no elements then the reporting of additional
diff --git a/jdk/src/share/classes/java/util/GregorianCalendar.java b/jdk/src/share/classes/java/util/GregorianCalendar.java
index 8381a4fab4b..eadb5d020dc 100644
--- a/jdk/src/share/classes/java/util/GregorianCalendar.java
+++ b/jdk/src/share/classes/java/util/GregorianCalendar.java
@@ -41,11 +41,8 @@ package java.util;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.time.Instant;
-import java.time.ZoneId;
import java.time.ZonedDateTime;
-import java.time.chrono.IsoChronology;
import java.time.temporal.ChronoField;
-import java.time.temporal.TemporalQuery;
import sun.util.calendar.BaseCalendar;
import sun.util.calendar.CalendarDate;
import sun.util.calendar.CalendarSystem;
@@ -867,6 +864,7 @@ public class GregorianCalendar extends Calendar {
* false otherwise.
* @see Calendar#compareTo(Calendar)
*/
+ @Override
public boolean equals(Object obj) {
return obj instanceof GregorianCalendar &&
super.equals(obj) &&
@@ -876,6 +874,7 @@ public class GregorianCalendar extends Calendar {
/**
* Generates the hash code for this GregorianCalendar object.
*/
+ @Override
public int hashCode() {
return super.hashCode() ^ (int)gregorianCutoverDate;
}
@@ -908,6 +907,7 @@ public class GregorianCalendar extends Calendar {
* or if any calendar fields have out-of-range values in
* non-lenient mode.
*/
+ @Override
public void add(int field, int amount) {
// If amount == 0, do nothing even the given field is out of
// range. This is tested by JCK.
@@ -1106,6 +1106,7 @@ public class GregorianCalendar extends Calendar {
* @see #add(int,int)
* @see #set(int,int)
*/
+ @Override
public void roll(int field, boolean up) {
roll(field, up ? +1 : -1);
}
@@ -1154,6 +1155,7 @@ public class GregorianCalendar extends Calendar {
* @see #set(int,int)
* @since 1.2
*/
+ @Override
public void roll(int field, int amount) {
// If amount == 0, do nothing even the given field is out of
// range. This is tested by JCK.
@@ -1272,25 +1274,44 @@ public class GregorianCalendar extends Calendar {
int woy = internalGet(WEEK_OF_YEAR);
int value = woy + amount;
if (!isCutoverYear(y)) {
- // If the new value is in between min and max
- // (exclusive), then we can use the value.
- if (value > min && value < max) {
- set(WEEK_OF_YEAR, value);
- return;
- }
- long fd = getCurrentFixedDate();
- // Make sure that the min week has the current DAY_OF_WEEK
- long day1 = fd - (7 * (woy - min));
- if (calsys.getYearFromFixedDate(day1) != y) {
- min++;
- }
+ int weekYear = getWeekYear();
+ if (weekYear == y) {
+ // If the new value is in between min and max
+ // (exclusive), then we can use the value.
+ if (value > min && value < max) {
+ set(WEEK_OF_YEAR, value);
+ return;
+ }
+ long fd = getCurrentFixedDate();
+ // Make sure that the min week has the current DAY_OF_WEEK
+ // in the calendar year
+ long day1 = fd - (7 * (woy - min));
+ if (calsys.getYearFromFixedDate(day1) != y) {
+ min++;
+ }
- // Make sure the same thing for the max week
- fd += 7 * (max - internalGet(WEEK_OF_YEAR));
- if (calsys.getYearFromFixedDate(fd) != y) {
- max--;
+ // Make sure the same thing for the max week
+ fd += 7 * (max - internalGet(WEEK_OF_YEAR));
+ if (calsys.getYearFromFixedDate(fd) != y) {
+ max--;
+ }
+ } else {
+ // When WEEK_OF_YEAR and YEAR are out of sync,
+ // adjust woy and amount to stay in the calendar year.
+ if (weekYear > y) {
+ if (amount < 0) {
+ amount++;
+ }
+ woy = max;
+ } else {
+ if (amount > 0) {
+ amount -= woy - max;
+ }
+ woy = min;
+ }
}
- break;
+ set(field, getRolledValue(woy, amount, min, max));
+ return;
}
// Handle cutover here.
@@ -1510,6 +1531,7 @@ public class GregorianCalendar extends Calendar {
* @see #getActualMinimum(int)
* @see #getActualMaximum(int)
*/
+ @Override
public int getMinimum(int field) {
return MIN_VALUES[field];
}
@@ -1533,6 +1555,7 @@ public class GregorianCalendar extends Calendar {
* @see #getActualMinimum(int)
* @see #getActualMaximum(int)
*/
+ @Override
public int getMaximum(int field) {
switch (field) {
case MONTH:
@@ -1581,6 +1604,7 @@ public class GregorianCalendar extends Calendar {
* @see #getActualMinimum(int)
* @see #getActualMaximum(int)
*/
+ @Override
public int getGreatestMinimum(int field) {
if (field == DAY_OF_MONTH) {
BaseCalendar.Date d = getGregorianCutoverDate();
@@ -1610,6 +1634,7 @@ public class GregorianCalendar extends Calendar {
* @see #getActualMinimum(int)
* @see #getActualMaximum(int)
*/
+ @Override
public int getLeastMaximum(int field) {
switch (field) {
case MONTH:
@@ -1659,6 +1684,7 @@ public class GregorianCalendar extends Calendar {
* @see #getActualMaximum(int)
* @since 1.2
*/
+ @Override
public int getActualMinimum(int field) {
if (field == DAY_OF_MONTH) {
GregorianCalendar gc = getNormalizedCalendar();
@@ -1702,6 +1728,7 @@ public class GregorianCalendar extends Calendar {
* @see #getActualMinimum(int)
* @since 1.2
*/
+ @Override
public int getActualMaximum(int field) {
final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK|
HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK|
@@ -1970,6 +1997,7 @@ public class GregorianCalendar extends Calendar {
(internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET));
}
+ @Override
public Object clone()
{
GregorianCalendar other = (GregorianCalendar) super.clone();
@@ -1987,6 +2015,7 @@ public class GregorianCalendar extends Calendar {
return other;
}
+ @Override
public TimeZone getTimeZone() {
TimeZone zone = super.getTimeZone();
// To share the zone by CalendarDates
@@ -1997,6 +2026,7 @@ public class GregorianCalendar extends Calendar {
return zone;
}
+ @Override
public void setTimeZone(TimeZone zone) {
super.setTimeZone(zone);
// To share the zone by CalendarDates
@@ -2227,6 +2257,7 @@ public class GregorianCalendar extends Calendar {
* @see #getActualMaximum(int)
* @since 1.7
*/
+ @Override
public int getWeeksInWeekYear() {
GregorianCalendar gc = getNormalizedCalendar();
int weekYear = gc.getWeekYear();
@@ -2262,8 +2293,9 @@ public class GregorianCalendar extends Calendar {
*
* @see Calendar#complete
*/
+ @Override
protected void computeFields() {
- int mask = 0;
+ int mask;
if (isPartiallyNormalized()) {
// Determine which calendar fields need to be computed.
mask = getSetStateFields();
@@ -2598,6 +2630,7 @@ public class GregorianCalendar extends Calendar {
*
* @exception IllegalArgumentException if any calendar fields are invalid.
*/
+ @Override
protected void computeTime() {
// In non-lenient mode, perform brief checking of calendar
// fields which have been set externally. Through this
diff --git a/jdk/src/share/classes/java/util/List.java b/jdk/src/share/classes/java/util/List.java
index 65ad1404c38..42a1acf22c5 100644
--- a/jdk/src/share/classes/java/util/List.java
+++ b/jdk/src/share/classes/java/util/List.java
@@ -396,11 +396,13 @@ public interface List extends Collection {
* replacing the first element.
*
* @param operator the operator to apply to each element
- * @throws UnsupportedOperationException if the {@code set}
- * operation is not supported by this list
+ * @throws UnsupportedOperationException if this list is unmodifiable.
+ * Implementations may throw this exception if an element
+ * cannot be replaced or if, in general, modification is not
+ * supported
* @throws NullPointerException if the specified operator is null or
- * if the element is replaced with a null value and this list
- * does not permit null elements
+ * if the operator result is a null value and this list does
+ * not permit null elements
* (optional)
* @since 1.8
*/
@@ -685,4 +687,3 @@ public interface List extends Collection {
return Spliterators.spliterator(this, Spliterator.ORDERED);
}
}
-
diff --git a/jdk/src/share/classes/java/util/Map.java b/jdk/src/share/classes/java/util/Map.java
index bf1ba8391c8..d1695ef23ee 100644
--- a/jdk/src/share/classes/java/util/Map.java
+++ b/jdk/src/share/classes/java/util/Map.java
@@ -86,10 +86,6 @@ import java.io.Serializable;
* Such exceptions are marked as "optional" in the specification for this
* interface.
*
- * This interface is a member of the
- *
- * Java Collections Framework.
- *
*
Many methods in Collections Framework interfaces are defined
* in terms of the {@link Object#equals(Object) equals} method. For
* example, the specification for the {@link #containsKey(Object)
@@ -107,6 +103,17 @@ import java.io.Serializable;
* the specified behavior of underlying {@link Object} methods wherever the
* implementor deems it appropriate.
*
+ *
Some map operations which perform recursive traversal of the map may fail
+ * with an exception for self-referential instances where the map directly or
+ * indirectly contains itself. This includes the {@code clone()},
+ * {@code equals()}, {@code hashCode()} and {@code toString()} methods.
+ * Implementations may optionally handle the self-referential scenario, however
+ * most current implementations do not do so.
+ *
+ *
This interface is a member of the
+ *
+ * Java Collections Framework.
+ *
* @param the type of keys maintained by this map
* @param the type of mapped values
*
diff --git a/jdk/src/share/classes/java/util/Optional.java b/jdk/src/share/classes/java/util/Optional.java
index ce2a33d1de6..10b79234b18 100644
--- a/jdk/src/share/classes/java/util/Optional.java
+++ b/jdk/src/share/classes/java/util/Optional.java
@@ -85,6 +85,7 @@ public final class Optional {
* Constructs an instance with the value present.
*
* @param value the non-null value to be present
+ * @throws NullPointerException if value is null
*/
private Optional(T value) {
this.value = Objects.requireNonNull(value);
@@ -96,6 +97,7 @@ public final class Optional {
* @param the class of the value
* @param value the value to be present, which must be non-null
* @return an {@code Optional} with the value present
+ * @throws NullPointerException if value is null
*/
public static Optional of(T value) {
return new Optional<>(value);
diff --git a/jdk/src/share/classes/java/util/Random.java b/jdk/src/share/classes/java/util/Random.java
index 2c0e0135c72..2095c437168 100644
--- a/jdk/src/share/classes/java/util/Random.java
+++ b/jdk/src/share/classes/java/util/Random.java
@@ -89,7 +89,7 @@ class Random implements java.io.Serializable {
private static final long addend = 0xBL;
private static final long mask = (1L << 48) - 1;
- private static final double DOUBLE_UNIT = 1.0 / (1L << 53);
+ private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
// IllegalArgumentException messages
static final String BadBound = "bound must be positive";
diff --git a/jdk/src/share/classes/java/util/Set.java b/jdk/src/share/classes/java/util/Set.java
index d47a06a4a8a..2703049b30d 100644
--- a/jdk/src/share/classes/java/util/Set.java
+++ b/jdk/src/share/classes/java/util/Set.java
@@ -386,15 +386,18 @@ public interface Set extends Collection {
/**
* Creates a {@code Spliterator} over the elements in this set.
*
- * The {@code Spliterator} reports {@link Spliterator#SIZED} and
- * {@link Spliterator#DISTINCT}. Implementations should document the
- * reporting of additional characteristic values.
+ *
The {@code Spliterator} reports {@link Spliterator#DISTINCT}.
+ * Implementations should document the reporting of additional
+ * characteristic values.
*
* @implSpec
* The default implementation creates a
* late-binding spliterator
* from the set's {@code Iterator}. The spliterator inherits the
* fail-fast properties of the set's iterator.
+ *
+ * The created {@code Spliterator} additionally reports
+ * {@link Spliterator#SIZED}.
*
* @implNote
* The created {@code Spliterator} additionally reports
diff --git a/jdk/src/share/classes/java/util/SortedSet.java b/jdk/src/share/classes/java/util/SortedSet.java
index 3e64804e7b5..3ea932949a3 100644
--- a/jdk/src/share/classes/java/util/SortedSet.java
+++ b/jdk/src/share/classes/java/util/SortedSet.java
@@ -223,10 +223,10 @@ public interface SortedSet extends Set {
/**
* Creates a {@code Spliterator} over the elements in this sorted set.
*
- * The {@code Spliterator} reports {@link Spliterator#SIZED},
- * {@link Spliterator#DISTINCT}, {@link Spliterator#SORTED} and
- * {@link Spliterator#ORDERED}. Implementations should document the
- * reporting of additional characteristic values.
+ *
The {@code Spliterator} reports {@link Spliterator#DISTINCT},
+ * {@link Spliterator#SORTED} and {@link Spliterator#ORDERED}.
+ * Implementations should document the reporting of additional
+ * characteristic values.
*
*
The spliterator's comparator (see
* {@link java.util.Spliterator#getComparator()}) must be {@code null} if
@@ -240,6 +240,9 @@ public interface SortedSet extends Set {
* from the sorted set's {@code Iterator}. The spliterator inherits the
* fail-fast properties of the set's iterator. The
* spliterator's comparator is the same as the sorted set's comparator.
+ *
+ * The created {@code Spliterator} additionally reports
+ * {@link Spliterator#SIZED}.
*
* @implNote
* The created {@code Spliterator} additionally reports
diff --git a/jdk/src/share/classes/java/util/SplittableRandom.java b/jdk/src/share/classes/java/util/SplittableRandom.java
index c3f5c0b4234..00de113a6f8 100644
--- a/jdk/src/share/classes/java/util/SplittableRandom.java
+++ b/jdk/src/share/classes/java/util/SplittableRandom.java
@@ -107,29 +107,25 @@ public final class SplittableRandom {
* Methods nextLong, nextInt, and derivatives do not return the
* sequence (seed) values, but instead a hash-like bit-mix of
* their bits, producing more independently distributed sequences.
- * For nextLong, the mix64 bit-mixing function computes the same
- * value as the "64-bit finalizer" function in Austin Appleby's
- * MurmurHash3 algorithm. See
- * http://code.google.com/p/smhasher/wiki/MurmurHash3 , which
- * comments: "The constants for the finalizers were generated by a
- * simple simulated-annealing algorithm, and both avalanche all
- * bits of 'h' to within 0.25% bias." The mix32 function is
- * equivalent to (int)(mix64(seed) >>> 32), but faster because it
- * omits a step that doesn't contribute to result.
+ * For nextLong, the mix64 function is based on David Stafford's
+ * (http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html)
+ * "Mix13" variant of the "64-bit finalizer" function in Austin
+ * Appleby's MurmurHash3 algorithm (see
+ * http://code.google.com/p/smhasher/wiki/MurmurHash3). The mix32
+ * function is based on Stafford's Mix04 mix function, but returns
+ * the upper 32 bits cast as int.
*
* The split operation uses the current generator to form the seed
* and gamma for another SplittableRandom. To conservatively
* avoid potential correlations between seed and value generation,
- * gamma selection (method nextGamma) uses the "Mix13" constants
- * for MurmurHash3 described by David Stafford
- * (http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html)
- * To avoid potential weaknesses in bit-mixing transformations, we
- * restrict gammas to odd values with at least 12 and no more than
- * 52 bits set. Rather than rejecting candidates with too few or
- * too many bits set, method nextGamma flips some bits (which has
- * the effect of mapping at most 4 to any given gamma value).
- * This reduces the effective set of 64bit odd gamma values by
- * about 214, a very tiny percentage, and serves as an
+ * gamma selection (method mixGamma) uses different
+ * (Murmurhash3's) mix constants. To avoid potential weaknesses
+ * in bit-mixing transformations, we restrict gammas to odd values
+ * with at least 24 0-1 or 1-0 bit transitions. Rather than
+ * rejecting candidates with too few or too many bits set, method
+ * mixGamma flips some bits (which has the effect of mapping at
+ * most 4 to any given gamma value). This reduces the effective
+ * set of 64bit odd gamma values by about 2%, and serves as an
* automated screening for sequence constant selection that is
* left as an empirical decision in some other hashing and crypto
* algorithms.
@@ -140,14 +136,15 @@ public final class SplittableRandom {
* avalanching.
*
* The default (no-argument) constructor, in essence, invokes
- * split() for a common "seeder" SplittableRandom. Unlike other
- * cases, this split must be performed in a thread-safe manner, so
- * we use an AtomicLong to represent the seed rather than use an
- * explicit SplittableRandom. To bootstrap the seeder, we start
- * off using a seed based on current time and host unless the
- * java.util.secureRandomSeed property is set. This serves as a
- * slimmed-down (and insecure) variant of SecureRandom that also
- * avoids stalls that may occur when using /dev/random.
+ * split() for a common "defaultGen" SplittableRandom. Unlike
+ * other cases, this split must be performed in a thread-safe
+ * manner, so we use an AtomicLong to represent the seed rather
+ * than use an explicit SplittableRandom. To bootstrap the
+ * defaultGen, we start off using a seed based on current time and
+ * network interface address unless the java.util.secureRandomSeed
+ * property is set. This serves as a slimmed-down (and insecure)
+ * variant of SecureRandom that also avoids stalls that may occur
+ * when using /dev/random.
*
* It is a relatively simple matter to apply the basic design here
* to use 128 bit seeds. However, emulating 128bit arithmetic and
@@ -160,17 +157,16 @@ public final class SplittableRandom {
*/
/**
- * The initial gamma value for (unsplit) SplittableRandoms. Must
- * be odd with at least 12 and no more than 52 bits set. Currently
- * set to the golden ratio scaled to 64bits.
+ * The golden ratio scaled to 64bits, used as the initial gamma
+ * value for (unsplit) SplittableRandoms.
*/
- private static final long INITIAL_GAMMA = 0x9e3779b97f4a7c15L;
+ private static final long GOLDEN_GAMMA = 0x9e3779b97f4a7c15L;
/**
* The least non-zero value returned by nextDouble(). This value
* is scaled by a random value of 53 bits to produce a result.
*/
- private static final double DOUBLE_UNIT = 1.0 / (1L << 53);
+ private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53);
/**
* The seed. Updated only via method nextSeed.
@@ -191,31 +187,31 @@ public final class SplittableRandom {
}
/**
- * Computes MurmurHash3 64bit mix function.
+ * Computes Stafford variant 13 of 64bit mix function.
*/
private static long mix64(long z) {
- z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
- z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
- return z ^ (z >>> 33);
+ z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L;
+ z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL;
+ return z ^ (z >>> 31);
}
/**
- * Returns the 32 high bits of mix64(z) as int.
+ * Returns the 32 high bits of Stafford variant 4 mix64 function as int.
*/
private static int mix32(long z) {
- z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
- return (int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) >>> 32);
+ z = (z ^ (z >>> 33)) * 0x62a9d9ed799705f5L;
+ return (int)(((z ^ (z >>> 28)) * 0xcb24d0a5c88c35b3L) >>> 32);
}
/**
* Returns the gamma value to use for a new split instance.
*/
- private static long nextGamma(long z) {
- z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L; // Stafford "Mix13"
- z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL;
- z = (z ^ (z >>> 31)) | 1L; // force to be odd
- int n = Long.bitCount(z); // ensure enough 0 and 1 bits
- return (n < 12 || n > 52) ? z ^ 0xaaaaaaaaaaaaaaaaL : z;
+ private static long mixGamma(long z) {
+ z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; // MurmurHash3 mix constants
+ z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
+ z = (z ^ (z >>> 33)) | 1L; // force to be odd
+ int n = Long.bitCount(z ^ (z >>> 1)); // ensure enough transitions
+ return (n < 24) ? z ^ 0xaaaaaaaaaaaaaaaaL : z;
}
/**
@@ -228,7 +224,7 @@ public final class SplittableRandom {
/**
* The seed generator for default constructors.
*/
- private static final AtomicLong seeder = new AtomicLong(initialSeed());
+ private static final AtomicLong defaultGen = new AtomicLong(initialSeed());
private static long initialSeed() {
String pp = java.security.AccessController.doPrivileged(
@@ -396,7 +392,7 @@ public final class SplittableRandom {
* @param seed the initial seed
*/
public SplittableRandom(long seed) {
- this(seed, INITIAL_GAMMA);
+ this(seed, GOLDEN_GAMMA);
}
/**
@@ -405,8 +401,10 @@ public final class SplittableRandom {
* of those of any other instances in the current program; and
* may, and typically does, vary across program invocations.
*/
- public SplittableRandom() { // emulate seeder.split()
- this.gamma = nextGamma(this.seed = seeder.addAndGet(INITIAL_GAMMA));
+ public SplittableRandom() { // emulate defaultGen.split()
+ long s = defaultGen.getAndAdd(2 * GOLDEN_GAMMA);
+ this.seed = mix64(s);
+ this.gamma = mixGamma(s + GOLDEN_GAMMA);
}
/**
@@ -424,8 +422,7 @@ public final class SplittableRandom {
* @return the new SplittableRandom instance
*/
public SplittableRandom split() {
- long s = nextSeed();
- return new SplittableRandom(s, nextGamma(s));
+ return new SplittableRandom(nextLong(), mixGamma(nextSeed()));
}
/**
diff --git a/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java b/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java
index 2cd2b0094bf..2606bed44be 100644
--- a/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java
+++ b/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java
@@ -194,8 +194,8 @@ public class ThreadLocalRandom extends Random {
private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
// Constants from SplittableRandom
- private static final double DOUBLE_UNIT = 1.0 / (1L << 53);
- private static final float FLOAT_UNIT = 1.0f / (1 << 24);
+ private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
+ private static final float FLOAT_UNIT = 0x1.0p-24f; // 1.0f / (1 << 24)
/** Rarely-used holder for the second of a pair of Gaussians */
private static final ThreadLocal nextLocalGaussian =
diff --git a/jdk/src/share/classes/java/util/stream/Node.java b/jdk/src/share/classes/java/util/stream/Node.java
index bf4c2c6340a..381d06defbe 100644
--- a/jdk/src/share/classes/java/util/stream/Node.java
+++ b/jdk/src/share/classes/java/util/stream/Node.java
@@ -149,7 +149,9 @@ interface Node {
/**
* Copies the content of this {@code Node} into an array, starting at a
* given offset into the array. It is the caller's responsibility to ensure
- * there is sufficient room in the array.
+ * there is sufficient room in the array, otherwise unspecified behaviour
+ * will occur if the array length is less than the number of elements
+ * contained in this node.
*
* @param array the array into which to copy the contents of this
* {@code Node}
@@ -258,6 +260,12 @@ interface Node {
*/
@Override
default T[] asArray(IntFunction generator) {
+ if (java.util.stream.Tripwire.ENABLED)
+ java.util.stream.Tripwire.trip(getClass(), "{0} calling Node.OfPrimitive.asArray");
+
+ long size = count();
+ if (size >= Nodes.MAX_ARRAY_SIZE)
+ throw new IllegalArgumentException(Nodes.BAD_SIZE);
T[] boxed = generator.apply((int) count());
copyInto(boxed, 0);
return boxed;
diff --git a/jdk/src/share/classes/java/util/stream/Nodes.java b/jdk/src/share/classes/java/util/stream/Nodes.java
index 687174462b3..d69b9f61b1a 100644
--- a/jdk/src/share/classes/java/util/stream/Nodes.java
+++ b/jdk/src/share/classes/java/util/stream/Nodes.java
@@ -60,6 +60,9 @@ final class Nodes {
*/
static final long MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+ // IllegalArgumentException messages
+ static final String BAD_SIZE = "Stream size exceeds max array size";
+
@SuppressWarnings("raw")
private static final Node EMPTY_NODE = new EmptyNode.OfRef();
private static final Node.OfInt EMPTY_INT_NODE = new EmptyNode.OfInt();
@@ -317,7 +320,7 @@ final class Nodes {
long size = helper.exactOutputSizeIfKnown(spliterator);
if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
if (size >= MAX_ARRAY_SIZE)
- throw new IllegalArgumentException("Stream size exceeds max array size");
+ throw new IllegalArgumentException(BAD_SIZE);
P_OUT[] array = generator.apply((int) size);
new SizedCollectorTask.OfRef<>(spliterator, helper, array).invoke();
return node(array);
@@ -354,7 +357,7 @@ final class Nodes {
long size = helper.exactOutputSizeIfKnown(spliterator);
if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
if (size >= MAX_ARRAY_SIZE)
- throw new IllegalArgumentException("Stream size exceeds max array size");
+ throw new IllegalArgumentException(BAD_SIZE);
int[] array = new int[(int) size];
new SizedCollectorTask.OfInt<>(spliterator, helper, array).invoke();
return node(array);
@@ -392,7 +395,7 @@ final class Nodes {
long size = helper.exactOutputSizeIfKnown(spliterator);
if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
if (size >= MAX_ARRAY_SIZE)
- throw new IllegalArgumentException("Stream size exceeds max array size");
+ throw new IllegalArgumentException(BAD_SIZE);
long[] array = new long[(int) size];
new SizedCollectorTask.OfLong<>(spliterator, helper, array).invoke();
return node(array);
@@ -430,7 +433,7 @@ final class Nodes {
long size = helper.exactOutputSizeIfKnown(spliterator);
if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
if (size >= MAX_ARRAY_SIZE)
- throw new IllegalArgumentException("Stream size exceeds max array size");
+ throw new IllegalArgumentException(BAD_SIZE);
double[] array = new double[(int) size];
new SizedCollectorTask.OfDouble<>(spliterator, helper, array).invoke();
return node(array);
@@ -460,7 +463,10 @@ final class Nodes {
*/
public static Node flatten(Node node, IntFunction generator) {
if (node.getChildCount() > 0) {
- T[] array = generator.apply((int) node.count());
+ long size = node.count();
+ if (size >= MAX_ARRAY_SIZE)
+ throw new IllegalArgumentException(BAD_SIZE);
+ T[] array = generator.apply((int) size);
new ToArrayTask.OfRef<>(node, array, 0).invoke();
return node(array);
} else {
@@ -483,7 +489,10 @@ final class Nodes {
*/
public static Node.OfInt flattenInt(Node.OfInt node) {
if (node.getChildCount() > 0) {
- int[] array = new int[(int) node.count()];
+ long size = node.count();
+ if (size >= MAX_ARRAY_SIZE)
+ throw new IllegalArgumentException(BAD_SIZE);
+ int[] array = new int[(int) size];
new ToArrayTask.OfInt(node, array, 0).invoke();
return node(array);
} else {
@@ -506,7 +515,10 @@ final class Nodes {
*/
public static Node.OfLong flattenLong(Node.OfLong node) {
if (node.getChildCount() > 0) {
- long[] array = new long[(int) node.count()];
+ long size = node.count();
+ if (size >= MAX_ARRAY_SIZE)
+ throw new IllegalArgumentException(BAD_SIZE);
+ long[] array = new long[(int) size];
new ToArrayTask.OfLong(node, array, 0).invoke();
return node(array);
} else {
@@ -529,7 +541,10 @@ final class Nodes {
*/
public static Node.OfDouble flattenDouble(Node.OfDouble node) {
if (node.getChildCount() > 0) {
- double[] array = new double[(int) node.count()];
+ long size = node.count();
+ if (size >= MAX_ARRAY_SIZE)
+ throw new IllegalArgumentException(BAD_SIZE);
+ double[] array = new double[(int) size];
new ToArrayTask.OfDouble(node, array, 0).invoke();
return node(array);
} else {
@@ -627,7 +642,7 @@ final class Nodes {
@SuppressWarnings("unchecked")
ArrayNode(long size, IntFunction generator) {
if (size >= MAX_ARRAY_SIZE)
- throw new IllegalArgumentException("Stream size exceeds max array size");
+ throw new IllegalArgumentException(BAD_SIZE);
this.array = generator.apply((int) size);
this.curSize = 0;
}
@@ -777,12 +792,17 @@ final class Nodes {
public void copyInto(T[] array, int offset) {
Objects.requireNonNull(array);
left.copyInto(array, offset);
+ // Cast to int is safe since it is the callers responsibility to
+ // ensure that there is sufficient room in the array
right.copyInto(array, offset + (int) left.count());
}
@Override
public T[] asArray(IntFunction generator) {
- T[] array = generator.apply((int) count());
+ long size = count();
+ if (size >= MAX_ARRAY_SIZE)
+ throw new IllegalArgumentException(BAD_SIZE);
+ T[] array = generator.apply((int) size);
copyInto(array, 0);
return array;
}
@@ -836,12 +856,17 @@ final class Nodes {
@Override
public void copyInto(T_ARR array, int offset) {
left.copyInto(array, offset);
+ // Cast to int is safe since it is the callers responsibility to
+ // ensure that there is sufficient room in the array
right.copyInto(array, offset + (int) left.count());
}
@Override
public T_ARR asPrimitiveArray() {
- T_ARR array = newArray((int) count());
+ long size = count();
+ if (size >= MAX_ARRAY_SIZE)
+ throw new IllegalArgumentException(BAD_SIZE);
+ T_ARR array = newArray((int) size);
copyInto(array, 0);
return array;
}
@@ -1287,7 +1312,7 @@ final class Nodes {
IntArrayNode(long size) {
if (size >= MAX_ARRAY_SIZE)
- throw new IllegalArgumentException("Stream size exceeds max array size");
+ throw new IllegalArgumentException(BAD_SIZE);
this.array = new int[(int) size];
this.curSize = 0;
}
@@ -1343,7 +1368,7 @@ final class Nodes {
LongArrayNode(long size) {
if (size >= MAX_ARRAY_SIZE)
- throw new IllegalArgumentException("Stream size exceeds max array size");
+ throw new IllegalArgumentException(BAD_SIZE);
this.array = new long[(int) size];
this.curSize = 0;
}
@@ -1397,7 +1422,7 @@ final class Nodes {
DoubleArrayNode(long size) {
if (size >= MAX_ARRAY_SIZE)
- throw new IllegalArgumentException("Stream size exceeds max array size");
+ throw new IllegalArgumentException(BAD_SIZE);
this.array = new double[(int) size];
this.curSize = 0;
}
@@ -1843,8 +1868,8 @@ final class Nodes {
task = task.makeChild(rightSplit, task.offset + leftSplitSize,
task.length - leftSplitSize);
}
- if (task.offset + task.length >= MAX_ARRAY_SIZE)
- throw new IllegalArgumentException("Stream size exceeds max array size");
+
+ assert task.offset + task.length < MAX_ARRAY_SIZE;
T_SINK sink = (T_SINK) task;
task.helper.wrapAndCopyInto(sink, rightSplit);
task.propagateCompletion();
@@ -1854,10 +1879,13 @@ final class Nodes {
@Override
public void begin(long size) {
- if(size > length)
+ if (size > length)
throw new IllegalStateException("size passed to Sink.begin exceeds array length");
+ // Casts to int are safe since absolute size is verified to be within
+ // bounds when the root concrete SizedCollectorTask is constructed
+ // with the shared array
index = (int) offset;
- fence = (int) offset + (int) length;
+ fence = index + (int) length;
}
@SuppressWarnings("serial")
diff --git a/jdk/src/share/classes/java/util/stream/SortedOps.java b/jdk/src/share/classes/java/util/stream/SortedOps.java
index 9df65e352e2..8dcabb49145 100644
--- a/jdk/src/share/classes/java/util/stream/SortedOps.java
+++ b/jdk/src/share/classes/java/util/stream/SortedOps.java
@@ -278,7 +278,7 @@ final class SortedOps {
}
/**
- * {@link ForkJoinTask} for implementing sort on SIZED reference streams.
+ * {@link Sink} for implementing sort on SIZED reference streams.
*/
private static final class SizedRefSortingSink extends Sink.ChainedReference {
private final Comparator super T> comparator;
@@ -293,16 +293,12 @@ final class SortedOps {
@Override
public void begin(long size) {
if (size >= Nodes.MAX_ARRAY_SIZE)
- throw new IllegalArgumentException("Stream size exceeds max array size");
+ throw new IllegalArgumentException(Nodes.BAD_SIZE);
array = (T[]) new Object[(int) size];
}
@Override
public void end() {
- // Need to use offset rather than array.length since the downstream
- // many be short-circuiting
- // @@@ A better approach is to know if the downstream short-circuits
- // and check sink.cancellationRequested
Arrays.sort(array, 0, offset, comparator);
downstream.begin(offset);
for (int i = 0; i < offset; i++)
@@ -331,6 +327,8 @@ final class SortedOps {
@Override
public void begin(long size) {
+ if (size >= Nodes.MAX_ARRAY_SIZE)
+ throw new IllegalArgumentException(Nodes.BAD_SIZE);
list = (size >= 0) ? new ArrayList((int) size) : new ArrayList();
}
@@ -363,7 +361,7 @@ final class SortedOps {
@Override
public void begin(long size) {
if (size >= Nodes.MAX_ARRAY_SIZE)
- throw new IllegalArgumentException("Stream size exceeds max array size");
+ throw new IllegalArgumentException(Nodes.BAD_SIZE);
array = new int[(int) size];
}
@@ -395,6 +393,8 @@ final class SortedOps {
@Override
public void begin(long size) {
+ if (size >= Nodes.MAX_ARRAY_SIZE)
+ throw new IllegalArgumentException(Nodes.BAD_SIZE);
b = (size > 0) ? new SpinedBuffer.OfInt((int) size) : new SpinedBuffer.OfInt();
}
@@ -428,7 +428,7 @@ final class SortedOps {
@Override
public void begin(long size) {
if (size >= Nodes.MAX_ARRAY_SIZE)
- throw new IllegalArgumentException("Stream size exceeds max array size");
+ throw new IllegalArgumentException(Nodes.BAD_SIZE);
array = new long[(int) size];
}
@@ -460,6 +460,8 @@ final class SortedOps {
@Override
public void begin(long size) {
+ if (size >= Nodes.MAX_ARRAY_SIZE)
+ throw new IllegalArgumentException(Nodes.BAD_SIZE);
b = (size > 0) ? new SpinedBuffer.OfLong((int) size) : new SpinedBuffer.OfLong();
}
@@ -493,7 +495,7 @@ final class SortedOps {
@Override
public void begin(long size) {
if (size >= Nodes.MAX_ARRAY_SIZE)
- throw new IllegalArgumentException("Stream size exceeds max array size");
+ throw new IllegalArgumentException(Nodes.BAD_SIZE);
array = new double[(int) size];
}
@@ -525,6 +527,8 @@ final class SortedOps {
@Override
public void begin(long size) {
+ if (size >= Nodes.MAX_ARRAY_SIZE)
+ throw new IllegalArgumentException(Nodes.BAD_SIZE);
b = (size > 0) ? new SpinedBuffer.OfDouble((int) size) : new SpinedBuffer.OfDouble();
}
diff --git a/jdk/src/share/classes/java/util/stream/SpinedBuffer.java b/jdk/src/share/classes/java/util/stream/SpinedBuffer.java
index 7312c984a51..e7fac67510f 100644
--- a/jdk/src/share/classes/java/util/stream/SpinedBuffer.java
+++ b/jdk/src/share/classes/java/util/stream/SpinedBuffer.java
@@ -156,6 +156,9 @@ class SpinedBuffer
public E get(long index) {
// @@@ can further optimize by caching last seen spineIndex,
// which is going to be right most of the time
+
+ // Casts to int are safe since the spine array index is the index minus
+ // the prior element count from the current spine
if (spineIndex == 0) {
if (index < elementIndex)
return curChunk[((int) index)];
@@ -201,11 +204,11 @@ class SpinedBuffer
* elements into it.
*/
public E[] asArray(IntFunction arrayFactory) {
- // @@@ will fail for size == MAX_VALUE
- E[] result = arrayFactory.apply((int) count());
-
+ long size = count();
+ if (size >= Nodes.MAX_ARRAY_SIZE)
+ throw new IllegalArgumentException(Nodes.BAD_SIZE);
+ E[] result = arrayFactory.apply((int) size);
copyInto(result, 0);
-
return result;
}
@@ -547,8 +550,10 @@ class SpinedBuffer
}
public T_ARR asPrimitiveArray() {
- // @@@ will fail for size == MAX_VALUE
- T_ARR result = newArray((int) count());
+ long size = count();
+ if (size >= Nodes.MAX_ARRAY_SIZE)
+ throw new IllegalArgumentException(Nodes.BAD_SIZE);
+ T_ARR result = newArray((int) size);
copyInto(result, 0);
return result;
}
@@ -760,11 +765,13 @@ class SpinedBuffer
}
public int get(long index) {
+ // Casts to int are safe since the spine array index is the index minus
+ // the prior element count from the current spine
int ch = chunkFor(index);
if (spineIndex == 0 && ch == 0)
return curChunk[(int) index];
else
- return spine[ch][(int) (index-priorElementCount[ch])];
+ return spine[ch][(int) (index - priorElementCount[ch])];
}
@Override
@@ -871,11 +878,13 @@ class SpinedBuffer
}
public long get(long index) {
+ // Casts to int are safe since the spine array index is the index minus
+ // the prior element count from the current spine
int ch = chunkFor(index);
if (spineIndex == 0 && ch == 0)
return curChunk[(int) index];
else
- return spine[ch][(int) (index-priorElementCount[ch])];
+ return spine[ch][(int) (index - priorElementCount[ch])];
}
@Override
@@ -984,11 +993,13 @@ class SpinedBuffer
}
public double get(long index) {
+ // Casts to int are safe since the spine array index is the index minus
+ // the prior element count from the current spine
int ch = chunkFor(index);
if (spineIndex == 0 && ch == 0)
return curChunk[(int) index];
else
- return spine[ch][(int) (index-priorElementCount[ch])];
+ return spine[ch][(int) (index - priorElementCount[ch])];
}
@Override
diff --git a/jdk/src/share/classes/java/util/stream/Streams.java b/jdk/src/share/classes/java/util/stream/Streams.java
index 8af33f2b3c2..41f3adad592 100644
--- a/jdk/src/share/classes/java/util/stream/Streams.java
+++ b/jdk/src/share/classes/java/util/stream/Streams.java
@@ -169,7 +169,9 @@ final class Streams {
private int splitPoint(long size) {
int d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO;
- // 2 <= size <= 2^32
+ // Cast to int is safe since:
+ // 2 <= size < 2^32
+ // 2 <= d <= 8
return (int) (size / d);
}
}
diff --git a/jdk/src/share/classes/javax/imageio/plugins/bmp/BMPImageWriteParam.java b/jdk/src/share/classes/javax/imageio/plugins/bmp/BMPImageWriteParam.java
index de35f5fe11e..230f7203fc4 100644
--- a/jdk/src/share/classes/javax/imageio/plugins/bmp/BMPImageWriteParam.java
+++ b/jdk/src/share/classes/javax/imageio/plugins/bmp/BMPImageWriteParam.java
@@ -29,6 +29,7 @@ import java.util.Locale;
import javax.imageio.ImageWriteParam;
import com.sun.imageio.plugins.bmp.BMPConstants;
+import com.sun.imageio.plugins.bmp.BMPCompressionTypes;
/**
* A subclass of ImageWriteParam for encoding images in
@@ -78,7 +79,7 @@ public class BMPImageWriteParam extends ImageWriteParam {
super(locale);
// Set compression types ("BI_RGB" denotes uncompressed).
- compressionTypes = BMPConstants.compressionTypeNames.clone();
+ compressionTypes = BMPCompressionTypes.getCompressionTypes();
// Set compression flag.
canWriteCompressed = true;
diff --git a/jdk/src/share/classes/javax/management/Descriptor.java b/jdk/src/share/classes/javax/management/Descriptor.java
index 2337e2eb166..b07447ad590 100644
--- a/jdk/src/share/classes/javax/management/Descriptor.java
+++ b/jdk/src/share/classes/javax/management/Descriptor.java
@@ -319,7 +319,7 @@ import javax.management.openmbean.OpenType;
* {@code ModelMBeanOperationInfo}, as
* well as the chapter "Model MBeans" of the JMX
+ * href="http://www.oracle.com/technetwork/java/javase/tech/javamanagement-140525.html">JMX
* Specification. The following table summarizes these fields. Note
* that when the Type in this table is Number, a String that is the decimal
* representation of a Long can also be used.
diff --git a/jdk/src/share/classes/javax/print/Doc.java b/jdk/src/share/classes/javax/print/Doc.java
index 04d92d2e4a8..187873135a8 100644
--- a/jdk/src/share/classes/javax/print/Doc.java
+++ b/jdk/src/share/classes/javax/print/Doc.java
@@ -65,8 +65,8 @@ import javax.print.attribute.DocAttributeSet;
* representation object "consumes" the print data as the caller obtains the
* print data, such as a print data representation object which is a stream.
* Once the Print Job has called {@link #getPrintData()
- * getPrintData()} and obtained the stream, any further calls to
- * {@link #getPrintData() getPrintData()} will return the same
+ * getPrintData()} and obtained the stream, any further calls to
+ * {@link #getPrintData() getPrintData()} will return the same
* stream object upon which reading may already be in progress, not a new
* stream object that will re-read the print data from the beginning. Specifying
* a doc object to behave this way simplifies the implementation of doc objects,
@@ -83,7 +83,7 @@ import javax.print.attribute.DocAttributeSet;
* object is constructed. In this case the doc object might provide a "lazy"
* implementation that generates the print data representation object (and/or
* the print data) only when the Print Job calls for it (when the Print Job
- * calls the {@link #getPrintData() getPrintData()} method).
+ * calls the {@link #getPrintData() getPrintData()} method).
*
* There is no restriction on the number of client threads that may be
* simultaneously accessing the same doc. Therefore, all implementations of
diff --git a/jdk/src/share/classes/javax/print/DocFlavor.java b/jdk/src/share/classes/javax/print/DocFlavor.java
index 5b3f10c2486..c5d96af423e 100644
--- a/jdk/src/share/classes/javax/print/DocFlavor.java
+++ b/jdk/src/share/classes/javax/print/DocFlavor.java
@@ -53,7 +53,7 @@ import java.io.Serializable;
*
* Representation class name. This specifies the fully-qualified name of
* the class of the object from which the actual print data comes, as returned
- * by the {@link java.lang.Class#getName() Class.getName()} method.
+ * by the {@link java.lang.Class#getName() Class.getName()} method.
* (Thus the class name for byte[] is "[B", for
* char[] it is "[C".)
*
@@ -174,7 +174,7 @@ import java.io.Serializable;
* platform for data (eg files) stored in that platform's encoding.
* A CharSet which corresponds to this and is suitable for use in a
* mime-type for a DocFlavor can be obtained
- * from {@link DocFlavor#hostEncoding DocFlavor.hostEncoding}
+ * from {@link DocFlavor#hostEncoding DocFlavor.hostEncoding}
* This may not always be the primary IANA name but is guaranteed to be
* understood by this VM.
* For common flavors, the pre-defined *HOST DocFlavors may be used.
@@ -669,7 +669,7 @@ public class DocFlavor implements Serializable, Cloneable {
/**
* Doc flavor with MIME type = "text/plain",
* encoded in the host platform encoding.
- * See {@link DocFlavor#hostEncoding hostEncoding}
+ * See {@link DocFlavor#hostEncoding hostEncoding}
* Print data representation class name =
* "[B" (byte array).
*/
@@ -728,7 +728,7 @@ public class DocFlavor implements Serializable, Cloneable {
/**
* Doc flavor with MIME type = "text/html",
* encoded in the host platform encoding.
- * See {@link DocFlavor#hostEncoding hostEncoding}
+ * See {@link DocFlavor#hostEncoding hostEncoding}
* Print data representation class name =
* "[B" (byte array).
*/
@@ -838,7 +838,7 @@ public class DocFlavor implements Serializable, Cloneable {
/**
* Class DocFlavor.INPUT_STREAM provides predefined static constant
* DocFlavor objects for example doc flavors using a byte stream ({@link
- * java.io.InputStream java.io.InputStream}) as the print
+ * java.io.InputStream java.io.InputStream}) as the print
* data representation class.
*
*
@@ -868,7 +868,7 @@ public class DocFlavor implements Serializable, Cloneable {
/**
* Doc flavor with MIME type = "text/plain",
* encoded in the host platform encoding.
- * See {@link DocFlavor#hostEncoding hostEncoding}
+ * See {@link DocFlavor#hostEncoding hostEncoding}
* Print data representation class name =
* "java.io.InputStream" (byte stream).
*/
@@ -925,7 +925,7 @@ public class DocFlavor implements Serializable, Cloneable {
/**
* Doc flavor with MIME type = "text/html",
* encoded in the host platform encoding.
- * See {@link DocFlavor#hostEncoding hostEncoding}
+ * See {@link DocFlavor#hostEncoding hostEncoding}
* Print data representation class name =
* "java.io.InputStream" (byte stream).
*/
@@ -1041,7 +1041,7 @@ public class DocFlavor implements Serializable, Cloneable {
* Class DocFlavor.URL provides predefined static constant DocFlavor
* objects.
* For example doc flavors using a Uniform Resource Locator ({@link
- * java.net.URL java.net.URL}) as the print data
+ * java.net.URL java.net.URL}) as the print data
* representation class.
*
*
@@ -1068,7 +1068,7 @@ public class DocFlavor implements Serializable, Cloneable {
/**
* Doc flavor with MIME type = "text/plain",
* encoded in the host platform encoding.
- * See {@link DocFlavor#hostEncoding hostEncoding}
+ * See {@link DocFlavor#hostEncoding hostEncoding}
* Print data representation class name =
* "java.net.URL" (byte stream).
*/
@@ -1125,7 +1125,7 @@ public class DocFlavor implements Serializable, Cloneable {
/**
* Doc flavor with MIME type = "text/html",
* encoded in the host platform encoding.
- * See {@link DocFlavor#hostEncoding hostEncoding}
+ * See {@link DocFlavor#hostEncoding hostEncoding}
* Print data representation class name =
* "java.net.URL" (byte stream).
*/
@@ -1280,7 +1280,7 @@ public class DocFlavor implements Serializable, Cloneable {
/**
* Class DocFlavor.STRING provides predefined static constant DocFlavor
* objects for example doc flavors using a string ({@link java.lang.String
- * java.lang.String}) as the print data representation class.
+ * java.lang.String}) as the print data representation class.
* As such, the character set is Unicode.
*
*
@@ -1328,7 +1328,7 @@ public class DocFlavor implements Serializable, Cloneable {
/**
* Class DocFlavor.READER provides predefined static constant DocFlavor
* objects for example doc flavors using a character stream ({@link
- * java.io.Reader java.io.Reader}) as the print data
+ * java.io.Reader java.io.Reader}) as the print data
* representation class. As such, the character set is Unicode.
*
*
diff --git a/jdk/src/share/classes/javax/print/MultiDoc.java b/jdk/src/share/classes/javax/print/MultiDoc.java
index 69a1756d883..4813a59931b 100644
--- a/jdk/src/share/classes/javax/print/MultiDoc.java
+++ b/jdk/src/share/classes/javax/print/MultiDoc.java
@@ -39,9 +39,9 @@ import java.io.IOException;
* docs. A multidoc object is like a node in the linked list, containing the
* current doc in the list and a pointer to the next node (multidoc) in the
* list. The Print Job can call the multidoc's {@link #getDoc()
- * getDoc()} method to get the current doc. When it's ready to go
+ * getDoc()} method to get the current doc. When it's ready to go
* on to the next doc, the Print Job can call the multidoc's {@link #next()
- * next()} method to get the next multidoc, which contains the
+ * next()} method to get the next multidoc, which contains the
* next doc. So Print Job code for accessing a multidoc might look like this:
*
* void processMultiDoc(MultiDoc theMultiDoc) {
@@ -88,12 +88,12 @@ import java.io.IOException;
* multiple docs to a Print Job, every Print Service proxy that supports
* multidoc print jobs is required to access a MultiDoc object using the
* interleaved pattern. That is, given a MultiDoc object, the print service
- * proxy will call {@link #getDoc() getDoc()} one or more times
+ * proxy will call {@link #getDoc() getDoc()} one or more times
* until it successfully obtains the current Doc object. The print service proxy
* will then obtain the current doc's print data, not proceeding until all the
* print data is obtained or an unrecoverable error occurs. If it is able to
* continue, the print service proxy will then call {@link #next()
- * next()} one or more times until it successfully obtains either
+ * next()} one or more times until it successfully obtains either
* the next MultiDoc object or an indication that there are no more. An
* implementation of interface MultiDoc can assume the print service proxy will
* follow this interleaved pattern; for any other pattern of usage, the MultiDoc
diff --git a/jdk/src/share/classes/javax/print/attribute/standard/Finishings.java b/jdk/src/share/classes/javax/print/attribute/standard/Finishings.java
index 3f09cd9088f..65332e54e1c 100644
--- a/jdk/src/share/classes/javax/print/attribute/standard/Finishings.java
+++ b/jdk/src/share/classes/javax/print/attribute/standard/Finishings.java
@@ -42,16 +42,16 @@ import javax.print.attribute.PrintJobAttribute;
* Standard Finishings values are:
*
*
- * |
+ * |
*
* |
- *
+ * |
* {@link #NONE NONE}
* |
- *
+ * |
* {@link #STAPLE STAPLE}
* |
- *
+ * |
* {@link #EDGE_STITCH EDGE_STITCH}
* |
*
@@ -78,70 +78,70 @@ import javax.print.attribute.PrintJobAttribute;
* corner or an edge as if the document were a portrait document:
*
*
- * |
+ * |
*
* |
- *
+ * |
* {@link #STAPLE_TOP_LEFT STAPLE_TOP_LEFT}
* |
- *
+ * |
* {@link #EDGE_STITCH_LEFT EDGE_STITCH_LEFT}
* |
- *
+ * |
* {@link #STAPLE_DUAL_LEFT STAPLE_DUAL_LEFT}
* |
- *
+ * |
*
* |
*
*
- * |
+ * |
*
* |
- *
+ * |
* {@link #STAPLE_BOTTOM_LEFT STAPLE_BOTTOM_LEFT}
* |
- *
+ * |
* {@link #EDGE_STITCH_TOP EDGE_STITCH_TOP}
* |
- *
+ * |
* {@link #STAPLE_DUAL_TOP STAPLE_DUAL_TOP}
* |
- *
+ * |
*
* |
*
*
- * |
+ * |
*
* |
- *
+ * |
* {@link #STAPLE_TOP_RIGHT STAPLE_TOP_RIGHT}
* |
- *
+ * |
* {@link #EDGE_STITCH_RIGHT EDGE_STITCH_RIGHT}
* |
- *
+ * |
* {@link #STAPLE_DUAL_RIGHT STAPLE_DUAL_RIGHT}
* |
- *
+ * |
*
* |
*
*
- * |
+ * |
*
* |
- *
+ * |
* {@link #STAPLE_BOTTOM_RIGHT STAPLE_BOTTOM_RIGHT}
* |
- *
+ * |
* {@link #EDGE_STITCH_BOTTOM EDGE_STITCH_BOTTOM}
* |
- *
+ * |
* {@link #STAPLE_DUAL_BOTTOM STAPLE_DUAL_BOTTOM}
* |
- *
+ * |
*
* |
*
diff --git a/jdk/src/share/classes/javax/print/attribute/standard/JobStateReasons.java b/jdk/src/share/classes/javax/print/attribute/standard/JobStateReasons.java
index 9cb104b5c11..d9e225f621f 100644
--- a/jdk/src/share/classes/javax/print/attribute/standard/JobStateReasons.java
+++ b/jdk/src/share/classes/javax/print/attribute/standard/JobStateReasons.java
@@ -110,7 +110,7 @@ public final class JobStateReasons
* The underlying hash set's initial capacity and load factor are as
* specified in the superclass constructor {@link
* java.util.HashSet#HashSet(java.util.Collection)
- * HashSet(Collection)}.
+ * HashSet(Collection)}.
*
* @param collection Collection to copy.
*
diff --git a/jdk/src/share/classes/javax/print/attribute/standard/MediaPrintableArea.java b/jdk/src/share/classes/javax/print/attribute/standard/MediaPrintableArea.java
index a800f7c6c42..9f33f054e77 100644
--- a/jdk/src/share/classes/javax/print/attribute/standard/MediaPrintableArea.java
+++ b/jdk/src/share/classes/javax/print/attribute/standard/MediaPrintableArea.java
@@ -56,7 +56,7 @@ import javax.print.attribute.PrintRequestAttribute;
* any specified finishings.
* PrintService provides the method to query the supported
* values of an attribute in a suitable context :
- * See {@link javax.print.PrintService#getSupportedAttributeValues(Class,DocFlavor, AttributeSet) PrintService.getSupportedAttributeValues()}
+ * See {@link javax.print.PrintService#getSupportedAttributeValues(Class,DocFlavor, AttributeSet) PrintService.getSupportedAttributeValues()}
*
* The rectangular printable area is defined thus:
* The (x,y) origin is positioned at the top-left of the paper in portrait
@@ -153,8 +153,8 @@ public final class MediaPrintableArea
* Get the printable area as an array of 4 values in the order
* x, y, w, h. The values returned are in the given units.
* @param units
- * Unit conversion factor, e.g. {@link #INCH INCH} or
- * {@link #MM MM}.
+ * Unit conversion factor, e.g. {@link #INCH INCH} or
+ * {@link #MM MM}.
*
* @return printable area as array of x, y, w, h in the specified units.
*
@@ -170,8 +170,8 @@ public final class MediaPrintableArea
* Get the x location of the origin of the printable area in the
* specified units.
* @param units
- * Unit conversion factor, e.g. {@link #INCH INCH} or
- * {@link #MM MM}.
+ * Unit conversion factor, e.g. {@link #INCH INCH} or
+ * {@link #MM MM}.
*
* @return x location of the origin of the printable area in the
* specified units.
@@ -187,8 +187,8 @@ public final class MediaPrintableArea
* Get the y location of the origin of the printable area in the
* specified units.
* @param units
- * Unit conversion factor, e.g. {@link #INCH INCH} or
- * {@link #MM MM}.
+ * Unit conversion factor, e.g. {@link #INCH INCH} or
+ * {@link #MM MM}.
*
* @return y location of the origin of the printable area in the
* specified units.
@@ -203,8 +203,8 @@ public final class MediaPrintableArea
/**
* Get the width of the printable area in the specified units.
* @param units
- * Unit conversion factor, e.g. {@link #INCH INCH} or
- * {@link #MM MM}.
+ * Unit conversion factor, e.g. {@link #INCH INCH} or
+ * {@link #MM MM}.
*
* @return width of the printable area in the specified units.
*
@@ -218,8 +218,8 @@ public final class MediaPrintableArea
/**
* Get the height of the printable area in the specified units.
* @param units
- * Unit conversion factor, e.g. {@link #INCH INCH} or
- * {@link #MM MM}.
+ * Unit conversion factor, e.g. {@link #INCH INCH} or
+ * {@link #MM MM}.
*
* @return height of the printable area in the specified units.
*
@@ -292,8 +292,8 @@ public final class MediaPrintableArea
* given units.
*
* @param units
- * Unit conversion factor, e.g. {@link #INCH INCH} or
- * {@link #MM MM}.
+ * Unit conversion factor, e.g. {@link #INCH INCH} or
+ * {@link #MM MM}.
* @param unitsName
* Units name string, e.g. "in" or "mm". If
* null, no units name is appended to the result.
diff --git a/jdk/src/share/classes/javax/print/attribute/standard/MultipleDocumentHandling.java b/jdk/src/share/classes/javax/print/attribute/standard/MultipleDocumentHandling.java
index 6c43fd6f5e9..30f4fe0a5f0 100644
--- a/jdk/src/share/classes/javax/print/attribute/standard/MultipleDocumentHandling.java
+++ b/jdk/src/share/classes/javax/print/attribute/standard/MultipleDocumentHandling.java
@@ -71,7 +71,7 @@ import javax.print.attribute.PrintJobAttribute;
*
* -
* {@link #SINGLE_DOCUMENT
- *
SINGLE_DOCUMENT}. If a print job has multiple
+ * SINGLE_DOCUMENT}. If a print job has multiple
* documents -- say, the document data is called a and
* b -- then the result of processing all the document data
* (a and then b) must be treated as a single sequence
@@ -86,7 +86,7 @@ import javax.print.attribute.PrintJobAttribute;
*
*
-
* {@link #SEPARATE_DOCUMENTS_UNCOLLATED_COPIES
- *
SEPARATE_DOCUMENTS_UNCOLLATED_COPIES}. If a print job
+ * SEPARATE_DOCUMENTS_UNCOLLATED_COPIES}. If a print job
* has multiple documents -- say, the document data is called a and
* b -- then the result of processing the data in each document
* instance must be treated as a single sequence of media sheets for finishing
@@ -99,7 +99,7 @@ import javax.print.attribute.PrintJobAttribute;
*
*
-
* {@link #SEPARATE_DOCUMENTS_COLLATED_COPIES
- *
SEPARATE_DOCUMENTS_COLLATED_COPIES}. If a print job
+ * SEPARATE_DOCUMENTS_COLLATED_COPIES}. If a print job
* has multiple documents -- say, the document data is called a and
* b -- then the result of processing the data in each document
* instance must be treated as a single sequence of media sheets for finishing
@@ -112,7 +112,7 @@ import javax.print.attribute.PrintJobAttribute;
*
*
-
* {@link #SINGLE_DOCUMENT_NEW_SHEET
- *
SINGLE_DOCUMENT_NEW_SHEET}. Same as SINGLE_DOCUMENT,
+ * SINGLE_DOCUMENT_NEW_SHEET}. Same as SINGLE_DOCUMENT,
* except that the printer must ensure that the first impression of each
* document instance in the job is placed on a new media sheet. This value
* allows multiple documents to be stapled together with a single staple where
@@ -127,7 +127,7 @@ import javax.print.attribute.PrintJobAttribute;
* next document or document copy on to a new sheet.
*
* In addition, if a {@link Finishings Finishings} attribute of
- * {@link Finishings#STAPLE STAPLE} is specified, then:
+ * {@link Finishings#STAPLE STAPLE} is specified, then:
*
* -
* With SINGLE_DOCUMENT, documents
a and b are
diff --git a/jdk/src/share/classes/javax/print/attribute/standard/PrinterStateReasons.java b/jdk/src/share/classes/javax/print/attribute/standard/PrinterStateReasons.java
index 48707636f77..52758fadd0d 100644
--- a/jdk/src/share/classes/javax/print/attribute/standard/PrinterStateReasons.java
+++ b/jdk/src/share/classes/javax/print/attribute/standard/PrinterStateReasons.java
@@ -129,7 +129,7 @@ public final class PrinterStateReasons
* Severity} mappings as the given map. The underlying hash map's initial
* capacity and load factor are as specified in the superclass constructor
* {@link java.util.HashMap#HashMap(java.util.Map)
- * HashMap(Map)}.
+ * HashMap(Map)}.
*
* @param map Map to copy.
*
diff --git a/jdk/src/share/classes/javax/print/attribute/standard/Sides.java b/jdk/src/share/classes/javax/print/attribute/standard/Sides.java
index eaff96b2eb6..93fed683e51 100644
--- a/jdk/src/share/classes/javax/print/attribute/standard/Sides.java
+++ b/jdk/src/share/classes/javax/print/attribute/standard/Sides.java
@@ -134,7 +134,7 @@ public final class Sides extends EnumSyntax
* sides of consecutive media sheets, such that the orientation of each
* pair of print-stream pages on the medium would be correct for the
* reader as if for binding on the long edge. This imposition is also
- * known as "duplex" (see {@link #DUPLEX DUPLEX}).
+ * known as "duplex" (see {@link #DUPLEX DUPLEX}).
*/
public static final Sides TWO_SIDED_LONG_EDGE = new Sides(1);
@@ -143,19 +143,19 @@ public final class Sides extends EnumSyntax
* sides of consecutive media sheets, such that the orientation of each
* pair of print-stream pages on the medium would be correct for the
* reader as if for binding on the short edge. This imposition is also
- * known as "tumble" (see {@link #TUMBLE TUMBLE}).
+ * known as "tumble" (see {@link #TUMBLE TUMBLE}).
*/
public static final Sides TWO_SIDED_SHORT_EDGE = new Sides(2);
/**
* An alias for "two sided long edge" (see {@link #TWO_SIDED_LONG_EDGE
- * TWO_SIDED_LONG_EDGE}).
+ * TWO_SIDED_LONG_EDGE}).
*/
public static final Sides DUPLEX = TWO_SIDED_LONG_EDGE;
/**
* An alias for "two sided short edge" (see {@link #TWO_SIDED_SHORT_EDGE
- * TWO_SIDED_SHORT_EDGE}).
+ * TWO_SIDED_SHORT_EDGE}).
*/
public static final Sides TUMBLE = TWO_SIDED_SHORT_EDGE;
diff --git a/jdk/src/share/classes/javax/swing/AbstractAction.java b/jdk/src/share/classes/javax/swing/AbstractAction.java
index 1d55a949e72..5b49dd92c91 100644
--- a/jdk/src/share/classes/javax/swing/AbstractAction.java
+++ b/jdk/src/share/classes/javax/swing/AbstractAction.java
@@ -49,7 +49,7 @@ import sun.security.action.GetPropertyAction;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/AbstractButton.java b/jdk/src/share/classes/javax/swing/AbstractButton.java
index b8612f1280a..193317c99ac 100644
--- a/jdk/src/share/classes/javax/swing/AbstractButton.java
+++ b/jdk/src/share/classes/javax/swing/AbstractButton.java
@@ -53,12 +53,12 @@ import java.util.*;
* configuring a button. Refer to
* Swing Components Supporting Action for more
* details, and you can find more information in How
+ * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions, a section in The Java Tutorial.
*
* For further information see
* How to Use Buttons, Check Boxes, and Radio Buttons,
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/button.html">How to Use Buttons, Check Boxes, and Radio Buttons,
* a section in The Java Tutorial.
*
* Warning:
@@ -66,7 +66,7 @@ import java.util.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -1973,7 +1973,7 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
@@ -2379,7 +2379,7 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
* @since 1.4
diff --git a/jdk/src/share/classes/javax/swing/AbstractCellEditor.java b/jdk/src/share/classes/javax/swing/AbstractCellEditor.java
index 17ce6d26e01..f9efea555dc 100644
--- a/jdk/src/share/classes/javax/swing/AbstractCellEditor.java
+++ b/jdk/src/share/classes/javax/swing/AbstractCellEditor.java
@@ -43,7 +43,7 @@ import java.io.Serializable;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/AbstractListModel.java b/jdk/src/share/classes/javax/swing/AbstractListModel.java
index 9200102bc34..7270c8f222c 100644
--- a/jdk/src/share/classes/javax/swing/AbstractListModel.java
+++ b/jdk/src/share/classes/javax/swing/AbstractListModel.java
@@ -38,7 +38,7 @@ import java.util.EventListener;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/BorderFactory.java b/jdk/src/share/classes/javax/swing/BorderFactory.java
index 33b1b0024d9..1a1e4ab3b0e 100644
--- a/jdk/src/share/classes/javax/swing/BorderFactory.java
+++ b/jdk/src/share/classes/javax/swing/BorderFactory.java
@@ -35,7 +35,7 @@ import javax.swing.border.*;
* possible, this factory will hand out references to shared
* Border instances.
* For further information and examples see
- * How
+ * How
to Use Borders,
* a section in The Java Tutorial.
*
diff --git a/jdk/src/share/classes/javax/swing/BoundedRangeModel.java b/jdk/src/share/classes/javax/swing/BoundedRangeModel.java
index 3d077fcd1f7..c8348b9ca26 100644
--- a/jdk/src/share/classes/javax/swing/BoundedRangeModel.java
+++ b/jdk/src/share/classes/javax/swing/BoundedRangeModel.java
@@ -71,8 +71,8 @@ import javax.swing.event.*;
*
* For an example of specifying custom bounded range models used by sliders,
* see The Anatomy of a Swing-Based Program
- * in The Java Tutorial.
+ href="http://www.oracle.com/technetwork/java/architecture-142923.html#separable">Separable model architecture
+ * in A Swing Architecture Overview.
*
* @author Hans Muller
* @see DefaultBoundedRangeModel
diff --git a/jdk/src/share/classes/javax/swing/Box.java b/jdk/src/share/classes/javax/swing/Box.java
index d1c132364b6..2f4c6e4c76f 100644
--- a/jdk/src/share/classes/javax/swing/Box.java
+++ b/jdk/src/share/classes/javax/swing/Box.java
@@ -60,7 +60,7 @@ import javax.accessibility.*;
* If you are implementing a BoxLayout you
* can find further information and examples in
* How to Use BoxLayout,
+ href="http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html">How to Use BoxLayout,
* a section in The Java Tutorial.
*
* Warning:
@@ -68,7 +68,7 @@ import javax.accessibility.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -298,7 +298,7 @@ public class Box extends JComponent implements Accessible {
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/BoxLayout.java b/jdk/src/share/classes/javax/swing/BoxLayout.java
index de1703d5b76..abe4b73201f 100644
--- a/jdk/src/share/classes/javax/swing/BoxLayout.java
+++ b/jdk/src/share/classes/javax/swing/BoxLayout.java
@@ -36,12 +36,12 @@ import java.io.PrintStream;
* vertically or horizontally. The components will not wrap so, for
* example, a vertical arrangement of components will stay vertically
* arranged when the frame is resized.
- *
+ *
*
* |
- * 
+ * WIDTH="191" HEIGHT="201" STYLE="FLOAT:BOTTOM; BORDER:0">
*
|
*
*
@@ -116,7 +116,7 @@ import java.io.PrintStream;
*
* For further information and examples see
* How to Use BoxLayout,
+ href="http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html">How to Use BoxLayout,
* a section in The Java Tutorial.
*
* Warning:
@@ -124,7 +124,7 @@ import java.io.PrintStream;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/ButtonGroup.java b/jdk/src/share/classes/javax/swing/ButtonGroup.java
index c2971f722e4..7f6229d485e 100644
--- a/jdk/src/share/classes/javax/swing/ButtonGroup.java
+++ b/jdk/src/share/classes/javax/swing/ButtonGroup.java
@@ -51,7 +51,7 @@ import java.io.Serializable;
* Initially, all buttons in the group are unselected.
*
* For examples and further information on using button groups see
- * How to Use Radio Buttons,
+ * How to Use Radio Buttons,
* a section in The Java Tutorial.
*
* Warning:
@@ -59,7 +59,7 @@ import java.io.Serializable;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/CellRendererPane.java b/jdk/src/share/classes/javax/swing/CellRendererPane.java
index 7523ef0698b..6a9f17b058a 100644
--- a/jdk/src/share/classes/javax/swing/CellRendererPane.java
+++ b/jdk/src/share/classes/javax/swing/CellRendererPane.java
@@ -57,7 +57,7 @@ import javax.accessibility.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/DefaultBoundedRangeModel.java b/jdk/src/share/classes/javax/swing/DefaultBoundedRangeModel.java
index 418adf48c03..fb250acbcda 100644
--- a/jdk/src/share/classes/javax/swing/DefaultBoundedRangeModel.java
+++ b/jdk/src/share/classes/javax/swing/DefaultBoundedRangeModel.java
@@ -37,7 +37,7 @@ import java.util.EventListener;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/DefaultButtonModel.java b/jdk/src/share/classes/javax/swing/DefaultButtonModel.java
index 5eaec14f9e9..7c0fa3d2181 100644
--- a/jdk/src/share/classes/javax/swing/DefaultButtonModel.java
+++ b/jdk/src/share/classes/javax/swing/DefaultButtonModel.java
@@ -39,7 +39,7 @@ import javax.swing.event.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/DefaultCellEditor.java b/jdk/src/share/classes/javax/swing/DefaultCellEditor.java
index 1738e0e69b7..60042a378ef 100644
--- a/jdk/src/share/classes/javax/swing/DefaultCellEditor.java
+++ b/jdk/src/share/classes/javax/swing/DefaultCellEditor.java
@@ -43,7 +43,7 @@ import java.io.Serializable;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/DefaultFocusManager.java b/jdk/src/share/classes/javax/swing/DefaultFocusManager.java
index 91304aafbd8..4ebc54a9090 100644
--- a/jdk/src/share/classes/javax/swing/DefaultFocusManager.java
+++ b/jdk/src/share/classes/javax/swing/DefaultFocusManager.java
@@ -37,7 +37,7 @@ import java.util.Comparator;
* java.awt.DefaultKeyboardFocusManager instead.
*
* Please see
- *
+ *
* How to Use the Focus Subsystem,
* a section in The Java Tutorial, and the
* Focus Specification
diff --git a/jdk/src/share/classes/javax/swing/DefaultListCellRenderer.java b/jdk/src/share/classes/javax/swing/DefaultListCellRenderer.java
index 85a10e28f14..4d7a64909e1 100644
--- a/jdk/src/share/classes/javax/swing/DefaultListCellRenderer.java
+++ b/jdk/src/share/classes/javax/swing/DefaultListCellRenderer.java
@@ -63,7 +63,7 @@ import sun.swing.DefaultLookup;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -337,7 +337,7 @@ public class DefaultListCellRenderer extends JLabel
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/DefaultListModel.java b/jdk/src/share/classes/javax/swing/DefaultListModel.java
index 5fc23eaf0cd..33efc4abe32 100644
--- a/jdk/src/share/classes/javax/swing/DefaultListModel.java
+++ b/jdk/src/share/classes/javax/swing/DefaultListModel.java
@@ -44,7 +44,7 @@ import javax.swing.event.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/DefaultListSelectionModel.java b/jdk/src/share/classes/javax/swing/DefaultListSelectionModel.java
index 57fb5d776db..8da0b4254a8 100644
--- a/jdk/src/share/classes/javax/swing/DefaultListSelectionModel.java
+++ b/jdk/src/share/classes/javax/swing/DefaultListSelectionModel.java
@@ -41,7 +41,7 @@ import javax.swing.event.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/DefaultSingleSelectionModel.java b/jdk/src/share/classes/javax/swing/DefaultSingleSelectionModel.java
index 65b33204207..1d5ad7ccac0 100644
--- a/jdk/src/share/classes/javax/swing/DefaultSingleSelectionModel.java
+++ b/jdk/src/share/classes/javax/swing/DefaultSingleSelectionModel.java
@@ -37,7 +37,7 @@ import java.util.EventListener;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/FocusManager.java b/jdk/src/share/classes/javax/swing/FocusManager.java
index 6afb84f61eb..554a1553190 100644
--- a/jdk/src/share/classes/javax/swing/FocusManager.java
+++ b/jdk/src/share/classes/javax/swing/FocusManager.java
@@ -34,7 +34,7 @@ import java.awt.*;
* java.awt.DefaultKeyboardFocusManager instead.
*
* Please see
- *
+ *
* How to Use the Focus Subsystem,
* a section in The Java Tutorial, and the
* Focus Specification
diff --git a/jdk/src/share/classes/javax/swing/ImageIcon.java b/jdk/src/share/classes/javax/swing/ImageIcon.java
index b16a62fe6b3..236d682d9a8 100644
--- a/jdk/src/share/classes/javax/swing/ImageIcon.java
+++ b/jdk/src/share/classes/javax/swing/ImageIcon.java
@@ -50,7 +50,7 @@ import java.security.*;
*
*
* For further information and examples of using image icons, see
- * How to Use Icons
+ * How to Use Icons
* in The Java Tutorial.
*
*
@@ -59,7 +59,7 @@ import java.security.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -555,7 +555,7 @@ public class ImageIcon implements Icon, Serializable, Accessible {
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
* @since 1.3
diff --git a/jdk/src/share/classes/javax/swing/JApplet.java b/jdk/src/share/classes/javax/swing/JApplet.java
index 0da6c3e532a..acb02035420 100644
--- a/jdk/src/share/classes/javax/swing/JApplet.java
+++ b/jdk/src/share/classes/javax/swing/JApplet.java
@@ -40,7 +40,7 @@ import javax.accessibility.*;
* in The Java Tutorial,
* in the section
* How to Make Applets.
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/applet.html">How to Make Applets.
*
* The JApplet class is slightly incompatible with
* java.applet.Applet. JApplet contains a
@@ -77,7 +77,7 @@ import javax.accessibility.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -183,7 +183,7 @@ public class JApplet extends Applet implements Accessible,
* are currently typed to {@code JComponent}.
*
* Please see
- *
+ *
* How to Use Drag and Drop and Data Transfer, a section in
* The Java Tutorial, for more information.
*
diff --git a/jdk/src/share/classes/javax/swing/JButton.java b/jdk/src/share/classes/javax/swing/JButton.java
index 45e8757315c..0e97ba8dd44 100644
--- a/jdk/src/share/classes/javax/swing/JButton.java
+++ b/jdk/src/share/classes/javax/swing/JButton.java
@@ -48,10 +48,10 @@ import java.io.IOException;
* configuring a button. Refer to
* Swing Components Supporting Action for more
* details, and you can find more information in How
+ * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions, a section in The Java Tutorial.
*
- * See How to Use Buttons, Check Boxes, and Radio Buttons
+ * See How to Use Buttons, Check Boxes, and Radio Buttons
* in The Java Tutorial
* for information and examples of using buttons.
*
@@ -65,7 +65,7 @@ import java.io.IOException;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -304,7 +304,7 @@ public class JButton extends AbstractButton implements Accessible {
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JCheckBox.java b/jdk/src/share/classes/javax/swing/JCheckBox.java
index 4d80e9549c6..8fdbd17fa04 100644
--- a/jdk/src/share/classes/javax/swing/JCheckBox.java
+++ b/jdk/src/share/classes/javax/swing/JCheckBox.java
@@ -40,7 +40,7 @@ import java.io.IOException;
* An implementation of a check box -- an item that can be selected or
* deselected, and which displays its state to the user.
* By convention, any number of check boxes in a group can be selected.
- * See How to Use Buttons, Check Boxes, and Radio Buttons
+ * See How to Use Buttons, Check Boxes, and Radio Buttons
* in The Java Tutorial
* for examples and information on using check boxes.
*
@@ -50,7 +50,7 @@ import java.io.IOException;
* configuring a button. Refer to
* Swing Components Supporting Action for more
* details, and you can find more information in How
+ * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions, a section in The Java Tutorial.
*
* Warning: Swing is not thread safe. For more
@@ -63,7 +63,7 @@ import java.io.IOException;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -330,7 +330,7 @@ public class JCheckBox extends JToggleButton implements Accessible {
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JCheckBoxMenuItem.java b/jdk/src/share/classes/javax/swing/JCheckBoxMenuItem.java
index 8b42b729f14..3d924d38536 100644
--- a/jdk/src/share/classes/javax/swing/JCheckBoxMenuItem.java
+++ b/jdk/src/share/classes/javax/swing/JCheckBoxMenuItem.java
@@ -59,12 +59,12 @@ import javax.accessibility.*;
* configuring a menu item. Refer to
* Swing Components Supporting Action for more
* details, and you can find more information in How
+ * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions, a section in The Java Tutorial.
*
* For further information and examples of using check box menu items,
* see How to Use Menus,
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html">How to Use Menus,
* a section in The Java Tutorial.
*
* Warning: Swing is not thread safe. For more
@@ -77,7 +77,7 @@ import javax.accessibility.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -289,7 +289,7 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JColorChooser.java b/jdk/src/share/classes/javax/swing/JColorChooser.java
index eb3aff69a5c..9fb2a35a778 100644
--- a/jdk/src/share/classes/javax/swing/JColorChooser.java
+++ b/jdk/src/share/classes/javax/swing/JColorChooser.java
@@ -42,7 +42,7 @@ import sun.swing.SwingUtilities2;
* a user to manipulate and select a color.
* For information about using color choosers, see
* How to Use Color Choosers,
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/colorchooser.html">How to Use Color Choosers,
* a section in The Java Tutorial.
*
*
@@ -69,7 +69,7 @@ import sun.swing.SwingUtilities2;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/JComboBox.java b/jdk/src/share/classes/javax/swing/JComboBox.java
index ba3bb8abb1d..2d81a18a1d0 100644
--- a/jdk/src/share/classes/javax/swing/JComboBox.java
+++ b/jdk/src/share/classes/javax/swing/JComboBox.java
@@ -57,13 +57,13 @@ import javax.accessibility.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
*
- * See How to Use Combo Boxes
- * in The Java Tutorial
+ * See How to Use Combo Boxes
+ * in The Java Tutorial
* for further information.
*
* @see ComboBoxModel
@@ -350,9 +350,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* by the look and feel. Some look and feels always use
* heavyweight popups, no matter what the value of this property.
*
- * See the article Mixing Heavy and Light Components
- * on
- * The Swing Connection
+ * See the article Mixing Heavy and Light Components
* This method fires a property changed event.
*
* @param aFlag if true, lightweight popups are desired
@@ -1610,7 +1608,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible {
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JComponent.java b/jdk/src/share/classes/javax/swing/JComponent.java
index 13576590a39..a15ec705655 100644
--- a/jdk/src/share/classes/javax/swing/JComponent.java
+++ b/jdk/src/share/classes/javax/swing/JComponent.java
@@ -78,7 +78,7 @@ import sun.swing.UIClientPropertyKey;
* that provide a place for other Swing components to paint themselves.
* For an explanation of containment hierarchies, see
* Swing Components and the Containment Hierarchy,
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html">Swing Components and the Containment Hierarchy,
* a section in The Java Tutorial.
*
*
@@ -92,21 +92,20 @@ import sun.swing.UIClientPropertyKey;
* UI delegate -- an object that descends from
* {@link javax.swing.plaf.ComponentUI}.
* See How
+ * href="http://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html">How
* to Set the Look and Feel
* in The Java Tutorial
* for more information.
*
- Comprehensive keystroke handling.
* See the document Keyboard
- * Bindings in Swing,
- * an article in The Swing Connection,
+ * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html">How to Use Key Bindings,
+ * an article in The Java Tutorial,
* for more information.
*
- Support for tool tips --
* short descriptions that pop up when the cursor lingers
* over a component.
* See How
+ * href="http://docs.oracle.com/javase/tutorial/uiswing/components/tooltip.html">How
* to Use Tool Tips
* in The Java Tutorial
* for more information.
@@ -124,15 +123,15 @@ import sun.swing.UIClientPropertyKey;
*
- An infrastructure for painting
* that includes double buffering and support for borders.
* For more information see Painting and
- * How
+ * href="http://www.oracle.com/technetwork/java/painting-140037.html#swing">Painting and
+ * How
* to Use Borders,
* both of which are sections in The Java Tutorial.
*
* For more information on these subjects, see the
* Swing package description
* and The Java Tutorial section
- * The JComponent Class.
+ * The JComponent Class.
*
* JComponent and its subclasses document default values
* for certain properties. For example, JTable documents the
@@ -150,7 +149,7 @@ import sun.swing.UIClientPropertyKey;
*
* In release 1.4, the focus subsystem was rearchitected.
* For more information, see
- *
+ *
* How to Use the Focus Subsystem,
* a section in The Java Tutorial.
*
@@ -164,7 +163,7 @@ import sun.swing.UIClientPropertyKey;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -1291,7 +1290,7 @@ public abstract class JComponent extends Container implements Serializable,
/**
* In release 1.4, the focus subsystem was rearchitected.
* For more information, see
- *
+ *
* How to Use the Focus Subsystem,
* a section in The Java Tutorial.
*
@@ -1353,7 +1352,7 @@ public abstract class JComponent extends Container implements Serializable,
/**
* In release 1.4, the focus subsystem was rearchitected.
* For more information, see
- *
+ *
* How to Use the Focus Subsystem,
* a section in The Java Tutorial.
*
@@ -1386,7 +1385,7 @@ public abstract class JComponent extends Container implements Serializable,
/**
* In release 1.4, the focus subsystem was rearchitected.
* For more information, see
- *
+ *
* How to Use the Focus Subsystem,
* a section in The Java Tutorial.
*
@@ -1419,7 +1418,7 @@ public abstract class JComponent extends Container implements Serializable,
* all, use the setFocusable method instead.
*
* Please see
- *
+ *
* How to Use the Focus Subsystem,
* a section in The Java Tutorial,
* for more information.
@@ -1438,7 +1437,7 @@ public abstract class JComponent extends Container implements Serializable,
* get focus; otherwise returns false.
*
* Please see
- *
+ *
* How to Use the Focus Subsystem,
* a section in The Java Tutorial,
* for more information.
@@ -1464,7 +1463,7 @@ public abstract class JComponent extends Container implements Serializable,
* its behavior is platform dependent. Instead we recommend the
* use of {@link #requestFocusInWindow() requestFocusInWindow()}.
* If you would like more information on focus, see
- *
+ *
* How to Use the Focus Subsystem,
* a section in The Java Tutorial.
*
@@ -1487,7 +1486,7 @@ public abstract class JComponent extends Container implements Serializable,
* use of {@link #requestFocusInWindow(boolean)
* requestFocusInWindow(boolean)}.
* If you would like more information on focus, see
- *
+ *
* How to Use the Focus Subsystem,
* a section in The Java Tutorial.
*
@@ -1509,7 +1508,7 @@ public abstract class JComponent extends Container implements Serializable,
* this method.
*
* If you would like more information on focus, see
- *
+ *
* How to Use the Focus Subsystem,
* a section in The Java Tutorial.
*
@@ -1530,7 +1529,7 @@ public abstract class JComponent extends Container implements Serializable,
* this method.
*
* If you would like more information on focus, see
- *
+ *
* How to Use the Focus Subsystem,
* a section in The Java Tutorial.
*
@@ -2595,7 +2594,7 @@ public abstract class JComponent extends Container implements Serializable,
/**
* In release 1.4, the focus subsystem was rearchitected.
* For more information, see
- *
+ *
* How to Use the Focus Subsystem,
* a section in The Java Tutorial.
*
@@ -2986,7 +2985,7 @@ public abstract class JComponent extends Container implements Serializable,
* Registers the text to display in a tool tip.
* The text displays when the cursor lingers over the component.
*
- * See How to Use Tool Tips
+ * See How to Use Tool Tips
* in The Java Tutorial
* for further documentation.
*
@@ -3206,7 +3205,7 @@ public abstract class JComponent extends Container implements Serializable,
* default value for the system property is {@code false}.
*
* Please see
- *
+ *
* How to Use Drag and Drop and Data Transfer,
* a section in The Java Tutorial, for more information.
*
@@ -3654,7 +3653,7 @@ public abstract class JComponent extends Container implements Serializable,
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JDesktopPane.java b/jdk/src/share/classes/javax/swing/JDesktopPane.java
index 8d5342f47cb..6ba0bc82bf2 100644
--- a/jdk/src/share/classes/javax/swing/JDesktopPane.java
+++ b/jdk/src/share/classes/javax/swing/JDesktopPane.java
@@ -63,7 +63,7 @@ import java.util.TreeSet;
* (closing, resizing, etc).
*
* For further documentation and examples see
- * How to Use Internal Frames,
+ * How to Use Internal Frames,
* a section in The Java Tutorial.
*
* Warning: Swing is not thread safe. For more
@@ -76,7 +76,7 @@ import java.util.TreeSet;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -612,7 +612,7 @@ public class JDesktopPane extends JLayeredPane implements Accessible
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JDialog.java b/jdk/src/share/classes/javax/swing/JDialog.java
index a53c4abe50c..2e4b2b72efd 100644
--- a/jdk/src/share/classes/javax/swing/JDialog.java
+++ b/jdk/src/share/classes/javax/swing/JDialog.java
@@ -35,7 +35,7 @@ import javax.accessibility.*;
* For information about creating dialogs, see
* The Java Tutorial section
* How
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html">How
* to Make Dialogs.
*
*
@@ -77,7 +77,7 @@ import javax.accessibility.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the {@code java.beans} package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -786,7 +786,7 @@ public class JDialog extends Dialog implements WindowConstants,
* are currently typed to {@code JComponent}.
*
* Please see
- *
+ *
* How to Use Drag and Drop and Data Transfer, a section in
* The Java Tutorial, for more information.
*
diff --git a/jdk/src/share/classes/javax/swing/JEditorPane.java b/jdk/src/share/classes/javax/swing/JEditorPane.java
index fa9aeb0aa20..f4c5893068c 100644
--- a/jdk/src/share/classes/javax/swing/JEditorPane.java
+++ b/jdk/src/share/classes/javax/swing/JEditorPane.java
@@ -43,7 +43,7 @@ import javax.accessibility.*;
/**
* A text component to edit various kinds of content.
* You can find how-to information and examples of using editor panes in
- * Using Text Components,
+ * Using Text Components,
* a section in The Java Tutorial.
*
*
@@ -179,7 +179,7 @@ import javax.accessibility.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -1636,7 +1636,7 @@ public class JEditorPane extends JTextComponent {
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
@@ -1690,7 +1690,7 @@ public class JEditorPane extends JTextComponent {
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JFileChooser.java b/jdk/src/share/classes/javax/swing/JFileChooser.java
index 61806b439b8..5f897e3ed9a 100644
--- a/jdk/src/share/classes/javax/swing/JFileChooser.java
+++ b/jdk/src/share/classes/javax/swing/JFileChooser.java
@@ -57,7 +57,7 @@ import java.lang.ref.WeakReference;
* choose a file.
* For information about using JFileChooser, see
* How to Use File Choosers,
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/filechooser.html">How to Use File Choosers,
* a section in The Java Tutorial.
*
*
diff --git a/jdk/src/share/classes/javax/swing/JFormattedTextField.java b/jdk/src/share/classes/javax/swing/JFormattedTextField.java
index 31f4017d026..e682c571e51 100644
--- a/jdk/src/share/classes/javax/swing/JFormattedTextField.java
+++ b/jdk/src/share/classes/javax/swing/JFormattedTextField.java
@@ -54,7 +54,7 @@ import javax.swing.text.*;
* configuring what action should be taken when focus is lost. The possible
* configurations are:
*
- * Value | Description |
+ * Value | Description |
* | JFormattedTextField.REVERT
* | Revert the display to match that of getValue,
* possibly losing the current edit.
@@ -171,7 +171,7 @@ import javax.swing.text.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/JFrame.java b/jdk/src/share/classes/javax/swing/JFrame.java
index aee994eecf9..038c63b122a 100644
--- a/jdk/src/share/classes/javax/swing/JFrame.java
+++ b/jdk/src/share/classes/javax/swing/JFrame.java
@@ -40,7 +40,7 @@ import javax.accessibility.*;
* You can find task-oriented documentation about using JFrame
* in The Java Tutorial, in the section
* How to Make Frames.
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/frame.html">How to Make Frames.
*
*
* The JFrame class is slightly incompatible with Frame.
@@ -77,7 +77,7 @@ import javax.accessibility.*;
* For more information on content panes
* and other features that root panes provide,
* see Using Top-Level Containers in The Java Tutorial.
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html">Using Top-Level Containers in The Java Tutorial.
*
* In a multi-screen environment, you can create a JFrame
* on a different screen device. See {@link java.awt.Frame} for more
@@ -93,7 +93,7 @@ import javax.accessibility.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -430,7 +430,7 @@ public class JFrame extends Frame implements WindowConstants,
* are currently typed to {@code JComponent}.
*
* Please see
- *
+ *
* How to Use Drag and Drop and Data Transfer, a section in
* The Java Tutorial, for more information.
*
diff --git a/jdk/src/share/classes/javax/swing/JInternalFrame.java b/jdk/src/share/classes/javax/swing/JInternalFrame.java
index a0ba3a18084..ad78df11c01 100644
--- a/jdk/src/share/classes/javax/swing/JInternalFrame.java
+++ b/jdk/src/share/classes/javax/swing/JInternalFrame.java
@@ -50,7 +50,7 @@ import sun.swing.SwingUtilities2;
* resizing, title display, and support for a menu bar.
* For task-oriented documentation and examples of using internal frames,
* see How to Use Internal Frames,
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/internalframe.html" target="_top">How to Use Internal Frames,
* a section in The Java Tutorial.
*
*
@@ -90,7 +90,7 @@ import sun.swing.SwingUtilities2;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -2029,7 +2029,7 @@ public class JInternalFrame extends JComponent implements
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
@@ -2144,7 +2144,7 @@ public class JInternalFrame extends JComponent implements
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -2318,7 +2318,7 @@ public class JInternalFrame extends JComponent implements
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JLabel.java b/jdk/src/share/classes/javax/swing/JLabel.java
index 82235093f97..cf4ae3921f0 100644
--- a/jdk/src/share/classes/javax/swing/JLabel.java
+++ b/jdk/src/share/classes/javax/swing/JLabel.java
@@ -80,7 +80,7 @@ import java.util.*;
* should appear between the text and the image.
* The default is 4 pixels.
*
- * See How to Use Labels
+ * See How to Use Labels
* in The Java Tutorial
* for further documentation.
*
@@ -94,7 +94,7 @@ import java.util.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -1064,7 +1064,7 @@ public class JLabel extends JComponent implements SwingConstants, Accessible
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JLayeredPane.java b/jdk/src/share/classes/javax/swing/JLayeredPane.java
index 3b61f28f1c6..075e535309b 100644
--- a/jdk/src/share/classes/javax/swing/JLayeredPane.java
+++ b/jdk/src/share/classes/javax/swing/JLayeredPane.java
@@ -41,15 +41,15 @@ import javax.accessibility.*;
* container, where higher-numbered components sit "on top" of other
* components.
* For task-oriented documentation and examples of using layered panes see
- * How to Use a Layered Pane,
+ * How to Use a Layered Pane,
* a section in The Java Tutorial.
*
- *
+ *
*
* |
- * 
+ * WIDTH="269" HEIGHT="264" STYLE="FLOAT:BOTTOM; BORDER=0">
*
|
*
*
@@ -148,7 +148,7 @@ import javax.accessibility.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -765,7 +765,7 @@ public class JLayeredPane extends JComponent implements Accessible {
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JList.java b/jdk/src/share/classes/javax/swing/JList.java
index ad22fc38e52..9b016251a7e 100644
--- a/jdk/src/share/classes/javax/swing/JList.java
+++ b/jdk/src/share/classes/javax/swing/JList.java
@@ -253,15 +253,13 @@ import static sun.swing.SwingUtilities2.Section.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
- * See How to Use Lists
- * in The Java Tutorial
+ * See How to Use Lists
+ * in The Java Tutorial
* for further documentation.
- * Also see the article Advanced JList Programming
- * in The Swing Connection.
*
* @see ListModel
* @see AbstractListModel
@@ -972,7 +970,7 @@ public class JList extends JComponent implements Scrollable, Accessible
*
*
- * Value | Description |
+ * Value | Description |
* VERTICAL
* | Cells are layed out vertically in a single column.
* | HORIZONTAL_WRAP
@@ -2879,7 +2877,7 @@ public class JList extends JComponent implements Scrollable, Accessible
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JMenu.java b/jdk/src/share/classes/javax/swing/JMenu.java
index 62b6f41e2fe..ad5f6fef68e 100644
--- a/jdk/src/share/classes/javax/swing/JMenu.java
+++ b/jdk/src/share/classes/javax/swing/JMenu.java
@@ -76,11 +76,11 @@ import java.lang.ref.WeakReference;
* configuring a menu. Refer to
* Swing Components Supporting Action for more
* details, and you can find more information in How
+ * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions, a section in The Java Tutorial.
*
* For information and examples of using menus see
- * How to Use Menus,
+ * How to Use Menus,
* a section in The Java Tutorial.
*
* Warning: Swing is not thread safe. For more
@@ -93,7 +93,7 @@ import java.lang.ref.WeakReference;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -1149,7 +1149,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
@@ -1386,7 +1386,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JMenuBar.java b/jdk/src/share/classes/javax/swing/JMenuBar.java
index 22dbe6274fe..8e6683d6f17 100644
--- a/jdk/src/share/classes/javax/swing/JMenuBar.java
+++ b/jdk/src/share/classes/javax/swing/JMenuBar.java
@@ -54,7 +54,7 @@ import javax.accessibility.*;
*
* For information and examples of using menu bars see
* How to Use Menus,
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html">How to Use Menus,
* a section in The Java Tutorial.
*
* Warning: Swing is not thread safe. For more
@@ -67,7 +67,7 @@ import javax.accessibility.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -502,7 +502,7 @@ public class JMenuBar extends JComponent implements Accessible,MenuElement
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JMenuItem.java b/jdk/src/share/classes/javax/swing/JMenuItem.java
index e13dc8b5b9d..10b59bbce3f 100644
--- a/jdk/src/share/classes/javax/swing/JMenuItem.java
+++ b/jdk/src/share/classes/javax/swing/JMenuItem.java
@@ -54,12 +54,12 @@ import javax.accessibility.*;
* configuring a menu item. Refer to
* Swing Components Supporting Action for more
* details, and you can find more information in How
+ * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions, a section in The Java Tutorial.
*
* For further documentation and for examples, see
* How to Use Menus
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html">How to Use Menus
* in The Java Tutorial.
*
* Warning: Swing is not thread safe. For more
@@ -72,7 +72,7 @@ import javax.accessibility.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -826,7 +826,7 @@ public class JMenuItem extends AbstractButton implements Accessible,MenuElement
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JOptionPane.java b/jdk/src/share/classes/javax/swing/JOptionPane.java
index c532cf619c0..8bbd49db63a 100644
--- a/jdk/src/share/classes/javax/swing/JOptionPane.java
+++ b/jdk/src/share/classes/javax/swing/JOptionPane.java
@@ -62,7 +62,7 @@ import static javax.swing.ClientPropertyKey.PopupFactory_FORCE_HEAVYWEIGHT_POPUP
* prompts users for a value or informs them of something.
* For information about using JOptionPane, see
* How to Make Dialogs,
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html">How to Make Dialogs,
* a section in The Java Tutorial.
*
*
@@ -108,16 +108,16 @@ import static javax.swing.ClientPropertyKey.PopupFactory_FORCE_HEAVYWEIGHT_POPUP
* the caller until the user's interaction is complete.
*
*
- *
+ *
*
- * | icon |
- * message |
+ * icon |
+ * message |
*
*
- * | input value |
+ * input value |
*
*
- * | option buttons |
+ * option buttons |
*
*
*
@@ -127,7 +127,7 @@ import static javax.swing.ClientPropertyKey.PopupFactory_FORCE_HEAVYWEIGHT_POPUP
* ultimately responsible for the final result. In particular, the
* look-and-feels will adjust the layout to accommodate the option pane's
* ComponentOrientation property.
- *
+ *
*
* Parameters:
* The parameters to these methods follow consistent patterns:
@@ -298,7 +298,7 @@ import static javax.swing.ClientPropertyKey.PopupFactory_FORCE_HEAVYWEIGHT_POPUP
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -2573,7 +2573,7 @@ public class JOptionPane extends JComponent implements Accessible
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JPanel.java b/jdk/src/share/classes/javax/swing/JPanel.java
index 7287a53ba27..8ebfcb1cbfb 100644
--- a/jdk/src/share/classes/javax/swing/JPanel.java
+++ b/jdk/src/share/classes/javax/swing/JPanel.java
@@ -39,7 +39,7 @@ import java.io.IOException;
* JPanel is a generic lightweight container.
* For examples and task-oriented documentation for JPanel, see
* How to Use Panels,
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/panel.html">How to Use Panels,
* a section in The Java Tutorial.
*
* Warning: Swing is not thread safe. For more
@@ -52,7 +52,7 @@ import java.io.IOException;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -229,7 +229,7 @@ public class JPanel extends JComponent implements Accessible
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JPasswordField.java b/jdk/src/share/classes/javax/swing/JPasswordField.java
index 1da370921da..8a646944ada 100644
--- a/jdk/src/share/classes/javax/swing/JPasswordField.java
+++ b/jdk/src/share/classes/javax/swing/JPasswordField.java
@@ -39,7 +39,7 @@ import java.util.Arrays;
* the editing of a single line of text where the view indicates
* something was typed, but does not show the original characters.
* You can find further information and examples in
- * How to Use Text Fields,
+ * How to Use Text Fields,
* a section in The Java Tutorial.
*
* JPasswordField is intended
@@ -64,7 +64,7 @@ import java.util.Arrays;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -399,7 +399,7 @@ public class JPasswordField extends JTextField {
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JPopupMenu.java b/jdk/src/share/classes/javax/swing/JPopupMenu.java
index 03532d12fde..3b9bbfc7237 100644
--- a/jdk/src/share/classes/javax/swing/JPopupMenu.java
+++ b/jdk/src/share/classes/javax/swing/JPopupMenu.java
@@ -58,7 +58,7 @@ import java.applet.Applet;
*
* For information and examples of using popup menus, see
* How to Use Menus
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html">How to Use Menus
* in The Java Tutorial.
*
* Warning: Swing is not thread safe. For more
@@ -71,7 +71,7 @@ import java.applet.Applet;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
diff --git a/jdk/src/share/classes/javax/swing/JProgressBar.java b/jdk/src/share/classes/javax/swing/JProgressBar.java
index 2be3a57c396..606ff13c2ca 100644
--- a/jdk/src/share/classes/javax/swing/JProgressBar.java
+++ b/jdk/src/share/classes/javax/swing/JProgressBar.java
@@ -100,7 +100,7 @@ import javax.swing.plaf.ProgressBarUI;
*
*
* For complete examples and further documentation see
- * How to Monitor Progress,
+ * How to Monitor Progress,
* a section in The Java Tutorial.
*
*
@@ -114,7 +114,7 @@ import javax.swing.plaf.ProgressBarUI;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -643,7 +643,7 @@ public class JProgressBar extends JComponent implements SwingConstants, Accessib
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
@@ -910,7 +910,7 @@ public class JProgressBar extends JComponent implements SwingConstants, Accessib
*
*
* See
- * How to Monitor Progress
+ * How to Monitor Progress
* for examples of using indeterminate progress bars.
*
* @param newValue true if the progress bar
@@ -1031,7 +1031,7 @@ public class JProgressBar extends JComponent implements SwingConstants, Accessib
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JRadioButton.java b/jdk/src/share/classes/javax/swing/JRadioButton.java
index 5d594ceac65..ad7a3abf8b9 100644
--- a/jdk/src/share/classes/javax/swing/JRadioButton.java
+++ b/jdk/src/share/classes/javax/swing/JRadioButton.java
@@ -57,10 +57,10 @@ import java.io.IOException;
* configuring a button. Refer to
* Swing Components Supporting Action for more
* details, and you can find more information in How
+ * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions, a section in The Java Tutorial.
*
- * See How to Use Buttons, Check Boxes, and Radio Buttons
+ * See How to Use Buttons, Check Boxes, and Radio Buttons
* in The Java Tutorial
* for further documentation.
*
@@ -74,7 +74,7 @@ import java.io.IOException;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -280,7 +280,7 @@ public class JRadioButton extends JToggleButton implements Accessible {
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JRadioButtonMenuItem.java b/jdk/src/share/classes/javax/swing/JRadioButtonMenuItem.java
index 1c4dd4c81f0..897ba97c760 100644
--- a/jdk/src/share/classes/javax/swing/JRadioButtonMenuItem.java
+++ b/jdk/src/share/classes/javax/swing/JRadioButtonMenuItem.java
@@ -53,12 +53,12 @@ import javax.accessibility.*;
* configuring a menu item. Refer to
* Swing Components Supporting Action for more
* details, and you can find more information in How
+ * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions, a section in The Java Tutorial.
*
* For further documentation and examples see
* How to Use Menus,
+ href="http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html">How to Use Menus,
* a section in The Java Tutorial.
*
* Warning: Swing is not thread safe. For more
@@ -71,7 +71,7 @@ import javax.accessibility.*;
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -262,7 +262,7 @@ public class JRadioButtonMenuItem extends JMenuItem implements Accessible {
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeansTM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*/
diff --git a/jdk/src/share/classes/javax/swing/JRootPane.java b/jdk/src/share/classes/javax/swing/JRootPane.java
index 1f41ccbfd8d..480af1b5ca3 100644
--- a/jdk/src/share/classes/javax/swing/JRootPane.java
+++ b/jdk/src/share/classes/javax/swing/JRootPane.java
@@ -43,13 +43,13 @@ import sun.security.action.GetBooleanAction;
* JFrame, JDialog, JWindow,
* JApplet, and JInternalFrame.
* For task-oriented information on functionality provided by root panes
- * see How to Use Root Panes,
+ * see How to Use Root Panes,
* a section in The Java Tutorial.
*
*
* The following image shows the relationships between
* the classes that use root panes.
- *  
* The "heavyweight" components (those that delegate to a peer, or native
@@ -69,7 +69,7 @@ import sun.security.action.GetBooleanAction;
* can be used to obtain the JRootPane that contains
* a given component.
*
- *
+ *
*
*
* TM
+ * of all JavaBeans™
* has been added to the java.beans package.
* Please see {@link java.beans.XMLEncoder}.
*
@@ -898,7 +898,7 @@ public class JRootPane extends JComponent implements Accessible {
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
- * of all JavaBeans | | |