diff --git a/src/share/classes/java/io/DataInput.java b/src/share/classes/java/io/DataInput.java index 4dad59d55f34c4bae14907b250bbcfaa6ff2eae7..58a3a2bfd3f5075786fba046a84220a9d5e3756a 100644 --- a/src/share/classes/java/io/DataInput.java +++ b/src/share/classes/java/io/DataInput.java @@ -48,132 +48,87 @@ package java.io; * may be thrown if the input stream has been * closed. * - *

Modified UTF-8

+ *

Modified UTF-8

*

* Implementations of the DataInput and DataOutput interfaces represent * Unicode strings in a format that is a slight modification of UTF-8. * (For information regarding the standard UTF-8 format, see section * 3.9 Unicode Encoding Forms of The Unicode Standard, Version * 4.0). - * Note that in the following tables, the most significant bit appears in the + * Note that in the following table, the most significant bit appears in the * far left-hand column. - *

- * All characters in the range {@code '\u005Cu0001'} to - * {@code '\u005Cu007F'} are represented by a single byte: * *

- * * + * + * + * * - * + * * * * - * + * + * + * * - *
+ * All characters in the range {@code '\u005Cu0001'} to + * {@code '\u005Cu007F'} are represented by a single byte:
Bit ValuesBit Values
Byte 1 - * - * - * - *
0
- *
bits 6-0
- *
- *
0
+ *
bits 6-0
+ *
+ * The null character {@code '\u005Cu0000'} and characters + * in the range {@code '\u005Cu0080'} to {@code '\u005Cu07FF'} are + * represented by a pair of bytes:
- *
- * - *

- * The null character {@code '\u005Cu0000'} and characters in the - * range {@code '\u005Cu0080'} to {@code '\u005Cu07FF'} are - * represented by a pair of bytes: - * - *

- * * * - * + * * * * - * + * * * - * + * + * + * * - *
Bit ValuesBit Values
Byte 1 - * - * - * - *
1
- *
1
- *
0
- *
bits 10-6
- *
- *
1
+ *
1
+ *
0
+ *
bits 10-6
*
Byte 2 - * - * - * - *
1
- *
0
- *
bits 5-0
- *
- *
1
+ *
0
+ *
bits 5-0
+ *
+ * {@code char} values in the range {@code '\u005Cu0800'} + * to {@code '\u005CuFFFF'} are represented by three bytes:
- *
- * - *
- * {@code char} values in the range {@code '\u005Cu0800'} to - * {@code '\u005CuFFFF'} are represented by three bytes: - * - *
- * * * - * + * * * * - * + * * * - * + * * * - * + * *
Bit ValuesBit Values
Byte 1 - * - * - * - *
1
- *
1
- *
1
- *
0
- *
bits 15-12
- *
- *
1
+ *
1
+ *
1
+ *
0
+ *
bits 15-12
*
Byte 2 - * - * - * - *
1
- *
0
- *
bits 11-6
- *
- *
1
+ *
0
+ *
bits 11-6
*
Byte 3 - * - * - * - *
1
- *
0
- *
bits 5-0
- *
- *
1
+ *
0
+ *
bits 5-0
*
- *
- * + * *

* The differences between this format and the * standard UTF-8 format are the following: diff --git a/src/share/classes/java/io/File.java b/src/share/classes/java/io/File.java index 6bab9bb21fe7e428d40a0b381a139316bdd55af3..f11530d2f67cbd201063c3c5c3effd9b0000de3d 100644 --- a/src/share/classes/java/io/File.java +++ b/src/share/classes/java/io/File.java @@ -129,7 +129,7 @@ import sun.security.action.GetPropertyAction; * created, the abstract pathname represented by a File object * will never change. * - *

Interoperability with {@code java.nio.file} package

+ *

Interoperability with {@code java.nio.file} package

* *

The {@code java.nio.file} * package defines interfaces and classes for the Java virtual machine to access diff --git a/src/share/classes/java/io/ObjectInputStream.java b/src/share/classes/java/io/ObjectInputStream.java index ca0400539f96323231fbc0083728f1919d44fe3b..d754cc2c27537c8b8469d8a8a235d0a8a7c2f839 100644 --- a/src/share/classes/java/io/ObjectInputStream.java +++ b/src/share/classes/java/io/ObjectInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -313,6 +313,7 @@ public class ObjectInputStream * @throws SecurityException if a security manager exists and its * checkPermission method denies enabling * subclassing. + * @throws IOException if an I/O error occurs while creating this stream * @see SecurityManager#checkPermission * @see java.io.SerializablePermission */ diff --git a/src/share/classes/java/io/ObjectOutputStream.java b/src/share/classes/java/io/ObjectOutputStream.java index f7a94bb0342a0cf394341a435077353120a60faa..6f4c1f3e070fc53a03888b0349872e5a81a55073 100644 --- a/src/share/classes/java/io/ObjectOutputStream.java +++ b/src/share/classes/java/io/ObjectOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -265,6 +265,7 @@ public class ObjectOutputStream * @throws SecurityException if a security manager exists and its * checkPermission method denies enabling * subclassing. + * @throws IOException if an I/O error occurs while creating this stream * @see SecurityManager#checkPermission * @see java.io.SerializablePermission */ diff --git a/src/share/classes/java/io/ObjectStreamField.java b/src/share/classes/java/io/ObjectStreamField.java index ceae3fd188e3a574ce3cb6d661b46ed8f17bae41..981e4ba8ca2da9951e8e424e30f88bd3034d2443 100644 --- a/src/share/classes/java/io/ObjectStreamField.java +++ b/src/share/classes/java/io/ObjectStreamField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -240,6 +240,8 @@ public class ObjectStreamField * Returns boolean value indicating whether or not the serializable field * represented by this ObjectStreamField instance is unshared. * + * @return {@code true} if this field is unshared + * * @since 1.4 */ public boolean isUnshared() { diff --git a/src/share/classes/java/io/RandomAccessFile.java b/src/share/classes/java/io/RandomAccessFile.java index 5e32ad5dba1f55ceabcb044d57815cab10decd31..440cd225c803000bda7a78cf69352b4494650770 100644 --- a/src/share/classes/java/io/RandomAccessFile.java +++ b/src/share/classes/java/io/RandomAccessFile.java @@ -128,7 +128,7 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable { * meanings are: * * - * + * * *

Value

Meaning

ValueMeaning
"r" Open for reading only. Invoking any of the write * methods of the resulting object will cause an {@link diff --git a/src/share/classes/java/lang/Class.java b/src/share/classes/java/lang/Class.java index 2e47377996f665c310ebcbfd2233f091c0985d37..9df0805167b7a0d54629074cebbf751744827344 100644 --- a/src/share/classes/java/lang/Class.java +++ b/src/share/classes/java/lang/Class.java @@ -157,10 +157,10 @@ public final class Class implements java.io.Serializable, * * The string is formatted as a list of type modifiers, if any, * followed by the kind of type (empty string for primitive types - * and {@code class}, {@code enum}, {@code interface}, or {@code - * @interface}, as appropriate), followed by the type's name, - * followed by an angle-bracketed comma-separated list of the - * type's type parameters, if any. + * and {@code class}, {@code enum}, {@code interface}, or + * @{@code interface}, as appropriate), followed + * by the type's name, followed by an angle-bracketed + * comma-separated list of the type's type parameters, if any. * * A space is used to separate modifiers from one another and to * separate any modifiers from the kind of type. The modifiers diff --git a/src/share/classes/java/lang/invoke/LambdaConversionException.java b/src/share/classes/java/lang/invoke/LambdaConversionException.java index 5cc3c626e363c407031fbc118093780450788fe5..e1123da59d81291bf0ef0048682730aaee35f0ff 100644 --- a/src/share/classes/java/lang/invoke/LambdaConversionException.java +++ b/src/share/classes/java/lang/invoke/LambdaConversionException.java @@ -29,6 +29,8 @@ package java.lang.invoke; * LambdaConversionException */ public class LambdaConversionException extends Exception { + private static final long serialVersionUID = 292L + 8L; + /** * Constructs a {@code LambdaConversionException}. */ diff --git a/src/share/classes/java/lang/reflect/Parameter.java b/src/share/classes/java/lang/reflect/Parameter.java index f49c1daa436a2fe7598b89acf84cf73499436b2b..0568d9ee2e07c4910f1d87c32992f0ad80bb361e 100644 --- a/src/share/classes/java/lang/reflect/Parameter.java +++ b/src/share/classes/java/lang/reflect/Parameter.java @@ -162,7 +162,7 @@ public final class Parameter implements AnnotatedElement { /** * Returns the name of the parameter. If the parameter's name is - * {@linkplain isNamePresent() present}, then this method returns + * {@linkplain #isNamePresent() present}, then this method returns * the name provided by the class file. Otherwise, this method * synthesizes a name of the form argN, where N is the index of * the parameter in the descriptor of the method which declares diff --git a/src/share/classes/java/net/URI.java b/src/share/classes/java/net/URI.java index 643c8af8a71a4ecf27e294838bff98575ed71da8..24e1a979f6e134bb9cefecfc17923e614c6fc59d 100644 --- a/src/share/classes/java/net/URI.java +++ b/src/share/classes/java/net/URI.java @@ -530,7 +530,7 @@ public final class URI * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396, * Appendix A, except for the following deviations:

* - *
    + *
      * *
    • An empty authority component is permitted as long as it is * followed by a non-empty path, a query component, or a fragment @@ -993,7 +993,7 @@ public final class URI *

    • Otherwise the new URI's authority component is copied from * this URI, and its path is computed as follows:

      * - *
        + *
          * *
        1. If the given URI's path is absolute then the new URI's path * is taken from the given URI.

        2. @@ -1241,7 +1241,7 @@ public final class URI *

          The host component of a URI, if defined, will have one of the * following forms:

          * - *
            + *
              * *
            • A domain name consisting of one or more labels * separated by period characters ('.'), optionally followed by @@ -1495,7 +1495,7 @@ public final class URI * *

              The ordering of URIs is defined as follows:

              * - *
                + *
                  * *
                • Two URIs with different schemes are ordered according the * ordering of their schemes, without regard to case.

                • @@ -1513,7 +1513,7 @@ public final class URI *
                • Two hierarchical URIs with identical schemes are ordered * according to the ordering of their authority components:

                  * - *
                    + *
                      * *
                    • If both authority components are server-based then the URIs * are ordered according to their user-information components; if these diff --git a/src/share/classes/java/nio/channels/package-info.java b/src/share/classes/java/nio/channels/package-info.java index 85590dde06d2bf18249ec1432ba647fdfcb8cd58..cb55f8f8da71e786bf3e45cd254507942a151380 100644 --- a/src/share/classes/java/nio/channels/package-info.java +++ b/src/share/classes/java/nio/channels/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -31,7 +31,7 @@ * * *

                      - * + * * * * @@ -110,7 +110,7 @@ * write them to a given writable byte channel. * *

                      Channels

                      Description

                      ChannelsDescription
                      {@link java.nio.channels.Channel}A nexus for I/O operations
                        {@link java.nio.channels.ReadableByteChannel}
                      - * + * * * * @@ -138,7 +138,7 @@ * * *

                      File channels

                      Description

                      File channelsDescription
                      {@link java.nio.channels.FileChannel}Reads, writes, maps, and manipulates files
                      {@link java.nio.channels.FileLock}
                      - * + * * * * @@ -225,7 +225,7 @@ * * *

                      Multiplexed, non-blocking I/O

                      Description

                      Multiplexed, non-blocking I/O

                      Description

                      {@link java.nio.channels.SelectableChannel}A channel that can be multiplexed
                        {@link java.nio.channels.DatagramChannel}
                      - * + * * * * diff --git a/src/share/classes/java/nio/charset/Charset.java b/src/share/classes/java/nio/charset/Charset.java index 278bacb17c501ebf617f99586f44add7b3459ef6..e1a828dcb15df6af9f6cbdc50b8defc8b08eaba1 100644 --- a/src/share/classes/java/nio/charset/Charset.java +++ b/src/share/classes/java/nio/charset/Charset.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ import sun.security.action.GetPropertyAction; * concurrent threads. * * - * + * *

                      Charset names

                      * *

                      Charsets are named by strings composed of the following characters: @@ -111,21 +111,17 @@ import sun.security.action.GetPropertyAction; * The aliases of a charset are returned by the {@link #aliases() aliases} * method. * - * - * - *

                      Some charsets have an historical name that is defined for - * compatibility with previous versions of the Java platform. A charset's + *

                      Some charsets have an historical name that is defined for + * compatibility with previous versions of the Java platform. A charset's * historical name is either its canonical name or one of its aliases. The * historical name is returned by the getEncoding() methods of the * {@link java.io.InputStreamReader#getEncoding InputStreamReader} and {@link * java.io.OutputStreamWriter#getEncoding OutputStreamWriter} classes. * - * - * - *

                      If a charset listed in the If a charset listed in the IANA Charset * Registry is supported by an implementation of the Java platform then - * its canonical name must be the name listed in the registry. Many charsets + * its canonical name must be the name listed in the registry. Many charsets * are given more than one name in the registry, in which case the registry * identifies one of the names as MIME-preferred. If a charset has more * than one registry name then its canonical name must be the MIME-preferred @@ -142,15 +138,15 @@ import sun.security.action.GetPropertyAction; * *

                      Standard charsets

                      * - * * - *

                      Every implementation of the Java platform is required to support the - * following standard charsets. Consult the release documentation for your + * + *

                      Every implementation of the Java platform is required to support the + * following standard charsets. Consult the release documentation for your * implementation to see if any other charsets are supported. The behavior * of such optional charsets may differ between implementations. * *

                      Asynchronous I/O

                      Description

                      Asynchronous I/ODescription
                      {@link java.nio.channels.AsynchronousFileChannel}An asynchronous channel for reading, writing, and manipulating a file
                      {@link java.nio.channels.AsynchronousSocketChannel}
                      - * + * * * diff --git a/src/share/classes/java/nio/charset/MalformedInputException.java b/src/share/classes/java/nio/charset/MalformedInputException.java index ba1d1018a53a96683ab4b63a8f441e98e31b3d72..aadbadccc2a01193937ac4158751f7dabd8639aa 100644 --- a/src/share/classes/java/nio/charset/MalformedInputException.java +++ b/src/share/classes/java/nio/charset/MalformedInputException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,14 +42,27 @@ public class MalformedInputException private int inputLength; + /** + * Constructs an {@code MalformedInputException} with the given + * length. + * @param inputLength the length of the input + */ public MalformedInputException(int inputLength) { this.inputLength = inputLength; } + /** + * Returns the length of the input. + * @return the length of the input + */ public int getInputLength() { return inputLength; } + /** + * Returns the message. + * @return the message + */ public String getMessage() { return "Input length = " + inputLength; } diff --git a/src/share/classes/java/nio/charset/UnmappableCharacterException.java b/src/share/classes/java/nio/charset/UnmappableCharacterException.java index 5fa12476d688e29cf671398b88521305ed64a4ef..c33f0404b64ef3c209ea5e411c860c02848b977e 100644 --- a/src/share/classes/java/nio/charset/UnmappableCharacterException.java +++ b/src/share/classes/java/nio/charset/UnmappableCharacterException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -42,14 +42,27 @@ public class UnmappableCharacterException private int inputLength; + /** + * Constructs an {@code UnmappableCharacterException} with the + * given length. + * @param inputLength the length of the input + */ public UnmappableCharacterException(int inputLength) { this.inputLength = inputLength; } + /** + * Returns the length of the input. + * @return the length of the input + */ public int getInputLength() { return inputLength; } + /** + * Returns the message. + * @return the message + */ public String getMessage() { return "Input length = " + inputLength; } diff --git a/src/share/classes/java/nio/file/attribute/package-info.java b/src/share/classes/java/nio/file/attribute/package-info.java index 222b7251f00e973062ce28fc19f70f91dc930cfd..b0e87b64c763ba373df54fa940807be1681bd2f3 100644 --- a/src/share/classes/java/nio/file/attribute/package-info.java +++ b/src/share/classes/java/nio/file/attribute/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -27,7 +27,7 @@ * Interfaces and classes providing access to file and file system attributes. * *

                      Charset

                      Description

                      CharsetDescription
                      US-ASCIISeven-bit ASCII, a.k.a. ISO646-US, * a.k.a. the Basic Latin block of the Unicode character set
                      - * + * * * * @@ -38,7 +38,7 @@ * * * - * + * * * * @@ -86,14 +86,14 @@ * *
                        * - *

                      • The {@link java.nio.file.attribute.UserPrincipal} and + *
                      • The {@link java.nio.file.attribute.UserPrincipal} and * {@link java.nio.file.attribute.GroupPrincipal} interfaces represent an * identity or group identity.
                      • * - *

                      • The {@link java.nio.file.attribute.UserPrincipalLookupService} + *
                      • The {@link java.nio.file.attribute.UserPrincipalLookupService} * interface defines methods to lookup user or group principals.
                      • * - *

                      • The {@link java.nio.file.attribute.FileAttribute} interface + *
                      • The {@link java.nio.file.attribute.FileAttribute} interface * represents the value of an attribute for cases where the attribute value is * required to be set atomically when creating an object in the file system.
                      • * diff --git a/src/share/classes/java/nio/file/package-info.java b/src/share/classes/java/nio/file/package-info.java index c0cf571b555df1121013b8d77ea422c2942fc698..ca3e946d567ab8bd8104e30e9100a31f293da096 100644 --- a/src/share/classes/java/nio/file/package-info.java +++ b/src/share/classes/java/nio/file/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,8 +33,8 @@ * package is used by service provider implementors wishing to extend the * platform default provider, or to construct other provider implementations.

                        * - *

                        Symbolic Links

                        - * Many operating systems and file systems support for symbolic links. + *

                        Symbolic Links

                        + *

                        Many operating systems and file systems support for symbolic links. * A symbolic link is a special file that serves as a reference to another file. * For the most part, symbolic links are transparent to applications and * operations on symbolic links are automatically redirected to the target @@ -45,8 +45,8 @@ * that are semantically close but support for these other types of links is * not included in this package.

                        * - *

                        Interoperability

                        - * The {@link java.io.File} class defines the {@link java.io.File#toPath + *

                        Interoperability

                        + *

                        The {@link java.io.File} class defines the {@link java.io.File#toPath * toPath} method to construct a {@link java.nio.file.Path} by converting * the abstract path represented by the {@code java.io.File} object. The resulting * {@code Path} can be used to operate on the same file as the {@code File} @@ -55,7 +55,7 @@ * and {@code java.io.File} objects.

                        * *

                        Visibility

                        - * The view of the files and file system provided by classes in this package are + *

                        The view of the files and file system provided by classes in this package are * guaranteed to be consistent with other views provided by other instances in the * same Java virtual machine. The view may or may not, however, be consistent with * the view of the file system as seen by other concurrently running programs due @@ -65,8 +65,8 @@ * or on some other machine. The exact nature of any such inconsistencies are * system-dependent and are therefore unspecified.

                        * - *

                        Synchronized I/O File Integrity

                        - * The {@link java.nio.file.StandardOpenOption#SYNC SYNC} and {@link + *

                        Synchronized I/O File Integrity

                        + *

                        The {@link java.nio.file.StandardOpenOption#SYNC SYNC} and {@link * java.nio.file.StandardOpenOption#DSYNC DSYNC} options are used when opening a file * to require that updates to the file are written synchronously to the underlying * storage device. In the case of the default provider, and the file resides on @@ -83,7 +83,7 @@ * specific.

                        * *

                        General Exceptions

                        - * Unless otherwise noted, passing a {@code null} argument to a constructor + *

                        Unless otherwise noted, passing a {@code null} argument to a constructor * or method of any class or interface in this package will cause a {@link * java.lang.NullPointerException NullPointerException} to be thrown. Additionally, * invoking a method with a collection containing a {@code null} element will diff --git a/src/share/classes/java/security/cert/PKIXRevocationChecker.java b/src/share/classes/java/security/cert/PKIXRevocationChecker.java index 2446c821df660061a55445ae412fc1cbf0f1631c..d0e2ee0298611f45e5e793ec6cef0c35cfd711ed 100644 --- a/src/share/classes/java/security/cert/PKIXRevocationChecker.java +++ b/src/share/classes/java/security/cert/PKIXRevocationChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,21 +50,26 @@ import java.util.Set; * status of certificates with OCSP and CRLs. By default, OCSP is the * preferred mechanism for checking revocation status, with CRLs as the * fallback mechanism. However, this preference can be switched to CRLs with - * the {@link Option#PREFER_CRLS PREFER_CRLS} option. + * the {@link Option#PREFER_CRLS PREFER_CRLS} option. In addition, the fallback + * mechanism can be disabled with the {@link Option#NO_FALLBACK NO_FALLBACK} + * option. * *

                        A {@code PKIXRevocationChecker} is obtained by calling the * {@link CertPathValidator#getRevocationChecker getRevocationChecker} method * of a PKIX {@code CertPathValidator}. Additional parameters and options - * specific to revocation can be set (by calling {@link #setOCSPResponder} - * method for instance). The {@code PKIXRevocationChecker} is added to - * a {@code PKIXParameters} object using the - * {@link PKIXParameters#addCertPathChecker addCertPathChecker} + * specific to revocation can be set (by calling the + * {@link #setOcspResponder setOcspResponder} method for instance). The + * {@code PKIXRevocationChecker} is added to a {@code PKIXParameters} object + * using the {@link PKIXParameters#addCertPathChecker addCertPathChecker} * or {@link PKIXParameters#setCertPathCheckers setCertPathCheckers} method, * and then the {@code PKIXParameters} is passed along with the {@code CertPath} * to be validated to the {@link CertPathValidator#validate validate} method * of a PKIX {@code CertPathValidator}. When supplying a revocation checker in * this manner, it will be used to check revocation irrespective of the setting * of the {@link PKIXParameters#isRevocationEnabled RevocationEnabled} flag. + * Similarly, a {@code PKIXRevocationChecker} may be added to a + * {@code PKIXBuilderParameters} object for use with a PKIX + * {@code CertPathBuilder}. * *

                        Note that when a {@code PKIXRevocationChecker} is added to * {@code PKIXParameters}, it clones the {@code PKIXRevocationChecker}; @@ -83,6 +88,13 @@ import java.util.Set; * need not synchronize. * * @since 1.8 + * + * @see RFC 2560: X.509 + * Internet Public Key Infrastructure Online Certificate Status Protocol - + * OCSP,
                        RFC 5280: Internet X.509 + * Public Key Infrastructure Certificate and Certificate Revocation List (CRL) + * Profile */ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker { private URI ocspResponder; @@ -101,7 +113,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker { * * @param uri the responder URI */ - public void setOCSPResponder(URI uri) { + public void setOcspResponder(URI uri) { this.ocspResponder = uri; } @@ -114,7 +126,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker { * * @return the responder URI, or {@code null} if not set */ - public URI getOCSPResponder() { + public URI getOcspResponder() { return ocspResponder; } @@ -126,7 +138,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker { * * @param cert the responder's certificate */ - public void setOCSPResponderCert(X509Certificate cert) { + public void setOcspResponderCert(X509Certificate cert) { this.ocspResponderCert = cert; } @@ -140,7 +152,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker { * * @return the responder's certificate, or {@code null} if not set */ - public X509Certificate getOCSPResponderCert() { + public X509Certificate getOcspResponderCert() { return ocspResponderCert; } @@ -151,7 +163,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker { * @param extensions a list of extensions. The list is copied to protect * against subsequent modification. */ - public void setOCSPExtensions(List extensions) + public void setOcspExtensions(List extensions) { this.ocspExtensions = (extensions == null) ? Collections.emptyList() @@ -161,10 +173,10 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker { /** * Gets the optional OCSP request extensions. * - * @return an unmodifiable list of extensions. Returns an empty list if no + * @return an unmodifiable list of extensions. The list is empty if no * extensions have been specified. */ - public List getOCSPExtensions() { + public List getOcspExtensions() { return Collections.unmodifiableList(ocspExtensions); } @@ -177,7 +189,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker { * DER-encoded OCSP response for that certificate. A deep copy of * the map is performed to protect against subsequent modification. */ - public void setOCSPResponses(Map responses) + public void setOcspResponses(Map responses) { if (responses == null) { this.ocspResponses = Collections.emptyMap(); @@ -200,7 +212,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker { * the map is returned to protect against subsequent modification. * Returns an empty map if no responses have been specified. */ - public Map getOCSPResponses() { + public Map getOcspResponses() { Map copy = new HashMap<>(ocspResponses.size()); for (Map.Entry e : ocspResponses.entrySet()) { copy.put(e.getKey(), e.getValue().clone()); @@ -223,15 +235,31 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker { /** * Gets the revocation options. * - * @return an unmodifiable set of revocation options, or an empty set if - * none are specified + * @return an unmodifiable set of revocation options. The set is empty if + * no options have been specified. */ public Set

                        + * An implementation of {@code PKIXRevocationChecker} is responsible for + * adding the ignored exceptions to the list. + * + * @return an unmodifiable list containing the ignored exceptions. The list + * is empty if no exceptions have been ignored. + */ + public abstract List getSoftFailExceptions(); + @Override - public Object clone() { + public PKIXRevocationChecker clone() { PKIXRevocationChecker copy = (PKIXRevocationChecker)super.clone(); copy.ocspExtensions = new ArrayList<>(ocspExtensions); copy.ocspResponses = new HashMap<>(ocspResponses); @@ -262,9 +290,26 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker { */ PREFER_CRLS, /** - * Ignore network failures. The default behavior is to consider it a - * failure if the revocation status of a certificate cannot be obtained - * due to a network error. This option applies to both OCSP and CRLs. + * Disable the fallback mechanism. + */ + NO_FALLBACK, + /** + * Allow revocation check to succeed if the revocation status cannot be + * determined for one of the following reasons: + *

                          + *
                        • The CRL or OCSP response cannot be obtained because of a + * network error. + *
                        • The OCSP responder returns one of the following errors + * specified in section 2.3 of RFC 2560: internalError, tryLater, + * or unauthorized. + *

                        + * Note that these conditions apply to both OCSP and CRLs, and unless + * the {@code NO_FALLBACK} option is set, the revocation check is + * allowed to succeed only if both mechanisms fail under one of the + * conditions as stated above. + * Exceptions that cause the network errors are ignored but can be + * later retrieved by calling the + * {@link #getSoftFailExceptions getSoftFailExceptions} method. */ SOFT_FAIL } diff --git a/src/share/classes/java/time/DayOfWeek.java b/src/share/classes/java/time/DayOfWeek.java index d2a6f5aa5416721c3cca967202113a2e4359a958..b48482241df2e357b46f5e5c3cdc453ad8fa4672 100644 --- a/src/share/classes/java/time/DayOfWeek.java +++ b/src/share/classes/java/time/DayOfWeek.java @@ -61,7 +61,6 @@ */ package java.time; -import java.time.temporal.UnsupportedTemporalTypeException; import static java.time.temporal.ChronoField.DAY_OF_WEEK; import static java.time.temporal.ChronoUnit.DAYS; @@ -73,6 +72,7 @@ import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; +import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.time.temporal.WeekFields; import java.util.Locale; @@ -339,7 +339,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster { if (field == DAY_OF_WEEK) { return getValue(); } else if (field instanceof ChronoField) { - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } diff --git a/src/share/classes/java/time/Duration.java b/src/share/classes/java/time/Duration.java index 52b225e6e697c591ba6deef9de77d119a5ae9be7..ab7da66f83a63f9c0d536183e999f93fe0836817 100644 --- a/src/share/classes/java/time/Duration.java +++ b/src/share/classes/java/time/Duration.java @@ -459,9 +459,9 @@ public final class Duration */ public static Duration between(Temporal startInclusive, Temporal endExclusive) { try { - return ofNanos(startInclusive.periodUntil(endExclusive, NANOS)); + return ofNanos(startInclusive.until(endExclusive, NANOS)); } catch (DateTimeException | ArithmeticException ex) { - long secs = startInclusive.periodUntil(endExclusive, SECONDS); + long secs = startInclusive.until(endExclusive, SECONDS); long nanos; try { nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND); @@ -523,7 +523,7 @@ public final class Duration } else if (unit == NANOS) { return nanos; } else { - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } } diff --git a/src/share/classes/java/time/Instant.java b/src/share/classes/java/time/Instant.java index 6dc246469451213cb14ac4dc2623819861ecc68c..aeecdbed5247becb2137b6e6e3f3603425d3bd29 100644 --- a/src/share/classes/java/time/Instant.java +++ b/src/share/classes/java/time/Instant.java @@ -69,6 +69,7 @@ import static java.time.temporal.ChronoField.INSTANT_SECONDS; import static java.time.temporal.ChronoField.MICRO_OF_SECOND; import static java.time.temporal.ChronoField.MILLI_OF_SECOND; import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoUnit.DAYS; import static java.time.temporal.ChronoUnit.NANOS; import java.io.DataInput; @@ -418,8 +419,9 @@ public final class Instant * Checks if the specified field is supported. *

                        * This checks if this instant can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

                        * If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -447,6 +449,44 @@ public final class Instant return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

                        + * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

                        + * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

                          + *
                        • {@code NANOS} + *
                        • {@code MICROS} + *
                        • {@code MILLIS} + *
                        • {@code SECONDS} + *
                        • {@code MINUTES} + *
                        • {@code HOURS} + *
                        • {@code HALF_DAYS} + *
                        • {@code DAYS} + *
                        + * All other {@code ChronoUnit} instances will return false. + *

                        + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + public boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit.isTimeBased() || unit == DAYS; + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

                        @@ -511,7 +551,7 @@ public final class Instant case MILLI_OF_SECOND: return nanos / 1000_000; case INSTANT_SECONDS: INSTANT_SECONDS.checkValidIntValue(seconds); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return range(field).checkValidIntValue(field.getFrom(this), field); } @@ -548,7 +588,7 @@ public final class Instant case MILLI_OF_SECOND: return nanos / 1000_000; case INSTANT_SECONDS: return seconds; } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } @@ -665,7 +705,7 @@ public final class Instant case NANO_OF_SECOND: return (newValue != nanos ? create(seconds, (int) newValue) : this); case INSTANT_SECONDS: return (newValue != seconds ? create(newValue, nanos) : this); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.adjustInto(this, newValue); } @@ -807,7 +847,7 @@ public final class Instant case HALF_DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY / 2)); case DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY)); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.addTo(this, amountToAdd); } @@ -1053,14 +1093,14 @@ public final class Instant * complete units between the two instants. * The {@code Temporal} passed to this method must be an {@code Instant}. * For example, the amount in days between two dates can be calculated - * using {@code startInstant.periodUntil(endInstant, SECONDS)}. + * using {@code startInstant.until(endInstant, SECONDS)}. *

                        * There are two equivalent ways of using this method. * The first is to invoke this method. * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

                              *   // these two lines are equivalent
                        -     *   amount = start.periodUntil(end, SECONDS);
                        +     *   amount = start.until(end, SECONDS);
                              *   amount = SECONDS.between(start, end);
                              * 
                        * The choice should be made based on which makes the code more readable. @@ -1085,7 +1125,7 @@ public final class Instant * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endInstant, TemporalUnit unit) { + 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"); @@ -1103,7 +1143,7 @@ public final class Instant case HALF_DAYS: return secondsUntil(end) / (12 * SECONDS_PER_HOUR); case DAYS: return secondsUntil(end) / (SECONDS_PER_DAY); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.between(this, endInstant); } diff --git a/src/share/classes/java/time/LocalDate.java b/src/share/classes/java/time/LocalDate.java index ede6d8326b96e554aa7b94b0176427266c6fddc2..d96f5b1fd1e9fc1606663dd960b4ddb6cd7f84a0 100644 --- a/src/share/classes/java/time/LocalDate.java +++ b/src/share/classes/java/time/LocalDate.java @@ -127,7 +127,7 @@ import java.util.Objects; * @since 1.8 */ public final class LocalDate - implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable { + implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable { /** * The minimum supported {@code LocalDate}, '-999999999-01-01'. @@ -466,8 +466,9 @@ public final class LocalDate * Checks if the specified field is supported. *

                        * This checks if this date can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

                        * If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -501,6 +502,41 @@ public final class LocalDate return ChronoLocalDate.super.isSupported(field); } + /** + * Checks if the specified unit is supported. + *

                        + * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

                        + * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

                          + *
                        • {@code DAYS} + *
                        • {@code WEEKS} + *
                        • {@code MONTHS} + *
                        • {@code YEARS} + *
                        • {@code DECADES} + *
                        • {@code CENTURIES} + *
                        • {@code MILLENNIA} + *
                        • {@code ERAS} + *
                        + * All other {@code ChronoUnit} instances will return false. + *

                        + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override // override for Javadoc + public boolean isSupported(TemporalUnit unit) { + return ChronoLocalDate.super.isSupported(unit); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

                        @@ -538,7 +574,7 @@ public final class LocalDate } return field.range(); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.rangeRefinedBy(this); } @@ -631,7 +667,7 @@ public final class LocalDate case YEAR: return year; case ERA: return (year >= 1 ? 1 : 0); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } private long getProlepticMonth() { @@ -988,7 +1024,7 @@ public final class LocalDate case YEAR: return withYear((int) newValue); case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year)); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.adjustInto(this, newValue); } @@ -1187,7 +1223,7 @@ public final class LocalDate case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000)); case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd)); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.addTo(this, amountToAdd); } @@ -1497,7 +1533,7 @@ public final class LocalDate * The result will be negative if the end is before the start. * The {@code Temporal} passed to this method must be a {@code LocalDate}. * For example, the amount in days between two dates can be calculated - * using {@code startDate.periodUntil(endDate, DAYS)}. + * using {@code startDate.until(endDate, DAYS)}. *

                        * The calculation returns a whole number, representing the number of * complete units between the two dates. @@ -1509,7 +1545,7 @@ public final class LocalDate * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

                              *   // these two lines are equivalent
                        -     *   amount = start.periodUntil(end, MONTHS);
                        +     *   amount = start.until(end, MONTHS);
                              *   amount = MONTHS.between(start, end);
                              * 
                        * The choice should be made based on which makes the code more readable. @@ -1534,7 +1570,7 @@ public final class LocalDate * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endDate, TemporalUnit unit) { + public long until(Temporal endDate, TemporalUnit unit) { Objects.requireNonNull(unit, "unit"); if (endDate instanceof LocalDate == false) { Objects.requireNonNull(endDate, "endDate"); @@ -1552,7 +1588,7 @@ public final class LocalDate case MILLENNIA: return monthsUntil(end) / 12000; case ERAS: return end.getLong(ERA) - getLong(ERA); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.between(this, endDate); } @@ -1591,7 +1627,7 @@ public final class LocalDate * The second is to use {@link Period#between(LocalDate, LocalDate)}: *
                              *   // these two lines are equivalent
                        -     *   period = start.periodUntil(end);
                        +     *   period = start.until(end);
                              *   period = Period.between(start, end);
                              * 
                        * The choice should be made based on which makes the code more readable. @@ -1600,7 +1636,7 @@ public final class LocalDate * @return the period between this date and the end date, not null */ @Override - public Period periodUntil(ChronoLocalDate endDate) { + public Period until(ChronoLocalDate endDate) { LocalDate end = LocalDate.from(endDate); long totalMonths = end.getProlepticMonth() - this.getProlepticMonth(); // safe int days = end.day - this.day; @@ -1803,7 +1839,7 @@ public final class LocalDate * @return the comparator value, negative if less, positive if greater */ @Override // override for Javadoc and performance - public int compareTo(ChronoLocalDate other) { + public int compareTo(ChronoLocalDate other) { if (other instanceof LocalDate) { return compareTo0((LocalDate) other); } @@ -1843,7 +1879,7 @@ public final class LocalDate * @return true if this date is after the specified date */ @Override // override for Javadoc and performance - public boolean isAfter(ChronoLocalDate other) { + public boolean isAfter(ChronoLocalDate other) { if (other instanceof LocalDate) { return compareTo0((LocalDate) other) > 0; } @@ -1872,7 +1908,7 @@ public final class LocalDate * @return true if this date is before the specified date */ @Override // override for Javadoc and performance - public boolean isBefore(ChronoLocalDate other) { + public boolean isBefore(ChronoLocalDate other) { if (other instanceof LocalDate) { return compareTo0((LocalDate) other) < 0; } @@ -1901,7 +1937,7 @@ public final class LocalDate * @return true if this date is equal to the specified date */ @Override // override for Javadoc and performance - public boolean isEqual(ChronoLocalDate other) { + public boolean isEqual(ChronoLocalDate other) { if (other instanceof LocalDate) { return compareTo0((LocalDate) other) == 0; } diff --git a/src/share/classes/java/time/LocalDateTime.java b/src/share/classes/java/time/LocalDateTime.java index 6e6c87bc2ff9a077460f60d0a8558df4d41ea368..d68d6f52537d9b517a0e1f419c3bd4edb8ee95fd 100644 --- a/src/share/classes/java/time/LocalDateTime.java +++ b/src/share/classes/java/time/LocalDateTime.java @@ -515,8 +515,9 @@ public final class LocalDateTime * Checks if the specified field is supported. *

                        * This checks if this date-time can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

                        * If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -569,6 +570,48 @@ public final class LocalDateTime return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

                        + * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

                        + * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

                          + *
                        • {@code NANOS} + *
                        • {@code MICROS} + *
                        • {@code MILLIS} + *
                        • {@code SECONDS} + *
                        • {@code MINUTES} + *
                        • {@code HOURS} + *
                        • {@code HALF_DAYS} + *
                        • {@code DAYS} + *
                        • {@code WEEKS} + *
                        • {@code MONTHS} + *
                        • {@code YEARS} + *
                        • {@code DECADES} + *
                        • {@code CENTURIES} + *
                        • {@code MILLENNIA} + *
                        • {@code ERAS} + *
                        + * All other {@code ChronoUnit} instances will return false. + *

                        + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override // override for Javadoc + public boolean isSupported(TemporalUnit unit) { + return ChronoLocalDateTime.super.isSupported(unit); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

                        @@ -1570,7 +1613,7 @@ public final class LocalDateTime * The result will be negative if the end is before the start. * The {@code Temporal} passed to this method must be a {@code LocalDateTime}. * For example, the amount in days between two date-times can be calculated - * using {@code startDateTime.periodUntil(endDateTime, DAYS)}. + * using {@code startDateTime.until(endDateTime, DAYS)}. *

                        * The calculation returns a whole number, representing the number of * complete units between the two date-times. @@ -1582,7 +1625,7 @@ public final class LocalDateTime * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

                              *   // these two lines are equivalent
                        -     *   amount = start.periodUntil(end, MONTHS);
                        +     *   amount = start.until(end, MONTHS);
                              *   amount = MONTHS.between(start, end);
                              * 
                        * The choice should be made based on which makes the code more readable. @@ -1609,18 +1652,17 @@ public final class LocalDateTime * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + 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; if (unit instanceof ChronoUnit) { - ChronoUnit f = (ChronoUnit) unit; - if (f.isTimeUnit()) { + if (unit.isTimeBased()) { long amount = date.daysUntil(end.date); if (amount == 0) { - return time.periodUntil(end.time, unit); + return time.until(end.time, unit); } long timePart = end.time.toNanoOfDay() - time.toNanoOfDay(); if (amount > 0) { @@ -1630,7 +1672,7 @@ public final class LocalDateTime amount++; // safe timePart -= NANOS_PER_DAY; // safe } - switch (f) { + switch ((ChronoUnit) unit) { case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break; @@ -1667,7 +1709,7 @@ public final class LocalDateTime } else if (endDate.isBefore(date) && end.time.isAfter(time)) { endDate = endDate.plusDays(1); } - return date.periodUntil(endDate, unit); + return date.until(endDate, unit); } return unit.between(this, endDateTime); } diff --git a/src/share/classes/java/time/LocalTime.java b/src/share/classes/java/time/LocalTime.java index 41b1a92756009e31c55bab5f25fdc42c19d60a9f..2bace6e7bc9047f36b3da4d61ac818c83ffa53da 100644 --- a/src/share/classes/java/time/LocalTime.java +++ b/src/share/classes/java/time/LocalTime.java @@ -470,8 +470,9 @@ public final class LocalTime * Checks if the specified field is supported. *

                        * This checks if this time can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

                        * If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -510,6 +511,43 @@ public final class LocalTime return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

                        + * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

                        + * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

                          + *
                        • {@code NANOS} + *
                        • {@code MICROS} + *
                        • {@code MILLIS} + *
                        • {@code SECONDS} + *
                        • {@code MINUTES} + *
                        • {@code HOURS} + *
                        • {@code HALF_DAYS} + *
                        + * All other {@code ChronoUnit} instances will return false. + *

                        + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override // override for Javadoc + public boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit.isTimeBased(); + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

                        @@ -628,7 +666,7 @@ public final class LocalTime case CLOCK_HOUR_OF_DAY: return (hour == 0 ? 24 : hour); case AMPM_OF_DAY: return hour / 12; } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } //----------------------------------------------------------------------- @@ -803,7 +841,7 @@ public final class LocalTime case CLOCK_HOUR_OF_DAY: return withHour((int) (newValue == 24 ? 0 : newValue)); case AMPM_OF_DAY: return plusHours((newValue - (hour / 12)) * 12); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.adjustInto(this, newValue); } @@ -995,8 +1033,7 @@ public final class LocalTime @Override public LocalTime plus(long amountToAdd, TemporalUnit unit) { if (unit instanceof ChronoUnit) { - ChronoUnit f = (ChronoUnit) unit; - switch (f) { + switch ((ChronoUnit) unit) { case NANOS: return plusNanos(amountToAdd); case MICROS: return plusNanos((amountToAdd % MICROS_PER_DAY) * 1000); case MILLIS: return plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000_000); @@ -1005,7 +1042,7 @@ public final class LocalTime case HOURS: return plusHours(amountToAdd); case HALF_DAYS: return plusHours((amountToAdd % 2) * 12); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.addTo(this, amountToAdd); } @@ -1295,7 +1332,7 @@ public final class LocalTime * The result will be negative if the end is before the start. * The {@code Temporal} passed to this method must be a {@code LocalTime}. * For example, the amount in hours between two times can be calculated - * using {@code startTime.periodUntil(endTime, HOURS)}. + * using {@code startTime.until(endTime, HOURS)}. *

                        * The calculation returns a whole number, representing the number of * complete units between the two times. @@ -1307,7 +1344,7 @@ public final class LocalTime * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

                              *   // these two lines are equivalent
                        -     *   amount = start.periodUntil(end, MINUTES);
                        +     *   amount = start.until(end, MINUTES);
                              *   amount = MINUTES.between(start, end);
                              * 
                        * The choice should be made based on which makes the code more readable. @@ -1332,7 +1369,7 @@ public final class LocalTime * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endTime, TemporalUnit unit) { + 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"); @@ -1349,7 +1386,7 @@ public final class LocalTime case HOURS: return nanosUntil / NANOS_PER_HOUR; case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.between(this, endTime); } diff --git a/src/share/classes/java/time/Month.java b/src/share/classes/java/time/Month.java index 272e8f96b360a62373580569900265390b05fcfc..85d12d8f1362e655110e234c8f769d22a6e0fcbc 100644 --- a/src/share/classes/java/time/Month.java +++ b/src/share/classes/java/time/Month.java @@ -61,7 +61,6 @@ */ package java.time; -import java.time.temporal.UnsupportedTemporalTypeException; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoUnit.MONTHS; @@ -75,6 +74,7 @@ import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; +import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.Locale; @@ -370,7 +370,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster { if (field == MONTH_OF_YEAR) { return getValue(); } else if (field instanceof ChronoField) { - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } diff --git a/src/share/classes/java/time/MonthDay.java b/src/share/classes/java/time/MonthDay.java index 4204ef74a7ddd3247d10c2ec378477ef6129a655..06aa0437af8a94acf16640129a34f4cb997fae6a 100644 --- a/src/share/classes/java/time/MonthDay.java +++ b/src/share/classes/java/time/MonthDay.java @@ -438,7 +438,7 @@ public final class MonthDay case DAY_OF_MONTH: return day; case MONTH_OF_YEAR: return month; } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } diff --git a/src/share/classes/java/time/OffsetDateTime.java b/src/share/classes/java/time/OffsetDateTime.java index b053085a9f5d6a9670b82ba8b214dbc3c12903a8..5641154cf3ec44560fac4f311fc5d34fc49dae9d 100644 --- a/src/share/classes/java/time/OffsetDateTime.java +++ b/src/share/classes/java/time/OffsetDateTime.java @@ -65,6 +65,7 @@ import static java.time.temporal.ChronoField.EPOCH_DAY; import static java.time.temporal.ChronoField.INSTANT_SECONDS; import static java.time.temporal.ChronoField.NANO_OF_DAY; import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoUnit.FOREVER; import static java.time.temporal.ChronoUnit.NANOS; import java.io.IOException; @@ -137,25 +138,40 @@ public final class OffsetDateTime public static final OffsetDateTime MAX = LocalDateTime.MAX.atOffset(ZoneOffset.MIN); /** - * Comparator for two {@code OffsetDateTime} instances based solely on the instant. + * Gets a comparator that compares two {@code OffsetDateTime} instances + * based solely on the instant. *

                        * This method differs from the comparison in {@link #compareTo} in that it * only compares the underlying instant. * + * @return a comparator that compares in time-line order + * * @see #isAfter * @see #isBefore * @see #isEqual */ - public static final Comparator INSTANT_COMPARATOR = new Comparator() { - @Override - public int compare(OffsetDateTime datetime1, OffsetDateTime datetime2) { - int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond()); - if (cmp == 0) { - cmp = Long.compare(datetime1.toLocalTime().toNanoOfDay(), datetime2.toLocalTime().toNanoOfDay()); - } - return cmp; + public static Comparator timeLineOrder() { + return OffsetDateTime::compareInstant; + } + + /** + * Compares this {@code OffsetDateTime} to another date-time. + * The comparison is based on the instant. + * + * @param datetime1 the first date-time to compare, not null + * @param datetime2 the other date-time to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + private static int compareInstant(OffsetDateTime datetime1, OffsetDateTime datetime2) { + if (datetime1.getOffset().equals(datetime2.getOffset())) { + return datetime1.toLocalDateTime().compareTo(datetime2.toLocalDateTime()); + } + int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond()); + if (cmp == 0) { + cmp = datetime1.toLocalTime().getNano() - datetime2.toLocalTime().getNano(); } - }; + return cmp; + } /** * Serialization version. @@ -406,8 +422,9 @@ public final class OffsetDateTime * Checks if the specified field is supported. *

                        * This checks if this date-time can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

                        * If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -458,6 +475,51 @@ public final class OffsetDateTime return field instanceof ChronoField || (field != null && field.isSupportedBy(this)); } + /** + * Checks if the specified unit is supported. + *

                        + * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

                        + * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

                          + *
                        • {@code NANOS} + *
                        • {@code MICROS} + *
                        • {@code MILLIS} + *
                        • {@code SECONDS} + *
                        • {@code MINUTES} + *
                        • {@code HOURS} + *
                        • {@code HALF_DAYS} + *
                        • {@code DAYS} + *
                        • {@code WEEKS} + *
                        • {@code MONTHS} + *
                        • {@code YEARS} + *
                        • {@code DECADES} + *
                        • {@code CENTURIES} + *
                        • {@code MILLENNIA} + *
                        • {@code ERAS} + *
                        + * All other {@code ChronoUnit} instances will return false. + *

                        + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override // override for Javadoc + public boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit != FOREVER; + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

                        @@ -1528,7 +1590,7 @@ public final class OffsetDateTime * 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. * For example, the period in days between two date-times can be calculated - * using {@code startDateTime.periodUntil(endDateTime, DAYS)}. + * using {@code startDateTime.until(endDateTime, DAYS)}. *

                        * The {@code Temporal} passed to this method must be an {@code OffsetDateTime}. * If the offset differs between the two date-times, the specified @@ -1544,7 +1606,7 @@ public final class OffsetDateTime * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

                              *   // these two lines are equivalent
                        -     *   amount = start.periodUntil(end, MONTHS);
                        +     *   amount = start.until(end, MONTHS);
                              *   amount = MONTHS.between(start, end);
                              * 
                        * The choice should be made based on which makes the code more readable. @@ -1571,7 +1633,7 @@ public final class OffsetDateTime * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + 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"); @@ -1579,7 +1641,7 @@ public final class OffsetDateTime if (unit instanceof ChronoUnit) { OffsetDateTime end = (OffsetDateTime) endDateTime; end = end.withOffsetSameInstant(offset); - return dateTime.periodUntil(end.dateTime, unit); + return dateTime.until(end.dateTime, unit); } return unit.between(this, endDateTime); } @@ -1724,15 +1786,9 @@ public final class OffsetDateTime */ @Override public int compareTo(OffsetDateTime other) { - if (getOffset().equals(other.getOffset())) { - return toLocalDateTime().compareTo(other.toLocalDateTime()); - } - int cmp = Long.compare(toEpochSecond(), other.toEpochSecond()); + int cmp = compareInstant(this, other); if (cmp == 0) { - cmp = toLocalTime().getNano() - other.toLocalTime().getNano(); - if (cmp == 0) { - cmp = toLocalDateTime().compareTo(other.toLocalDateTime()); - } + cmp = toLocalDateTime().compareTo(other.toLocalDateTime()); } return cmp; } diff --git a/src/share/classes/java/time/OffsetTime.java b/src/share/classes/java/time/OffsetTime.java index ff990696942dffef8eca4b9080d11c4f37740c68..2872cff4b265aae3d7d4d6adbece3169d4cc57de 100644 --- a/src/share/classes/java/time/OffsetTime.java +++ b/src/share/classes/java/time/OffsetTime.java @@ -348,8 +348,9 @@ public final class OffsetTime * Checks if the specified field is supported. *

                        * This checks if this time can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

                        * If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -389,6 +390,43 @@ public final class OffsetTime return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

                        + * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

                        + * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

                          + *
                        • {@code NANOS} + *
                        • {@code MICROS} + *
                        • {@code MILLIS} + *
                        • {@code SECONDS} + *
                        • {@code MINUTES} + *
                        • {@code HOURS} + *
                        • {@code HALF_DAYS} + *
                        + * All other {@code ChronoUnit} instances will return false. + *

                        + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override // override for Javadoc + public boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit.isTimeBased(); + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

                        @@ -1084,7 +1122,7 @@ public final class OffsetTime * The start and end points are {@code this} and the specified time. * The result will be negative if the end is before the start. * For example, the period in hours between two times can be calculated - * using {@code startTime.periodUntil(endTime, HOURS)}. + * using {@code startTime.until(endTime, HOURS)}. *

                        * The {@code Temporal} passed to this method must be an {@code OffsetTime}. * If the offset differs between the two times, then the specified @@ -1100,7 +1138,7 @@ public final class OffsetTime * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

                              *   // these two lines are equivalent
                        -     *   amount = start.periodUntil(end, MINUTES);
                        +     *   amount = start.until(end, MINUTES);
                              *   amount = MINUTES.between(start, end);
                              * 
                        * The choice should be made based on which makes the code more readable. @@ -1125,7 +1163,7 @@ public final class OffsetTime * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endTime, TemporalUnit unit) { + 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"); @@ -1142,7 +1180,7 @@ public final class OffsetTime case HOURS: return nanosUntil / NANOS_PER_HOUR; case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.between(this, endTime); } diff --git a/src/share/classes/java/time/Period.java b/src/share/classes/java/time/Period.java index b2748f089ce8826a991ca14e928cc7710651d955..45980d08740a4ee260d67adce2cf8a1a2dd1689f 100644 --- a/src/share/classes/java/time/Period.java +++ b/src/share/classes/java/time/Period.java @@ -139,7 +139,7 @@ public final class Period * The pattern for parsing. */ private final static Pattern PATTERN = - Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)D)?", Pattern.CASE_INSENSITIVE); + Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?", Pattern.CASE_INSENSITIVE); /** * The set of supported units. */ @@ -186,6 +186,20 @@ public final class Period return create(0, months, 0); } + /** + * Obtains a {@code Period} representing a number of weeks. + *

                        + * The resulting period will be day-based, with the amount of days + * equal to the number of weeks multiplied by 7. + * The years and months units will be zero. + * + * @param weeks the number of weeks, positive or negative + * @return the period, with the input weeks converted to days, not null + */ + public static Period ofWeeks(int weeks) { + return create(0, 0, Math.multiplyExact(weeks, 7)); + } + /** * Obtains a {@code Period} representing a number of days. *

                        @@ -257,22 +271,36 @@ public final class Period * Obtains a {@code Period} from a text string such as {@code PnYnMnD}. *

                        * This will parse the string produced by {@code toString()} which is - * based on the ISO-8601 period format {@code PnYnMnD}. + * based on the ISO-8601 period formats {@code PnYnMnD} and {@code PnW}. *

                        * The string starts with an optional sign, denoted by the ASCII negative * or positive symbol. If negative, the whole period is negated. * The ASCII letter "P" is next in upper or lower case. - * There are then three sections, each consisting of a number and a suffix. - * At least one of the three sections must be present. - * The sections have suffixes in ASCII of "Y", "M" and "D" for - * years, months and days, accepted in upper or lower case. + * There are then four sections, each consisting of a number and a suffix. + * At least one of the four sections must be present. + * The sections have suffixes in ASCII of "Y", "M", "W" and "D" for + * years, months, weeks and days, accepted in upper or lower case. * The suffixes must occur in order. * The number part of each section must consist of ASCII digits. * The number may be prefixed by the ASCII negative or positive symbol. * The number must parse to an {@code int}. *

                        * The leading plus/minus sign, and negative values for other units are - * not part of the ISO-8601 standard. + * not part of the ISO-8601 standard. In addition, ISO-8601 does not + * permit mixing between the {@code PnYnMnD} and {@code PnW} formats. + * Any week-based input is multiplied by 7 and treated as a number of days. + *

                        + * For example, the following are valid inputs: + *

                        +     *   "P2Y"             -- Period.ofYears(2)
                        +     *   "P3M"             -- Period.ofMonths(3)
                        +     *   "P4W"             -- Period.ofWeeks(4)
                        +     *   "P5D"             -- Period.ofDays(5)
                        +     *   "P1Y2M3D"         -- Period.of(1, 2, 3)
                        +     *   "P1Y2M3W4D"       -- Period.of(1, 2, 25)
                        +     *   "P-1Y2M"          -- Period.of(-1, 2, 0)
                        +     *   "-P1Y2M"          -- Period.of(-1, -2, 0)
                        +     * 
                        * * @param text the text to parse, not null * @return the parsed period, not null @@ -285,14 +313,18 @@ public final class Period int negate = ("-".equals(matcher.group(1)) ? -1 : 1); String yearMatch = matcher.group(2); String monthMatch = matcher.group(3); - String dayMatch = matcher.group(4); - if (yearMatch != null || monthMatch != null || dayMatch != null) { + String weekMatch = matcher.group(4); + String dayMatch = matcher.group(5); + if (yearMatch != null || monthMatch != null || dayMatch != null || weekMatch != null) { try { - return create(parseNumber(text, yearMatch, negate), - parseNumber(text, monthMatch, negate), - parseNumber(text, dayMatch, negate)); + int years = parseNumber(text, yearMatch, negate); + int months = parseNumber(text, monthMatch, negate); + int weeks = parseNumber(text, weekMatch, negate); + int days = parseNumber(text, dayMatch, negate); + days = Math.addExact(days, Math.multiplyExact(weeks, 7)); + return create(years, months, days); } catch (NumberFormatException ex) { - throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Period", text, 0).initCause(ex); + throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0, ex); } } } @@ -307,7 +339,7 @@ public final class Period try { return Math.multiplyExact(val, negate); } catch (ArithmeticException ex) { - throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Period", text, 0).initCause(ex); + throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0, ex); } } @@ -329,10 +361,10 @@ public final class Period * @param startDate the start date, inclusive, not null * @param endDate the end date, exclusive, not null * @return the period between this date and the end date, not null - * @see ChronoLocalDate#periodUntil(ChronoLocalDate) + * @see ChronoLocalDate#until(ChronoLocalDate) */ public static Period between(LocalDate startDate, LocalDate endDate) { - return startDate.periodUntil(endDate); + return startDate.until(endDate); } //----------------------------------------------------------------------- @@ -386,7 +418,7 @@ public final class Period } else if (unit == ChronoUnit.DAYS) { return getDays(); } else { - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } } diff --git a/src/share/classes/java/time/Year.java b/src/share/classes/java/time/Year.java index c2d9974d79ae6c21420df33a4240027ec84e1294..fb180d859cbee2265e6c2eb7feee3e34917a5f91 100644 --- a/src/share/classes/java/time/Year.java +++ b/src/share/classes/java/time/Year.java @@ -64,6 +64,10 @@ package java.time; import static java.time.temporal.ChronoField.ERA; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.CENTURIES; +import static java.time.temporal.ChronoUnit.DECADES; +import static java.time.temporal.ChronoUnit.ERAS; +import static java.time.temporal.ChronoUnit.MILLENNIA; import static java.time.temporal.ChronoUnit.YEARS; import java.io.DataInput; @@ -329,8 +333,9 @@ public final class Year * Checks if the specified field is supported. *

                        * This checks if this year can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

                        * If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -357,6 +362,41 @@ public final class Year return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

                        + * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

                        + * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

                          + *
                        • {@code YEARS} + *
                        • {@code DECADES} + *
                        • {@code CENTURIES} + *
                        • {@code MILLENNIA} + *
                        • {@code ERAS} + *
                        + * All other {@code ChronoUnit} instances will return false. + *

                        + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + public boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit == YEARS || unit == DECADES || unit == CENTURIES || unit == MILLENNIA || unit == ERAS; + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

                        @@ -450,7 +490,7 @@ public final class Year case YEAR: return year; case ERA: return (year < 1 ? 0 : 1); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } @@ -575,7 +615,7 @@ public final class Year case YEAR: return Year.of((int) newValue); case ERA: return (getLong(ERA) == newValue ? this : Year.of(1 - year)); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.adjustInto(this, newValue); } @@ -664,7 +704,7 @@ public final class Year case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000)); case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd)); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.addTo(this, amountToAdd); } @@ -821,7 +861,7 @@ public final class 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}. * For example, the period in decades between two year can be calculated - * using {@code startYear.periodUntil(endYear, DECADES)}. + * using {@code startYear.until(endYear, DECADES)}. *

                        * The calculation returns a whole number, representing the number of * complete units between the two years. @@ -833,7 +873,7 @@ public final class Year * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

                              *   // these two lines are equivalent
                        -     *   amount = start.periodUntil(end, YEARS);
                        +     *   amount = start.until(end, YEARS);
                              *   amount = YEARS.between(start, end);
                              * 
                        * The choice should be made based on which makes the code more readable. @@ -858,7 +898,7 @@ public final class Year * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endYear, TemporalUnit unit) { + 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"); @@ -873,7 +913,7 @@ public final class Year case MILLENNIA: return yearsUntil / 1000; case ERAS: return end.getLong(ERA) - getLong(ERA); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.between(this, endYear); } diff --git a/src/share/classes/java/time/YearMonth.java b/src/share/classes/java/time/YearMonth.java index 855774eed1a77b41891ee5b244e9d570fe609dbd..1d974095336124d6c9e1daf949d573a102cbe652 100644 --- a/src/share/classes/java/time/YearMonth.java +++ b/src/share/classes/java/time/YearMonth.java @@ -66,7 +66,12 @@ import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.CENTURIES; +import static java.time.temporal.ChronoUnit.DECADES; +import static java.time.temporal.ChronoUnit.ERAS; +import static java.time.temporal.ChronoUnit.MILLENNIA; import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.YEARS; import java.io.DataInput; import java.io.DataOutput; @@ -313,8 +318,9 @@ public final class YearMonth * Checks if the specified field is supported. *

                        * This checks if this year-month can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

                        * If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -344,6 +350,42 @@ public final class YearMonth return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

                        + * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

                        + * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

                          + *
                        • {@code MONTHS} + *
                        • {@code YEARS} + *
                        • {@code DECADES} + *
                        • {@code CENTURIES} + *
                        • {@code MILLENNIA} + *
                        • {@code ERAS} + *
                        + * All other {@code ChronoUnit} instances will return false. + *

                        + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + public boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit == MONTHS || unit == YEARS || unit == DECADES || unit == CENTURIES || unit == MILLENNIA || unit == ERAS; + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

                        @@ -440,7 +482,7 @@ public final class YearMonth case YEAR: return year; case ERA: return (year < 1 ? 0 : 1); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } @@ -639,7 +681,7 @@ public final class YearMonth case YEAR: return withYear((int) newValue); case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year)); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.adjustInto(this, newValue); } @@ -761,7 +803,7 @@ public final class YearMonth case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000)); case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd)); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.addTo(this, amountToAdd); } @@ -952,7 +994,7 @@ public final class YearMonth * The result will be negative if the end is before the start. * The {@code Temporal} passed to this method must be a {@code YearMonth}. * For example, the period in years between two year-months can be calculated - * using {@code startYearMonth.periodUntil(endYearMonth, YEARS)}. + * using {@code startYearMonth.until(endYearMonth, YEARS)}. *

                        * The calculation returns a whole number, representing the number of * complete units between the two year-months. @@ -964,7 +1006,7 @@ public final class YearMonth * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

                              *   // these two lines are equivalent
                        -     *   amount = start.periodUntil(end, MONTHS);
                        +     *   amount = start.until(end, MONTHS);
                              *   amount = MONTHS.between(start, end);
                              * 
                        * The choice should be made based on which makes the code more readable. @@ -989,7 +1031,7 @@ public final class YearMonth * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endYearMonth, TemporalUnit unit) { + 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"); @@ -1005,7 +1047,7 @@ public final class YearMonth case MILLENNIA: return monthsUntil / 12000; case ERAS: return end.getLong(ERA) - getLong(ERA); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.between(this, endYearMonth); } diff --git a/src/share/classes/java/time/ZoneId.java b/src/share/classes/java/time/ZoneId.java index 026f73ef5125a00ac357996970598bc39c95a113..dcde85ae884b9f9fb14d16a3d4845f30882663eb 100644 --- a/src/share/classes/java/time/ZoneId.java +++ b/src/share/classes/java/time/ZoneId.java @@ -400,6 +400,36 @@ public abstract class ZoneId implements Serializable { return of(zoneId, true); } + /** + * Obtains an instance of {@code ZoneId} wrapping an offset. + *

                        + * If the prefix is "GMT", "UTC", or "UT" a {@code ZoneId} + * with the prefix and the non-zero offset is returned. + * If the prefix is empty {@code ""} the {@code ZoneOffset} is returned. + * + * @param prefix the time-zone ID, not null + * @param offset the offset, not null + * @return the zone ID, not null + * @throws IllegalArgumentException if the prefix is not one of + * "GMT", "UTC", or "UT", or "" + */ + public static ZoneId ofOffset(String prefix, ZoneOffset offset) { + Objects.requireNonNull(prefix, "prefix"); + Objects.requireNonNull(offset, "offset"); + if (prefix.length() == 0) { + return offset; + } + + if (!prefix.equals("GMT") && !prefix.equals("UTC") && !prefix.equals("UT")) { + throw new IllegalArgumentException("prefix should be GMT, UTC or UT, is: " + prefix); + } + + if (offset.getTotalSeconds() != 0) { + prefix = prefix.concat(offset.getId()); + } + return new ZoneRegion(prefix, offset.getRules()); + } + /** * Parses the ID, taking a flag to indicate whether {@code ZoneRulesException} * should be thrown or not, used in deserialization. @@ -433,7 +463,7 @@ public abstract class ZoneId implements Serializable { private static ZoneId ofWithPrefix(String zoneId, int prefixLength, boolean checkAvailable) { String prefix = zoneId.substring(0, prefixLength); if (zoneId.length() == prefixLength) { - return ZoneRegion.ofPrefixedOffset(prefix, ZoneOffset.UTC); + return ofOffset(prefix, ZoneOffset.UTC); } if (zoneId.charAt(prefixLength) != '+' && zoneId.charAt(prefixLength) != '-') { return ZoneRegion.ofId(zoneId, checkAvailable); // drop through to ZoneRulesProvider @@ -441,9 +471,9 @@ public abstract class ZoneId implements Serializable { try { ZoneOffset offset = ZoneOffset.of(zoneId.substring(prefixLength)); if (offset == ZoneOffset.UTC) { - return ZoneRegion.ofPrefixedOffset(prefix, offset); + return ofOffset(prefix, offset); } - return ZoneRegion.ofPrefixedOffset(prefix + offset.toString(), offset); + return ofOffset(prefix, offset); } catch (DateTimeException ex) { throw new DateTimeException("Invalid ID for offset-based ZoneId: " + zoneId, ex); } diff --git a/src/share/classes/java/time/ZoneOffset.java b/src/share/classes/java/time/ZoneOffset.java index 4bbc4e4fa84fa5f74991d8e3e8718335c56ddce6..c5e4d056ee82528891af0051ee390fc64448ac90 100644 --- a/src/share/classes/java/time/ZoneOffset.java +++ b/src/share/classes/java/time/ZoneOffset.java @@ -61,7 +61,6 @@ */ package java.time; -import java.time.temporal.UnsupportedTemporalTypeException; import static java.time.LocalTime.MINUTES_PER_HOUR; import static java.time.LocalTime.SECONDS_PER_HOUR; import static java.time.LocalTime.SECONDS_PER_MINUTE; @@ -79,6 +78,7 @@ import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; +import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.time.zone.ZoneRules; import java.util.Objects; @@ -581,7 +581,7 @@ public final class ZoneOffset if (field == OFFSET_SECONDS) { return totalSeconds; } else if (field instanceof ChronoField) { - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return range(field).checkValidIntValue(getLong(field), field); } @@ -613,7 +613,7 @@ public final class ZoneOffset if (field == OFFSET_SECONDS) { return totalSeconds; } else if (field instanceof ChronoField) { - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } diff --git a/src/share/classes/java/time/ZoneRegion.java b/src/share/classes/java/time/ZoneRegion.java index af6a5405a69e57245c70468f6de9a5bbe557dbdf..66d30709d98a75ffa7084246326cb3124f271782 100644 --- a/src/share/classes/java/time/ZoneRegion.java +++ b/src/share/classes/java/time/ZoneRegion.java @@ -66,7 +66,6 @@ import java.time.zone.ZoneRules; import java.time.zone.ZoneRulesException; import java.time.zone.ZoneRulesProvider; import java.util.Objects; -import java.util.regex.Pattern; /** * A geographical region where the same time-zone rules apply. @@ -153,19 +152,6 @@ final class ZoneRegion extends ZoneId implements Serializable { } } - /** - * Obtains an instance of {@code ZoneId} wrapping an offset. - *

                        - * For example, zone IDs like 'UTC', 'GMT', 'UT' and 'UTC+01:30' will be setup here. - * - * @param zoneId the time-zone ID, not null - * @param offset the offset, not null - * @return the zone ID, not null - */ - static ZoneRegion ofPrefixedOffset(String zoneId, ZoneOffset offset) { - return new ZoneRegion(zoneId, offset.getRules()); - } - //------------------------------------------------------------------------- /** * Constructor. diff --git a/src/share/classes/java/time/ZonedDateTime.java b/src/share/classes/java/time/ZonedDateTime.java index e7ed5551d33adcee26319fbe7325b3871b96ba95..151470ecf939903b5c480ea9a01692988867e3ee 100644 --- a/src/share/classes/java/time/ZonedDateTime.java +++ b/src/share/classes/java/time/ZonedDateTime.java @@ -642,8 +642,9 @@ public final class ZonedDateTime * Checks if the specified field is supported. *

                        * This checks if this date-time can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

                        * If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -694,6 +695,48 @@ public final class ZonedDateTime return field instanceof ChronoField || (field != null && field.isSupportedBy(this)); } + /** + * Checks if the specified unit is supported. + *

                        + * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

                        + * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

                          + *
                        • {@code NANOS} + *
                        • {@code MICROS} + *
                        • {@code MILLIS} + *
                        • {@code SECONDS} + *
                        • {@code MINUTES} + *
                        • {@code HOURS} + *
                        • {@code HALF_DAYS} + *
                        • {@code DAYS} + *
                        • {@code WEEKS} + *
                        • {@code MONTHS} + *
                        • {@code YEARS} + *
                        • {@code DECADES} + *
                        • {@code CENTURIES} + *
                        • {@code MILLENNIA} + *
                        • {@code ERAS} + *
                        + * All other {@code ChronoUnit} instances will return false. + *

                        + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override // override for Javadoc + public boolean isSupported(TemporalUnit unit) { + return ChronoZonedDateTime.super.isSupported(unit); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

                        @@ -1540,8 +1583,7 @@ public final class ZonedDateTime @Override public ZonedDateTime plus(long amountToAdd, TemporalUnit unit) { if (unit instanceof ChronoUnit) { - ChronoUnit u = (ChronoUnit) unit; - if (u.isDateUnit()) { + if (unit.isDateBased()) { return resolveLocal(dateTime.plus(amountToAdd, unit)); } else { return resolveInstant(dateTime.plus(amountToAdd, unit)); @@ -1990,7 +2032,7 @@ public final class ZonedDateTime * 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. * For example, the period in days between two date-times can be calculated - * using {@code startDateTime.periodUntil(endDateTime, DAYS)}. + * using {@code startDateTime.until(endDateTime, DAYS)}. *

                        * The {@code Temporal} passed to this method must be a {@code ZonedDateTime}. * If the time-zone differs between the two zoned date-times, the specified @@ -2006,7 +2048,7 @@ public final class ZonedDateTime * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

                              *   // these two lines are equivalent
                        -     *   amount = start.periodUntil(end, MONTHS);
                        +     *   amount = start.until(end, MONTHS);
                              *   amount = MONTHS.between(start, end);
                              * 
                        * The choice should be made based on which makes the code more readable. @@ -2047,7 +2089,7 @@ public final class ZonedDateTime * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + 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"); @@ -2055,11 +2097,10 @@ public final class ZonedDateTime if (unit instanceof ChronoUnit) { ZonedDateTime end = (ZonedDateTime) endDateTime; end = end.withZoneSameInstant(zone); - ChronoUnit u = (ChronoUnit) unit; - if (u.isDateUnit()) { - return dateTime.periodUntil(end.dateTime, unit); + if (unit.isDateBased()) { + return dateTime.until(end.dateTime, unit); } else { - return toOffsetDateTime().periodUntil(end.toOffsetDateTime(), unit); + return toOffsetDateTime().until(end.toOffsetDateTime(), unit); } } return unit.between(this, endDateTime); diff --git a/src/share/classes/java/time/chrono/ChronoDateImpl.java b/src/share/classes/java/time/chrono/ChronoDateImpl.java index 14e2bf58f2a7fe53d710c9c13171dea1e04735d4..99ba58f05b9a8dae2c84a789d3eef569bb1ad8bb 100644 --- a/src/share/classes/java/time/chrono/ChronoDateImpl.java +++ b/src/share/classes/java/time/chrono/ChronoDateImpl.java @@ -67,6 +67,8 @@ import java.time.DateTimeException; import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalField; import java.time.temporal.TemporalUnit; import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; @@ -96,12 +98,12 @@ import java.util.Objects; * // Enumerate the list of available calendars and print today for each * Set<Chronology> chronos = Chronology.getAvailableChronologies(); * for (Chronology chrono : chronos) { - * ChronoLocalDate<?> date = chrono.dateNow(); + * ChronoLocalDate date = chrono.dateNow(); * System.out.printf(" %20s: %s%n", chrono.getID(), date.toString()); * } * * // Print the Hijrah date and calendar - * ChronoLocalDate<?> date = Chronology.of("Hijrah").dateNow(); + * ChronoLocalDate date = Chronology.of("Hijrah").dateNow(); * int day = date.get(ChronoField.DAY_OF_MONTH); * int dow = date.get(ChronoField.DAY_OF_WEEK); * int month = date.get(ChronoField.MONTH_OF_YEAR); @@ -110,10 +112,10 @@ import java.util.Objects; * dow, day, month, year); * // Print today's date and the last day of the year - * ChronoLocalDate<?> now1 = Chronology.of("Hijrah").dateNow(); - * ChronoLocalDate<?> first = now1.with(ChronoField.DAY_OF_MONTH, 1) + * ChronoLocalDate now1 = Chronology.of("Hijrah").dateNow(); + * ChronoLocalDate first = now1.with(ChronoField.DAY_OF_MONTH, 1) * .with(ChronoField.MONTH_OF_YEAR, 1); - * ChronoLocalDate<?> last = first.plus(1, ChronoUnit.YEARS) + * ChronoLocalDate last = first.plus(1, ChronoUnit.YEARS) * .minus(1, ChronoUnit.DAYS); * System.out.printf(" Today is %s: start: %s; end: %s%n", last.getChronology().getID(), * first, last); @@ -138,22 +140,61 @@ import java.util.Objects; * @param the ChronoLocalDate of this date-time * @since 1.8 */ -abstract class ChronoDateImpl> - implements ChronoLocalDate, Temporal, TemporalAdjuster, Serializable { +abstract class ChronoDateImpl + implements ChronoLocalDate, Temporal, TemporalAdjuster, Serializable { /** * Serialization version. */ private static final long serialVersionUID = 6282433883239719096L; + /** + * Casts the {@code Temporal} to {@code ChronoLocalDate} ensuring it bas the specified chronology. + * + * @param chrono the chronology to check for, not null + * @param temporal a date-time to cast, not null + * @return the date-time checked and cast to {@code ChronoLocalDate}, not null + * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate + * or the chronology is not equal this Chronology + */ + static D ensureValid(Chronology chrono, Temporal temporal) { + @SuppressWarnings("unchecked") + D other = (D) temporal; + if (chrono.equals(other.getChronology()) == false) { + throw new ClassCastException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + other.getChronology().getId()); + } + return other; + } + + //----------------------------------------------------------------------- /** * Creates an instance. */ ChronoDateImpl() { } + @Override + @SuppressWarnings("unchecked") + public D with(TemporalAdjuster adjuster) { + return (D) ChronoLocalDate.super.with(adjuster); + } + + @Override + @SuppressWarnings("unchecked") + public D with(TemporalField field, long value) { + return (D) ChronoLocalDate.super.with(field, value); + } + + //----------------------------------------------------------------------- + @Override + @SuppressWarnings("unchecked") + public D plus(TemporalAmount amount) { + return (D) ChronoLocalDate.super.plus(amount); + } + //----------------------------------------------------------------------- @Override + @SuppressWarnings("unchecked") public D plus(long amountToAdd, TemporalUnit unit) { if (unit instanceof ChronoUnit) { ChronoUnit f = (ChronoUnit) unit; @@ -167,9 +208,21 @@ abstract class ChronoDateImpl> case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000)); case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd)); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return ChronoLocalDate.super.plus(amountToAdd, unit); + return (D) ChronoLocalDate.super.plus(amountToAdd, unit); + } + + @Override + @SuppressWarnings("unchecked") + public D minus(TemporalAmount amount) { + return (D) ChronoLocalDate.super.minus(amount); + } + + @Override + @SuppressWarnings("unchecked") + public D minus(long amountToSubtract, TemporalUnit unit) { + return (D) ChronoLocalDate.super.minus(amountToSubtract, unit); } //----------------------------------------------------------------------- @@ -254,6 +307,7 @@ abstract class ChronoDateImpl> * @return a date based on this one with the years subtracted, not null * @throws DateTimeException if the result exceeds the supported date range */ + @SuppressWarnings("unchecked") D minusYears(long yearsToSubtract) { return (yearsToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusYears(Long.MAX_VALUE)).plusYears(1) : plusYears(-yearsToSubtract)); } @@ -274,6 +328,7 @@ abstract class ChronoDateImpl> * @return a date based on this one with the months subtracted, not null * @throws DateTimeException if the result exceeds the supported date range */ + @SuppressWarnings("unchecked") D minusMonths(long monthsToSubtract) { return (monthsToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusMonths(Long.MAX_VALUE)).plusMonths(1) : plusMonths(-monthsToSubtract)); } @@ -293,6 +348,7 @@ abstract class ChronoDateImpl> * @return a date based on this one with the weeks subtracted, not null * @throws DateTimeException if the result exceeds the supported date range */ + @SuppressWarnings("unchecked") D minusWeeks(long weeksToSubtract) { return (weeksToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusWeeks(Long.MAX_VALUE)).plusWeeks(1) : plusWeeks(-weeksToSubtract)); } @@ -310,6 +366,7 @@ abstract class ChronoDateImpl> * @return a date based on this one with the days subtracted, not null * @throws DateTimeException if the result exceeds the supported date range */ + @SuppressWarnings("unchecked") D minusDays(long daysToSubtract) { return (daysToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusDays(Long.MAX_VALUE)).plusDays(1) : plusDays(-daysToSubtract)); } @@ -321,13 +378,13 @@ abstract class ChronoDateImpl> * @throws ArithmeticException {@inheritDoc} */ @Override - public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + 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; + ChronoLocalDate end = (ChronoLocalDate) endDateTime; if (getChronology().equals(end.getChronology()) == false) { throw new DateTimeException("Unable to calculate amount as objects have different chronologies"); } @@ -342,16 +399,16 @@ abstract class ChronoDateImpl> case MILLENNIA: return monthsUntil(end) / 12000; case ERAS: return end.getLong(ERA) - getLong(ERA); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.between(this, endDateTime); } - private long daysUntil(ChronoLocalDate end) { + private long daysUntil(ChronoLocalDate end) { return end.toEpochDay() - toEpochDay(); // no overflow } - private long monthsUntil(ChronoLocalDate end) { + 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"); @@ -367,7 +424,7 @@ abstract class ChronoDateImpl> return true; } if (obj instanceof ChronoLocalDate) { - return compareTo((ChronoLocalDate) obj) == 0; + return compareTo((ChronoLocalDate) obj) == 0; } return false; } diff --git a/src/share/classes/java/time/chrono/ChronoLocalDate.java b/src/share/classes/java/time/chrono/ChronoLocalDate.java index 31c08260d6e5f3a750095b8db63d6d69572b277a..923e8960b0f219fab34cec2a635673a31e693403 100644 --- a/src/share/classes/java/time/chrono/ChronoLocalDate.java +++ b/src/share/classes/java/time/chrono/ChronoLocalDate.java @@ -242,11 +242,10 @@ import java.util.Objects; * Additional calendar systems may be added to the system. * See {@link Chronology} for more details. * - * @param the concrete type for the date * @since 1.8 */ -public interface ChronoLocalDate> - extends Temporal, TemporalAdjuster, Comparable> { +public interface ChronoLocalDate + extends Temporal, TemporalAdjuster, Comparable { /** * Gets a comparator that compares {@code ChronoLocalDate} in @@ -263,7 +262,7 @@ public interface ChronoLocalDate> * @see #isBefore * @see #isEqual */ - static Comparator> timeLineOrder() { + static Comparator timeLineOrder() { return Chronology.DATE_ORDER; } @@ -289,9 +288,9 @@ public interface ChronoLocalDate> * @throws DateTimeException if unable to convert to a {@code ChronoLocalDate} * @see Chronology#date(TemporalAccessor) */ - static ChronoLocalDate from(TemporalAccessor temporal) { + static ChronoLocalDate from(TemporalAccessor temporal) { if (temporal instanceof ChronoLocalDate) { - return (ChronoLocalDate) temporal; + return (ChronoLocalDate) temporal; } Chronology chrono = temporal.query(TemporalQuery.chronology()); if (chrono == null) { @@ -367,6 +366,25 @@ public interface ChronoLocalDate> return (isLeapYear() ? 366 : 365); } + /** + * Checks if the specified field is supported. + *

                        + * This checks if the specified field can be queried on this date. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. + *

                        + * The set of supported fields is defined by the chronology and normally includes + * all {@code ChronoField} date fields. + *

                        + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field can be queried, false if not + */ @Override default boolean isSupported(TemporalField field) { if (field instanceof ChronoField) { @@ -375,6 +393,32 @@ public interface ChronoLocalDate> return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

                        + * This checks if the specified unit can be added to or subtracted from this date. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

                        + * The set of supported units is defined by the chronology and normally includes + * all {@code ChronoUnit} date units except {@code FOREVER}. + *

                        + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + default boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit.isDateBased(); + } + return unit != null && unit.isSupportedBy(this); + } + //----------------------------------------------------------------------- // override for covariant return type /** @@ -383,8 +427,8 @@ public interface ChronoLocalDate> * @throws ArithmeticException {@inheritDoc} */ @Override - default D with(TemporalAdjuster adjuster) { - return (D) getChronology().ensureChronoLocalDate(Temporal.super.with(adjuster)); + default ChronoLocalDate with(TemporalAdjuster adjuster) { + return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.with(adjuster)); } /** @@ -394,11 +438,11 @@ public interface ChronoLocalDate> * @throws ArithmeticException {@inheritDoc} */ @Override - default D with(TemporalField field, long newValue) { + default ChronoLocalDate with(TemporalField field, long newValue) { if (field instanceof ChronoField) { - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } - return (D) getChronology().ensureChronoLocalDate(field.adjustInto(this, newValue)); + return ChronoDateImpl.ensureValid(getChronology(), field.adjustInto(this, newValue)); } /** @@ -407,8 +451,8 @@ public interface ChronoLocalDate> * @throws ArithmeticException {@inheritDoc} */ @Override - default D plus(TemporalAmount amount) { - return (D) getChronology().ensureChronoLocalDate(Temporal.super.plus(amount)); + default ChronoLocalDate plus(TemporalAmount amount) { + return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.plus(amount)); } /** @@ -417,11 +461,11 @@ public interface ChronoLocalDate> * @throws ArithmeticException {@inheritDoc} */ @Override - default D plus(long amountToAdd, TemporalUnit unit) { + default ChronoLocalDate plus(long amountToAdd, TemporalUnit unit) { if (unit instanceof ChronoUnit) { - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return (D) getChronology().ensureChronoLocalDate(unit.addTo(this, amountToAdd)); + return ChronoDateImpl.ensureValid(getChronology(), unit.addTo(this, amountToAdd)); } /** @@ -430,8 +474,8 @@ public interface ChronoLocalDate> * @throws ArithmeticException {@inheritDoc} */ @Override - default D minus(TemporalAmount amount) { - return (D) getChronology().ensureChronoLocalDate(Temporal.super.minus(amount)); + default ChronoLocalDate minus(TemporalAmount amount) { + return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.minus(amount)); } /** @@ -441,8 +485,8 @@ public interface ChronoLocalDate> * @throws ArithmeticException {@inheritDoc} */ @Override - default D minus(long amountToSubtract, TemporalUnit unit) { - return (D) getChronology().ensureChronoLocalDate(Temporal.super.minus(amountToSubtract, unit)); + default ChronoLocalDate minus(long amountToSubtract, TemporalUnit unit) { + return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit)); } //----------------------------------------------------------------------- @@ -522,14 +566,14 @@ public interface ChronoLocalDate> * 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 - * using {@code startDate.periodUntil(endDate, DAYS)}. + * using {@code startDate.until(endDate, DAYS)}. *

                        * There are two equivalent ways of using this method. * The first is to invoke this method. * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

                              *   // these two lines are equivalent
                        -     *   amount = start.periodUntil(end, MONTHS);
                        +     *   amount = start.until(end, MONTHS);
                              *   amount = MONTHS.between(start, end);
                              * 
                        * The choice should be made based on which makes the code more readable. @@ -555,7 +599,7 @@ public interface ChronoLocalDate> * @throws ArithmeticException if numeric overflow occurs */ @Override // override for Javadoc - long periodUntil(Temporal endDate, TemporalUnit unit); + long until(Temporal endDate, TemporalUnit unit); /** * Calculates the period between this date and another date as a {@code Period}. @@ -575,7 +619,7 @@ public interface ChronoLocalDate> * @throws DateTimeException if the period cannot be calculated * @throws ArithmeticException if numeric overflow occurs */ - Period periodUntil(ChronoLocalDate endDate); + Period until(ChronoLocalDate endDate); /** * Formats this date using the specified formatter. @@ -606,8 +650,9 @@ public interface ChronoLocalDate> * @param localTime the local time to use, not null * @return the local date-time formed from this date and the specified time, not null */ - default ChronoLocalDateTime atTime(LocalTime localTime) { - return (ChronoLocalDateTime)ChronoLocalDateTimeImpl.of(this, localTime); + @SuppressWarnings("unchecked") + default ChronoLocalDateTime atTime(LocalTime localTime) { + return ChronoLocalDateTimeImpl.of(this, localTime); } //----------------------------------------------------------------------- @@ -656,7 +701,7 @@ public interface ChronoLocalDate> * @return the comparator value, negative if less, positive if greater */ @Override - default int compareTo(ChronoLocalDate other) { + default int compareTo(ChronoLocalDate other) { int cmp = Long.compare(toEpochDay(), other.toEpochDay()); if (cmp == 0) { cmp = getChronology().compareTo(other.getChronology()); @@ -678,7 +723,7 @@ public interface ChronoLocalDate> * @param other the other date to compare to, not null * @return true if this is after the specified date */ - default boolean isAfter(ChronoLocalDate other) { + default boolean isAfter(ChronoLocalDate other) { return this.toEpochDay() > other.toEpochDay(); } @@ -696,7 +741,7 @@ public interface ChronoLocalDate> * @param other the other date to compare to, not null * @return true if this is before the specified date */ - default boolean isBefore(ChronoLocalDate other) { + default boolean isBefore(ChronoLocalDate other) { return this.toEpochDay() < other.toEpochDay(); } @@ -714,7 +759,7 @@ public interface ChronoLocalDate> * @param other the other date to compare to, not null * @return true if the underlying date is equal to the specified date */ - default boolean isEqual(ChronoLocalDate other) { + default boolean isEqual(ChronoLocalDate other) { return this.toEpochDay() == other.toEpochDay(); } diff --git a/src/share/classes/java/time/chrono/ChronoLocalDateTime.java b/src/share/classes/java/time/chrono/ChronoLocalDateTime.java index f0a893a4c9523de658d3578f3aa8038ca9fde9eb..be93f0e036a0ab494b4c56a2208bd7fde68125c8 100644 --- a/src/share/classes/java/time/chrono/ChronoLocalDateTime.java +++ b/src/share/classes/java/time/chrono/ChronoLocalDateTime.java @@ -63,6 +63,7 @@ package java.time.chrono; import static java.time.temporal.ChronoField.EPOCH_DAY; import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoUnit.FOREVER; import static java.time.temporal.ChronoUnit.NANOS; import java.time.DateTimeException; @@ -73,6 +74,7 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; @@ -114,7 +116,7 @@ import java.util.Objects; * @param the concrete type for the date of this date-time * @since 1.8 */ -public interface ChronoLocalDateTime> +public interface ChronoLocalDateTime extends Temporal, TemporalAdjuster, Comparable> { /** @@ -191,9 +193,54 @@ public interface ChronoLocalDateTime> */ LocalTime toLocalTime(); - @Override // Override to provide javadoc + /** + * Checks if the specified field is supported. + *

                        + * This checks if the specified field can be queried on this date-time. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. + *

                        + * The set of supported fields is defined by the chronology and normally includes + * all {@code ChronoField} date and time fields. + *

                        + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field can be queried, false if not + */ + @Override boolean isSupported(TemporalField field); + /** + * Checks if the specified unit is supported. + *

                        + * This checks if the specified unit can be added to or subtracted from this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

                        + * The set of supported units is defined by the chronology and normally includes + * all {@code ChronoUnit} units except {@code FOREVER}. + *

                        + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + default boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit != FOREVER; + } + return unit != null && unit.isSupportedBy(this); + } + //----------------------------------------------------------------------- // override for covariant return type /** @@ -203,7 +250,7 @@ public interface ChronoLocalDateTime> */ @Override default ChronoLocalDateTime with(TemporalAdjuster adjuster) { - return (ChronoLocalDateTime)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.with(adjuster))); + return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.with(adjuster)); } /** @@ -221,7 +268,7 @@ public interface ChronoLocalDateTime> */ @Override default ChronoLocalDateTime plus(TemporalAmount amount) { - return (ChronoLocalDateTime)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.plus(amount))); + return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.plus(amount)); } /** @@ -239,7 +286,7 @@ public interface ChronoLocalDateTime> */ @Override default ChronoLocalDateTime minus(TemporalAmount amount) { - return (ChronoLocalDateTime)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.minus(amount))); + return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amount)); } /** @@ -249,7 +296,7 @@ public interface ChronoLocalDateTime> */ @Override default ChronoLocalDateTime minus(long amountToSubtract, TemporalUnit unit) { - return (ChronoLocalDateTime)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.minus(amountToSubtract, unit))); + return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amountToSubtract, unit)); } //----------------------------------------------------------------------- diff --git a/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java b/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java index 1f7195bc6f7f9cdf3546ef3fce17402360dc3d00..14f7bd927c232b5b62f55fd4910b23a0b799336e 100644 --- a/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java +++ b/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java @@ -98,7 +98,7 @@ import java.util.Objects; * @param the concrete type for the date of this date-time * @since 1.8 */ -final class ChronoLocalDateTimeImpl> +final class ChronoLocalDateTimeImpl implements ChronoLocalDateTime, Temporal, TemporalAdjuster, Serializable { /** @@ -171,9 +171,27 @@ final class ChronoLocalDateTimeImpl> * @param time the local time, not null * @return the local date-time, not null */ - @SuppressWarnings("rawtypes") - static ChronoLocalDateTimeImpl of(ChronoLocalDate date, LocalTime time) { - return new ChronoLocalDateTimeImpl(date, time); + static ChronoLocalDateTimeImpl of(R date, LocalTime time) { + return new ChronoLocalDateTimeImpl<>(date, time); + } + + /** + * Casts the {@code Temporal} to {@code ChronoLocalDateTime} ensuring it bas the specified chronology. + * + * @param chrono the chronology to check for, not null + * @param temporal a date-time to cast, not null + * @return the date-time checked and cast to {@code ChronoLocalDateTime}, not null + * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDateTimeImpl + * or the chronology is not equal this Chronology + */ + static ChronoLocalDateTimeImpl ensureValid(Chronology chrono, Temporal temporal) { + @SuppressWarnings("unchecked") + ChronoLocalDateTimeImpl other = (ChronoLocalDateTimeImpl) temporal; + if (chrono.equals(other.toLocalDate().getChronology()) == false) { + throw new ClassCastException("Chronology mismatch, required: " + chrono.getId() + + ", actual: " + other.toLocalDate().getChronology().getId()); + } + return other; } /** @@ -202,7 +220,7 @@ final class ChronoLocalDateTimeImpl> return this; } // Validate that the new Temporal is a ChronoLocalDate (and not something else) - D cd = (D) date.getChronology().ensureChronoLocalDate(newDate); + D cd = ChronoDateImpl.ensureValid(date.getChronology(), newDate); return new ChronoLocalDateTimeImpl<>(cd, newTime); } @@ -260,13 +278,13 @@ final class ChronoLocalDateTimeImpl> public ChronoLocalDateTimeImpl with(TemporalAdjuster adjuster) { if (adjuster instanceof ChronoLocalDate) { // The Chronology is checked in with(date,time) - return with((ChronoLocalDate) adjuster, time); + return with((ChronoLocalDate) adjuster, time); } else if (adjuster instanceof LocalTime) { return with(date, (LocalTime) adjuster); } else if (adjuster instanceof ChronoLocalDateTimeImpl) { - return (ChronoLocalDateTimeImpl)(date.getChronology().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl) adjuster)); + return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), (ChronoLocalDateTimeImpl) adjuster); } - return (ChronoLocalDateTimeImpl)(date.getChronology().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl) adjuster.adjustInto(this))); + return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), (ChronoLocalDateTimeImpl) adjuster.adjustInto(this)); } @Override @@ -279,7 +297,7 @@ final class ChronoLocalDateTimeImpl> return with(date.with(field, newValue), time); } } - return (ChronoLocalDateTimeImpl)(date.getChronology().ensureChronoLocalDateTime(field.adjustInto(this, newValue))); + return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), field.adjustInto(this, newValue)); } //----------------------------------------------------------------------- @@ -298,7 +316,7 @@ final class ChronoLocalDateTimeImpl> } return with(date.plus(amountToAdd, unit), time); } - return (ChronoLocalDateTimeImpl)(date.getChronology().ensureChronoLocalDateTime(unit.addTo(this, amountToAdd))); + return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), unit.addTo(this, amountToAdd)); } private ChronoLocalDateTimeImpl plusDays(long days) { @@ -322,7 +340,7 @@ final class ChronoLocalDateTimeImpl> } //----------------------------------------------------------------------- - private ChronoLocalDateTimeImpl plusWithOverflow(ChronoLocalDate newDate, long hours, long minutes, long seconds, long nanos) { + private ChronoLocalDateTimeImpl plusWithOverflow(D newDate, long hours, long minutes, long seconds, long nanos) { // 9223372036854775808 long, 2147483648 int if ((hours | minutes | seconds | nanos) == 0) { return with(newDate, time); @@ -351,7 +369,7 @@ final class ChronoLocalDateTimeImpl> //----------------------------------------------------------------------- @Override - public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + 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"); } @@ -361,10 +379,9 @@ final class ChronoLocalDateTimeImpl> throw new DateTimeException("Unable to calculate amount as objects have different chronologies"); } if (unit instanceof ChronoUnit) { - ChronoUnit f = (ChronoUnit) unit; - if (f.isTimeUnit()) { + if (unit.isTimeBased()) { long amount = end.getLong(EPOCH_DAY) - date.getLong(EPOCH_DAY); - switch (f) { + switch ((ChronoUnit) unit) { case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break; case MICROS: amount = Math.multiplyExact(amount, MICROS_PER_DAY); break; case MILLIS: amount = Math.multiplyExact(amount, MILLIS_PER_DAY); break; @@ -373,13 +390,13 @@ final class ChronoLocalDateTimeImpl> case HOURS: amount = Math.multiplyExact(amount, HOURS_PER_DAY); break; case HALF_DAYS: amount = Math.multiplyExact(amount, 2); break; } - return Math.addExact(amount, time.periodUntil(end.toLocalTime(), unit)); + return Math.addExact(amount, time.until(end.toLocalTime(), unit)); } - D endDate = end.toLocalDate(); + ChronoLocalDate endDate = end.toLocalDate(); if (end.toLocalTime().isBefore(time)) { endDate = endDate.minus(1, ChronoUnit.DAYS); } - return date.periodUntil(endDate, unit); + return date.until(endDate, unit); } return unit.between(this, endDateTime); } @@ -404,7 +421,7 @@ final class ChronoLocalDateTimeImpl> } static ChronoLocalDateTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - ChronoLocalDate date = (ChronoLocalDate) in.readObject(); + ChronoLocalDate date = (ChronoLocalDate) in.readObject(); LocalTime time = (LocalTime) in.readObject(); return date.atTime(time); } diff --git a/src/share/classes/java/time/chrono/ChronoZonedDateTime.java b/src/share/classes/java/time/chrono/ChronoZonedDateTime.java index d838a36ec292cb32756ba616be45053193dac42a..dd911fcd789647af34697c15f0018f7fba18d645 100644 --- a/src/share/classes/java/time/chrono/ChronoZonedDateTime.java +++ b/src/share/classes/java/time/chrono/ChronoZonedDateTime.java @@ -63,6 +63,7 @@ package java.time.chrono; import static java.time.temporal.ChronoField.INSTANT_SECONDS; import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoUnit.FOREVER; import static java.time.temporal.ChronoUnit.NANOS; import java.time.DateTimeException; @@ -73,6 +74,7 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; @@ -115,7 +117,7 @@ import java.util.Objects; * @param the concrete type for the date of this date-time * @since 1.8 */ -public interface ChronoZonedDateTime> +public interface ChronoZonedDateTime extends Temporal, Comparable> { /** @@ -338,9 +340,54 @@ public interface ChronoZonedDateTime> */ ChronoZonedDateTime withZoneSameInstant(ZoneId zone); - @Override // Override to provide javadoc + /** + * Checks if the specified field is supported. + *

                        + * This checks if the specified field can be queried on this date-time. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. + *

                        + * The set of supported fields is defined by the chronology and normally includes + * all {@code ChronoField} fields. + *

                        + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field can be queried, false if not + */ + @Override boolean isSupported(TemporalField field); + /** + * Checks if the specified unit is supported. + *

                        + * This checks if the specified unit can be added to or subtracted from this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

                        + * The set of supported units is defined by the chronology and normally includes + * all {@code ChronoUnit} units except {@code FOREVER}. + *

                        + * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + default boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit != FOREVER; + } + return unit != null && unit.isSupportedBy(this); + } + //----------------------------------------------------------------------- // override for covariant return type /** @@ -350,7 +397,7 @@ public interface ChronoZonedDateTime> */ @Override default ChronoZonedDateTime with(TemporalAdjuster adjuster) { - return (ChronoZonedDateTime)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.with(adjuster))); + return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.with(adjuster)); } /** @@ -368,7 +415,7 @@ public interface ChronoZonedDateTime> */ @Override default ChronoZonedDateTime plus(TemporalAmount amount) { - return (ChronoZonedDateTime)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.plus(amount))); + return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.plus(amount)); } /** @@ -386,7 +433,7 @@ public interface ChronoZonedDateTime> */ @Override default ChronoZonedDateTime minus(TemporalAmount amount) { - return (ChronoZonedDateTime)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.minus(amount))); + return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amount)); } /** @@ -396,7 +443,7 @@ public interface ChronoZonedDateTime> */ @Override default ChronoZonedDateTime minus(long amountToSubtract, TemporalUnit unit) { - return (ChronoZonedDateTime)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.minus(amountToSubtract, unit))); + return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amountToSubtract, unit)); } //----------------------------------------------------------------------- diff --git a/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java b/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java index 835ec9321847ae56064e157a49f901a2327187a6..a39ed298d37f8748b55b7c986a0c75ba12feda5e 100644 --- a/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java +++ b/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java @@ -101,7 +101,7 @@ import java.util.Objects; * @param the concrete type for the date of this date-time * @since 1.8 */ -final class ChronoZonedDateTimeImpl> +final class ChronoZonedDateTimeImpl implements ChronoZonedDateTime, Serializable { /** @@ -131,7 +131,7 @@ final class ChronoZonedDateTimeImpl> * @param preferredOffset the zone offset, null if no preference * @return the zoned date-time, not null */ - static > ChronoZonedDateTime ofBest( + static ChronoZonedDateTime ofBest( ChronoLocalDateTimeImpl localDateTime, ZoneId zone, ZoneOffset preferredOffset) { Objects.requireNonNull(localDateTime, "localDateTime"); Objects.requireNonNull(zone, "zone"); @@ -167,14 +167,13 @@ final class ChronoZonedDateTimeImpl> * @param zone the zone identifier, not null * @return the zoned date-time, not null */ - @SuppressWarnings("rawtypes") static ChronoZonedDateTimeImpl ofInstant(Chronology chrono, Instant instant, ZoneId zone) { ZoneRules rules = zone.getRules(); ZoneOffset offset = rules.getOffset(instant); Objects.requireNonNull(offset, "offset"); // protect against bad ZoneRules LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset); - ChronoLocalDateTimeImpl cldt = (ChronoLocalDateTimeImpl) chrono.localDateTime(ldt); - return new ChronoZonedDateTimeImpl(cldt, offset, zone); + ChronoLocalDateTimeImpl cldt = (ChronoLocalDateTimeImpl)chrono.localDateTime(ldt); + return new ChronoZonedDateTimeImpl<>(cldt, offset, zone); } /** @@ -184,10 +183,30 @@ final class ChronoZonedDateTimeImpl> * @param zone the time-zone to use, validated not null * @return the zoned date-time, validated not null */ + @SuppressWarnings("unchecked") private ChronoZonedDateTimeImpl create(Instant instant, ZoneId zone) { return (ChronoZonedDateTimeImpl)ofInstant(toLocalDate().getChronology(), instant, zone); } + /** + * Casts the {@code Temporal} to {@code ChronoZonedDateTimeImpl} ensuring it bas the specified chronology. + * + * @param chrono the chronology to check for, not null + * @param temporal a date-time to cast, not null + * @return the date-time checked and cast to {@code ChronoZonedDateTimeImpl}, not null + * @throws ClassCastException if the date-time cannot be cast to ChronoZonedDateTimeImpl + * or the chronology is not equal this Chronology + */ + static ChronoZonedDateTimeImpl ensureValid(Chronology chrono, Temporal temporal) { + @SuppressWarnings("unchecked") + ChronoZonedDateTimeImpl other = (ChronoZonedDateTimeImpl) temporal; + if (chrono.equals(other.toLocalDate().getChronology()) == false) { + throw new ClassCastException("Chronology mismatch, required: " + chrono.getId() + + ", actual: " + other.toLocalDate().getChronology().getId()); + } + return other; + } + //----------------------------------------------------------------------- /** * Constructor. @@ -271,7 +290,7 @@ final class ChronoZonedDateTimeImpl> } return ofBest(dateTime.with(field, newValue), zone, offset); } - return (ChronoZonedDateTime)(toLocalDate().getChronology().ensureChronoZonedDateTime(field.adjustInto(this, newValue))); + return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), field.adjustInto(this, newValue)); } //----------------------------------------------------------------------- @@ -280,12 +299,12 @@ final class ChronoZonedDateTimeImpl> if (unit instanceof ChronoUnit) { return with(dateTime.plus(amountToAdd, unit)); } - return (ChronoZonedDateTime)(toLocalDate().getChronology().ensureChronoZonedDateTime(unit.addTo(this, amountToAdd))); /// TODO: Generics replacement Risk! + return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), unit.addTo(this, amountToAdd)); /// TODO: Generics replacement Risk! } //----------------------------------------------------------------------- @Override - public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + 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"); } @@ -296,7 +315,7 @@ final class ChronoZonedDateTimeImpl> } if (unit instanceof ChronoUnit) { end = end.withZoneSameInstant(offset); - return dateTime.periodUntil(end.toLocalDateTime(), unit); + return dateTime.until(end.toLocalDateTime(), unit); } return unit.between(this, endDateTime); } diff --git a/src/share/classes/java/time/chrono/Chronology.java b/src/share/classes/java/time/chrono/Chronology.java index e5daae764645a4faff914a5b653ba8a0ddf91816..561e2f794faa0dabfbeebeacfa618f19a0c45006 100644 --- a/src/share/classes/java/time/chrono/Chronology.java +++ b/src/share/classes/java/time/chrono/Chronology.java @@ -74,6 +74,9 @@ import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.TemporalAdjuster.nextOrSame; import java.io.DataInput; @@ -88,14 +91,16 @@ 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.ChronoUnit; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; import java.time.temporal.UnsupportedTemporalTypeException; @@ -188,8 +193,8 @@ public abstract class Chronology implements Comparable { /** * ChronoLocalDate order constant. */ - static final Comparator> DATE_ORDER = - (Comparator> & Serializable) (date1, date2) -> { + static final Comparator DATE_ORDER = + (Comparator & Serializable) (date1, date2) -> { return Long.compare(date1.toEpochDay(), date2.toEpochDay()); }; /** @@ -480,60 +485,6 @@ public abstract class Chronology implements Comparable { protected Chronology() { } - //----------------------------------------------------------------------- - /** - * Casts the {@code Temporal} to {@code ChronoLocalDate} with the same chronology. - * - * @param temporal a date-time to cast, not null - * @return the date-time checked and cast to {@code ChronoLocalDate}, not null - * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate - * or the chronology is not equal this Chronology - */ - ChronoLocalDate ensureChronoLocalDate(Temporal temporal) { - @SuppressWarnings("unchecked") - ChronoLocalDate other = (ChronoLocalDate) temporal; - if (this.equals(other.getChronology()) == false) { - throw new ClassCastException("Chronology mismatch, expected: " + getId() + ", actual: " + other.getChronology().getId()); - } - return other; - } - - /** - * Casts the {@code Temporal} to {@code ChronoLocalDateTime} with the same chronology. - * - * @param temporal a date-time to cast, not null - * @return the date-time checked and cast to {@code ChronoLocalDateTime}, not null - * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDateTimeImpl - * or the chronology is not equal this Chronology - */ - ChronoLocalDateTimeImpl ensureChronoLocalDateTime(Temporal temporal) { - @SuppressWarnings("unchecked") - ChronoLocalDateTimeImpl other = (ChronoLocalDateTimeImpl) temporal; - if (this.equals(other.toLocalDate().getChronology()) == false) { - throw new ClassCastException("Chronology mismatch, required: " + getId() - + ", supplied: " + other.toLocalDate().getChronology().getId()); - } - return other; - } - - /** - * Casts the {@code Temporal} to {@code ChronoZonedDateTimeImpl} with the same chronology. - * - * @param temporal a date-time to cast, not null - * @return the date-time checked and cast to {@code ChronoZonedDateTimeImpl}, not null - * @throws ClassCastException if the date-time cannot be cast to ChronoZonedDateTimeImpl - * or the chronology is not equal this Chronology - */ - ChronoZonedDateTimeImpl ensureChronoZonedDateTime(Temporal temporal) { - @SuppressWarnings("unchecked") - ChronoZonedDateTimeImpl other = (ChronoZonedDateTimeImpl) temporal; - if (this.equals(other.toLocalDate().getChronology()) == false) { - throw new ClassCastException("Chronology mismatch, required: " + getId() - + ", supplied: " + other.toLocalDate().getChronology().getId()); - } - return other; - } - //----------------------------------------------------------------------- /** * Gets the ID of the chronology. @@ -574,7 +525,7 @@ public abstract class Chronology implements Comparable { * @throws DateTimeException if unable to create the date * @throws ClassCastException if the {@code era} is not of the correct type for the chronology */ - public ChronoLocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) { + public ChronoLocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) { return date(prolepticYear(era, yearOfEra), month, dayOfMonth); } @@ -588,7 +539,7 @@ public abstract class Chronology implements Comparable { * @return the local date in this chronology, not null * @throws DateTimeException if unable to create the date */ - public abstract ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth); + public abstract ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth); /** * Obtains a local date in this chronology from the era, year-of-era and @@ -601,7 +552,7 @@ public abstract class Chronology implements Comparable { * @throws DateTimeException if unable to create the date * @throws ClassCastException if the {@code era} is not of the correct type for the chronology */ - public ChronoLocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { + public ChronoLocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear); } @@ -614,7 +565,7 @@ public abstract class Chronology implements Comparable { * @return the local date in this chronology, not null * @throws DateTimeException if unable to create the date */ - public abstract ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear); + public abstract ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear); /** * Obtains a local date in this chronology from the epoch-day. @@ -626,7 +577,7 @@ public abstract class Chronology implements Comparable { * @return the local date in this chronology, not null * @throws DateTimeException if unable to create the date */ - public abstract ChronoLocalDate dateEpochDay(long epochDay); + public abstract ChronoLocalDate dateEpochDay(long epochDay); //----------------------------------------------------------------------- /** @@ -643,7 +594,7 @@ public abstract class Chronology implements Comparable { * @return the current local date using the system clock and default time-zone, not null * @throws DateTimeException if unable to create the date */ - public ChronoLocalDate dateNow() { + public ChronoLocalDate dateNow() { return dateNow(Clock.systemDefaultZone()); } @@ -660,7 +611,7 @@ public abstract class Chronology implements Comparable { * @return the current local date using the system clock, not null * @throws DateTimeException if unable to create the date */ - public ChronoLocalDate dateNow(ZoneId zone) { + public ChronoLocalDate dateNow(ZoneId zone) { return dateNow(Clock.system(zone)); } @@ -675,7 +626,7 @@ public abstract class Chronology implements Comparable { * @return the current local date, not null * @throws DateTimeException if unable to create the date */ - public ChronoLocalDate dateNow(Clock clock) { + public ChronoLocalDate dateNow(Clock clock) { Objects.requireNonNull(clock, "clock"); return date(LocalDate.now(clock)); } @@ -699,7 +650,7 @@ public abstract class Chronology implements Comparable { * @throws DateTimeException if unable to create the date * @see ChronoLocalDate#from(TemporalAccessor) */ - public abstract ChronoLocalDate date(TemporalAccessor temporal); + public abstract ChronoLocalDate date(TemporalAccessor temporal); /** * Obtains a local date-time in this chronology from another temporal object. @@ -722,7 +673,7 @@ public abstract class Chronology implements Comparable { * @throws DateTimeException if unable to create the date-time * @see ChronoLocalDateTime#from(TemporalAccessor) */ - public ChronoLocalDateTime localDateTime(TemporalAccessor temporal) { + public ChronoLocalDateTime localDateTime(TemporalAccessor temporal) { try { return date(temporal).atTime(LocalTime.from(temporal)); } catch (DateTimeException ex) { @@ -754,7 +705,7 @@ public abstract class Chronology implements Comparable { * @throws DateTimeException if unable to create the date-time * @see ChronoZonedDateTime#from(TemporalAccessor) */ - public ChronoZonedDateTime zonedDateTime(TemporalAccessor temporal) { + public ChronoZonedDateTime zonedDateTime(TemporalAccessor temporal) { try { ZoneId zone = ZoneId.from(temporal); try { @@ -762,8 +713,7 @@ public abstract class Chronology implements Comparable { return zonedDateTime(instant, zone); } catch (DateTimeException ex1) { - @SuppressWarnings("rawtypes") - ChronoLocalDateTimeImpl cldt = ensureChronoLocalDateTime(localDateTime(temporal)); + ChronoLocalDateTimeImpl cldt = ChronoLocalDateTimeImpl.ensureValid(this, localDateTime(temporal)); return ChronoZonedDateTimeImpl.ofBest(cldt, zone, null); } } catch (DateTimeException ex) { @@ -781,7 +731,7 @@ public abstract class Chronology implements Comparable { * @return the zoned date-time, not null * @throws DateTimeException if the result exceeds the supported range */ - public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { + public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { return ChronoZonedDateTimeImpl.ofInstant(this, instant, zone); } @@ -929,11 +879,82 @@ public abstract class Chronology implements Comparable { * As such, {@code ChronoField} date fields are resolved here in the * context of a specific chronology. *

                        + * {@code ChronoField} instances are resolved by this method, which may + * be overridden in subclasses. + *

                          + *
                        • {@code EPOCH_DAY} - If present, this is converted to a date and + * all other date fields are then cross-checked against the date. + *
                        • {@code PROLEPTIC_MONTH} - If present, then it is split into the + * {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart + * then the field is validated. + *
                        • {@code YEAR_OF_ERA} and {@code ERA} - If both are present, then they + * are combined to form a {@code YEAR}. In lenient mode, the {@code YEAR_OF_ERA} + * range is not validated, in smart and strict mode it is. The {@code ERA} is + * validated for range in all three modes. If only the {@code YEAR_OF_ERA} is + * present, and the mode is smart or lenient, then the last available era + * is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is + * left untouched. If only the {@code ERA} is present, then it is left untouched. + *
                        • {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} - + * If all three are present, then they are combined to form a date. + * In all three modes, the {@code YEAR} is validated. + * If the mode is smart or strict, then the month and day are validated. + * If the mode is lenient, then the date is combined in a manner equivalent to + * creating a date on the first day of the first month in the requested year, + * then adding the difference in months, then the difference in days. + * If the mode is smart, and the day-of-month is greater than the maximum for + * the year-month, then the day-of-month is adjusted to the last day-of-month. + * If the mode is strict, then the three fields must form a valid date. + *
                        • {@code YEAR} and {@code DAY_OF_YEAR} - + * If both are present, then they are combined to form a date. + * In all three modes, the {@code YEAR} is validated. + * If the mode is lenient, then the date is combined in a manner equivalent to + * creating a date on the first day of the requested year, then adding + * the difference in days. + * If the mode is smart or strict, then the two fields must form a valid date. + *
                        • {@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and + * {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} - + * If all four are present, then they are combined to form a date. + * In all three modes, the {@code YEAR} is validated. + * If the mode is lenient, then the date is combined in a manner equivalent to + * creating a date on the first day of the first month in the requested year, then adding + * the difference in months, then the difference in weeks, then in days. + * If the mode is smart or strict, then the all four fields are validated to + * their outer ranges. The date is then combined in a manner equivalent to + * creating a date on the first day of the requested year and month, then adding + * the amount in weeks and days to reach their values. If the mode is strict, + * the date is additionally validated to check that the day and week adjustment + * did not change the month. + *
                        • {@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and + * {@code DAY_OF_WEEK} - If all four are present, then they are combined to + * form a date. The approach is the same as described above for + * years, months and weeks in {@code ALIGNED_DAY_OF_WEEK_IN_MONTH}. + * The day-of-week is adjusted as the next or same matching day-of-week once + * the years, months and weeks have been handled. + *
                        • {@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} - + * If all three are present, then they are combined to form a date. + * In all three modes, the {@code YEAR} is validated. + * If the mode is lenient, then the date is combined in a manner equivalent to + * creating a date on the first day of the requested year, then adding + * the difference in weeks, then in days. + * If the mode is smart or strict, then the all three fields are validated to + * their outer ranges. The date is then combined in a manner equivalent to + * creating a date on the first day of the requested year, then adding + * the amount in weeks and days to reach their values. If the mode is strict, + * the date is additionally validated to check that the day and week adjustment + * did not change the year. + *
                        • {@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code DAY_OF_WEEK} - + * If all three are present, then they are combined to form a date. + * The approach is the same as described above for years and weeks in + * {@code ALIGNED_DAY_OF_WEEK_IN_YEAR}. The day-of-week is adjusted as the + * next or same matching day-of-week once the years and weeks have been handled. + *
                        + *

                        * The default implementation is suitable for most calendar systems. * If {@link ChronoField#YEAR_OF_ERA} is found without an {@link ChronoField#ERA} * then the last era in {@link #eras()} is used. * The implementation assumes a 7 day week, that the first day-of-month - * has the value 1, and that first day-of-year has the value 1. + * has the value 1, that first day-of-year has the value 1, and that the + * first of the month and year always exists. * * @param fieldValues the map of fields to values, which can be updated, not null * @param resolverStyle the requested type of resolve, not null @@ -941,99 +962,214 @@ public abstract class Chronology implements Comparable { * @throws DateTimeException if the date cannot be resolved, typically * because of a conflict in the input data */ - public ChronoLocalDate resolveDate(Map fieldValues, ResolverStyle resolverStyle) { + public ChronoLocalDate resolveDate(Map fieldValues, ResolverStyle resolverStyle) { // check epoch-day before inventing era if (fieldValues.containsKey(EPOCH_DAY)) { return dateEpochDay(fieldValues.remove(EPOCH_DAY)); } // fix proleptic month before inventing era - Long pMonth = fieldValues.remove(PROLEPTIC_MONTH); - if (pMonth != null) { - // first day-of-month is likely to be safest for setting proleptic-month - // cannot add to year zero, as not all chronologies have a year zero - ChronoLocalDate chronoDate = dateNow() - .with(DAY_OF_MONTH, 1).with(PROLEPTIC_MONTH, pMonth); - addFieldValue(fieldValues, MONTH_OF_YEAR, chronoDate.get(MONTH_OF_YEAR)); - addFieldValue(fieldValues, YEAR, chronoDate.get(YEAR)); - } + resolveProlepticMonth(fieldValues, resolverStyle); // invent era if necessary to resolve year-of-era - Long yoeLong = fieldValues.remove(YEAR_OF_ERA); - if (yoeLong != null) { - Long eraLong = fieldValues.remove(ERA); - int yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA); - if (eraLong != null) { - Era eraObj = eraOf(Math.toIntExact(eraLong)); - addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe)); - } else if (fieldValues.containsKey(YEAR)) { - int year = range(YEAR).checkValidIntValue(fieldValues.get(YEAR), YEAR); - ChronoLocalDate chronoDate = dateYearDay(year, 1); - addFieldValue(fieldValues, YEAR, prolepticYear(chronoDate.getEra(), yoe)); - } else { - List eras = eras(); - if (eras.isEmpty()) { - addFieldValue(fieldValues, YEAR, yoe); - } else { - Era eraObj = eras.get(eras.size() - 1); - addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe)); - } - } + ChronoLocalDate resolved = resolveYearOfEra(fieldValues, resolverStyle); + if (resolved != null) { + return resolved; } // build date if (fieldValues.containsKey(YEAR)) { if (fieldValues.containsKey(MONTH_OF_YEAR)) { if (fieldValues.containsKey(DAY_OF_MONTH)) { - int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); - int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); - int dom = range(DAY_OF_MONTH).checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH); - return date(y, moy, dom); + return resolveYMD(fieldValues, resolverStyle); } if (fieldValues.containsKey(ALIGNED_WEEK_OF_MONTH)) { if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_MONTH)) { - int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); - int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); - int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH); - int ad = range(ALIGNED_DAY_OF_WEEK_IN_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), ALIGNED_DAY_OF_WEEK_IN_MONTH); - ChronoLocalDate chronoDate = date(y, moy, 1); - return chronoDate.plus((aw - 1) * 7 + (ad - 1), ChronoUnit.DAYS); + return resolveYMAA(fieldValues, resolverStyle); } if (fieldValues.containsKey(DAY_OF_WEEK)) { - int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); - int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); - int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH); - int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK); - ChronoLocalDate chronoDate = date(y, moy, 1); - return chronoDate.plus((aw - 1) * 7, ChronoUnit.DAYS).with(nextOrSame(DayOfWeek.of(dow))); + return resolveYMAD(fieldValues, resolverStyle); } } } if (fieldValues.containsKey(DAY_OF_YEAR)) { - int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); - int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR); - return dateYearDay(y, doy); + return resolveYD(fieldValues, resolverStyle); } if (fieldValues.containsKey(ALIGNED_WEEK_OF_YEAR)) { if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_YEAR)) { - int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); - int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR); - int ad = range(ALIGNED_DAY_OF_WEEK_IN_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), ALIGNED_DAY_OF_WEEK_IN_YEAR); - ChronoLocalDate chronoDate = dateYearDay(y, 1); - return chronoDate.plus((aw - 1) * 7 + (ad - 1), ChronoUnit.DAYS); + return resolveYAA(fieldValues, resolverStyle); } if (fieldValues.containsKey(DAY_OF_WEEK)) { - int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); - int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR); - int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK); - ChronoLocalDate chronoDate = dateYearDay(y, 1); - return chronoDate.plus((aw - 1) * 7, ChronoUnit.DAYS).with(nextOrSame(DayOfWeek.of(dow))); + return resolveYAD(fieldValues, resolverStyle); + } + } + } + return null; + } + + void resolveProlepticMonth(Map fieldValues, ResolverStyle resolverStyle) { + Long pMonth = fieldValues.remove(PROLEPTIC_MONTH); + if (pMonth != null) { + if (resolverStyle != ResolverStyle.LENIENT) { + PROLEPTIC_MONTH.checkValidValue(pMonth); + } + // first day-of-month is likely to be safest for setting proleptic-month + // cannot add to year zero, as not all chronologies have a year zero + ChronoLocalDate chronoDate = dateNow() + .with(DAY_OF_MONTH, 1).with(PROLEPTIC_MONTH, pMonth); + addFieldValue(fieldValues, MONTH_OF_YEAR, chronoDate.get(MONTH_OF_YEAR)); + addFieldValue(fieldValues, YEAR, chronoDate.get(YEAR)); + } + } + + ChronoLocalDate resolveYearOfEra(Map fieldValues, ResolverStyle resolverStyle) { + Long yoeLong = fieldValues.remove(YEAR_OF_ERA); + if (yoeLong != null) { + Long eraLong = fieldValues.remove(ERA); + int yoe; + if (resolverStyle != ResolverStyle.LENIENT) { + yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA); + } else { + yoe = Math.toIntExact(yoeLong); + } + if (eraLong != null) { + Era eraObj = eraOf(range(ERA).checkValidIntValue(eraLong, ERA)); + addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe)); + } else { + if (fieldValues.containsKey(YEAR)) { + int year = range(YEAR).checkValidIntValue(fieldValues.get(YEAR), YEAR); + ChronoLocalDate chronoDate = dateYearDay(year, 1); + addFieldValue(fieldValues, YEAR, prolepticYear(chronoDate.getEra(), yoe)); + } else if (resolverStyle == ResolverStyle.STRICT) { + // do not invent era if strict + // reinstate the field removed earlier, no cross-check issues + fieldValues.put(YEAR_OF_ERA, yoeLong); + } else { + List eras = eras(); + if (eras.isEmpty()) { + addFieldValue(fieldValues, YEAR, yoe); + } else { + Era eraObj = eras.get(eras.size() - 1); + addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe)); + } } } + } else if (fieldValues.containsKey(ERA)) { + range(ERA).checkValidValue(fieldValues.get(ERA), ERA); // always validated } return null; } + ChronoLocalDate resolveYMD(Map fieldValues, ResolverStyle resolverStyle) { + int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); + if (resolverStyle == ResolverStyle.LENIENT) { + long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); + long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1); + return date(y, 1, 1).plus(months, MONTHS).plus(days, DAYS); + } + int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); + ValueRange domRange = range(DAY_OF_MONTH); + int dom = domRange.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH); + if (resolverStyle == ResolverStyle.SMART) { // previous valid + try { + return date(y, moy, dom); + } catch (DateTimeException ex) { + return date(y, moy, 1).with(TemporalAdjuster.lastDayOfMonth()); + } + } + return date(y, moy, dom); + } + + ChronoLocalDate resolveYD(Map fieldValues, ResolverStyle resolverStyle) { + int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); + if (resolverStyle == ResolverStyle.LENIENT) { + long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1); + return dateYearDay(y, 1).plus(days, DAYS); + } + int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR); + return dateYearDay(y, doy); // smart is same as strict + } + + ChronoLocalDate resolveYMAA(Map fieldValues, ResolverStyle resolverStyle) { + int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); + if (resolverStyle == ResolverStyle.LENIENT) { + long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); + long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1); + long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), 1); + return date(y, 1, 1).plus(months, MONTHS).plus(weeks, WEEKS).plus(days, DAYS); + } + int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); + int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH); + int ad = range(ALIGNED_DAY_OF_WEEK_IN_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), ALIGNED_DAY_OF_WEEK_IN_MONTH); + ChronoLocalDate date = date(y, moy, 1).plus((aw - 1) * 7 + (ad - 1), DAYS); + if (resolverStyle == ResolverStyle.STRICT && date.get(MONTH_OF_YEAR) != moy) { + throw new DateTimeException("Strict mode rejected resolved date as it is in a different month"); + } + return date; + } + + ChronoLocalDate resolveYMAD(Map fieldValues, ResolverStyle resolverStyle) { + int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); + if (resolverStyle == ResolverStyle.LENIENT) { + long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); + long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1); + long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1); + return resolveAligned(date(y, 1, 1), months, weeks, dow); + } + int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); + int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH); + int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK); + ChronoLocalDate date = date(y, moy, 1).plus((aw - 1) * 7, DAYS).with(nextOrSame(DayOfWeek.of(dow))); + if (resolverStyle == ResolverStyle.STRICT && date.get(MONTH_OF_YEAR) != moy) { + throw new DateTimeException("Strict mode rejected resolved date as it is in a different month"); + } + return date; + } + + ChronoLocalDate resolveYAA(Map fieldValues, ResolverStyle resolverStyle) { + int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); + if (resolverStyle == ResolverStyle.LENIENT) { + long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1); + long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), 1); + return dateYearDay(y, 1).plus(weeks, WEEKS).plus(days, DAYS); + } + int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR); + int ad = range(ALIGNED_DAY_OF_WEEK_IN_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), ALIGNED_DAY_OF_WEEK_IN_YEAR); + ChronoLocalDate date = dateYearDay(y, 1).plus((aw - 1) * 7 + (ad - 1), DAYS); + if (resolverStyle == ResolverStyle.STRICT && date.get(YEAR) != y) { + throw new DateTimeException("Strict mode rejected resolved date as it is in a different year"); + } + return date; + } + + ChronoLocalDate resolveYAD(Map fieldValues, ResolverStyle resolverStyle) { + int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); + if (resolverStyle == ResolverStyle.LENIENT) { + long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1); + long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1); + return resolveAligned(dateYearDay(y, 1), 0, weeks, dow); + } + int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR); + int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK); + ChronoLocalDate date = dateYearDay(y, 1).plus((aw - 1) * 7, DAYS).with(nextOrSame(DayOfWeek.of(dow))); + if (resolverStyle == ResolverStyle.STRICT && date.get(YEAR) != y) { + throw new DateTimeException("Strict mode rejected resolved date as it is in a different year"); + } + return date; + } + + ChronoLocalDate resolveAligned(ChronoLocalDate base, long months, long weeks, long dow) { + ChronoLocalDate date = base.plus(months, MONTHS).plus(weeks, WEEKS); + if (dow > 7) { + date = date.plus((dow - 1) / 7, WEEKS); + dow = ((dow - 1) % 7) + 1; + } else if (dow < 1) { + date = date.plus(Math.subtractExact(dow, 7) / 7, WEEKS); + dow = ((dow + 6) % 7) + 1; + } + return date.with(nextOrSame(DayOfWeek.of((int) dow))); + } + /** * Adds a field-value pair to the map, checking for conflicts. *

                        diff --git a/src/share/classes/java/time/chrono/Era.java b/src/share/classes/java/time/chrono/Era.java index 330346dcc360ee91057629b8ec95cdb6535f0870..0fd31c9887dff908d10d5daf0887d24c2d178cb0 100644 --- a/src/share/classes/java/time/chrono/Era.java +++ b/src/share/classes/java/time/chrono/Era.java @@ -238,7 +238,7 @@ public interface Era extends TemporalAccessor, TemporalAdjuster { if (field == ERA) { return getValue(); } else if (field instanceof ChronoField) { - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } diff --git a/src/share/classes/java/time/chrono/HijrahChronology.java b/src/share/classes/java/time/chrono/HijrahChronology.java index 63dfc1c213ba62bccfdf0a9733e88e34007193fb..c5061b05a323ae895311d8abb8c2e472f70bc281 100644 --- a/src/share/classes/java/time/chrono/HijrahChronology.java +++ b/src/share/classes/java/time/chrono/HijrahChronology.java @@ -71,8 +71,10 @@ import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; +import java.time.format.ResolverStyle; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; import java.time.temporal.ValueRange; import java.util.Arrays; import java.util.HashMap; @@ -115,7 +117,7 @@ import sun.util.logging.PlatformLogger; *

                      * * - * + * * * * @@ -126,10 +128,10 @@ import sun.util.logging.PlatformLogger; *

                      * Selecting the chronology from the locale uses {@link Chronology#ofLocale} * to find the Chronology based on Locale supported BCP 47 extension mechanism - * to request a specific calendar ("ca") and variant ("cv"). For example, + * to request a specific calendar ("ca"). For example, *

                      *
                      - *      Locale locale = Locale.forLanguageTag("en-US-u-ca-islamic-cv-umalqura");
                      + *      Locale locale = Locale.forLanguageTag("en-US-u-ca-islamic-umalqura");
                        *      Chronology chrono = Chronology.ofLocale(locale);
                        * 
                      * @@ -472,11 +474,16 @@ public final class HijrahChronology extends Chronology implements Serializable { * @param prolepticYear the proleptic-year * @param dayOfYear the day-of-year * @return the Hijrah local date, not null - * @throws DateTimeException if unable to create the date + * @throws DateTimeException if the value of the year is out of range, + * or if the day-of-year is invalid for the year */ @Override public HijrahDate dateYearDay(int prolepticYear, int dayOfYear) { - return HijrahDate.of(this, prolepticYear, 1, 1).plusDays(dayOfYear - 1); // TODO better + HijrahDate date = HijrahDate.of(this, prolepticYear, 1, 1); + if (dayOfYear > date.lengthOfYear()) { + throw new DateTimeException("Invalid dayOfYear: " + dayOfYear); + } + return date.plusDays(dayOfYear - 1); } /** @@ -515,16 +522,19 @@ public final class HijrahChronology extends Chronology implements Serializable { } @Override + @SuppressWarnings("unchecked") public ChronoLocalDateTime localDateTime(TemporalAccessor temporal) { return (ChronoLocalDateTime) super.localDateTime(temporal); } @Override + @SuppressWarnings("unchecked") public ChronoZonedDateTime zonedDateTime(TemporalAccessor temporal) { return (ChronoZonedDateTime) super.zonedDateTime(temporal); } @Override + @SuppressWarnings("unchecked") public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { return (ChronoZonedDateTime) super.zonedDateTime(instant, zone); } @@ -550,7 +560,7 @@ public final class HijrahChronology extends Chronology implements Serializable { } @Override - public Era eraOf(int eraValue) { + public HijrahEra eraOf(int eraValue) { switch (eraValue) { case 1: return HijrahEra.AH; @@ -580,6 +590,8 @@ public final class HijrahChronology extends Chronology implements Serializable { case YEAR: case YEAR_OF_ERA: return ValueRange.of(getMinimumYear(), getMaximumYear()); + case ERA: + return ValueRange.of(1, 1); default: return field.range(); } @@ -587,6 +599,13 @@ public final class HijrahChronology extends Chronology implements Serializable { return field.range(); } + //----------------------------------------------------------------------- + @Override // override for return type + public HijrahDate resolveDate(Map fieldValues, ResolverStyle resolverStyle) { + return (HijrahDate) super.resolveDate(fieldValues, resolverStyle); + } + + //----------------------------------------------------------------------- /** * Check the validity of a year. * diff --git a/src/share/classes/java/time/chrono/HijrahDate.java b/src/share/classes/java/time/chrono/HijrahDate.java index 3c01e94b9805782dd6a06c8a95c16054b947073b..ef40b6dc94839ddd762a14db7802bab1e891ae4b 100644 --- a/src/share/classes/java/time/chrono/HijrahDate.java +++ b/src/share/classes/java/time/chrono/HijrahDate.java @@ -109,7 +109,7 @@ import java.time.temporal.ValueRange; */ public final class HijrahDate extends ChronoDateImpl - implements ChronoLocalDate, Serializable { + implements ChronoLocalDate, Serializable { /** * Serialization version. @@ -204,7 +204,7 @@ public final class HijrahDate * @throws DateTimeException if the current date cannot be obtained */ public static HijrahDate now(Clock clock) { - return HijrahChronology.INSTANCE.date(LocalDate.now(clock)); + return HijrahDate.ofEpochDay(HijrahChronology.INSTANCE, LocalDate.now(clock).toEpochDay()); } /** @@ -349,7 +349,7 @@ public final class HijrahDate } return getChronology().range(f); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.rangeRefinedBy(this); } @@ -372,7 +372,7 @@ public final class HijrahDate case YEAR: return prolepticYear; case ERA: return getEraValue(); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } @@ -393,7 +393,7 @@ public final class HijrahDate case ALIGNED_DAY_OF_WEEK_IN_MONTH: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_MONTH)); case ALIGNED_DAY_OF_WEEK_IN_YEAR: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_YEAR)); case DAY_OF_MONTH: return resolvePreviousValid(prolepticYear, monthOfYear, nvalue); - case DAY_OF_YEAR: return resolvePreviousValid(prolepticYear, ((nvalue - 1) / 30) + 1, ((nvalue - 1) % 30) + 1); + case DAY_OF_YEAR: return plusDays(Math.min(nvalue, lengthOfYear()) - getDayOfYear()); case EPOCH_DAY: return new HijrahDate(chrono, newValue); case ALIGNED_WEEK_OF_MONTH: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_MONTH)) * 7); case ALIGNED_WEEK_OF_YEAR: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_YEAR)) * 7); @@ -403,9 +403,9 @@ public final class HijrahDate case YEAR: return resolvePreviousValid(nvalue, monthOfYear, dayOfMonth); case ERA: return resolvePreviousValid(1 - prolepticYear, monthOfYear, dayOfMonth); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } - return ChronoLocalDate.super.with(field, newValue); + return super.with(field, newValue); } private HijrahDate resolvePreviousValid(int prolepticYear, int month, int day) { @@ -479,7 +479,7 @@ public final class HijrahDate * @return the day-of-year */ private int getDayOfYear() { - return chrono.getDayOfYear(prolepticYear, monthOfYear); + return chrono.getDayOfYear(prolepticYear, monthOfYear) + dayOfMonth; } /** @@ -575,12 +575,13 @@ public final class HijrahDate } @Override // for javadoc and covariant return type + @SuppressWarnings("unchecked") public final ChronoLocalDateTime atTime(LocalTime localTime) { - return super.atTime(localTime); + return (ChronoLocalDateTime)super.atTime(localTime); } @Override - public Period periodUntil(ChronoLocalDate endDate) { + public Period until(ChronoLocalDate endDate) { // TODO: untested HijrahDate end = getChronology().date(endDate); long totalMonths = (end.prolepticYear - this.prolepticYear) * 12 + (end.monthOfYear - this.monthOfYear); // safe @@ -622,7 +623,7 @@ public final class HijrahDate return this; } - static ChronoLocalDate readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + static HijrahDate readExternal(ObjectInput in) throws IOException, ClassNotFoundException { HijrahChronology chrono = (HijrahChronology) in.readObject(); int year = in.readInt(); int month = in.readByte(); diff --git a/src/share/classes/java/time/chrono/IsoChronology.java b/src/share/classes/java/time/chrono/IsoChronology.java index 66b0dc10d23e4f36dfe981636f605fed4b778936..a2f6badeaa524b544cc6ab749debd1965a077ffa 100644 --- a/src/share/classes/java/time/chrono/IsoChronology.java +++ b/src/share/classes/java/time/chrono/IsoChronology.java @@ -61,25 +61,16 @@ */ package java.time.chrono; -import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; -import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; -import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; -import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; import static java.time.temporal.ChronoField.DAY_OF_MONTH; -import static java.time.temporal.ChronoField.DAY_OF_WEEK; -import static java.time.temporal.ChronoField.DAY_OF_YEAR; -import static java.time.temporal.ChronoField.EPOCH_DAY; import static java.time.temporal.ChronoField.ERA; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; -import static java.time.temporal.TemporalAdjuster.nextOrSame; import java.io.Serializable; import java.time.Clock; import java.time.DateTimeException; -import java.time.DayOfWeek; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; @@ -398,7 +389,7 @@ public final class IsoChronology extends Chronology implements Serializable { } @Override - public Era eraOf(int eraValue) { + public IsoEra eraOf(int eraValue) { return IsoEra.of(eraValue); } @@ -421,7 +412,7 @@ public final class IsoChronology extends Chronology implements Serializable { * as follows. *
                        *
                      • {@code EPOCH_DAY} - If present, this is converted to a {@code LocalDate} - * all other date fields are then cross-checked against the date + * and all other date fields are then cross-checked against the date. *
                      • {@code PROLEPTIC_MONTH} - If present, then it is split into the * {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart * then the field is validated. @@ -430,7 +421,7 @@ public final class IsoChronology extends Chronology implements Serializable { * range is not validated, in smart and strict mode it is. The {@code ERA} is * validated for range in all three modes. If only the {@code YEAR_OF_ERA} is * present, and the mode is smart or lenient, then the current era (CE/AD) - * is assumed. In strict mode, no ers is assumed and the {@code YEAR_OF_ERA} is + * is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is * left untouched. If only the {@code ERA} is present, then it is left untouched. *
                      • {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} - * If all three are present, then they are combined to form a {@code LocalDate}. @@ -495,48 +486,11 @@ public final class IsoChronology extends Chronology implements Serializable { */ @Override // override for performance public LocalDate resolveDate(Map fieldValues, ResolverStyle resolverStyle) { - // check epoch-day before inventing era - if (fieldValues.containsKey(EPOCH_DAY)) { - return LocalDate.ofEpochDay(fieldValues.remove(EPOCH_DAY)); - } - - // fix proleptic month before inventing era - resolveProlepticMonth(fieldValues, resolverStyle); - - // invent era if necessary to resolve year-of-era - resolveYearOfEra(fieldValues, resolverStyle); - - // build date - if (fieldValues.containsKey(YEAR)) { - if (fieldValues.containsKey(MONTH_OF_YEAR)) { - if (fieldValues.containsKey(DAY_OF_MONTH)) { - return resolveYMD(fieldValues, resolverStyle); - } - if (fieldValues.containsKey(ALIGNED_WEEK_OF_MONTH)) { - if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_MONTH)) { - return resolveYMAA(fieldValues, resolverStyle); - } - if (fieldValues.containsKey(DAY_OF_WEEK)) { - return resolveYMAD(fieldValues, resolverStyle); - } - } - } - if (fieldValues.containsKey(DAY_OF_YEAR)) { - return resolveYD(fieldValues, resolverStyle); - } - if (fieldValues.containsKey(ALIGNED_WEEK_OF_YEAR)) { - if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_YEAR)) { - return resolveYAA(fieldValues, resolverStyle); - } - if (fieldValues.containsKey(DAY_OF_WEEK)) { - return resolveYAD(fieldValues, resolverStyle); - } - } - } - return null; + return (LocalDate) super.resolveDate(fieldValues, resolverStyle); } - private void resolveProlepticMonth(Map fieldValues, ResolverStyle resolverStyle) { + @Override // override for better proleptic algorithm + void resolveProlepticMonth(Map fieldValues, ResolverStyle resolverStyle) { Long pMonth = fieldValues.remove(PROLEPTIC_MONTH); if (pMonth != null) { if (resolverStyle != ResolverStyle.LENIENT) { @@ -547,7 +501,8 @@ public final class IsoChronology extends Chronology implements Serializable { } } - private void resolveYearOfEra(Map fieldValues, ResolverStyle resolverStyle) { + @Override // override for enhanced behaviour + LocalDate resolveYearOfEra(Map fieldValues, ResolverStyle resolverStyle) { Long yoeLong = fieldValues.remove(YEAR_OF_ERA); if (yoeLong != null) { if (resolverStyle != ResolverStyle.LENIENT) { @@ -575,10 +530,14 @@ public final class IsoChronology extends Chronology implements Serializable { } else { throw new DateTimeException("Invalid value for era: " + era); } + } else if (fieldValues.containsKey(ERA)) { + ERA.checkValidValue(fieldValues.get(ERA)); // always validated } + return null; } - private LocalDate resolveYMD(Map fieldValues, ResolverStyle resolverStyle) { + @Override // override for performance + LocalDate resolveYMD(Map fieldValues, ResolverStyle resolverStyle) { int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR)); if (resolverStyle == ResolverStyle.LENIENT) { long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); @@ -598,96 +557,6 @@ public final class IsoChronology extends Chronology implements Serializable { return LocalDate.of(y, moy, dom); } - private LocalDate resolveYD(Map fieldValues, ResolverStyle resolverStyle) { - int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR)); - if (resolverStyle == ResolverStyle.LENIENT) { - long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1); - return LocalDate.of(y, 1, 1).plusDays(days); - } - int doy = DAY_OF_YEAR.checkValidIntValue(fieldValues.remove(DAY_OF_YEAR)); - return LocalDate.ofYearDay(y, doy); // smart is same as strict - } - - private LocalDate resolveYMAA(Map fieldValues, ResolverStyle resolverStyle) { - int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR)); - if (resolverStyle == ResolverStyle.LENIENT) { - long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); - long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1); - long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), 1); - return LocalDate.of(y, 1, 1).plusMonths(months).plusWeeks(weeks).plusDays(days); - } - int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR)); - int aw = ALIGNED_WEEK_OF_MONTH.checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH)); - int ad = ALIGNED_DAY_OF_WEEK_IN_MONTH.checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH)); - LocalDate date = LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7 + (ad - 1)); - if (resolverStyle == ResolverStyle.STRICT && date.getMonthValue() != moy) { - throw new DateTimeException("Strict mode rejected resolved date as it is in a different month"); - } - return date; - } - - private LocalDate resolveYMAD(Map fieldValues, ResolverStyle resolverStyle) { - int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR)); - if (resolverStyle == ResolverStyle.LENIENT) { - long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); - long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1); - long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1); - return resolveAligned(y, months, weeks, dow); - } - int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR)); - int aw = ALIGNED_WEEK_OF_MONTH.checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH)); - int dow = DAY_OF_WEEK.checkValidIntValue(fieldValues.remove(DAY_OF_WEEK)); - LocalDate date = LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow))); - if (resolverStyle == ResolverStyle.STRICT && date.getMonthValue() != moy) { - throw new DateTimeException("Strict mode rejected resolved date as it is in a different month"); - } - return date; - } - - private LocalDate resolveYAA(Map fieldValues, ResolverStyle resolverStyle) { - int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR)); - if (resolverStyle == ResolverStyle.LENIENT) { - long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1); - long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), 1); - return LocalDate.of(y, 1, 1).plusWeeks(weeks).plusDays(days); - } - int aw = ALIGNED_WEEK_OF_YEAR.checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR)); - int ad = ALIGNED_DAY_OF_WEEK_IN_YEAR.checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR)); - LocalDate date = LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7 + (ad - 1)); - if (resolverStyle == ResolverStyle.STRICT && date.getYear() != y) { - throw new DateTimeException("Strict mode rejected resolved date as it is in a different year"); - } - return date; - } - - private LocalDate resolveYAD(Map fieldValues, ResolverStyle resolverStyle) { - int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR)); - if (resolverStyle == ResolverStyle.LENIENT) { - long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1); - long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1); - return resolveAligned(y, 0, weeks, dow); - } - int aw = ALIGNED_WEEK_OF_YEAR.checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR)); - int dow = DAY_OF_WEEK.checkValidIntValue(fieldValues.remove(DAY_OF_WEEK)); - LocalDate date = LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow))); - if (resolverStyle == ResolverStyle.STRICT && date.getYear() != y) { - throw new DateTimeException("Strict mode rejected resolved date as it is in a different year"); - } - return date; - } - - private LocalDate resolveAligned(int y, long months, long weeks, long dow) { - LocalDate date = LocalDate.of(y, 1, 1).plusMonths(months).plusWeeks(weeks); - if (dow > 7) { - date = date.plusWeeks((dow - 1) / 7); - dow = ((dow - 1) % 7) + 1; - } else if (dow < 1) { - date = date.plusWeeks(Math.subtractExact(dow, 7) / 7); - dow = ((dow + 6) % 7) + 1; - } - return date.with(nextOrSame(DayOfWeek.of((int) dow))); - } - //----------------------------------------------------------------------- @Override public ValueRange range(ChronoField field) { diff --git a/src/share/classes/java/time/chrono/JapaneseChronology.java b/src/share/classes/java/time/chrono/JapaneseChronology.java index 1aead71b8ad3006ecd65b959227aa1298ef9c7ae..68a12755ea30aff50caf2ebb73018417f53e3de3 100644 --- a/src/share/classes/java/time/chrono/JapaneseChronology.java +++ b/src/share/classes/java/time/chrono/JapaneseChronology.java @@ -56,6 +56,15 @@ */ package java.time.chrono; +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; +import static java.time.temporal.ChronoField.ERA; +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 static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.MONTHS; + import java.io.Serializable; import java.time.Clock; import java.time.DateTimeException; @@ -63,13 +72,18 @@ import java.time.Instant; import java.time.LocalDate; import java.time.Year; import java.time.ZoneId; +import java.time.format.ResolverStyle; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalField; +import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.Arrays; import java.util.Calendar; import java.util.List; import java.util.Locale; +import java.util.Map; import sun.util.calendar.CalendarSystem; import sun.util.calendar.LocalGregorianCalendar; @@ -82,8 +96,22 @@ import sun.util.calendar.LocalGregorianCalendar; * The Japanese Imperial calendar system is the same as the ISO calendar system * apart from the era-based year numbering. *

                        - * Only Meiji (1865-04-07 - 1868-09-07) and later eras are supported. - * Older eras are handled as an unknown era where the year-of-era is the ISO year. + * Japan introduced the Gregorian calendar starting with Meiji 6. + * Only Meiji and later eras are supported; + * dates before Meiji 6, January 1 are not supported. + *

                        + * The supported {@code ChronoField} instances are: + *

                          + *
                        • {@code DAY_OF_WEEK} + *
                        • {@code DAY_OF_MONTH} + *
                        • {@code DAY_OF_YEAR} + *
                        • {@code EPOCH_DAY} + *
                        • {@code MONTH_OF_YEAR} + *
                        • {@code PROLEPTIC_MONTH} + *
                        • {@code YEAR_OF_ERA} + *
                        • {@code YEAR} + *
                        • {@code ERA} + *
                        * * @implSpec * This class is immutable and thread-safe. @@ -91,7 +119,6 @@ import sun.util.calendar.LocalGregorianCalendar; * @since 1.8 */ public final class JapaneseChronology extends Chronology implements Serializable { - // TODO: definition for unknown era may break requirement that year-of-era >= 1 static final LocalGregorianCalendar JCAL = (LocalGregorianCalendar) CalendarSystem.forName("japanese"); @@ -152,6 +179,16 @@ public final class JapaneseChronology extends Chronology implements Serializable /** * Obtains a local date in Japanese calendar system from the * era, year-of-era, month-of-year and day-of-month fields. + *

                        + * The Japanese month and day-of-month are the same as those in the + * ISO calendar system. They are not reset when the era changes. + * For example: + *

                        +     *  6th Jan Showa 64 = ISO 1989-01-06
                        +     *  7th Jan Showa 64 = ISO 1989-01-07
                        +     *  8th Jan Heisei 1 = ISO 1989-01-08
                        +     *  9th Jan Heisei 1 = ISO 1989-01-09
                        +     * 
                        * * @param era the Japanese era, not null * @param yearOfEra the year-of-era @@ -172,6 +209,9 @@ public final class JapaneseChronology extends Chronology implements Serializable /** * Obtains a local date in Japanese calendar system from the * proleptic-year, month-of-year and day-of-month fields. + *

                        + * The Japanese proleptic year, month and day-of-month are the same as those + * in the ISO calendar system. They are not reset when the era changes. * * @param prolepticYear the proleptic-year * @param month the month-of-year @@ -187,6 +227,17 @@ public final class JapaneseChronology extends Chronology implements Serializable /** * Obtains a local date in Japanese calendar system from the * era, year-of-era and day-of-year fields. + *

                        + * The day-of-year in this factory is expressed relative to the start of the year-of-era. + * This definition changes the normal meaning of day-of-year only in those years + * where the year-of-era is reset to one due to a change in the era. + * For example: + *

                        +     *  6th Jan Showa 64 = day-of-year 6
                        +     *  7th Jan Showa 64 = day-of-year 7
                        +     *  8th Jan Heisei 1 = day-of-year 1
                        +     *  9th Jan Heisei 1 = day-of-year 2
                        +     * 
                        * * @param era the Japanese era, not null * @param yearOfEra the year-of-era @@ -203,6 +254,10 @@ public final class JapaneseChronology extends Chronology implements Serializable /** * Obtains a local date in Japanese calendar system from the * proleptic-year and day-of-year fields. + *

                        + * The day-of-year in this factory is expressed relative to the start of the proleptic year. + * The Japanese proleptic year and day-of-year are the same as those in the ISO calendar system. + * They are not reset when the era changes. * * @param prolepticYear the proleptic-year * @param dayOfYear the day-of-year @@ -211,8 +266,7 @@ public final class JapaneseChronology extends Chronology implements Serializable */ @Override public JapaneseDate dateYearDay(int prolepticYear, int dayOfYear) { - LocalDate date = LocalDate.ofYearDay(prolepticYear, dayOfYear); - return date(prolepticYear, date.getMonthValue(), date.getDayOfMonth()); + return new JapaneseDate(LocalDate.ofYearDay(prolepticYear, dayOfYear)); } /** @@ -290,15 +344,6 @@ public final class JapaneseChronology extends Chronology implements Serializable throw new ClassCastException("Era must be JapaneseEra"); } - if (era == JapaneseEra.SEIREKI) { - JapaneseEra nextEra = JapaneseEra.values()[1]; - int nextEraYear = nextEra.getPrivateEra().getSinceDate().getYear(); - if (yearOfEra >= nextEraYear || yearOfEra < Year.MIN_VALUE) { - throw new DateTimeException("Invalid yearOfEra value"); - } - return yearOfEra; - } - JapaneseEra jera = (JapaneseEra) era; int gregorianYear = jera.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1; if (yearOfEra == 1) { @@ -320,14 +365,13 @@ public final class JapaneseChronology extends Chronology implements Serializable * See the description of each Era for the numeric values of: * {@link JapaneseEra#HEISEI}, {@link JapaneseEra#SHOWA},{@link JapaneseEra#TAISHO}, * {@link JapaneseEra#MEIJI}), only Meiji and later eras are supported. - * Prior to Meiji {@link JapaneseEra#SEIREKI} is used. * * @param eraValue the era value * @return the Japanese {@code Era} for the given numeric era value * @throws DateTimeException if {@code eraValue} is invalid */ @Override - public Era eraOf(int eraValue) { + public JapaneseEra eraOf(int eraValue) { return JapaneseEra.of(eraValue); } @@ -346,49 +390,117 @@ public final class JapaneseChronology extends Chronology implements Serializable @Override public ValueRange range(ChronoField field) { switch (field) { - case YEAR: - case DAY_OF_MONTH: - case DAY_OF_WEEK: - case MICRO_OF_DAY: - case MICRO_OF_SECOND: - case HOUR_OF_DAY: - case HOUR_OF_AMPM: - case MINUTE_OF_DAY: - case MINUTE_OF_HOUR: - case SECOND_OF_DAY: - case SECOND_OF_MINUTE: - case MILLI_OF_DAY: - case MILLI_OF_SECOND: - case NANO_OF_DAY: - case NANO_OF_SECOND: - case CLOCK_HOUR_OF_DAY: - case CLOCK_HOUR_OF_AMPM: - case EPOCH_DAY: - case PROLEPTIC_MONTH: - case MONTH_OF_YEAR: - return field.range(); - case ERA: - return ValueRange.of(JapaneseEra.SEIREKI.getValue(), - getCurrentEra().getValue()); - } - Calendar jcal = Calendar.getInstance(LOCALE); - int fieldIndex; - switch (field) { + case ALIGNED_DAY_OF_WEEK_IN_MONTH: + case ALIGNED_DAY_OF_WEEK_IN_YEAR: + case ALIGNED_WEEK_OF_MONTH: + case ALIGNED_WEEK_OF_YEAR: + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); case YEAR_OF_ERA: { + Calendar jcal = Calendar.getInstance(LOCALE); int startYear = getCurrentEra().getPrivateEra().getSinceDate().getYear(); - return ValueRange.of(Year.MIN_VALUE, jcal.getGreatestMinimum(Calendar.YEAR), + return ValueRange.of(1, jcal.getGreatestMinimum(Calendar.YEAR), jcal.getLeastMaximum(Calendar.YEAR) + 1, // +1 due to the different definitions Year.MAX_VALUE - startYear); } - case DAY_OF_YEAR: - fieldIndex = Calendar.DAY_OF_YEAR; - break; + case DAY_OF_YEAR: { + Calendar jcal = Calendar.getInstance(LOCALE); + int fieldIndex = Calendar.DAY_OF_YEAR; + return ValueRange.of(jcal.getMinimum(fieldIndex), jcal.getGreatestMinimum(fieldIndex), + jcal.getLeastMaximum(fieldIndex), jcal.getMaximum(fieldIndex)); + } + case YEAR: + return ValueRange.of(JapaneseDate.MEIJI_6_ISODATE.getYear(), Year.MAX_VALUE); + case ERA: + return ValueRange.of(JapaneseEra.MEIJI.getValue(), getCurrentEra().getValue()); default: - // TODO: review the remaining fields - throw new UnsupportedOperationException("Unimplementable field: " + field); + return field.range(); + } + } + + //----------------------------------------------------------------------- + @Override // override for return type + public JapaneseDate resolveDate(Map fieldValues, ResolverStyle resolverStyle) { + return (JapaneseDate) super.resolveDate(fieldValues, resolverStyle); + } + + @Override // override for special Japanese behavior + ChronoLocalDate resolveYearOfEra(Map fieldValues, ResolverStyle resolverStyle) { + // validate era and year-of-era + Long eraLong = fieldValues.get(ERA); + JapaneseEra era = null; + if (eraLong != null) { + era = eraOf(range(ERA).checkValidIntValue(eraLong, ERA)); // always validated + } + Long yoeLong = fieldValues.get(YEAR_OF_ERA); + int yoe = 0; + if (yoeLong != null) { + yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA); // always validated + } + // if only year-of-era and no year then invent era unless strict + if (era == null && yoeLong != null && fieldValues.containsKey(YEAR) == false && resolverStyle != ResolverStyle.STRICT) { + era = JapaneseEra.values()[JapaneseEra.values().length - 1]; + } + // if both present, then try to create date + if (yoeLong != null && era != null) { + if (fieldValues.containsKey(MONTH_OF_YEAR)) { + if (fieldValues.containsKey(DAY_OF_MONTH)) { + return resolveYMD(era, yoe, fieldValues, resolverStyle); + } + } + if (fieldValues.containsKey(DAY_OF_YEAR)) { + return resolveYD(era, yoe, fieldValues, resolverStyle); + } + } + return null; + } + + private int prolepticYearLenient(JapaneseEra era, int yearOfEra) { + return era.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1; + } + + private ChronoLocalDate resolveYMD(JapaneseEra era, int yoe, Map fieldValues, ResolverStyle resolverStyle) { + fieldValues.remove(ERA); + fieldValues.remove(YEAR_OF_ERA); + if (resolverStyle == ResolverStyle.LENIENT) { + int y = prolepticYearLenient(era, yoe); + long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); + long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1); + return date(y, 1, 1).plus(months, MONTHS).plus(days, DAYS); + } + int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); + int dom = range(DAY_OF_MONTH).checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH); + if (resolverStyle == ResolverStyle.SMART) { // previous valid + if (yoe < 1) { + throw new DateTimeException("Invalid YearOfEra: " + yoe); + } + int y = prolepticYearLenient(era, yoe); + JapaneseDate result; + try { + result = date(y, moy, dom); + } catch (DateTimeException ex) { + result = date(y, moy, 1).with(TemporalAdjuster.lastDayOfMonth()); + } + // handle the era being changed + // only allow if the new date is in the same Jan-Dec as the era change + // determine by ensuring either original yoe or result yoe is 1 + if (result.getEra() != era && result.get(YEAR_OF_ERA) > 1 && yoe > 1) { + throw new DateTimeException("Invalid YearOfEra for Era: " + era + " " + yoe); + } + return result; + } + return date(era, yoe, moy, dom); + } + + private ChronoLocalDate resolveYD(JapaneseEra era, int yoe, Map fieldValues, ResolverStyle resolverStyle) { + fieldValues.remove(ERA); + fieldValues.remove(YEAR_OF_ERA); + if (resolverStyle == ResolverStyle.LENIENT) { + int y = prolepticYearLenient(era, yoe); + long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1); + return dateYearDay(y, 1).plus(days, DAYS); } - return ValueRange.of(jcal.getMinimum(fieldIndex), jcal.getGreatestMinimum(fieldIndex), - jcal.getLeastMaximum(fieldIndex), jcal.getMaximum(fieldIndex)); + int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR); + return dateYearDay(era, yoe, doy); // smart is same as strict } } diff --git a/src/share/classes/java/time/chrono/JapaneseDate.java b/src/share/classes/java/time/chrono/JapaneseDate.java index 646315b3d809e864a59b415c15f312f98991847a..e49a8f33c75533af25fb0127a5ce63a660c2c757 100644 --- a/src/share/classes/java/time/chrono/JapaneseDate.java +++ b/src/share/classes/java/time/chrono/JapaneseDate.java @@ -56,9 +56,15 @@ */ package java.time.chrono; +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; import static java.time.temporal.ChronoField.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; @@ -96,6 +102,10 @@ import sun.util.calendar.LocalGregorianCalendar; * apart from the era-based year numbering. The proleptic-year is defined to be * equal to the ISO proleptic-year. *

                        + * Japan introduced the Gregorian calendar starting with Meiji 6. + * Only Meiji and later eras are supported; + * dates before Meiji 6, January 1 are not supported. + *

                        * For example, the Japanese year "Heisei 24" corresponds to ISO year "2012".
                        * Calling {@code japaneseDate.get(YEAR_OF_ERA)} will return 24.
                        * Calling {@code japaneseDate.get(YEAR)} will return 2012.
                        @@ -109,7 +119,7 @@ import sun.util.calendar.LocalGregorianCalendar; */ public final class JapaneseDate extends ChronoDateImpl - implements ChronoLocalDate, Serializable { + implements ChronoLocalDate, Serializable { /** * Serialization version. @@ -129,6 +139,11 @@ public final class JapaneseDate */ private transient int yearOfEra; + /** + * The first day supported by the JapaneseChronology is Meiji 6, January 1st. + */ + final static LocalDate MEIJI_6_ISODATE = LocalDate.of(1873, 1, 1); + //----------------------------------------------------------------------- /** * Obtains the current {@code JapaneseDate} from the system clock in the default time-zone. @@ -173,7 +188,7 @@ public final class JapaneseDate * @throws DateTimeException if the current date cannot be obtained */ public static JapaneseDate now(Clock clock) { - return JapaneseChronology.INSTANCE.date(LocalDate.now(clock)); + return new JapaneseDate(LocalDate.now(clock)); } /** @@ -182,6 +197,16 @@ public final class JapaneseDate *

                        * This returns a {@code JapaneseDate} with the specified fields. * The day must be valid for the year and month, otherwise an exception will be thrown. + *

                        + * The Japanese month and day-of-month are the same as those in the + * ISO calendar system. They are not reset when the era changes. + * For example: + *

                        +     *  6th Jan Showa 64 = ISO 1989-01-06
                        +     *  7th Jan Showa 64 = ISO 1989-01-07
                        +     *  8th Jan Heisei 1 = ISO 1989-01-08
                        +     *  9th Jan Heisei 1 = ISO 1989-01-09
                        +     * 
                        * * @param era the Japanese era, not null * @param yearOfEra the Japanese year-of-era @@ -192,11 +217,15 @@ public final class JapaneseDate * or if the day-of-month is invalid for the month-year, * or if the date is not a Japanese era */ - public static JapaneseDate of(Era era, int yearOfEra, int month, int dayOfMonth) { - if (era instanceof JapaneseEra == false) { - throw new ClassCastException("Era must be JapaneseEra"); + public static JapaneseDate of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth) { + Objects.requireNonNull(era, "era"); + LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null); + jdate.setEra(era.getPrivateEra()).setDate(yearOfEra, month, dayOfMonth); + if (!JapaneseChronology.JCAL.validate(jdate)) { + throw new DateTimeException("year, month, and day not valid for Era"); } - return JapaneseDate.of((JapaneseEra) era, yearOfEra, month, dayOfMonth); + LocalDate date = LocalDate.of(jdate.getNormalizedYear(), month, dayOfMonth); + return new JapaneseDate(era, yearOfEra, date); } /** @@ -205,6 +234,9 @@ public final class JapaneseDate *

                        * This returns a {@code JapaneseDate} with the specified fields. * The day must be valid for the year and month, otherwise an exception will be thrown. + *

                        + * The Japanese proleptic year, month and day-of-month are the same as those + * in the ISO calendar system. They are not reset when the era changes. * * @param prolepticYear the Japanese proleptic-year * @param month the Japanese month-of-year, from 1 to 12 @@ -219,23 +251,31 @@ public final class JapaneseDate /** * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar - * system from the proleptic-year and day-of-year fields. + * system from the era, year-of-era and day-of-year fields. *

                        * This returns a {@code JapaneseDate} with the specified fields. * The day must be valid for the year, otherwise an exception will be thrown. + *

                        + * The day-of-year in this factory is expressed relative to the start of the year-of-era. + * This definition changes the normal meaning of day-of-year only in those years + * where the year-of-era is reset to one due to a change in the era. + * For example: + *

                        +     *  6th Jan Showa 64 = day-of-year 6
                        +     *  7th Jan Showa 64 = day-of-year 7
                        +     *  8th Jan Heisei 1 = day-of-year 1
                        +     *  9th Jan Heisei 1 = day-of-year 2
                        +     * 
                        * - * @param prolepticYear the chronology proleptic-year + * @param era the Japanese era, not null + * @param yearOfEra the Japanese year-of-era * @param dayOfYear the chronology day-of-year, from 1 to 366 * @return the date in Japanese calendar system, not null * @throws DateTimeException if the value of any field is out of range, * or if the day-of-year is invalid for the year */ - public static JapaneseDate ofYearDay(int prolepticYear, int dayOfYear) { - LocalDate date = LocalDate.ofYearDay(prolepticYear, dayOfYear); - return of(prolepticYear, date.getMonthValue(), date.getDayOfMonth()); - } - static JapaneseDate ofYearDay(JapaneseEra era, int yearOfEra, int dayOfYear) { + Objects.requireNonNull(era, "era"); CalendarDate firstDay = era.getPrivateEra().getSinceDate(); LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null); jdate.setEra(era.getPrivateEra()); @@ -253,32 +293,6 @@ public final class JapaneseDate return new JapaneseDate(era, yearOfEra, localdate); } - /** - * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar - * system from the era, year-of-era, month-of-year and day-of-month fields. - *

                        - * This returns a {@code JapaneseDate} with the specified fields. - * The day must be valid for the year and month, otherwise an exception will be thrown. - * - * @param era the Japanese era, not null - * @param yearOfEra the Japanese year-of-era - * @param month the Japanese month-of-year, from 1 to 12 - * @param dayOfMonth the Japanese day-of-month, from 1 to 31 - * @return the date in Japanese calendar system, not null - * @throws DateTimeException if the value of any field is out of range, - * or if the day-of-month is invalid for the month-year - */ - static JapaneseDate of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth) { - Objects.requireNonNull(era, "era"); - LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null); - jdate.setEra(era.getPrivateEra()).setDate(yearOfEra, month, dayOfMonth); - if (!JapaneseChronology.JCAL.validate(jdate)) { - throw new DateTimeException("year, month, and day not valid for Era"); - } - LocalDate date = LocalDate.of(jdate.getNormalizedYear(), month, dayOfMonth); - return new JapaneseDate(era, yearOfEra, date); - } - /** * Obtains a {@code JapaneseDate} from a temporal object. *

                        @@ -307,6 +321,9 @@ public final class JapaneseDate * @param isoDate the standard local date, validated not null */ JapaneseDate(LocalDate isoDate) { + if (isoDate.isBefore(MEIJI_6_ISODATE)) { + throw new DateTimeException("JapaneseDate before Meiji 6 is not supported"); + } LocalGregorianCalendar.Date jdate = toPrivateJapaneseDate(isoDate); this.era = JapaneseEra.toJapaneseEra(jdate.getEra()); this.yearOfEra = jdate.getYear(); @@ -322,6 +339,9 @@ public final class JapaneseDate * @param isoDate the standard local date, validated not null */ JapaneseDate(JapaneseEra era, int year, LocalDate isoDate) { + if (isoDate.isBefore(MEIJI_6_ISODATE)) { + throw new DateTimeException("JapaneseDate before Meiji 6 is not supported"); + } this.era = era; this.yearOfEra = year; this.isoDate = isoDate; @@ -366,55 +386,99 @@ public final class JapaneseDate return isoDate.lengthOfMonth(); } + @Override + public int lengthOfYear() { + Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE); + jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET); + jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth()); + return jcal.getActualMaximum(Calendar.DAY_OF_YEAR); + } + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + *

                        + * This checks if this date can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range} and + * {@link #get(TemporalField) get} methods will throw an exception. + *

                        + * If the field is a {@link ChronoField} then the query is implemented here. + * The supported fields are: + *

                          + *
                        • {@code DAY_OF_WEEK} + *
                        • {@code DAY_OF_MONTH} + *
                        • {@code DAY_OF_YEAR} + *
                        • {@code EPOCH_DAY} + *
                        • {@code MONTH_OF_YEAR} + *
                        • {@code PROLEPTIC_MONTH} + *
                        • {@code YEAR_OF_ERA} + *
                        • {@code YEAR} + *
                        • {@code ERA} + *
                        + * All other {@code ChronoField} instances will return false. + *

                        + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this date, false if not + */ + @Override + public boolean isSupported(TemporalField field) { + if (field == ALIGNED_DAY_OF_WEEK_IN_MONTH || field == ALIGNED_DAY_OF_WEEK_IN_YEAR || + field == ALIGNED_WEEK_OF_MONTH || field == ALIGNED_WEEK_OF_YEAR) { + return false; + } + return ChronoLocalDate.super.isSupported(field); + } + @Override public ValueRange range(TemporalField field) { if (field instanceof ChronoField) { if (isSupported(field)) { ChronoField f = (ChronoField) field; switch (f) { - case DAY_OF_MONTH: - case ALIGNED_WEEK_OF_MONTH: - return isoDate.range(field); - case DAY_OF_YEAR: - return actualRange(Calendar.DAY_OF_YEAR); - case YEAR_OF_ERA: - return actualRange(Calendar.YEAR); + case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth()); + case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear()); + case YEAR_OF_ERA: { + Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE); + jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET); + jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth()); + return ValueRange.of(1, jcal.getActualMaximum(Calendar.YEAR)); + } } return getChronology().range(f); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.rangeRefinedBy(this); } - private ValueRange actualRange(int calendarField) { - Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE); - jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET); // TODO: cannot calculate this way for SEIREKI - jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth()); - return ValueRange.of(jcal.getActualMinimum(calendarField), - jcal.getActualMaximum(calendarField)); - } - @Override public long getLong(TemporalField field) { if (field instanceof ChronoField) { // same as ISO: - // DAY_OF_WEEK, ALIGNED_DAY_OF_WEEK_IN_MONTH, DAY_OF_MONTH, EPOCH_DAY, - // ALIGNED_WEEK_OF_MONTH, MONTH_OF_YEAR, PROLEPTIC_MONTH, YEAR + // DAY_OF_WEEK, DAY_OF_MONTH, EPOCH_DAY, MONTH_OF_YEAR, PROLEPTIC_MONTH, YEAR // // calendar specific fields - // ALIGNED_DAY_OF_WEEK_IN_YEAR, DAY_OF_YEAR, ALIGNED_WEEK_OF_YEAR, YEAR_OF_ERA, ERA + // DAY_OF_YEAR, YEAR_OF_ERA, ERA switch ((ChronoField) field) { + case ALIGNED_DAY_OF_WEEK_IN_MONTH: + case ALIGNED_DAY_OF_WEEK_IN_YEAR: + case ALIGNED_WEEK_OF_MONTH: + case ALIGNED_WEEK_OF_YEAR: + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); case YEAR_OF_ERA: return yearOfEra; case ERA: return era.getValue(); - case DAY_OF_YEAR: { - LocalGregorianCalendar.Date jdate = toPrivateJapaneseDate(isoDate); - return JapaneseChronology.JCAL.getDayOfYear(jdate); - } - // TODO: ALIGNED_DAY_OF_WEEK_IN_YEAR and ALIGNED_WEEK_OF_YEAR ??? + case DAY_OF_YEAR: + Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE); + jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET); + jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth()); + return jcal.get(Calendar.DAY_OF_YEAR); } return isoDate.getLong(field); } @@ -444,7 +508,7 @@ public final class JapaneseDate public JapaneseDate with(TemporalField field, long newValue) { if (field instanceof ChronoField) { ChronoField f = (ChronoField) field; - if (getLong(f) == newValue) { + if (getLong(f) == newValue) { // getLong() validates for supported fields return this; } switch (f) { @@ -464,10 +528,9 @@ public final class JapaneseDate } } // YEAR, PROLEPTIC_MONTH and others are same as ISO - // TODO: review other fields, such as WEEK_OF_YEAR return with(isoDate.with(field, newValue)); } - return ChronoLocalDate.super.with(field, newValue); + return super.with(field, newValue); } /** @@ -592,13 +655,14 @@ public final class JapaneseDate } @Override // for javadoc and covariant return type + @SuppressWarnings("unchecked") public final ChronoLocalDateTime atTime(LocalTime localTime) { - return super.atTime(localTime); + return (ChronoLocalDateTime)super.atTime(localTime); } @Override - public Period periodUntil(ChronoLocalDate endDate) { - return isoDate.periodUntil(endDate); + public Period until(ChronoLocalDate endDate) { + return isoDate.until(endDate); } @Override // override for performance @@ -624,14 +688,6 @@ public final class JapaneseDate return getChronology().getId().hashCode() ^ isoDate.hashCode(); } - @Override - public String toString() { - if (era == JapaneseEra.SEIREKI) { - return getChronology().getId() + " " + isoDate.toString(); - } - return super.toString(); - } - //----------------------------------------------------------------------- private Object writeReplace() { return new Ser(Ser.JAPANESE_DATE_TYPE, this); diff --git a/src/share/classes/java/time/chrono/JapaneseEra.java b/src/share/classes/java/time/chrono/JapaneseEra.java index 17635793b089552a4133dc59753a31b0bfc5e3b1..ba9fb434bf93694f4490b9b70064e77e131cb4e6 100644 --- a/src/share/classes/java/time/chrono/JapaneseEra.java +++ b/src/share/classes/java/time/chrono/JapaneseEra.java @@ -61,6 +61,7 @@ */ package java.time.chrono; +import static java.time.chrono.JapaneseDate.MEIJI_6_ISODATE; import static java.time.temporal.ChronoField.ERA; import java.io.DataInput; @@ -84,12 +85,9 @@ import sun.util.calendar.CalendarDate; * An era in the Japanese Imperial calendar system. *

                        * This class defines the valid eras for the Japanese chronology. - * Only Meiji (1868-09-08 - 1912-07-29) and later eras are supported. - * Japan introduced the Gregorian calendar since Meiji 6. The dates - * between Meiji 1 - 5 are not historically correct. - * The older eras are recognized as Seireki (Western calendar) era, - * and the year of era of Seireki is proleptic Gregorian year. - * (The Julian to Gregorian transition is not supported.) + * Japan introduced the Gregorian calendar starting with Meiji 6. + * Only Meiji and later eras are supported; + * dates before Meiji 6, January 1 are not supported. * * @implSpec * This class is immutable and thread-safe. @@ -100,16 +98,11 @@ public final class JapaneseEra implements Era, Serializable { // The offset value to 0-based index from the era value. - // i.e., getValue() + ERA_OFFSET == 0-based index; except that -999 is mapped to zero + // i.e., getValue() + ERA_OFFSET == 0-based index static final int ERA_OFFSET = 2; static final sun.util.calendar.Era[] ERA_CONFIG; - /** - * The singleton instance for the before Meiji era ( - 1868-09-07) - * which has the value -999. - */ - public static final JapaneseEra SEIREKI = new JapaneseEra(-999, LocalDate.MIN); /** * The singleton instance for the 'Meiji' era (1868-09-08 - 1912-07-29) * which has the value -1. @@ -144,17 +137,13 @@ public final class JapaneseEra private static final JapaneseEra[] KNOWN_ERAS; static { - sun.util.calendar.Era[] sunEras = JapaneseChronology.JCAL.getEras(); - ERA_CONFIG = new sun.util.calendar.Era[sunEras.length + 1]; - for (int i = 1; i < ERA_CONFIG.length; i++) { - ERA_CONFIG[i] = sunEras[i - 1]; - } + ERA_CONFIG = JapaneseChronology.JCAL.getEras(); + KNOWN_ERAS = new JapaneseEra[ERA_CONFIG.length]; - KNOWN_ERAS[0] = SEIREKI; - KNOWN_ERAS[1] = MEIJI; - KNOWN_ERAS[2] = TAISHO; - KNOWN_ERAS[3] = SHOWA; - KNOWN_ERAS[4] = HEISEI; + KNOWN_ERAS[0] = MEIJI; + KNOWN_ERAS[1] = TAISHO; + KNOWN_ERAS[2] = SHOWA; + KNOWN_ERAS[3] = HEISEI; for (int i = N_ERA_CONSTANTS; i < ERA_CONFIG.length; i++) { CalendarDate date = ERA_CONFIG[i].getSinceDate(); LocalDate isoDate = LocalDate.of(date.getYear(), date.getMonth(), date.getDayOfMonth()); @@ -203,10 +192,8 @@ public final class JapaneseEra //----------------------------------------------------------------------- /** * Returns the Sun private Era instance corresponding to this {@code JapaneseEra}. - * SEIREKI doesn't have its corresponding one. * - * @return the Sun private Era instance for this {@code JapaneseEra}, - * or null for SEIREKI. + * @return the Sun private Era instance for this {@code JapaneseEra}. */ sun.util.calendar.Era getPrivateEra() { return ERA_CONFIG[ordinal(eraValue)]; @@ -218,16 +205,14 @@ public final class JapaneseEra *

                        * The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1 * Later era is numbered 2 ({@link #HEISEI}). Earlier eras are numbered 0 ({@link #TAISHO}), - * -1 ({@link #MEIJI}), only Meiji and later eras are supported. The prior to Meiji, - * {@link #SEIREKI} is used. + * -1 ({@link #MEIJI}), only Meiji and later eras are supported. * * @param japaneseEra the era to represent * @return the {@code JapaneseEra} singleton, not null * @throws DateTimeException if the value is invalid */ public static JapaneseEra of(int japaneseEra) { - if (japaneseEra != SEIREKI.eraValue && - (japaneseEra < MEIJI.eraValue || japaneseEra > HEISEI.eraValue)) { + if (japaneseEra < MEIJI.eraValue || japaneseEra > HEISEI.eraValue) { throw new DateTimeException("Invalid era: " + japaneseEra); } return KNOWN_ERAS[ordinal(japaneseEra)]; @@ -276,22 +261,25 @@ public final class JapaneseEra * @return the Era singleton, never null */ static JapaneseEra from(LocalDate date) { + if (date.isBefore(MEIJI_6_ISODATE)) { + throw new DateTimeException("JapaneseDate before Meiji 6 are not supported"); + } for (int i = KNOWN_ERAS.length - 1; i > 0; i--) { JapaneseEra era = KNOWN_ERAS[i]; if (date.compareTo(era.since) >= 0) { return era; } } - return SEIREKI; + return null; } static JapaneseEra toJapaneseEra(sun.util.calendar.Era privateEra) { - for (int i = ERA_CONFIG.length - 1; i > 0; i--) { + for (int i = ERA_CONFIG.length - 1; i >= 0; i--) { if (ERA_CONFIG[i].equals(privateEra)) { return KNOWN_ERAS[i]; } } - return SEIREKI; + return null; } static sun.util.calendar.Era privateEraFrom(LocalDate isoDate) { @@ -306,13 +294,13 @@ public final class JapaneseEra /** * Returns the index into the arrays from the Era value. - * the eraValue is a valid Era number, -999, -1..2. + * the eraValue is a valid Era number, -1..2. * * @param eraValue the era value to convert to the index * @return the index of the current Era */ private static int ordinal(int eraValue) { - return (eraValue == SEIREKI.eraValue) ? 0 : eraValue + ERA_OFFSET; + return eraValue + ERA_OFFSET - 1; } //----------------------------------------------------------------------- @@ -321,7 +309,7 @@ public final class JapaneseEra *

                        * The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1. * Later eras are numbered from 2 ({@link #HEISEI}). - * Earlier eras are numbered 0 ({@link #TAISHO}), -1 ({@link #MEIJI}), and -999 ({@link #SEIREKI}). + * Earlier eras are numbered 0 ({@link #TAISHO}), -1 ({@link #MEIJI})). * * @return the era value */ @@ -374,11 +362,7 @@ public final class JapaneseEra } String getName() { - int index = ordinal(getValue()); - if (index == 0) { - return "Seireki"; - } - return ERA_CONFIG[index].getName(); + return ERA_CONFIG[ordinal(getValue())].getName(); } @Override diff --git a/src/share/classes/java/time/chrono/MinguoChronology.java b/src/share/classes/java/time/chrono/MinguoChronology.java index 1c9c2e34c16ec1baf284e5d266a6b5c17f6a5532..088588004c30053885ac15d2c0f137cf03ad3be2 100644 --- a/src/share/classes/java/time/chrono/MinguoChronology.java +++ b/src/share/classes/java/time/chrono/MinguoChronology.java @@ -65,12 +65,15 @@ import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; +import java.time.format.ResolverStyle; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; import java.time.temporal.ValueRange; import java.util.Arrays; import java.util.List; import java.util.Locale; +import java.util.Map; /** * The Minguo calendar system. @@ -253,16 +256,19 @@ public final class MinguoChronology extends Chronology implements Serializable { } @Override + @SuppressWarnings("unchecked") public ChronoLocalDateTime localDateTime(TemporalAccessor temporal) { return (ChronoLocalDateTime)super.localDateTime(temporal); } @Override + @SuppressWarnings("unchecked") public ChronoZonedDateTime zonedDateTime(TemporalAccessor temporal) { return (ChronoZonedDateTime)super.zonedDateTime(temporal); } @Override + @SuppressWarnings("unchecked") public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { return (ChronoZonedDateTime)super.zonedDateTime(instant, zone); } @@ -292,7 +298,7 @@ public final class MinguoChronology extends Chronology implements Serializable { } @Override - public Era eraOf(int eraValue) { + public MinguoEra eraOf(int eraValue) { return MinguoEra.of(eraValue); } @@ -321,4 +327,10 @@ public final class MinguoChronology extends Chronology implements Serializable { return field.range(); } + //----------------------------------------------------------------------- + @Override // override for return type + public MinguoDate resolveDate(Map fieldValues, ResolverStyle resolverStyle) { + return (MinguoDate) super.resolveDate(fieldValues, resolverStyle); + } + } diff --git a/src/share/classes/java/time/chrono/MinguoDate.java b/src/share/classes/java/time/chrono/MinguoDate.java index b6a5582ef98854e28382eb063f8b5b7eac8b5d59..e15b0e90a15419c10c5876e3c4dce1dc73ddf3b4 100644 --- a/src/share/classes/java/time/chrono/MinguoDate.java +++ b/src/share/classes/java/time/chrono/MinguoDate.java @@ -96,7 +96,7 @@ import java.util.Objects; */ public final class MinguoDate extends ChronoDateImpl - implements ChronoLocalDate, Serializable { + implements ChronoLocalDate, Serializable { /** * Serialization version. @@ -152,7 +152,7 @@ public final class MinguoDate * @throws DateTimeException if the current date cannot be obtained */ public static MinguoDate now(Clock clock) { - return MinguoChronology.INSTANCE.date(LocalDate.now(clock)); + return new MinguoDate(LocalDate.now(clock)); } /** @@ -264,7 +264,7 @@ public final class MinguoDate } return getChronology().range(f); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.rangeRefinedBy(this); } @@ -325,7 +325,7 @@ public final class MinguoDate } return with(isoDate.with(field, newValue)); } - return ChronoLocalDate.super.with(field, newValue); + return super.with(field, newValue); } /** @@ -369,6 +369,11 @@ public final class MinguoDate return with(isoDate.plusMonths(months)); } + @Override + MinguoDate plusWeeks(long weeksToAdd) { + return super.plusWeeks(weeksToAdd); + } + @Override MinguoDate plusDays(long days) { return with(isoDate.plusDays(days)); @@ -384,11 +389,6 @@ public final class MinguoDate return super.minus(amountToAdd, unit); } - @Override - MinguoDate plusWeeks(long weeksToAdd) { - return super.plusWeeks(weeksToAdd); - } - @Override MinguoDate minusYears(long yearsToSubtract) { return super.minusYears(yearsToSubtract); @@ -414,13 +414,14 @@ public final class MinguoDate } @Override // for javadoc and covariant return type + @SuppressWarnings("unchecked") public final ChronoLocalDateTime atTime(LocalTime localTime) { - return super.atTime(localTime); + return (ChronoLocalDateTime)super.atTime(localTime); } @Override - public Period periodUntil(ChronoLocalDate endDate) { - return isoDate.periodUntil(endDate); + public Period until(ChronoLocalDate endDate) { + return isoDate.until(endDate); } @Override // override for performance @@ -458,7 +459,7 @@ public final class MinguoDate out.writeByte(get(DAY_OF_MONTH)); } - static ChronoLocalDate readExternal(DataInput in) throws IOException { + static MinguoDate readExternal(DataInput in) throws IOException { int year = in.readInt(); int month = in.readByte(); int dayOfMonth = in.readByte(); diff --git a/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java b/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java index 27c98a6f079e49c7bf5145bb62d57f4f6373507f..04f59ceb93c087b194347a5bf8488cccf226324f 100644 --- a/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java +++ b/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java @@ -65,13 +65,16 @@ import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; +import java.time.format.ResolverStyle; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; import java.time.temporal.ValueRange; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; /** * The Thai Buddhist calendar system. @@ -289,16 +292,19 @@ public final class ThaiBuddhistChronology extends Chronology implements Serializ } @Override + @SuppressWarnings("unchecked") public ChronoLocalDateTime localDateTime(TemporalAccessor temporal) { return (ChronoLocalDateTime)super.localDateTime(temporal); } @Override + @SuppressWarnings("unchecked") public ChronoZonedDateTime zonedDateTime(TemporalAccessor temporal) { return (ChronoZonedDateTime)super.zonedDateTime(temporal); } @Override + @SuppressWarnings("unchecked") public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { return (ChronoZonedDateTime)super.zonedDateTime(instant, zone); } @@ -328,7 +334,7 @@ public final class ThaiBuddhistChronology extends Chronology implements Serializ } @Override - public Era eraOf(int eraValue) { + public ThaiBuddhistEra eraOf(int eraValue) { return ThaiBuddhistEra.of(eraValue); } @@ -357,4 +363,10 @@ public final class ThaiBuddhistChronology extends Chronology implements Serializ return field.range(); } + //----------------------------------------------------------------------- + @Override // override for return type + public ThaiBuddhistDate resolveDate(Map fieldValues, ResolverStyle resolverStyle) { + return (ThaiBuddhistDate) super.resolveDate(fieldValues, resolverStyle); + } + } diff --git a/src/share/classes/java/time/chrono/ThaiBuddhistDate.java b/src/share/classes/java/time/chrono/ThaiBuddhistDate.java index 973c7b8ab0fa159b6f1ced5f64be000c64c11a2f..67799ad5af8197a70b1dda68b1df7465ff7f39c6 100644 --- a/src/share/classes/java/time/chrono/ThaiBuddhistDate.java +++ b/src/share/classes/java/time/chrono/ThaiBuddhistDate.java @@ -96,7 +96,7 @@ import java.util.Objects; */ public final class ThaiBuddhistDate extends ChronoDateImpl - implements ChronoLocalDate, Serializable { + implements ChronoLocalDate, Serializable { /** * Serialization version. @@ -152,7 +152,7 @@ public final class ThaiBuddhistDate * @throws DateTimeException if the current date cannot be obtained */ public static ThaiBuddhistDate now(Clock clock) { - return ThaiBuddhistChronology.INSTANCE.date(LocalDate.now(clock)); + return new ThaiBuddhistDate(LocalDate.now(clock)); } /** @@ -264,7 +264,7 @@ public final class ThaiBuddhistDate } return getChronology().range(f); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.rangeRefinedBy(this); } @@ -325,7 +325,7 @@ public final class ThaiBuddhistDate } return with(isoDate.with(field, newValue)); } - return ChronoLocalDate.super.with(field, newValue); + return super.with(field, newValue); } /** @@ -414,13 +414,14 @@ public final class ThaiBuddhistDate } @Override // for javadoc and covariant return type + @SuppressWarnings("unchecked") public final ChronoLocalDateTime atTime(LocalTime localTime) { - return super.atTime(localTime); + return (ChronoLocalDateTime) super.atTime(localTime); } @Override - public Period periodUntil(ChronoLocalDate endDate) { - return isoDate.periodUntil(endDate); + public Period until(ChronoLocalDate endDate) { + return isoDate.until(endDate); } @Override // override for performance diff --git a/src/share/classes/java/time/chrono/package-info.java b/src/share/classes/java/time/chrono/package-info.java index 4f2a3f6e78c90380834ab4f60f01198b25fb8c05..9273a770f82689fc042ae20a1730808aa4cf26d7 100644 --- a/src/share/classes/java/time/chrono/package-info.java +++ b/src/share/classes/java/time/chrono/package-info.java @@ -103,7 +103,7 @@ * // Enumerate the list of available calendars and print todays date for each. * Set<Chronology> chronos = Chronology.getAvailableChronologies(); * for (Chronology chrono : chronos) { - * ChronoLocalDate<?> date = chrono.dateNow(); + * ChronoLocalDate date = chrono.dateNow(); * System.out.printf(" %20s: %s%n", chrono.getId(), date.toString()); * } * @@ -113,7 +113,7 @@ *

                        *
                          *   // Print the Thai Buddhist date
                        - *       ChronoLocalDate<?> now1 = Chronology.of("ThaiBuddhist").dateNow();
                        + *       ChronoLocalDate now1 = Chronology.of("ThaiBuddhist").dateNow();
                          *       int day = now1.get(ChronoField.DAY_OF_MONTH);
                          *       int dow = now1.get(ChronoField.DAY_OF_WEEK);
                          *       int month = now1.get(ChronoField.MONTH_OF_YEAR);
                        @@ -121,10 +121,10 @@
                          *       System.out.printf("  Today is %s %s %d-%s-%d%n", now1.getChronology().getId(),
                          *                 dow, day, month, year);
                          *   // Print today's date and the last day of the year for the Thai Buddhist Calendar.
                        - *       ChronoLocalDate<?> first = now1
                        + *       ChronoLocalDate first = now1
                          *                 .with(ChronoField.DAY_OF_MONTH, 1)
                          *                 .with(ChronoField.MONTH_OF_YEAR, 1);
                        - *       ChronoLocalDate<?> last = first
                        + *       ChronoLocalDate last = first
                          *                 .plus(1, ChronoUnit.YEARS)
                          *                 .minus(1, ChronoUnit.DAYS);
                          *       System.out.printf("  %s: 1st of year: %s; end of year: %s%n", last.getChronology().getId(),
                        diff --git a/src/share/classes/java/time/format/DateTimeFormatter.java b/src/share/classes/java/time/format/DateTimeFormatter.java
                        index 2552f96e5ad36f3e5abdb8343eaff2bcaa418e82..0c0a5979b14840326bbc5d4d68cb0658cf006db0 100644
                        --- a/src/share/classes/java/time/format/DateTimeFormatter.java
                        +++ b/src/share/classes/java/time/format/DateTimeFormatter.java
                        @@ -265,7 +265,7 @@ import java.util.Set;
                          * 

                        * For example: *

                        - *  DateTimeFormatter formatter = DateTimeFormatter.pattern("yyyy MM dd");
                        + *  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
                          *  String text = date.toString(formatter);
                          *  LocalDate date = LocalDate.parse(text, formatter);
                          * 
                        @@ -460,7 +460,7 @@ import java.util.Set; *
                      • The {@code ChronoField} time fields are resolved. * This is documented on {@link ChronoField} and is the same for all chronologies. *
                      • Any fields that are not {@code ChronoField} are processed. - * This is achieved using {@link TemporalField#resolve(TemporalAccessor, long, ResolverStyle)}. + * This is achieved using {@link TemporalField#resolve(Map, Chronology, ZoneId, ResolverStyle)}. * Documentation about field resolution is located in the implementation * of {@code TemporalField}. *
                      • The {@code ChronoField} date and time fields are re-resolved. diff --git a/src/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/share/classes/java/time/format/DateTimeFormatterBuilder.java index cec07840439ae6424cd8211a6df8ffdd016118f6..f4983b488613dbebdecf00d82f585b568d32bbb3 100644 --- a/src/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/src/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -77,7 +77,6 @@ import java.math.BigInteger; import java.math.RoundingMode; import java.text.ParsePosition; import java.time.DateTimeException; -import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; @@ -962,12 +961,9 @@ public final class DateTimeFormatterBuilder { *
                              *   "Europe/London"           -- ZoneId.of("Europe/London")
                              *   "Z"                       -- ZoneOffset.UTC
                        -     *   "UT"                      -- ZoneOffset.UTC
                        -     *   "UTC"                     -- ZoneOffset.UTC
                        -     *   "GMT"                     -- ZoneOffset.UTC
                        -     *   "UT0"                     -- ZoneOffset.UTC
                        -     *   "UTC0"                    -- ZoneOffset.UTC
                        -     *   "GMT0"                    -- ZoneOffset.UTC
                        +     *   "UT"                      -- ZoneId.of("UT")
                        +     *   "UTC"                     -- ZoneId.of("UTC")
                        +     *   "GMT"                     -- ZoneId.of("GMT")
                              *   "+01:30"                  -- ZoneOffset.of("+01:30")
                              *   "UT+01:30"                -- ZoneOffset.of("+01:30")
                              *   "UTC+01:30"               -- ZoneOffset.of("+01:30")
                        @@ -1016,12 +1012,9 @@ public final class DateTimeFormatterBuilder {
                              * 
                              *   "Europe/London"           -- ZoneId.of("Europe/London")
                              *   "Z"                       -- ZoneOffset.UTC
                        -     *   "UT"                      -- ZoneOffset.UTC
                        -     *   "UTC"                     -- ZoneOffset.UTC
                        -     *   "GMT"                     -- ZoneOffset.UTC
                        -     *   "UT0"                     -- ZoneOffset.UTC
                        -     *   "UTC0"                    -- ZoneOffset.UTC
                        -     *   "GMT0"                    -- ZoneOffset.UTC
                        +     *   "UT"                      -- ZoneId.of("UT")
                        +     *   "UTC"                     -- ZoneId.of("UTC")
                        +     *   "GMT"                     -- ZoneId.of("GMT")
                              *   "+01:30"                  -- ZoneOffset.of("+01:30")
                              *   "UT+01:30"                -- ZoneOffset.of("+01:30")
                              *   "UTC+01:30"               -- ZoneOffset.of("+01:30")
                        @@ -1077,16 +1070,13 @@ public final class DateTimeFormatterBuilder {
                              * 
                              *   "Europe/London"           -- ZoneId.of("Europe/London")
                              *   "Z"                       -- ZoneOffset.UTC
                        -     *   "UT"                      -- ZoneOffset.UTC
                        -     *   "UTC"                     -- ZoneOffset.UTC
                        -     *   "GMT"                     -- ZoneOffset.UTC
                        -     *   "UT0"                     -- ZoneOffset.UTC
                        -     *   "UTC0"                    -- ZoneOffset.UTC
                        -     *   "GMT0"                    -- ZoneOffset.UTC
                        +     *   "UT"                      -- ZoneId.of("UT")
                        +     *   "UTC"                     -- ZoneId.of("UTC")
                        +     *   "GMT"                     -- ZoneId.of("GMT")
                              *   "+01:30"                  -- ZoneOffset.of("+01:30")
                        -     *   "UT+01:30"                -- ZoneOffset.of("+01:30")
                        -     *   "UTC+01:30"               -- ZoneOffset.of("+01:30")
                        -     *   "GMT+01:30"               -- ZoneOffset.of("+01:30")
                        +     *   "UT+01:30"                -- ZoneOffset.of("UT+01:30")
                        +     *   "UTC+01:30"               -- ZoneOffset.of("UTC+01:30")
                        +     *   "GMT+01:30"               -- ZoneOffset.of("GMT+01:30")
                              * 
                        *

                        * Note that this method is is identical to {@code appendZoneId()} except @@ -2530,7 +2520,7 @@ public final class DateTimeFormatterBuilder { DecimalStyle decimalStyle = context.getDecimalStyle(); String str = (value == Long.MIN_VALUE ? "9223372036854775808" : Long.toString(Math.abs(value))); if (str.length() > maxWidth) { - throw new DateTimeException("Field " + field.getName() + + throw new DateTimeException("Field " + field + " cannot be printed as the value " + value + " exceeds the maximum print width of " + maxWidth); } @@ -2555,7 +2545,7 @@ public final class DateTimeFormatterBuilder { buf.append(decimalStyle.getNegativeSign()); break; case NOT_NEGATIVE: - throw new DateTimeException("Field " + field.getName() + + throw new DateTimeException("Field " + field + " cannot be printed as the value " + value + " cannot be negative according to the SignStyle"); } @@ -2699,12 +2689,12 @@ public final class DateTimeFormatterBuilder { @Override public String toString() { if (minWidth == 1 && maxWidth == 19 && signStyle == SignStyle.NORMAL) { - return "Value(" + field.getName() + ")"; + return "Value(" + field + ")"; } if (minWidth == maxWidth && signStyle == SignStyle.NOT_NEGATIVE) { - return "Value(" + field.getName() + "," + minWidth + ")"; + return "Value(" + field + "," + minWidth + ")"; } - return "Value(" + field.getName() + "," + minWidth + "," + maxWidth + "," + signStyle + ")"; + return "Value(" + field + "," + minWidth + "," + maxWidth + "," + signStyle + ")"; } } @@ -2817,7 +2807,7 @@ public final class DateTimeFormatterBuilder { @Override public String toString() { - return "ReducedValue(" + field.getName() + "," + minWidth + "," + maxWidth + "," + baseValue + ")"; + return "ReducedValue(" + field + "," + minWidth + "," + maxWidth + "," + baseValue + ")"; } } @@ -2842,7 +2832,7 @@ public final class DateTimeFormatterBuilder { FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) { Objects.requireNonNull(field, "field"); if (field.range().isFixed() == false) { - throw new IllegalArgumentException("Field must have a fixed set of values: " + field.getName()); + throw new IllegalArgumentException("Field must have a fixed set of values: " + field); } if (minWidth < 0 || minWidth > 9) { throw new IllegalArgumentException("Minimum width must be from 0 to 9 inclusive but was " + minWidth); @@ -2984,7 +2974,7 @@ public final class DateTimeFormatterBuilder { @Override public String toString() { String decimal = (decimalPoint ? ",DecimalPoint" : ""); - return "Fraction(" + field.getName() + "," + minWidth + "," + maxWidth + decimal + ")"; + return "Fraction(" + field + "," + minWidth + "," + maxWidth + decimal + ")"; } } @@ -3079,9 +3069,9 @@ public final class DateTimeFormatterBuilder { @Override public String toString() { if (textStyle == TextStyle.FULL) { - return "Text(" + field.getName() + ")"; + return "Text(" + field + ")"; } - return "Text(" + field.getName() + "," + textStyle + ")"; + return "Text(" + field + "," + textStyle + ")"; } } @@ -3756,17 +3746,17 @@ public final class DateTimeFormatterBuilder { // handle fixed time-zone IDs char nextChar = text.charAt(position); if (nextChar == '+' || nextChar == '-') { - return parseOffsetBased(context, text, position, OffsetIdPrinterParser.INSTANCE_ID_Z); + return parseOffsetBased(context, text, position, position, OffsetIdPrinterParser.INSTANCE_ID_Z); } else if (length >= position + 2) { char nextNextChar = text.charAt(position + 1); if (context.charEquals(nextChar, 'U') && context.charEquals(nextNextChar, 'T')) { if (length >= position + 3 && context.charEquals(text.charAt(position + 2), 'C')) { - return parseOffsetBased(context, text, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO); + return parseOffsetBased(context, text, position, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO); } - return parseOffsetBased(context, text, position + 2, OffsetIdPrinterParser.INSTANCE_ID_ZERO); + return parseOffsetBased(context, text, position, position + 2, OffsetIdPrinterParser.INSTANCE_ID_ZERO); } else if (context.charEquals(nextChar, 'G') && length >= position + 3 && context.charEquals(nextNextChar, 'M') && context.charEquals(text.charAt(position + 2), 'T')) { - return parseOffsetBased(context, text, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO); + return parseOffsetBased(context, text, position, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO); } } @@ -3785,20 +3775,49 @@ public final class DateTimeFormatterBuilder { return ppos.getIndex(); } - private int parseOffsetBased(DateTimeParseContext context, CharSequence text, int position, OffsetIdPrinterParser parser) { + /** + * Parse an offset following a prefix and set the ZoneId if it is valid. + * To matching the parsing of ZoneId.of the values are not normalized + * to ZoneOffsets. + * + * @param context the parse context + * @param text the input text + * @param prefixPos start of the prefix + * @param position start of text after the prefix + * @param parser parser for the value after the prefix + * @return the position after the parse + */ + private int parseOffsetBased(DateTimeParseContext context, CharSequence text, int prefixPos, int position, OffsetIdPrinterParser parser) { + String prefix = text.toString().substring(prefixPos, position).toUpperCase(); + if (position >= text.length()) { + context.setParsed(ZoneId.of(prefix)); + return position; + } + + // '0' or 'Z' after prefix is not part of a valid ZoneId; use bare prefix + if (text.charAt(position) == '0' || + context.charEquals(text.charAt(position), 'Z')) { + context.setParsed(ZoneId.of(prefix)); + return position; + } + DateTimeParseContext newContext = context.copy(); int endPos = parser.parse(newContext, text, position); - if (endPos < 0) { - if (parser == OffsetIdPrinterParser.INSTANCE_ID_Z) { - return ~position; + try { + if (endPos < 0) { + if (parser == OffsetIdPrinterParser.INSTANCE_ID_Z) { + return ~prefixPos; + } + context.setParsed(ZoneId.of(prefix)); + return position; } - context.setParsed(ZoneOffset.UTC); - return position; + int offset = (int) newContext.getParsed(OFFSET_SECONDS).longValue(); + ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(offset); + context.setParsed(ZoneId.ofOffset(prefix, zoneOffset)); + return endPos; + } catch (DateTimeException dte) { + return ~prefixPos; } - int offset = (int) newContext.getParsed(OFFSET_SECONDS).longValue(); - ZoneId zone = ZoneOffset.ofTotalSeconds(offset); - context.setParsed(zone); - return endPos; } @Override diff --git a/src/share/classes/java/time/format/DateTimePrintContext.java b/src/share/classes/java/time/format/DateTimePrintContext.java index 3e3f90fb5ebdc23dfcb63f95d383532a7d2335cd..e744bb7d946c8653dbe19005defb41b7caec8911 100644 --- a/src/share/classes/java/time/format/DateTimePrintContext.java +++ b/src/share/classes/java/time/format/DateTimePrintContext.java @@ -157,7 +157,7 @@ final class DateTimePrintContext { } } final ZoneId effectiveZone = (overrideZone != null ? overrideZone : temporalZone); - final ChronoLocalDate effectiveDate; + final ChronoLocalDate effectiveDate; if (overrideChrono != null) { if (temporal.isSupported(EPOCH_DAY)) { effectiveDate = effectiveChrono.date(temporal); diff --git a/src/share/classes/java/time/format/Parsed.java b/src/share/classes/java/time/format/Parsed.java index b0a7fe810d988a67a0348f796a8fb007b60216a8..42223d6c1d993ab69e7caca8edb8826cde2b36e6 100644 --- a/src/share/classes/java/time/format/Parsed.java +++ b/src/share/classes/java/time/format/Parsed.java @@ -143,7 +143,7 @@ final class Parsed implements TemporalAccessor { /** * The resolved date. */ - private ChronoLocalDate date; + private ChronoLocalDate date; /** * The resolved time. */ @@ -197,7 +197,7 @@ final class Parsed implements TemporalAccessor { return time.getLong(field); } if (field instanceof ChronoField) { - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } @@ -255,42 +255,34 @@ final class Parsed implements TemporalAccessor { // if any other fields, handle them // any lenient date resolution should return epoch-day if (fieldValues.size() > 0) { - boolean changed = false; + int changedCount = 0; outer: - while (true) { + while (changedCount < 50) { for (Map.Entry entry : fieldValues.entrySet()) { TemporalField targetField = entry.getKey(); - Map changes = targetField.resolve(this, entry.getValue(), resolverStyle); - if (changes != null) { - changed = true; - resolveFieldsMakeChanges(targetField, changes); - fieldValues.remove(targetField); // helps avoid infinite loops + ChronoLocalDate resolvedDate = targetField.resolve(fieldValues, chrono, zone, resolverStyle); + if (resolvedDate != null) { + updateCheckConflict(resolvedDate); + changedCount++; + continue outer; // have to restart to avoid concurrent modification + } else if (fieldValues.containsKey(targetField) == false) { + changedCount++; continue outer; // have to restart to avoid concurrent modification } } break; } + if (changedCount == 50) { // catch infinite loops + throw new DateTimeException("One of the parsed fields has an incorrectly implemented resolve method"); + } // if something changed then have to redo ChronoField resolve - if (changed) { + if (changedCount > 0) { resolveDateFields(); resolveTimeFields(); } } } - private void resolveFieldsMakeChanges(TemporalField targetField, Map changes) { - for (Map.Entry change : changes.entrySet()) { - TemporalField changeField = change.getKey(); - Long changeValue = change.getValue(); - Objects.requireNonNull(changeField, "changeField"); - if (changeValue != null) { - updateCheckConflict(targetField, changeField, changeValue); - } else { - fieldValues.remove(changeField); - } - } - } - private void updateCheckConflict(TemporalField targetField, TemporalField changeField, Long changeValue) { Long old = fieldValues.put(changeField, changeValue); if (old != null && old.longValue() != changeValue.longValue()) { @@ -305,7 +297,7 @@ final class Parsed implements TemporalAccessor { updateCheckConflict(chrono.resolveDate(fieldValues, resolverStyle)); } - private void updateCheckConflict(ChronoLocalDate cld) { + private void updateCheckConflict(ChronoLocalDate cld) { if (date != null) { if (cld != null && date.equals(cld) == false) { throw new DateTimeException("Conflict found: Fields resolved to two different dates: " + date + " " + cld); diff --git a/src/share/classes/java/time/temporal/ChronoField.java b/src/share/classes/java/time/temporal/ChronoField.java index ac4522bb60bc47e083687a647cfd299c4ce64d8a..fe3254e60abf2b8e55c0882354a2d922ed839507 100644 --- a/src/share/classes/java/time/temporal/ChronoField.java +++ b/src/share/classes/java/time/temporal/ChronoField.java @@ -403,6 +403,12 @@ public enum ChronoField implements TemporalField { * Non-ISO calendar systems should implement this field using the most recognized * day-of-year values for users of the calendar system. * Normally, this is a count of days from 1 to the length of the year. + *

                        + * Note that a non-ISO calendar system may have year numbering system that changes + * at a different point to the natural reset in the month numbering. An example + * of this is the Japanese calendar system where a change of era, which resets + * the year number to 1, can happen on any date. The era and year reset also cause + * the day-of-year to be reset to 1, but not the month-of-year or day-of-month. */ DAY_OF_YEAR("DayOfYear", DAYS, YEARS, ValueRange.of(1, 365, 366)), /** @@ -559,12 +565,11 @@ public enum ChronoField implements TemporalField { *

                        * This represents the concept of the sequential count of seconds where * 1970-01-01T00:00Z (ISO) is zero. - * This field may be used with {@link #NANO_OF_DAY} to represent the fraction of the day. + * This field may be used with {@link #NANO_OF_SECOND} to represent the fraction of the second. *

                        * An {@link Instant} represents an instantaneous point on the time-line. - * On their own they have no elements which allow a local date-time to be obtained. - * Only when paired with an offset or time-zone can the local date or time be found. - * This field allows the seconds part of the instant to be queried. + * On their own, an instant has insufficient information to allow a local date-time to be obtained. + * Only when paired with an offset or time-zone can the local date or time be calculated. *

                        * This field is strictly defined to have the same meaning in all calendar systems. * This is necessary to ensure interoperation between calendars. @@ -608,24 +613,18 @@ public enum ChronoField implements TemporalField { this.displayNameKey = displayNameKey; } - //----------------------------------------------------------------------- - @Override - public String getName() { - return name; - } - @Override public String getDisplayName(Locale locale) { Objects.requireNonNull(locale, "locale"); if (displayNameKey == null) { - return getName(); + return name; } LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased() .getLocaleResources(locale); ResourceBundle rb = lr.getJavaTimeFormatData(); String key = "field." + displayNameKey; - return rb.containsKey(key) ? rb.getString(key) : getName(); + return rb.containsKey(key) ? rb.getString(key) : name; } @Override @@ -748,7 +747,7 @@ public enum ChronoField implements TemporalField { //----------------------------------------------------------------------- @Override public String toString() { - return getName(); + return name; } } diff --git a/src/share/classes/java/time/temporal/ChronoUnit.java b/src/share/classes/java/time/temporal/ChronoUnit.java index 661960c28fb21295b549610bf8108460508b50c8..19a37e46f4cd06ae7043bb1064622b4abb4a04cd 100644 --- a/src/share/classes/java/time/temporal/ChronoUnit.java +++ b/src/share/classes/java/time/temporal/ChronoUnit.java @@ -57,9 +57,6 @@ package java.time.temporal; import java.time.Duration; -import java.time.chrono.ChronoLocalDate; -import java.time.chrono.ChronoLocalDateTime; -import java.time.chrono.ChronoZonedDateTime; /** * A standard set of date periods units. @@ -200,12 +197,6 @@ public enum ChronoUnit implements TemporalUnit { this.duration = estimatedDuration; } - //----------------------------------------------------------------------- - @Override - public String getName() { - return name; - } - //----------------------------------------------------------------------- /** * Gets the estimated duration of this unit in the ISO calendar system. @@ -233,41 +224,40 @@ public enum ChronoUnit implements TemporalUnit { */ @Override public boolean isDurationEstimated() { - return isDateUnit(); + return this.compareTo(DAYS) >= 0; } //----------------------------------------------------------------------- /** * Checks if this unit is a date unit. + *

                        + * All units from days to eras inclusive are date-based. + * Time-based units and {@code FOREVER} return false. * * @return true if a date unit, false if a time unit */ - public boolean isDateUnit() { - return this.compareTo(DAYS) >= 0; + @Override + public boolean isDateBased() { + return this.compareTo(DAYS) >= 0 && this != FOREVER; } /** * Checks if this unit is a time unit. + *

                        + * All units from nanos to half-days inclusive are time-based. + * Date-based units and {@code FOREVER} return false. * * @return true if a time unit, false if a date unit */ - public boolean isTimeUnit() { + @Override + public boolean isTimeBased() { return this.compareTo(DAYS) < 0; } //----------------------------------------------------------------------- @Override public boolean isSupportedBy(Temporal temporal) { - if (this == FOREVER) { - return false; - } - if (temporal instanceof ChronoLocalDate) { - return isDateUnit(); - } - if (temporal instanceof ChronoLocalDateTime || temporal instanceof ChronoZonedDateTime) { - return true; - } - return TemporalUnit.super.isSupportedBy(temporal); + return temporal.isSupported(this); } @SuppressWarnings("unchecked") @@ -279,13 +269,13 @@ public enum ChronoUnit implements TemporalUnit { //----------------------------------------------------------------------- @Override public long between(Temporal temporal1, Temporal temporal2) { - return temporal1.periodUntil(temporal2, this); + return temporal1.until(temporal2, this); } //----------------------------------------------------------------------- @Override public String toString() { - return getName(); + return name; } } diff --git a/src/share/classes/java/time/temporal/IsoFields.java b/src/share/classes/java/time/temporal/IsoFields.java index e335c434d23de921e2ab9327960f3047fc18f076..eae057afb2a9ebc70a644e5f5fdc4ce464655a5c 100644 --- a/src/share/classes/java/time/temporal/IsoFields.java +++ b/src/share/classes/java/time/temporal/IsoFields.java @@ -71,6 +71,8 @@ import static java.time.temporal.ChronoUnit.YEARS; import java.time.Duration; import java.time.LocalDate; +import java.time.ZoneId; +import java.time.chrono.ChronoLocalDate; import java.time.chrono.Chronology; import java.time.chrono.IsoChronology; import java.time.format.ResolverStyle; @@ -288,10 +290,6 @@ public final class IsoFields { */ private static enum Field implements TemporalField { DAY_OF_QUARTER { - @Override - public String getName() { - return "DayOfQuarter"; - } @Override public TemporalUnit getBaseUnit() { return DAYS; @@ -344,17 +342,21 @@ public final class IsoFields { return (R) temporal.with(DAY_OF_YEAR, temporal.getLong(DAY_OF_YEAR) + (newValue - curValue)); } @Override - public Map resolve(TemporalAccessor temporal, long doq, ResolverStyle resolverStyle) { - if ((temporal.isSupported(YEAR) && temporal.isSupported(QUARTER_OF_YEAR)) == false) { + public ChronoLocalDate resolve( + Map fieldValues, Chronology chronology, ZoneId zone, ResolverStyle resolverStyle) { + Long yearLong = fieldValues.get(YEAR); + Long qoyLong = fieldValues.get(QUARTER_OF_YEAR); + if (yearLong == null || qoyLong == null) { return null; } - int y = temporal.get(YEAR); // validated + int y = YEAR.checkValidIntValue(yearLong); // always validate + long doq = fieldValues.get(DAY_OF_QUARTER); LocalDate date; if (resolverStyle == ResolverStyle.LENIENT) { - long qoy = temporal.getLong(QUARTER_OF_YEAR); // unvalidated - date = LocalDate.of(y, 1, 1).plusMonths(Math.multiplyExact(Math.subtractExact(qoy, 1), 3)); + date = LocalDate.of(y, 1, 1).plusMonths(Math.multiplyExact(Math.subtractExact(qoyLong, 1), 3)); + doq = Math.subtractExact(doq, 1); } else { - int qoy = temporal.get(QUARTER_OF_YEAR); // validated + int qoy = QUARTER_OF_YEAR.range().checkValidIntValue(qoyLong, QUARTER_OF_YEAR); // validated date = LocalDate.of(y, ((qoy - 1) * 3) + 1, 1); if (doq < 1 || doq > 90) { if (resolverStyle == ResolverStyle.STRICT) { @@ -363,20 +365,19 @@ public final class IsoFields { range().checkValidValue(doq, this); // allow 1-92 rolling into next quarter } } + doq--; } - long epochDay = Math.addExact(date.toEpochDay(), Math.subtractExact(doq, 1)); - Map result = new HashMap<>(4, 1.0f); - result.put(EPOCH_DAY, epochDay); - result.put(YEAR, null); - result.put(QUARTER_OF_YEAR, null); - return result; + fieldValues.remove(this); + fieldValues.remove(YEAR); + fieldValues.remove(QUARTER_OF_YEAR); + return date.plusDays(doq); } - }, - QUARTER_OF_YEAR { @Override - public String getName() { - return "QuarterOfYear"; + public String toString() { + return "DayOfQuarter"; } + }, + QUARTER_OF_YEAR { @Override public TemporalUnit getBaseUnit() { return QUARTER_YEARS; @@ -409,20 +410,19 @@ public final class IsoFields { range().checkValidValue(newValue, this); // strictly check from 1 to 4 return (R) temporal.with(MONTH_OF_YEAR, temporal.getLong(MONTH_OF_YEAR) + (newValue - curValue) * 3); } - }, - WEEK_OF_WEEK_BASED_YEAR { @Override - public String getName() { - return "WeekOfWeekBasedYear"; + public String toString() { + return "QuarterOfYear"; } - + }, + WEEK_OF_WEEK_BASED_YEAR { @Override public String getDisplayName(Locale locale) { Objects.requireNonNull(locale, "locale"); LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased() .getLocaleResources(locale); ResourceBundle rb = lr.getJavaTimeFormatData(); - return rb.containsKey("field.week") ? rb.getString("field.week") : getName(); + return rb.containsKey("field.week") ? rb.getString("field.week") : toString(); } @Override @@ -463,14 +463,18 @@ public final class IsoFields { return (R) temporal.plus(Math.subtractExact(newValue, getFrom(temporal)), WEEKS); } @Override - public Map resolve(TemporalAccessor temporal, long wowby, ResolverStyle resolverStyle) { - if ((temporal.isSupported(WEEK_BASED_YEAR) && temporal.isSupported(DAY_OF_WEEK)) == false) { + public ChronoLocalDate resolve( + Map fieldValues, Chronology chronology, ZoneId zone, ResolverStyle resolverStyle) { + Long wbyLong = fieldValues.get(WEEK_BASED_YEAR); + Long dowLong = fieldValues.get(DAY_OF_WEEK); + if (wbyLong == null || dowLong == null) { return null; } - int wby = temporal.get(WEEK_BASED_YEAR); // validated + int wby = WEEK_BASED_YEAR.range().checkValidIntValue(wbyLong, WEEK_BASED_YEAR); // always validate + long wowby = fieldValues.get(WEEK_OF_WEEK_BASED_YEAR); LocalDate date = LocalDate.of(wby, 1, 4); if (resolverStyle == ResolverStyle.LENIENT) { - long dow = temporal.getLong(DAY_OF_WEEK); // unvalidated + long dow = dowLong; // unvalidated if (dow > 7) { date = date.plusWeeks((dow - 1) / 7); dow = ((dow - 1) % 7) + 1; @@ -480,7 +484,7 @@ public final class IsoFields { } date = date.plusWeeks(Math.subtractExact(wowby, 1)).with(DAY_OF_WEEK, dow); } else { - int dow = temporal.get(DAY_OF_WEEK); // validated + int dow = DAY_OF_WEEK.checkValidIntValue(dowLong); // validated if (wowby < 1 || wowby > 52) { if (resolverStyle == ResolverStyle.STRICT) { getWeekRange(date).checkValidValue(wowby, this); // only allow exact range @@ -490,18 +494,17 @@ public final class IsoFields { } date = date.plusWeeks(wowby - 1).with(DAY_OF_WEEK, dow); } - Map result = new HashMap<>(2, 1.0f); - result.put(EPOCH_DAY, date.toEpochDay()); - result.put(WEEK_BASED_YEAR, null); - result.put(DAY_OF_WEEK, null); - return result; + fieldValues.remove(this); + fieldValues.remove(WEEK_BASED_YEAR); + fieldValues.remove(DAY_OF_WEEK); + return date; } - }, - WEEK_BASED_YEAR { @Override - public String getName() { - return "WeekBasedYear"; + public String toString() { + return "WeekOfWeekBasedYear"; } + }, + WEEK_BASED_YEAR { @Override public TemporalUnit getBaseUnit() { return WEEK_BASED_YEARS; @@ -537,6 +540,10 @@ public final class IsoFields { date = date.withDayOfYear(180).withYear(newVal).with(WEEK_OF_WEEK_BASED_YEAR, week); return (R) date.with(date); } + @Override + public String toString() { + return "WeekBasedYear"; + } }; @Override @@ -545,13 +552,13 @@ public final class IsoFields { } @Override - public ValueRange rangeRefinedBy(TemporalAccessor temporal) { - return range(); + public boolean isTimeBased() { + return false; } @Override - public String toString() { - return getName(); + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + return range(); } //------------------------------------------------------------------------- @@ -635,11 +642,6 @@ public final class IsoFields { this.duration = estimatedDuration; } - @Override - public String getName() { - return name; - } - @Override public Duration getDuration() { return duration; @@ -650,6 +652,16 @@ public final class IsoFields { return true; } + @Override + public boolean isDateBased() { + return true; + } + + @Override + public boolean isTimeBased() { + return false; + } + @Override public boolean isSupportedBy(Temporal temporal) { return temporal.isSupported(EPOCH_DAY); @@ -658,7 +670,7 @@ public final class IsoFields { @SuppressWarnings("unchecked") @Override public R addTo(R temporal, long amount) { - switch(this) { + switch (this) { case WEEK_BASED_YEARS: return (R) temporal.with(WEEK_BASED_YEAR, Math.addExact(temporal.get(WEEK_BASED_YEAR), amount)); @@ -678,7 +690,7 @@ public final class IsoFields { return Math.subtractExact(temporal2.getLong(WEEK_BASED_YEAR), temporal1.getLong(WEEK_BASED_YEAR)); case QUARTER_YEARS: - return temporal1.periodUntil(temporal2, MONTHS) / 3; + return temporal1.until(temporal2, MONTHS) / 3; default: throw new IllegalStateException("Unreachable"); } @@ -686,8 +698,7 @@ public final class IsoFields { @Override public String toString() { - return getName(); - + return name; } } } diff --git a/src/share/classes/java/time/temporal/JulianFields.java b/src/share/classes/java/time/temporal/JulianFields.java index 95400addcaa3cb8eb167462f510e0ad11bb2a7e8..326f20d222ffd36758e3ea45475057bd0077aa60 100644 --- a/src/share/classes/java/time/temporal/JulianFields.java +++ b/src/share/classes/java/time/temporal/JulianFields.java @@ -66,6 +66,9 @@ import static java.time.temporal.ChronoUnit.DAYS; import static java.time.temporal.ChronoUnit.FOREVER; 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.Collections; import java.util.Map; @@ -232,11 +235,6 @@ public final class JulianFields { } //----------------------------------------------------------------------- - @Override - public String getName() { - return name; - } - @Override public TemporalUnit getBaseUnit() { return baseUnit; @@ -252,6 +250,11 @@ public final class JulianFields { return true; } + @Override + public boolean isTimeBased() { + return false; + } + @Override public ValueRange range() { return range; @@ -287,15 +290,14 @@ public final class JulianFields { //----------------------------------------------------------------------- @Override - public Map resolve(TemporalAccessor temporal, long value, ResolverStyle resolverStyle) { - long epochDay; + public ChronoLocalDate resolve( + Map fieldValues, Chronology chronology, ZoneId zone, ResolverStyle resolverStyle) { + long value = fieldValues.remove(this); if (resolverStyle == ResolverStyle.LENIENT) { - epochDay = Math.subtractExact(value, offset); - } else { - range().checkValidValue(value, this); - epochDay = value - offset; + return chronology.dateEpochDay(Math.subtractExact(value, offset)); } - return Collections.singletonMap(EPOCH_DAY, epochDay); + range().checkValidValue(value, this); + return chronology.dateEpochDay(value - offset); } //----------------------------------------------------------------------- diff --git a/src/share/classes/java/time/temporal/Temporal.java b/src/share/classes/java/time/temporal/Temporal.java index 1928186b285de2f70b068611c6f924289b39ec06..af8424c1560a1599175ddee1ab764da9988109af 100644 --- a/src/share/classes/java/time/temporal/Temporal.java +++ b/src/share/classes/java/time/temporal/Temporal.java @@ -62,7 +62,6 @@ package java.time.temporal; import java.time.DateTimeException; -import java.time.ZoneId; /** * Framework-level interface defining read-write access to a temporal object, @@ -81,7 +80,8 @@ import java.time.ZoneId; * See {@link ChronoField} for the standard set of fields. *

                        * Two pieces of date/time information cannot be represented by numbers, - * the {@linkplain java.time.chrono.Chronology chronology} and the {@linkplain ZoneId time-zone}. + * the {@linkplain java.time.chrono.Chronology chronology} and the + * {@linkplain java.time.ZoneId time-zone}. * These can be accessed via {@link #query(TemporalQuery) queries} using * the static methods defined on {@link TemporalQuery}. *

                        @@ -128,6 +128,29 @@ import java.time.ZoneId; */ public interface Temporal extends TemporalAccessor { + /** + * Checks if the specified unit is supported. + *

                        + * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + * + * @implSpec + * Implementations must check and handle all units defined in {@link ChronoUnit}. + * If the unit is supported, then true must be returned, otherwise false must be returned. + *

                        + * If the field is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + *

                        + * Implementations must ensure that no observable state is altered when this + * read-only method is invoked. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + boolean isSupported(TemporalUnit unit); + /** * Returns an adjusted object of the same type as this object with the adjustment made. *

                        @@ -352,7 +375,7 @@ public interface Temporal extends TemporalAccessor { * The start and end points are {@code this} and the specified temporal. * 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.periodUntil(endTime, HOURS)}. + * calculated using {@code startTime.until(endTime, HOURS)}. *

                        * The calculation returns a whole number, representing the number of * complete units between the two temporals. @@ -364,7 +387,7 @@ public interface Temporal extends TemporalAccessor { * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

                              *   // these two lines are equivalent
                        -     *   temporal = start.periodUntil(end, unit);
                        +     *   temporal = start.until(end, unit);
                              *   temporal = unit.between(start, end);
                              * 
                        * The choice should be made based on which makes the code more readable. @@ -372,7 +395,7 @@ public interface Temporal extends TemporalAccessor { * For example, this method allows the number of days between two dates to * be calculated: *
                        -     *  long daysBetween = start.periodUntil(end, DAYS);
                        +     *  long daysBetween = start.until(end, DAYS);
                              *  // or alternatively
                              *  long daysBetween = DAYS.between(start, end);
                              * 
                        @@ -399,7 +422,8 @@ public interface Temporal extends TemporalAccessor { * return unit.between(this, endTemporal); *
                        *

                        - * Neither this object, nor the specified temporal, may be altered. + * 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 unit the unit to measure the amount in, not null @@ -410,6 +434,6 @@ public interface Temporal extends TemporalAccessor { * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ - long periodUntil(Temporal endTemporal, TemporalUnit unit); + long until(Temporal endTemporal, TemporalUnit unit); } diff --git a/src/share/classes/java/time/temporal/TemporalAccessor.java b/src/share/classes/java/time/temporal/TemporalAccessor.java index a212be859810c6945310c120006115a310ce4f40..343447e36b9b43b1188148a0db56fc57001e257a 100644 --- a/src/share/classes/java/time/temporal/TemporalAccessor.java +++ b/src/share/classes/java/time/temporal/TemporalAccessor.java @@ -62,7 +62,6 @@ package java.time.temporal; import java.time.DateTimeException; -import java.time.ZoneId; import java.util.Objects; /** @@ -80,7 +79,8 @@ import java.util.Objects; * See {@link ChronoField} for the standard set of fields. *

                        * Two pieces of date/time information cannot be represented by numbers, - * the {@linkplain java.time.chrono.Chronology chronology} and the {@linkplain ZoneId time-zone}. + * the {@linkplain java.time.chrono.Chronology chronology} and the + * {@linkplain java.time.ZoneId time-zone}. * These can be accessed via {@linkplain #query(TemporalQuery) queries} using * the static methods defined on {@link TemporalQuery}. *

                        @@ -111,13 +111,14 @@ public interface TemporalAccessor { * * @implSpec * Implementations must check and handle all fields defined in {@link ChronoField}. - * If the field is supported, then true is returned, otherwise false + * If the field is supported, then true must be returned, otherwise false must be returned. *

                        * If the field is not a {@code ChronoField}, then the result of this method * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} * passing {@code this} as the argument. *

                        - * Implementations must not alter either this object. + * Implementations must ensure that no observable state is altered when this + * read-only method is invoked. * * @param field the field to check, null returns false * @return true if this date-time can be queried for the field, false if not @@ -146,7 +147,8 @@ public interface TemporalAccessor { * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessorl)} * passing {@code this} as the argument. *

                        - * Implementations must not alter either this object. + * Implementations must ensure that no observable state is altered when this + * read-only method is invoked. *

                        * The default implementation must behave equivalent to this code: *

                        @@ -154,7 +156,7 @@ public interface TemporalAccessor {
                              *    if (isSupported(field)) {
                              *      return field.range();
                              *    }
                        -     *    throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
                        +     *    throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
                              *  }
                              *  return field.rangeRefinedBy(this);
                              * 
                        @@ -169,7 +171,7 @@ public interface TemporalAccessor { if (isSupported(field)) { return field.range(); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } Objects.requireNonNull(field, "field"); return field.rangeRefinedBy(this); @@ -193,7 +195,8 @@ public interface TemporalAccessor { * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. *

                        - * Implementations must not alter this object. + * Implementations must ensure that no observable state is altered when this + * read-only method is invoked. *

                        * The default implementation must behave equivalent to this code: *

                        @@ -240,7 +243,8 @@ public interface TemporalAccessor {
                              * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
                              * passing {@code this} as the argument.
                              * 

                        - * Implementations must not alter either this object. + * Implementations must ensure that no observable state is altered when this + * read-only method is invoked. * * @param field the field to get, not null * @return the value for the field @@ -291,6 +295,9 @@ public interface TemporalAccessor { * } * return TemporalAccessor.super.query(query); *

                        + *

                        + * Implementations must ensure that no observable state is altered when this + * read-only method is invoked. * * @param the type of the result * @param query the query to invoke, not null diff --git a/src/share/classes/java/time/temporal/TemporalField.java b/src/share/classes/java/time/temporal/TemporalField.java index cce2dfbd4de74475e76b76bde3a787620821fcb0..e4d6b407783f23ad253a18e8d803e5ef17307f0a 100644 --- a/src/share/classes/java/time/temporal/TemporalField.java +++ b/src/share/classes/java/time/temporal/TemporalField.java @@ -62,6 +62,9 @@ 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; import java.util.Map; @@ -92,30 +95,20 @@ import java.util.Objects; */ public interface TemporalField { - /** - * Gets a descriptive name for the field. - *

                        - * The should be of the format 'BaseOfRange', such as 'MonthOfYear', - * unless the field has a range of {@code FOREVER}, when only - * the base unit is mentioned, such as 'Year' or 'Era'. - * - * @return the name, not null - */ - String getName(); - /** * Gets the display name for the field in the requested locale. *

                        - * If there is no display name for the locale the value of {@code getName} - * is returned. + * If there is no display name for the locale then a suitable default must be returned. + *

                        + * The default implementation must check the locale is not null + * and return {@code toString()}. * * @param locale the locale to use, not null - * @return the display name for the locale or the value of {@code getName}, - * not null + * @return the display name for the locale or a suitable default, not null */ default String getDisplayName(Locale locale) { - Objects.requireNonNull(locale, "local"); - return getName(); + Objects.requireNonNull(locale, "locale"); + return toString(); } /** @@ -164,28 +157,24 @@ public interface TemporalField { *

                        * A field is date-based if it can be derived from * {@link ChronoField#EPOCH_DAY EPOCH_DAY}. - *

                        - * The default implementation must return false. + * Note that it is valid for both {@code isDateBased()} and {@code isTimeBased()} + * to return false, such as when representing a field like minute-of-week. * * @return true if this field is a component of a date */ - default boolean isDateBased() { - return false; - } + boolean isDateBased(); /** * Checks if this field represents a component of a time. *

                        * A field is time-based if it can be derived from * {@link ChronoField#NANO_OF_DAY NANO_OF_DAY}. - *

                        - * The default implementation must return false. + * Note that it is valid for both {@code isDateBased()} and {@code isTimeBased()} + * to return false, such as when representing a field like minute-of-week. * * @return true if this field is a component of a time */ - default boolean isTimeBased() { - return false; - } + boolean isTimeBased(); //----------------------------------------------------------------------- /** @@ -319,45 +308,79 @@ public interface TemporalField { R adjustInto(R temporal, long newValue); /** - * Resolves this field to provide a simpler alternative. + * Resolves this field to provide a simpler alternative or a date. *

                        * This method is invoked during the resolve phase of parsing. * It is designed to allow application defined fields to be simplified into - * more standard fields, such as those on {@code ChronoField}. - *

                        - * The method will only be invoked if the specified temporal supports this field. - * The value of this field is provided. - *

                        - * The temporal must be queried using the methods of {@code TemporalAccessor}, - * not using {@code getFrom}, {@code isSupportedBy} or {@code rangeRefinedBy}. - * Before querying any field, implementations must ensure it is supported, as - * exceptions of this type would negatively affect the calculation of a parsed result. + * more standard fields, such as those on {@code ChronoField}, or into a date. *

                        - * If this field can resolve, it must return a map, if not it must return null. - * The returned map contains the changes to be made to the temporal, expressed - * as field-value pairs. If the value for a field is null, the field is to be - * removed from the temporal. A null key must not be added to the result map. - *

                        - * If the result is non-null, this field will be removed from the temporal. - * This field should not be added to the result map. - *

                        - * The {@link ResolverStyle} should be used by implementations to determine - * how to perform the resolve. + * Applications should not normally invoke this method directly. + * + * @implSpec + * If an implementation represents a field that can be simplified, or + * combined with others, then this method must be implemented. + *

                        + * The specified map contains the current state of the parse. + * The map is mutable and must be mutated to resolve the field and + * any related fields. This method will only be invoked during parsing + * if the map contains this field, and implementations should therefore + * assume this field is present. + *

                        + * Resolving a field will consist of looking at the value of this field, + * and potentially other fields, and either updating the map with a + * simpler value, such as a {@code ChronoField}, or returning a + * complete {@code ChronoLocalDate}. If a resolve is successful, + * the code must remove all the fields that were resolved from the map, + * including this field. + *

                        + * For example, the {@code IsoFields} class contains the quarter-of-year + * and day-of-quarter fields. The implementation of this method in that class + * resolves the two fields plus the {@link ChronoField#YEAR YEAR} into a + * complete {@code LocalDate}. The resolve method will remove all three + * fields from the map before returning the {@code LocalDate}. + *

                        + * If resolution should be possible, but the data is invalid, the resolver + * style should be used to determine an appropriate level of leniency, which + * may require throwing a {@code DateTimeException} or {@code ArithmeticException}. + * If no resolution is possible, the resolve method must return null. + *

                        + * When resolving time fields, the map will be altered and null returned. + * When resolving date fields, the date is normally returned from the method, + * with the map altered to remove the resolved fields. However, it would also + * be acceptable for the date fields to be resolved into other {@code ChronoField} + * instances that can produce a date, such as {@code EPOCH_DAY}. + *

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

                        * The default implementation must return null. * - * @param temporal the temporal to resolve, not null - * @param value the value of this field + * @param fieldValues the map of fields to values, which can be updated, not null + * @param chronology the effective chronology, not null + * @param zone the effective zone, not null * @param resolverStyle the requested type of resolve, not null - * @return a map of fields to update in the temporal, with a mapping to null - * indicating a deletion. The whole map must be null if no resolving occurred + * @return the resolved date; 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 - * @throws ArithmeticException if numeric overflow occurs */ - default Map resolve( - TemporalAccessor temporal, long value, ResolverStyle resolverStyle) { + default ChronoLocalDate resolve( + Map fieldValues, Chronology chronology, + ZoneId zone, ResolverStyle resolverStyle) { return null; } + /** + * Gets a descriptive name for the field. + *

                        + * The should be of the format 'BaseOfRange', such as 'MonthOfYear', + * unless the field has a range of {@code FOREVER}, when only + * the base unit is mentioned, such as 'Year' or 'Era'. + * + * @return the name of the field, not null + */ + @Override + String toString(); + + } diff --git a/src/share/classes/java/time/temporal/TemporalUnit.java b/src/share/classes/java/time/temporal/TemporalUnit.java index 01ab406f85a32edd3770620573efa555adfdd98f..05577d713f8239c38c6b04cd6e5443ff9dc95931 100644 --- a/src/share/classes/java/time/temporal/TemporalUnit.java +++ b/src/share/classes/java/time/temporal/TemporalUnit.java @@ -63,7 +63,11 @@ package java.time.temporal; import java.time.DateTimeException; import java.time.Duration; +import java.time.LocalTime; import java.time.Period; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.ChronoZonedDateTime; /** * A unit of date-time, such as Days or Hours. @@ -92,15 +96,6 @@ import java.time.Period; */ public interface TemporalUnit { - /** - * Gets a descriptive name for the unit. - *

                        - * This should be in the plural and upper-first camel case, such as 'Days' or 'Minutes'. - * - * @return the name, not null - */ - String getName(); - /** * Gets the duration of this unit, which may be an estimate. *

                        @@ -130,6 +125,33 @@ public interface TemporalUnit { */ boolean isDurationEstimated(); + //----------------------------------------------------------------------- + /** + * Checks if this unit represents a component of a date. + *

                        + * A date is time-based if it can be used to imply meaning from a date. + * It must have a {@linkplain #getDuration() duration} that is an integral + * multiple of the length of a standard day. + * Note that it is valid for both {@code isDateBased()} and {@code isTimeBased()} + * to return false, such as when representing a unit like 36 hours. + * + * @return true if this unit is a component of a date + */ + boolean isDateBased(); + + /** + * Checks if this unit represents a component of a time. + *

                        + * A unit is time-based if it can be used to imply meaning from a time. + * It must have a {@linkplain #getDuration() duration} that divides into + * the length of a standard day without remainder. + * Note that it is valid for both {@code isDateBased()} and {@code isTimeBased()} + * to return false, such as when representing a unit like 36 hours. + * + * @return true if this unit is a component of a time + */ + boolean isTimeBased(); + //----------------------------------------------------------------------- /** * Checks if this unit is supported by the specified temporal object. @@ -144,6 +166,15 @@ public interface TemporalUnit { * @return true if the unit is supported */ default boolean isSupportedBy(Temporal temporal) { + if (temporal instanceof LocalTime) { + return isTimeBased(); + } + if (temporal instanceof ChronoLocalDate) { + return isDateBased(); + } + if (temporal instanceof ChronoLocalDateTime || temporal instanceof ChronoZonedDateTime) { + return true; + } try { temporal.plus(1, this); return true; @@ -212,11 +243,11 @@ public interface TemporalUnit { *

                        * There are two equivalent ways of using this method. * The first is to invoke this method directly. - * The second is to use {@link Temporal#periodUntil(Temporal, TemporalUnit)}: + * The second is to use {@link Temporal#until(Temporal, TemporalUnit)}: *

                              *   // these two lines are equivalent
                              *   between = thisUnit.between(start, end);
                        -     *   between = start.periodUntil(end, thisUnit);
                        +     *   between = start.until(end, thisUnit);
                              * 
                        * The choice should be made based on which makes the code more readable. *

                        @@ -225,7 +256,7 @@ public interface TemporalUnit { *

                              *  long daysBetween = DAYS.between(start, end);
                              *  // or alternatively
                        -     *  long daysBetween = start.periodUntil(end, DAYS);
                        +     *  long daysBetween = start.until(end, DAYS);
                              * 
                        *

                        * Implementations should perform any queries or calculations using the units @@ -245,7 +276,9 @@ public interface TemporalUnit { //----------------------------------------------------------------------- /** - * Outputs this unit as a {@code String} using the name. + * Gets a descriptive name for the unit. + *

                        + * This should be in the plural and upper-first camel case, such as 'Days' or 'Minutes'. * * @return the name of this unit, not null */ diff --git a/src/share/classes/java/time/temporal/ValueRange.java b/src/share/classes/java/time/temporal/ValueRange.java index 4ac8e74402a9687ac78ddc0e42b1fa7d9d690f3f..e003f114adccd87d6031e61f4d0487ba2f99d580 100644 --- a/src/share/classes/java/time/temporal/ValueRange.java +++ b/src/share/classes/java/time/temporal/ValueRange.java @@ -331,7 +331,7 @@ public final class ValueRange implements Serializable { private String genInvalidFieldMessage(TemporalField field, long value) { if (field != null) { - return "Invalid value for " + field.getName() + " (valid values " + this + "): " + value; + return "Invalid value for " + field + " (valid values " + this + "): " + value; } else { return "Invalid value (valid values " + this + "): " + value; } diff --git a/src/share/classes/java/time/temporal/WeekFields.java b/src/share/classes/java/time/temporal/WeekFields.java index 07ffa91d2a353bad9c6ce34a87ecac391eb2e6bd..b3eb13834500886f9996f58e775c69ec44682dae 100644 --- a/src/share/classes/java/time/temporal/WeekFields.java +++ b/src/share/classes/java/time/temporal/WeekFields.java @@ -75,7 +75,9 @@ import static java.time.temporal.ChronoUnit.YEARS; import java.io.InvalidObjectException; import java.io.Serializable; +import java.time.DateTimeException; import java.time.DayOfWeek; +import java.time.ZoneId; import java.time.chrono.ChronoLocalDate; import java.time.chrono.Chronology; import java.time.format.ResolverStyle; @@ -395,6 +397,11 @@ public final class WeekFields implements Serializable { *

                        * For example, if the first day-of-week is Sunday, then that will have the * value 1, with other days ranging from Monday as 2 to Saturday as 7. + *

                        + * In the resolving phase of parsing, a localized day-of-week will be converted + * to a standardized {@code ChronoField} day-of-week. + * The day-of-week must be in the valid range 1 to 7. + * Other fields in this class build dates using the standardized day-of-week. * * @return a field providing access to the day-of-week with localized numbering, not null */ @@ -421,6 +428,26 @@ public final class WeekFields implements Serializable { * - if the 5th day of the month is a Monday, week two starts on the 5th and the 1st to 4th is in week one
                        *

                        * This field can be used with any calendar system. + *

                        + * In the resolving phase of parsing, a date can be created from a year, + * week-of-month, month-of-year and day-of-week. + *

                        + * In {@linkplain ResolverStyle#STRICT strict mode}, all four fields are + * validated against their range of valid values. The week-of-month field + * is validated to ensure that the resulting month is the month requested. + *

                        + * In {@linkplain ResolverStyle#SMART smart mode}, all four fields are + * validated against their range of valid values. The week-of-month field + * is validated from 0 to 6, meaning that the resulting date can be in a + * different month to that specified. + *

                        + * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week + * are validated against the range of valid values. The resulting date is calculated + * equivalent to the following four stage approach. + * First, create a date on the first day of the first week of January in the requested year. + * Then take the month-of-year, subtract one, and add the amount in months to the date. + * Then take the week-of-month, subtract one, and add the amount in weeks to the date. + * Finally, adjust to the correct day-of-week within the localized week. * * @return a field providing access to the week-of-month, not null */ @@ -447,6 +474,25 @@ public final class WeekFields implements Serializable { * - if the 5th day of the year is a Monday, week two starts on the 5th and the 1st to 4th is in week one
                        *

                        * This field can be used with any calendar system. + *

                        + * In the resolving phase of parsing, a date can be created from a year, + * week-of-year and day-of-week. + *

                        + * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are + * validated against their range of valid values. The week-of-year field + * is validated to ensure that the resulting year is the year requested. + *

                        + * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are + * validated against their range of valid values. The week-of-year field + * is validated from 0 to 54, meaning that the resulting date can be in a + * different year to that specified. + *

                        + * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week + * are validated against the range of valid values. The resulting date is calculated + * equivalent to the following three stage approach. + * First, create a date on the first day of the first week in the requested year. + * Then take the week-of-year, subtract one, and add the amount in weeks to the date. + * Finally, adjust to the correct day-of-week within the localized week. * * @return a field providing access to the week-of-year, not null */ @@ -477,6 +523,26 @@ public final class WeekFields implements Serializable { * the 1st to 4th is in week one
                        *

                        * This field can be used with any calendar system. + *

                        + * In the resolving phase of parsing, a date can be created from a week-based-year, + * week-of-year and day-of-week. + *

                        + * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are + * validated against their range of valid values. The week-of-year field + * is validated to ensure that the resulting week-based-year is the + * week-based-year requested. + *

                        + * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are + * validated against their range of valid values. The week-of-week-based-year field + * is validated from 1 to 53, meaning that the resulting date can be in the + * following week-based-year to that specified. + *

                        + * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week + * are validated against the range of valid values. The resulting date is calculated + * equivalent to the following three stage approach. + * First, create a date on the first day of the first week in the requested week-based-year. + * Then take the week-of-week-based-year, subtract one, and add the amount in weeks to the date. + * Finally, adjust to the correct day-of-week within the localized week. * * @return a field providing access to the week-of-week-based-year, not null */ @@ -499,6 +565,26 @@ public final class WeekFields implements Serializable { * is in the last week of the previous year. *

                        * This field can be used with any calendar system. + *

                        + * In the resolving phase of parsing, a date can be created from a week-based-year, + * week-of-year and day-of-week. + *

                        + * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are + * validated against their range of valid values. The week-of-year field + * is validated to ensure that the resulting week-based-year is the + * week-based-year requested. + *

                        + * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are + * validated against their range of valid values. The week-of-week-based-year field + * is validated from 1 to 53, meaning that the resulting date can be in the + * following week-based-year to that specified. + *

                        + * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week + * are validated against the range of valid values. The resulting date is calculated + * equivalent to the following three stage approach. + * First, create a date on the first day of the first week in the requested week-based-year. + * Then take the week-of-week-based-year, subtract one, and add the amount in weeks to the date. + * Finally, adjust to the correct day-of-week within the localized week. * * @return a field providing access to the week-based-year, not null */ @@ -615,9 +701,9 @@ public final class WeekFields implements Serializable { * @param dow the day of the week * @return a ChronoLocalDate for the requested year, week of year, and day of week */ - private ChronoLocalDate ofWeekBasedYear(Chronology chrono, + private ChronoLocalDate ofWeekBasedYear(Chronology chrono, int yowby, int wowby, int dow) { - ChronoLocalDate date = chrono.date(yowby, 1, 1); + ChronoLocalDate date = chrono.date(yowby, 1, 1); int ldow = localizedDayOfWeek(date); int offset = startOfWeekOffset(1, ldow); @@ -671,6 +757,11 @@ public final class WeekFields implements Serializable { return Math.floorMod(isoDow - sow, 7) + 1; } + private int localizedDayOfWeek(int isoDow) { + int sow = weekDef.getFirstDayOfWeek().getValue(); + return Math.floorMod(isoDow - sow, 7) + 1; + } + private long localizedWeekOfMonth(TemporalAccessor temporal) { int dow = localizedDayOfWeek(temporal); int dom = temporal.get(DAY_OF_MONTH); @@ -800,75 +891,121 @@ public final class WeekFields implements Serializable { } @Override - public Map resolve(TemporalAccessor temporal, long value, ResolverStyle resolverStyle) { - int newValue = range.checkValidIntValue(value, this); - int sow = weekDef.getFirstDayOfWeek().getValue(); + public ChronoLocalDate resolve( + Map fieldValues, Chronology chronology, ZoneId zone, ResolverStyle resolverStyle) { + final long value = fieldValues.get(this); + final int newValue = Math.toIntExact(value); // broad limit makes overflow checking lighter + // first convert localized day-of-week to ISO day-of-week + // doing this first handles case where both ISO and localized were parsed and might mismatch + // day-of-week is always strict as two different day-of-week values makes lenient complex if (rangeUnit == WEEKS) { // day-of-week - int isoDow = Math.floorMod((sow - 1) + (newValue - 1), 7) + 1; - return Collections.singletonMap(DAY_OF_WEEK, (long) isoDow); + final int checkedValue = range.checkValidIntValue(value, this); // no leniency as too complex + final int startDow = weekDef.getFirstDayOfWeek().getValue(); + long isoDow = Math.floorMod((startDow - 1) + (checkedValue - 1), 7) + 1; + fieldValues.remove(this); + fieldValues.put(DAY_OF_WEEK, isoDow); + return null; } - if (temporal.isSupported(DAY_OF_WEEK) == false) { + + // can only build date if ISO day-of-week is present + if (fieldValues.containsKey(DAY_OF_WEEK) == false) { return null; } - Chronology chrono = Chronology.from(temporal); // defaults to ISO - int dow = localizedDayOfWeek(temporal); - if (temporal.isSupported(YEAR)) { - int year = temporal.get(YEAR); - if (rangeUnit == MONTHS) { // week-of-month - if (temporal.isSupported(MONTH_OF_YEAR) == false) { - return null; - } - int month = temporal.get(ChronoField.MONTH_OF_YEAR); - @SuppressWarnings("rawtypes") - ChronoLocalDate date = chrono.date(year, month, 1); - int dateDow = localizedDayOfWeek(date); - long weeks = newValue - localizedWeekOfMonth(date); - int days = dow - dateDow; - date = date.plus(weeks * 7 + days, DAYS); - Map result = new HashMap<>(4, 1.0f); - result.put(EPOCH_DAY, date.toEpochDay()); - result.put(YEAR, null); - result.put(MONTH_OF_YEAR, null); - result.put(DAY_OF_WEEK, null); - return result; - } else if (rangeUnit == YEARS) { // week-of-year - @SuppressWarnings("rawtypes") - ChronoLocalDate date = chrono.date(year, 1, 1); - int dateDow = localizedDayOfWeek(date); - long weeks = newValue - localizedWeekOfYear(date); - int days = dow - dateDow; - date = date.plus(weeks * 7 + days, DAYS); - Map result = new HashMap<>(4, 1.0f); - result.put(EPOCH_DAY, date.toEpochDay()); - result.put(YEAR, null); - result.put(DAY_OF_WEEK, null); - return result; + int isoDow = DAY_OF_WEEK.checkValidIntValue(fieldValues.get(DAY_OF_WEEK)); + int dow = localizedDayOfWeek(isoDow); + + // build date + if (fieldValues.containsKey(YEAR)) { + int year = YEAR.checkValidIntValue(fieldValues.get(YEAR)); // validate + if (rangeUnit == MONTHS && fieldValues.containsKey(MONTH_OF_YEAR)) { // week-of-month + long month = fieldValues.get(MONTH_OF_YEAR); // not validated yet + return resolveWoM(fieldValues, chronology, year, month, newValue, dow, resolverStyle); } - } else if (rangeUnit == WEEK_BASED_YEARS || rangeUnit == FOREVER) { - if (temporal.isSupported(weekDef.weekBasedYear) && - temporal.isSupported(weekDef.weekOfWeekBasedYear)) { - // week-of-week-based-year and year-of-week-based-year - int yowby = temporal.get(weekDef.weekBasedYear); - int wowby = temporal.get(weekDef.weekOfWeekBasedYear); - ChronoLocalDate date = ofWeekBasedYear(Chronology.from(temporal), yowby, wowby, dow); - - Map result = new HashMap<>(4, 1.0f); - result.put(EPOCH_DAY, date.toEpochDay()); - result.put(DAY_OF_WEEK, null); - result.put(weekDef.weekOfWeekBasedYear, null); - result.put(weekDef.weekBasedYear, null); - return result; + if (rangeUnit == YEARS) { // week-of-year + return resolveWoY(fieldValues, chronology, year, newValue, dow, resolverStyle); } + } else if ((rangeUnit == WEEK_BASED_YEARS || rangeUnit == FOREVER) && + fieldValues.containsKey(weekDef.weekBasedYear) && + fieldValues.containsKey(weekDef.weekOfWeekBasedYear)) { // week-of-week-based-year and year-of-week-based-year + return resolveWBY(fieldValues, chronology, dow, resolverStyle); } return null; } - //----------------------------------------------------------------------- - @Override - public String getName() { - return name; + private ChronoLocalDate resolveWoM( + Map fieldValues, Chronology chrono, int year, long month, long wom, int localDow, ResolverStyle resolverStyle) { + ChronoLocalDate date; + if (resolverStyle == ResolverStyle.LENIENT) { + date = chrono.date(year, 1, 1).plus(Math.subtractExact(month, 1), MONTHS); + long weeks = Math.subtractExact(wom, localizedWeekOfMonth(date)); + int days = localDow - localizedDayOfWeek(date); // safe from overflow + date = date.plus(Math.addExact(Math.multiplyExact(weeks, 7), days), DAYS); + } else { + int monthValid = MONTH_OF_YEAR.checkValidIntValue(month); // validate + date = chrono.date(year, monthValid, 1); + int womInt = range.checkValidIntValue(wom, this); // validate + int weeks = (int) (womInt - localizedWeekOfMonth(date)); // safe from overflow + int days = localDow - localizedDayOfWeek(date); // safe from overflow + date = date.plus(weeks * 7 + days, DAYS); + if (resolverStyle == ResolverStyle.STRICT && date.getLong(MONTH_OF_YEAR) != month) { + throw new DateTimeException("Strict mode rejected resolved date as it is in a different month"); + } + } + fieldValues.remove(this); + fieldValues.remove(YEAR); + fieldValues.remove(MONTH_OF_YEAR); + fieldValues.remove(DAY_OF_WEEK); + return date; + } + + private ChronoLocalDate resolveWoY( + Map fieldValues, Chronology chrono, int year, long woy, int localDow, ResolverStyle resolverStyle) { + ChronoLocalDate date = chrono.date(year, 1, 1); + if (resolverStyle == ResolverStyle.LENIENT) { + long weeks = Math.subtractExact(woy, localizedWeekOfYear(date)); + int days = localDow - localizedDayOfWeek(date); // safe from overflow + date = date.plus(Math.addExact(Math.multiplyExact(weeks, 7), days), DAYS); + } else { + int womInt = range.checkValidIntValue(woy, this); // validate + int weeks = (int) (womInt - localizedWeekOfYear(date)); // safe from overflow + int days = localDow - localizedDayOfWeek(date); // safe from overflow + date = date.plus(weeks * 7 + days, DAYS); + if (resolverStyle == ResolverStyle.STRICT && date.getLong(YEAR) != year) { + throw new DateTimeException("Strict mode rejected resolved date as it is in a different year"); + } + } + fieldValues.remove(this); + fieldValues.remove(YEAR); + fieldValues.remove(DAY_OF_WEEK); + return date; + } + + private ChronoLocalDate resolveWBY( + Map fieldValues, Chronology chrono, int localDow, ResolverStyle resolverStyle) { + int yowby = weekDef.weekBasedYear.range().checkValidIntValue( + fieldValues.get(weekDef.weekBasedYear), weekDef.weekBasedYear); + ChronoLocalDate date; + if (resolverStyle == ResolverStyle.LENIENT) { + date = ofWeekBasedYear(chrono, yowby, 1, localDow); + long wowby = fieldValues.get(weekDef.weekOfWeekBasedYear); + long weeks = Math.subtractExact(wowby, 1); + date = date.plus(weeks, WEEKS); + } else { + int wowby = weekDef.weekOfWeekBasedYear.range().checkValidIntValue( + fieldValues.get(weekDef.weekOfWeekBasedYear), weekDef.weekOfWeekBasedYear); // validate + date = ofWeekBasedYear(chrono, yowby, wowby, localDow); + if (resolverStyle == ResolverStyle.STRICT && localizedWeekBasedYear(date) != yowby) { + throw new DateTimeException("Strict mode rejected resolved date as it is in a different week-based-year"); + } + } + fieldValues.remove(this); + fieldValues.remove(weekDef.weekBasedYear); + fieldValues.remove(weekDef.weekOfWeekBasedYear); + fieldValues.remove(DAY_OF_WEEK); + return date; } + //----------------------------------------------------------------------- @Override public String getDisplayName(Locale locale) { Objects.requireNonNull(locale, "locale"); @@ -876,9 +1013,9 @@ public final class WeekFields implements Serializable { LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased() .getLocaleResources(locale); ResourceBundle rb = lr.getJavaTimeFormatData(); - return rb.containsKey("field.week") ? rb.getString("field.week") : getName(); + return rb.containsKey("field.week") ? rb.getString("field.week") : name; } - return getName(); + return name; } @Override @@ -896,6 +1033,11 @@ public final class WeekFields implements Serializable { return true; } + @Override + public boolean isTimeBased() { + return false; + } + @Override public ValueRange range() { return range; @@ -988,7 +1130,7 @@ public final class WeekFields implements Serializable { //----------------------------------------------------------------------- @Override public String toString() { - return getName() + "[" + weekDef.toString() + "]"; + return name + "[" + weekDef.toString() + "]"; } } } diff --git a/src/share/classes/java/util/PriorityQueue.java b/src/share/classes/java/util/PriorityQueue.java index c28647b58bbd0bbeea21199c32f7fd4a4a17f5fc..c5a961cdbe9f291cd96fac79e10b359568cf4e29 100644 --- a/src/share/classes/java/util/PriorityQueue.java +++ b/src/share/classes/java/util/PriorityQueue.java @@ -135,6 +135,19 @@ public class PriorityQueue extends AbstractQueue this(initialCapacity, null); } + /** + * Creates a {@code PriorityQueue} with the default initial capacity + * that orders its elements according to the specified comparator. + * + * @param comparator the comparator that will be used to order this + * priority queue. If {@code null}, the {@linkplain Comparable + * natural ordering} of the elements will be used. + * @since 1.8 + */ + public PriorityQueue(Comparator comparator) { + this(DEFAULT_INITIAL_CAPACITY, comparator); + } + /** * Creates a {@code PriorityQueue} with the specified initial capacity * that orders its elements according to the specified comparator. diff --git a/src/share/classes/java/util/concurrent/AbstractExecutorService.java b/src/share/classes/java/util/concurrent/AbstractExecutorService.java index 4e2b766c94355d0f8e7f04e4d389dc7853539450..73aa047ca30947079d03b43495b65fc010e235c2 100644 --- a/src/share/classes/java/util/concurrent/AbstractExecutorService.java +++ b/src/share/classes/java/util/concurrent/AbstractExecutorService.java @@ -76,6 +76,7 @@ public abstract class AbstractExecutorService implements ExecutorService { * * @param runnable the runnable task being wrapped * @param value the default value for the returned future + * @param the type of the given value * @return a {@code RunnableFuture} which, when run, will run the * underlying runnable and which, as a {@code Future}, will yield * the given value as its result and provide for cancellation of @@ -90,6 +91,7 @@ public abstract class AbstractExecutorService implements ExecutorService { * Returns a {@code RunnableFuture} for the given callable task. * * @param callable the callable task being wrapped + * @param the type of the callable's result * @return a {@code RunnableFuture} which, when run, will call the * underlying callable and which, as a {@code Future}, will yield * the callable's result as its result and provide for diff --git a/src/share/classes/java/util/concurrent/ConcurrentHashMap.java b/src/share/classes/java/util/concurrent/ConcurrentHashMap.java index 08e2bd38239be56aa229fb57ad915e20759924b8..edd788afe25701d7142be732549f5421d44723db 100644 --- a/src/share/classes/java/util/concurrent/ConcurrentHashMap.java +++ b/src/share/classes/java/util/concurrent/ConcurrentHashMap.java @@ -265,7 +265,8 @@ import java.util.stream.Stream; * @param the type of keys maintained by this map * @param the type of mapped values */ -public class ConcurrentHashMap extends AbstractMap implements ConcurrentMap, Serializable { +public class ConcurrentHashMap extends AbstractMap + implements ConcurrentMap, Serializable { private static final long serialVersionUID = 7249069246763182397L; /* @@ -439,16 +440,18 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * related operations (which is the main reason we cannot use * existing collections such as TreeMaps). TreeBins contain * Comparable elements, but may contain others, as well as - * elements that are Comparable but not necessarily Comparable - * for the same T, so we cannot invoke compareTo among them. To - * handle this, the tree is ordered primarily by hash value, then - * by Comparable.compareTo order if applicable. On lookup at a - * node, if elements are not comparable or compare as 0 then both - * left and right children may need to be searched in the case of - * tied hash values. (This corresponds to the full list search - * that would be necessary if all elements were non-Comparable and - * had tied hashes.) The red-black balancing code is updated from - * pre-jdk-collections + * elements that are Comparable but not necessarily Comparable for + * the same T, so we cannot invoke compareTo among them. To handle + * this, the tree is ordered primarily by hash value, then by + * Comparable.compareTo order if applicable. On lookup at a node, + * if elements are not comparable or compare as 0 then both left + * and right children may need to be searched in the case of tied + * hash values. (This corresponds to the full list search that + * would be necessary if all elements were non-Comparable and had + * tied hashes.) On insertion, to keep a total ordering (or as + * close as is required here) across rebalancings, we compare + * classes and identityHashCodes as tie-breakers. The red-black + * balancing code is updated from pre-jdk-collections * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java) * based in turn on Cormen, Leiserson, and Rivest "Introduction to * Algorithms" (CLR). @@ -478,6 +481,10 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * unused "Segment" class that is instantiated in minimal form * only when serializing. * + * Also, solely for compatibility with previous versions of this + * class, it extends AbstractMap, even though all of its methods + * are overridden, so it is just useless baggage. + * * This file is organized to make things a little easier to follow * while reading than they might otherwise: First the main static * declarations and utilities, then fields, then main public @@ -1352,6 +1359,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * Saves the state of the {@code ConcurrentHashMap} instance to a * stream (i.e., serializes it). * @param s the stream + * @throws java.io.IOException if an I/O error occurs * @serialData * the key (Object) and value (Object) * for each key-value mapping, followed by a null pair. @@ -1394,6 +1402,9 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre /** * Reconstitutes the instance from a stream (that is, deserializes it). * @param s the stream + * @throws ClassNotFoundException if the class of a serialized object + * could not be found + * @throws java.io.IOException if an I/O error occurs */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { @@ -2080,6 +2091,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * Creates a new {@link Set} backed by a ConcurrentHashMap * from the given type to {@code Boolean.TRUE}. * + * @param the element type of the returned set * @return the new set * @since 1.8 */ @@ -2094,9 +2106,10 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * * @param initialCapacity The implementation performs internal * sizing to accommodate this many elements. + * @param the element type of the returned set + * @return the new set * @throws IllegalArgumentException if the initial capacity of * elements is negative - * @return the new set * @since 1.8 */ public static KeySetView newKeySet(int initialCapacity) { @@ -2643,19 +2656,18 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre p = pr; else if ((pk = p.key) == k || (pk != null && k.equals(pk))) return p; - else if (pl == null && pr == null) - break; + else if (pl == null) + p = pr; + else if (pr == null) + p = pl; else if ((kc != null || (kc = comparableClassFor(k)) != null) && (dir = compareComparables(kc, k, pk)) != 0) p = (dir < 0) ? pl : pr; - else if (pl == null) - p = pr; - else if (pr == null || - (q = pr.findTreeNode(h, k, kc)) == null) - p = pl; - else + else if ((q = pr.findTreeNode(h, k, kc)) != null) return q; + else + p = pl; } while (p != null); } return null; @@ -2681,6 +2693,23 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre static final int WAITER = 2; // set when waiting for write lock static final int READER = 4; // increment value for setting read lock + /** + * Tie-breaking utility for ordering insertions when equal + * hashCodes and non-comparable. We don't require a total + * order, just a consistent insertion rule to maintain + * equivalence across rebalancings. Tie-breaking further than + * necessary simplifies testing a bit. + */ + static int tieBreakOrder(Object a, Object b) { + int d; + if (a == null || b == null || + (d = a.getClass().getName(). + compareTo(b.getClass().getName())) == 0) + d = (System.identityHashCode(a) <= System.identityHashCode(b) ? + -1 : 1); + return d; + } + /** * Creates bin with initial set of nodes headed by b. */ @@ -2697,21 +2726,21 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre r = x; } else { - Object key = x.key; - int hash = x.hash; + K k = x.key; + int h = x.hash; Class kc = null; for (TreeNode p = r;;) { int dir, ph; - if ((ph = p.hash) > hash) + K pk = p.key; + if ((ph = p.hash) > h) dir = -1; - else if (ph < hash) + else if (ph < h) dir = 1; - else if ((kc != null || - (kc = comparableClassFor(key)) != null)) - dir = compareComparables(kc, key, p.key); - else - dir = 0; - TreeNode xp = p; + else if ((kc == null && + (kc = comparableClassFor(k)) == null) || + (dir = compareComparables(kc, k, pk)) == 0) + dir = tieBreakOrder(k, pk); + TreeNode xp = p; if ((p = (dir <= 0) ? p.left : p.right) == null) { x.parent = xp; if (dir <= 0) @@ -2725,6 +2754,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre } } this.root = r; + assert checkInvariants(root); } /** @@ -2805,8 +2835,9 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre */ final TreeNode putTreeVal(int h, K k, V v) { Class kc = null; + boolean searched = false; for (TreeNode p = root;;) { - int dir, ph; K pk; TreeNode q, pr; + int dir, ph; K pk; if (p == null) { first = root = new TreeNode(h, k, v, null, null); break; @@ -2820,21 +2851,25 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre else if ((kc == null && (kc = comparableClassFor(k)) == null) || (dir = compareComparables(kc, k, pk)) == 0) { - if (p.left == null) - dir = 1; - else if ((pr = p.right) == null || - (q = pr.findTreeNode(h, k, kc)) == null) - dir = -1; - else - return q; + if (!searched) { + TreeNode q, ch; + searched = true; + if (((ch = p.left) != null && + (q = ch.findTreeNode(h, k, kc)) != null) || + ((ch = p.right) != null && + (q = ch.findTreeNode(h, k, kc)) != null)) + return q; + } + dir = tieBreakOrder(k, pk); } + TreeNode xp = p; - if ((p = (dir < 0) ? p.left : p.right) == null) { + if ((p = (dir <= 0) ? p.left : p.right) == null) { TreeNode x, f = first; first = x = new TreeNode(h, k, v, f, xp); if (f != null) f.prev = x; - if (dir < 0) + if (dir <= 0) xp.left = x; else xp.right = x; @@ -3546,6 +3581,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * for an element, or null if there is no transformation (in * which case the action is not applied) * @param action the action + * @param the return type of the transformer * @since 1.8 */ public void forEach(long parallelismThreshold, @@ -3569,6 +3605,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * needed for this operation to be executed in parallel * @param searchFunction a function returning a non-null * result on success, else null + * @param the return type of the search function * @return a non-null result from applying the given search * function on each (key, value), or null if none * @since 1.8 @@ -3592,6 +3629,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * for an element, or null if there is no transformation (in * which case it is not combined) * @param reducer a commutative associative combining function + * @param the return type of the transformer * @return the result of accumulating the given transformation * of all (key, value) pairs * @since 1.8 @@ -3710,6 +3748,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * for an element, or null if there is no transformation (in * which case the action is not applied) * @param action the action + * @param the return type of the transformer * @since 1.8 */ public void forEachKey(long parallelismThreshold, @@ -3733,6 +3772,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * needed for this operation to be executed in parallel * @param searchFunction a function returning a non-null * result on success, else null + * @param the return type of the search function * @return a non-null result from applying the given search * function on each key, or null if none * @since 1.8 @@ -3775,6 +3815,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * for an element, or null if there is no transformation (in * which case it is not combined) * @param reducer a commutative associative combining function + * @param the return type of the transformer * @return the result of accumulating the given transformation * of all keys * @since 1.8 @@ -3894,6 +3935,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * for an element, or null if there is no transformation (in * which case the action is not applied) * @param action the action + * @param the return type of the transformer * @since 1.8 */ public void forEachValue(long parallelismThreshold, @@ -3917,6 +3959,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * needed for this operation to be executed in parallel * @param searchFunction a function returning a non-null * result on success, else null + * @param the return type of the search function * @return a non-null result from applying the given search * function on each value, or null if none * @since 1.8 @@ -3958,6 +4001,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * for an element, or null if there is no transformation (in * which case it is not combined) * @param reducer a commutative associative combining function + * @param the return type of the transformer * @return the result of accumulating the given transformation * of all values * @since 1.8 @@ -4075,6 +4119,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * for an element, or null if there is no transformation (in * which case the action is not applied) * @param action the action + * @param the return type of the transformer * @since 1.8 */ public void forEachEntry(long parallelismThreshold, @@ -4098,6 +4143,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * needed for this operation to be executed in parallel * @param searchFunction a function returning a non-null * result on success, else null + * @param the return type of the search function * @return a non-null result from applying the given search * function on each entry, or null if none * @since 1.8 @@ -4139,6 +4185,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concurre * for an element, or null if there is no transformation (in * which case it is not combined) * @param reducer a commutative associative combining function + * @param the return type of the transformer * @return the result of accumulating the given transformation * of all entries * @since 1.8 diff --git a/src/share/classes/java/util/concurrent/ExecutorService.java b/src/share/classes/java/util/concurrent/ExecutorService.java index e01921d16ce72612a9ebfe01cd9bd0e787ec744b..455b312b6f9307ceac29454361431c1664798c15 100644 --- a/src/share/classes/java/util/concurrent/ExecutorService.java +++ b/src/share/classes/java/util/concurrent/ExecutorService.java @@ -227,6 +227,7 @@ public interface ExecutorService extends Executor { * {@link Callable} form so they can be submitted. * * @param task the task to submit + * @param the type of the task's result * @return a Future representing pending completion of the task * @throws RejectedExecutionException if the task cannot be * scheduled for execution @@ -241,6 +242,7 @@ public interface ExecutorService extends Executor { * * @param task the task to submit * @param result the result to return + * @param the type of the result * @return a Future representing pending completion of the task * @throws RejectedExecutionException if the task cannot be * scheduled for execution @@ -272,6 +274,7 @@ public interface ExecutorService extends Executor { * collection is modified while this operation is in progress. * * @param tasks the collection of tasks + * @param the type of the values returned from the tasks * @return a list of Futures representing the tasks, in the same * sequential order as produced by the iterator for the * given task list, each of which has completed @@ -299,6 +302,7 @@ public interface ExecutorService extends Executor { * @param tasks the collection of tasks * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument + * @param the type of the values returned from the tasks * @return a list of Futures representing the tasks, in the same * sequential order as produced by the iterator for the * given task list. If the operation did not time out, @@ -324,6 +328,7 @@ public interface ExecutorService extends Executor { * collection is modified while this operation is in progress. * * @param tasks the collection of tasks + * @param the type of the values returned from the tasks * @return the result returned by one of the tasks * @throws InterruptedException if interrupted while waiting * @throws NullPointerException if tasks or any element task @@ -348,6 +353,7 @@ public interface ExecutorService extends Executor { * @param tasks the collection of tasks * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument + * @param the type of the values returned from the tasks * @return the result returned by one of the tasks * @throws InterruptedException if interrupted while waiting * @throws NullPointerException if tasks, or unit, or any element diff --git a/src/share/classes/java/util/concurrent/Executors.java b/src/share/classes/java/util/concurrent/Executors.java index 264e7ae33e71649f8953c65159396c2857afc46e..8f39829d6f5e260475dd1c2f2ce803879940f87e 100644 --- a/src/share/classes/java/util/concurrent/Executors.java +++ b/src/share/classes/java/util/concurrent/Executors.java @@ -397,6 +397,7 @@ public class Executors { * {@code Callable} to an otherwise resultless action. * @param task the task to run * @param result the result to return + * @param the type of the result * @return a callable object * @throws NullPointerException if task null */ @@ -458,6 +459,7 @@ public class Executors { * action; or if not possible, throw an associated {@link * AccessControlException}. * @param callable the underlying task + * @param the type of the callable's result * @return a callable object * @throws NullPointerException if callable null */ @@ -480,6 +482,7 @@ public class Executors { * AccessControlException}. * * @param callable the underlying task + * @param the type of the callable's result * @return a callable object * @throws NullPointerException if callable null * @throws AccessControlException if the current access control diff --git a/src/share/classes/java/util/concurrent/ForkJoinPool.java b/src/share/classes/java/util/concurrent/ForkJoinPool.java index c9df40bc7b04a05c40c26d3200d8034e230b65b4..6db2d48c166ba61d2c9d51ddb6f7505407f36a7c 100644 --- a/src/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/src/share/classes/java/util/concurrent/ForkJoinPool.java @@ -561,8 +561,8 @@ public class ForkJoinPool extends AbstractExecutorService { * Returns a new worker thread operating in the given pool. * * @param pool the pool this thread works in - * @throws NullPointerException if the pool is null * @return the new worker thread + * @throws NullPointerException if the pool is null */ public ForkJoinWorkerThread newThread(ForkJoinPool pool); } @@ -2497,6 +2497,7 @@ public class ForkJoinPool extends AbstractExecutorService { * minimally only the latter. * * @param task the task + * @param the type of the task's result * @return the task's result * @throws NullPointerException if the task is null * @throws RejectedExecutionException if the task cannot be @@ -2545,6 +2546,7 @@ public class ForkJoinPool extends AbstractExecutorService { * Submits a ForkJoinTask for execution. * * @param task the task to submit + * @param the type of the task's result * @return the task * @throws NullPointerException if the task is null * @throws RejectedExecutionException if the task cannot be diff --git a/src/share/classes/java/util/concurrent/ForkJoinTask.java b/src/share/classes/java/util/concurrent/ForkJoinTask.java index 56262ea1bdb48241cbe39a3dca92587c21f9e5ed..5f239dbf894406fb922fd0f6d7d235f07083d598 100644 --- a/src/share/classes/java/util/concurrent/ForkJoinTask.java +++ b/src/share/classes/java/util/concurrent/ForkJoinTask.java @@ -810,6 +810,7 @@ public abstract class ForkJoinTask implements Future, Serializable { * unprocessed. * * @param tasks the collection of tasks + * @param the type of the values returned from the tasks * @return the tasks argument, to simplify usage * @throws NullPointerException if tasks or any element are null */ @@ -1472,6 +1473,7 @@ public abstract class ForkJoinTask implements Future, Serializable { * * @param runnable the runnable action * @param result the result upon completion + * @param the type of the result * @return the task */ public static ForkJoinTask adapt(Runnable runnable, T result) { @@ -1485,6 +1487,7 @@ public abstract class ForkJoinTask implements Future, Serializable { * encountered into {@code RuntimeException}. * * @param callable the callable action + * @param the type of the callable's result * @return the task */ public static ForkJoinTask adapt(Callable callable) { @@ -1498,6 +1501,8 @@ public abstract class ForkJoinTask implements Future, Serializable { /** * Saves this task to a stream (that is, serializes it). * + * @param s the stream + * @throws java.io.IOException if an I/O error occurs * @serialData the current run status and the exception thrown * during execution, or {@code null} if none */ @@ -1509,6 +1514,10 @@ public abstract class ForkJoinTask implements Future, Serializable { /** * Reconstitutes this task from a stream (that is, deserializes it). + * @param s the stream + * @throws ClassNotFoundException if the class of a serialized object + * could not be found + * @throws java.io.IOException if an I/O error occurs */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { diff --git a/src/share/classes/java/util/concurrent/ScheduledExecutorService.java b/src/share/classes/java/util/concurrent/ScheduledExecutorService.java index da9c68c0daba068a7a53568a2cdb9ca905255f72..d20aaef060efaeac731df00f86eb64d782c20ae2 100644 --- a/src/share/classes/java/util/concurrent/ScheduledExecutorService.java +++ b/src/share/classes/java/util/concurrent/ScheduledExecutorService.java @@ -117,6 +117,7 @@ public interface ScheduledExecutorService extends ExecutorService { * @param callable the function to execute * @param delay the time from now to delay execution * @param unit the time unit of the delay parameter + * @param the type of the callable's result * @return a ScheduledFuture that can be used to extract result or cancel * @throws RejectedExecutionException if the task cannot be * scheduled for execution diff --git a/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java b/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java index afe3b36196fa574efc2ac4695bf30ce0d293bdd4..458828c90ed2ad7e08163a7d76a9af760aeb5072 100644 --- a/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java +++ b/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java @@ -392,6 +392,7 @@ public class ScheduledThreadPoolExecutor * * @param runnable the submitted Runnable * @param task the task created to execute the runnable + * @param the type of the task's result * @return a task that can execute the runnable * @since 1.6 */ @@ -408,6 +409,7 @@ public class ScheduledThreadPoolExecutor * * @param callable the submitted Callable * @param task the task created to execute the callable + * @param the type of the task's result * @return a task that can execute the callable * @since 1.6 */ diff --git a/src/share/classes/java/util/concurrent/TimeUnit.java b/src/share/classes/java/util/concurrent/TimeUnit.java index bd56b4835a747ca114d6797bc575a67b2638a67b..e5c007d8c5f911edcbf4aebeea258a6a6fc17f5f 100644 --- a/src/share/classes/java/util/concurrent/TimeUnit.java +++ b/src/share/classes/java/util/concurrent/TimeUnit.java @@ -69,6 +69,9 @@ package java.util.concurrent; * @author Doug Lea */ public enum TimeUnit { + /** + * Time unit representing one thousandth of a microsecond + */ NANOSECONDS { public long toNanos(long d) { return d; } public long toMicros(long d) { return d/(C1/C0); } @@ -80,6 +83,10 @@ public enum TimeUnit { public long convert(long d, TimeUnit u) { return u.toNanos(d); } int excessNanos(long d, long m) { return (int)(d - (m*C2)); } }, + + /** + * Time unit representing one thousandth of a millisecond + */ MICROSECONDS { public long toNanos(long d) { return x(d, C1/C0, MAX/(C1/C0)); } public long toMicros(long d) { return d; } @@ -91,6 +98,10 @@ public enum TimeUnit { public long convert(long d, TimeUnit u) { return u.toMicros(d); } int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); } }, + + /** + * Time unit representing one thousandth of a second + */ MILLISECONDS { public long toNanos(long d) { return x(d, C2/C0, MAX/(C2/C0)); } public long toMicros(long d) { return x(d, C2/C1, MAX/(C2/C1)); } @@ -102,6 +113,10 @@ public enum TimeUnit { public long convert(long d, TimeUnit u) { return u.toMillis(d); } int excessNanos(long d, long m) { return 0; } }, + + /** + * Time unit representing one second + */ SECONDS { public long toNanos(long d) { return x(d, C3/C0, MAX/(C3/C0)); } public long toMicros(long d) { return x(d, C3/C1, MAX/(C3/C1)); } @@ -113,6 +128,10 @@ public enum TimeUnit { public long convert(long d, TimeUnit u) { return u.toSeconds(d); } int excessNanos(long d, long m) { return 0; } }, + + /** + * Time unit representing sixty seconds + */ MINUTES { public long toNanos(long d) { return x(d, C4/C0, MAX/(C4/C0)); } public long toMicros(long d) { return x(d, C4/C1, MAX/(C4/C1)); } @@ -124,6 +143,10 @@ public enum TimeUnit { public long convert(long d, TimeUnit u) { return u.toMinutes(d); } int excessNanos(long d, long m) { return 0; } }, + + /** + * Time unit representing sixty minutes + */ HOURS { public long toNanos(long d) { return x(d, C5/C0, MAX/(C5/C0)); } public long toMicros(long d) { return x(d, C5/C1, MAX/(C5/C1)); } @@ -135,6 +158,10 @@ public enum TimeUnit { public long convert(long d, TimeUnit u) { return u.toHours(d); } int excessNanos(long d, long m) { return 0; } }, + + /** + * Time unit representing twenty four hours + */ DAYS { public long toNanos(long d) { return x(d, C6/C0, MAX/(C6/C0)); } public long toMicros(long d) { return x(d, C6/C1, MAX/(C6/C1)); } diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java index af72a4755d4ebea0303e5ac5446957b75164d72b..a60b7ce621b350a59e6237ac09585c65ec399c1d 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java @@ -71,6 +71,7 @@ public abstract class AtomicIntegerFieldUpdater { * * @param tclass the class of the objects holding the field * @param fieldName the name of the field to be updated + * @param the type of instances of tclass * @return the updater * @throws IllegalArgumentException if the field is not a * volatile integer type diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java index 9a298d64931fe53c5f6403ae2f1f007cf693270d..aae2b248a124ad70f9422c45020e392e36d4ebed 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java @@ -71,6 +71,7 @@ public abstract class AtomicLongFieldUpdater { * * @param tclass the class of the objects holding the field * @param fieldName the name of the field to be updated + * @param the type of instances of tclass * @return the updater * @throws IllegalArgumentException if the field is not a * volatile long type diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java index 901b71c9d2b45152c22ce153ee2f337fcdffce3e..f0a084001828bd500d1359a122b4dcd9ca22be18 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java @@ -91,6 +91,8 @@ public abstract class AtomicReferenceFieldUpdater { * @param tclass the class of the objects holding the field * @param vclass the class of the field * @param fieldName the name of the field to be updated + * @param the type of instances of tclass + * @param the type of instances of vclass * @return the updater * @throws ClassCastException if the field is of the wrong type * @throws IllegalArgumentException if the field is not volatile diff --git a/src/share/classes/java/util/function/BiConsumer.java b/src/share/classes/java/util/function/BiConsumer.java index afc0ba34d1e7ea90c9558dafb1ac01c9f9bcafcd..61690e6471a795c951d7afcc30189dbbc63d7f5d 100644 --- a/src/share/classes/java/util/function/BiConsumer.java +++ b/src/share/classes/java/util/function/BiConsumer.java @@ -27,13 +27,16 @@ package java.util.function; import java.util.Objects; /** - * An operation which accepts two input arguments and returns no result. This is - * the two-arity specialization of {@link Consumer}. Unlike most other - * functional interfaces, {@code BiConsumer} is expected to operate via - * side-effects. + * Represents an operation that accepts two input arguments and returns no + * result. This is the two-arity specialization of {@link Consumer}. + * Unlike most other functional interfaces, {@code BiConsumer} is expected + * to operate via side-effects. * - * @param the type of the first argument to the {@code accept} operation - * @param the type of the second argument to the {@code accept} operation + *

                        This is a functional interface + * whose functional method is {@link #accept(Object, Object)}. + * + * @param the type of the first argument to the operation + * @param the type of the second argument to the operation * * @see Consumer * @since 1.8 @@ -42,35 +45,31 @@ import java.util.Objects; public interface BiConsumer { /** - * Performs operations upon the provided objects which may modify those - * objects and/or external state. + * Performs this operation on the given arguments. * - * @param t an input object - * @param u an input object + * @param t the first input argument + * @param u the second input argument */ void accept(T t, U u); /** - * Returns a {@code BiConsumer} which performs, in sequence, the operation - * represented by this object followed by the operation represented by - * the other {@code BiConsumer}. - * - *

                        Any exceptions thrown by either {@code accept} method are relayed - * to the caller; if performing this operation throws an exception, the - * other operation will not be performed. + * Returns a composed {@code BiConsumer} that performs, in sequence, this + * operation followed by the {@code after} operation. If performing either + * operation throws an exception, it is relayed to the caller of the + * composed operation. If performing this operation throws an exception, + * the {@code after} operation will not be performed. * - * @param other a BiConsumer which will be chained after this BiConsumer - * @return a BiConsumer which performs in sequence the {@code accept} method - * of this BiConsumer and the {@code accept} method of the specified - * BiConsumer operation - * @throws NullPointerException if other is null + * @param after the operation to perform after this operation + * @return a composed {@code BiConsumer} that performs in sequence this + * operation followed by the {@code after} operation + * @throws NullPointerException if {@code after} is null */ - default BiConsumer chain(BiConsumer other) { - Objects.requireNonNull(other); + default BiConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); return (l, r) -> { accept(l, r); - other.accept(l, r); + after.accept(l, r); }; } } diff --git a/src/share/classes/java/util/function/BiFunction.java b/src/share/classes/java/util/function/BiFunction.java index fb66ec0e8bbde0262f2fddb957c3c0ca4f2f25bc..ef75901fb3461e0556e1ddaa45ffc52b05a5233f 100644 --- a/src/share/classes/java/util/function/BiFunction.java +++ b/src/share/classes/java/util/function/BiFunction.java @@ -27,14 +27,15 @@ package java.util.function; import java.util.Objects; /** - * Apply a function to the input arguments, yielding an appropriate result. This - * is the two-arity specialization of {@link Function}. A function may - * variously provide a mapping between types, object instances or keys and - * values or any other form of transformation upon the input. + * Represents a function that accepts two arguments and produces a result. + * This is the two-arity specialization of {@link Function}. * - * @param the type of the first argument to the {@code apply} operation - * @param the type of the second argument to the {@code apply} operation - * @param the type of results returned by the {@code apply} operation + *

                        This is a functional interface + * whose functional method is {@link #apply(Object, Object)}. + * + * @param the type of the first argument to the function + * @param the type of the second argument to the function + * @param the type of the result of the function * * @see Function * @since 1.8 @@ -43,25 +44,25 @@ import java.util.Objects; public interface BiFunction { /** - * Compute the result of applying the function to the input arguments + * Applies this function to the given arguments. * - * @param t an input object - * @param u an input object + * @param t the first function argument + * @param u the second function argument * @return the function result */ R apply(T t, U u); /** - * Returns a new function which applies this function followed by the - * provided function. If either function throws an exception, it is relayed - * to the caller. + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. * - * @param Type of output objects to the combined function. May be the - * same type as {@code }, {@code } or {@code } - * @param after An additional function to be applied after this function is - * applied - * @return A function which performs this function followed by the provided - * function + * @param the type of output of the {@code after} function, and of the + * composed function + * @param after the function to apply after this function is applied + * @return a composed function that first applies this function and then + * applies the {@code after} function * @throws NullPointerException if after is null */ default BiFunction andThen(Function after) { diff --git a/src/share/classes/java/util/function/BiPredicate.java b/src/share/classes/java/util/function/BiPredicate.java index 29e92b875f76e11d66261b6df2e039cb3e90a3dd..a0f19b812d0e3709aa1d32fe55570bb3f8f32f44 100644 --- a/src/share/classes/java/util/function/BiPredicate.java +++ b/src/share/classes/java/util/function/BiPredicate.java @@ -27,11 +27,14 @@ package java.util.function; import java.util.Objects; /** - * Determines if the input objects match some criteria. This is the two-arity - * specialization of {@link Predicate}. + * Represents a predicate (boolean-valued function) of two arguments. This is + * the two-arity specialization of {@link Predicate}. * - * @param the type of the first argument to {@code test} - * @param the type of the second argument to {@code test} + *

                        This is a functional interface + * whose functional method is {@link #test(Object, Object)}. + * + * @param the type of the first argument to the predicate + * @param the type of the second argument the predicate * * @see Predicate * @since 1.8 @@ -40,34 +43,41 @@ import java.util.Objects; public interface BiPredicate { /** - * Return {@code true} if the inputs match some criteria. + * Evaluates this predicate on the given arguments. * - * @param t an input object - * @param u an input object - * @return {@code true} if the inputs match some criteria + * @param t the first input argument + * @param u the second input argument + * @return {@code true} if the input arguments match the predicate, + * otherwise {@code false} */ boolean test(T t, U u); /** - * Returns a predicate which evaluates to {@code true} only if this - * predicate and the provided predicate both evaluate to {@code true}. If - * this predicate returns {@code false} then the remaining predicate is not - * evaluated. + * Returns a composed predicate that represents a short-circuiting logical + * AND of this predicate and another. When evaluating the composed + * predicate, if this predicate is {@code false}, then the {@code other} + * predicate is not evaluated. + * + *

                        Any exceptions thrown during evaluation of either predicate are relayed + * to the caller; if evaluation of this predicate throws an exception, the + * {@code other} predicate will not be evaluated. * - * @param p a predicate which will be logically-ANDed with this predicate - * @return a new predicate which returns {@code true} only if both - * predicates return {@code true} - * @throws NullPointerException if p is null + * @param other a predicate that will be logically-ANDed with this + * predicate + * @return a composed predicate that represents the short-circuiting logical + * AND of this predicate and the {@code other} predicate + * @throws NullPointerException if other is null */ - default BiPredicate and(BiPredicate p) { - Objects.requireNonNull(p); - return (T t, U u) -> test(t, u) && p.test(t, u); + default BiPredicate and(BiPredicate other) { + Objects.requireNonNull(other); + return (T t, U u) -> test(t, u) && other.test(t, u); } /** - * Returns a predicate which negates the result of this predicate. + * Returns a predicate that represents the logical negation of this + * predicate. * - * @return a new predicate who's result is always the opposite of this + * @return a predicate that represents the logical negation of this * predicate */ default BiPredicate negate() { @@ -75,18 +85,23 @@ public interface BiPredicate { } /** - * Returns a predicate which evaluates to {@code true} if either this - * predicate or the provided predicate evaluates to {@code true}. If this - * predicate returns {@code true} then the remaining predicate is not - * evaluated. + * Returns a composed predicate that represents a short-circuiting logical + * OR of this predicate and another. When evaluating the composed + * predicate, if this predicate is {@code true}, then the {@code other} + * predicate is not evaluated. + * + *

                        Any exceptions thrown during evaluation of either predicate are relayed + * to the caller; if evaluation of this predicate throws an exception, the + * {@code other} predicate will not be evaluated. * - * @param p a predicate which will be logically-ORed with this predicate - * @return a new predicate which returns {@code true} if either predicate - * returns {@code true} - * @throws NullPointerException if p is null + * @param other a predicate that will be logically-ORed with this + * predicate + * @return a composed predicate that represents the short-circuiting logical + * OR of this predicate and the {@code other} predicate + * @throws NullPointerException if other is null */ - default BiPredicate or(BiPredicate p) { - Objects.requireNonNull(p); - return (T t, U u) -> test(t, u) || p.test(t, u); + default BiPredicate or(BiPredicate other) { + Objects.requireNonNull(other); + return (T t, U u) -> test(t, u) || other.test(t, u); } } diff --git a/src/share/classes/java/util/function/BinaryOperator.java b/src/share/classes/java/util/function/BinaryOperator.java index 195eba1c3c1fa2991c1a8c6dfe5b29ffa78bbb65..a0150589c808b1fde2140310645920764f5c5167 100644 --- a/src/share/classes/java/util/function/BinaryOperator.java +++ b/src/share/classes/java/util/function/BinaryOperator.java @@ -28,42 +28,48 @@ import java.util.Objects; import java.util.Comparator; /** - * An operation upon two operands yielding a result. This is a specialization of - * {@code BiFunction} where the operands and the result are all of the same type. + * Represents an operation upon two operands of the same type, producing a result + * of the same type as the operands. This is a specialization of + * {@link BiFunction} for the case where the operands and the result are all of + * the same type. * - * @param the type of operands to {@code apply} and of the result + *

                        This is a functional interface + * whose functional method is {@link #apply(Object, Object)}. + * + * @param the type of the operands and result of the operator * * @see BiFunction + * @see UnaryOperator * @since 1.8 */ @FunctionalInterface public interface BinaryOperator extends BiFunction { /** * Returns a {@link BinaryOperator} which returns the lesser of two elements - * according to the specified {@code Comparator} + * according to the specified {@code Comparator}. * - * @param the type of values to be compared and returned - * @param comparator a {@code Comparator} for comparing the two values + * @param the type of the input arguments of the comparator + * @param comparator a {@code Comparator} for comparing the two values * @return a {@code BinaryOperator} which returns the lesser of its operands, * according to the supplied {@code Comparator} * @throws NullPointerException if the argument is null */ - public static BinaryOperator minBy(Comparator comparator) { + public static BinaryOperator minBy(Comparator comparator) { Objects.requireNonNull(comparator); return (a, b) -> comparator.compare(a, b) <= 0 ? a : b; } /** * Returns a {@link BinaryOperator} which returns the greater of two elements - * according to the specified {@code Comparator} + * according to the specified {@code Comparator}. * - * @param the type of values to be compared and returned - * @param comparator a {@code Comparator} for comparing the two values + * @param the type of the input arguments of the comparator + * @param comparator a {@code Comparator} for comparing the two values * @return a {@code BinaryOperator} which returns the greater of its operands, * according to the supplied {@code Comparator} * @throws NullPointerException if the argument is null */ - public static BinaryOperator maxBy(Comparator comparator) { + public static BinaryOperator maxBy(Comparator comparator) { Objects.requireNonNull(comparator); return (a, b) -> comparator.compare(a, b) >= 0 ? a : b; } diff --git a/src/share/classes/java/util/function/BooleanSupplier.java b/src/share/classes/java/util/function/BooleanSupplier.java index 875ac74862881930fb0d721da97b4d917c3dd152..2faff307e635bc791c0577b7183ff5f121caf820 100644 --- a/src/share/classes/java/util/function/BooleanSupplier.java +++ b/src/share/classes/java/util/function/BooleanSupplier.java @@ -26,8 +26,14 @@ package java.util.function; /** - * A supplier of {@code boolean} values. This is the {@code boolean}-providing - * primitive specialization of {@link Supplier}. + * Represents a supplier of {@code boolean}-valued results. This is the + * {@code boolean}-producing primitive specialization of {@link Supplier}. + * + *

                        There is no requirement that a new or distinct result be returned each + * time the supplier is invoked. + * + *

                        This is a functional interface + * whose functional method is {@link #getAsBoolean()}. * * @see Supplier * @since 1.8 @@ -36,9 +42,9 @@ package java.util.function; public interface BooleanSupplier { /** - * Returns a {@code boolean} value. + * Gets a result. * - * @return a {@code boolean} value + * @return a result */ boolean getAsBoolean(); } diff --git a/src/share/classes/java/util/function/Consumer.java b/src/share/classes/java/util/function/Consumer.java index 69add851dcc2ad250cb2c05b9b1f124d0488c314..a2481fe4f41f80e2cc8d6170de1e001e059d6e72 100644 --- a/src/share/classes/java/util/function/Consumer.java +++ b/src/share/classes/java/util/function/Consumer.java @@ -27,11 +27,14 @@ package java.util.function; import java.util.Objects; /** - * An operation which accepts a single input argument and returns no result. - * Unlike most other functional interfaces, {@code Consumer} is expected to - * operate via side-effects. + * Represents an operation that accepts a single input argument and returns no + * result. Unlike most other functional interfaces, {@code Consumer} is expected + * to operate via side-effects. * - * @param The type of input objects to {@code accept} + *

                        This is a functional interface + * whose functional method is {@link #accept(Object)}. + * + * @param the type of the input to the operation * * @since 1.8 */ @@ -39,29 +42,26 @@ import java.util.Objects; public interface Consumer { /** - * Accept an input value. + * Performs this operation on the given argument. * - * @param t the input object + * @param t the input argument */ void accept(T t); /** - * Returns a {@code Consumer} which performs, in sequence, the operation - * represented by this object followed by the operation represented by - * the other {@code Consumer}. - * - *

                        Any exceptions thrown by either {@code accept} method are relayed - * to the caller; if performing this operation throws an exception, the - * other operation will not be performed. + * Returns a composed {@code Consumer} that performs, in sequence, this + * operation followed by the {@code after} operation. If performing either + * operation throws an exception, it is relayed to the caller of the + * composed operation. If performing this operation throws an exception, + * the {@code after} operation will not be performed. * - * @param other a Consumer which will be chained after this Consumer - * @return a Consumer which performs in sequence the {@code accept} method - * of this Consumer and the {@code accept} method of the specified Consumer - * operation - * @throws NullPointerException if other is null + * @param after the operation to perform after this operation + * @return a composed {@code Consumer} that performs in sequence this + * operation followed by the {@code after} operation + * @throws NullPointerException if {@code after} is null */ - default Consumer chain(Consumer other) { - Objects.requireNonNull(other); - return (T t) -> { accept(t); other.accept(t); }; + default Consumer andThen(Consumer after) { + Objects.requireNonNull(after); + return (T t) -> { accept(t); after.accept(t); }; } } diff --git a/src/share/classes/java/util/function/DoubleBinaryOperator.java b/src/share/classes/java/util/function/DoubleBinaryOperator.java index 7d1e68aaced1dc9b357bd7d352bda87905e7de0a..839433da573874d4eebeb882768b6e8806183d48 100644 --- a/src/share/classes/java/util/function/DoubleBinaryOperator.java +++ b/src/share/classes/java/util/function/DoubleBinaryOperator.java @@ -25,23 +25,25 @@ package java.util.function; /** - * An operation on two {@code double} operands yielding a {@code double} result. - * This is the primitive type specialization of {@link BinaryOperator} for - * {@code double}. + * Represents an operation upon two {@code double}-valued operands and producing a + * {@code double}-valued result. This is the primitive type specialization of + * {@link BinaryOperator} for {@code double}. + * + *

                        This is a functional interface + * whose functional method is {@link #applyAsDouble(double, double)}. * * @see BinaryOperator + * @see DoubleUnaryOperator * @since 1.8 */ @FunctionalInterface public interface DoubleBinaryOperator { /** - * Returns the {@code double} result of the operation upon the - * {@code double} operands. The parameters are named {@code left} and - * {@code right} for operations where the order of parameters matters. + * Applies this operator to the given operands. * - * @param left the left operand value - * @param right the right operand value - * @return the result of the operation + * @param left the first operand + * @param right the second operand + * @return the operator result */ double applyAsDouble(double left, double right); } diff --git a/src/share/classes/java/util/function/DoubleConsumer.java b/src/share/classes/java/util/function/DoubleConsumer.java index 665b80a3d20fd3338371a7d3fa4d6d4d9d0b4bc0..046360c6da88f8acd7688d2e4a0bf340c72353f4 100644 --- a/src/share/classes/java/util/function/DoubleConsumer.java +++ b/src/share/classes/java/util/function/DoubleConsumer.java @@ -27,11 +27,14 @@ package java.util.function; import java.util.Objects; /** - * An operation which accepts a single double argument and returns no result. - * This is the primitive type specialization of {@link Consumer} for - * {@code double}. Unlike most other functional interfaces, + * Represents an operation that accepts a single {@code double}-valued argument and + * returns no result. This is the primitive type specialization of + * {@link Consumer} for {@code double}. Unlike most other functional interfaces, * {@code DoubleConsumer} is expected to operate via side-effects. * + *

                        This is a functional interface + * whose functional method is {@link #accept(double)}. + * * @see Consumer * @since 1.8 */ @@ -39,30 +42,26 @@ import java.util.Objects; public interface DoubleConsumer { /** - * Accept an input value. + * Performs this operation on the given argument. * - * @param value the input value + * @param value the input argument */ void accept(double value); /** - * Returns a {@code DoubleConsumer} which performs, in sequence, the operation - * represented by this object followed by the operation represented by - * another {@code DoubleConsumer}. - * - *

                        Any exceptions thrown by either {@code accept} method are relayed - * to the caller; if performing this operation throws an exception, the - * other operation will not be performed. + * Returns a composed {@code DoubleConsumer} that performs, in sequence, this + * operation followed by the {@code after} operation. If performing either + * operation throws an exception, it is relayed to the caller of the + * composed operation. If performing this operation throws an exception, + * the {@code after} operation will not be performed. * - * @param other a DoubleConsumer which will be chained after this - * DoubleConsumer - * @return an DoubleConsumer which performs in sequence the {@code accept} method - * of this DoubleConsumer and the {@code accept} method of the specified IntConsumer - * operation - * @throws NullPointerException if other is null + * @param after the operation to perform after this operation + * @return a composed {@code DoubleConsumer} that performs in sequence this + * operation followed by the {@code after} operation + * @throws NullPointerException if {@code after} is null */ - default DoubleConsumer chain(DoubleConsumer other) { - Objects.requireNonNull(other); - return (double t) -> { accept(t); other.accept(t); }; + default DoubleConsumer andThen(DoubleConsumer after) { + Objects.requireNonNull(after); + return (double t) -> { accept(t); after.accept(t); }; } } diff --git a/src/share/classes/java/util/function/DoubleFunction.java b/src/share/classes/java/util/function/DoubleFunction.java index d8141d0a8a23e87c1696620aba43f113e8f2aaaf..a8bb57ddd88ca773a1907d0c4a922df5283350c0 100644 --- a/src/share/classes/java/util/function/DoubleFunction.java +++ b/src/share/classes/java/util/function/DoubleFunction.java @@ -25,11 +25,14 @@ package java.util.function; /** - * Apply a function to the double-valued input argument, yielding an appropriate - * result. This is the {@code double}-consuming primitive specialization for + * Represents a function that accepts a double-valued argument and produces a + * result. This is the {@code double}-consuming primitive specialization for * {@link Function}. * - * @param the type of output objects from the function + *

                        This is a functional interface + * whose functional method is {@link #apply(double)}. + * + * @param the type of the result of the function * * @see Function * @since 1.8 @@ -38,9 +41,9 @@ package java.util.function; public interface DoubleFunction { /** - * Compute the result of applying the function to the input argument + * Applies this function to the given argument. * - * @param value the input value + * @param value the function argument * @return the function result */ R apply(double value); diff --git a/src/share/classes/java/util/function/DoublePredicate.java b/src/share/classes/java/util/function/DoublePredicate.java index 8156b65cb93aaba6a495803060345387193f0981..1df17624cabd99745a1313f4097a85b46337df6f 100644 --- a/src/share/classes/java/util/function/DoublePredicate.java +++ b/src/share/classes/java/util/function/DoublePredicate.java @@ -27,9 +27,12 @@ package java.util.function; import java.util.Objects; /** - * Determines if the {@code double} input value matches some criteria. This is - * the {@code double}-consuming primitive type specialization of - * {@link Predicate}. + * Represents a predicate (boolean-valued function) of one {@code double}-valued + * argument. This is the {@code double}-consuming primitive type specialization + * of {@link Predicate}. + * + *

                        This is a functional interface + * whose functional method is {@link #test(double)}. * * @see Predicate * @since 1.8 @@ -38,38 +41,40 @@ import java.util.Objects; public interface DoublePredicate { /** - * Returns {@code true} if the input value matches some criteria. + * Evaluates this predicate on the given argument. * - * @param value the value to be tested - * @return {@code true} if the input value matches some criteria, otherwise - * {@code false} + * @param value the input argument + * @return {@code true} if the input argument matches the predicate, + * otherwise {@code false} */ boolean test(double value); /** - * Returns a predicate which evaluates to {@code true} only if this - * predicate and the provided predicate both evaluate to {@code true}. If - * this predicate returns {@code false} then the remaining predicate is not - * evaluated. + * Returns a composed predicate that represents a short-circuiting logical + * AND of this predicate and another. When evaluating the composed + * predicate, if this predicate is {@code false}, then the {@code other} + * predicate is not evaluated. * - *

                        Any exceptions thrown by either {@code test} method are relayed - * to the caller; if performing first operation throws an exception, the - * second operation will not be performed. + *

                        Any exceptions thrown during evaluation of either predicate are relayed + * to the caller; if evaluation of this predicate throws an exception, the + * {@code other} predicate will not be evaluated. * - * @param p a predicate which will be logically-ANDed with this predicate - * @return a new predicate which returns {@code true} only if both - * predicates return {@code true} - * @throws NullPointerException if p is null + * @param other a predicate that will be logically-ANDed with this + * predicate + * @return a composed predicate that represents the short-circuiting logical + * AND of this predicate and the {@code other} predicate + * @throws NullPointerException if other is null */ - default DoublePredicate and(DoublePredicate p) { - Objects.requireNonNull(p); - return (value) -> test(value) && p.test(value); + default DoublePredicate and(DoublePredicate other) { + Objects.requireNonNull(other); + return (value) -> test(value) && other.test(value); } /** - * Returns a predicate which negates the result of this predicate. + * Returns a predicate that represents the logical negation of this + * predicate. * - * @return a new predicate who's result is always the opposite of this + * @return a predicate that represents the logical negation of this * predicate */ default DoublePredicate negate() { @@ -77,22 +82,23 @@ public interface DoublePredicate { } /** - * Returns a predicate which evaluates to {@code true} if either this - * predicate or the provided predicate evaluates to {@code true}. If this - * predicate returns {@code true} then the remaining predicate is not - * evaluated. + * Returns a composed predicate that represents a short-circuiting logical + * OR of this predicate and another. When evaluating the composed + * predicate, if this predicate is {@code true}, then the {@code other} + * predicate is not evaluated. * - *

                        Any exceptions thrown by either {@code test} method are relayed - * to the caller; if performing first operation throws an exception, the - * second operation will not be performed. + *

                        Any exceptions thrown during evaluation of either predicate are relayed + * to the caller; if evaluation of this predicate throws an exception, the + * {@code other} predicate will not be evaluated. * - * @param p a predicate which will be logically-ANDed with this predicate - * @return a new predicate which returns {@code true} if either predicate - * returns {@code true} - * @throws NullPointerException if p is null + * @param other a predicate that will be logically-ORed with this + * predicate + * @return a composed predicate that represents the short-circuiting logical + * OR of this predicate and the {@code other} predicate + * @throws NullPointerException if other is null */ - default DoublePredicate or(DoublePredicate p) { - Objects.requireNonNull(p); - return (value) -> test(value) || p.test(value); + default DoublePredicate or(DoublePredicate other) { + Objects.requireNonNull(other); + return (value) -> test(value) || other.test(value); } } diff --git a/src/share/classes/java/util/function/DoubleSupplier.java b/src/share/classes/java/util/function/DoubleSupplier.java index c661fdff927e09ff8ca8e3a65f9db0e9a62de0f9..5169011b3a5df5481712650fb2143bd589905b18 100644 --- a/src/share/classes/java/util/function/DoubleSupplier.java +++ b/src/share/classes/java/util/function/DoubleSupplier.java @@ -25,8 +25,14 @@ package java.util.function; /** - * A supplier of {@code double} values. This is the {@code double}-providing - * primitive specialization of {@link Supplier}. + * Represents a supplier of {@code double}-valued results. This is the + * {@code double}-producing primitive specialization of {@link Supplier}. + * + *

                        There is no requirement that a distinct result be returned each + * time the supplier is invoked. + * + *

                        This is a functional interface + * whose functional method is {@link #getAsDouble()}. * * @see Supplier * @since 1.8 @@ -35,9 +41,9 @@ package java.util.function; public interface DoubleSupplier { /** - * Returns a {@code double} value. + * Gets a result. * - * @return a {@code double} value + * @return a result */ double getAsDouble(); } diff --git a/src/share/classes/java/util/function/DoubleToIntFunction.java b/src/share/classes/java/util/function/DoubleToIntFunction.java index 8eaf0b8374a9fbf657445d20273cc1f33be9ff11..a23f033e4df939b363715922d2c1599f4915bee7 100644 --- a/src/share/classes/java/util/function/DoubleToIntFunction.java +++ b/src/share/classes/java/util/function/DoubleToIntFunction.java @@ -25,22 +25,24 @@ package java.util.function; /** - * Apply a function to the input argument, yielding an appropriate result. - * This is the {@code double}-to-{@code int} specialization for {@link Function}. + * Represents a function that accepts a double-valued argument and produces an + * int-valued result. This is the {@code double}-to-{@code int} primitive + * specialization for {@link Function}. + * + *

                        This is a functional interface + * whose functional method is {@link #applyAsInt(double)}. * * @see Function - * @see IntToDoubleFunction - * @see LongToIntFunction * @since 1.8 */ @FunctionalInterface public interface DoubleToIntFunction { /** - * Compute the result of applying the function to the input arguments. + * Applies this function to the given argument. * - * @param value the input value - * @return the function result value + * @param value the function argument + * @return the function result */ int applyAsInt(double value); } diff --git a/src/share/classes/java/util/function/DoubleToLongFunction.java b/src/share/classes/java/util/function/DoubleToLongFunction.java index 7568157353dafe0e0ed77a543fddc902c67b135d..436369c6f48f63b6940a30032288eaeaa45df097 100644 --- a/src/share/classes/java/util/function/DoubleToLongFunction.java +++ b/src/share/classes/java/util/function/DoubleToLongFunction.java @@ -25,22 +25,24 @@ package java.util.function; /** - * Apply a function to the input argument, yielding an appropriate result. - * This is the {@code double}-to-{@code long} specialization for {@link Function}. + * Represents a function that accepts a double-valued argument and produces a + * long-valued result. This is the {@code double}-to-{@code long} primitive + * specialization for {@link Function}. + * + *

                        This is a functional interface + * whose functional method is {@link #applyAsLong(double)}. * * @see Function - * @see LongToDoubleFunction - * @see IntToLongFunction * @since 1.8 */ @FunctionalInterface public interface DoubleToLongFunction { /** - * Compute the result of applying the function to the input arguments. + * Applies this function to the given argument. * - * @param value the input value - * @return the function result value + * @param value the function argument + * @return the function result */ long applyAsLong(double value); } diff --git a/src/share/classes/java/util/function/DoubleUnaryOperator.java b/src/share/classes/java/util/function/DoubleUnaryOperator.java index 39dfa6ab6a70699dac756adea645a9910f6b7138..2f134c9994fdfc84b175ac36e12b81c24a55a67a 100644 --- a/src/share/classes/java/util/function/DoubleUnaryOperator.java +++ b/src/share/classes/java/util/function/DoubleUnaryOperator.java @@ -27,9 +27,12 @@ package java.util.function; import java.util.Objects; /** - * An operation on a {@code double} operand yielding a {@code double} - * result. This is the primitive type specialization of {@link UnaryOperator} - * for {@code double}. + * Represents an operation on a single {@code double}-valued operand that produces + * a {@code double}-valued result. This is the primitive type specialization of + * {@link UnaryOperator} for {@code double}. + * + *

                        This is a functional interface + * whose functional method is {@link #applyAsDouble(double)}. * * @see UnaryOperator * @since 1.8 @@ -38,24 +41,25 @@ import java.util.Objects; public interface DoubleUnaryOperator { /** - * Returns the {@code double} result of the operation upon the - * {@code double} operand. + * Applies this operator to the given operand. * - * @param operand the operand value - * @return the operation result value + * @param operand the operand + * @return the operator result */ double applyAsDouble(double operand); /** - * Compose a new function which applies the provided function followed by - * this function. If either function throws an exception, it is relayed - * to the caller. + * Returns a composed operator that first applies the {@code before} + * operator to its input, and then applies this operator to the result. + * If evaluation of either operator throws an exception, it is relayed to + * the caller of the composed operator. * - * @param before An additional function to be applied before this function - * is applied - * @return A function which performs the provided function followed by this - * function + * @param before the operator to apply before this operator is applied + * @return a composed operator that first applies the {@code before} + * operator and then applies this operator * @throws NullPointerException if before is null + * + * @see #andThen(DoubleUnaryOperator) */ default DoubleUnaryOperator compose(DoubleUnaryOperator before) { Objects.requireNonNull(before); @@ -63,15 +67,17 @@ public interface DoubleUnaryOperator { } /** - * Compose a new function which applies this function followed by the - * provided function. If either function throws an exception, it is relayed - * to the caller. + * Returns a composed operator that first applies this operator to + * its input, and then applies the {@code after} operator to the result. + * If evaluation of either operator throws an exception, it is relayed to + * the caller of the composed operator. * - * @param after An additional function to be applied after this function is - * applied - * @return A function which performs this function followed by the provided - * function followed + * @param after the operator to apply after this operator is applied + * @return a composed operator that first applies this operator and then + * applies the {@code after} operator * @throws NullPointerException if after is null + * + * @see #compose(DoubleUnaryOperator) */ default DoubleUnaryOperator andThen(DoubleUnaryOperator after) { Objects.requireNonNull(after); @@ -79,9 +85,9 @@ public interface DoubleUnaryOperator { } /** - * Returns a unary operator that provides its input value as the result. + * Returns a unary operator that always returns its input argument. * - * @return a unary operator that provides its input value as the result + * @return a unary operator that always returns its input argument */ static DoubleUnaryOperator identity() { return t -> t; diff --git a/src/share/classes/java/util/function/Function.java b/src/share/classes/java/util/function/Function.java index 084ba4cc9c766f88db7fda1d7744d2139b06f688..7bcbfd06bb6a367c60367965980eb8a284dedac3 100644 --- a/src/share/classes/java/util/function/Function.java +++ b/src/share/classes/java/util/function/Function.java @@ -27,12 +27,13 @@ package java.util.function; import java.util.Objects; /** - * Apply a function to the input argument, yielding an appropriate result. A - * function may variously provide a mapping between types, object instances or - * keys and values or any other form of transformation upon the input. + * Represents a function that accepts one argument and produces a result. * - * @param the type of the input to the {@code apply} operation - * @param the type of the result of the {@code apply} operation + *

                        This is a functional interface + * whose functional method is {@link #apply(Object)}. + * + * @param the type of the input to the function + * @param the type of the result of the function * * @since 1.8 */ @@ -40,25 +41,27 @@ import java.util.Objects; public interface Function { /** - * Compute the result of applying the function to the input argument + * Applies this function to the given argument. * - * @param t the input object + * @param t the function argument * @return the function result */ R apply(T t); /** - * Returns a new function which applies the provided function followed by - * this function. If either function throws an exception, it is relayed - * to the caller. + * Returns a composed function that first applies the {@code before} + * function to its input, and then applies this function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. * - * @param type of input objects to the combined function. May be the - * same type as {@code } or {@code } - * @param before an additional function to be applied before this function - * is applied - * @return a function which performs the provided function followed by this - * function + * @param the type of input to the {@code before} function, and to the + * composed function + * @param before the function to apply before this function is applied + * @return a composed function that first applies the {@code before} + * function and then applies this function * @throws NullPointerException if before is null + * + * @see #andThen(Function) */ default Function compose(Function before) { Objects.requireNonNull(before); @@ -66,17 +69,19 @@ public interface Function { } /** - * Returns a new function which applies this function followed by the - * provided function. If either function throws an exception, it is relayed - * to the caller. + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. * - * @param type of output objects to the combined function. May be the - * same type as {@code } or {@code } - * @param after an additional function to be applied after this function is - * applied - * @return a function which performs this function followed by the provided - * function + * @param the type of output of the {@code after} function, and of the + * composed function + * @param after the function to apply after this function is applied + * @return a composed function that first applies this function and then + * applies the {@code after} function * @throws NullPointerException if after is null + * + * @see #compose(Function) */ default Function andThen(Function after) { Objects.requireNonNull(after); @@ -84,10 +89,10 @@ public interface Function { } /** - * Returns a {@code Function} whose {@code apply} method returns its input. + * Returns a function that always returns its input argument. * * @param the type of the input and output objects to the function - * @return a {@code Function} whose {@code apply} method returns its input + * @return a function that always returns its input argument */ static Function identity() { return t -> t; diff --git a/src/share/classes/java/util/function/IntBinaryOperator.java b/src/share/classes/java/util/function/IntBinaryOperator.java index a0788a1d734db3ab783545c7db3963124e8bb09b..21bb9469ede67efce1a520a12264d2e5de6f98ea 100644 --- a/src/share/classes/java/util/function/IntBinaryOperator.java +++ b/src/share/classes/java/util/function/IntBinaryOperator.java @@ -25,24 +25,26 @@ package java.util.function; /** - * An operation on two {@code int} operands yielding an {@code int} result. - * This is the primitive type specialization of {@link BinaryOperator} for - * {@code int}. + * Represents an operation upon two {@code int}-valued operands and producing an + * {@code int}-valued result. This is the primitive type specialization of + * {@link BinaryOperator} for {@code int}. + * + *

                        This is a functional interface + * whose functional method is {@link #applyAsInt(int, int)}. * * @see BinaryOperator + * @see IntUnaryOperator * @since 1.8 */ @FunctionalInterface public interface IntBinaryOperator { /** - * Returns the {@code int} result of the operation upon the {@code int} - * operands. The parameters are named {@code left} and {@code right} for - * operations where the order of parameters matters. + * Applies this operator to the given operands. * - * @param left the left operand value - * @param right the right operand value - * @return the result of the operation + * @param left the first operand + * @param right the second operand + * @return the operator result */ int applyAsInt(int left, int right); } diff --git a/src/share/classes/java/util/function/IntConsumer.java b/src/share/classes/java/util/function/IntConsumer.java index 3c2a770332f9cd4fd89f55dfcfa9bf32af06b410..d8daf73ca2ca96eec850173e848430fc69bfbd05 100644 --- a/src/share/classes/java/util/function/IntConsumer.java +++ b/src/share/classes/java/util/function/IntConsumer.java @@ -27,10 +27,13 @@ package java.util.function; import java.util.Objects; /** - * An operation which accepts a single integer argument and returns no result. - * This is the primitive type specialization of {@link Consumer} for {@code int}. - * Unlike most other functional interfaces, {@code IntConsumer} is expected to - * operate via side-effects. + * Represents an operation that accepts a single {@code int}-valued argument and + * returns no result. This is the primitive type specialization of + * {@link Consumer} for {@code int}. Unlike most other functional interfaces, + * {@code IntConsumer} is expected to operate via side-effects. + * + *

                        This is a functional interface + * whose functional method is {@link #accept(int)}. * * @see Consumer * @since 1.8 @@ -39,30 +42,26 @@ import java.util.Objects; public interface IntConsumer { /** - * Accept an input value. + * Performs this operation on the given argument. * - * @param value the input value + * @param value the input argument */ void accept(int value); /** - * Returns an {@code IntConsumer} which performs, in sequence, the operation - * represented by this object followed by the operation represented by - * another {@code IntConsumer}. - * - *

                        Any exceptions thrown by either {@code accept} method are relayed - * to the caller; if performing this operation throws an exception, the - * other operation will not be performed. + * Returns a composed {@code IntConsumer} that performs, in sequence, this + * operation followed by the {@code after} operation. If performing either + * operation throws an exception, it is relayed to the caller of the + * composed operation. If performing this operation throws an exception, + * the {@code after} operation will not be performed. * - * @param other an IntConsumer which will be chained after this - * IntConsumer - * @return an IntConsumer which performs in sequence the {@code accept} method - * of this IntConsumer and the {@code accept} method of the specified IntConsumer - * operation - * @throws NullPointerException if other is null + * @param after the operation to perform after this operation + * @return a composed {@code IntConsumer} that performs in sequence this + * operation followed by the {@code after} operation + * @throws NullPointerException if {@code after} is null */ - default IntConsumer chain(IntConsumer other) { - Objects.requireNonNull(other); - return (int t) -> { accept(t); other.accept(t); }; + default IntConsumer andThen(IntConsumer after) { + Objects.requireNonNull(after); + return (int t) -> { accept(t); after.accept(t); }; } } diff --git a/src/share/classes/java/util/function/IntFunction.java b/src/share/classes/java/util/function/IntFunction.java index ec2ffcae249d446e103e20a73ebf04c536e0f090..de10df499e13b89ef6c8c04d8a70652221d3422f 100644 --- a/src/share/classes/java/util/function/IntFunction.java +++ b/src/share/classes/java/util/function/IntFunction.java @@ -25,11 +25,14 @@ package java.util.function; /** - * Apply a function to the integer-valued input argument, yielding an - * appropriate result. This is the {@code int}-consuming primitive - * specialization for {@link Function}. + * Represents a function that accepts an int-valued argument and produces a + * result. This is the {@code int}-consuming primitive specialization for + * {@link Function}. * - * @param the type of output objects from the function + *

                        This is a functional interface + * whose functional method is {@link #apply(int)}. + * + * @param the type of the result of the function * * @see Function * @since 1.8 @@ -38,9 +41,9 @@ package java.util.function; public interface IntFunction { /** - * Compute the result of applying the function to the input argument + * Applies this function to the given argument. * - * @param value the input value + * @param value the function argument * @return the function result */ R apply(int value); diff --git a/src/share/classes/java/util/function/IntPredicate.java b/src/share/classes/java/util/function/IntPredicate.java index 0e7ec0737d5ac1fdd180a6c9790f049c072f621a..5a9bd46dd703ca4c967356a21854267a5e73776c 100644 --- a/src/share/classes/java/util/function/IntPredicate.java +++ b/src/share/classes/java/util/function/IntPredicate.java @@ -27,8 +27,12 @@ package java.util.function; import java.util.Objects; /** - * Determines if the {@code int} input value matches some criteria. This is the - * {@code int}-consuming primitive type specialization of {@link Predicate}. + * Represents a predicate (boolean-valued function) of one {@code int}-valued + * argument. This is the {@code int}-consuming primitive type specialization of + * {@link Predicate}. + * + *

                        This is a functional interface + * whose functional method is {@link #test(int)}. * * @see Predicate * @since 1.8 @@ -37,38 +41,40 @@ import java.util.Objects; public interface IntPredicate { /** - * Returns {@code true} if the input value matches some criteria. + * Evaluates this predicate on the given argument. * - * @param value the value to be tested - * @return {@code true} if the input value matches some criteria, otherwise - * {@code false} + * @param value the input argument + * @return {@code true} if the input argument matches the predicate, + * otherwise {@code false} */ boolean test(int value); /** - * Returns a predicate which evaluates to {@code true} only if this - * predicate and the provided predicate both evaluate to {@code true}. If - * this predicate returns {@code false} then the remaining predicate is not - * evaluated. + * Returns a composed predicate that represents a short-circuiting logical + * AND of this predicate and another. When evaluating the composed + * predicate, if this predicate is {@code false}, then the {@code other} + * predicate is not evaluated. * - *

                        Any exceptions thrown by either {@code test} method are relayed - * to the caller; if performing first operation throws an exception, the - * second operation will not be performed. + *

                        Any exceptions thrown during evaluation of either predicate are relayed + * to the caller; if evaluation of this predicate throws an exception, the + * {@code other} predicate will not be evaluated. * - * @param p a predicate which will be logically-ANDed with this predicate - * @return a new predicate which returns {@code true} only if both - * predicates return {@code true} - * @throws NullPointerException if p is null + * @param other a predicate that will be logically-ANDed with this + * predicate + * @return a composed predicate that represents the short-circuiting logical + * AND of this predicate and the {@code other} predicate + * @throws NullPointerException if other is null */ - default IntPredicate and(IntPredicate p) { - Objects.requireNonNull(p); - return (value) -> test(value) && p.test(value); + default IntPredicate and(IntPredicate other) { + Objects.requireNonNull(other); + return (value) -> test(value) && other.test(value); } /** - * Returns a predicate which negates the result of this predicate. + * Returns a predicate that represents the logical negation of this + * predicate. * - * @return a new predicate who's result is always the opposite of this + * @return a predicate that represents the logical negation of this * predicate */ default IntPredicate negate() { @@ -76,22 +82,23 @@ public interface IntPredicate { } /** - * Returns a predicate which evaluates to {@code true} if either this - * predicate or the provided predicate evaluates to {@code true}. If this - * predicate returns {@code true} then the remaining predicate is not - * evaluated. + * Returns a composed predicate that represents a short-circuiting logical + * OR of this predicate and another. When evaluating the composed + * predicate, if this predicate is {@code true}, then the {@code other} + * predicate is not evaluated. * - *

                        Any exceptions thrown by either {@code test} method are relayed - * to the caller; if performing first operation throws an exception, the - * second operation will not be performed. + *

                        Any exceptions thrown during evaluation of either predicate are relayed + * to the caller; if evaluation of this predicate throws an exception, the + * {@code other} predicate will not be evaluated. * - * @param p a predicate which will be logically-ORed with this predicate - * @return a new predicate which returns {@code true} if either predicate - * returns {@code true} - * @throws NullPointerException if p is null + * @param other a predicate that will be logically-ORed with this + * predicate + * @return a composed predicate that represents the short-circuiting logical + * OR of this predicate and the {@code other} predicate + * @throws NullPointerException if other is null */ - default IntPredicate or(IntPredicate p) { - Objects.requireNonNull(p); - return (value) -> test(value) || p.test(value); + default IntPredicate or(IntPredicate other) { + Objects.requireNonNull(other); + return (value) -> test(value) || other.test(value); } } diff --git a/src/share/classes/java/util/function/IntSupplier.java b/src/share/classes/java/util/function/IntSupplier.java index 3165d3f406156a355441938e0cf24696bf4a024c..89489c59bac817e043cf2056d8b6c81554670e1d 100644 --- a/src/share/classes/java/util/function/IntSupplier.java +++ b/src/share/classes/java/util/function/IntSupplier.java @@ -25,8 +25,14 @@ package java.util.function; /** - * A supplier of {@code int} values. This is the {@code int}-providing - * primitive specialization of {@link Supplier}. + * Represents a supplier of {@code int}-valued results. This is the + * {@code int}-producing primitive specialization of {@link Supplier}. + * + *

                        There is no requirement that a distinct result be returned each + * time the supplier is invoked. + * + *

                        This is a functional interface + * whose functional method is {@link #getAsInt()}. * * @see Supplier * @since 1.8 @@ -35,9 +41,9 @@ package java.util.function; public interface IntSupplier { /** - * Returns an {@code int} value. + * Gets a result. * - * @return an {@code int} value + * @return a result */ int getAsInt(); } diff --git a/src/share/classes/java/util/function/IntToDoubleFunction.java b/src/share/classes/java/util/function/IntToDoubleFunction.java index 773164d4c96b068e7f2d8048db8c09d038eaf4b7..5012154c2a03582dde87838a4a828fb3bd292c44 100644 --- a/src/share/classes/java/util/function/IntToDoubleFunction.java +++ b/src/share/classes/java/util/function/IntToDoubleFunction.java @@ -25,22 +25,24 @@ package java.util.function; /** - * Apply a function to the input argument, yielding an appropriate result. - * This is the {@code int}-to-{@code double} specialization for {@link Function}. + * Represents a function that accepts an int-valued argument and produces a + * double-valued result. This is the {@code int}-to-{@code double} primitive + * specialization for {@link Function}. + * + *

                        This is a functional interface + * whose functional method is {@link #applyAsDouble(int)}. * * @see Function - * @see DoubleToIntFunction - * @see LongToDoubleFunction * @since 1.8 */ @FunctionalInterface public interface IntToDoubleFunction { /** - * Compute the result of applying the function to the input arguments. + * Applies this function to the given argument. * - * @param value the input value - * @return the function result value + * @param value the function argument + * @return the function result */ double applyAsDouble(int value); } diff --git a/src/share/classes/java/util/function/IntToLongFunction.java b/src/share/classes/java/util/function/IntToLongFunction.java index c50b20fc8c88e755cf7c08966da484ae17f72f45..6c52faa70093f9014b2fc43383016d2dbc9fa93a 100644 --- a/src/share/classes/java/util/function/IntToLongFunction.java +++ b/src/share/classes/java/util/function/IntToLongFunction.java @@ -25,22 +25,24 @@ package java.util.function; /** - * Apply a function to the input argument, yielding an appropriate result. - * This is the {@code int}-to-{@code long} specialization for {@link Function}. + * Represents a function that accepts an int-valued argument and produces a + * long-valued result. This is the {@code int}-to-{@code long} primitive + * specialization for {@link Function}. + * + *

                        This is a functional interface + * whose functional method is {@link #applyAsLong(int)}. * * @see Function - * @see LongToIntFunction - * @see DoubleToLongFunction * @since 1.8 */ @FunctionalInterface public interface IntToLongFunction { /** - * Compute the result of applying the function to the input arguments. + * Applies this function to the given argument. * - * @param value the input value - * @return the function result value + * @param value the function argument + * @return the function result */ long applyAsLong(int value); } diff --git a/src/share/classes/java/util/function/IntUnaryOperator.java b/src/share/classes/java/util/function/IntUnaryOperator.java index 2e14c151b1f19374be842df33b5f1fe873e0a68a..300fc14666adb7930ac58346d1f01f5c232d1c5c 100644 --- a/src/share/classes/java/util/function/IntUnaryOperator.java +++ b/src/share/classes/java/util/function/IntUnaryOperator.java @@ -27,9 +27,12 @@ package java.util.function; import java.util.Objects; /** - * An operation on a single {@code int} operand yielding an {@code int} result. - * This is the primitive type specialization of {@link UnaryOperator} for - * {@code int}. + * Represents an operation on a single {@code int}-valued operand that produces + * an {@code int}-valued result. This is the primitive type specialization of + * {@link UnaryOperator} for {@code int}. + * + *

                        This is a functional interface + * whose functional method is {@link #applyAsInt(int)}. * * @see UnaryOperator * @since 1.8 @@ -38,24 +41,25 @@ import java.util.Objects; public interface IntUnaryOperator { /** - * Returns the {@code int} value result of the operation upon the - * {@code int} operand. + * Applies this operator to the given operand. * - * @param operand the operand value - * @return the operation result value + * @param operand the operand + * @return the operator result */ int applyAsInt(int operand); /** - * Compose a new function which applies the provided function followed by - * this function. If either function throws an exception, it is relayed - * to the caller. + * Returns a composed operator that first applies the {@code before} + * operator to its input, and then applies this operator to the result. + * If evaluation of either operator throws an exception, it is relayed to + * the caller of the composed operator. * - * @param before an additional function to be applied before this function - * is applied - * @return a function which performs the provided function followed by this - * function + * @param before the operator to apply before this operator is applied + * @return a composed operator that first applies the {@code before} + * operator and then applies this operator * @throws NullPointerException if before is null + * + * @see #andThen(IntUnaryOperator) */ default IntUnaryOperator compose(IntUnaryOperator before) { Objects.requireNonNull(before); @@ -63,15 +67,17 @@ public interface IntUnaryOperator { } /** - * Compose a new function which applies this function followed by the - * provided function. If either function throws an exception, it is relayed - * to the caller. + * Returns a composed operator that first applies this operator to + * its input, and then applies the {@code after} operator to the result. + * If evaluation of either operator throws an exception, it is relayed to + * the caller of the composed operator. * - * @param after an additional function to be applied after this function is - * applied - * @return a function which performs this function followed by the provided - * function followed + * @param after the operator to apply after this operator is applied + * @return a composed operator that first applies this operator and then + * applies the {@code after} operator * @throws NullPointerException if after is null + * + * @see #compose(IntUnaryOperator) */ default IntUnaryOperator andThen(IntUnaryOperator after) { Objects.requireNonNull(after); @@ -79,9 +85,9 @@ public interface IntUnaryOperator { } /** - * Returns a unary operator that provides its input value as the result. + * Returns a unary operator that always returns its input argument. * - * @return a unary operator that provides its input value as the result + * @return a unary operator that always returns its input argument */ static IntUnaryOperator identity() { return t -> t; diff --git a/src/share/classes/java/util/function/LongBinaryOperator.java b/src/share/classes/java/util/function/LongBinaryOperator.java index f35258bea600cad3cbffbcc7f5784eb70ee7bcfb..287481e4e340233236f69c5c3b750fb01c4076cd 100644 --- a/src/share/classes/java/util/function/LongBinaryOperator.java +++ b/src/share/classes/java/util/function/LongBinaryOperator.java @@ -25,24 +25,26 @@ package java.util.function; /** - * An operation on two {@code long} operands yielding a {@code long} result. - * This is the primitive type specialization of {@link BinaryOperator} for - * {@code long}. + * Represents an operation upon two {@code long}-valued operands and producing a + * {@code long}-valued result. This is the primitive type specialization of + * {@link BinaryOperator} for {@code long}. + * + *

                        This is a functional interface + * whose functional method is {@link #applyAsLong(long, long)}. * * @see BinaryOperator + * @see LongUnaryOperator * @since 1.8 */ @FunctionalInterface public interface LongBinaryOperator { /** - * Returns the {@code long} result of the operation upon the {@code long} - * operands. The parameters are named {@code left} and {@code right} for - * operations where the order of parameters matters. + * Applies this operator to the given operands. * - * @param left the left operand value - * @param right the right operand value - * @return the result of the operation + * @param left the first operand + * @param right the second operand + * @return the operator result */ long applyAsLong(long left, long right); } diff --git a/src/share/classes/java/util/function/LongConsumer.java b/src/share/classes/java/util/function/LongConsumer.java index 754af39d9183a234a2d87a2b31e3e7086ceb213f..b59d0303f91666a7eb89517087ab536ea3976566 100644 --- a/src/share/classes/java/util/function/LongConsumer.java +++ b/src/share/classes/java/util/function/LongConsumer.java @@ -27,10 +27,13 @@ package java.util.function; import java.util.Objects; /** - * An operation which accepts a single long argument and returns no result. - * This is the {@code long}-consuming primitive type specialization of - * {@link Consumer}. Unlike most other functional interfaces, {@code LongConsumer} - * is expected to operate via side-effects. + * Represents an operation that accepts a single {@code long}-valued argument and + * returns no result. This is the primitive type specialization of + * {@link Consumer} for {@code long}. Unlike most other functional interfaces, + * {@code LongConsumer} is expected to operate via side-effects. + * + *

                        This is a functional interface + * whose functional method is {@link #accept(long)}. * * @see Consumer * @since 1.8 @@ -39,30 +42,26 @@ import java.util.Objects; public interface LongConsumer { /** - * Accept an input value. + * Performs this operation on the given argument. * - * @param value the input value + * @param value the input argument */ void accept(long value); /** - * Returns a {@code LongConsumer} which performs, in sequence, the operation - * represented by this object followed by the operation represented by - * another {@code LongConsumer}. - * - *

                        Any exceptions thrown by either {@code accept} method are relayed - * to the caller; if performing this operation throws an exception, the - * other operation will not be performed. + * Returns a composed {@code LongConsumer} that performs, in sequence, this + * operation followed by the {@code after} operation. If performing either + * operation throws an exception, it is relayed to the caller of the + * composed operation. If performing this operation throws an exception, + * the {@code after} operation will not be performed. * - * @param other a LongConsumer which will be chained after this - * LongConsumer - * @return a LongConsumer which performs in sequence the {@code accept} method - * of this LongConsumer and the {@code accept} method of the specified LongConsumer - * operation - * @throws NullPointerException if other is null + * @param after the operation to perform after this operation + * @return a composed {@code LongConsumer} that performs in sequence this + * operation followed by the {@code after} operation + * @throws NullPointerException if {@code after} is null */ - default LongConsumer chain(LongConsumer other) { - Objects.requireNonNull(other); - return (long t) -> { accept(t); other.accept(t); }; + default LongConsumer andThen(LongConsumer after) { + Objects.requireNonNull(after); + return (long t) -> { accept(t); after.accept(t); }; } } diff --git a/src/share/classes/java/util/function/LongFunction.java b/src/share/classes/java/util/function/LongFunction.java index d87f22ab7e93c9caf3ad6bc9308316b1b8f265f5..2030c04e4228bd99825c5055fc1f9bbb3a3a3865 100644 --- a/src/share/classes/java/util/function/LongFunction.java +++ b/src/share/classes/java/util/function/LongFunction.java @@ -25,11 +25,14 @@ package java.util.function; /** - * Apply a function to the long-valued input argument, yielding an appropriate - * result. This is the {@code long}-consuming primitive specialization for + * Represents a function that accepts a long-valued argument and produces a + * result. This is the {@code long}-consuming primitive specialization for * {@link Function}. * - * @param the type of output objects from the function + *

                        This is a functional interface + * whose functional method is {@link #apply(long)}. + * + * @param the type of the result of the function * * @see Function * @since 1.8 @@ -38,9 +41,9 @@ package java.util.function; public interface LongFunction { /** - * Compute the result of applying the function to the input argument + * Applies this function to the given argument. * - * @param value the input value + * @param value the function argument * @return the function result */ R apply(long value); diff --git a/src/share/classes/java/util/function/LongPredicate.java b/src/share/classes/java/util/function/LongPredicate.java index 1a28708ea4521f26c83096073b5df69067b21aae..5afdd41ef1d876b5d4f17e986b4efd9e9ba4a6c9 100644 --- a/src/share/classes/java/util/function/LongPredicate.java +++ b/src/share/classes/java/util/function/LongPredicate.java @@ -27,8 +27,12 @@ package java.util.function; import java.util.Objects; /** - * Determines if the {@code long} input value matches some criteria. This is the - * {@code long}-consuming primitive type specialization of {@link Predicate}. + * Represents a predicate (boolean-valued function) of one {@code long}-valued + * argument. This is the {@code long}-consuming primitive type specialization of + * {@link Predicate}. + * + *

                        This is a functional interface + * whose functional method is {@link #test(long)}. * * @see Predicate * @since 1.8 @@ -37,37 +41,40 @@ import java.util.Objects; public interface LongPredicate { /** - * Returns {@code true} if the input value matches some criteria. + * Evaluates this predicate on the given argument. * - * @param value the value to be tested - * @return {@code true} if the input value matches some criteria, otherwise - * {@code false} + * @param value the input argument + * @return {@code true} if the input argument matches the predicate, + * otherwise {@code false} */ boolean test(long value); /** - * Returns a predicate which evaluates to {@code true} only if this - * predicate and the provided predicate both evaluate to {@code true}. If - * this predicate returns {@code false} then the remaining predicate is not - * evaluated. + * Returns a composed predicate that represents a short-circuiting logical + * AND of this predicate and another. When evaluating the composed + * predicate, if this predicate is {@code false}, then the {@code other} + * predicate is not evaluated. * - *

                        Any exceptions thrown by either {@code test} method are relayed - * to the caller; if performing first operation throws an exception, the - * second operation will not be performed. + *

                        Any exceptions thrown during evaluation of either predicate are relayed + * to the caller; if evaluation of this predicate throws an exception, the + * {@code other} predicate will not be evaluated. * - * @param p a predicate which will be logically-ANDed with this predicate - * @return a new predicate which returns {@code true} only if both - * predicates return {@code true} + * @param other a predicate that will be logically-ANDed with this + * predicate + * @return a composed predicate that represents the short-circuiting logical + * AND of this predicate and the {@code other} predicate + * @throws NullPointerException if other is null */ - default LongPredicate and(LongPredicate p) { - Objects.requireNonNull(p); - return (value) -> test(value) && p.test(value); + default LongPredicate and(LongPredicate other) { + Objects.requireNonNull(other); + return (value) -> test(value) && other.test(value); } /** - * Returns a predicate which negates the result of this predicate. + * Returns a predicate that represents the logical negation of this + * predicate. * - * @return a new predicate who's result is always the opposite of this + * @return a predicate that represents the logical negation of this * predicate */ default LongPredicate negate() { @@ -75,22 +82,23 @@ public interface LongPredicate { } /** - * Returns a predicate which evaluates to {@code true} if either this - * predicate or the provided predicate evaluates to {@code true}. If this - * predicate returns {@code true} then the remaining predicate is not - * evaluated. + * Returns a composed predicate that represents a short-circuiting logical + * OR of this predicate and another. When evaluating the composed + * predicate, if this predicate is {@code true}, then the {@code other} + * predicate is not evaluated. * - *

                        Any exceptions thrown by either {@code test} method are relayed - * to the caller; if performing first operation throws an exception, the - * second operation will not be performed. + *

                        Any exceptions thrown during evaluation of either predicate are relayed + * to the caller; if evaluation of this predicate throws an exception, the + * {@code other} predicate will not be evaluated. * - * @param p a predicate which will be logically-ORed with this predicate - * @return a new predicate which returns {@code true} if either predicate - * returns {@code true} - * @throws NullPointerException if p is null + * @param other a predicate that will be logically-ORed with this + * predicate + * @return a composed predicate that represents the short-circuiting logical + * OR of this predicate and the {@code other} predicate + * @throws NullPointerException if other is null */ - default LongPredicate or(LongPredicate p) { - Objects.requireNonNull(p); - return (value) -> test(value) || p.test(value); + default LongPredicate or(LongPredicate other) { + Objects.requireNonNull(other); + return (value) -> test(value) || other.test(value); } } diff --git a/src/share/classes/java/util/function/LongSupplier.java b/src/share/classes/java/util/function/LongSupplier.java index d88c399a7905ac8770423cb279bad1a1ae63945d..513d9062e94da166b92c2b967959133646501c0e 100644 --- a/src/share/classes/java/util/function/LongSupplier.java +++ b/src/share/classes/java/util/function/LongSupplier.java @@ -25,8 +25,14 @@ package java.util.function; /** - * A supplier of {@code long} values. This is the {@code long}-providing - * primitive specialization of {@link Supplier}. + * Represents a supplier of {@code long}-valued results. This is the + * {@code long}-producing primitive specialization of {@link Supplier}. + * + *

                        There is no requirement that a distinct result be returned each + * time the supplier is invoked. + * + *

                        This is a functional interface + * whose functional method is {@link #getAsLong()}. * * @see Supplier * @since 1.8 @@ -35,9 +41,9 @@ package java.util.function; public interface LongSupplier { /** - * Returns a {@code long} value. + * Gets a result. * - * @return a {@code long} value + * @return a result */ long getAsLong(); } diff --git a/src/share/classes/java/util/function/LongToDoubleFunction.java b/src/share/classes/java/util/function/LongToDoubleFunction.java index 718021cc9a823763456de9977f4338f9e9023ba2..9d0831f35ec45a1d8b170d26954a330ce042b26d 100644 --- a/src/share/classes/java/util/function/LongToDoubleFunction.java +++ b/src/share/classes/java/util/function/LongToDoubleFunction.java @@ -25,22 +25,24 @@ package java.util.function; /** - * Apply a function to the input argument, yielding an appropriate result. - * This is the {@code long}-to-{@code double} specialization for {@link Function}. + * Represents a function that accepts a long-valued argument and produces a + * double-valued result. This is the {@code long}-to-{@code double} primitive + * specialization for {@link Function}. + * + *

                        This is a functional interface + * whose functional method is {@link #applyAsDouble(long)}. * * @see Function - * @see DoubleToLongFunction - * @see IntToDoubleFunction * @since 1.8 */ @FunctionalInterface public interface LongToDoubleFunction { /** - * Compute the result of applying the function to the input arguments. + * Applies this function to the given argument. * - * @param value the input value - * @return the function result value + * @param value the function argument + * @return the function result */ double applyAsDouble(long value); } diff --git a/src/share/classes/java/util/function/LongToIntFunction.java b/src/share/classes/java/util/function/LongToIntFunction.java index e5dc6ba3d0d425d169020941dd62bcc993c71107..d1d6c347054c8b710de760ae52a9cf9a141543f1 100644 --- a/src/share/classes/java/util/function/LongToIntFunction.java +++ b/src/share/classes/java/util/function/LongToIntFunction.java @@ -25,22 +25,24 @@ package java.util.function; /** - * Apply a function to the input argument, yielding an appropriate result. - * This is the {@code long}-to-{@code int} specialization for {@link Function}. + * Represents a function that accepts a long-valued argument and produces an + * int-valued result. This is the {@code long}-to-{@code int} primitive + * specialization for {@link Function}. + * + *

                        This is a functional interface + * whose functional method is {@link #applyAsInt(long)}. * * @see Function - * @see IntToLongFunction - * @see DoubleToIntFunction * @since 1.8 */ @FunctionalInterface public interface LongToIntFunction { /** - * Compute the result of applying the function to the input arguments. + * Applies this function to the given argument. * - * @param value the input value - * @return the function result value + * @param value the function argument + * @return the function result */ int applyAsInt(long value); } diff --git a/src/share/classes/java/util/function/LongUnaryOperator.java b/src/share/classes/java/util/function/LongUnaryOperator.java index a32918fc56b278b73a6ff56d9fd84317a767f689..e2bbdddbfc9ae801b28002115b0795763f5117e2 100644 --- a/src/share/classes/java/util/function/LongUnaryOperator.java +++ b/src/share/classes/java/util/function/LongUnaryOperator.java @@ -27,9 +27,12 @@ package java.util.function; import java.util.Objects; /** - * An operation on a single {@code long} operand yielding a {@code long} result. - * This is the primitive type specialization of {@link UnaryOperator} for - * {@code long}. + * Represents an operation on a single {@code long}-valued operand that produces + * a {@code long}-valued result. This is the primitive type specialization of + * {@link UnaryOperator} for {@code long}. + * + *

                        This is a functional interface + * whose functional method is {@link #applyAsLong(long)}. * * @see UnaryOperator * @since 1.8 @@ -38,24 +41,25 @@ import java.util.Objects; public interface LongUnaryOperator { /** - * Returns the {@code long} result of the operation upon the {@code long} - * operand. + * Applies this operator to the given operand. * - * @param operand the operand value - * @return the operation result value + * @param operand the operand + * @return the operator result */ long applyAsLong(long operand); /** - * Compose a new function which applies the provided function followed by - * this function. If either function throws an exception, it is relayed - * to the caller. + * Returns a composed operator that first applies the {@code before} + * operator to its input, and then applies this operator to the result. + * If evaluation of either operator throws an exception, it is relayed to + * the caller of the composed operator. * - * @param before An additional function to be applied before this function - * is applied - * @return A function which performs the provided function followed by this - * function + * @param before the operator to apply before this operator is applied + * @return a composed operator that first applies the {@code before} + * operator and then applies this operator * @throws NullPointerException if before is null + * + * @see #andThen(LongUnaryOperator) */ default LongUnaryOperator compose(LongUnaryOperator before) { Objects.requireNonNull(before); @@ -63,15 +67,17 @@ public interface LongUnaryOperator { } /** - * Compose a new function which applies this function followed by the - * provided function. If either function throws an exception, it is relayed - * to the caller. + * Returns a composed operator that first applies this operator to + * its input, and then applies the {@code after} operator to the result. + * If evaluation of either operator throws an exception, it is relayed to + * the caller of the composed operator. * - * @param after An additional function to be applied after this function is - * applied - * @return A function which performs this function followed by the provided - * function followed + * @param after the operator to apply after this operator is applied + * @return a composed operator that first applies this operator and then + * applies the {@code after} operator * @throws NullPointerException if after is null + * + * @see #compose(LongUnaryOperator) */ default LongUnaryOperator andThen(LongUnaryOperator after) { Objects.requireNonNull(after); @@ -79,9 +85,9 @@ public interface LongUnaryOperator { } /** - * Returns a unary operator that provides its input value as the result. + * Returns a unary operator that always returns its input argument. * - * @return a unary operator that provides its input value as the result + * @return a unary operator that always returns its input argument */ static LongUnaryOperator identity() { return t -> t; diff --git a/src/share/classes/java/util/function/ObjDoubleConsumer.java b/src/share/classes/java/util/function/ObjDoubleConsumer.java index dd8c0c9cf998469bbd82d5dcabdd4c283bc2fbb9..d551fc7bf001dc265b1ae0ce379a5dea380d880b 100644 --- a/src/share/classes/java/util/function/ObjDoubleConsumer.java +++ b/src/share/classes/java/util/function/ObjDoubleConsumer.java @@ -25,12 +25,16 @@ package java.util.function; /** - * An operation which accepts an object reference and a double, and returns no - * result. This is the {@code (reference, double)} specialization of - * {@link BiConsumer}. Unlike most other functional interfaces, - * {@code ObjDoubleConsumer} is expected to operate via side-effects. + * Represents an operation that accepts an object-valued and a + * {@code double}-valued argument, and returns no result. This is the + * {@code (reference, double)} specialization of {@link BiConsumer}. + * Unlike most other functional interfaces, {@code ObjDoubleConsumer} is + * expected to operate via side-effects. * - * @param Type of reference argument to {@code accept()}. + *

                        This is a functional interface + * whose functional method is {@link #accept(Object, double)}. + * + * @param the type of the object argument to the operation * * @see BiConsumer * @since 1.8 @@ -39,10 +43,10 @@ package java.util.function; public interface ObjDoubleConsumer { /** - * Accept a set of input values. + * Performs this operation on the given arguments. * - * @param t an input object - * @param value an input value + * @param t the first input argument + * @param value the second input argument */ void accept(T t, double value); } diff --git a/src/share/classes/java/util/function/ObjIntConsumer.java b/src/share/classes/java/util/function/ObjIntConsumer.java index 3ab4d5eef05aa6f0a17421f944ab51237eda2862..2eb32d63ec4eed6087c975fee55502700e102ae3 100644 --- a/src/share/classes/java/util/function/ObjIntConsumer.java +++ b/src/share/classes/java/util/function/ObjIntConsumer.java @@ -25,12 +25,16 @@ package java.util.function; /** - * An operation which accepts an object reference and an int, and returns no - * result. This is the {@code (reference, int)} specialization of - * {@link BiConsumer}. Unlike most other functional interfaces, - * {@code ObjIntConsumer} is expected to operate via side-effects. + * Represents an operation that accepts an object-valued and a + * {@code int}-valued argument, and returns no result. This is the + * {@code (reference, int)} specialization of {@link BiConsumer}. + * Unlike most other functional interfaces, {@code ObjIntConsumer} is + * expected to operate via side-effects. * - * @param Type of reference argument to {@code accept()} + *

                        This is a functional interface + * whose functional method is {@link #accept(Object, int)}. + * + * @param the type of the object argument to the operation * * @see BiConsumer * @since 1.8 @@ -39,10 +43,10 @@ package java.util.function; public interface ObjIntConsumer { /** - * Accept a set of input values. + * Performs this operation on the given arguments. * - * @param t an input object - * @param value an input value + * @param t the first input argument + * @param value the second input argument */ void accept(T t, int value); } diff --git a/src/share/classes/java/util/function/ObjLongConsumer.java b/src/share/classes/java/util/function/ObjLongConsumer.java index f90a4f84c77ffeefd363c2a5dea63fcef3a939ea..f40eea2c0f834e68e516c8966ea8bd46891b6d94 100644 --- a/src/share/classes/java/util/function/ObjLongConsumer.java +++ b/src/share/classes/java/util/function/ObjLongConsumer.java @@ -25,12 +25,16 @@ package java.util.function; /** - * An operation which accepts an object reference and a long, and returns no - * result. This is the {@code (reference, long)} specialization of - * {@link BiConsumer}. Unlike most other functional interfaces, - * {@code ObjLongConsumer} is expected to operate via side-effects. + * Represents an operation that accepts an object-valued and a + * {@code long}-valued argument, and returns no result. This is the + * {@code (reference, long)} specialization of {@link BiConsumer}. + * Unlike most other functional interfaces, {@code ObjLongConsumer} is + * expected to operate via side-effects. * - * @param Type of reference argument to {@code accept()} + *

                        This is a functional interface + * whose functional method is {@link #accept(Object, long)}. + * + * @param the type of the object argument to the operation * * @see BiConsumer * @since 1.8 @@ -39,10 +43,10 @@ package java.util.function; public interface ObjLongConsumer { /** - * Accept a set of input values. + * Performs this operation on the given arguments. * - * @param t an input object - * @param value an input value + * @param t the first input argument + * @param value the second input argument */ void accept(T t, long value); } diff --git a/src/share/classes/java/util/function/Predicate.java b/src/share/classes/java/util/function/Predicate.java index ac207a3d5937cfbd9a1417032c73d79d8c03d648..e2f448b167426cde099e07509fd4d26d328d6dc9 100644 --- a/src/share/classes/java/util/function/Predicate.java +++ b/src/share/classes/java/util/function/Predicate.java @@ -27,9 +27,12 @@ package java.util.function; import java.util.Objects; /** - * Determines if the input object matches some criteria. + * Represents a predicate (boolean-valued function) of one argument. * - * @param the type of argument to {@code test} + *

                        This is a functional interface + * whose functional method is {@link #test(Object)}. + * + * @param the type of the input to the predicate * * @since 1.8 */ @@ -37,76 +40,80 @@ import java.util.Objects; public interface Predicate { /** - * Returns {@code true} if the input object matches some criteria. + * Evaluates this predicate on the given argument. * - * @param t the input object - * @return {@code true} if the input object matches some criteria, otherwise - * {@code false} + * @param t the input argument + * @return {@code true} if the input argument matches the predicate, + * otherwise {@code false} */ boolean test(T t); /** - * Returns a predicate which evaluates to {@code true} only if this - * predicate and the provided predicate both evaluate to {@code true}. If - * this predicate returns {@code false} then the remaining predicate is not - * evaluated. + * Returns a composed predicate that represents a short-circuiting logical + * AND of this predicate and another. When evaluating the composed + * predicate, if this predicate is {@code false}, then the {@code other} + * predicate is not evaluated. * - *

                        Any exceptions thrown by either {@code test} method are relayed - * to the caller; if performing first operation throws an exception, the - * second operation will not be performed. + *

                        Any exceptions thrown during evaluation of either predicate are relayed + * to the caller; if evaluation of this predicate throws an exception, the + * {@code other} predicate will not be evaluated. * - * @param p a predicate which will be logically-ANDed with this predicate - * @return a new predicate which returns {@code true} only if both - * predicates return {@code true} - * @throws NullPointerException if p is null + * @param other a predicate that will be logically-ANDed with this + * predicate + * @return a composed predicate that represents the short-circuiting logical + * AND of this predicate and the {@code other} predicate + * @throws NullPointerException if other is null */ - default Predicate and(Predicate p) { - Objects.requireNonNull(p); - return (t) -> test(t) && p.test(t); + default Predicate and(Predicate other) { + Objects.requireNonNull(other); + return (t) -> test(t) && other.test(t); } /** - * Returns a predicate which negates the result of this predicate. - * - * @return a new predicate who's result is always the opposite of this + * Returns a predicate that represents the logical negation of this * predicate. + * + * @return a predicate that represents the logical negation of this + * predicate */ default Predicate negate() { return (t) -> !test(t); } /** - * Returns a predicate which evaluates to {@code true} if either this - * predicate or the provided predicate evaluates to {@code true}. If this - * predicate returns {@code true} then the remaining predicate is not - * evaluated. + * Returns a composed predicate that represents a short-circuiting logical + * OR of this predicate and another. When evaluating the composed + * predicate, if this predicate is {@code true}, then the {@code other} + * predicate is not evaluated. * - *

                        Any exceptions thrown by either {@code test} method are relayed - * to the caller; if performing first operation throws an exception, the - * second operation will not be performed. + *

                        Any exceptions thrown during evaluation of either predicate are relayed + * to the caller; if evaluation of this predicate throws an exception, the + * {@code other} predicate will not be evaluated. * - * @param p a predicate which will be logically-ORed with this predicate - * @return a new predicate which returns {@code true} if either predicate - * returns {@code true} - * @throws NullPointerException if p is null + * @param other a predicate that will be logically-ORed with this + * predicate + * @return a composed predicate that represents the short-circuiting logical + * OR of this predicate and the {@code other} predicate + * @throws NullPointerException if other is null */ - default Predicate or(Predicate p) { - Objects.requireNonNull(p); - return (t) -> test(t) || p.test(t); + default Predicate or(Predicate other) { + Objects.requireNonNull(other); + return (t) -> test(t) || other.test(t); } /** - * Returns a predicate who's result matches - * {@code Objects.equals(target, t)}. + * Returns a predicate that tests if two arguments are equal according + * to {@link Objects#equals(Object, Object)}. * - * @param the type of values evaluated by the predicate - * @param target the target value to be compared for equality - * @return a predicate who's result matches - * {@code Objects.equals(target, t)} + * @param the type of arguments to the predicate + * @param targetRef the object reference with which to compare for equality, + * which may be {@code null} + * @return a predicate that tests if two arguments are equal according + * to {@link Objects#equals(Object, Object)} */ - static Predicate isEqual(Object target) { - return (null == target) + static Predicate isEqual(Object targetRef) { + return (null == targetRef) ? Objects::isNull - : object -> target.equals(object); + : object -> targetRef.equals(object); } } diff --git a/src/share/classes/java/util/function/Supplier.java b/src/share/classes/java/util/function/Supplier.java index 728994b17cf8935f375a02a1ed4d322db73209c4..b87777e882ad577aa0d9a8b692643a48dda06347 100644 --- a/src/share/classes/java/util/function/Supplier.java +++ b/src/share/classes/java/util/function/Supplier.java @@ -25,10 +25,15 @@ package java.util.function; /** - * A supplier of objects. The result objects are either created during the - * invocation of {@link #get} or by some prior action. + * Represents a supplier of results. * - * @param The type of objects returned by {@code get} + *

                        There is no requirement that a new or distinct result be returned each + * time the supplier is invoked. + * + *

                        This is a functional interface + * whose functional method is {@link #get()}. + * + * @param the type of results supplied by this supplier * * @since 1.8 */ @@ -36,9 +41,9 @@ package java.util.function; public interface Supplier { /** - * Returns an object. + * Gets a result. * - * @return an object + * @return a result */ T get(); } diff --git a/src/share/classes/java/util/function/ToDoubleBiFunction.java b/src/share/classes/java/util/function/ToDoubleBiFunction.java index bd82422b9abe71cca4e5b63de8bffe1ef5bfd645..d0efceef54e69c882a56d7a2b025babfbda17adb 100644 --- a/src/share/classes/java/util/function/ToDoubleBiFunction.java +++ b/src/share/classes/java/util/function/ToDoubleBiFunction.java @@ -25,13 +25,15 @@ package java.util.function; /** - * Apply a function to the input arguments, yielding an appropriate result. - * This is the {@code double}-bearing specialization for {@link BiFunction}. + * Represents a function that accepts two arguments and produces a double-valued + * result. This is the {@code double}-producing primitive specialization for + * {@link BiFunction}. * - * @param the type of the first argument to the {@code applyAsDouble} - * operation. - * @param the type of the second argument to the {@code applyAsDouble} - * operation. + *

                        This is a functional interface + * whose functional method is {@link #applyAsDouble(Object, Object)}. + * + * @param the type of the first argument to the function + * @param the type of the second argument to the function * * @see BiFunction * @since 1.8 @@ -40,11 +42,11 @@ package java.util.function; public interface ToDoubleBiFunction { /** - * Compute the result of applying the function to the input arguments + * Applies this function to the given arguments. * - * @param t an input object - * @param u an input object - * @return the function result value + * @param t the first function argument + * @param u the second function argument + * @return the function result */ double applyAsDouble(T t, U u); } diff --git a/src/share/classes/java/util/function/ToDoubleFunction.java b/src/share/classes/java/util/function/ToDoubleFunction.java index c63d984a7edf6fc30ff8f9a5417b1dfd29584f12..29bf9881387e42132aa069641f5ba66c700c0299 100644 --- a/src/share/classes/java/util/function/ToDoubleFunction.java +++ b/src/share/classes/java/util/function/ToDoubleFunction.java @@ -25,10 +25,13 @@ package java.util.function; /** - * Apply a function to the input argument, yielding an appropriate result. - * This is the {@code double}-bearing specialization for {@link Function}. + * Represents a function that produces a double-valued result. This is the + * {@code double}-producing primitive specialization for {@link Function}. * - * @param the type of input objects to the function + *

                        This is a functional interface + * whose functional method is {@link #applyAsDouble(Object)}. + * + * @param the type of the input to the function * * @see Function * @since 1.8 @@ -37,10 +40,10 @@ package java.util.function; public interface ToDoubleFunction { /** - * Compute the result of applying the function to the input argument + * Applies this function to the given argument. * - * @param t the input object - * @return the function result value + * @param value the function argument + * @return the function result */ - double applyAsDouble(T t); + double applyAsDouble(T value); } diff --git a/src/share/classes/java/util/function/ToIntBiFunction.java b/src/share/classes/java/util/function/ToIntBiFunction.java index 3fc6d560030dc8fe717d0e04bfbce7197cb7dcf4..e31092825696fb59b9950dc5ef349adb07dd1d5b 100644 --- a/src/share/classes/java/util/function/ToIntBiFunction.java +++ b/src/share/classes/java/util/function/ToIntBiFunction.java @@ -25,13 +25,15 @@ package java.util.function; /** - * Apply a function to the input arguments, yielding an appropriate result. - * This is the {@code int}-bearing specialization for {@link BiFunction}. + * Represents a function that accepts two arguments and produces an int-valued + * result. This is the {@code int}-producing primitive specialization for + * {@link BiFunction}. * - * @param the type of the first argument to the {@code applyAsInt} - * operation - * @param the type of the second argument to the {@code applyAsInt} - * operation + *

                        This is a functional interface + * whose functional method is {@link #applyAsInt(Object, Object)}. + * + * @param the type of the first argument to the function + * @param the type of the second argument to the function * * @see BiFunction * @since 1.8 @@ -40,11 +42,11 @@ package java.util.function; public interface ToIntBiFunction { /** - * Compute the result of applying the function to the input arguments + * Applies this function to the given arguments. * - * @param t an input object - * @param u an input object - * @return the function result value + * @param t the first function argument + * @param u the second function argument + * @return the function result */ int applyAsInt(T t, U u); } diff --git a/src/share/classes/java/util/function/ToIntFunction.java b/src/share/classes/java/util/function/ToIntFunction.java index c3fd2f7004fc6e222c90848315ad8ed075a302d0..5768242d1b4cbb97cee8d855fd45a061a92364da 100644 --- a/src/share/classes/java/util/function/ToIntFunction.java +++ b/src/share/classes/java/util/function/ToIntFunction.java @@ -25,10 +25,13 @@ package java.util.function; /** - * Apply a function to the input argument, yielding an appropriate result. - * This is the {@code int}-bearing specialization for {@link Function}. + * Represents a function that produces an int-valued result. This is the + * {@code int}-producing primitive specialization for {@link Function}. * - * @param the type of input objects to the function + *

                        This is a functional interface + * whose functional method is {@link #applyAsInt(Object)}. + * + * @param the type of the input to the function * * @see Function * @since 1.8 @@ -37,10 +40,10 @@ package java.util.function; public interface ToIntFunction { /** - * Compute the result of applying the function to the input arguments + * Applies this function to the given argument. * - * @param t the input object - * @return the function result value + * @param value the function argument + * @return the function result */ - int applyAsInt(T t); + int applyAsInt(T value); } diff --git a/src/share/classes/java/util/function/ToLongBiFunction.java b/src/share/classes/java/util/function/ToLongBiFunction.java index abf6f7851d17729514f956c1198ce4f0be526295..8b5ed7e533d9058b2d58c15760174542b666b075 100644 --- a/src/share/classes/java/util/function/ToLongBiFunction.java +++ b/src/share/classes/java/util/function/ToLongBiFunction.java @@ -25,13 +25,15 @@ package java.util.function; /** - * Apply a function to the input arguments, yielding an appropriate result. - * This is the {@code long}-bearing specialization for {@link BiFunction}. + * Represents a function that accepts two arguments and produces a long-valued + * result. This is the {@code long}-producing primitive specialization for + * {@link BiFunction}. * - * @param the type of the first argument to the {@code applyAsLong} - * operation. - * @param the type of the second argument to the {@code applyAsLong} - * operation. + *

                        This is a functional interface + * whose functional method is {@link #applyAsLong(Object, Object)}. + * + * @param the type of the first argument to the function + * @param the type of the second argument to the function * * @see BiFunction * @since 1.8 @@ -40,11 +42,11 @@ package java.util.function; public interface ToLongBiFunction { /** - * Compute the result of applying the function to the input arguments. + * Applies this function to the given arguments. * - * @param t an input object - * @param u an input object - * @return the function result value + * @param t the first function argument + * @param u the second function argument + * @return the function result */ long applyAsLong(T t, U u); } diff --git a/src/share/classes/java/util/function/ToLongFunction.java b/src/share/classes/java/util/function/ToLongFunction.java index 4489c6fa6555de9e9dda4ffde03a765e4aef22fa..eefb6178bd54ea499d192483ed2c94016b467455 100644 --- a/src/share/classes/java/util/function/ToLongFunction.java +++ b/src/share/classes/java/util/function/ToLongFunction.java @@ -25,10 +25,13 @@ package java.util.function; /** - * Apply a function to the input argument, yielding an appropriate result. - * This is the {@code long}-bearing specialization for {@link Function}. + * Represents a function that produces a long-valued result. This is the + * {@code long}-producing primitive specialization for {@link Function}. * - * @param the type of input objects to the function + *

                        This is a functional interface + * whose functional method is {@link #applyAsLong(Object)}. + * + * @param the type of the input to the function * * @see Function * @since 1.8 @@ -37,10 +40,10 @@ package java.util.function; public interface ToLongFunction { /** - * Compute the result of applying the function to the input arguments. + * Applies this function to the given argument. * - * @param t the input object - * @return the function result value + * @param value the function argument + * @return the function result */ - long applyAsLong(T t); + long applyAsLong(T value); } diff --git a/src/share/classes/java/util/function/UnaryOperator.java b/src/share/classes/java/util/function/UnaryOperator.java index e7794ca19e50a43a22af61323d49ebeea949fc54..c4aa749a68a02b55af4cae6387a20a0e2858a05d 100644 --- a/src/share/classes/java/util/function/UnaryOperator.java +++ b/src/share/classes/java/util/function/UnaryOperator.java @@ -25,11 +25,14 @@ package java.util.function; /** - * An operation upon a single operand yielding a result. The operand and the - * result are of the same type. This is a specialization of {@code Function} for + * Represents an operation on a single operand that produces a result of the + * same type as its operand. This is a specialization of {@code Function} for * the case where the operand and result are of the same type. * - * @param the type of operand to {@code apply} and of the result + *

                        This is a functional interface + * whose functional method is {@link #apply(Object)}. + * + * @param the type of the operand and result of the operator * * @see Function * @since 1.8 @@ -38,10 +41,10 @@ package java.util.function; public interface UnaryOperator extends Function { /** - * Returns a unary operator that provides its input value as the result. + * Returns a unary operator that always returns its input argument. * - * @param the type of the input and output objects to the function - * @return a unary operator that provides its input value as the result + * @param the type of the input and output of the operator + * @return a unary operator that always returns its input argument */ static UnaryOperator identity() { return t -> t; diff --git a/src/share/classes/java/util/function/package-info.java b/src/share/classes/java/util/function/package-info.java index 36eda330d1922888212b7355b2a4449586508a40..158d1f0212dbf386d87023adaa0d5453fddd5ee4 100644 --- a/src/share/classes/java/util/function/package-info.java +++ b/src/share/classes/java/util/function/package-info.java @@ -25,56 +25,82 @@ /** * Functional interfaces provide target types for lambda expressions - * and method references. Each functional interface has a single abstract method + * and method references. Each functional interface has a single abstract + * method, called the functional method for that functional interface, * to which the lambda expression's parameter and return types are matched or - * adapted. Functional interfaces can provide a target type in multiple contexts, - * such as assignment context, method invocation, or cast context: + * adapted. Functional interfaces can provide a target type in multiple + * contexts, such as assignment context, method invocation, or cast context: * - *

                        - *     Predicate<String> p = String::isEmpty;
                        + * 
                        {@code
                        + *     // Assignment context
                        + *     Predicate p = String::isEmpty;
                          *
                        + *     // Method invocation context
                          *     stream.filter(e -> e.getSize() > 10)...
                          *
                        + *     // Cast context
                          *     stream.map((ToIntFunction) e -> e.getSize())...
                        - * 
                        + * }
                        * - *

                        The interfaces in this package are functional interfaces used by the JDK, - * and are available to be used by user code as well. While they do not identify - * a complete set of function shapes to which lambda expressions might be adapted, - * they provide enough to cover common requirements. + *

                        The interfaces in this package are general purpose functional interfaces + * used by the JDK, and are available to be used by user code as well. While + * they do not identify a complete set of function shapes to which lambda + * expressions might be adapted, they provide enough to cover common + * requirements. Other functional interfaces provided for specific purposes, + * such as {@link java.io.FileFilter}, are defined in the packages where they + * are used. * - *

                        The interfaces in this package are annotated with @{link FunctionalInterface}. - * This annotation is not a requirement for the compiler to recognize an interface - * as a functional interface, but merely an aid to capture design intent and enlist the - * help of the compiler in identifying accidental violations of design intent. + *

                        The interfaces in this package are annotated with + * {@link java.lang.FunctionalInterface}. This annotation is not a requirement + * for the compiler to recognize an interface as a functional interface, but + * merely an aid to capture design intent and enlist the help of the compiler in + * identifying accidental violations of design intent. * - *

                        The functional interfaces in this package follow an extensible naming convention, - * as follows: + *

                        Functional interfaces often represent abstract concepts like functions, + * actions, or predicates. In documenting functional interfaces, or referring + * to variables typed as functional interfaces, it is common to refer directly + * to those abstract concepts, for example using "this function" instead of + * "the function represented by this object". + * + *

                        The functional interfaces in this package follow an extensible naming + * convention, as follows: * *

                          - *
                        • There are several basic function shapes, including {@link java.util.function.Function} ({@code T -> R}), - * {@link java.util.function.Consumer} ({@code T -> void}), - * {@link java.util.function.Predicate} ({@code T -> boolean}), - * and {@link java.util.function.Supplier} ({@code () -> T}). + *
                        • There are several basic function shapes, including + * {@link java.util.function.Function} (unary function from {@code T} to {@code R}), + * {@link java.util.function.Consumer} (unary function from {@code T} to {@code void}), + * {@link java.util.function.Predicate} (unary function from {@code T} to {@code boolean}), + * and {@link java.util.function.Supplier} (nilary function to {@code R}). *
                        • - *
                        • Function shapes have a natural arity based on how they are most commonly used. - * The basic shapes can be modified by an arity prefix to indicate a different arity, - * such as {@link java.util.function.BiFunction} ({@code (T, U) -> R}). + * + *
                        • Function shapes have a natural arity based on how they are most + * commonly used. The basic shapes can be modified by an arity prefix to + * indicate a different arity, such as + * {@link java.util.function.BiFunction} (binary function from {@code T} and + * {@code U} to {@code R}). *
                        • - *
                        • There are additional derived function shapes which extend the basic function - * shapes, including {@link java.util.function.UnaryOperator} (extends {@code Function}) and - * {@link java.util.function.BinaryOperator} (extends {@code BiFunction}). + * + *
                        • There are additional derived function shapes which extend the basic + * function shapes, including {@link java.util.function.UnaryOperator} + * (extends {@code Function}) and {@link java.util.function.BinaryOperator} + * (extends {@code BiFunction}). *
                        • - *
                        • Type parameters of functional interfaces can be specialized to primitives with - * additional type prefixes. To specialize the return type for a type that has both - * generic return type and generic arguments, we prefix {@code ToXxx}, as in - * {@link java.util.function.ToIntFunction}. Otherwise, type arguments are specialized left-to-right, - * as in {@link java.util.function.DoubleConsumer} or {@link java.util.function.ObjIntConsumer}. - * (The type prefix {@code Obj} is used to indicate that we don't want to specialize this parameter, - * but want to move on to the next parameter.) These schemes can be combined as in {@code IntToDoubleFunction}. + * + *
                        • Type parameters of functional interfaces can be specialized to + * primitives with additional type prefixes. To specialize the return type + * for a type that has both generic return type and generic arguments, we + * prefix {@code ToXxx}, as in {@link java.util.function.ToIntFunction}. + * Otherwise, type arguments are specialized left-to-right, as in + * {@link java.util.function.DoubleConsumer} + * or {@link java.util.function.ObjIntConsumer}. + * (The type prefix {@code Obj} is used to indicate that we don't want to + * specialize this parameter, but want to move on to the next parameter, + * as in {@link java.util.function.ObjIntConsumer}.) + * These schemes can be combined, as in {@code IntToDoubleFunction}. *
                        • - *
                        • If there are specialization prefixes for all arguments, the arity prefix may be left - * out (as in {@link java.util.function.ObjIntConsumer}). + * + *
                        • If there are specialization prefixes for all arguments, the arity + * prefix may be left out (as in {@link java.util.function.ObjIntConsumer}). *
                        • *
                        * diff --git a/src/share/classes/java/util/jar/Attributes.java b/src/share/classes/java/util/jar/Attributes.java index 18ea64293e5bc4a7281594dcc38c61025df40f91..514018391cbe2d4e2fdc7c862abe78724687d463 100644 --- a/src/share/classes/java/util/jar/Attributes.java +++ b/src/share/classes/java/util/jar/Attributes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -527,7 +527,7 @@ public class Attributes implements Map, Cloneable { * Name object for Manifest-Version * manifest attribute. This attribute indicates the version number * of the manifest standard to which a JAR file's manifest conforms. - * @see + * @see * Manifest and Signature Specification */ public static final Name MANIFEST_VERSION = new Name("Manifest-Version"); @@ -535,7 +535,7 @@ public class Attributes implements Map, Cloneable { /** * Name object for Signature-Version * manifest attribute used when signing JAR files. - * @see + * @see * Manifest and Signature Specification */ public static final Name SIGNATURE_VERSION = new Name("Signature-Version"); diff --git a/src/share/classes/java/util/jar/JarEntry.java b/src/share/classes/java/util/jar/JarEntry.java index 0b494461739de53417515fb5fc41c544b664583b..b0e6841bf832c415da5aabb1c71aae6c76e21147 100644 --- a/src/share/classes/java/util/jar/JarEntry.java +++ b/src/share/classes/java/util/jar/JarEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,6 +81,7 @@ class JarEntry extends ZipEntry { * * @return the Manifest Attributes for this * entry, or null if none + * @throws IOException if an I/O error has occurred */ public Attributes getAttributes() throws IOException { return attr; diff --git a/src/share/classes/java/util/jar/JarFile.java b/src/share/classes/java/util/jar/JarFile.java index f8deb7643ac056b59d8376604dab3dcff6d28528..6759a28ccbad3d3cb05eca1d614b42afdad14e8e 100644 --- a/src/share/classes/java/util/jar/JarFile.java +++ b/src/share/classes/java/util/jar/JarFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -168,6 +168,7 @@ class JarFile extends ZipFile { * * @throws IllegalStateException * may be thrown if the jar file has been closed + * @throws IOException if an I/O error has occurred */ public Manifest getManifest() throws IOException { return getManifestFromReference(); diff --git a/src/share/classes/java/util/stream/StreamSupport.java b/src/share/classes/java/util/stream/StreamSupport.java index 0d9a5c36e827f3c0ebc9f8faba090042d424ae4d..f6e04b0a51a7d1771ee3fd0d19dc6fefd2f13521 100644 --- a/src/share/classes/java/util/stream/StreamSupport.java +++ b/src/share/classes/java/util/stream/StreamSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,6 +96,7 @@ public final class StreamSupport { * Non-Interference for * more details. * + * @param the type of stream elements * @param supplier a {@code Supplier} of a {@code Spliterator} * @param characteristics Spliterator characteristics of the supplied * {@code Spliterator}. The characteristics must be equal to diff --git a/src/share/classes/sun/security/pkcs/PKCS9Attribute.java b/src/share/classes/sun/security/pkcs/PKCS9Attribute.java index 0a9e3a5dbea173a2b83e5fec1d319659f2cd1c0b..d847b104955f22e8b6250722ea86755d3ca3bdce 100644 --- a/src/share/classes/sun/security/pkcs/PKCS9Attribute.java +++ b/src/share/classes/sun/security/pkcs/PKCS9Attribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -310,7 +310,8 @@ public class PKCS9Attribute implements DerEncoder { private static final Byte[][] PKCS9_VALUE_TAGS = { null, {new Byte(DerValue.tag_IA5String)}, // EMailAddress - {new Byte(DerValue.tag_IA5String)}, // UnstructuredName + {new Byte(DerValue.tag_IA5String), // UnstructuredName + new Byte(DerValue.tag_PrintableString)}, {new Byte(DerValue.tag_ObjectId)}, // ContentType {new Byte(DerValue.tag_OctetString)}, // MessageDigest {new Byte(DerValue.tag_UtcTime)}, // SigningTime diff --git a/src/share/classes/sun/security/provider/certpath/OCSP.java b/src/share/classes/sun/security/provider/certpath/OCSP.java index ca82ef598a05939764357139f3a1d7253137c30a..2c375a869b76dd87afe64d31eedb400635d57ba9 100644 --- a/src/share/classes/sun/security/provider/certpath/OCSP.java +++ b/src/share/classes/sun/security/provider/certpath/OCSP.java @@ -255,7 +255,9 @@ public final class OCSP { } response = Arrays.copyOf(response, total); } catch (IOException ioe) { - throw new NetworkFailureException(ioe); + throw new CertPathValidatorException( + "Unable to determine revocation status due to network error", + ioe, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); } finally { if (in != null) { try { @@ -355,17 +357,4 @@ public final class OCSP { */ Map getSingleExtensions(); } - - static class NetworkFailureException extends CertPathValidatorException { - private static final long serialVersionUID = 0l; - - NetworkFailureException(Throwable t) { - super(t); - } - - @Override - public CertPathValidatorException.Reason getReason() { - return BasicReason.UNDETERMINED_REVOCATION_STATUS; - } - } } diff --git a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java index 1d84a4c144900cfac9ff166a56fccade67ccf936..5580dc70b888a71b9bbf91e351aee3afa22a9f5b 100644 --- a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java +++ b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java @@ -30,6 +30,7 @@ import java.security.*; import java.security.cert.CertificateException; import java.security.cert.CertificateParsingException; import java.security.cert.CertPathValidatorException; +import java.security.cert.CertPathValidatorException.BasicReason; import java.security.cert.CRLReason; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; @@ -121,8 +122,8 @@ public final class OCSPResponse { public enum ResponseStatus { SUCCESSFUL, // Response has valid confirmations - MALFORMED_REQUEST, // Illegal confirmation request - INTERNAL_ERROR, // Internal error in issuer + MALFORMED_REQUEST, // Illegal request + INTERNAL_ERROR, // Internal error in responder TRY_LATER, // Try again later UNUSED, // is not used SIG_REQUIRED, // Must sign the request @@ -381,9 +382,18 @@ public final class OCSPResponse { Date date, byte[] nonce) throws CertPathValidatorException { - if (responseStatus != ResponseStatus.SUCCESSFUL) { - throw new CertPathValidatorException - ("OCSP response error: " + responseStatus); + switch (responseStatus) { + case SUCCESSFUL: + break; + case UNAUTHORIZED: + case TRY_LATER: + case INTERNAL_ERROR: + throw new CertPathValidatorException( + "OCSP response error: " + responseStatus, null, null, -1, + BasicReason.UNDETERMINED_REVOCATION_STATUS); + default: + throw new CertPathValidatorException("OCSP response error: " + + responseStatus); } // Check that the response includes a response for all of the diff --git a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java index 057e99e40706064b1d5557c46faf682bd0c1ab61..728bc19f5db5150e3883f0805201eee279b5943e 100644 --- a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java +++ b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -193,10 +193,15 @@ public final class PKIXCertPathValidator extends CertPathValidatorSpi { List checkers = params.certPathCheckers(); for (PKIXCertPathChecker checker : checkers) { if (checker instanceof PKIXRevocationChecker) { + if (revCheckerAdded) { + throw new CertPathValidatorException( + "Only one PKIXRevocationChecker can be specified"); + } revCheckerAdded = true; // if it's our own, initialize it - if (checker instanceof RevocationChecker) + if (checker instanceof RevocationChecker) { ((RevocationChecker)checker).init(anchor, params); + } } } // only add a RevocationChecker if revocation is enabled and diff --git a/src/share/classes/sun/security/provider/certpath/ReverseState.java b/src/share/classes/sun/security/provider/certpath/ReverseState.java index 1ec6147cb36b32f3e647b2b46bad8abf534cefe6..c51500308aebcbd2284717dde46c917d400a2dea 100644 --- a/src/share/classes/sun/security/provider/certpath/ReverseState.java +++ b/src/share/classes/sun/security/provider/certpath/ReverseState.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.security.PublicKey; import java.security.cert.CertificateException; import java.security.cert.CertPathValidatorException; import java.security.cert.PKIXCertPathChecker; +import java.security.cert.PKIXRevocationChecker; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.util.ArrayList; @@ -235,9 +236,16 @@ class ReverseState implements State { for (PKIXCertPathChecker checker : userCheckers) { if (checker instanceof AlgorithmChecker) { ((AlgorithmChecker)checker).trySetTrustAnchor(anchor); - } else if (checker instanceof RevocationChecker) { - ((RevocationChecker)checker).init(anchor, buildParams); - ((RevocationChecker)checker).init(false); + } else if (checker instanceof PKIXRevocationChecker) { + if (revCheckerAdded) { + throw new CertPathValidatorException( + "Only one PKIXRevocationChecker can be specified"); + } + // if it's our own, initialize it + if (checker instanceof RevocationChecker) { + ((RevocationChecker)checker).init(anchor, buildParams); + } + ((PKIXRevocationChecker)checker).init(false); revCheckerAdded = true; } } diff --git a/src/share/classes/sun/security/provider/certpath/RevocationChecker.java b/src/share/classes/sun/security/provider/certpath/RevocationChecker.java index 98d8a9d227237650e8fdcdeb7e454d502373c76d..0aad090a8b05241f9330d87836000807b27c9b2b 100644 --- a/src/share/classes/sun/security/provider/certpath/RevocationChecker.java +++ b/src/share/classes/sun/security/provider/certpath/RevocationChecker.java @@ -38,14 +38,7 @@ import java.security.Security; import java.security.cert.CertPathValidatorException.BasicReason; import java.security.cert.Extension; import java.security.cert.*; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import javax.security.auth.x500.X500Principal; import static sun.security.provider.certpath.OCSP.*; @@ -70,13 +63,16 @@ class RevocationChecker extends PKIXRevocationChecker { private Map ocspResponses; private List ocspExtensions; private boolean legacy; + private LinkedList softFailExceptions = + new LinkedList<>(); // state variables private X509Certificate issuerCert; private PublicKey prevPubKey; private boolean crlSignFlag; + private int certIndex; - private enum Mode { PREFER_OCSP, PREFER_CRLS, ONLY_CRLS }; + private enum Mode { PREFER_OCSP, PREFER_CRLS, ONLY_CRLS, ONLY_OCSP }; private Mode mode = Mode.PREFER_OCSP; private static class RevocationProperties { @@ -104,9 +100,9 @@ class RevocationChecker extends PKIXRevocationChecker { throws CertPathValidatorException { RevocationProperties rp = getRevocationProperties(); - URI uri = getOCSPResponder(); + URI uri = getOcspResponder(); responderURI = (uri == null) ? toURI(rp.ocspUrl) : uri; - X509Certificate cert = getOCSPResponderCert(); + X509Certificate cert = getOcspResponderCert(); responderCert = (cert == null) ? getResponderCert(rp, params.trustAnchors(), params.certStores()) @@ -117,31 +113,38 @@ class RevocationChecker extends PKIXRevocationChecker { case ONLY_END_ENTITY: case PREFER_CRLS: case SOFT_FAIL: + case NO_FALLBACK: break; default: throw new CertPathValidatorException( "Unrecognized revocation parameter option: " + option); } } + softFail = options.contains(Option.SOFT_FAIL); // set mode, only end entity flag if (legacy) { mode = (rp.ocspEnabled) ? Mode.PREFER_OCSP : Mode.ONLY_CRLS; onlyEE = rp.onlyEE; } else { - if (options.contains(Option.PREFER_CRLS)) { + if (options.contains(Option.NO_FALLBACK)) { + if (options.contains(Option.PREFER_CRLS)) { + mode = Mode.ONLY_CRLS; + } else { + mode = Mode.ONLY_OCSP; + } + } else if (options.contains(Option.PREFER_CRLS)) { mode = Mode.PREFER_CRLS; } onlyEE = options.contains(Option.ONLY_END_ENTITY); } - softFail = options.contains(Option.SOFT_FAIL); if (legacy) { crlDP = rp.crlDPEnabled; } else { crlDP = true; } - ocspResponses = getOCSPResponses(); - ocspExtensions = getOCSPExtensions(); + ocspResponses = getOcspResponses(); + ocspExtensions = getOcspExtensions(); this.anchor = anchor; this.params = params; @@ -297,14 +300,19 @@ class RevocationChecker extends PKIXRevocationChecker { if (forward) { throw new CertPathValidatorException("forward checking not supported"); + } + if (anchor != null) { + issuerCert = anchor.getTrustedCert(); + prevPubKey = (issuerCert != null) ? issuerCert.getPublicKey() + : anchor.getCAPublicKey(); + } + crlSignFlag = true; + if (params.certPath() != null) { + certIndex = params.certPath().getCertificates().size() - 1; } else { - if (anchor != null) { - issuerCert = anchor.getTrustedCert(); - prevPubKey = (issuerCert != null) ? issuerCert.getPublicKey() - : anchor.getCAPublicKey(); - } - crlSignFlag = true; + certIndex = -1; } + softFailExceptions.clear(); } @Override @@ -317,28 +325,35 @@ class RevocationChecker extends PKIXRevocationChecker { return null; } + @Override + public List getSoftFailExceptions() { + return Collections.unmodifiableList(softFailExceptions); + } + @Override public void check(Certificate cert, Collection unresolvedCritExts) throws CertPathValidatorException { - X509Certificate xcert = (X509Certificate)cert; - if (onlyEE && xcert.getBasicConstraints() != -1) { - if (debug != null) { - debug.println("Skipping revocation check, not end entity cert"); - } - } else { - check(xcert, unresolvedCritExts, prevPubKey, crlSignFlag); - } - updateState(xcert); + check((X509Certificate)cert, unresolvedCritExts, + prevPubKey, crlSignFlag); } - void check(X509Certificate xcert, Collection unresolvedCritExts, - PublicKey pubKey, boolean crlSignFlag) + private void check(X509Certificate xcert, + Collection unresolvedCritExts, + PublicKey pubKey, boolean crlSignFlag) throws CertPathValidatorException { try { + if (onlyEE && xcert.getBasicConstraints() != -1) { + if (debug != null) { + debug.println("Skipping revocation check, not end " + + "entity cert"); + } + return; + } switch (mode) { case PREFER_OCSP: + case ONLY_OCSP: checkOCSP(xcert, unresolvedCritExts); break; case PREFER_CRLS: @@ -351,14 +366,17 @@ class RevocationChecker extends PKIXRevocationChecker { if (e.getReason() == BasicReason.REVOKED) { throw e; } - CertPathValidatorException cause = e; - if (softFail && e instanceof NetworkFailureException) { - if (mode == Mode.ONLY_CRLS) return; - } - // Rethrow the exception if ONLY_CRLS - if (mode == Mode.ONLY_CRLS) { - throw e; + boolean eSoftFail = isSoftFailException(e); + if (eSoftFail) { + if (mode == Mode.ONLY_OCSP || mode == Mode.ONLY_CRLS) { + return; + } + } else { + if (mode == Mode.ONLY_OCSP || mode == Mode.ONLY_CRLS) { + throw e; + } } + CertPathValidatorException cause = e; // Otherwise, failover if (debug != null) { debug.println("RevocationChecker.check() " + e.getMessage()); @@ -382,20 +400,33 @@ class RevocationChecker extends PKIXRevocationChecker { if (x.getReason() == BasicReason.REVOKED) { throw x; } - if (cause != null) { - if (softFail && cause instanceof NetworkFailureException) { - return; - } else { - cause.addSuppressed(x); + if (!isSoftFailException(x)) { + cause.addSuppressed(x); + throw cause; + } else { + // only pass if both exceptions were soft failures + if (!eSoftFail) { throw cause; } } - if (softFail && x instanceof NetworkFailureException) { - return; - } - throw x; } + } finally { + updateState(xcert); + } + } + + private boolean isSoftFailException(CertPathValidatorException e) { + if (softFail && + e.getReason() == BasicReason.UNDETERMINED_REVOCATION_STATUS) + { + // recreate exception with correct index + CertPathValidatorException e2 = new CertPathValidatorException( + e.getMessage(), e.getCause(), params.certPath(), certIndex, + e.getReason()); + softFailExceptions.addFirst(e2); + return true; } + return false; } private void updateState(X509Certificate cert) @@ -411,6 +442,9 @@ class RevocationChecker extends PKIXRevocationChecker { } prevPubKey = pubKey; crlSignFlag = certCanSignCrl(cert); + if (certIndex > 0) { + certIndex--; + } } // Maximum clock skew in milliseconds (15 minutes) allowed when checking @@ -446,8 +480,8 @@ class RevocationChecker extends PKIXRevocationChecker { " circular dependency"); } throw new CertPathValidatorException - ("Could not determine revocation status", null, null, -1, - BasicReason.UNDETERMINED_REVOCATION_STATUS); + ("Could not determine revocation status", null, null, -1, + BasicReason.UNDETERMINED_REVOCATION_STATUS); } Set possibleCRLs = new HashSet<>(); @@ -457,7 +491,7 @@ class RevocationChecker extends PKIXRevocationChecker { CertPathHelper.setDateAndTime(sel, params.date(), MAX_CLOCK_SKEW); // First, check user-specified CertStores - NetworkFailureException nfe = null; + CertPathValidatorException networkFailureException = null; for (CertStore store : certStores) { try { for (CRL crl : store.getCRLs(sel)) { @@ -468,10 +502,13 @@ class RevocationChecker extends PKIXRevocationChecker { debug.println("RevocationChecker.checkCRLs() " + "CertStoreException: " + e.getMessage()); } - if (softFail && nfe == null && + if (networkFailureException == null && CertStoreHelper.isCausedByNetworkIssue(store.getType(),e)) { // save this exception, we may need to throw it later - nfe = new NetworkFailureException(e); + networkFailureException = new CertPathValidatorException( + "Unable to determine revocation status due to " + + "network error", e, null, -1, + BasicReason.UNDETERMINED_REVOCATION_STATUS); } } } @@ -508,14 +545,17 @@ class RevocationChecker extends PKIXRevocationChecker { approvedCRLs.addAll(DistributionPointFetcher.getCRLs( sel, signFlag, prevKey, params.sigProvider(), certStores, - reasonsMask, anchors, params.date())); + reasonsMask, anchors, null)); } } catch (CertStoreException e) { - if (softFail && e instanceof CertStoreTypeException) { + if (e instanceof CertStoreTypeException) { CertStoreTypeException cste = (CertStoreTypeException)e; if (CertStoreHelper.isCausedByNetworkIssue(cste.getType(), e)) { - throw new NetworkFailureException(e); + throw new CertPathValidatorException( + "Unable to determine revocation status due to " + + "network error", e, null, -1, + BasicReason.UNDETERMINED_REVOCATION_STATUS); } } throw new CertPathValidatorException(e); @@ -531,26 +571,26 @@ class RevocationChecker extends PKIXRevocationChecker { stackedCerts); return; } catch (CertPathValidatorException cpve) { - if (nfe != null) { + if (networkFailureException != null) { // if a network issue previously prevented us from // retrieving a CRL from one of the user-specified - // CertStores and SOFT_FAIL is enabled, throw it now - // so it can be handled appropriately - throw nfe; + // CertStores, throw it now so it can be handled + // appropriately + throw networkFailureException; } throw cpve; } } else { - if (nfe != null) { + if (networkFailureException != null) { // if a network issue previously prevented us from // retrieving a CRL from one of the user-specified - // CertStores and SOFT_FAIL is enabled, throw it now - // so it can be handled appropriately - throw nfe; + // CertStores, throw it now so it can be handled + // appropriately + throw networkFailureException; } - throw new CertPathValidatorException - ("Could not determine revocation status", null, null, -1, - BasicReason.UNDETERMINED_REVOCATION_STATUS); + throw new CertPathValidatorException( + "Could not determine revocation status", null, null, -1, + BasicReason.UNDETERMINED_REVOCATION_STATUS); } } } @@ -595,14 +635,9 @@ class RevocationChecker extends PKIXRevocationChecker { unresCritExts.remove(ReasonCode_Id.toString()); unresCritExts.remove(CertificateIssuer_Id.toString()); if (!unresCritExts.isEmpty()) { - if (debug != null) { - debug.println("Unrecognized " - + "critical extension(s) in revoked CRL entry: " - + unresCritExts); - } - throw new CertPathValidatorException - ("Could not determine revocation status", null, null, - -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); + throw new CertPathValidatorException( + "Unrecognized critical extension(s) in revoked " + + "CRL entry"); } } @@ -610,11 +645,14 @@ class RevocationChecker extends PKIXRevocationChecker { if (reasonCode == null) { reasonCode = CRLReason.UNSPECIFIED; } - Throwable t = new CertificateRevokedException - (entry.getRevocationDate(), reasonCode, - crl.getIssuerX500Principal(), entry.getExtensions()); - throw new CertPathValidatorException(t.getMessage(), t, - null, -1, BasicReason.REVOKED); + Date revocationDate = entry.getRevocationDate(); + if (revocationDate.before(params.date())) { + Throwable t = new CertificateRevokedException( + revocationDate, reasonCode, + crl.getIssuerX500Principal(), entry.getExtensions()); + throw new CertPathValidatorException( + t.getMessage(), t, null, -1, BasicReason.REVOKED); + } } } } @@ -630,9 +668,6 @@ class RevocationChecker extends PKIXRevocationChecker { throw new CertPathValidatorException(ce); } - URI responderURI = (this.responderURI != null) - ? this.responderURI : getOCSPServerURI(currCert); - X509Certificate respCert = (responderCert == null) ? issuerCert : responderCert; @@ -671,23 +706,38 @@ class RevocationChecker extends PKIXRevocationChecker { params.date(), nonce); } else { + URI responderURI = (this.responderURI != null) + ? this.responderURI + : OCSP.getResponderURI(currCert); + if (responderURI == null) { + throw new CertPathValidatorException( + "Certificate does not specify OCSP responder", null, + null, -1); + } + response = OCSP.check(Collections.singletonList(certId), - responderURI, respCert, params.date(), + responderURI, respCert, null, ocspExtensions); } } catch (IOException e) { - throw new CertPathValidatorException(e); + throw new CertPathValidatorException( + "Unable to determine revocation status due to network error", + e, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); } RevocationStatus rs = (RevocationStatus)response.getSingleResponse(certId); RevocationStatus.CertStatus certStatus = rs.getCertStatus(); if (certStatus == RevocationStatus.CertStatus.REVOKED) { - Throwable t = new CertificateRevokedException( - rs.getRevocationTime(), rs.getRevocationReason(), - respCert.getSubjectX500Principal(), rs.getSingleExtensions()); - throw new CertPathValidatorException(t.getMessage(), t, null, - -1, BasicReason.REVOKED); + Date revocationTime = rs.getRevocationTime(); + if (revocationTime.before(params.date())) { + Throwable t = new CertificateRevokedException( + revocationTime, rs.getRevocationReason(), + respCert.getSubjectX500Principal(), + rs.getSingleExtensions()); + throw new CertPathValidatorException(t.getMessage(), t, null, + -1, BasicReason.REVOKED); + } } else if (certStatus == RevocationStatus.CertStatus.UNKNOWN) { throw new CertPathValidatorException( "Certificate's revocation status is unknown", null, @@ -711,34 +761,6 @@ class RevocationChecker extends PKIXRevocationChecker { return hexNumber.toString(); } - private static URI getOCSPServerURI(X509CertImpl cert) - throws CertPathValidatorException - { - // Examine the certificate's AuthorityInfoAccess extension - AuthorityInfoAccessExtension aia = - cert.getAuthorityInfoAccessExtension(); - if (aia == null) { - throw new CertPathValidatorException( - "Must specify the location of an OCSP Responder"); - } - - List descriptions = aia.getAccessDescriptions(); - for (AccessDescription description : descriptions) { - if (description.getAccessMethod().equals((Object) - AccessDescription.Ad_OCSP_Id)) { - - GeneralName generalName = description.getAccessLocation(); - if (generalName.getType() == GeneralNameInterface.NAME_URI) { - URIName uri = (URIName)generalName.getName(); - return uri.getURI(); - } - } - } - - throw new CertPathValidatorException( - "Cannot find the location of the OCSP Responder"); - } - /** * Checks that a cert can be used to verify a CRL. * @@ -870,8 +892,8 @@ class RevocationChecker extends PKIXRevocationChecker { " circular dependency"); } throw new CertPathValidatorException - ("Could not determine revocation status", null, null, - -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); + ("Could not determine revocation status", null, null, -1, + BasicReason.UNDETERMINED_REVOCATION_STATUS); } // Try to find another key that might be able to sign @@ -1067,6 +1089,15 @@ class RevocationChecker extends PKIXRevocationChecker { } } + @Override + public RevocationChecker clone() { + RevocationChecker copy = (RevocationChecker)super.clone(); + // we don't deep-copy the exceptions, but that is ok because they + // are never modified after they are instantiated + copy.softFailExceptions = new LinkedList<>(softFailExceptions); + return copy; + } + /* * This inner class extends the X509CertSelector to add an additional * check to make sure the subject public key isn't on a particular list. diff --git a/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java b/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java index 33c1d8b98aa9da17d39ff5f29859f0cc5eb7e5f9..9c39fb6ef4d28e3779119463eea6ee7924406f15 100644 --- a/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java +++ b/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -422,7 +422,6 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi { buildParams.anyPolicyInhibited(), buildParams.policyQualifiersRejected(), rootNode); - checkers.add(policyChecker); // add the algorithm checker @@ -455,11 +454,16 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi { List ckrs = buildParams.certPathCheckers(); for (PKIXCertPathChecker ckr : ckrs) { if (ckr instanceof PKIXRevocationChecker) { + if (revCheckerAdded) { + throw new CertPathValidatorException( + "Only one PKIXRevocationChecker can be specified"); + } revCheckerAdded = true; // if it's our own, initialize it - if (ckr instanceof RevocationChecker) + if (ckr instanceof RevocationChecker) { ((RevocationChecker)ckr).init(builder.trustAnchor, buildParams); + } } } // only add a RevocationChecker if revocation is enabled and diff --git a/src/share/classes/sun/security/tools/keytool/Main.java b/src/share/classes/sun/security/tools/keytool/Main.java index c8e96eb6d6569c97386b7508b3ea1da0077b77c7..02ea1d0497fe775b1fa8bfe4bd460a121c755a5a 100644 --- a/src/share/classes/sun/security/tools/keytool/Main.java +++ b/src/share/classes/sun/security/tools/keytool/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2198,8 +2198,15 @@ public final class Main { printExtensions(rb.getString("Extension.Request."), exts, out); } } else { - out.println(attr.getAttributeId()); - out.println(attr.getAttributeValue()); + out.println("Attribute: " + attr.getAttributeId()); + PKCS9Attribute pkcs9Attr = + new PKCS9Attribute(attr.getAttributeId(), + attr.getAttributeValue()); + out.print(pkcs9Attr.getName() + ": "); + Object attrVal = attr.getAttributeValue(); + out.println(attrVal instanceof String[] ? + Arrays.toString((String[]) attrVal) : + attrVal); } } if (debug) { diff --git a/src/share/lib/hijrah-config-umalqura.properties b/src/share/lib/hijrah-config-umalqura.properties index ac16c7e222f537dff2f060624e43d9f8c7ca9b70..1786c14de97e2224f5a30a3cff2f73bc923926e4 100644 --- a/src/share/lib/hijrah-config-umalqura.properties +++ b/src/share/lib/hijrah-config-umalqura.properties @@ -1,58 +1,369 @@ -# -# hijrah-config-umalqura.properties -# -# -# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. -# -# This properties file defines a Hijrah calendar variant. -# -# Fields: -# -# ::= 'version' '=' -# ::= 'id' '=' -# ::= 'type' '=' -# ::= 'iso-start' '=' -# ::= '=' -# -# version ... (Required) -# -# id ... (Required) -# Identifies the Java Chronology -# -# type ... (Required) -# Identifies the type of calendar in the standard calendar ID scheme -# iso-start ... (Required) -# Specifies the corresponding ISO date to the first Hijrah day -# in the defined range of dates -# -# year ... (Required) -# Number of days for each month of a Hijrah year -# * Each line defines a year. The years must be in the chronological -# order and no gap is allowed. -# * Each line is in the form indicated above. is a Hijrah year and -# nn is the number of days for a month listed in the order of the months. -# * Each year must have 12 months. -# * Each month should be 29 or 30 days long. -# * There must be one or more space characters between the months. -# - -# indicates the version of this definition -version=1.8.0_1 - -# Java chronology ID -id=Hijrah-umalqura - -# Standard calendar type specification -type=islamic-umalqura - -# defines the corresponding ISO date to the earliest Hijrah date -iso-start=2010-12-07 - -# -# the data section; defines the dates with the number of days for each month -# -# Placeholder data until full Umm alQura data can be validated -1432=29 30 30 30 29 30 29 30 29 30 29 29 -1433=30 29 30 30 29 30 30 29 30 29 30 29 -1434=29 30 29 30 29 30 30 29 30 30 29 29 -1435=30 29 30 29 30 29 30 29 30 30 29 30 +# 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 properties file defines a Hijrah calendar variant. +# +# Fields: +# +# ::= 'version' '=' +# ::= 'id' '=' +# ::= 'type' '=' +# ::= 'iso-start' '=' +# ::= '=' +# +# version ... (Required) +# +# id ... (Required) +# Identifies the Java Chronology +# +# type ... (Required) +# Identifies the type of calendar in the standard calendar ID scheme +# iso-start ... (Required) +# Specifies the corresponding ISO date to the first Hijrah day +# in the defined range of dates +# +# year ... (Required) +# Number of days for each month of a Hijrah year +# * Each line defines a year. The years must be in chronological +# order and no gap is allowed. +# * Each line is in the form indicated above. is a Hijrah year and +# nn is the number of days for a month listed in the order of the months. +# * Each year must have 12 months. +# * Each month should be 29 or 30 days long. +# * There must be one or more space characters between the months. +# + +# Version of this definition +version=1.8.0_1 + +# Java chronology ID +id=Hijrah-umalqura + +# Standard calendar type specification +type=islamic-umalqura + +# defines the corresponding ISO date to the earliest Hijrah date +iso-start=1882-11-12 + +# 1 2 3 4 5 6 7 8 9 10 11 12 +1300=30 29 30 29 30 29 30 29 30 29 30 29 +1301=30 30 29 30 29 30 29 30 29 30 29 29 +1302=30 30 30 29 30 30 29 29 30 29 29 30 +1303=29 30 30 29 30 30 29 30 29 30 29 29 +1304=29 30 30 29 30 30 30 29 30 29 30 29 +1305=29 29 30 30 29 30 30 29 30 30 29 29 +1306=30 29 30 29 30 29 30 29 30 30 29 30 +1307=29 30 29 30 29 30 29 30 29 30 29 30 +1308=29 30 30 29 30 29 30 29 30 29 29 30 +1309=29 30 30 30 30 29 29 30 29 29 30 29 +1310=30 29 30 30 30 29 30 29 30 29 29 30 +1311=29 30 29 30 30 30 29 30 29 30 29 29 +1312=30 29 30 29 30 30 29 30 30 29 30 29 +1313=29 30 29 30 29 30 29 30 30 30 29 29 +1314=30 30 29 30 29 29 30 29 30 30 29 30 +1315=29 30 30 29 30 29 29 30 29 30 29 30 +1316=29 30 30 30 29 30 29 29 30 29 30 29 +1317=30 29 30 30 29 30 29 30 29 30 29 29 +1318=30 29 30 30 29 30 30 29 30 29 30 29 +1319=29 30 29 30 30 29 30 29 30 30 29 30 +1320=29 30 29 29 30 29 30 29 30 30 30 29 +1321=30 29 30 29 29 30 29 29 30 30 30 30 +1322=29 30 29 30 29 29 29 30 29 30 30 30 +1323=29 30 30 29 30 29 29 29 30 29 30 30 +1324=29 30 30 29 30 29 30 29 29 30 29 30 +1325=30 29 30 29 30 30 29 30 29 30 29 30 +1326=29 29 30 29 30 30 29 30 29 30 30 29 +1327=30 29 29 30 29 30 29 30 30 29 30 30 +1328=29 30 29 29 30 29 29 30 30 30 29 30 +1329=30 29 30 29 29 30 29 29 30 30 29 30 +1330=30 30 29 30 29 29 30 29 29 30 30 29 +1331=30 30 29 30 30 29 29 30 29 30 29 30 +1332=29 30 29 30 30 29 30 29 30 30 29 29 +1333=30 29 29 30 30 29 30 30 29 30 30 29 +1334=29 29 30 29 30 29 30 30 30 29 30 29 +1335=30 29 30 29 29 30 29 30 30 29 30 30 +1336=29 30 29 30 29 29 30 29 30 29 30 30 +1337=30 29 30 29 30 29 29 30 29 30 29 30 +1338=29 30 30 29 30 30 29 29 30 29 30 29 +1339=30 29 30 29 30 30 30 29 30 29 29 30 +1340=29 29 30 29 30 30 30 30 29 30 29 29 +1341=30 29 29 30 29 30 30 30 29 30 30 29 +1342=29 29 30 29 30 29 30 30 29 30 30 29 +1343=30 29 29 30 29 30 29 30 29 30 30 29 +1344=30 29 30 29 30 30 29 29 30 29 30 29 +1345=30 29 30 30 30 29 30 29 29 30 29 29 +1346=30 29 30 30 30 30 29 30 29 29 30 29 +1347=29 30 29 30 30 30 29 30 30 29 29 30 +1348=29 29 30 29 30 30 29 30 30 30 29 29 +1349=30 29 29 30 29 30 30 29 30 30 29 30 +1350=29 30 29 30 29 30 29 29 30 30 29 30 +1351=30 29 30 29 30 29 30 29 29 30 29 30 +1352=30 29 30 30 29 30 29 30 29 29 30 29 +1353=30 29 30 30 30 29 30 29 29 30 29 30 +1354=29 30 29 30 30 29 30 30 29 30 29 29 +1355=30 29 29 30 30 29 30 30 29 30 30 29 +1356=29 30 29 30 29 30 29 30 29 30 30 30 +1357=29 29 30 29 30 29 29 30 29 30 30 30 +1358=29 30 29 30 29 30 29 29 30 29 30 30 +1359=29 30 30 29 30 29 30 29 29 29 30 30 +1360=29 30 30 30 29 30 29 30 29 29 30 29 +1361=30 29 30 30 29 30 30 29 29 30 29 30 +1362=29 30 29 30 29 30 30 29 30 29 30 29 +1363=30 29 30 29 30 29 30 29 30 29 30 30 +1364=29 30 29 30 29 29 30 29 30 29 30 30 +1365=30 30 29 29 30 29 29 30 29 30 29 30 +1366=30 30 29 30 29 30 29 29 30 29 30 29 +1367=30 30 29 30 30 29 30 29 29 30 29 30 +1368=29 30 29 30 30 30 29 29 30 29 30 29 +1369=30 29 30 29 30 30 29 30 29 30 30 29 +1370=30 29 29 30 29 30 29 30 29 30 30 30 +1371=29 30 29 29 30 29 30 29 30 29 30 30 +1372=30 29 29 30 29 30 29 29 30 29 30 30 +1373=30 29 30 29 30 29 30 29 29 30 29 30 +1374=30 29 30 30 29 30 29 30 29 29 30 29 +1375=30 29 30 30 29 30 30 29 30 29 30 29 +1376=29 30 29 30 29 30 30 30 29 30 29 30 +1377=29 29 30 29 29 30 30 30 29 30 30 29 +1378=30 29 29 29 30 29 30 30 29 30 30 30 +1379=29 30 29 29 29 30 29 30 30 29 30 30 +1380=29 30 29 30 29 30 29 30 29 30 29 30 +1381=29 30 29 30 30 29 30 29 30 29 29 30 +1382=29 30 29 30 30 29 30 30 29 30 29 29 +1383=30 29 29 30 30 30 29 30 30 29 30 29 +1384=29 30 29 29 30 30 29 30 30 30 29 30 +1385=29 29 30 29 29 30 30 29 30 30 30 29 +1386=30 29 29 30 29 29 30 30 29 30 30 29 +1387=30 29 30 29 30 29 30 29 30 29 30 29 +1388=30 30 29 30 29 30 29 30 29 30 29 29 +1389=30 30 29 30 30 29 30 30 29 29 30 29 +1390=29 30 29 30 30 30 29 30 29 30 29 30 +1391=29 29 30 29 30 30 29 30 30 29 30 29 +1392=30 29 29 30 29 30 29 30 30 29 30 30 +1393=29 30 29 29 30 29 30 29 30 29 30 30 +1394=30 29 30 29 29 30 29 30 29 30 29 30 +1395=30 29 30 30 29 30 29 29 30 29 29 30 +1396=30 29 30 30 29 30 30 29 29 30 29 29 +1397=30 29 30 30 29 30 30 30 29 29 29 30 +1398=29 30 29 30 30 29 30 30 29 30 29 29 +1399=30 29 30 29 30 29 30 30 29 30 29 30 +1400=30 29 30 29 29 30 29 30 29 30 29 30 +1401=30 30 29 30 29 29 30 29 29 30 29 30 +1402=30 30 30 29 30 29 29 30 29 29 30 29 +1403=30 30 30 29 30 30 29 29 30 29 29 30 +1404=29 30 30 29 30 30 29 30 29 30 29 29 +1405=30 29 30 29 30 30 30 29 30 29 29 30 +1406=30 29 29 30 29 30 30 29 30 29 30 30 +1407=29 30 29 29 30 29 30 29 30 29 30 30 +1408=30 29 30 29 30 29 29 30 29 29 30 30 +1409=30 30 29 30 29 30 29 29 30 29 29 30 +1410=30 30 29 30 30 29 30 29 29 30 29 29 +1411=30 30 29 30 30 29 30 30 29 29 30 29 +1412=30 29 30 29 30 29 30 30 30 29 29 30 +1413=29 30 29 29 30 29 30 30 30 29 30 29 +1414=30 29 30 29 29 30 29 30 30 29 30 30 +1415=29 30 29 30 29 29 30 29 30 29 30 30 +1416=30 29 30 29 30 29 29 30 29 30 29 30 +1417=30 29 30 30 29 29 30 29 30 29 30 29 +1418=30 29 30 30 29 30 29 30 29 30 29 30 +1419=29 30 29 30 29 30 29 30 30 30 29 29 +1420=29 30 29 29 30 29 30 30 30 30 29 30 +1421=29 29 30 29 29 29 30 30 30 30 29 30 +1422=30 29 29 30 29 29 29 30 30 30 29 30 +1423=30 29 30 29 30 29 29 30 29 30 29 30 +1424=30 29 30 30 29 30 29 29 30 29 30 29 +1425=30 29 30 30 29 30 29 30 30 29 30 29 +1426=29 30 29 30 29 30 30 29 30 30 29 30 +1427=29 29 30 29 30 29 30 30 29 30 30 29 +1428=30 29 29 30 29 29 30 30 30 29 30 30 +1429=29 30 29 29 30 29 29 30 30 29 30 30 +1430=29 30 30 29 29 30 29 30 29 30 29 30 +1431=29 30 30 29 30 29 30 29 30 29 29 30 +1432=29 30 30 30 29 30 29 30 29 30 29 29 +1433=30 29 30 30 29 30 30 29 30 29 30 29 +1434=29 30 29 30 29 30 30 29 30 30 29 29 +1435=30 29 30 29 30 29 30 29 30 30 29 30 +1436=29 30 29 30 29 30 29 30 29 30 29 30 +1437=30 29 30 30 29 29 30 29 30 29 29 30 +1438=30 29 30 30 30 29 29 30 29 29 30 29 +1439=30 29 30 30 30 29 30 29 30 29 29 30 +1440=29 30 29 30 30 30 29 30 29 30 29 29 +1441=30 29 30 29 30 30 29 30 30 29 30 29 +1442=29 30 29 30 29 30 29 30 30 29 30 29 +1443=30 29 30 29 30 29 30 29 30 29 30 30 +1444=29 30 29 30 30 29 29 30 29 30 29 30 +1445=29 30 30 30 29 30 29 29 30 29 29 30 +1446=29 30 30 30 29 30 30 29 29 30 29 29 +1447=30 29 30 30 30 29 30 29 30 29 30 29 +1448=29 30 29 30 30 29 30 30 29 30 29 30 +1449=29 29 30 29 30 29 30 30 29 30 30 29 +1450=30 29 30 29 29 30 29 30 29 30 30 29 +1451=30 30 30 29 29 30 29 29 30 30 29 30 +1452=30 29 30 30 29 29 30 29 29 30 29 30 +1453=30 29 30 30 29 30 29 30 29 29 30 29 +1454=30 29 30 30 29 30 30 29 30 29 30 29 +1455=29 30 29 30 30 29 30 29 30 30 29 30 +1456=29 29 30 29 30 29 30 29 30 30 30 29 +1457=30 29 29 30 29 29 30 29 30 30 30 30 +1458=29 30 29 29 30 29 29 30 29 30 30 30 +1459=29 30 30 29 29 30 29 29 30 29 30 30 +1460=29 30 30 29 30 29 30 29 29 30 29 30 +1461=29 30 30 29 30 29 30 29 30 30 29 29 +1462=30 29 30 29 30 30 29 30 29 30 30 29 +1463=29 30 29 30 29 30 29 30 30 30 29 30 +1464=29 30 29 29 30 29 29 30 30 30 29 30 +1465=30 29 30 29 29 30 29 29 30 30 29 30 +1466=30 30 29 30 29 29 29 30 29 30 30 29 +1467=30 30 29 30 30 29 29 30 29 30 29 30 +1468=29 30 29 30 30 29 30 29 30 29 30 29 +1469=29 30 29 30 30 29 30 30 29 30 29 30 +1470=29 29 30 29 30 30 29 30 30 29 30 29 +1471=30 29 29 30 29 30 29 30 30 29 30 30 +1472=29 30 29 29 30 29 30 29 30 30 29 30 +1473=29 30 29 30 30 29 29 30 29 30 29 30 +1474=29 30 30 29 30 30 29 29 30 29 30 29 +1475=29 30 30 29 30 30 30 29 29 30 29 29 +1476=30 29 30 29 30 30 30 29 30 29 30 29 +1477=29 30 29 29 30 30 30 30 29 30 29 30 +1478=29 29 30 29 30 29 30 30 29 30 30 29 +1479=30 29 29 30 29 30 29 30 29 30 30 29 +1480=30 29 30 29 30 29 30 29 30 29 30 29 +1481=30 29 30 30 29 30 29 30 29 30 29 29 +1482=30 29 30 30 30 30 29 30 29 29 30 29 +1483=29 30 29 30 30 30 29 30 30 29 29 30 +1484=29 29 30 29 30 30 30 29 30 29 30 29 +1485=30 29 29 30 29 30 30 29 30 30 29 30 +1486=29 30 29 29 30 29 30 29 30 30 29 30 +1487=30 29 30 29 30 29 29 30 29 30 29 30 +1488=30 29 30 30 29 30 29 29 30 29 30 29 +1489=30 29 30 30 30 29 30 29 29 30 29 30 +1490=29 30 29 30 30 29 30 30 29 29 30 29 +1491=30 29 29 30 30 29 30 30 29 30 29 30 +1492=29 30 29 29 30 30 29 30 29 30 30 29 +1493=30 29 30 29 30 29 29 30 29 30 30 30 +1494=29 30 29 30 29 30 29 29 29 30 30 30 +1495=29 30 30 29 30 29 29 30 29 29 30 30 +1496=29 30 30 30 29 30 29 29 30 29 29 30 +1497=30 29 30 30 29 30 29 30 29 30 29 30 +1498=29 30 29 30 29 30 30 29 30 29 30 29 +1499=30 29 30 29 29 30 30 29 30 29 30 30 +1500=29 30 29 30 29 29 30 29 30 29 30 30 +1501=30 29 30 29 30 29 29 29 30 29 30 30 +1502=30 30 29 30 29 30 29 29 29 30 30 29 +1503=30 30 29 30 30 29 30 29 29 29 30 30 +1504=29 30 29 30 30 30 29 29 30 29 30 29 +1505=30 29 30 29 30 30 29 30 29 30 30 29 +1506=29 30 29 29 30 30 29 30 30 29 30 30 +1507=29 29 30 29 29 30 30 29 30 29 30 30 +1508=30 29 29 30 29 30 29 29 30 29 30 30 +1509=30 29 30 29 30 29 30 29 29 30 29 30 +1510=30 29 30 30 29 30 29 30 29 29 30 29 +1511=30 29 30 30 29 30 30 29 30 29 29 30 +1512=29 30 29 30 29 30 30 30 29 30 29 30 +1513=29 29 29 30 29 30 30 30 29 30 30 29 +1514=30 29 29 29 30 29 30 30 29 30 30 30 +1515=29 29 30 29 29 30 29 30 30 29 30 30 +1516=29 30 29 30 29 29 30 29 30 29 30 30 +1517=29 30 29 30 29 30 30 29 29 30 29 30 +1518=29 30 29 30 30 29 30 30 29 30 29 29 +1519=30 29 29 30 30 30 29 30 30 29 30 29 +1520=29 30 29 29 30 30 30 29 30 30 29 30 +1521=29 29 29 30 29 30 30 29 30 30 29 30 +1522=30 29 29 29 30 29 30 30 29 30 30 29 +1523=30 29 30 29 30 29 30 29 29 30 30 29 +1524=30 30 29 30 29 30 29 30 29 29 30 29 +1525=30 30 29 30 30 29 30 29 30 29 29 30 +1526=29 30 29 30 30 30 29 30 29 30 29 29 +1527=30 29 30 29 30 30 29 30 30 29 30 29 +1528=30 29 29 30 29 30 29 30 30 29 30 30 +1529=29 30 29 29 30 29 30 29 30 29 30 30 +1530=29 30 30 29 29 30 29 30 29 29 30 30 +1531=29 30 30 30 29 29 30 29 30 29 29 30 +1532=29 30 30 30 29 30 30 29 29 29 30 29 +1533=30 29 30 30 30 29 30 29 30 29 29 30 +1534=29 30 29 30 30 29 30 30 29 29 30 29 +1535=30 29 30 29 30 29 30 30 29 30 29 30 +1536=29 30 29 30 29 30 29 30 29 30 29 30 +1537=30 29 30 30 29 29 30 29 29 30 29 30 +1538=30 30 29 30 30 29 29 30 29 29 30 29 +1539=30 30 30 29 30 30 29 29 30 29 29 30 +1540=29 30 30 29 30 30 29 30 29 29 30 29 +1541=30 29 30 29 30 30 30 29 30 29 29 30 +1542=29 30 29 30 29 30 30 29 30 29 30 30 +1543=29 30 29 29 30 29 30 29 30 29 30 30 +1544=30 29 30 29 29 30 29 30 29 30 29 30 +1545=30 30 29 30 29 29 30 29 30 29 29 30 +1546=30 30 29 30 29 30 29 30 29 30 29 29 +1547=30 30 29 30 30 29 30 29 30 29 30 29 +1548=30 29 29 30 30 29 30 30 29 30 29 30 +1549=29 30 29 29 30 29 30 30 30 29 30 29 +1550=30 29 30 29 29 29 30 30 30 29 30 30 +1551=29 30 29 29 30 29 29 30 30 29 30 30 +1552=30 29 30 29 29 30 29 29 30 30 29 30 +1553=30 29 30 29 30 29 30 29 30 29 30 29 +1554=30 29 30 29 30 30 29 30 29 30 29 30 +1555=29 29 30 29 30 30 29 30 30 29 30 29 +1556=30 29 29 30 29 30 29 30 30 30 29 30 +1557=29 30 29 29 29 30 29 30 30 30 30 29 +1558=30 29 30 29 29 29 30 29 30 30 30 29 +1559=30 30 29 29 30 29 29 30 30 29 30 29 +1560=30 30 29 30 29 30 29 30 29 30 29 30 +1561=29 30 30 29 30 29 30 30 29 29 30 29 +1562=29 30 30 29 30 29 30 30 30 29 29 30 +1563=29 30 29 29 30 29 30 30 30 29 30 29 +1564=30 29 30 29 29 30 29 30 30 30 29 30 +1565=29 30 29 30 29 29 30 29 30 30 29 30 +1566=30 29 30 29 30 29 29 30 29 30 29 30 +1567=30 29 30 30 29 30 29 30 29 29 30 29 +1568=30 29 30 30 30 29 30 29 30 29 29 29 +1569=30 29 30 30 30 29 30 30 29 30 29 29 +1570=29 30 29 30 30 29 30 30 30 29 29 30 +1571=29 29 30 29 30 30 29 30 30 29 30 29 +1572=30 29 29 30 29 30 29 30 30 29 30 29 +1573=30 29 30 30 29 30 29 29 30 29 30 29 +1574=30 30 29 30 30 29 30 29 29 30 29 29 +1575=30 30 30 29 30 30 29 30 29 29 29 30 +1576=29 30 30 29 30 30 30 29 30 29 29 29 +1577=30 29 30 30 29 30 30 29 30 29 30 29 +1578=29 30 29 30 29 30 30 29 30 30 29 30 +1579=29 30 29 30 29 29 30 30 29 30 29 30 +1580=29 30 30 29 30 29 29 30 29 30 29 30 +1581=30 30 29 30 29 30 29 29 30 29 30 29 +1582=30 30 29 30 30 29 30 29 30 29 29 29 +1583=30 30 29 30 30 30 29 30 29 30 29 29 +1584=29 30 30 29 30 30 29 30 30 29 30 29 +1585=29 30 29 30 29 30 29 30 30 29 30 30 +1586=29 29 30 29 30 29 29 30 30 30 29 30 +1587=29 30 30 29 29 29 30 29 30 29 30 30 +1588=30 29 30 30 29 29 29 30 29 30 29 30 +1589=30 29 30 30 29 30 29 29 30 29 30 29 +1590=30 29 30 30 30 29 29 30 29 30 29 30 +1591=29 30 29 30 30 29 30 29 30 29 30 29 +1592=30 29 30 29 30 29 30 29 30 30 30 29 +1593=30 29 29 30 29 29 30 29 30 30 30 29 +1594=30 30 29 29 30 29 29 29 30 30 30 30 +1595=29 30 29 30 29 29 30 29 29 30 30 30 +1596=29 30 30 29 30 29 29 30 29 30 29 30 +1597=29 30 30 29 30 29 30 29 30 29 30 29 +1598=30 29 30 29 30 30 29 30 29 30 30 29 +1599=29 30 29 30 29 30 29 30 30 30 29 30 +1600=29 29 30 29 30 29 29 30 30 30 29 30 diff --git a/src/share/native/java/io/io_util.c b/src/share/native/java/io/io_util.c index 9a9ca7d292ddb52664c82187cd0917dd8e04bb95..5dd822382f0ca21c481236d6321f136e5e89dac5 100644 --- a/src/share/native/java/io/io_util.c +++ b/src/share/native/java/io/io_util.c @@ -211,7 +211,11 @@ throwFileNotFoundException(JNIEnv *env, jstring path) n = getLastErrorString(buf, sizeof(buf)); if (n > 0) { +#ifdef WIN32 + why = (*env)->NewStringUTF(env, buf); +#else why = JNU_NewStringPlatform(env, buf); +#endif } x = JNU_NewObjectByName(env, "java/io/FileNotFoundException", diff --git a/src/share/native/java/net/net_util.c b/src/share/native/java/net/net_util.c index 5d15f9d9b0e95354321a41c05efa08c5697a014d..2f99a342ddd7224e43e4fff960f6c17b3774287d 100644 --- a/src/share/native/java/net/net_util.c +++ b/src/share/native/java/net/net_util.c @@ -75,7 +75,7 @@ JNI_OnLoad(JavaVM *vm, void *reserved) static int initialized = 0; -void init(JNIEnv *env) { +static void initInetAddrs(JNIEnv *env) { if (!initialized) { Java_java_net_InetAddress_init(env, 0); Java_java_net_Inet4Address_init(env, 0); @@ -96,42 +96,43 @@ extern jfieldID iac_familyID; void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address) { jobject holder; - init(env); + initInetAddrs(env); holder = (*env)->GetObjectField(env, iaObj, ia_holderID); (*env)->SetIntField(env, holder, iac_addressID, address); } void setInetAddress_family(JNIEnv *env, jobject iaObj, int family) { jobject holder; - init(env); + initInetAddrs(env); holder = (*env)->GetObjectField(env, iaObj, ia_holderID); (*env)->SetIntField(env, holder, iac_familyID, family); } void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject host) { jobject holder; - init(env); + initInetAddrs(env); holder = (*env)->GetObjectField(env, iaObj, ia_holderID); (*env)->SetObjectField(env, holder, iac_hostNameID, host); } int getInetAddress_addr(JNIEnv *env, jobject iaObj) { jobject holder; - init(env); + initInetAddrs(env); holder = (*env)->GetObjectField(env, iaObj, ia_holderID); return (*env)->GetIntField(env, holder, iac_addressID); } int getInetAddress_family(JNIEnv *env, jobject iaObj) { jobject holder; - init(env); + + initInetAddrs(env); holder = (*env)->GetObjectField(env, iaObj, ia_holderID); return (*env)->GetIntField(env, holder, iac_familyID); } jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) { jobject holder; - init(env); + initInetAddrs(env); holder = (*env)->GetObjectField(env, iaObj, ia_holderID); return (*env)->GetObjectField(env, holder, iac_hostNameID); } @@ -139,7 +140,7 @@ jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) { JNIEXPORT jobject JNICALL NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { jobject iaObj; - init(env); + initInetAddrs(env); #ifdef AF_INET6 if (him->sa_family == AF_INET6) { jbyteArray ipaddress; diff --git a/src/windows/native/java/io/io_util_md.c b/src/windows/native/java/io/io_util_md.c index 3e9aef352f7a83cadbb78083603b8d1b822fe933..d886aea9f622b106286755c3eb1b426d0328440d 100644 --- a/src/windows/native/java/io/io_util_md.c +++ b/src/windows/native/java/io/io_util_md.c @@ -29,6 +29,7 @@ #include "io_util.h" #include "io_util_md.h" #include +#include #include #include @@ -40,6 +41,7 @@ #include #include + static DWORD MAX_INPUT_EVENTS = 2000; /* If this returns NULL then an exception is pending */ @@ -569,42 +571,75 @@ handleLseek(FD fd, jlong offset, jint whence) } size_t -getLastErrorString(char *buf, size_t len) +getLastErrorString(char *utf8_jvmErrorMsg, size_t cbErrorMsg) { - DWORD errval; - if (len > 0) { - if ((errval = GetLastError()) != 0) { - // DOS error - size_t n = (size_t)FormatMessage( - FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - errval, - 0, - buf, - (DWORD)len, - NULL); - if (n > 3) { - // Drop final '.', CR, LF - if (buf[n - 1] == '\n') n--; - if (buf[n - 1] == '\r') n--; - if (buf[n - 1] == '.') n--; - buf[n] = '\0'; - } - return n; - } - - if (errno != 0) { - // C runtime error that has no corresponding DOS error code - const char *err = strerror(errno); - size_t n = strlen(err); - if (n >= len) - n = len - 1; + size_t n = 0; + if (cbErrorMsg > 0) { + BOOLEAN noError = FALSE; + WCHAR *utf16_osErrorMsg = (WCHAR *)malloc(cbErrorMsg*sizeof(WCHAR)); + if (utf16_osErrorMsg == NULL) { + // OOM accident + strncpy(utf8_jvmErrorMsg, "Out of memory", cbErrorMsg); + // truncate if too long + utf8_jvmErrorMsg[cbErrorMsg - 1] = '\0'; + n = strlen(utf8_jvmErrorMsg); + } else { + DWORD errval = GetLastError(); + if (errval != 0) { + // WIN32 error + n = (size_t)FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + errval, + 0, + utf16_osErrorMsg, + (DWORD)cbErrorMsg, + NULL); + if (n > 3) { + // Drop final '.', CR, LF + if (utf16_osErrorMsg[n - 1] == L'\n') --n; + if (utf16_osErrorMsg[n - 1] == L'\r') --n; + if (utf16_osErrorMsg[n - 1] == L'.') --n; + utf16_osErrorMsg[n] = L'\0'; + } + } else if (errno != 0) { + // C runtime error that has no corresponding WIN32 error code + const WCHAR *rtError = _wcserror(errno); + if (rtError != NULL) { + wcsncpy(utf16_osErrorMsg, rtError, cbErrorMsg); + // truncate if too long + utf16_osErrorMsg[cbErrorMsg - 1] = L'\0'; + n = wcslen(utf16_osErrorMsg); + } + } else + noError = TRUE; //OS has no error to report + + if (!noError) { + if (n > 0) { + n = WideCharToMultiByte( + CP_UTF8, + 0, + utf16_osErrorMsg, + n, + utf8_jvmErrorMsg, + cbErrorMsg, + NULL, + NULL); + + // no way to die + if (n > 0) + utf8_jvmErrorMsg[min(cbErrorMsg - 1, n)] = '\0'; + } - strncpy(buf, err, n); - buf[n] = '\0'; - return n; + if (n <= 0) { + strncpy(utf8_jvmErrorMsg, "Secondary error while OS message extraction", cbErrorMsg); + // truncate if too long + utf8_jvmErrorMsg[cbErrorMsg - 1] = '\0'; + n = strlen(utf8_jvmErrorMsg); + } + } + free(utf16_osErrorMsg); } } - - return 0; + return n; } diff --git a/src/windows/native/java/lang/ProcessImpl_md.c b/src/windows/native/java/lang/ProcessImpl_md.c index 5b45f8f24f2df3c3727804f6f8aee67584226ace..c372013456cd4691ac19e7c9ab5cd29b1f851c0c 100644 --- a/src/windows/native/java/lang/ProcessImpl_md.c +++ b/src/windows/native/java/lang/ProcessImpl_md.c @@ -40,20 +40,70 @@ */ #define PIPE_SIZE (4096+24) +/* We have THREE locales in action: + * 1. Thread default locale - dictates UNICODE-to-8bit conversion + * 2. System locale that defines the message localization + * 3. The file name locale + * Each locale could be an extended locale, that means that text cannot be + * mapped to 8bit sequence without multibyte encoding. + * VM is ready for that, if text is UTF-8. + * Here we make the work right from the beginning. + */ +size_t os_error_message(int errnum, WCHAR* utf16_OSErrorMsg, size_t maxMsgLength) { + size_t n = (size_t)FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + (DWORD)errnum, + 0, + utf16_OSErrorMsg, + (DWORD)maxMsgLength, + NULL); + if (n > 3) { + // Drop final '.', CR, LF + if (utf16_OSErrorMsg[n - 1] == L'\n') --n; + if (utf16_OSErrorMsg[n - 1] == L'\r') --n; + if (utf16_OSErrorMsg[n - 1] == L'.') --n; + utf16_OSErrorMsg[n] = L'\0'; + } + return n; +} + +#define MESSAGE_LENGTH (256 + 100) +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x)) + static void -win32Error(JNIEnv *env, const char *functionName) +win32Error(JNIEnv *env, const WCHAR *functionName) { - static const char * const format = "%s error=%d, %s"; - static const char * const fallbackFormat = "%s failed, error=%d"; - char buf[256]; - char errmsg[sizeof(buf) + 100]; - const int errnum = GetLastError(); - const int n = JVM_GetLastErrorString(buf, sizeof(buf)); - if (n > 0) - sprintf(errmsg, format, functionName, errnum, buf); - else - sprintf(errmsg, fallbackFormat, functionName, errnum); - JNU_ThrowIOException(env, errmsg); + WCHAR utf16_OSErrorMsg[MESSAGE_LENGTH - 100]; + WCHAR utf16_javaMessage[MESSAGE_LENGTH]; + /*Good suggestion about 2-bytes-per-symbol in localized error reports*/ + char utf8_javaMessage[MESSAGE_LENGTH*2]; + const int errnum = (int)GetLastError(); + int n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg)); + n = (n > 0) + ? swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s error=%d, %s", functionName, errnum, utf16_OSErrorMsg) + : swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s failed, error=%d", functionName, errnum); + + if (n > 0) /*terminate '\0' is not a part of conversion procedure*/ + n = WideCharToMultiByte( + CP_UTF8, + 0, + utf16_javaMessage, + n, /*by creation n <= MESSAGE_LENGTH*/ + utf8_javaMessage, + MESSAGE_LENGTH*2, + NULL, + NULL); + + /*no way to die*/ + { + const char *errorMessage = "Secondary error while OS message extraction"; + if (n > 0) { + utf8_javaMessage[min(MESSAGE_LENGTH*2 - 1, n)] = '\0'; + errorMessage = utf8_javaMessage; + } + JNU_ThrowIOException(env, errorMessage); + } } static void @@ -116,7 +166,7 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, handles[0] = (jlong) -1; } else { if (! CreatePipe(&inRead, &inWrite, &sa, PIPE_SIZE)) { - win32Error(env, "CreatePipe"); + win32Error(env, L"CreatePipe"); goto Catch; } si.hStdInput = inRead; @@ -132,7 +182,7 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, handles[1] = (jlong) -1; } else { if (! CreatePipe(&outRead, &outWrite, &sa, PIPE_SIZE)) { - win32Error(env, "CreatePipe"); + win32Error(env, L"CreatePipe"); goto Catch; } si.hStdOutput = outWrite; @@ -151,7 +201,7 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, handles[2] = (jlong) -1; } else { if (! CreatePipe(&errRead, &errWrite, &sa, PIPE_SIZE)) { - win32Error(env, "CreatePipe"); + win32Error(env, L"CreatePipe"); goto Catch; } si.hStdError = errWrite; @@ -174,7 +224,7 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, &si, /* (in) startup information */ &pi); /* (out) process information */ if (!ret) { - win32Error(env, "CreateProcess"); + win32Error(env, L"CreateProcess"); goto Catch; } @@ -210,7 +260,7 @@ Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong { DWORD exit_code; if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0) - win32Error(env, "GetExitCodeProcess"); + win32Error(env, L"GetExitCodeProcess"); return exit_code; } @@ -231,7 +281,7 @@ Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlo FALSE, /* Wait for ANY event */ INFINITE) /* Wait forever */ == WAIT_FAILED) - win32Error(env, "WaitForMultipleObjects"); + win32Error(env, L"WaitForMultipleObjects"); } JNIEXPORT void JNICALL @@ -250,7 +300,7 @@ Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env, dwTimeout); /* Wait for dwTimeout */ if (result == WAIT_FAILED) - win32Error(env, "WaitForMultipleObjects"); + win32Error(env, L"WaitForMultipleObjects"); } JNIEXPORT void JNICALL @@ -263,7 +313,7 @@ JNIEXPORT jboolean JNICALL Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle) { DWORD dwExitStatus; - GetExitCodeProcess(handle, &dwExitStatus); + GetExitCodeProcess((HANDLE) handle, &dwExitStatus); return dwExitStatus == STILL_ACTIVE; } diff --git a/test/ProblemList.txt b/test/ProblemList.txt index 8c98dbda37afd1aa6984829b37488afef7061b29..a2e02261a922c29074986298f6086bd957d1fb6e 100644 --- a/test/ProblemList.txt +++ b/test/ProblemList.txt @@ -131,12 +131,14 @@ java/lang/management/MemoryMXBean/CollectionUsageThreshold.java generic-all # 7196801 java/lang/management/MemoryMXBean/LowMemoryTest2.sh generic-all -# 8008200 -java/lang/Class/asSubclass/BasicUnit.java generic-all - # 8015780 java/lang/reflect/Method/GenericStringTest.java generic-all +# 8019845 due to memleak not related to the tested fix +java/lang/instrument/RedefineBigClass.sh linux-x64 +java/lang/instrument/RetransformBigClass.sh linux-x64 + + ############################################################################ # jdk_management @@ -165,6 +167,9 @@ demo/jvmti/compiledMethodLoad/CompiledMethodLoadTest.java generic-all # 7027502 demo/jvmti/hprof/MonitorTest.java generic-all +# 8021186 +jdk/lambda/vm/DefaultMethodsTest.java generic-all + ############################################################################ # jdk_net @@ -371,6 +376,9 @@ java/util/concurrent/ThreadPoolExecutor/CoreThreadTimeOut.java generic-all # Filed 6772009 java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java generic-all +# 8020435 +java/util/concurrent/CompletableFuture/Basic.java generic-all + # 7041639, Solaris DSA keypair generation bug java/util/TimeZone/TimeZoneDatePermissionCheck.sh solaris-all diff --git a/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanDoubleInvocationTest.java b/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanDoubleInvocationTest.java index 91f30b0376c293c31814dde371e6e386652af5d2..c2f1e23883c71223e611e6cbf29eb05028122259 100644 --- a/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanDoubleInvocationTest.java +++ b/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanDoubleInvocationTest.java @@ -25,25 +25,15 @@ * @test * @bug 7150256 * @summary Basic Test for the DiagnosticCommandMBean - * @author Frederic Parain + * @author Frederic Parain, Shanliang JIANG * - * @run main/othervm -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=8125 DcmdMBeanDoubleInvocationTest + * @run main/othervm DcmdMBeanDoubleInvocationTest */ -import java.io.IOException; import java.lang.management.ManagementFactory; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.management.Descriptor; -import javax.management.InstanceNotFoundException; -import javax.management.IntrospectionException; -import javax.management.MBeanInfo; -import javax.management.MBeanOperationInfo; import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; import javax.management.ObjectName; -import javax.management.ReflectionException; import javax.management.*; import javax.management.remote.*; @@ -52,39 +42,42 @@ public class DcmdMBeanDoubleInvocationTest { private static String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME = "com.sun.management:type=DiagnosticCommand"; - public static void main(String[] args) { - MBeanServerConnection mbs = null; - try { - JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:8125/jmxrmi"); - JMXConnector connector = JMXConnectorFactory.connect(url); - mbs = connector.getMBeanServerConnection(); - } catch(Throwable t) { - t.printStackTrace(); - } - ObjectName name; + public static void main(String[] args) throws Exception { + System.out.println("--->JRCMD MBean Test: invocation on \"help VM.version\" ..."); + + ObjectName name = new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME); + String[] helpArgs = {"-all", "\n", "VM.version"}; + Object[] dcmdArgs = {helpArgs}; + String[] signature = {String[].class.getName()}; + + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + JMXServiceURL url = new JMXServiceURL("rmi", null, 0); + JMXConnectorServer cs = null; + JMXConnector cc = null; try { - name = new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME); - MBeanInfo info = mbs.getMBeanInfo(name); - String[] helpArgs = {"-all", "\n", "VM.version"}; - Object[] dcmdArgs = {helpArgs}; - String[] signature = {String[].class.getName()}; - String result = (String) mbs.invoke(name, "help", dcmdArgs, signature); + cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); + cs.start(); + JMXServiceURL addr = cs.getAddress(); + cc = JMXConnectorFactory.connect(addr); + MBeanServerConnection mbsc = cc.getMBeanServerConnection(); + + String result = (String) mbsc.invoke(name, "help", dcmdArgs, signature); System.out.println(result); - } catch (RuntimeMBeanException ex) { + + throw new Error("Test failed: Double commands have not been detected"); + } catch (RuntimeMBeanException ex) { if (ex.getCause() instanceof IllegalArgumentException) { - System.out.println("Test passed"); - return; + System.out.println("JTest passed: Double commands have been detected"); } else { ex.printStackTrace(); - throw new RuntimeException("TEST FAILED"); + throw new Error("TEST FAILED: got unknown exception "+ex); + } + } finally { + try { + cc.close(); + cs.stop(); + } catch (Exception e) { } - } catch (InstanceNotFoundException | IntrospectionException - | ReflectionException | MalformedObjectNameException - | MBeanException|IOException ex) { - ex.printStackTrace(); - throw new RuntimeException("TEST FAILED"); } - System.out.println("Double commands have not been detected"); - throw new RuntimeException("TEST FAILED"); } } diff --git a/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanInvocationTest.java b/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanInvocationTest.java index 02132c37e5dc03eb2caa67760d81f884f30968ab..343ae017948034f49461a1442c86340509024606 100644 --- a/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanInvocationTest.java +++ b/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanInvocationTest.java @@ -25,25 +25,15 @@ * @test * @bug 7150256 * @summary Basic Test for the DiagnosticCommandMBean - * @author Frederic Parain + * @author Frederic Parain, Shanliang JIANG * - * @run main/othervm -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=8129 DcmdMBeanInvocationTest + * @run main/othervm DcmdMBeanInvocationTest */ -import java.io.IOException; import java.lang.management.ManagementFactory; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.management.Descriptor; -import javax.management.InstanceNotFoundException; -import javax.management.IntrospectionException; -import javax.management.MBeanInfo; -import javax.management.MBeanOperationInfo; import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; import javax.management.ObjectName; -import javax.management.ReflectionException; import javax.management.*; import javax.management.remote.*; @@ -52,30 +42,35 @@ public class DcmdMBeanInvocationTest { private static String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME = "com.sun.management:type=DiagnosticCommand"; - public static void main(String[] args) { - MBeanServerConnection mbs = null; - try { - JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:8129/jmxrmi"); - JMXConnector connector = JMXConnectorFactory.connect(url); - mbs = connector.getMBeanServerConnection(); - } catch(Throwable t) { - t.printStackTrace(); - } - ObjectName name; + public static void main(String[] args) throws Exception { + System.out.println("--->JRCMD MBean Test: invocation on \"help -all\" ..."); + + ObjectName name = new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME); + String[] helpArgs = {"-all"}; + Object[] dcmdArgs = {helpArgs}; + String[] signature = {String[].class.getName()}; + + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + JMXServiceURL url = new JMXServiceURL("rmi", null, 0); + JMXConnectorServer cs = null; + JMXConnector cc = null; try { - name = new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME); - MBeanInfo info = mbs.getMBeanInfo(name); - String[] helpArgs = {"-all"}; - Object[] dcmdArgs = {helpArgs}; - String[] signature = {String[].class.getName()}; - String result = (String) mbs.invoke(name, "help", dcmdArgs, signature); + cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); + cs.start(); + JMXServiceURL addr = cs.getAddress(); + cc = JMXConnectorFactory.connect(addr); + MBeanServerConnection mbsc = cc.getMBeanServerConnection(); + + String result = (String) mbsc.invoke(name, "help", dcmdArgs, signature); System.out.println(result); - } catch (InstanceNotFoundException | IntrospectionException - | ReflectionException | MalformedObjectNameException - | MBeanException|IOException ex) { - ex.printStackTrace(); - throw new RuntimeException("TEST FAILED"); + } finally { + try { + cc.close(); + cs.stop(); + } catch (Exception e) { + } } + System.out.println("Test passed"); } } diff --git a/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTest.java b/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTest.java index 10ce4240402f113b8078166920d8221a7ad6385a..9072b2c135935bbccfc424281f4ec82d23baf7eb 100644 --- a/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTest.java +++ b/test/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTest.java @@ -25,25 +25,18 @@ * @test * @bug 7150256 * @summary Basic Test for the DiagnosticCommandMBean - * @author Frederic Parain + * @author Frederic Parain, Shanliang JIANG * - * @run main/othervm -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=8127 DcmdMBeanTest + * @run main/othervm DcmdMBeanTest */ -import java.io.IOException; import java.lang.management.ManagementFactory; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.management.Descriptor; -import javax.management.InstanceNotFoundException; -import javax.management.IntrospectionException; import javax.management.MBeanInfo; import javax.management.MBeanOperationInfo; import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; import javax.management.ObjectName; -import javax.management.ReflectionException; import javax.management.*; import javax.management.remote.*; @@ -52,34 +45,42 @@ public class DcmdMBeanTest { private static String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME = "com.sun.management:type=DiagnosticCommand"; - public static void main(String[] args) { - MBeanServerConnection mbs = null; - try { - JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:8127/jmxrmi"); - JMXConnector connector = JMXConnectorFactory.connect(url); - mbs = connector.getMBeanServerConnection(); - } catch(Throwable t) { - t.printStackTrace(); - } - ObjectName name; + public static void main(String[] args) throws Exception { + System.out.println("--->JRCMD MBean Test: invocation on \"operation info\"..."); + + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + JMXServiceURL url = new JMXServiceURL("rmi", null, 0); + JMXConnectorServer cs = null; + JMXConnector cc = null; try { - name = new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME); - MBeanInfo info = mbs.getMBeanInfo(name); + cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); + cs.start(); + JMXServiceURL addr = cs.getAddress(); + cc = JMXConnectorFactory.connect(addr); + MBeanServerConnection mbsc = cc.getMBeanServerConnection(); + ObjectName name = new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME); + MBeanInfo info = mbsc.getMBeanInfo(name); + // the test should check that the MBean doesn't have any // Attribute, notification or constructor. Current version only // check operations - System.out.println("Class Name:"+info.getClassName()); - System.out.println("Description:"+info.getDescription()); + System.out.println("Class Name:" + info.getClassName()); + System.out.println("Description:" + info.getDescription()); MBeanOperationInfo[] opInfo = info.getOperations(); System.out.println("Operations:"); - for(int i=0; i MEM_LEAK_THRESHOLD) { + System.err.println("FAIL: Virtual memory usage increased by " + vMemDelta + "Kb " + + "(greater than " + MEM_LEAK_THRESHOLD + "Kb)"); + System.exit(1); + } + System.err.println("PASS: Virtual memory usage increased by " + vMemDelta + "Kb " + + "(not greater than " + MEM_LEAK_THRESHOLD + "Kb)"); + } System.exit(0); } + + /** + * Return size of virtual memory allocated to the process in Kb. + * Linux specific. On other platforms and in case of any errors return 0. + */ + private static long getVMemSize() { + + // Refer to the Linux proc(5) man page for details about /proc/self/stat file + // + // In short, this file contains status information about the current process + // written in one line. The fields are separated with spaces. + // The 23rd field is defined as 'vsize %lu Virtual memory size in bytes' + + try (FileReader fileReader = new FileReader("/proc/self/stat"); + BufferedReader bufferedReader = new BufferedReader(fileReader)) { + String line = bufferedReader.readLine(); + return Long.parseLong(line.split(" ")[22]) / 1024; + } catch (Exception ex) {} + return 0; + } } diff --git a/test/java/lang/instrument/RetransformBigClass.sh b/test/java/lang/instrument/RetransformBigClass.sh index acaa5ae0d0cfee355228854f5707a5c3cba889c1..dddde89c7853120586c670a9a6c5ace482fa80f4 100644 --- a/test/java/lang/instrument/RetransformBigClass.sh +++ b/test/java/lang/instrument/RetransformBigClass.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2013 Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ # # @test -# @bug 7122253 +# @bug 7122253 8016838 # @summary Retransform a big class. # @author Daniel D. Daugherty # diff --git a/test/java/lang/instrument/RetransformBigClassApp.java b/test/java/lang/instrument/RetransformBigClassApp.java index 37a40e97bd0dc8e9770438d47d6e07bd24894473..3f777bbb20ea7cd1f3c27b7a0ad3bb69935fa8c0 100644 --- a/test/java/lang/instrument/RetransformBigClassApp.java +++ b/test/java/lang/instrument/RetransformBigClassApp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,12 +21,21 @@ * questions. */ +import java.io.*; + public class RetransformBigClassApp { + /** + * Memory leak is assumed, if application consumes more than specified amount of memory during its execution. + * The number is given in Kb. + */ + private static final long MEM_LEAK_THRESHOLD = 32 * 1024; // 32Mb + public static void main(String[] args) throws Exception { System.out.println("Creating instance of " + RetransformBigClassAgent.clz); RetransformBigClassAgent.clz.newInstance(); + long vMemBefore = getVMemSize(); int count = 0; while (!RetransformBigClassAgent.doneRetransforming) { System.out.println("App loop count: " + ++count); @@ -37,6 +46,39 @@ public class RetransformBigClassApp { } System.out.println("App looped " + count + " times."); + long vMemAfter = getVMemSize(); + if (vMemBefore == 0 || vMemAfter == 0) { + System.err.println("WARNING: Cannot perform memory leak detection on this OS"); + } else { + long vMemDelta = vMemAfter - vMemBefore; + if (vMemDelta > MEM_LEAK_THRESHOLD) { + System.err.println("FAIL: Virtual memory usage increased by " + vMemDelta + "Kb " + + "(greater than " + MEM_LEAK_THRESHOLD + "Kb)"); + System.exit(1); + } + System.err.println("PASS: Virtual memory usage increased by " + vMemDelta + "Kb " + + "(not greater than " + MEM_LEAK_THRESHOLD + "Kb)"); + } System.exit(0); } + + /** + * Return size of virtual memory allocated to the process in Kb. + * Linux specific. On other platforms and in case of any errors return 0. + */ + private static long getVMemSize() { + + // Refer to the Linux proc(5) man page for details about /proc/self/stat file + // + // In short, this file contains status information about the current process + // written in one line. The fields are separated with spaces. + // The 23rd field is defined as 'vsize %lu Virtual memory size in bytes' + + try (FileReader fileReader = new FileReader("/proc/self/stat"); + BufferedReader bufferedReader = new BufferedReader(fileReader)) { + String line = bufferedReader.readLine(); + return Long.parseLong(line.split(" ")[22]) / 1024; + } catch (Exception ex) {} + return 0; + } } diff --git a/test/java/security/cert/PKIXRevocationChecker/UnitTest.java b/test/java/security/cert/PKIXRevocationChecker/UnitTest.java index 27fd1629ace8e227c22194201aeb0a2846bcb4e8..5c5f5bcfcf0aded74203bfc192950402e11c1936 100644 --- a/test/java/security/cert/PKIXRevocationChecker/UnitTest.java +++ b/test/java/security/cert/PKIXRevocationChecker/UnitTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /** * @test - * @bug 6854712 7171570 + * @bug 6854712 7171570 8010748 * @summary Basic unit test for PKIXRevocationChecker */ @@ -32,19 +32,9 @@ import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URI; -import java.security.cert.CertificateFactory; -import java.security.cert.CertPathBuilder; -import java.security.cert.CertPathChecker; -import java.security.cert.CertPathValidator; -import java.security.cert.Extension; -import java.security.cert.PKIXRevocationChecker; +import java.security.cert.*; import java.security.cert.PKIXRevocationChecker.Option; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; public class UnitTest { @@ -56,22 +46,23 @@ public class UnitTest { System.out.println("Testing that get methods return null or " + "empty lists/sets/maps"); - requireNull(prc.getOCSPResponder(), "getOCSPResponder()"); - requireNull(prc.getOCSPResponderCert(), "getOCSPResponderCert()"); - requireEmpty(prc.getOCSPExtensions(), "getOCSPExtensions()"); - requireEmpty(prc.getOCSPResponses(), "getOCSPResponses()"); + requireNull(prc.getOcspResponder(), "getOcspResponder()"); + requireNull(prc.getOcspResponderCert(), "getOcspResponderCert()"); + requireEmpty(prc.getOcspExtensions(), "getOcspExtensions()"); + requireEmpty(prc.getOcspResponses(), "getOcspResponses()"); requireEmpty(prc.getOptions(), "getOptions()"); + requireEmpty(prc.getSoftFailExceptions(), "getSoftFailExceptions()"); System.out.println("Testing that get methods return same parameters " + "that are passed to set methods"); URI uri = new URI("http://localhost"); - prc.setOCSPResponder(uri); - requireEquals(uri, prc.getOCSPResponder(), "getOCSPResponder()"); + prc.setOcspResponder(uri); + requireEquals(uri, prc.getOcspResponder(), "getOcspResponder()"); X509Certificate cert = getCert(); - prc.setOCSPResponderCert(cert); - requireEquals(cert, prc.getOCSPResponderCert(), - "getOCSPResponderCert()"); + prc.setOcspResponderCert(cert); + requireEquals(cert, prc.getOcspResponderCert(), + "getOcspResponderCert()"); List exts = new ArrayList<>(); for (String oid : cert.getNonCriticalExtensionOIDs()) { @@ -79,8 +70,8 @@ public class UnitTest { exts.add(new ExtensionImpl(oid, cert.getExtensionValue(oid), false)); } - prc.setOCSPExtensions(exts); - requireEquals(exts, prc.getOCSPExtensions(), "getOCSPExtensions()"); + prc.setOcspExtensions(exts); + requireEquals(exts, prc.getOcspExtensions(), "getOcspExtensions()"); Set

                      Attribute views

                      Description

                      Attribute viewsDescription
                      {@link java.nio.file.attribute.AttributeView}Can read or update non-opaque values associated with objects in a file system
                        {@link java.nio.file.attribute.FileAttributeView}Can read or update POSIX defined file attributes
                            {@link java.nio.file.attribute.DosFileAttributeView}  Can read or update FAT file attributes
                          {@link java.nio.file.attribute.FileOwnerAttributeView}  
                          {@link java.nio.file.attribute.FileOwnerAttributeView}  Can read or update the owner of a file
                           {@link java.nio.file.attribute.AclFileAttributeView}  Can read or update Access Control Lists
                      Hijrah-umalquraislamic-umalquraca-islamic-cv-umalquraca-islamic-umalquraIslamic - Umm Al-Qura calendar of Saudi Arabia