Merge "Clarify updateProcessState() semantics"
diff --git a/EXPECTED_UPSTREAM b/EXPECTED_UPSTREAM
index d05335d..61525e9 100644
--- a/EXPECTED_UPSTREAM
+++ b/EXPECTED_UPSTREAM
@@ -238,7 +238,24 @@
ojluni/src/main/java/java/lang/annotation/RetentionPolicy.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/annotation/RetentionPolicy.java
ojluni/src/main/java/java/lang/annotation/Target.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/annotation/Target.java
ojluni/src/main/java/java/lang/annotation/package-info.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/annotation/package-info.java
+ojluni/src/main/java/java/lang/constant/AsTypeMethodHandleDesc.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/AsTypeMethodHandleDesc.java
+ojluni/src/main/java/java/lang/constant/ClassDesc.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/ClassDesc.java
+ojluni/src/main/java/java/lang/constant/Constable.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/Constable.java
+ojluni/src/main/java/java/lang/constant/ConstantDesc.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/ConstantDesc.java
+ojluni/src/main/java/java/lang/constant/ConstantDescs.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/ConstantDescs.java
+ojluni/src/main/java/java/lang/constant/ConstantUtils.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/ConstantUtils.java
+ojluni/src/main/java/java/lang/constant/DirectMethodHandleDesc.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/DirectMethodHandleDesc.java
+ojluni/src/main/java/java/lang/constant/DirectMethodHandleDescImpl.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/DirectMethodHandleDescImpl.java
+ojluni/src/main/java/java/lang/constant/DynamicCallSiteDesc.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/DynamicCallSiteDesc.java
+ojluni/src/main/java/java/lang/constant/DynamicConstantDesc.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java
+ojluni/src/main/java/java/lang/constant/MethodHandleDesc.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java
+ojluni/src/main/java/java/lang/constant/MethodTypeDesc.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java
+ojluni/src/main/java/java/lang/constant/MethodTypeDescImpl.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java
+ojluni/src/main/java/java/lang/constant/PrimitiveClassDescImpl.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/PrimitiveClassDescImpl.java
+ojluni/src/main/java/java/lang/constant/ReferenceClassDescImpl.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/ReferenceClassDescImpl.java
+ojluni/src/main/java/java/lang/constant/package-info.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/constant/package-info.java
ojluni/src/main/java/java/lang/invoke/CallSite.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/lang/invoke/CallSite.java
+ojluni/src/main/java/java/lang/invoke/ConstantBootstraps.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java
ojluni/src/main/java/java/lang/invoke/ConstantCallSite.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/lang/invoke/ConstantCallSite.java
ojluni/src/main/java/java/lang/invoke/LambdaConversionException.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/lang/invoke/LambdaConversionException.java
ojluni/src/main/java/java/lang/invoke/MethodHandle.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/lang/invoke/MethodHandle.java
@@ -251,6 +268,7 @@
ojluni/src/main/java/java/lang/invoke/MethodTypeForm.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java
ojluni/src/main/java/java/lang/invoke/MutableCallSite.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/lang/invoke/MutableCallSite.java
ojluni/src/main/java/java/lang/invoke/Stable.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/lang/invoke/Stable.java
+ojluni/src/main/java/java/lang/invoke/TypeDescriptor.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/invoke/TypeDescriptor.java
# java.lang.invoke.Transformers isn't in the upstream OpenJDK
ojluni/src/main/java/java/lang/invoke/VarHandle.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/lang/invoke/VarHandle.java
ojluni/src/main/java/java/lang/invoke/VolatileCallSite.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/lang/invoke/VolatileCallSite.java
@@ -282,6 +300,7 @@
ojluni/src/main/java/java/lang/reflect/Parameter.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/lang/reflect/Parameter.java
ojluni/src/main/java/java/lang/reflect/ParameterizedType.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/lang/reflect/ParameterizedType.java
ojluni/src/main/java/java/lang/reflect/Proxy.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/lang/reflect/Proxy.java
+ojluni/src/main/java/java/lang/reflect/RecordComponent.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/lang/reflect/RecordComponent.java
ojluni/src/main/java/java/lang/reflect/ReflectPermission.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/lang/reflect/ReflectPermission.java
ojluni/src/main/java/java/lang/reflect/Type.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/lang/reflect/Type.java
ojluni/src/main/java/java/lang/reflect/TypeVariable.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/lang/reflect/TypeVariable.java
@@ -418,7 +437,7 @@
ojluni/src/main/java/java/nio/channels/spi/AbstractSelector.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/nio/channels/spi/AbstractSelector.java
ojluni/src/main/java/java/nio/channels/spi/AsynchronousChannelProvider.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java
ojluni/src/main/java/java/nio/channels/spi/SelectorProvider.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java
-ojluni/src/main/java/java/nio/charset/Charset-X-Coder.java.template,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/nio/charset/Charset-X-Coder.java.template
+ojluni/src/main/java/java/nio/charset/Charset-X-Coder.java.template,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/nio/charset/Charset-X-Coder.java.template
ojluni/src/main/java/java/nio/charset/Charset.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/nio/charset/Charset.java
ojluni/src/main/java/java/nio/charset/CoderMalfunctionError.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/nio/charset/CoderMalfunctionError.java
ojluni/src/main/java/java/nio/charset/CoderResult.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/nio/charset/CoderResult.java
@@ -426,7 +445,7 @@
ojluni/src/main/java/java/nio/charset/MalformedInputException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/nio/charset/MalformedInputException.java
ojluni/src/main/java/java/nio/charset/StandardCharsets.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/nio/charset/StandardCharsets.java
ojluni/src/main/java/java/nio/charset/UnmappableCharacterException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/nio/charset/UnmappableCharacterException.java
-ojluni/src/main/java/java/nio/charset/exceptions,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/nio/charset/exceptions
+ojluni/src/main/java/java/nio/charset/exceptions,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/nio/charset/exceptions
ojluni/src/main/java/java/nio/charset/package-info.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/nio/charset/package-info.java
ojluni/src/main/java/java/nio/charset/spi/CharsetProvider.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/nio/charset/spi/CharsetProvider.java
ojluni/src/main/java/java/nio/file/AccessDeniedException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/nio/file/AccessDeniedException.java
@@ -524,6 +543,7 @@
ojluni/src/main/java/java/security/DigestOutputStream.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/DigestOutputStream.java
ojluni/src/main/java/java/security/DomainCombiner.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/DomainCombiner.java
ojluni/src/main/java/java/security/DomainLoadStoreParameter.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/DomainLoadStoreParameter.java
+ojluni/src/main/java/java/security/DrbgParameters.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/DrbgParameters.java
ojluni/src/main/java/java/security/GeneralSecurityException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/GeneralSecurityException.java
ojluni/src/main/java/java/security/Guard.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/Guard.java
ojluni/src/main/java/java/security/GuardedObject.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/GuardedObject.java
@@ -565,6 +585,7 @@
ojluni/src/main/java/java/security/PublicKey.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/PublicKey.java
ojluni/src/main/java/java/security/SecureClassLoader.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/security/SecureClassLoader.java
ojluni/src/main/java/java/security/SecureRandom.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/security/SecureRandom.java
+ojluni/src/main/java/java/security/SecureRandomParameters.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/SecureRandomParameters.java
ojluni/src/main/java/java/security/SecureRandomSpi.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/security/SecureRandomSpi.java
ojluni/src/main/java/java/security/Security.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/security/Security.java
ojluni/src/main/java/java/security/SecurityPermission.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/SecurityPermission.java
@@ -639,27 +660,28 @@
ojluni/src/main/java/java/security/cert/X509Extension.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/security/cert/X509Extension.java
ojluni/src/main/java/java/security/cert/package-info.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/security/cert/package-info.java
ojluni/src/main/java/java/security/interfaces/DSAKey.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/interfaces/DSAKey.java
-ojluni/src/main/java/java/security/interfaces/DSAKeyPairGenerator.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/interfaces/DSAKeyPairGenerator.java
+ojluni/src/main/java/java/security/interfaces/DSAKeyPairGenerator.java,jdk17u/jdk-17.0.5-ga,src/java.base/share/classes/java/security/interfaces/DSAKeyPairGenerator.java
ojluni/src/main/java/java/security/interfaces/DSAParams.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/interfaces/DSAParams.java
-ojluni/src/main/java/java/security/interfaces/DSAPrivateKey.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/interfaces/DSAPrivateKey.java
-ojluni/src/main/java/java/security/interfaces/DSAPublicKey.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/interfaces/DSAPublicKey.java
+ojluni/src/main/java/java/security/interfaces/DSAPrivateKey.java,jdk17u/jdk-17.0.5-ga,src/java.base/share/classes/java/security/interfaces/DSAPrivateKey.java
+ojluni/src/main/java/java/security/interfaces/DSAPublicKey.java,jdk17u/jdk-17.0.5-ga,src/java.base/share/classes/java/security/interfaces/DSAPublicKey.java
ojluni/src/main/java/java/security/interfaces/ECKey.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/interfaces/ECKey.java
-ojluni/src/main/java/java/security/interfaces/ECPrivateKey.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/interfaces/ECPrivateKey.java
-ojluni/src/main/java/java/security/interfaces/ECPublicKey.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/interfaces/ECPublicKey.java
+ojluni/src/main/java/java/security/interfaces/ECPrivateKey.java,jdk17u/jdk-17.0.5-ga,src/java.base/share/classes/java/security/interfaces/ECPrivateKey.java
+ojluni/src/main/java/java/security/interfaces/ECPublicKey.java,jdk17u/jdk-17.0.5-ga,src/java.base/share/classes/java/security/interfaces/ECPublicKey.java
ojluni/src/main/java/java/security/interfaces/EdECKey.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/interfaces/EdECKey.java
ojluni/src/main/java/java/security/interfaces/EdECPrivateKey.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/interfaces/EdECPrivateKey.java
ojluni/src/main/java/java/security/interfaces/EdECPublicKey.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/interfaces/EdECPublicKey.java
-ojluni/src/main/java/java/security/interfaces/RSAKey.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/security/interfaces/RSAKey.java
-ojluni/src/main/java/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java
-ojluni/src/main/java/java/security/interfaces/RSAPrivateCrtKey.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/interfaces/RSAPrivateCrtKey.java
-ojluni/src/main/java/java/security/interfaces/RSAPrivateKey.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/interfaces/RSAPrivateKey.java
-ojluni/src/main/java/java/security/interfaces/RSAPublicKey.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/interfaces/RSAPublicKey.java
+ojluni/src/main/java/java/security/interfaces/RSAKey.java,jdk17u/jdk-17.0.5-ga,src/java.base/share/classes/java/security/interfaces/RSAKey.java
+ojluni/src/main/java/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java,jdk17u/jdk-17.0.5-ga,src/java.base/share/classes/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java
+ojluni/src/main/java/java/security/interfaces/RSAPrivateCrtKey.java,jdk17u/jdk-17.0.5-ga,src/java.base/share/classes/java/security/interfaces/RSAPrivateCrtKey.java
+ojluni/src/main/java/java/security/interfaces/RSAPrivateKey.java,jdk17u/jdk-17.0.5-ga,src/java.base/share/classes/java/security/interfaces/RSAPrivateKey.java
+ojluni/src/main/java/java/security/interfaces/RSAPublicKey.java,jdk17u/jdk-17.0.5-ga,src/java.base/share/classes/java/security/interfaces/RSAPublicKey.java
ojluni/src/main/java/java/security/interfaces/XECKey.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/interfaces/XECKey.java
ojluni/src/main/java/java/security/interfaces/XECPrivateKey.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/interfaces/XECPrivateKey.java
ojluni/src/main/java/java/security/interfaces/XECPublicKey.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/interfaces/XECPublicKey.java
-ojluni/src/main/java/java/security/interfaces/package-info.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/security/interfaces/package-info.java
+ojluni/src/main/java/java/security/interfaces/package-info.java,jdk17u/jdk-17.0.5-ga,src/java.base/share/classes/java/security/interfaces/package-info.java
ojluni/src/main/java/java/security/package-info.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/security/package-info.java
ojluni/src/main/java/java/security/spec/AlgorithmParameterSpec.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/spec/AlgorithmParameterSpec.java
+ojluni/src/main/java/java/security/spec/DSAGenParameterSpec.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/spec/DSAGenParameterSpec.java
ojluni/src/main/java/java/security/spec/DSAParameterSpec.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/spec/DSAParameterSpec.java
ojluni/src/main/java/java/security/spec/DSAPrivateKeySpec.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/spec/DSAPrivateKeySpec.java
ojluni/src/main/java/java/security/spec/DSAPublicKeySpec.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/spec/DSAPublicKeySpec.java
@@ -671,6 +693,7 @@
ojluni/src/main/java/java/security/spec/ECPoint.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/spec/ECPoint.java
ojluni/src/main/java/java/security/spec/ECPrivateKeySpec.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/spec/ECPrivateKeySpec.java
ojluni/src/main/java/java/security/spec/ECPublicKeySpec.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/security/spec/ECPublicKeySpec.java
+ojluni/src/main/java/java/security/spec/EdDSAParameterSpec.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/spec/EdDSAParameterSpec.java
ojluni/src/main/java/java/security/spec/EdECPoint.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/spec/EdECPoint.java
ojluni/src/main/java/java/security/spec/EdECPrivateKeySpec.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/spec/EdECPrivateKeySpec.java
ojluni/src/main/java/java/security/spec/EdECPublicKeySpec.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/security/spec/EdECPublicKeySpec.java
@@ -860,79 +883,79 @@
ojluni/src/main/java/java/time/zone/ZoneRulesException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/time/zone/ZoneRulesException.java
ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/time/zone/ZoneRulesProvider.java
ojluni/src/main/java/java/time/zone/package-info.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/time/zone/package-info.java
-ojluni/src/main/java/java/util/AbstractCollection.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/AbstractCollection.java
-ojluni/src/main/java/java/util/AbstractList.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/AbstractList.java
-ojluni/src/main/java/java/util/AbstractMap.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/AbstractMap.java
+ojluni/src/main/java/java/util/AbstractCollection.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/AbstractCollection.java
+ojluni/src/main/java/java/util/AbstractList.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/AbstractList.java
+ojluni/src/main/java/java/util/AbstractMap.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/AbstractMap.java
ojluni/src/main/java/java/util/AbstractQueue.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/AbstractQueue.java
ojluni/src/main/java/java/util/AbstractSequentialList.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/AbstractSequentialList.java
ojluni/src/main/java/java/util/AbstractSet.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/AbstractSet.java
-ojluni/src/main/java/java/util/ArrayDeque.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/ArrayDeque.java
-ojluni/src/main/java/java/util/ArrayList.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/ArrayList.java
-ojluni/src/main/java/java/util/ArrayPrefixHelpers.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/ArrayPrefixHelpers.java
+ojluni/src/main/java/java/util/ArrayDeque.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/ArrayDeque.java
+ojluni/src/main/java/java/util/ArrayList.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/ArrayList.java
+ojluni/src/main/java/java/util/ArrayPrefixHelpers.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/ArrayPrefixHelpers.java
ojluni/src/main/java/java/util/Arrays.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Arrays.java
-ojluni/src/main/java/java/util/ArraysParallelSortHelpers.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/ArraysParallelSortHelpers.java
-ojluni/src/main/java/java/util/Base64.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Base64.java
-ojluni/src/main/java/java/util/BitSet.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/BitSet.java
-ojluni/src/main/java/java/util/Calendar.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Calendar.java
-ojluni/src/main/java/java/util/Collection.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Collection.java
+ojluni/src/main/java/java/util/ArraysParallelSortHelpers.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/ArraysParallelSortHelpers.java
+ojluni/src/main/java/java/util/Base64.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Base64.java
+ojluni/src/main/java/java/util/BitSet.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/BitSet.java
+ojluni/src/main/java/java/util/Calendar.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Calendar.java
+ojluni/src/main/java/java/util/Collection.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Collection.java
ojluni/src/main/java/java/util/Collections.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Collections.java
ojluni/src/main/java/java/util/ComparableTimSort.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/ComparableTimSort.java
-ojluni/src/main/java/java/util/Comparator.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Comparator.java
-ojluni/src/main/java/java/util/Comparators.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Comparators.java
-ojluni/src/main/java/java/util/ConcurrentModificationException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/ConcurrentModificationException.java
-ojluni/src/main/java/java/util/Currency.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Currency.java
+ojluni/src/main/java/java/util/Comparator.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Comparator.java
+ojluni/src/main/java/java/util/Comparators.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Comparators.java
+ojluni/src/main/java/java/util/ConcurrentModificationException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/ConcurrentModificationException.java
+ojluni/src/main/java/java/util/Currency.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Currency.java
ojluni/src/main/java/java/util/Date.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Date.java
ojluni/src/main/java/java/util/Deque.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Deque.java
-ojluni/src/main/java/java/util/Dictionary.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Dictionary.java
+ojluni/src/main/java/java/util/Dictionary.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Dictionary.java
ojluni/src/main/java/java/util/DoubleSummaryStatistics.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/DoubleSummaryStatistics.java
-ojluni/src/main/java/java/util/DualPivotQuicksort.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/DualPivotQuicksort.java
-ojluni/src/main/java/java/util/DuplicateFormatFlagsException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/DuplicateFormatFlagsException.java
-ojluni/src/main/java/java/util/EmptyStackException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/EmptyStackException.java
-ojluni/src/main/java/java/util/EnumMap.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/EnumMap.java
-ojluni/src/main/java/java/util/EnumSet.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/EnumSet.java
-ojluni/src/main/java/java/util/Enumeration.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Enumeration.java
+ojluni/src/main/java/java/util/DualPivotQuicksort.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/DualPivotQuicksort.java
+ojluni/src/main/java/java/util/DuplicateFormatFlagsException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/DuplicateFormatFlagsException.java
+ojluni/src/main/java/java/util/EmptyStackException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/EmptyStackException.java
+ojluni/src/main/java/java/util/EnumMap.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/EnumMap.java
+ojluni/src/main/java/java/util/EnumSet.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/EnumSet.java
+ojluni/src/main/java/java/util/Enumeration.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Enumeration.java
ojluni/src/main/java/java/util/EventListener.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/EventListener.java
ojluni/src/main/java/java/util/EventListenerProxy.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/EventListenerProxy.java
-ojluni/src/main/java/java/util/EventObject.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/EventObject.java
-ojluni/src/main/java/java/util/FormatFlagsConversionMismatchException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/FormatFlagsConversionMismatchException.java
+ojluni/src/main/java/java/util/EventObject.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/EventObject.java
+ojluni/src/main/java/java/util/FormatFlagsConversionMismatchException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/FormatFlagsConversionMismatchException.java
ojluni/src/main/java/java/util/Formattable.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Formattable.java
ojluni/src/main/java/java/util/FormattableFlags.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/FormattableFlags.java
ojluni/src/main/java/java/util/Formatter.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Formatter.java
-ojluni/src/main/java/java/util/FormatterClosedException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/FormatterClosedException.java
+ojluni/src/main/java/java/util/FormatterClosedException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/FormatterClosedException.java
ojluni/src/main/java/java/util/GregorianCalendar.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/GregorianCalendar.java
ojluni/src/main/java/java/util/HashMap.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/HashMap.java
ojluni/src/main/java/java/util/HashSet.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/HashSet.java
ojluni/src/main/java/java/util/Hashtable.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Hashtable.java
ojluni/src/main/java/java/util/HexFormat.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/HexFormat.java
-ojluni/src/main/java/java/util/IdentityHashMap.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/IdentityHashMap.java
-ojluni/src/main/java/java/util/IllegalFormatCodePointException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/IllegalFormatCodePointException.java
-ojluni/src/main/java/java/util/IllegalFormatConversionException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/IllegalFormatConversionException.java
-ojluni/src/main/java/java/util/IllegalFormatException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/IllegalFormatException.java
-ojluni/src/main/java/java/util/IllegalFormatFlagsException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/IllegalFormatFlagsException.java
-ojluni/src/main/java/java/util/IllegalFormatPrecisionException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/IllegalFormatPrecisionException.java
-ojluni/src/main/java/java/util/IllegalFormatWidthException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/IllegalFormatWidthException.java
-ojluni/src/main/java/java/util/IllformedLocaleException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/IllformedLocaleException.java
-ojluni/src/main/java/java/util/ImmutableCollections.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/ImmutableCollections.java
-ojluni/src/main/java/java/util/InputMismatchException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/InputMismatchException.java
+ojluni/src/main/java/java/util/IdentityHashMap.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/IdentityHashMap.java
+ojluni/src/main/java/java/util/IllegalFormatCodePointException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/IllegalFormatCodePointException.java
+ojluni/src/main/java/java/util/IllegalFormatConversionException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/IllegalFormatConversionException.java
+ojluni/src/main/java/java/util/IllegalFormatException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/IllegalFormatException.java
+ojluni/src/main/java/java/util/IllegalFormatFlagsException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/IllegalFormatFlagsException.java
+ojluni/src/main/java/java/util/IllegalFormatPrecisionException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/IllegalFormatPrecisionException.java
+ojluni/src/main/java/java/util/IllegalFormatWidthException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/IllegalFormatWidthException.java
+ojluni/src/main/java/java/util/IllformedLocaleException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/IllformedLocaleException.java
+ojluni/src/main/java/java/util/ImmutableCollections.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/ImmutableCollections.java
+ojluni/src/main/java/java/util/InputMismatchException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/InputMismatchException.java
ojluni/src/main/java/java/util/IntSummaryStatistics.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/IntSummaryStatistics.java
-ojluni/src/main/java/java/util/InvalidPropertiesFormatException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/InvalidPropertiesFormatException.java
+ojluni/src/main/java/java/util/InvalidPropertiesFormatException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/InvalidPropertiesFormatException.java
ojluni/src/main/java/java/util/Iterator.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Iterator.java
ojluni/src/main/java/java/util/JapaneseImperialCalendar.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/JapaneseImperialCalendar.java
-ojluni/src/main/java/java/util/JumboEnumSet.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/JumboEnumSet.java
-ojluni/src/main/java/java/util/KeyValueHolder.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/KeyValueHolder.java
+ojluni/src/main/java/java/util/JumboEnumSet.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/JumboEnumSet.java
+ojluni/src/main/java/java/util/KeyValueHolder.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/KeyValueHolder.java
ojluni/src/main/java/java/util/LinkedHashMap.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/LinkedHashMap.java
-ojluni/src/main/java/java/util/LinkedHashSet.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/LinkedHashSet.java
-ojluni/src/main/java/java/util/LinkedList.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/LinkedList.java
-ojluni/src/main/java/java/util/List.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/List.java
+ojluni/src/main/java/java/util/LinkedHashSet.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/LinkedHashSet.java
+ojluni/src/main/java/java/util/LinkedList.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/LinkedList.java
+ojluni/src/main/java/java/util/List.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/List.java
ojluni/src/main/java/java/util/ListIterator.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/ListIterator.java
ojluni/src/main/java/java/util/ListResourceBundle.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/ListResourceBundle.java
ojluni/src/main/java/java/util/Locale.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Locale.java
ojluni/src/main/java/java/util/LocaleISOData.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/LocaleISOData.java
ojluni/src/main/java/java/util/LongSummaryStatistics.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/LongSummaryStatistics.java
-ojluni/src/main/java/java/util/Map.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Map.java
-ojluni/src/main/java/java/util/MissingFormatArgumentException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/MissingFormatArgumentException.java
-ojluni/src/main/java/java/util/MissingFormatWidthException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/MissingFormatWidthException.java
-ojluni/src/main/java/java/util/MissingResourceException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/MissingResourceException.java
+ojluni/src/main/java/java/util/Map.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Map.java
+ojluni/src/main/java/java/util/MissingFormatArgumentException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/MissingFormatArgumentException.java
+ojluni/src/main/java/java/util/MissingFormatWidthException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/MissingFormatWidthException.java
+ojluni/src/main/java/java/util/MissingResourceException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/MissingResourceException.java
ojluni/src/main/java/java/util/NavigableMap.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/NavigableMap.java
ojluni/src/main/java/java/util/NavigableSet.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/NavigableSet.java
ojluni/src/main/java/java/util/NoSuchElementException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/NoSuchElementException.java
@@ -943,42 +966,42 @@
ojluni/src/main/java/java/util/OptionalDouble.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/OptionalDouble.java
ojluni/src/main/java/java/util/OptionalInt.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/OptionalInt.java
ojluni/src/main/java/java/util/OptionalLong.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/OptionalLong.java
-ojluni/src/main/java/java/util/PrimitiveIterator.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/PrimitiveIterator.java
-ojluni/src/main/java/java/util/PriorityQueue.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/PriorityQueue.java
+ojluni/src/main/java/java/util/PrimitiveIterator.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/PrimitiveIterator.java
+ojluni/src/main/java/java/util/PriorityQueue.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/PriorityQueue.java
ojluni/src/main/java/java/util/Properties.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/util/Properties.java
ojluni/src/main/java/java/util/PropertyPermission.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/util/PropertyPermission.java
ojluni/src/main/java/java/util/PropertyResourceBundle.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/util/PropertyResourceBundle.java
ojluni/src/main/java/java/util/Queue.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Queue.java
ojluni/src/main/java/java/util/Random.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Random.java
ojluni/src/main/java/java/util/RandomAccess.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/RandomAccess.java
-ojluni/src/main/java/java/util/RegularEnumSet.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/RegularEnumSet.java
+ojluni/src/main/java/java/util/RegularEnumSet.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/RegularEnumSet.java
ojluni/src/main/java/java/util/ResourceBundle.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/ResourceBundle.java
ojluni/src/main/java/java/util/Scanner.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Scanner.java
-ojluni/src/main/java/java/util/ServiceConfigurationError.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/ServiceConfigurationError.java
+ojluni/src/main/java/java/util/ServiceConfigurationError.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/ServiceConfigurationError.java
ojluni/src/main/java/java/util/ServiceLoader.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/java/util/ServiceLoader.java
-ojluni/src/main/java/java/util/Set.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Set.java
+ojluni/src/main/java/java/util/Set.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Set.java
ojluni/src/main/java/java/util/SimpleTimeZone.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/SimpleTimeZone.java
ojluni/src/main/java/java/util/SortedMap.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/SortedMap.java
ojluni/src/main/java/java/util/SortedSet.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/SortedSet.java
-ojluni/src/main/java/java/util/Spliterator.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Spliterator.java
-ojluni/src/main/java/java/util/Spliterators.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Spliterators.java
+ojluni/src/main/java/java/util/Spliterator.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Spliterator.java
+ojluni/src/main/java/java/util/Spliterators.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Spliterators.java
ojluni/src/main/java/java/util/SplittableRandom.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/SplittableRandom.java
-ojluni/src/main/java/java/util/Stack.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Stack.java
+ojluni/src/main/java/java/util/Stack.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Stack.java
ojluni/src/main/java/java/util/StringJoiner.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/StringJoiner.java
-ojluni/src/main/java/java/util/StringTokenizer.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/StringTokenizer.java
+ojluni/src/main/java/java/util/StringTokenizer.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/StringTokenizer.java
ojluni/src/main/java/java/util/TimSort.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/TimSort.java
ojluni/src/main/java/java/util/TimeZone.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/TimeZone.java
ojluni/src/main/java/java/util/Timer.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Timer.java
ojluni/src/main/java/java/util/TimerTask.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/TimerTask.java
-ojluni/src/main/java/java/util/TooManyListenersException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/TooManyListenersException.java
+ojluni/src/main/java/java/util/TooManyListenersException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/TooManyListenersException.java
ojluni/src/main/java/java/util/TreeMap.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/TreeMap.java
-ojluni/src/main/java/java/util/TreeSet.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/TreeSet.java
-ojluni/src/main/java/java/util/Tripwire.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Tripwire.java
+ojluni/src/main/java/java/util/TreeSet.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/TreeSet.java
+ojluni/src/main/java/java/util/Tripwire.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Tripwire.java
ojluni/src/main/java/java/util/UUID.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/UUID.java
-ojluni/src/main/java/java/util/UnknownFormatConversionException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/UnknownFormatConversionException.java
-ojluni/src/main/java/java/util/UnknownFormatFlagsException.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/UnknownFormatFlagsException.java
-ojluni/src/main/java/java/util/Vector.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/Vector.java
-ojluni/src/main/java/java/util/WeakHashMap.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/java/util/WeakHashMap.java
+ojluni/src/main/java/java/util/UnknownFormatConversionException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/UnknownFormatConversionException.java
+ojluni/src/main/java/java/util/UnknownFormatFlagsException.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/UnknownFormatFlagsException.java
+ojluni/src/main/java/java/util/Vector.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/Vector.java
+ojluni/src/main/java/java/util/WeakHashMap.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/WeakHashMap.java
ojluni/src/main/java/java/util/XMLUtils.java,jdk7u/jdk7u40-b60,jdk/src/share/classes/java/util/XMLUtils.java
ojluni/src/main/java/java/util/concurrent/AbstractExecutorService.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/concurrent/AbstractExecutorService.java
ojluni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java
@@ -1259,6 +1282,7 @@
ojluni/src/main/java/javax/crypto/interfaces/DHPrivateKey.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/javax/crypto/interfaces/DHPrivateKey.java
ojluni/src/main/java/javax/crypto/interfaces/DHPublicKey.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/javax/crypto/interfaces/DHPublicKey.java
ojluni/src/main/java/javax/crypto/interfaces/PBEKey.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/javax/crypto/interfaces/PBEKey.java
+ojluni/src/main/java/javax/crypto/spec/ChaCha20ParameterSpec.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/javax/crypto/spec/ChaCha20ParameterSpec.java
ojluni/src/main/java/javax/crypto/spec/DESKeySpec.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/javax/crypto/spec/DESKeySpec.java
ojluni/src/main/java/javax/crypto/spec/DESedeKeySpec.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/javax/crypto/spec/DESedeKeySpec.java
ojluni/src/main/java/javax/crypto/spec/DHGenParameterSpec.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/javax/crypto/spec/DHGenParameterSpec.java
@@ -1332,6 +1356,7 @@
ojluni/src/main/java/javax/security/auth/login/package-info.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/javax/security/auth/login/package-info.java
ojluni/src/main/java/javax/security/auth/package-info.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/javax/security/auth/package-info.java
ojluni/src/main/java/javax/security/auth/x500/X500Principal.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/javax/security/auth/x500/X500Principal.java
+ojluni/src/main/java/javax/security/auth/x500/X500PrivateCredential.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/javax/security/auth/x500/X500PrivateCredential.java
ojluni/src/main/java/javax/security/auth/x500/package-info.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/javax/security/auth/x500/package-info.java
ojluni/src/main/java/javax/security/cert/Certificate.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/javax/security/cert/Certificate.java
ojluni/src/main/java/javax/security/cert/CertificateEncodingException.java,jdk8u/jdk8u121-b13,jdk/src/share/classes/javax/security/cert/CertificateEncodingException.java
@@ -1357,7 +1382,7 @@
ojluni/src/main/java/javax/sql/StatementEvent.java,jdk7u/jdk7u40-b60,jdk/src/share/classes/javax/sql/StatementEvent.java
ojluni/src/main/java/javax/sql/StatementEventListener.java,jdk7u/jdk7u40-b60,jdk/src/share/classes/javax/sql/StatementEventListener.java
ojluni/src/main/java/jdk/internal/HotSpotIntrinsicCandidate.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/jdk/internal/HotSpotIntrinsicCandidate.java
-# jdk.internal.ValueBased earlier imports have elected not to bring this across, no technical reason to add it for now (not used by ART).
+ojluni/src/main/java/jdk/internal/ValueBased.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/jdk/internal/ValueBased.java
ojluni/src/main/java/jdk/internal/math/DoubleConsts.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/jdk/internal/math/DoubleConsts.java
ojluni/src/main/java/jdk/internal/math/FDBigInteger.java,jdk11u/jdk-11.0.13-ga,src/java.base/share/classes/jdk/internal/math/FDBigInteger.java
ojluni/src/main/java/jdk/internal/math/FloatConsts.java,jdk17u/jdk-17.0.6-ga,src/java.base/share/classes/jdk/internal/math/FloatConsts.java
@@ -1884,6 +1909,12 @@
ojluni/src/test/java/lang/StringBuilder/EnsureCapacity.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/lang/StringBuilder/EnsureCapacity.java
ojluni/src/test/java/lang/StringBuilder/Insert.java,jdk11u/jdk-11.0.13-ga,test/jdk/java/lang/StringBuilder/Insert.java
ojluni/src/test/java/lang/StringBuilder/Supplementary.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/lang/StringBuilder/Supplementary.java
+ojluni/src/test/java/lang/constant/ConvertTest.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/lang/constant/ConvertTest.java
+ojluni/src/test/java/lang/constant/DynamicConstantDescTest.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/lang/constant/DynamicConstantDescTest.java
+ojluni/src/test/java/lang/constant/NameValidationTest.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/lang/constant/NameValidationTest.java
+ojluni/src/test/java/lang/constant/access_test/pkg1/MethodTypeDescriptorAccessTest.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/lang/constant/access_test/pkg1/MethodTypeDescriptorAccessTest.java
+ojluni/src/test/java/lang/constant/access_test/pkg2/NonPublicClass.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/lang/constant/access_test/pkg2/NonPublicClass.java
+ojluni/src/test/java/lang/constant/access_test/pkg2/PublicClass.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/lang/constant/access_test/pkg2/PublicClass.java
ojluni/src/test/java/lang/invoke/ClassValueTest.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/lang/invoke/ClassValueTest.java
ojluni/src/test/java/lang/invoke/MethodHandlesGeneralTest.java,jdk11u/jdk-11.0.13-ga,test/jdk/java/lang/invoke/MethodHandlesGeneralTest.java
ojluni/src/test/java/lang/invoke/VarHandles/VarHandleBaseByteArrayTest.java,jdk11u/jdk-11.0.13-ga,test/jdk/java/lang/invoke/VarHandles/VarHandleBaseByteArrayTest.java
@@ -1935,6 +1966,8 @@
ojluni/src/test/java/lang/invoke/VarHandles/accessibility/pkg/subpkg/B_extends_A.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/lang/invoke/VarHandles/accessibility/pkg/subpkg/B_extends_A.java
ojluni/src/test/java/lang/invoke/VarHandles/accessibility/pkg/subpkg/C.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/lang/invoke/VarHandles/accessibility/pkg/subpkg/C.java
ojluni/src/test/java/lang/invoke/VarHandles/generate-vh-tests.sh,jdk11u/jdk-11.0.13-ga,test/jdk/java/lang/invoke/VarHandles/generate-vh-tests.sh
+ojluni/src/test/java/lang/reflect/records/CheckEqualityIsBasedOnFields.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/lang/reflect/records/CheckEqualityIsBasedOnFields.java
+ojluni/src/test/java/lang/reflect/records/RecordReflectionTest.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/lang/reflect/records/RecordReflectionTest.java
ojluni/src/test/java/math/BigDecimal/AddTests.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/math/BigDecimal/AddTests.java
ojluni/src/test/java/math/BigDecimal/CompareToTests.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/math/BigDecimal/CompareToTests.java
ojluni/src/test/java/math/BigDecimal/Constructor.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/math/BigDecimal/Constructor.java
@@ -1983,6 +2016,7 @@
ojluni/src/test/java/net/InetSocketAddress/ToString.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/net/InetSocketAddress/ToString.java
ojluni/src/test/java/net/UnixDomainSocketAddress/LengthTest.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/net/UnixDomainSocketAddress/LengthTest.java
ojluni/src/test/java/net/UnixDomainSocketAddress/UnixDomainSocketAddressSerializationTest.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/net/UnixDomainSocketAddress/UnixDomainSocketAddressSerializationTest.java
+ojluni/src/test/java/nio/Buffer/EqualsCompareTest.java,jdk11u/jdk-11.0.13-ga,test/jdk/java/nio/Buffer/EqualsCompareTest.java
ojluni/src/test/java/nio/channels/SelectionKey/AtomicUpdates.java,jdk11u/jdk-11.0.13-ga,test/jdk/java/nio/channels/SelectionKey/AtomicUpdates.java
ojluni/src/test/java/nio/channels/Selector/ByteServer.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/nio/channels/Selector/ByteServer.java
ojluni/src/test/java/nio/channels/Selector/SelectAfterRead.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/nio/channels/Selector/SelectAfterRead.java
@@ -2194,6 +2228,7 @@
ojluni/src/test/java/util/Base64/urlEncode.txt,jdk17u/jdk-17.0.6-ga,test/jdk/java/util/Base64/urlEncode.txt
ojluni/src/test/java/util/Collections/NCopies.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/util/Collections/NCopies.java
ojluni/src/test/java/util/HashSet/Serialization.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/util/HashSet/Serialization.java
+ojluni/src/test/java/util/HexFormat/HexFormatTest.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/util/HexFormat/HexFormatTest.java
ojluni/src/test/java/util/IdentityHashMap/Capacity.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/util/IdentityHashMap/Capacity.java
ojluni/src/test/java/util/IdentityHashMap/DistinctEntrySetElements.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/util/IdentityHashMap/DistinctEntrySetElements.java
ojluni/src/test/java/util/IdentityHashMap/EntrySetIteratorRemoveInvalidatesEntry.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/util/IdentityHashMap/EntrySetIteratorRemoveInvalidatesEntry.java
@@ -2235,6 +2270,6 @@
ojluni/src/test/java/util/zip/TestCRC32C.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/util/zip/TestCRC32C.java
ojluni/src/test/java/util/zip/TestChecksum.java,jdk17u/jdk-17.0.6-ga,test/jdk/java/util/zip/TestChecksum.java
ojluni/src/test/java/util/zip/ZipFile/Zip64SizeTest.java,jdk11u/jdk-11.0.13-ga,test/jdk/java/util/zip/ZipFile/Zip64SizeTest.java
-ojluni/src/tools/make/gensrc/GensrcCharsetCoder.gmk,jdk11u/jdk-11.0.13-ga,make/gensrc/GensrcCharsetCoder.gmk
-ojluni/src/tools/scripts/addNotices.sh,jdk11u/jdk-11.0.13-ga,make/scripts/addNotices.sh
-ojluni/src/tools/scripts/genExceptions.sh,jdk11u/jdk-11.0.13-ga,make/scripts/genExceptions.sh
+ojluni/src/tools/make/gensrc/GensrcCharsetCoder.gmk,jdk17u/jdk-17.0.6-ga,make/modules/java.base/gensrc/GensrcCharsetCoder.gmk
+ojluni/src/tools/scripts/addNotices.sh,jdk17u/jdk-17.0.6-ga,make/scripts/addNotices.sh
+ojluni/src/tools/scripts/genExceptions.sh,jdk17u/jdk-17.0.6-ga,make/scripts/genExceptions.sh
diff --git a/JavaLibrary.bp b/JavaLibrary.bp
index 12f14fd..3b2cb44 100644
--- a/JavaLibrary.bp
+++ b/JavaLibrary.bp
@@ -475,6 +475,7 @@
"//art/build/sdk",
"//build/soong/java/core-libraries",
"//frameworks/base",
+ "//frameworks/base/api",
],
defaults: ["core_lambda_stubs_defaults"],
srcs: [
@@ -494,6 +495,7 @@
"//art/build/sdk",
"//build/soong/java/core-libraries",
"//frameworks/base",
+ "//frameworks/base/api",
],
defaults: ["libcore_java_defaults"],
srcs: [
@@ -658,6 +660,14 @@
visibility: ["//libcore/luni/src/test/java11language"],
}
+// A filegroup that provides access to a source file for a toolchain test that
+// checks Java 17 language features are handled properly by JarJar.
+filegroup {
+ name: "core-java-17-language-features-source",
+ srcs: ["luni/src/main/java/libcore/internal/Java17LanguageFeatures.java"],
+ visibility: ["//libcore/luni/src/test/java17language"],
+}
+
genrule {
name: "core-tests-smali-dex",
srcs: ["luni/src/test/java/**/*.smali"],
@@ -743,6 +753,7 @@
"core-java-9-compatibility-tests",
"core-java-9-language-tests",
"core-java-11-language-tests",
+ "core-java-17-language-tests",
"core-test-rules",
"core-tests-support",
"junit-params",
@@ -854,6 +865,7 @@
name: "known-oj-tags",
visibility: [
"//frameworks/base",
+ "//frameworks/base/api",
],
srcs: [
"known_oj_tags.txt",
@@ -1070,6 +1082,7 @@
"//art/build/sdk",
"//external/icu/android_icu4j",
"//frameworks/base",
+ "//frameworks/base/api",
],
host_supported: true,
srcs: [
diff --git a/TEST_MAPPING b/TEST_MAPPING
index f399594..429054c 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,4 +1,9 @@
{
+ "presubmit": [
+ {
+ "name": "luni-host-tests"
+ }
+ ],
"presubmit-large": [
{
"name": "CtsLibcoreTestCases",
@@ -86,5 +91,16 @@
}
]
}
+ ],
+ "kernel-presubmit": [
+ {
+ "name": "CtsLibcoreTestCases",
+ "options": [
+ {
+ // TODO(b/194105624)
+ "exclude-filter": "libcore.java.net.InetAddressTest#test_isReachable_by_ICMP"
+ }
+ ]
+ }
]
-}
\ No newline at end of file
+}
diff --git a/api/current.txt b/api/current.txt
index 5bc86bd..a61a723 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3041,9 +3041,12 @@
enum_constant public static final java.lang.Character.UnicodeScript ZANABAZAR_SQUARE;
}
- public final class Class<T> implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
+ public final class Class<T> implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type java.lang.invoke.TypeDescriptor.OfField<java.lang.Class<?>> {
+ method @NonNull public Class<?> arrayType();
method @NonNull public <U> Class<? extends U> asSubclass(@NonNull Class<U>);
method @Nullable public T cast(@Nullable Object);
+ method @Nullable public Class<?> componentType();
+ method @NonNull public String descriptorString();
method public boolean desiredAssertionStatus();
method @NonNull public static Class<?> forName(@NonNull String) throws java.lang.ClassNotFoundException;
method @NonNull public static Class<?> forName(@NonNull String, boolean, @Nullable ClassLoader) throws java.lang.ClassNotFoundException;
@@ -3086,6 +3089,7 @@
method @NonNull public String getPackageName();
method @Nullable public Class<?>[] getPermittedSubclasses();
method @Nullable public java.security.ProtectionDomain getProtectionDomain();
+ method @Nullable public java.lang.reflect.RecordComponent[] getRecordComponents();
method @Nullable public java.net.URL getResource(@NonNull String);
method @Nullable public java.io.InputStream getResourceAsStream(@NonNull String);
method @Nullable public Object[] getSigners();
@@ -3103,6 +3107,7 @@
method public boolean isMemberClass();
method public boolean isNestmateOf(@NonNull Class<?>);
method public boolean isPrimitive();
+ method public boolean isRecord();
method public boolean isSealed();
method public boolean isSynthetic();
method @Deprecated @NonNull public T newInstance() throws java.lang.IllegalAccessException, java.lang.InstantiationException;
@@ -3754,6 +3759,13 @@
method public int read(java.nio.CharBuffer) throws java.io.IOException;
}
+ public abstract class Record {
+ ctor protected Record();
+ method public abstract boolean equals(@Nullable Object);
+ method public abstract int hashCode();
+ method @NonNull public abstract String toString();
+ }
+
public class ReflectiveOperationException extends java.lang.Exception {
ctor public ReflectiveOperationException();
ctor public ReflectiveOperationException(String);
@@ -4656,11 +4668,12 @@
field public static final int PUBLIC = 1; // 0x1
}
- public final class MethodType implements java.io.Serializable {
+ public final class MethodType implements java.io.Serializable java.lang.invoke.TypeDescriptor.OfMethod<java.lang.Class<?>,java.lang.invoke.MethodType> {
method public java.lang.invoke.MethodType appendParameterTypes(Class<?>...);
method public java.lang.invoke.MethodType appendParameterTypes(java.util.List<java.lang.Class<?>>);
method public java.lang.invoke.MethodType changeParameterType(int, Class<?>);
method public java.lang.invoke.MethodType changeReturnType(Class<?>);
+ method @NonNull public String descriptorString();
method public java.lang.invoke.MethodType dropParameterTypes(int, int);
method public java.lang.invoke.MethodType erase();
method public static java.lang.invoke.MethodType fromMethodDescriptorString(String, ClassLoader) throws java.lang.IllegalArgumentException, java.lang.TypeNotPresentException;
@@ -4696,6 +4709,29 @@
method public void setTarget(java.lang.invoke.MethodHandle);
}
+ public interface TypeDescriptor {
+ method public String descriptorString();
+ }
+
+ public static interface TypeDescriptor.OfField<F extends java.lang.invoke.TypeDescriptor.OfField<F>> extends java.lang.invoke.TypeDescriptor {
+ method public F arrayType();
+ method public F componentType();
+ method public boolean isArray();
+ method public boolean isPrimitive();
+ }
+
+ public static interface TypeDescriptor.OfMethod<F extends java.lang.invoke.TypeDescriptor.OfField<F>, M extends java.lang.invoke.TypeDescriptor.OfMethod<F, M>> extends java.lang.invoke.TypeDescriptor {
+ method public M changeParameterType(int, F);
+ method public M changeReturnType(F);
+ method public M dropParameterTypes(int, int);
+ method public M insertParameterTypes(int, F...);
+ method public F[] parameterArray();
+ method public int parameterCount();
+ method public java.util.List<F> parameterList();
+ method public F parameterType(int);
+ method public F returnType();
+ }
+
public abstract class VarHandle {
method public final java.lang.invoke.MethodType accessModeType(java.lang.invoke.VarHandle.AccessMode);
method public static void acquireFence();
@@ -5061,6 +5097,18 @@
field protected java.lang.reflect.InvocationHandler h;
}
+ public final class RecordComponent implements java.lang.reflect.AnnotatedElement {
+ method @NonNull public java.lang.reflect.Method getAccessor();
+ method @Nullable public <T extends java.lang.annotation.Annotation> T getAnnotation(@NonNull Class<T>);
+ method @NonNull public java.lang.annotation.Annotation[] getAnnotations();
+ method @NonNull public java.lang.annotation.Annotation[] getDeclaredAnnotations();
+ method @NonNull public Class<?> getDeclaringRecord();
+ method @Nullable public String getGenericSignature();
+ method @NonNull public java.lang.reflect.Type getGenericType();
+ method @NonNull public String getName();
+ method @NonNull public Class<?> getType();
+ }
+
public final class ReflectPermission extends java.security.BasicPermission {
ctor public ReflectPermission(String);
ctor public ReflectPermission(String, String);
@@ -5089,6 +5137,14 @@
}
+package java.lang.runtime {
+
+ public class ObjectMethods {
+ method @NonNull public static Object bootstrap(@NonNull java.lang.invoke.MethodHandles.Lookup, @NonNull String, @NonNull java.lang.invoke.TypeDescriptor, @NonNull Class<?>, @Nullable String, @NonNull java.lang.invoke.MethodHandle...) throws java.lang.Throwable;
+ }
+
+}
+
package java.math {
public class BigDecimal extends java.lang.Number implements java.lang.Comparable<java.math.BigDecimal> {
diff --git a/dalvik/src/main/java/dalvik/system/VMDebug.java b/dalvik/src/main/java/dalvik/system/VMDebug.java
index eb37ca9..1496adc 100644
--- a/dalvik/src/main/java/dalvik/system/VMDebug.java
+++ b/dalvik/src/main/java/dalvik/system/VMDebug.java
@@ -569,24 +569,6 @@
@SystemApi(client = MODULE_LIBRARIES)
public static native long[] countInstancesOfClasses(Class[] classes, boolean assignable);
- /**
- * Gets instances of classes on the Java heap.
- * It is the caller's responsibility to do GC if they don't want unreachable
- * objects to be included.
- *
- * @param classes the classes to get instances of.
- * @param assignable if true, any instance whose class is assignable to
- * {@code classes[i]}, as defined by {@link Class#isAssignableFrom},
- * is included. If false, only instances whose class is
- * equal to {@code classes[i]} are included.
- * @return an array containing the list of matching instances. The value
- * for index {@code i} is an array containing the instances
- * of the class {@code classes[i]}
- *
- * @hide
- */
- public static native Object[][] getInstancesOfClasses(Class[] classes, boolean assignable);
-
/* Map from the names of the runtime stats supported by getRuntimeStat() to their IDs */
private static final HashMap<String, Integer> runtimeStatsMap = new HashMap<>();
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index e3411be..c4c7b73 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1817,5 +1817,16 @@
"test.java.util.concurrent.tck.ThreadPoolExecutorTest#testPoolSizeInvariants",
"test.java.util.concurrent.tck.ThreadTest#testGetAndSetDefaultUncaughtExceptionHandler"
]
+},
+{
+ description: "Android has a behavior difference to be fixed.",
+ result: EXEC_FAILED,
+ bug: 181171596,
+ names: [
+ "crossvmtest.java.lang.RecordComponentTest#testGetRecordComponentAnnotation",
+ "crossvmtest.java.lang.RecordComponentTest#testGetAnnotations",
+ "crossvmtest.java.lang.RecordComponentTest#testGetDeclaredAnnotations",
+ "crossvmtest.java.lang.RecordTest#testWriteField"
+ ]
}
]
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java
index 784776c..968639f 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java
@@ -29,7 +29,7 @@
static Boolean b;
static Integer integer;
- boolean isThrown = false;
+ volatile boolean isThrown = false;
protected void doneSuite() {
b = null;
@@ -123,26 +123,32 @@
sr.enqueue();
class RemoveThread extends Thread {
+ public final CountDownLatch inBlock = new CountDownLatch(1);
+ public final CountDownLatch outOfBlock = new CountDownLatch(1);
public void run() {
try {
+ inBlock.countDown();
rq.remove();
} catch(InterruptedException ie) {
isThrown = true;
}
+ outOfBlock.countDown();
}
}
RemoveThread rt = new RemoveThread();
rt.start();
try {
- Thread.sleep(100);
+ rt.inBlock.await();
+ // Sleep in case rt sets flag right before pausing.
+ Thread.sleep(50);
} catch(InterruptedException ie) {
-
+ fail("Unexpected interrupt");
}
rt.interrupt();
try {
- Thread.sleep(100);
+ rt.outOfBlock.await();
} catch(InterruptedException ie) {
-
+ fail("Unexpected interrupt");
}
assertTrue(isThrown);
assertNull(rq.poll());
@@ -212,12 +218,16 @@
try {
rt.inBlock.await();
// Try to be inside of rq.remove(1000L) if possible.
- Thread.sleep(10);
- } catch(InterruptedException ie) {}
+ Thread.sleep(50);
+ } catch(InterruptedException ie) {
+ fail("Unexpected interrupt");
+ }
rt.interrupt();
try {
rt.outOfBlock.await();
- } catch(InterruptedException ie) {}
+ } catch(InterruptedException ie) {
+ fail("Unexpected interrupt");
+ }
assertTrue(isThrown);
assertNull(rq.poll());
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetDecoderTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetDecoderTest.java
index 630b1d3..1da2552 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetDecoderTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetDecoderTest.java
@@ -21,6 +21,7 @@
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderMalfunctionError;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.MalformedInputException;
@@ -28,6 +29,8 @@
import junit.framework.TestCase;
+import org.junit.Assert;
+
/**
* API unit test for java.nio.CharsetDecoder
*/
@@ -286,12 +289,11 @@
assertCharBufferValue(replaceStr, out);
}
- // RuntimeException
- try {
- decoder.decode(getExceptionByteArray());
- fail("should throw runtime exception");
- } catch (RuntimeException e) {
- }
+ // CoderMalfunctionError
+ ByteBuffer inBuffer = getExceptionByteArray();
+ Class<? extends Throwable> throwableClass = inBuffer == null ? NullPointerException.class
+ : CoderMalfunctionError.class;
+ Assert.assertThrows(throwableClass, () -> decoder.decode(inBuffer));
}
/*
@@ -511,11 +513,9 @@
UnsupportedEncodingException {
CharBuffer out = CharBuffer.allocate(50);
decoder.reset();
- try {
- decoder.decode(in, out, endOfInput);
- fail("should throw runtime exception");
- } catch (RuntimeException e) {
- }
+ Class<? extends Throwable> throwableClass = in == null ? NullPointerException.class
+ : CoderMalfunctionError.class;
+ Assert.assertThrows(throwableClass, () -> decoder.decode(in, out, endOfInput));
}
private ByteBuffer readOnly(ByteBuffer b) {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetEncoderTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetEncoderTest.java
index 5fbac1b..7a9b263 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetEncoderTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/charset/CharsetEncoderTest.java
@@ -21,6 +21,7 @@
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderMalfunctionError;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.MalformedInputException;
@@ -30,6 +31,8 @@
import junit.framework.TestCase;
+import org.junit.Assert;
+
/**
* API unit test for java.nio.charset.CharsetEncoder
*/
@@ -676,12 +679,12 @@
assertByteArray(out, unibytesWithRep);
}
- // RuntimeException
- try {
- encoder.encode(getExceptionCharBuffer());
- fail("should throw runtime exception");
- } catch (RuntimeException e) {
- }
+ // CoderMalfunctionError
+ CharBuffer inBuffer = getExceptionCharBuffer();
+ Class<? extends Throwable> throwableClass = inBuffer == null
+ ? NullPointerException.class
+ : CoderMalfunctionError.class;
+ Assert.assertThrows(throwableClass, () -> encoder.encode(inBuffer));
}
/*
@@ -887,12 +890,12 @@
+ cs.name());
}
- // RuntimeException
- try {
- encoder.encode(getExceptionCharBuffer());
- fail("should throw runtime exception");
- } catch (RuntimeException e) {
- }
+ // CoderMalfunctionError
+ CharBuffer inBuffer = getExceptionCharBuffer();
+ Class<? extends Throwable> throwableClass = inBuffer == null
+ ? NullPointerException.class
+ : CoderMalfunctionError.class;
+ Assert.assertThrows(throwableClass, () -> encoder.encode(inBuffer));
}
private void assertCodingErrorAction(boolean endOfInput, ByteBuffer out,
diff --git a/libart/src/main/java/java/lang/Daemons.java b/libart/src/main/java/java/lang/Daemons.java
index 01d752d..24a51f2 100644
--- a/libart/src/main/java/java/lang/Daemons.java
+++ b/libart/src/main/java/java/lang/Daemons.java
@@ -20,6 +20,9 @@
import android.system.Os;
import android.system.OsConstants;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.lang.ref.Cleaner;
import java.lang.ref.FinalizerReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
@@ -31,6 +34,8 @@
import dalvik.system.VMRuntime;
import dalvik.system.VMDebug;
+import jdk.internal.ref.CleanerImpl;
+
/**
* Calls Object.finalize() on objects in the finalizer reference queue. The VM
* will abort if any finalize() call takes more than the maximum finalize time
@@ -287,29 +292,40 @@
try {
// Use non-blocking poll to avoid FinalizerWatchdogDaemon communication
// when busy.
- FinalizerReference<?> finalizingReference = (FinalizerReference<?>)queue.poll();
- if (finalizingReference != null) {
- finalizingObject = finalizingReference.get();
+ Object nextReference = queue.poll();
+ if (nextReference != null) {
progressCounter.lazySet(++localProgressCounter);
+ processReference(nextReference);
} else {
finalizingObject = null;
progressCounter.lazySet(++localProgressCounter);
// Slow path; block.
FinalizerWatchdogDaemon.INSTANCE.monitoringNotNeeded(
FinalizerWatchdogDaemon.FINALIZER_DAEMON);
- finalizingReference = (FinalizerReference<?>)queue.remove();
- finalizingObject = finalizingReference.get();
+ nextReference = queue.remove();
progressCounter.set(++localProgressCounter);
FinalizerWatchdogDaemon.INSTANCE.monitoringNeeded(
FinalizerWatchdogDaemon.FINALIZER_DAEMON);
+ processReference(nextReference);
}
- doFinalize(finalizingReference);
} catch (InterruptedException ignored) {
} catch (OutOfMemoryError ignored) {
}
}
}
+ private void processReference(Object ref) {
+ if (ref instanceof FinalizerReference finalizingReference) {
+ finalizingObject = finalizingReference.get();
+ doFinalize(finalizingReference);
+ } else if (ref instanceof Cleaner.Cleanable cleanableReference) {
+ finalizingObject = cleanableReference;
+ doClean(cleanableReference);
+ } else {
+ throw new AssertionError("Unknown class was placed into queue: " + ref);
+ }
+ }
+
@FindBugsSuppressWarnings("FI_EXPLICIT_INVOCATION")
private void doFinalize(FinalizerReference<?> reference) {
FinalizerReference.remove(reference);
@@ -325,6 +341,17 @@
finalizingObject = null;
}
}
+
+ private void doClean(Cleaner.Cleanable cleanable) {
+ try {
+ cleanable.clean();
+ } catch (Throwable ex) {
+ System.logE("Uncaught exception thrown by cleaner", ex);
+ } finally {
+ // No need to hold cleaner object.
+ finalizingObject = null;
+ }
+ }
}
/**
@@ -342,6 +369,18 @@
@UnsupportedAppUsage
private static final FinalizerWatchdogDaemon INSTANCE = new FinalizerWatchdogDaemon();
+ private static final VarHandle VH_ACTION;
+ static {
+ try {
+ VH_ACTION = MethodHandles
+ .privateLookupIn(
+ CleanerImpl.PhantomCleanableRef.class, MethodHandles.lookup())
+ .findVarHandle(
+ CleanerImpl.PhantomCleanableRef.class, "action", Runnable.class);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ throw new AssertionError("PhantomCleanableRef should have action field", e);
+ }
+ }
private int activeWatchees; // Only synchronized accesses.
@@ -512,8 +551,9 @@
// the case which a very slow finalization just finished as we were timing out.
if (isActive(FINALIZER_DAEMON)
&& FinalizerDaemon.INSTANCE.progressCounter.get() == finalizerStartCount) {
- System.logE("Was finalizing " + finalizing + ", now finalizing "
- + FinalizerDaemon.INSTANCE.finalizingObject);
+ System.logE("Was finalizing " + finalizingObjectAsString(finalizing)
+ + ", now finalizing "
+ + finalizingObjectAsString(FinalizerDaemon.INSTANCE.finalizingObject));
System.logE("Total elapsed millis: "
+ (System.currentTimeMillis() - startMillis));
System.logE("Total nanos: " + (System.nanoTime() - startNanos));
@@ -532,14 +572,31 @@
}
private static TimeoutException finalizerTimeoutException(Object object) {
- String message = object.getClass().getName() + ".finalize() timed out after "
- + VMRuntime.getRuntime().getFinalizerTimeoutMs() / 1000 + " seconds";
- TimeoutException syntheticException = new TimeoutException(message);
+ StringBuilder messageBuilder = new StringBuilder();
+
+ if (object instanceof Cleaner.Cleanable) {
+ messageBuilder.append(VH_ACTION.get(object).getClass().getName());
+ } else {
+ messageBuilder.append(object.getClass().getName()).append(".finalize()");
+ }
+
+ messageBuilder.append(" timed out after ")
+ .append(VMRuntime.getRuntime().getFinalizerTimeoutMs() / 1000)
+ .append(" seconds");
+ TimeoutException syntheticException = new TimeoutException(messageBuilder.toString());
// We use the stack from where finalize() was running to show where it was stuck.
syntheticException.setStackTrace(FinalizerDaemon.INSTANCE.getStackTrace());
return syntheticException;
}
+ private static String finalizingObjectAsString(Object obj) {
+ if (obj instanceof Cleaner.Cleanable) {
+ return VH_ACTION.get(obj).toString();
+ } else {
+ return obj.toString();
+ }
+ }
+
private static TimeoutException refQueueTimeoutException(ReferenceQueue rq) {
String message = "ReferenceQueueDaemon timed out while targeting " + rq;
return new TimeoutException(message);
diff --git a/luni/src/main/java/android/system/SystemCleaner.java b/luni/src/main/java/android/system/SystemCleaner.java
index 82060af..e49a625 100644
--- a/luni/src/main/java/android/system/SystemCleaner.java
+++ b/luni/src/main/java/android/system/SystemCleaner.java
@@ -35,10 +35,6 @@
* complete quickly, without explicit I/O, interprocess communication, or network access.
* Registering a non-terminating or excessively slow cleaning action with the shared cleaner
* may cause the process to perform very badly, hang, or be killed.
- *
- * Only for developers of the Android platform itself: As with all Cleaners, use of SystemCleaner
- * requires an extra thread to be started. This is unsafe for zygote-callable code. Use
- * NativeAllocationRegistry.
*/
public final class SystemCleaner {
@@ -48,10 +44,6 @@
* Return a single Cleaner that's shared across the entire process. Thread-safe.
*/
@NonNull public static Cleaner cleaner() {
- // We just abuse CleanerFactory. That has the down side that a runaway Cleaner will cause
- // issues for system libraries. If this eventually becomes a problem due to widespread use,
- // we can set up another thread here.
- // TODO: Add some sort of watchdog for this.
return CleanerFactory.cleaner();
}
}
diff --git a/luni/src/main/java/libcore/internal/Java17LanguageFeatures.java b/luni/src/main/java/libcore/internal/Java17LanguageFeatures.java
new file mode 100644
index 0000000..2b117dc
--- /dev/null
+++ b/luni/src/main/java/libcore/internal/Java17LanguageFeatures.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.internal;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Proof of concept / fake code whose only purpose is to demonstrate that Java 17
+ * language features are supported in libcore.
+ */
+public class Java17LanguageFeatures {
+
+ public static String getTextBlock() {
+ // Language feature (Java 15): JEP-378 - Text blocks
+ return """
+ This is a
+ multiline
+ string.""";
+ }
+
+ public static int calculateApproximateArea(Shape s) {
+ // Language feature (Java 16): JEP-394 - Pattern matching instanceof
+ if (s instanceof Triangle t) {
+ return (t.base * t.height / 2);
+ } else if (s instanceof Rectangle r) {
+ return (r.length * r.width);
+ } else if (s instanceof Circle c) {
+ return (c.radius * c.radius * 3);
+ } else {
+ return 0;
+ }
+ }
+
+ public static abstract class Shape {
+ }
+
+ public static class Triangle extends Shape {
+ public final int base;
+ public final int height;
+
+ public Triangle(int base, int height) {
+ this.base = base;
+ this.height = height;
+ }
+ }
+
+ public static class Rectangle extends Shape {
+ public final int length;
+ public final int width;
+
+ public Rectangle(int length, int width) {
+ this.length = length;
+ this.width = width;
+ }
+ }
+
+ public static class Circle extends Shape {
+ public final int radius;
+
+ public Circle(int radius) {
+ this.radius = radius;
+ }
+ }
+
+ public static Point buildPoint(int x, int y) {
+ // Language feature (Java 16): JEP-395 - Records
+ return new Point(x, y);
+ }
+
+ public record Point(int x, int y) { }
+
+ public static int getSealedClassId(BaseSealedClass obj) {
+ // Language feature (Java 17): JEP-409 - Sealed classes
+ return obj.getId();
+ }
+
+ public static sealed class BaseSealedClass permits FinalDerivedClass, NonSealedDerivedClass {
+ public int getId() {
+ return 0;
+ }
+ }
+
+ public static final class FinalDerivedClass extends BaseSealedClass {
+ @Override
+ public int getId() {
+ return 1;
+ }
+ }
+
+ public static non-sealed class NonSealedDerivedClass extends BaseSealedClass {
+ @Override
+ public int getId() {
+ return 2;
+ }
+ }
+}
diff --git a/luni/src/main/java/libcore/util/EmptyArray.java b/luni/src/main/java/libcore/util/EmptyArray.java
index aa6a6fd..af27eaa 100644
--- a/luni/src/main/java/libcore/util/EmptyArray.java
+++ b/luni/src/main/java/libcore/util/EmptyArray.java
@@ -22,6 +22,8 @@
import android.compat.annotation.UnsupportedAppUsage;
import dalvik.annotation.compat.VersionCodes;
+import java.lang.annotation.Annotation;
+
/**
* Empty array is immutable. Use a shared empty array to avoid allocation.
*
@@ -88,4 +90,6 @@
/** @hide */
public static final java.lang.reflect.TypeVariable[] TYPE_VARIABLE =
new java.lang.reflect.TypeVariable[0];
+ /** @hide */
+ public static final Annotation[] ANNOTATION = new Annotation[0];
}
diff --git a/luni/src/test/Android.bp b/luni/src/test/Android.bp
new file mode 100644
index 0000000..90bfc2c
--- /dev/null
+++ b/luni/src/test/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["libcore_luni_license"],
+}
+
+java_test_host {
+ name: "luni-host-tests",
+ srcs: [
+ "java/crossvmtest/**/*.java",
+ ],
+ test_options: {
+ unit_test: true,
+ },
+ static_libs: [
+ "junit",
+ ],
+ test_suites: ["general-tests"],
+}
diff --git a/luni/src/test/java/crossvmtest/java/lang/RecordComponentTest.java b/luni/src/test/java/crossvmtest/java/lang/RecordComponentTest.java
new file mode 100644
index 0000000..01f6d19
--- /dev/null
+++ b/luni/src/test/java/crossvmtest/java/lang/RecordComponentTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package crossvmtest.java.lang;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Method;
+import java.lang.reflect.RecordComponent;
+import java.math.BigInteger;
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.List;
+
+public class RecordComponentTest {
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.FIELD, ElementType.RECORD_COMPONENT})
+ public @interface CustomAnnotation {
+ String value();
+ }
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.RECORD_COMPONENT})
+ public @interface CustomAnnotation2 {
+
+ CustomAnnotation[] customAnnotations();
+ }
+ record RecordInteger(@CustomAnnotation2(customAnnotations = {@CustomAnnotation("a")})
+ @CustomAnnotation("b") int x) {}
+ record RecordString(String s) {}
+
+ record GenericRecord<A, B extends AbstractMap<String, BigInteger>> (
+ A a, B b, List<String> c) {}
+
+ @Test
+ public void testBasic() {
+ assertTrue(RecordInteger.class.isRecord());
+ RecordComponent[] components = RecordInteger.class.getRecordComponents();
+ assertEquals(Arrays.deepToString(components), 1, components.length);
+ }
+
+ @Test
+ public void testGetAccessor() throws Exception {
+ RecordComponent[] components = RecordInteger.class.getRecordComponents();
+ Method getter = components[0].getAccessor();
+
+ RecordInteger a = new RecordInteger(9);
+ assertEquals(9, getter.invoke(a));
+ }
+
+ @Test
+ public void testGetAnnotation() throws Exception {
+ RecordComponent[] components = RecordInteger.class.getRecordComponents();
+ assertEquals("b", RecordInteger.class.getDeclaredField("x")
+ .getAnnotation(CustomAnnotation.class)
+ .value());
+ assertEquals("b", components[0]
+ .getAnnotation(CustomAnnotation.class)
+ .value());
+ }
+
+ @Test
+ public void testGetRecordComponentAnnotation() throws Exception {
+ RecordComponent[] components = RecordInteger.class.getRecordComponents();
+
+ assertTrue(RecordInteger.class.isRecord());
+ assertEquals(1, components.length);
+ assertNull(RecordInteger.class.getDeclaredField("x")
+ .getAnnotation(CustomAnnotation2.class));
+ CustomAnnotation2 customAnnotation2 = components[0].getAnnotation(CustomAnnotation2.class);
+ assertNotNull(customAnnotation2);
+ assertEquals(1, customAnnotation2.customAnnotations().length);
+ assertEquals("a", customAnnotation2.customAnnotations()[0].value());
+ }
+
+ @Test
+ public void testGetAnnotations() {
+ RecordComponent[] components = RecordInteger.class.getRecordComponents();
+ assertEquals(2, components[0].getAnnotations().length);
+ }
+
+ @Test
+ public void testGetDeclaredAnnotations() {
+ RecordComponent[] components = RecordInteger.class.getRecordComponents();
+ assertEquals(2, components[0].getDeclaredAnnotations().length);
+ }
+
+ @Test
+ public void testGetDeclaringRecord() {
+ RecordComponent[] components = RecordInteger.class.getRecordComponents();
+ assertEquals(RecordInteger.class, components[0].getDeclaringRecord());
+ }
+
+ @Test
+ public void testGetName() {
+ RecordComponent[] components = RecordInteger.class.getRecordComponents();
+ assertEquals("x", components[0].getName());
+ }
+
+ @Test
+ public void testGetType() {
+ RecordComponent[] components = RecordInteger.class.getRecordComponents();
+ assertEquals(int.class, components[0].getType());
+ }
+
+ @Test
+ public void testToString() {
+ RecordComponent[] components = RecordInteger.class.getRecordComponents();
+ assertEquals("int x", components[0].toString());
+ }
+
+ @Test
+ public void testGetGenericType() {
+ RecordComponent[] components = RecordInteger.class.getRecordComponents();
+ assertEquals(int.class, components[0].getGenericType());
+
+ components = RecordString.class.getRecordComponents();
+ assertEquals(String.class, components[0].getGenericType());
+
+ components = GenericRecord.class.getRecordComponents();
+ assertEquals(3, components.length);
+ assertEquals("A", components[0].getGenericType().getTypeName());
+ assertEquals("B", components[1].getGenericType().getTypeName());
+ assertEquals("java.util.List<java.lang.String>", components[2].getGenericType().getTypeName());
+ }
+
+ @Test
+ public void testGetGenericSingature() {
+ RecordComponent[] components = RecordInteger.class.getRecordComponents();
+ assertNull(components[0].getGenericSignature());
+
+ components = RecordString.class.getRecordComponents();
+ assertNull(components[0].getGenericSignature());
+
+ components = GenericRecord.class.getRecordComponents();
+ assertEquals(3, components.length);
+ assertEquals("TA;", components[0].getGenericSignature());
+ assertEquals("TB;", components[1].getGenericSignature());
+ assertEquals("Ljava/util/List<Ljava/lang/String;>;", components[2].getGenericSignature());
+ }
+}
diff --git a/luni/src/test/java/crossvmtest/java/lang/RecordTest.java b/luni/src/test/java/crossvmtest/java/lang/RecordTest.java
new file mode 100644
index 0000000..8d70e5b
--- /dev/null
+++ b/luni/src/test/java/crossvmtest/java/lang/RecordTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package crossvmtest.java.lang;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+
+public class RecordTest {
+
+ record RecordInteger(int x) {}
+
+ private static class NonRecordInteger {
+
+ NonRecordInteger(int x) {
+ this.x = x;
+ }
+ private final int x;
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.FIELD, ElementType.RECORD_COMPONENT})
+ public @interface CustomAnnotation {
+ String value();
+ }
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.FIELD, ElementType.RECORD_COMPONENT})
+ public @interface CustomAnnotation2 {
+
+ CustomAnnotation[] customAnnotations();
+ }
+ record RecordInteger2(@CustomAnnotation2(customAnnotations = {@CustomAnnotation("a")})
+ @CustomAnnotation("b") int x) {}
+
+ @Test
+ public void testHashCode() {
+ RecordInteger a = new RecordInteger(9);
+ RecordInteger b = new RecordInteger(9);
+ RecordInteger c = new RecordInteger(0);
+
+ assertEquals(a.hashCode(), b.hashCode());
+ assertNotEquals(a.hashCode(), c.hashCode());
+ }
+
+ @Test
+ public void testEquals() {
+ RecordInteger a = new RecordInteger(9);
+ RecordInteger b = new RecordInteger(9);
+ RecordInteger c = new RecordInteger(0);
+
+ assertTrue(a.equals(b));
+ assertEquals(a, b);
+ assertFalse(a.equals(c));
+ assertNotEquals(a, c);
+ }
+
+ @Test
+ public void testToString() {
+ RecordInteger a = new RecordInteger(9);
+ RecordInteger b = new RecordInteger(9);
+ RecordInteger c = new RecordInteger(0);
+
+ assertEquals(a.toString(), b.toString());
+ assertNotEquals(a.toString(), c.toString());
+ }
+
+ @Test
+ public void testIsRecord() throws Exception {
+ RecordInteger a = new RecordInteger(9);
+ assertTrue(a.getClass().isRecord());
+ }
+
+ @Test
+ public void testReflectedConstructor() throws ReflectiveOperationException {
+ RecordInteger a = new RecordInteger(9);
+
+ Constructor<?> c = RecordInteger.class.getDeclaredConstructors()[0];
+ assertEquals(Arrays.deepToString(c.getParameters()), 1, c.getParameters().length);
+ assertEquals(c.getParameters()[0].toString(), "x", c.getParameters()[0].getName());
+ RecordInteger b = (RecordInteger) c.newInstance(9);
+ assertEquals(a.x, b.x);
+ assertEquals(a.x(), b.x());
+ assertEquals(a, b);
+ }
+
+ @Test
+ public void testReadField() throws ReflectiveOperationException {
+ RecordInteger a = new RecordInteger(9);
+ assertEquals(9, a.x);
+ assertEquals(9, a.x());
+
+ Field[] fields = RecordInteger.class.getDeclaredFields();
+ assertEquals(Arrays.deepToString(fields), 1, fields.length);
+ Field field = fields[0];
+ field.setAccessible(true);
+ assertEquals(field.toString(), "x", field.getName());
+ assertEquals(9, field.get(a));
+ }
+
+ @Test
+ public void testWriteField() throws ReflectiveOperationException {
+ NonRecordInteger a = new NonRecordInteger(8);
+ Field fieldA = NonRecordInteger.class.getDeclaredField("x");
+ fieldA.setAccessible(true);
+ fieldA.set(a, 7);
+ assertEquals(7, a.x);
+
+ RecordInteger b = new RecordInteger(8);
+
+ Field fieldB = RecordInteger.class.getDeclaredField("x");
+ fieldB.setAccessible(true);
+ assertThrows(IllegalAccessException.class, () -> fieldB.set(b, 7));
+ assertEquals(8, b.x);
+ }
+
+ @Test
+ public void testVarHandleWrite() throws ReflectiveOperationException {
+ NonRecordInteger a = new NonRecordInteger(8);
+
+ MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(NonRecordInteger.class,
+ MethodHandles.lookup());
+ VarHandle varHandle = lookup.findVarHandle(NonRecordInteger.class, "x", int.class);
+ assertEquals(8, varHandle.get(a));
+ assertThrows(UnsupportedOperationException.class, () -> varHandle.set(a, 6));
+ assertEquals(8, a.x);
+
+ RecordInteger b = new RecordInteger(8);
+
+ lookup = MethodHandles.privateLookupIn(RecordInteger.class, MethodHandles.lookup());
+ VarHandle varHandleB = lookup.findVarHandle(RecordInteger.class, "x", int.class);
+ assertThrows(UnsupportedOperationException.class, () -> varHandleB.set(b, 7));
+ assertEquals(8, b.x);
+ }
+}
diff --git a/luni/src/test/java/libcore/android/system/OsConstantsTest.java b/luni/src/test/java/libcore/android/system/OsConstantsTest.java
index a2dc744..f795d45 100644
--- a/luni/src/test/java/libcore/android/system/OsConstantsTest.java
+++ b/luni/src/test/java/libcore/android/system/OsConstantsTest.java
@@ -18,11 +18,35 @@
import android.system.OsConstants;
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
-public class OsConstantsTest extends TestCase {
+import static android.system.OsConstants.CAP_TO_INDEX;
+import static android.system.OsConstants.CAP_TO_MASK;
+import static android.system.OsConstants.S_ISBLK;
+import static android.system.OsConstants.S_ISCHR;
+import static android.system.OsConstants.S_ISDIR;
+import static android.system.OsConstants.S_ISFIFO;
+import static android.system.OsConstants.S_ISREG;
+import static android.system.OsConstants.S_ISLNK;
+import static android.system.OsConstants.S_ISSOCK;
+import static android.system.OsConstants.WEXITSTATUS;
+import static android.system.OsConstants.WCOREDUMP;
+import static android.system.OsConstants.WTERMSIG;
+import static android.system.OsConstants.WSTOPSIG;
+import static android.system.OsConstants.WIFEXITED;
+import static android.system.OsConstants.WIFSTOPPED;
+import static android.system.OsConstants.WIFSIGNALED;
+
+import static org.junit.Assert.*;
+
+@RunWith(JUnit4.class)
+public class OsConstantsTest {
// http://b/15602893
+ @Test
public void testBug15602893() {
assertTrue(OsConstants.RT_SCOPE_HOST > 0);
assertTrue(OsConstants.RT_SCOPE_LINK > 0);
@@ -32,6 +56,7 @@
}
// introduced for http://b/30402085
+ @Test
public void testTcpUserTimeoutIsDefined() {
assertTrue(OsConstants.TCP_USER_TIMEOUT > 0);
}
@@ -40,8 +65,377 @@
* Verifies equality assertions given in the documentation for
* {@link OsConstants#SOCK_CLOEXEC} and {@link OsConstants#SOCK_NONBLOCK}.
*/
+ @Test
public void testConstantsEqual() {
assertEquals(OsConstants.O_CLOEXEC, OsConstants.SOCK_CLOEXEC);
assertEquals(OsConstants.O_NONBLOCK, OsConstants.SOCK_NONBLOCK);
}
+
+ @Test
+ public void test_CAP_constants() {
+ assertEquals(0, OsConstants.CAP_CHOWN);
+ assertEquals(1, OsConstants.CAP_DAC_OVERRIDE);
+ assertEquals(2, OsConstants.CAP_DAC_READ_SEARCH);
+ assertEquals(3, OsConstants.CAP_FOWNER);
+ assertEquals(4, OsConstants.CAP_FSETID);
+ assertEquals(5, OsConstants.CAP_KILL);
+ assertEquals(6, OsConstants.CAP_SETGID);
+ assertEquals(7, OsConstants.CAP_SETUID);
+ assertEquals(8, OsConstants.CAP_SETPCAP);
+ assertEquals(9, OsConstants.CAP_LINUX_IMMUTABLE);
+ assertEquals(10, OsConstants.CAP_NET_BIND_SERVICE);
+ assertEquals(11, OsConstants.CAP_NET_BROADCAST);
+ assertEquals(12, OsConstants.CAP_NET_ADMIN);
+ assertEquals(13, OsConstants.CAP_NET_RAW);
+ assertEquals(14, OsConstants.CAP_IPC_LOCK);
+ assertEquals(15, OsConstants.CAP_IPC_OWNER);
+ assertEquals(16, OsConstants.CAP_SYS_MODULE);
+ assertEquals(17, OsConstants.CAP_SYS_RAWIO);
+ assertEquals(18, OsConstants.CAP_SYS_CHROOT);
+ assertEquals(19, OsConstants.CAP_SYS_PTRACE);
+ assertEquals(20, OsConstants.CAP_SYS_PACCT);
+ assertEquals(21, OsConstants.CAP_SYS_ADMIN);
+ assertEquals(22, OsConstants.CAP_SYS_BOOT);
+ assertEquals(23, OsConstants.CAP_SYS_NICE);
+ assertEquals(24, OsConstants.CAP_SYS_RESOURCE);
+ assertEquals(25, OsConstants.CAP_SYS_TIME);
+ assertEquals(26, OsConstants.CAP_SYS_TTY_CONFIG);
+ assertEquals(27, OsConstants.CAP_MKNOD);
+ assertEquals(28, OsConstants.CAP_LEASE);
+ assertEquals(29, OsConstants.CAP_AUDIT_WRITE);
+ assertEquals(30, OsConstants.CAP_AUDIT_CONTROL);
+ assertEquals(31, OsConstants.CAP_SETFCAP);
+ assertEquals(32, OsConstants.CAP_MAC_OVERRIDE);
+ assertEquals(33, OsConstants.CAP_MAC_ADMIN);
+ assertEquals(34, OsConstants.CAP_SYSLOG);
+ assertEquals(35, OsConstants.CAP_WAKE_ALARM);
+ assertEquals(36, OsConstants.CAP_BLOCK_SUSPEND);
+ // last constant
+ assertEquals(40, OsConstants.CAP_LAST_CAP);
+ }
+
+ @Test
+ public void test_CAP_TO_INDEX() {
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_CHOWN));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_DAC_OVERRIDE));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_DAC_READ_SEARCH));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_FOWNER));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_FSETID));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_KILL));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SETGID));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SETUID));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SETPCAP));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_LINUX_IMMUTABLE));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_NET_BIND_SERVICE));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_NET_BROADCAST));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_NET_ADMIN));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_NET_RAW));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_IPC_LOCK));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_IPC_OWNER));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_MODULE));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_RAWIO));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_CHROOT));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_PTRACE));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_PACCT));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_ADMIN));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_BOOT));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_NICE));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_RESOURCE));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_TIME));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_TTY_CONFIG));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_MKNOD));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_LEASE));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_AUDIT_WRITE));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_AUDIT_CONTROL));
+ assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SETFCAP));
+ assertEquals(1, CAP_TO_INDEX(OsConstants.CAP_MAC_OVERRIDE));
+ assertEquals(1, CAP_TO_INDEX(OsConstants.CAP_MAC_ADMIN));
+ assertEquals(1, CAP_TO_INDEX(OsConstants.CAP_SYSLOG));
+ assertEquals(1, CAP_TO_INDEX(OsConstants.CAP_WAKE_ALARM));
+ assertEquals(1, CAP_TO_INDEX(OsConstants.CAP_BLOCK_SUSPEND));
+ }
+
+ @Test
+ public void test_CAP_TO_MASK() {
+ assertEquals(1 << 0, CAP_TO_MASK(OsConstants.CAP_CHOWN));
+ assertEquals(1 << 1, CAP_TO_MASK(OsConstants.CAP_DAC_OVERRIDE));
+ assertEquals(1 << 2, CAP_TO_MASK(OsConstants.CAP_DAC_READ_SEARCH));
+ assertEquals(1 << 3, CAP_TO_MASK(OsConstants.CAP_FOWNER));
+ assertEquals(1 << 4, CAP_TO_MASK(OsConstants.CAP_FSETID));
+ assertEquals(1 << 5, CAP_TO_MASK(OsConstants.CAP_KILL));
+ assertEquals(1 << 6, CAP_TO_MASK(OsConstants.CAP_SETGID));
+ assertEquals(1 << 7, CAP_TO_MASK(OsConstants.CAP_SETUID));
+ assertEquals(1 << 8, CAP_TO_MASK(OsConstants.CAP_SETPCAP));
+ assertEquals(1 << 9, CAP_TO_MASK(OsConstants.CAP_LINUX_IMMUTABLE));
+ assertEquals(1 << 10, CAP_TO_MASK(OsConstants.CAP_NET_BIND_SERVICE));
+ assertEquals(1 << 11, CAP_TO_MASK(OsConstants.CAP_NET_BROADCAST));
+ assertEquals(1 << 12, CAP_TO_MASK(OsConstants.CAP_NET_ADMIN));
+ assertEquals(1 << 13, CAP_TO_MASK(OsConstants.CAP_NET_RAW));
+ assertEquals(1 << 14, CAP_TO_MASK(OsConstants.CAP_IPC_LOCK));
+ assertEquals(1 << 15, CAP_TO_MASK(OsConstants.CAP_IPC_OWNER));
+ assertEquals(1 << 16, CAP_TO_MASK(OsConstants.CAP_SYS_MODULE));
+ assertEquals(1 << 17, CAP_TO_MASK(OsConstants.CAP_SYS_RAWIO));
+ assertEquals(1 << 18, CAP_TO_MASK(OsConstants.CAP_SYS_CHROOT));
+ assertEquals(1 << 19, CAP_TO_MASK(OsConstants.CAP_SYS_PTRACE));
+ assertEquals(1 << 20, CAP_TO_MASK(OsConstants.CAP_SYS_PACCT));
+ assertEquals(1 << 21, CAP_TO_MASK(OsConstants.CAP_SYS_ADMIN));
+ assertEquals(1 << 22, CAP_TO_MASK(OsConstants.CAP_SYS_BOOT));
+ assertEquals(1 << 23, CAP_TO_MASK(OsConstants.CAP_SYS_NICE));
+ assertEquals(1 << 24, CAP_TO_MASK(OsConstants.CAP_SYS_RESOURCE));
+ assertEquals(1 << 25, CAP_TO_MASK(OsConstants.CAP_SYS_TIME));
+ assertEquals(1 << 26, CAP_TO_MASK(OsConstants.CAP_SYS_TTY_CONFIG));
+ assertEquals(1 << 27, CAP_TO_MASK(OsConstants.CAP_MKNOD));
+ assertEquals(1 << 28, CAP_TO_MASK(OsConstants.CAP_LEASE));
+ assertEquals(1 << 29, CAP_TO_MASK(OsConstants.CAP_AUDIT_WRITE));
+ assertEquals(1 << 30, CAP_TO_MASK(OsConstants.CAP_AUDIT_CONTROL));
+ assertEquals(1 << 31, CAP_TO_MASK(OsConstants.CAP_SETFCAP));
+ assertEquals(1 << 0, CAP_TO_MASK(OsConstants.CAP_MAC_OVERRIDE));
+ assertEquals(1 << 1, CAP_TO_MASK(OsConstants.CAP_MAC_ADMIN));
+ assertEquals(1 << 2, CAP_TO_MASK(OsConstants.CAP_SYSLOG));
+ assertEquals(1 << 3, CAP_TO_MASK(OsConstants.CAP_WAKE_ALARM));
+ assertEquals(1 << 4, CAP_TO_MASK(OsConstants.CAP_BLOCK_SUSPEND));
+ }
+
+ @Test
+ public void test_S_ISLNK() {
+ assertTrue(S_ISLNK(OsConstants.S_IFLNK));
+
+ assertFalse(S_ISLNK(OsConstants.S_IFBLK));
+ assertFalse(S_ISLNK(OsConstants.S_IFCHR));
+ assertFalse(S_ISLNK(OsConstants.S_IFDIR));
+ assertFalse(S_ISLNK(OsConstants.S_IFIFO));
+ assertFalse(S_ISLNK(OsConstants.S_IFMT));
+ assertFalse(S_ISLNK(OsConstants.S_IFREG));
+ assertFalse(S_ISLNK(OsConstants.S_IFSOCK));
+ assertFalse(S_ISLNK(OsConstants.S_IRGRP));
+ assertFalse(S_ISLNK(OsConstants.S_IROTH));
+ assertFalse(S_ISLNK(OsConstants.S_IRUSR));
+ assertFalse(S_ISLNK(OsConstants.S_IRWXG));
+ assertFalse(S_ISLNK(OsConstants.S_IRWXO));
+ assertFalse(S_ISLNK(OsConstants.S_IRWXU));
+ assertFalse(S_ISLNK(OsConstants.S_ISGID));
+ assertFalse(S_ISLNK(OsConstants.S_ISUID));
+ assertFalse(S_ISLNK(OsConstants.S_ISVTX));
+ assertFalse(S_ISLNK(OsConstants.S_IWGRP));
+ assertFalse(S_ISLNK(OsConstants.S_IWOTH));
+ assertFalse(S_ISLNK(OsConstants.S_IWUSR));
+ assertFalse(S_ISLNK(OsConstants.S_IXGRP));
+ assertFalse(S_ISLNK(OsConstants.S_IXOTH));
+ assertFalse(S_ISLNK(OsConstants.S_IXUSR));
+ }
+
+ @Test
+ public void test_S_ISREG() {
+ assertTrue(S_ISREG(OsConstants.S_IFREG));
+
+ assertFalse(S_ISREG(OsConstants.S_IFBLK));
+ assertFalse(S_ISREG(OsConstants.S_IFCHR));
+ assertFalse(S_ISREG(OsConstants.S_IFDIR));
+ assertFalse(S_ISREG(OsConstants.S_IFIFO));
+ assertFalse(S_ISREG(OsConstants.S_IFLNK));
+ assertFalse(S_ISREG(OsConstants.S_IFMT));
+ assertFalse(S_ISREG(OsConstants.S_IFSOCK));
+ assertFalse(S_ISREG(OsConstants.S_IRGRP));
+ assertFalse(S_ISREG(OsConstants.S_IROTH));
+ assertFalse(S_ISREG(OsConstants.S_IRUSR));
+ assertFalse(S_ISREG(OsConstants.S_IRWXG));
+ assertFalse(S_ISREG(OsConstants.S_IRWXO));
+ assertFalse(S_ISREG(OsConstants.S_IRWXU));
+ assertFalse(S_ISREG(OsConstants.S_ISGID));
+ assertFalse(S_ISREG(OsConstants.S_ISUID));
+ assertFalse(S_ISREG(OsConstants.S_ISVTX));
+ assertFalse(S_ISREG(OsConstants.S_IWGRP));
+ assertFalse(S_ISREG(OsConstants.S_IWOTH));
+ assertFalse(S_ISREG(OsConstants.S_IWUSR));
+ assertFalse(S_ISREG(OsConstants.S_IXGRP));
+ assertFalse(S_ISREG(OsConstants.S_IXOTH));
+ assertFalse(S_ISREG(OsConstants.S_IXUSR));
+ }
+
+ @Test
+ public void test_S_ISDIR() {
+ assertTrue(S_ISDIR(OsConstants.S_IFDIR));
+
+ assertFalse(S_ISDIR(OsConstants.S_IFBLK));
+ assertFalse(S_ISDIR(OsConstants.S_IFCHR));
+ assertFalse(S_ISDIR(OsConstants.S_IFIFO));
+ assertFalse(S_ISDIR(OsConstants.S_IFLNK));
+ assertFalse(S_ISDIR(OsConstants.S_IFMT));
+ assertFalse(S_ISDIR(OsConstants.S_IFREG));
+ assertFalse(S_ISDIR(OsConstants.S_IFSOCK));
+ assertFalse(S_ISDIR(OsConstants.S_IRGRP));
+ assertFalse(S_ISDIR(OsConstants.S_IROTH));
+ assertFalse(S_ISDIR(OsConstants.S_IRUSR));
+ assertFalse(S_ISDIR(OsConstants.S_IRWXG));
+ assertFalse(S_ISDIR(OsConstants.S_IRWXO));
+ assertFalse(S_ISDIR(OsConstants.S_IRWXU));
+ assertFalse(S_ISDIR(OsConstants.S_ISGID));
+ assertFalse(S_ISDIR(OsConstants.S_ISUID));
+ assertFalse(S_ISDIR(OsConstants.S_ISVTX));
+ assertFalse(S_ISDIR(OsConstants.S_IWGRP));
+ assertFalse(S_ISDIR(OsConstants.S_IWOTH));
+ assertFalse(S_ISDIR(OsConstants.S_IWUSR));
+ assertFalse(S_ISDIR(OsConstants.S_IXGRP));
+ assertFalse(S_ISDIR(OsConstants.S_IXOTH));
+ assertFalse(S_ISDIR(OsConstants.S_IXUSR));
+ }
+
+ @Test
+ public void test_S_ISCHR() {
+ assertTrue(S_ISCHR(OsConstants.S_IFCHR));
+
+ assertFalse(S_ISCHR(OsConstants.S_IFBLK));
+ assertFalse(S_ISCHR(OsConstants.S_IFDIR));
+ assertFalse(S_ISCHR(OsConstants.S_IFIFO));
+ assertFalse(S_ISCHR(OsConstants.S_IFLNK));
+ assertFalse(S_ISCHR(OsConstants.S_IFMT));
+ assertFalse(S_ISCHR(OsConstants.S_IFREG));
+ assertFalse(S_ISCHR(OsConstants.S_IFSOCK));
+ assertFalse(S_ISCHR(OsConstants.S_IRGRP));
+ assertFalse(S_ISCHR(OsConstants.S_IROTH));
+ assertFalse(S_ISCHR(OsConstants.S_IRUSR));
+ assertFalse(S_ISCHR(OsConstants.S_IRWXG));
+ assertFalse(S_ISCHR(OsConstants.S_IRWXO));
+ assertFalse(S_ISCHR(OsConstants.S_IRWXU));
+ assertFalse(S_ISCHR(OsConstants.S_ISGID));
+ assertFalse(S_ISCHR(OsConstants.S_ISUID));
+ assertFalse(S_ISCHR(OsConstants.S_ISVTX));
+ assertFalse(S_ISCHR(OsConstants.S_IWGRP));
+ assertFalse(S_ISCHR(OsConstants.S_IWOTH));
+ assertFalse(S_ISCHR(OsConstants.S_IWUSR));
+ assertFalse(S_ISCHR(OsConstants.S_IXGRP));
+ assertFalse(S_ISCHR(OsConstants.S_IXOTH));
+ assertFalse(S_ISCHR(OsConstants.S_IXUSR));
+ }
+
+ @Test
+ public void test_S_ISBLK() {
+ assertTrue (S_ISBLK(OsConstants.S_IFBLK));
+
+ assertFalse(S_ISBLK(OsConstants.S_IFCHR));
+ assertFalse(S_ISBLK(OsConstants.S_IFDIR));
+ assertFalse(S_ISBLK(OsConstants.S_IFIFO));
+ assertFalse(S_ISBLK(OsConstants.S_IFLNK));
+ assertFalse(S_ISBLK(OsConstants.S_IFMT));
+ assertFalse(S_ISBLK(OsConstants.S_IFREG));
+ assertFalse(S_ISBLK(OsConstants.S_IFSOCK));
+ assertFalse(S_ISBLK(OsConstants.S_IRGRP));
+ assertFalse(S_ISBLK(OsConstants.S_IROTH));
+ assertFalse(S_ISBLK(OsConstants.S_IRUSR));
+ assertFalse(S_ISBLK(OsConstants.S_IRWXG));
+ assertFalse(S_ISBLK(OsConstants.S_IRWXO));
+ assertFalse(S_ISBLK(OsConstants.S_IRWXU));
+ assertFalse(S_ISBLK(OsConstants.S_ISGID));
+ assertFalse(S_ISBLK(OsConstants.S_ISUID));
+ assertFalse(S_ISBLK(OsConstants.S_ISVTX));
+ assertFalse(S_ISBLK(OsConstants.S_IWGRP));
+ assertFalse(S_ISBLK(OsConstants.S_IWOTH));
+ assertFalse(S_ISBLK(OsConstants.S_IWUSR));
+ assertFalse(S_ISBLK(OsConstants.S_IXGRP));
+ assertFalse(S_ISBLK(OsConstants.S_IXOTH));
+ assertFalse(S_ISBLK(OsConstants.S_IXUSR));
+ }
+
+ @Test
+ public void test_S_ISFIFO() {
+ assertTrue(S_ISFIFO(OsConstants.S_IFIFO));
+
+ assertFalse(S_ISFIFO(OsConstants.S_IFBLK));
+ assertFalse(S_ISFIFO(OsConstants.S_IFCHR));
+ assertFalse(S_ISFIFO(OsConstants.S_IFDIR));
+ assertFalse(S_ISFIFO(OsConstants.S_IFLNK));
+ assertFalse(S_ISFIFO(OsConstants.S_IFMT));
+ assertFalse(S_ISFIFO(OsConstants.S_IFREG));
+ assertFalse(S_ISFIFO(OsConstants.S_IFSOCK));
+ assertFalse(S_ISFIFO(OsConstants.S_IRGRP));
+ assertFalse(S_ISFIFO(OsConstants.S_IROTH));
+ assertFalse(S_ISFIFO(OsConstants.S_IRUSR));
+ assertFalse(S_ISFIFO(OsConstants.S_IRWXG));
+ assertFalse(S_ISFIFO(OsConstants.S_IRWXO));
+ assertFalse(S_ISFIFO(OsConstants.S_IRWXU));
+ assertFalse(S_ISFIFO(OsConstants.S_ISGID));
+ assertFalse(S_ISFIFO(OsConstants.S_ISUID));
+ assertFalse(S_ISFIFO(OsConstants.S_ISVTX));
+ assertFalse(S_ISFIFO(OsConstants.S_IWGRP));
+ assertFalse(S_ISFIFO(OsConstants.S_IWOTH));
+ assertFalse(S_ISFIFO(OsConstants.S_IWUSR));
+ assertFalse(S_ISFIFO(OsConstants.S_IXGRP));
+ assertFalse(S_ISFIFO(OsConstants.S_IXOTH));
+ assertFalse(S_ISFIFO(OsConstants.S_IXUSR));
+ }
+
+ @Test
+ public void test_S_ISSOCK() {
+ assertTrue(S_ISSOCK(OsConstants.S_IFSOCK));
+
+ assertFalse(S_ISSOCK(OsConstants.S_IFBLK));
+ assertFalse(S_ISSOCK(OsConstants.S_IFCHR));
+ assertFalse(S_ISSOCK(OsConstants.S_IFDIR));
+ assertFalse(S_ISSOCK(OsConstants.S_IFIFO));
+ assertFalse(S_ISSOCK(OsConstants.S_IFLNK));
+ assertFalse(S_ISSOCK(OsConstants.S_IFMT));
+ assertFalse(S_ISSOCK(OsConstants.S_IFREG));
+ assertFalse(S_ISSOCK(OsConstants.S_IRGRP));
+ assertFalse(S_ISSOCK(OsConstants.S_IROTH));
+ assertFalse(S_ISSOCK(OsConstants.S_IRUSR));
+ assertFalse(S_ISSOCK(OsConstants.S_IRWXG));
+ assertFalse(S_ISSOCK(OsConstants.S_IRWXO));
+ assertFalse(S_ISSOCK(OsConstants.S_IRWXU));
+ assertFalse(S_ISSOCK(OsConstants.S_ISGID));
+ assertFalse(S_ISSOCK(OsConstants.S_ISUID));
+ assertFalse(S_ISSOCK(OsConstants.S_ISVTX));
+ assertFalse(S_ISSOCK(OsConstants.S_IWGRP));
+ assertFalse(S_ISSOCK(OsConstants.S_IWOTH));
+ assertFalse(S_ISSOCK(OsConstants.S_IWUSR));
+ assertFalse(S_ISSOCK(OsConstants.S_IXGRP));
+ assertFalse(S_ISSOCK(OsConstants.S_IXOTH));
+ assertFalse(S_ISSOCK(OsConstants.S_IXUSR));
+ }
+
+ @Test
+ public void test_WEXITSTATUS() {
+ assertEquals(0, WEXITSTATUS(0x0000));
+ assertEquals(0, WEXITSTATUS(0x00DE));
+ assertEquals(0xF0, WEXITSTATUS(0xF000));
+ assertEquals(0xAB, WEXITSTATUS(0xAB12));
+ }
+
+ @Test
+ public void test_WCOREDUMP() {
+ assertFalse(WCOREDUMP(0));
+ assertTrue(WCOREDUMP(0x80));
+ }
+
+ @Test
+ public void test_WTERMSIG() {
+ assertEquals(0, WTERMSIG(0));
+ assertEquals(0x7f, WTERMSIG(0x7f));
+ }
+
+ @Test
+ public void test_WSTOPSIG() {
+ assertEquals(0, WSTOPSIG(0x0000));
+ assertEquals(0, WSTOPSIG(0x00DE));
+ assertEquals(0xF0, WSTOPSIG(0xF000));
+ assertEquals(0xAB, WSTOPSIG(0xAB12));
+ }
+
+
+ @Test
+ public void test_WIFEXITED() {
+ assertTrue(WIFEXITED(0));
+ assertFalse(WIFEXITED(0x7f));
+ }
+
+ @Test
+ public void test_WIFSTOPPED() {
+ assertFalse(WIFSTOPPED(0));
+ assertTrue(WIFSTOPPED(0x7f));
+ }
+
+ @Test
+ public void test_WIFSIGNALED() {
+ assertFalse(WIFSIGNALED(0));
+ assertTrue(WIFSIGNALED(1));
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/ClassTest.java b/luni/src/test/java/libcore/java/lang/ClassTest.java
index 97ac124..7caea5e 100644
--- a/luni/src/test/java/libcore/java/lang/ClassTest.java
+++ b/luni/src/test/java/libcore/java/lang/ClassTest.java
@@ -45,6 +45,7 @@
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
+import java.util.Set;
import java.util.TreeMap;
import java.util.function.Function;
import java.util.stream.Stream;
@@ -498,6 +499,62 @@
}
@Test
+ public void isSealed() {
+ assertTrue(SealedInterface.class.isSealed());
+ assertFalse(SealedFinalClass.class.isSealed());
+ assertTrue(SealedAbstractClass.class.isSealed());
+ assertFalse(NonSealedDerivedClass.class.isSealed());
+ assertFalse(DerivedClass.class.isSealed());
+ }
+
+ @Test
+ public void getPermittedSubclasses() {
+ assertNull(SealedFinalClass.class.getPermittedSubclasses());
+ assertNull(NonSealedDerivedClass.class.getPermittedSubclasses());
+ assertNull(DerivedClass.class.getPermittedSubclasses());
+
+ var sealedInterfaceSubclasses = SealedInterface.class.getPermittedSubclasses();
+ assertNotNull(sealedInterfaceSubclasses);
+ assertEquals(2, sealedInterfaceSubclasses.length);
+ assertTrue(Set.of(sealedInterfaceSubclasses).contains(SealedAbstractClass.class));
+ assertTrue(Set.of(sealedInterfaceSubclasses).contains(SealedFinalClass.class));
+
+ var sealedAbstractClass = SealedAbstractClass.class.getPermittedSubclasses();
+ assertNotNull(sealedAbstractClass);
+ assertEquals(1, sealedAbstractClass.length);
+ assertEquals(NonSealedDerivedClass.class, sealedAbstractClass[0]);
+ }
+
+ public static sealed interface SealedInterface permits SealedAbstractClass, SealedFinalClass {
+ int getNumber();
+ }
+
+ public static final class SealedFinalClass implements SealedInterface {
+ @Override
+ public int getNumber() {
+ return 1;
+ }
+ }
+
+ public static abstract sealed class SealedAbstractClass implements SealedInterface
+ permits NonSealedDerivedClass {
+ }
+
+ public static non-sealed class NonSealedDerivedClass extends SealedAbstractClass {
+ @Override
+ public int getNumber() {
+ return 2;
+ }
+ }
+
+ public static class DerivedClass extends NonSealedDerivedClass {
+ @Override
+ public int getNumber() {
+ return 3;
+ }
+ }
+
+ @Test
public void recordClass() {
try {
ClassLoader classLoader = createClassLoaderForResource("core-tests-smali.dex");
@@ -637,4 +694,33 @@
}
}
+ @Test
+ public void testComponentType() {
+ assertNull(int.class.componentType());
+ assertNull(String.class.componentType());
+ assertNull(Object.class.componentType());
+
+ assertEquals(int.class, int[].class.componentType());
+ assertEquals(int[].class, int[][].class.componentType());
+ assertEquals(String.class, String[].class.componentType());
+ assertEquals(Foo.class, Foo[].class.componentType());
+ }
+
+ @Test
+ public void testArrayType() {
+ assertEquals(int[].class, int.class.arrayType());
+ assertEquals(int[][].class, int[].class.arrayType());
+ assertEquals(String[].class, String.class.arrayType());
+ assertEquals(Foo[].class, Foo.class.arrayType());
+ }
+
+ @Test
+ public void testDescriptorString() {
+ assertEquals("I", int.class.descriptorString());
+ assertEquals("V", void.class.descriptorString());
+ assertEquals("[I", int[].class.descriptorString());
+ assertEquals("[[I", int[][].class.descriptorString());
+ assertEquals("Ljava/lang/String;", String.class.descriptorString());
+ assertEquals("[Ljava/lang/String;", String[].class.descriptorString());
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/RecordTest.java b/luni/src/test/java/libcore/java/lang/RecordTest.java
new file mode 100644
index 0000000..b12e105b
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/RecordTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.java.lang;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+
+public class RecordTest {
+
+ public record RecordInteger(int x) {};
+
+ @Test
+ public void testHashCode() {
+ RecordInteger a = new RecordInteger(9);
+ RecordInteger b = new RecordInteger(9);
+ RecordInteger c = new RecordInteger(0);
+
+ assertEquals(a.hashCode(), b.hashCode());
+ assertNotEquals(a.hashCode(), c.hashCode());
+ }
+
+ @Test
+ public void testEquals() {
+ RecordInteger a = new RecordInteger(9);
+ RecordInteger b = new RecordInteger(9);
+ RecordInteger c = new RecordInteger(0);
+
+ assertTrue(a.equals(b));
+ assertEquals(a, b);
+ assertFalse(a.equals(c));
+ assertNotEquals(a, c);
+ }
+
+ @Test
+ public void testToString() {
+ RecordInteger a = new RecordInteger(9);
+ RecordInteger b = new RecordInteger(9);
+ RecordInteger c = new RecordInteger(0);
+
+ assertEquals(a.toString(), b.toString());
+ assertNotEquals(a.toString(), c.toString());
+ }
+
+ @Test
+ public void testReflection() {
+ RecordInteger a = new RecordInteger(9);
+
+ Field[] fields = a.getClass().getDeclaredFields();
+ assertEquals(Arrays.deepToString(fields), 1, fields.length);
+ Constructor<?> c = RecordInteger.class.getConstructors()[0];
+ assertEquals(Arrays.deepToString(c.getParameters()), 1, c.getParameters().length);
+ assertEquals(c.getParameters()[0].toString(), "x", c.getParameters()[0].getName());
+ assertEquals(fields[0].toString(), "x", fields[0].getName());
+ assertTrue(a.getClass().isRecord());
+ assertEquals(Arrays.deepToString(a.getClass().getRecordComponents()),
+ 1, a.getClass().getRecordComponents().length);
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/StringTest.java b/luni/src/test/java/libcore/java/lang/StringTest.java
index 0a8ef78..5cce88e 100644
--- a/luni/src/test/java/libcore/java/lang/StringTest.java
+++ b/luni/src/test/java/libcore/java/lang/StringTest.java
@@ -27,6 +27,7 @@
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderMalfunctionError;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;
@@ -94,7 +95,7 @@
// it was given.
s.getBytes(EVIL_CHARSET);
fail(); // We shouldn't have got here!
- } catch (ReadOnlyBufferException expected) {
+ } catch (CoderMalfunctionError expected) {
// We caught you trying to be naughty!
}
}
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java
index 8ea211f..9547a80 100644
--- a/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java
@@ -676,6 +676,17 @@
.toMethodDescriptorString());
}
+ public void testDescriptorString() {
+ assertEquals("(Ljava/lang/String;Ljava/lang/Object;)I", MethodType.methodType(
+ int.class, String.class, Object.class).descriptorString());
+
+ assertEquals("()I", MethodType.methodType(int.class).descriptorString());
+ assertEquals("()[I", MethodType.methodType(int[].class).descriptorString());
+
+ assertEquals("([I)V", MethodType.methodType(void.class, int[].class)
+ .descriptorString());
+ }
+
private static void assertParameterTypes(MethodType type, Class<?>... params) {
assertEquals(params.length, type.parameterCount());
diff --git a/luni/src/test/java/libcore/java/net/ServerSocketTest.java b/luni/src/test/java/libcore/java/net/ServerSocketTest.java
index c368a22..c7b4a12 100644
--- a/luni/src/test/java/libcore/java/net/ServerSocketTest.java
+++ b/luni/src/test/java/libcore/java/net/ServerSocketTest.java
@@ -21,6 +21,8 @@
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
+import java.net.SocketOption;
+import java.net.StandardSocketOptions;
import libcore.junit.junit3.TestCaseWithRules;
import libcore.junit.util.ResourceLeakageDetector;
import org.junit.Rule;
@@ -83,4 +85,30 @@
InetSocketAddress localAddressAfterClose = (InetSocketAddress) ss.getLocalSocketAddress();
assertEquals(boundAddress, localAddressAfterClose);
}
+
+ public void testSetGetOption() throws Exception {
+ try (ServerSocket ss = new ServerSocket()) {
+ ss.setOption(StandardSocketOptions.SO_REUSEADDR, true);
+ assertTrue(ss.getOption(StandardSocketOptions.SO_REUSEADDR));
+
+ ss.setOption(StandardSocketOptions.SO_REUSEADDR, false);
+ assertFalse(ss.getOption(StandardSocketOptions.SO_REUSEADDR));
+ }
+
+ try (ServerSocket ss = new ServerSocket()) {
+ ss.setOption(new SocketOption<>() {
+ @Override
+ public String name() {
+ return "non-existent invalid option";
+ }
+
+ @Override
+ public Class<Boolean> type() {
+ return Boolean.class;
+ }
+ }, true);
+ fail("Expected to fail setting an invalid option");
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/net/URITest.java b/luni/src/test/java/libcore/java/net/URITest.java
index d82a39a..613e919 100644
--- a/luni/src/test/java/libcore/java/net/URITest.java
+++ b/luni/src/test/java/libcore/java/net/URITest.java
@@ -751,5 +751,17 @@
assertFalse(lower.hashCode() == mixed.hashCode());
}
+ // check that "." and "_" characters are allowed in IPv6 scope_id.
+ public void test_JDK6933879() {
+ final String HOST = "fe80::c00:16fe:cebe:3214%eth1.12_55";
+ URI uri;
+ try {
+ uri = new URI("http", null, HOST, 10, "/", null, null);
+ } catch (URISyntaxException ex) {
+ throw new AssertionError("Should not happen", ex);
+ }
+ assertEquals("[" + HOST + "]", uri.getHost());
+ }
+
// Adding a new test? Consider adding an equivalent test to URLTest.java
}
diff --git a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java
index bc8c933..8076bfd 100644
--- a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java
@@ -16,7 +16,14 @@
package libcore.java.nio.channels;
-import org.junit.Rule;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNotNull;
import java.io.IOException;
import java.net.BindException;
@@ -36,14 +43,19 @@
import java.nio.channels.UnsupportedAddressTypeException;
import java.nio.channels.spi.SelectorProvider;
import java.util.Enumeration;
-import libcore.junit.junit3.TestCaseWithRules;
import libcore.junit.util.ResourceLeakageDetector;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
-public class DatagramChannelTest extends TestCaseWithRules {
+@RunWith(JUnit4.class)
+public class DatagramChannelTest {
@Rule
public ResourceLeakageDetector.LeakageDetectorRule guardRule =
ResourceLeakageDetector.getRule();
+ @Test
public void test_read_intoReadOnlyByteArrays() throws Exception {
ByteBuffer readOnly = ByteBuffer.allocate(1).asReadOnlyBuffer();
try (DatagramSocket ds = new DatagramSocket(0);
@@ -68,21 +80,19 @@
}
// http://code.google.com/p/android/issues/detail?id=16579
+ @Test
public void testNonBlockingRecv() throws Exception {
- DatagramChannel dc = DatagramChannel.open();
- try {
+ try (DatagramChannel dc = DatagramChannel.open()) {
dc.configureBlocking(false);
dc.socket().bind(null);
// Should return immediately, since we're non-blocking.
assertNull(dc.receive(ByteBuffer.allocate(2048)));
- } finally {
- dc.close();
}
}
+ @Test
public void testInitialState() throws Exception {
- DatagramChannel dc = DatagramChannel.open();
- try {
+ try (DatagramChannel dc = DatagramChannel.open()) {
DatagramSocket socket = dc.socket();
assertFalse(socket.isBound());
assertFalse(socket.getBroadcast());
@@ -97,11 +107,10 @@
assertFalse(socket.getReuseAddress());
assertSame(dc, socket.getChannel());
- } finally {
- dc.close();
}
}
+ @Test
public void test_bind_unresolvedAddress() throws IOException {
DatagramChannel dc = DatagramChannel.open();
try {
@@ -116,43 +125,51 @@
dc.close();
}
+ @Test
public void test_bind_any_IPv4() throws Exception {
test_bind_any(InetAddress.getByName("0.0.0.0"));
}
+ @Test
public void test_bind_any_IPv6() throws Exception {
test_bind_any(InetAddress.getByName("::"));
}
private void test_bind_any(InetAddress bindAddress) throws Exception {
- DatagramChannel dc = DatagramChannel.open();
- dc.socket().bind(new InetSocketAddress(bindAddress, 0));
+ try (DatagramChannel dc = DatagramChannel.open()) {
+ dc.socket().bind(new InetSocketAddress(bindAddress, 0));
- assertTrue(dc.isOpen());
- assertFalse(dc.isConnected());
+ assertTrue(dc.isOpen());
+ assertFalse(dc.isConnected());
- InetSocketAddress actualAddress = (InetSocketAddress) dc.socket().getLocalSocketAddress();
- assertTrue(actualAddress.getAddress().isAnyLocalAddress());
- assertTrue(actualAddress.getPort() > 0);
-
- dc.close();
+ InetSocketAddress actualAddress = (InetSocketAddress) dc.socket()
+ .getLocalSocketAddress();
+ assertTrue(actualAddress.getAddress().isAnyLocalAddress());
+ assertTrue(actualAddress.getPort() > 0);
+ }
}
+ @Test
public void test_bind_loopback_IPv4() throws Exception {
test_bind(InetAddress.getByName("127.0.0.1"));
}
+ @Test
public void test_bind_loopback_IPv6() throws Exception {
test_bind(InetAddress.getByName("::1"));
}
+ @Test
public void test_bind_IPv4() throws Exception {
InetAddress bindAddress = getNonLoopbackNetworkInterfaceAddress(true /* ipv4 */);
+ assumeNotNull(bindAddress);
test_bind(bindAddress);
}
+ @Test
public void test_bind_IPv6() throws Exception {
InetAddress bindAddress = getNonLoopbackNetworkInterfaceAddress(false /* ipv4 */);
+ assumeNotNull(bindAddress);
test_bind(bindAddress);
}
@@ -166,6 +183,7 @@
}
}
+ @Test
public void test_setOption() throws Exception {
DatagramChannel dc = DatagramChannel.open();
// There were problems in the past as the number used here was below the minimum for
@@ -186,6 +204,7 @@
}
// http://b/26292854
+ @Test
public void test_getFileDescriptor() throws Exception {
try (DatagramSocket socket = DatagramChannel.open().socket()) {
socket.getReuseAddress();
@@ -193,6 +212,7 @@
}
}
+ @Test
public void test_bind() throws IOException {
InetSocketAddress socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
DatagramChannel channel = DatagramChannel.open();
@@ -222,6 +242,7 @@
} catch (ClosedChannelException expected) {}
}
+ @Test
public void test_getRemoteAddress() throws IOException {
InetSocketAddress socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
try (DatagramChannel clientChannel = DatagramChannel.open();
@@ -238,6 +259,7 @@
}
}
+ @Test
public void test_open$java_net_ProtocolFamily() throws IOException {
try (DatagramChannel channel = DatagramChannel.open(StandardProtocolFamily.INET)) {
channel.bind(new InetSocketAddress(Inet4Address.LOOPBACK, 0));
@@ -265,6 +287,7 @@
} catch (NullPointerException expected) {}
}
+ @Test
public void test_closeGuardSupport() throws IOException {
try(DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) {
guardRule.assertUnreleasedResourceCount(dc, 1);
@@ -273,6 +296,7 @@
private static InetAddress getNonLoopbackNetworkInterfaceAddress(boolean ipv4) throws IOException {
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
+ assertNotNull(networkInterfaces);
while (networkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = networkInterfaces.nextElement();
if (networkInterface.isLoopback() || !networkInterface.isUp()) {
diff --git a/luni/src/test/java/libcore/java/util/HexFormatTest.java b/luni/src/test/java/libcore/java/util/HexFormatTest.java
new file mode 100644
index 0000000..a619f74
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/HexFormatTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.java.util;
+
+import java.util.HexFormat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.Before;
+import org.junit.runners.JUnit4;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(JUnit4.class)
+public class HexFormatTest {
+
+ @Test
+ public void toHexDigits_short() {
+ HexFormat hex = HexFormat.of();
+
+ final short shortValue = 0x4321;
+ final String expectedHexDigits = "4321";
+ String actualHexDigits = hex.toHexDigits(shortValue);
+ assertEquals(actualHexDigits, expectedHexDigits);
+
+ int actualInt = HexFormat.fromHexDigits(actualHexDigits);
+ assertTrue(actualInt >= Short.MIN_VALUE && actualInt <= Short.MAX_VALUE);
+ short actualShort = (short) actualInt;
+ assertEquals(actualShort, shortValue);
+ }
+
+}
diff --git a/luni/src/test/java/tests/java/nio/file/attribute/PosixFilePermissionsTest.java b/luni/src/test/java/tests/java/nio/file/attribute/PosixFilePermissionsTest.java
new file mode 100644
index 0000000..5ab7447
--- /dev/null
+++ b/luni/src/test/java/tests/java/nio/file/attribute/PosixFilePermissionsTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package tests.java.nio.file.attribute;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+
+import static java.nio.file.attribute.PosixFilePermission.OWNER_READ;
+import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE;
+import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE;
+import static java.nio.file.attribute.PosixFilePermission.GROUP_READ;
+import static java.nio.file.attribute.PosixFilePermission.GROUP_WRITE;
+import static java.nio.file.attribute.PosixFilePermission.GROUP_EXECUTE;
+import static java.nio.file.attribute.PosixFilePermission.OTHERS_READ;
+import static java.nio.file.attribute.PosixFilePermission.OTHERS_WRITE;
+import static java.nio.file.attribute.PosixFilePermission.OTHERS_EXECUTE;
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Parameterized.class)
+public class PosixFilePermissionsTest {
+
+ @Parameters(name = "perm:{0} str:{1}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][]{
+ // edge cases
+ {"0000", "---------", Set.<PosixFilePermission>of()},
+ {"0777", "rwxrwxrwx", Set.of(PosixFilePermission.values())},
+ // individual bits only
+ {"0400", "r--------", Set.of(OWNER_READ)},
+ {"0200", "-w-------", Set.of(OWNER_WRITE)},
+ {"0100", "--x------", Set.of(OWNER_EXECUTE)},
+ {"0040", "---r-----", Set.of(GROUP_READ)},
+ {"0020", "----w----", Set.of(GROUP_WRITE)},
+ {"0010", "-----x---", Set.of(GROUP_EXECUTE)},
+ {"0004", "------r--", Set.of(OTHERS_READ)},
+ {"0002", "-------w-", Set.of(OTHERS_WRITE)},
+ {"0001", "--------x", Set.of(OTHERS_EXECUTE)},
+ // only owner/group/others
+ {"0700", "rwx------", Set.of(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE)},
+ {"0070", "---rwx---", Set.of(GROUP_READ, GROUP_WRITE, GROUP_EXECUTE)},
+ {"0007", "------rwx", Set.of(OTHERS_READ, OTHERS_WRITE, OTHERS_EXECUTE)},
+ // all only r/w/x
+ {"0444", "r--r--r--", Set.of(OWNER_READ, GROUP_READ, OTHERS_READ)},
+ {"0222", "-w--w--w-", Set.of(OWNER_WRITE, GROUP_WRITE, OTHERS_WRITE)},
+ {"0111", "--x--x--x", Set.of(OWNER_EXECUTE, GROUP_EXECUTE, OTHERS_EXECUTE)},
+ // all only rw/rx/wx
+ {"0666", "rw-rw-rw-", Set.of(OWNER_READ, OWNER_WRITE, GROUP_READ, GROUP_WRITE,
+ OTHERS_READ, OTHERS_WRITE)},
+ {"0555", "r-xr-xr-x", Set.of(OWNER_READ, OWNER_EXECUTE, GROUP_READ, GROUP_EXECUTE,
+ OTHERS_READ, OTHERS_EXECUTE)},
+ {"0333", "-wx-wx-wx", Set.of(OWNER_WRITE, OWNER_EXECUTE, GROUP_WRITE, GROUP_EXECUTE,
+ OTHERS_WRITE, OTHERS_EXECUTE)},
+ // misc
+ {"0755", "rwxr-xr-x", Set.of(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE,
+ GROUP_READ, GROUP_EXECUTE,
+ OTHERS_READ, OTHERS_EXECUTE)},
+ {"0750", "rwxr-x---", Set.of(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE,
+ GROUP_READ, GROUP_EXECUTE)},
+ {"0644", "rw-r--r--", Set.of(OWNER_READ, OWNER_WRITE, GROUP_READ, OTHERS_READ)},
+ });
+ }
+
+ /**
+ * Permission value being tested in *nix format, e.g. 0755 or 0666.
+ */
+ @Parameter
+ public String perm;
+
+ @Parameter(1)
+ public String asString;
+
+ @Parameter(2)
+ public Set<PosixFilePermission> asSet;
+
+ @Test
+ public void test_asFileAttribute() {
+ Set<PosixFilePermission> input = asSet;
+ var asFileAttribute = PosixFilePermissions.asFileAttribute(input);
+ assertEquals("posix:permissions", asFileAttribute.name());
+ assertEquals(input, asFileAttribute.value());
+ }
+
+ @Test
+ public void test_fromString() {
+ String input = asString;
+ Set<PosixFilePermission> actual = PosixFilePermissions.fromString(input);
+ Set<PosixFilePermission> expected = asSet;
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void test_toString() {
+ Set<PosixFilePermission> input = asSet;
+ String actual = PosixFilePermissions.toString(input);
+ String expected = asString;
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void roundtrip() {
+ { // toString ∘ fromString = id
+ String input = asString;
+
+ var convertForward = PosixFilePermissions.fromString(input);
+ var actual = PosixFilePermissions.toString(convertForward);
+ assertEquals(asString, actual);
+ }
+
+ { // fromString ∘ toString = id
+ Set<PosixFilePermission> input = asSet;
+
+ var convertForward = PosixFilePermissions.toString(input);
+ var actual = PosixFilePermissions.fromString(convertForward);
+ assertEquals(asSet, actual);
+ }
+ }
+}
diff --git a/luni/src/test/java/tests/security/interfaces/RSAKeyTest.java b/luni/src/test/java/tests/security/interfaces/RSAKeyTest.java
index 9f2830d..619a2ad 100644
--- a/luni/src/test/java/tests/security/interfaces/RSAKeyTest.java
+++ b/luni/src/test/java/tests/security/interfaces/RSAKeyTest.java
@@ -47,4 +47,15 @@
key = (RSAKey) gen.generatePublic(new RSAPublicKeySpec(n, e));
assertEquals("invalid modulus", n, key.getModulus());
}
+
+ public void test_getParams() {
+ assertNull(new NoopRSAKey().getParams());
+ }
+
+ private class NoopRSAKey implements RSAKey {
+ @Override
+ public BigInteger getModulus() {
+ return null;
+ }
+ }
}
diff --git a/luni/src/test/java/tests/targets/security/cert/CertificateTest.java b/luni/src/test/java/tests/targets/security/cert/CertificateTest.java
index eebf2ca..d9a306f 100644
--- a/luni/src/test/java/tests/targets/security/cert/CertificateTest.java
+++ b/luni/src/test/java/tests/targets/security/cert/CertificateTest.java
@@ -15,747 +15,283 @@
*/
package tests.targets.security.cert;
-import java.io.ByteArrayInputStream;
-import java.security.KeyStore;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import java.io.InputStream;
+import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
import java.security.Provider;
import java.security.Security;
+import java.security.SignatureException;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorResult;
-import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.PKIXCertPathValidatorResult;
import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
-import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
-import libcore.java.security.StandardNames;
-import libcore.junit.junit3.TestCaseWithRules;
-import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
-import org.junit.Rule;
-import org.junit.rules.TestRule;
+import java.util.Set;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
-public class CertificateTest extends TestCaseWithRules {
-
- // Allow access to deprecated BC algorithms in this test, so we can ensure they
- // continue to work
- @Rule
- public TestRule enableDeprecatedBCAlgorithmsRule =
- EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+/*
+ * Tests for CertPathValidator with deprecated certificate types. Verifies that the public
+ * CertPath APIs can continue to process them even after they are rejected
+ * by the platform for TLS purposes.
+ *
+ * Expectations:
+ * * MD2-signed - always unsupported.
+ * * MD5-signed - depending on the version of the Conscrypt module, may be supported.
+ * * SHA1-signed - always supported.
+ *
+ * A supported certificate should always allow a CertPath rooted at that certificate to
+ * validate correctly.
+ *
+ * TODO: Should also test non-deprecated certificate types, but that is effectively covered
+ * by TLS tests.
+ */
+@RunWith(JUnit4.class)
+public class CertificateTest {
+ private final CertificateFactory certificateFactory = onlyX509CertificateFactory();
/*
- * Following certificate chain was taken from https://www.verisign.com and
- * uses MD2withRSA for the root certificate. This chain stops validating
- * in Nov 2016.
- */
-
- /**
- * A selfsigned certificate using MD2withRSA
+ * A self=signed certificate using MD2: https://crt.sh/?id=162
*
- * <pre>
- * Certificate:
- * Data:
- * Version: 1 (0x0)
- * Serial Number:
- * 70:ba:e4:1d:10:d9:29:34:b6:38:ca:7b:03:cc:ba:bf
* Signature Algorithm: md2WithRSAEncryption
- * Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority
+ * Issuer: C = US, O = "VeriSign, Inc.", OU = Class 3 Public Primary Certification Authority
* Validity
* Not Before: Jan 29 00:00:00 1996 GMT
* Not After : Aug 1 23:59:59 2028 GMT
- * Subject: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority
- * Subject Public Key Info:
- * Public Key Algorithm: rsaEncryption
- * RSA Public Key: (1024 bit)
- * Modulus (1024 bit):
- * 00:c9:5c:59:9e:f2:1b:8a:01:14:b4:10:df:04:40:
- * db:e3:57:af:6a:45:40:8f:84:0c:0b:d1:33:d9:d9:
- * 11:cf:ee:02:58:1f:25:f7:2a:a8:44:05:aa:ec:03:
- * 1f:78:7f:9e:93:b9:9a:00:aa:23:7d:d6:ac:85:a2:
- * 63:45:c7:72:27:cc:f4:4c:c6:75:71:d2:39:ef:4f:
- * 42:f0:75:df:0a:90:c6:8e:20:6f:98:0f:f8:ac:23:
- * 5f:70:29:36:a4:c9:86:e7:b1:9a:20:cb:53:a5:85:
- * e7:3d:be:7d:9a:fe:24:45:33:dc:76:15:ed:0f:a2:
- * 71:64:4c:65:2e:81:68:45:a7
- * Exponent: 65537 (0x10001)
- * Signature Algorithm: md2WithRSAEncryption
- * bb:4c:12:2b:cf:2c:26:00:4f:14:13:dd:a6:fb:fc:0a:11:84:
- * 8c:f3:28:1c:67:92:2f:7c:b6:c5:fa:df:f0:e8:95:bc:1d:8f:
- * 6c:2c:a8:51:cc:73:d8:a4:c0:53:f0:4e:d6:26:c0:76:01:57:
- * 81:92:5e:21:f1:d1:b1:ff:e7:d0:21:58:cd:69:17:e3:44:1c:
- * 9c:19:44:39:89:5c:dc:9c:00:0f:56:8d:02:99:ed:a2:90:45:
- * 4c:e4:bb:10:a4:3d:f0:32:03:0e:f1:ce:f8:e8:c9:51:8c:e6:
- * 62:9f:e6:9f:c0:7d:b7:72:9c:c9:36:3a:6b:9f:4e:a8:ff:64:
- * 0d:64
- * </pre>
+ * Subject: C = US, O = "VeriSign, Inc.", OU = Class 3 Public Primary Certification Authority
*/
- private static final String selfSignedCertMD2 =
- "-----BEGIN CERTIFICATE-----\n"
- + "MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG\n"
- + "A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz\n"
- + "cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2\n"
- + "MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV\n"
- + "BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt\n"
- + "YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN\n"
- + "ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE\n"
- + "BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is\n"
- + "I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G\n"
- + "CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do\n"
- + "lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc\n"
- + "AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k\n"
- + "-----END CERTIFICATE-----\n";
-
- /**
- * A certificate signed by selfSignedCertMD2
- *
- * <pre>
- * Certificate:
- * Data:
- * Version: 3 (0x2)
- * Serial Number:
- * 57:bf:fb:03:fb:2c:46:d4:e1:9e:ce:e0:d7:43:7f:13
- * Signature Algorithm: sha1WithRSAEncryption
- * Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority
- * Validity
- * Not Before: Nov 8 00:00:00 2006 GMT
- * Not After : Nov 7 23:59:59 2021 GMT
- * Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5
- * Subject Public Key Info:
- * Public Key Algorithm: rsaEncryption
- * RSA Public Key: (2048 bit)
- * Modulus (2048 bit):
- * 00:af:24:08:08:29:7a:35:9e:60:0c:aa:e7:4b:3b:
- * 4e:dc:7c:bc:3c:45:1c:bb:2b:e0:fe:29:02:f9:57:
- * 08:a3:64:85:15:27:f5:f1:ad:c8:31:89:5d:22:e8:
- * 2a:aa:a6:42:b3:8f:f8:b9:55:b7:b1:b7:4b:b3:fe:
- * 8f:7e:07:57:ec:ef:43:db:66:62:15:61:cf:60:0d:
- * a4:d8:de:f8:e0:c3:62:08:3d:54:13:eb:49:ca:59:
- * 54:85:26:e5:2b:8f:1b:9f:eb:f5:a1:91:c2:33:49:
- * d8:43:63:6a:52:4b:d2:8f:e8:70:51:4d:d1:89:69:
- * 7b:c7:70:f6:b3:dc:12:74:db:7b:5d:4b:56:d3:96:
- * bf:15:77:a1:b0:f4:a2:25:f2:af:1c:92:67:18:e5:
- * f4:06:04:ef:90:b9:e4:00:e4:dd:3a:b5:19:ff:02:
- * ba:f4:3c:ee:e0:8b:eb:37:8b:ec:f4:d7:ac:f2:f6:
- * f0:3d:af:dd:75:91:33:19:1d:1c:40:cb:74:24:19:
- * 21:93:d9:14:fe:ac:2a:52:c7:8f:d5:04:49:e4:8d:
- * 63:47:88:3c:69:83:cb:fe:47:bd:2b:7e:4f:c5:95:
- * ae:0e:9d:d4:d1:43:c0:67:73:e3:14:08:7e:e5:3f:
- * 9f:73:b8:33:0a:cf:5d:3f:34:87:96:8a:ee:53:e8:
- * 25:15
- * Exponent: 65537 (0x10001)
- * X509v3 extensions:
- * X509v3 Basic Constraints: critical
- * CA:TRUE
- * X509v3 CRL Distribution Points:
- * URI:http://crl.verisign.com/pca3.crl
- * X509v3 Key Usage: critical
- * Certificate Sign, CRL Sign
- * 1.3.6.1.5.5.7.1.12:
- * 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif
- * X509v3 Certificate Policies:
- * Policy: X509v3 Any Policy
- * CPS: https://www.verisign.com/cps
- * X509v3 Subject Key Identifier:
- * 7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33
- * X509v3 Extended Key Usage:
- * Netscape Server Gated Crypto, 2.16.840.1.113733.1.8.1, TLS Web Server Authentication, TLS Web Client Authentication
- * X509v3 Authority Key Identifier:
- * DirName:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
- * serial:70:BA:E4:1D:10:D9:29:34:B6:38:CA:7B:03:CC:BA:BF
- * Signature Algorithm: sha1WithRSAEncryption
- * a9:7b:66:29:30:f7:d5:b4:a6:96:12:d0:ee:72:f0:58:11:69:
- * 15:55:5f:41:ff:d2:12:84:13:a4:d9:03:66:ff:a9:e0:4c:c9:
- * ed:8c:72:8b:b4:d7:55:3b:29:15:60:c8:3c:21:ef:44:2e:93:
- * 3d:c6:0b:0c:8d:24:3f:1e:fb:01:5a:7a:dd:83:66:14:d1:c7:
- * fd:30:53:48:51:85:85:13:a8:54:e1:ee:76:a2:89:18:d3:97:
- * 89:7a:c6:fd:b3:bd:94:61:5a:3a:08:cf:14:93:bd:93:fd:09:
- * a9:7b:56:c8:00:b8:44:58:e9:de:5b:77:bd:07:1c:6c:0b:30:
- * 30:c7
- * </pre>
- */
- private static final String signedCert1Chain1 =
- "-----BEGIN CERTIFICATE-----\n"
- + "MIIFEzCCBHygAwIBAgIQV7/7A/ssRtThns7g10N/EzANBgkqhkiG9w0BAQUFADBf\n"
- + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT\n"
- + "LkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw\n"
- + "HhcNMDYxMTA4MDAwMDAwWhcNMjExMTA3MjM1OTU5WjCByjELMAkGA1UEBhMCVVMx\n"
- + "FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz\n"
- + "dCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZv\n"
- + "ciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAz\n"
- + "IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEi\n"
- + "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8\n"
- + "RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbext0uz/o9+B1fs70Pb\n"
- + "ZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhDY2pSS9KP6HBR\n"
- + "TdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/\n"
- + "Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNH\n"
- + "iDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMB\n"
- + "AAGjggHeMIIB2jAPBgNVHRMBAf8EBTADAQH/MDEGA1UdHwQqMCgwJqAkoCKGIGh0\n"
- + "dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMuY3JsMA4GA1UdDwEB/wQEAwIBBjBt\n"
- + "BggrBgEFBQcBDARhMF+hXaBbMFkwVzBVFglpbWFnZS9naWYwITAfMAcGBSsOAwIa\n"
- + "BBSP5dMahqyNjmvDz4Bq1EgYLHsZLjAlFiNodHRwOi8vbG9nby52ZXJpc2lnbi5j\n"
- + "b20vdnNsb2dvLmdpZjA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYc\n"
- + "aHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL2NwczAdBgNVHQ4EFgQUf9Nlp8Ld7Lvw\n"
- + "MAnzQzn6Aq8zMTMwNAYDVR0lBC0wKwYJYIZIAYb4QgQBBgpghkgBhvhFAQgBBggr\n"
- + "BgEFBQcDAQYIKwYBBQUHAwIwgYAGA1UdIwR5MHehY6RhMF8xCzAJBgNVBAYTAlVT\n"
- + "MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMyBQdWJs\n"
- + "aWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eYIQcLrkHRDZKTS2OMp7\n"
- + "A8y6vzANBgkqhkiG9w0BAQUFAAOBgQCpe2YpMPfVtKaWEtDucvBYEWkVVV9B/9IS\n"
- + "hBOk2QNm/6ngTMntjHKLtNdVOykVYMg8Ie9ELpM9xgsMjSQ/HvsBWnrdg2YU0cf9\n"
- + "MFNIUYWFE6hU4e52ookY05eJesb9s72UYVo6CM8Uk72T/Qmpe1bIALhEWOneW3e9\n"
- + "BxxsCzAwxw==\n"
- + "-----END CERTIFICATE-----";
-
- /**
- * A certificate signed by signedCert1Chain1
- *
- * <pre>
- * Certificate:
- * Data:
- * Version: 3 (0x2)
- * Serial Number:
- * 11:2a:00:6d:37:e5:10:6f:d6:ca:7c:c3:ef:ba:cc:18
- * Signature Algorithm: sha1WithRSAEncryption
- * Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5
- * Validity
- * Not Before: Nov 8 00:00:00 2006 GMT
- * Not After : Nov 7 23:59:59 2016 GMT
- * Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=Terms of use at https://www.verisign.com/rpa (c)06, CN=VeriSign Class 3 Extended Validation SSL SGC CA
- * Subject Public Key Info:
- * Public Key Algorithm: rsaEncryption
- * RSA Public Key: (2048 bit)
- * Modulus (2048 bit):
- * 00:bd:56:88:ba:88:34:64:64:cf:cd:ca:b0:ee:e7:
- * 19:73:c5:72:d9:bb:45:bc:b5:a8:ff:83:be:1c:03:
- * db:ed:89:b7:2e:10:1a:25:bc:55:ca:41:a1:9f:0b:
- * cf:19:5e:70:b9:5e:39:4b:9e:31:1c:5f:87:ae:2a:
- * aa:a8:2b:a2:1b:3b:10:23:5f:13:b1:dd:08:8c:4e:
- * 14:da:83:81:e3:b5:8c:e3:68:ed:24:67:ce:56:b6:
- * ac:9b:73:96:44:db:8a:8c:b3:d6:f0:71:93:8e:db:
- * 71:54:4a:eb:73:59:6a:8f:70:51:2c:03:9f:97:d1:
- * cc:11:7a:bc:62:0d:95:2a:c9:1c:75:57:e9:f5:c7:
- * ea:ba:84:35:cb:c7:85:5a:7e:e4:4d:e1:11:97:7d:
- * 0e:20:34:45:db:f1:a2:09:eb:eb:3d:9e:b8:96:43:
- * 5e:34:4b:08:25:1e:43:1a:a2:d9:b7:8a:01:34:3d:
- * c3:f8:e5:af:4f:8c:ff:cd:65:f0:23:4e:c5:97:b3:
- * 5c:da:90:1c:82:85:0d:06:0d:c1:22:b6:7b:28:a4:
- * 03:c3:4c:53:d1:58:bc:72:bc:08:39:fc:a0:76:a8:
- * a8:e9:4b:6e:88:3d:e3:b3:31:25:8c:73:29:48:0e:
- * 32:79:06:ed:3d:43:f4:f6:e4:e9:fc:7d:be:8e:08:
- * d5:1f
- * Exponent: 65537 (0x10001)
- * X509v3 extensions:
- * X509v3 Subject Key Identifier:
- * 4E:43:C8:1D:76:EF:37:53:7A:4F:F2:58:6F:94:F3:38:E2:D5:BD:DF
- * X509v3 Basic Constraints: critical
- * CA:TRUE, pathlen:0
- * X509v3 Certificate Policies:
- * Policy: X509v3 Any Policy
- * CPS: https://www.verisign.com/cps
- * X509v3 CRL Distribution Points:
- * URI:http://EVSecure-crl.verisign.com/pca3-g5.crl
- * X509v3 Extended Key Usage:
- * Netscape Server Gated Crypto, 2.16.840.1.113733.1.8.1
- * X509v3 Key Usage: critical
- * Certificate Sign, CRL Sign
- * Netscape Cert Type:
- * SSL CA, S/MIME CA
- * 1.3.6.1.5.5.7.1.12:
- * 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif
- * X509v3 Subject Alternative Name:
- * DirName:/CN=Class3CA2048-1-48
- * Authority Information Access:
- * OCSP - URI:http://EVSecure-ocsp.verisign.com
- * X509v3 Authority Key Identifier:
- * keyid:7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33
- * Signature Algorithm: sha1WithRSAEncryption
- * 5a:a2:b1:bf:eb:8d:d4:38:a8:80:72:c2:dc:38:2e:ac:a7:71:
- * f9:2b:a3:bb:47:bb:6d:69:6f:10:36:98:8c:c7:56:2e:bb:bc:
- * ab:4a:9b:7a:d6:f2:82:93:e0:14:fe:8a:ce:83:b7:83:db:93:
- * 87:ab:ac:65:79:49:fd:57:a9:b1:ce:09:1f:ba:10:15:c4:09:
- * 0e:62:e3:f9:0a:25:d5:64:98:f0:f2:a8:0f:76:32:7e:91:e6:
- * 18:ee:bc:e7:da:d0:4e:8d:78:bb:e2:9d:c0:59:2b:c0:ce:95:
- * 0d:24:0c:72:ca:34:5e:70:22:89:2b:4a:b0:f1:68:87:f3:ee:
- * 44:8d:28:40:77:39:6e:48:72:45:31:5d:6b:39:0e:86:02:ea:
- * 66:99:93:31:0f:df:67:de:a6:9f:8c:9d:4c:ce:71:6f:3a:21:
- * f6:b9:34:3f:f9:6e:d8:9a:f7:3e:da:f3:81:5f:7a:5c:6d:8f:
- * 7c:f6:99:74:b7:ff:e4:17:5d:ed:61:5e:ab:48:bb:96:8d:66:
- * 45:39:b4:12:0a:f6:70:e9:9c:76:22:4b:60:e9:2a:1b:34:49:
- * f7:a2:d4:67:c0:b1:26:ad:13:ba:d9:84:01:c1:ab:e1:8e:6d:
- * 70:16:3b:77:ac:91:9a:bb:1a:1f:da:58:a7:e4:4f:c1:61:ae:
- * bc:a2:fe:4b
- * </pre>
- */
- private static final String signedCert2Chain1 =
- "-----BEGIN CERTIFICATE-----\n"
- + "MIIGCjCCBPKgAwIBAgIQESoAbTflEG/WynzD77rMGDANBgkqhkiG9w0BAQUFADCB\n"
- + "yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\n"
- + "ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp\n"
- + "U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW\n"
- + "ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0\n"
- + "aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMTYxMTA3MjM1OTU5WjCBvjEL\n"
- + "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW\n"
- + "ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQg\n"
- + "aHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYSAoYykwNjE4MDYGA1UEAxMvVmVy\n"
- + "aVNpZ24gQ2xhc3MgMyBFeHRlbmRlZCBWYWxpZGF0aW9uIFNTTCBTR0MgQ0EwggEi\n"
- + "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9Voi6iDRkZM/NyrDu5xlzxXLZ\n"
- + "u0W8taj/g74cA9vtibcuEBolvFXKQaGfC88ZXnC5XjlLnjEcX4euKqqoK6IbOxAj\n"
- + "XxOx3QiMThTag4HjtYzjaO0kZ85Wtqybc5ZE24qMs9bwcZOO23FUSutzWWqPcFEs\n"
- + "A5+X0cwRerxiDZUqyRx1V+n1x+q6hDXLx4VafuRN4RGXfQ4gNEXb8aIJ6+s9nriW\n"
- + "Q140SwglHkMaotm3igE0PcP45a9PjP/NZfAjTsWXs1zakByChQ0GDcEitnsopAPD\n"
- + "TFPRWLxyvAg5/KB2qKjpS26IPeOzMSWMcylIDjJ5Bu09Q/T25On8fb6OCNUfAgMB\n"
- + "AAGjggH0MIIB8DAdBgNVHQ4EFgQUTkPIHXbvN1N6T/JYb5TzOOLVvd8wEgYDVR0T\n"
- + "AQH/BAgwBgEB/wIBADA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYc\n"
- + "aHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL2NwczA9BgNVHR8ENjA0MDKgMKAuhixo\n"
- + "dHRwOi8vRVZTZWN1cmUtY3JsLnZlcmlzaWduLmNvbS9wY2EzLWc1LmNybDAgBgNV\n"
- + "HSUEGTAXBglghkgBhvhCBAEGCmCGSAGG+EUBCAEwDgYDVR0PAQH/BAQDAgEGMBEG\n"
- + "CWCGSAGG+EIBAQQEAwIBBjBtBggrBgEFBQcBDARhMF+hXaBbMFkwVzBVFglpbWFn\n"
- + "ZS9naWYwITAfMAcGBSsOAwIaBBSP5dMahqyNjmvDz4Bq1EgYLHsZLjAlFiNodHRw\n"
- + "Oi8vbG9nby52ZXJpc2lnbi5jb20vdnNsb2dvLmdpZjApBgNVHREEIjAgpB4wHDEa\n"
- + "MBgGA1UEAxMRQ2xhc3MzQ0EyMDQ4LTEtNDgwPQYIKwYBBQUHAQEEMTAvMC0GCCsG\n"
- + "AQUFBzABhiFodHRwOi8vRVZTZWN1cmUtb2NzcC52ZXJpc2lnbi5jb20wHwYDVR0j\n"
- + "BBgwFoAUf9Nlp8Ld7LvwMAnzQzn6Aq8zMTMwDQYJKoZIhvcNAQEFBQADggEBAFqi\n"
- + "sb/rjdQ4qIBywtw4Lqyncfkro7tHu21pbxA2mIzHVi67vKtKm3rW8oKT4BT+is6D\n"
- + "t4Pbk4errGV5Sf1XqbHOCR+6EBXECQ5i4/kKJdVkmPDyqA92Mn6R5hjuvOfa0E6N\n"
- + "eLvincBZK8DOlQ0kDHLKNF5wIokrSrDxaIfz7kSNKEB3OW5IckUxXWs5DoYC6maZ\n"
- + "kzEP32fepp+MnUzOcW86Ifa5ND/5btia9z7a84Ffelxtj3z2mXS3/+QXXe1hXqtI\n"
- + "u5aNZkU5tBIK9nDpnHYiS2DpKhs0Sfei1GfAsSatE7rZhAHBq+GObXAWO3eskZq7\n"
- + "Gh/aWKfkT8Fhrryi/ks=\n"
- + "-----END CERTIFICATE-----";
+ private final X509Certificate md2Root = loadCertificate("md2Root.pem");
/*
- * Following certificate chain was taken from https://www.thawte.com and
- * uses MD5withRSA for the root certificate. This chain stops validating
- * in Nov 2016.
- */
-
- /**
- * A selfsigned certificate using MD5withRSA
+ * A self-signed certificate using MD5withRSA: https://crt.sh/?id=20
*
- * <pre>
- * Certificate:
- * Data:
- * Version: 3 (0x2)
- * Serial Number: 1 (0x1)
* Signature Algorithm: md5WithRSAEncryption
- * Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com
+ * Issuer: C = ZA, ST = Western Cape, L = Cape Town, O = Thawte Consulting cc, OU = Certification Services Division, CN = Thawte Premium Server CA, emailAddress = premium-server@thawte.com
* Validity
* Not Before: Aug 1 00:00:00 1996 GMT
* Not After : Dec 31 23:59:59 2020 GMT
- * Subject: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com
- * Subject Public Key Info:
- * Public Key Algorithm: rsaEncryption
- * RSA Public Key: (1024 bit)
- * Modulus (1024 bit):
- * 00:d2:36:36:6a:8b:d7:c2:5b:9e:da:81:41:62:8f:
- * 38:ee:49:04:55:d6:d0:ef:1c:1b:95:16:47:ef:18:
- * 48:35:3a:52:f4:2b:6a:06:8f:3b:2f:ea:56:e3:af:
- * 86:8d:9e:17:f7:9e:b4:65:75:02:4d:ef:cb:09:a2:
- * 21:51:d8:9b:d0:67:d0:ba:0d:92:06:14:73:d4:93:
- * cb:97:2a:00:9c:5c:4e:0c:bc:fa:15:52:fc:f2:44:
- * 6e:da:11:4a:6e:08:9f:2f:2d:e3:f9:aa:3a:86:73:
- * b6:46:53:58:c8:89:05:bd:83:11:b8:73:3f:aa:07:
- * 8d:f4:42:4d:e7:40:9d:1c:37
- * Exponent: 65537 (0x10001)
- * X509v3 extensions:
- * X509v3 Basic Constraints: critical
- * CA:TRUE
- * Signature Algorithm: md5WithRSAEncryption
- * 26:48:2c:16:c2:58:fa:e8:16:74:0c:aa:aa:5f:54:3f:f2:d7:
- * c9:78:60:5e:5e:6e:37:63:22:77:36:7e:b2:17:c4:34:b9:f5:
- * 08:85:fc:c9:01:38:ff:4d:be:f2:16:42:43:e7:bb:5a:46:fb:
- * c1:c6:11:1f:f1:4a:b0:28:46:c9:c3:c4:42:7d:bc:fa:ab:59:
- * 6e:d5:b7:51:88:11:e3:a4:85:19:6b:82:4c:a4:0c:12:ad:e9:
- * a4:ae:3f:f1:c3:49:65:9a:8c:c5:c8:3e:25:b7:94:99:bb:92:
- * 32:71:07:f0:86:5e:ed:50:27:a6:0d:a6:23:f9:bb:cb:a6:07:
- * 14:42
- * </pre>
+ * Subject: C = ZA, ST = Western Cape, L = Cape Town, O = Thawte Consulting cc, OU = Certification Services Division, CN = Thawte Premium Server CA, emailAddress = premium-server@thawte.com
*/
- private static final String selfSignedCertMD5 =
- "-----BEGIN CERTIFICATE-----\n"
- + "MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx\n"
- + "FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD\n"
- + "VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv\n"
- + "biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy\n"
- + "dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t\n"
- + "MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB\n"
- + "MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG\n"
- + "A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp\n"
- + "b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl\n"
- + "cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv\n"
- + "bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE\n"
- + "VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ\n"
- + "ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR\n"
- + "uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG\n"
- + "9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI\n"
- + "hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM\n"
- + "pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==\n"
- + "-----END CERTIFICATE-----";
-
- /**
- * A certificate signed by selfSignedCertMD5
+ private final X509Certificate md5ChainRoot = loadCertificate("md5ChainRoot.pem");
+ /*
+ * An intermediate certificate signed by md5ChainRoot: https://crt.sh/?id=845934
*
- * <pre>
- * Certificate:
- * Data:
- * Version: 3 (0x2)
- * Serial Number:
- * 5f:a6:be:80:b6:86:c6:2f:01:ed:0c:ab:b1:96:a1:05
* Signature Algorithm: sha1WithRSAEncryption
- * Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com
+ * Issuer: C = ZA, ST = Western Cape, L = Cape Town, O = Thawte Consulting cc, OU = Certification Services Division, CN = Thawte Premium Server CA, emailAddress = premium-server@thawte.com
* Validity
* Not Before: Nov 17 00:00:00 2006 GMT
* Not After : Dec 30 23:59:59 2020 GMT
- * Subject: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA
- * Subject Public Key Info:
- * Public Key Algorithm: rsaEncryption
- * RSA Public Key: (2048 bit)
- * Modulus (2048 bit):
- * 00:ac:a0:f0:fb:80:59:d4:9c:c7:a4:cf:9d:a1:59:
- * 73:09:10:45:0c:0d:2c:6e:68:f1:6c:5b:48:68:49:
- * 59:37:fc:0b:33:19:c2:77:7f:cc:10:2d:95:34:1c:
- * e6:eb:4d:09:a7:1c:d2:b8:c9:97:36:02:b7:89:d4:
- * 24:5f:06:c0:cc:44:94:94:8d:02:62:6f:eb:5a:dd:
- * 11:8d:28:9a:5c:84:90:10:7a:0d:bd:74:66:2f:6a:
- * 38:a0:e2:d5:54:44:eb:1d:07:9f:07:ba:6f:ee:e9:
- * fd:4e:0b:29:f5:3e:84:a0:01:f1:9c:ab:f8:1c:7e:
- * 89:a4:e8:a1:d8:71:65:0d:a3:51:7b:ee:bc:d2:22:
- * 60:0d:b9:5b:9d:df:ba:fc:51:5b:0b:af:98:b2:e9:
- * 2e:e9:04:e8:62:87:de:2b:c8:d7:4e:c1:4c:64:1e:
- * dd:cf:87:58:ba:4a:4f:ca:68:07:1d:1c:9d:4a:c6:
- * d5:2f:91:cc:7c:71:72:1c:c5:c0:67:eb:32:fd:c9:
- * 92:5c:94:da:85:c0:9b:bf:53:7d:2b:09:f4:8c:9d:
- * 91:1f:97:6a:52:cb:de:09:36:a4:77:d8:7b:87:50:
- * 44:d5:3e:6e:29:69:fb:39:49:26:1e:09:a5:80:7b:
- * 40:2d:eb:e8:27:85:c9:fe:61:fd:7e:e6:7c:97:1d:
- * d5:9d
- * Exponent: 65537 (0x10001)
- * X509v3 extensions:
- * X509v3 Basic Constraints: critical
- * CA:TRUE
- * X509v3 Certificate Policies:
- * Policy: X509v3 Any Policy
- * CPS: https://www.thawte.com/cps
- * X509v3 Key Usage: critical
- * Certificate Sign, CRL Sign
- * X509v3 Subject Key Identifier:
- * 7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50
- * X509v3 CRL Distribution Points:
- * URI:http://crl.thawte.com/ThawtePremiumServerCA.crl
- * X509v3 Extended Key Usage:
- * Netscape Server Gated Crypto, 2.16.840.1.113733.1.8.1
- * X509v3 Authority Key Identifier:
- * DirName:/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com
- * serial:01
- * Signature Algorithm: sha1WithRSAEncryption
- * 2b:ca:12:c9:dd:d7:cc:63:1c:9b:31:35:4a:dd:e4:b7:f6:9d:
- * d1:a4:fb:1e:f8:47:f9:ae:07:8e:0d:58:12:fb:da:ed:b5:cc:
- * 33:e5:97:68:47:61:42:d5:66:a9:6e:1e:47:bf:85:db:7d:58:
- * d1:77:5a:cc:90:61:98:9a:29:f5:9d:b1:cf:b8:dc:f3:7b:80:
- * 47:48:d1:7d:f4:68:8c:c4:41:cb:b4:e9:fd:f0:23:e0:b1:9b:
- * 76:2a:6d:28:56:a3:8c:cd:e9:ec:21:00:71:f0:5f:dd:50:a5:
- * 69:42:1b:83:11:5d:84:28:d3:27:ae:ec:2a:ab:2f:60:42:c5:
- * c4:78
- * </pre>
+ * Subject: C = US, O = "thawte, Inc.", OU = Certification Services Division, OU = "(c) 2006 thawte, Inc. - For authorized use only", CN = thawte Primary Root CA
*/
- private static final String signedCert1Chain2 =
- "-----BEGIN CERTIFICATE-----\n"
- + "MIIFUTCCBLqgAwIBAgIQX6a+gLaGxi8B7QyrsZahBTANBgkqhkiG9w0BAQUFADCB\n"
- + "zjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ\n"
- + "Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE\n"
- + "CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhh\n"
- + "d3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl\n"
- + "cnZlckB0aGF3dGUuY29tMB4XDTA2MTExNzAwMDAwMFoXDTIwMTIzMDIzNTk1OVow\n"
- + "gakxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUsIEluYy4xKDAmBgNVBAsT\n"
- + "H0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xODA2BgNVBAsTLyhjKSAy\n"
- + "MDA2IHRoYXd0ZSwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYD\n"
- + "VQQDExZ0aGF3dGUgUHJpbWFyeSBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\n"
- + "AQ8AMIIBCgKCAQEArKDw+4BZ1JzHpM+doVlzCRBFDA0sbmjxbFtIaElZN/wLMxnC\n"
- + "d3/MEC2VNBzm600JpxzSuMmXNgK3idQkXwbAzESUlI0CYm/rWt0RjSiaXISQEHoN\n"
- + "vXRmL2o4oOLVVETrHQefB7pv7un9Tgsp9T6EoAHxnKv4HH6JpOih2HFlDaNRe+68\n"
- + "0iJgDblbnd+6/FFbC6+Ysuku6QToYofeK8jXTsFMZB7dz4dYukpPymgHHRydSsbV\n"
- + "L5HMfHFyHMXAZ+sy/cmSXJTahcCbv1N9Kwn0jJ2RH5dqUsveCTakd9h7h1BE1T5u\n"
- + "KWn7OUkmHgmlgHtALevoJ4XJ/mH9fuZ8lx3VnQIDAQABo4IBzTCCAckwDwYDVR0T\n"
- + "AQH/BAUwAwEB/zA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0\n"
- + "cHM6Ly93d3cudGhhd3RlLmNvbS9jcHMwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQW\n"
- + "BBR7W0XPr87Lev0xkhpqtvNG61dIUDBABgNVHR8EOTA3MDWgM6Axhi9odHRwOi8v\n"
- + "Y3JsLnRoYXd0ZS5jb20vVGhhd3RlUHJlbWl1bVNlcnZlckNBLmNybDAgBgNVHSUE\n"
- + "GTAXBglghkgBhvhCBAEGCmCGSAGG+EUBCAEwgeUGA1UdIwSB3TCB2qGB1KSB0TCB\n"
- + "zjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ\n"
- + "Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE\n"
- + "CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhh\n"
- + "d3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl\n"
- + "cnZlckB0aGF3dGUuY29tggEBMA0GCSqGSIb3DQEBBQUAA4GBACvKEsnd18xjHJsx\n"
- + "NUrd5Lf2ndGk+x74R/muB44NWBL72u21zDPll2hHYULVZqluHke/hdt9WNF3WsyQ\n"
- + "YZiaKfWdsc+43PN7gEdI0X30aIzEQcu06f3wI+Cxm3YqbShWo4zN6ewhAHHwX91Q\n"
- + "pWlCG4MRXYQo0yeu7CqrL2BCxcR4\n"
- + "-----END CERTIFICATE-----";
+ private final X509Certificate md5ChainIntermediate
+ = loadCertificate("md5ChainIntermediate.pem");
- /**
- * A certificate signed by signedCert1Chain2
+ /*
+ * A certificate signed by md5ChainIntermediate: https://crt.sh/?id=134
*
- * <pre>
- * Certificate:
- * Data:
- * Version: 3 (0x2)
- * Serial Number:
- * 7b:11:55:eb:78:9a:90:85:b5:8c:92:ff:42:b7:fe:56
* Signature Algorithm: sha1WithRSAEncryption
- * Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA
+ * Issuer: C = US, O = "thawte, Inc.", OU = Certification Services Division, OU = "(c) 2006 thawte, Inc. - For authorized use only", CN = thawte Primary Root CA
* Validity
* Not Before: Nov 17 00:00:00 2006 GMT
* Not After : Nov 16 23:59:59 2016 GMT
- * Subject: C=US, O=thawte, Inc., OU=Terms of use at https://www.thawte.com/cps (c)06, CN=thawte Extended Validation SSL CA
- * Subject Public Key Info:
- * Public Key Algorithm: rsaEncryption
- * RSA Public Key: (2048 bit)
- * Modulus (2048 bit):
- * 00:b5:8d:47:f7:b0:48:76:9b:bd:fb:a9:cb:bf:04:
- * 31:a2:3d:9a:7e:30:29:d3:28:b8:fe:68:ce:cf:e9:
- * 30:6a:53:95:0e:50:65:80:26:c9:98:bf:f2:14:ff:
- * 06:7c:6a:7b:dc:50:07:e2:98:fa:df:cf:30:5d:ca:
- * a8:b9:8a:9b:2d:2d:7e:59:8b:1a:f7:b3:c9:c3:69:
- * 80:0f:89:19:08:77:b2:52:55:ad:78:83:9d:6b:b9:
- * 87:e4:53:24:37:2c:fc:19:0e:8b:79:14:4d:be:80:
- * 9e:b4:9b:73:74:31:f2:38:ec:8a:af:2a:36:8e:64:
- * ce:31:26:14:03:54:53:8e:fb:84:08:c1:7e:47:32:
- * 3d:71:e0:ba:ba:8c:82:58:96:4d:68:43:56:1a:f3:
- * 46:5a:32:99:95:b0:60:6f:e9:41:8a:48:cc:16:0d:
- * 44:68:b1:8a:dd:dd:17:3d:a4:9b:78:7f:2e:29:06:
- * f0:dc:d5:d2:13:3f:c0:36:05:fd:c7:b5:b9:80:1b:
- * 8a:46:74:2f:f1:ab:79:9e:97:6e:f8:a5:13:5a:f3:
- * fc:b5:d7:c8:96:19:37:ee:06:bc:c6:27:14:81:05:
- * 14:33:38:16:9f:4b:e2:0f:db:38:bb:f3:01:ef:35:
- * 2e:de:af:f1:e4:6f:6f:f7:96:00:56:5e:8f:60:94:
- * 1d:2f
- * Exponent: 65537 (0x10001)
- * X509v3 extensions:
- * Authority Information Access:
- * OCSP - URI:http://EVSecure-ocsp.thawte.com
- * X509v3 Basic Constraints: critical
- * CA:TRUE, pathlen:0
- * X509v3 Certificate Policies:
- * Policy: X509v3 Any Policy
- * CPS: https://www.thawte.com/cps
- * X509v3 CRL Distribution Points:
- * URI:http://crl.thawte.com/ThawtePCA.crl
- * X509v3 Key Usage: critical
- * Certificate Sign, CRL Sign
- * X509v3 Subject Alternative Name:
- * DirName:/CN=PrivateLabel3-2048-234
- * X509v3 Subject Key Identifier:
- * CD:32:E2:F2:5D:25:47:02:AA:8F:79:4B:32:EE:03:99:FD:30:49:D1
- * X509v3 Authority Key Identifier:
- * keyid:7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50
- * Signature Algorithm: sha1WithRSAEncryption
- * 0b:b4:96:ce:03:0c:d1:9d:af:cb:e3:39:56:0d:c6:22:a0:c9:
- * 71:7d:ea:65:95:31:f1:dc:b6:1e:f2:8d:31:5d:61:b3:54:84:
- * 13:cc:2b:3f:02:5c:c7:1f:15:01:82:90:1e:31:25:06:e3:32:
- * 0c:87:f0:c3:be:9a:c4:00:41:f6:c6:91:e5:6c:3e:92:5d:a3:
- * e4:3d:1f:32:2d:31:1e:50:c1:02:21:b4:23:e3:07:75:9a:52:
- * 45:51:fa:d3:1d:fd:01:6f:60:6d:25:d9:bf:43:b1:a7:43:6c:
- * ad:8c:bb:bc:f7:99:41:eb:d6:95:cf:20:5c:7e:6f:c4:2a:da:
- * 4b:4d:1b:5b:c2:9f:b0:94:d4:bf:47:97:fd:9d:49:79:60:8e:
- * ae:96:19:a1:b0:eb:e8:df:42:c7:22:74:61:0c:25:a3:7f:8f:
- * 45:d2:7e:e7:4a:6e:1d:4f:48:bb:c2:da:1a:7e:4a:59:81:fa:
- * 1c:e3:fb:14:73:41:03:a1:77:fa:9b:06:fc:7c:33:bd:46:3d:
- * 0c:06:17:85:7b:2a:7b:e3:36:e8:83:df:fa:aa:cb:32:0c:79:
- * aa:86:74:6c:44:54:f6:d8:07:9e:cd:98:f4:23:05:09:2f:a2:
- * 53:b5:db:0a:81:cc:5f:23:cb:79:11:c5:11:5b:85:6b:27:01:
- * 89:f3:0e:bb
- * </pre>
+ * Subject: C = US, O = "thawte, Inc.", OU = Terms of use at https://www.thawte.com/cps (c)06, CN = thawte Extended Validation SSL CA
*/
- private static final String signedCert2Chain2 =
- "-----BEGIN CERTIFICATE-----\n"
- + "MIIFCjCCA/KgAwIBAgIQexFV63iakIW1jJL/Qrf+VjANBgkqhkiG9w0BAQUFADCB\n"
- + "qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf\n"
- + "Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw\n"
- + "MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV\n"
- + "BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMTYx\n"
- + "MTE2MjM1OTU5WjCBizELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j\n"
- + "LjE5MDcGA1UECxMwVGVybXMgb2YgdXNlIGF0IGh0dHBzOi8vd3d3LnRoYXd0ZS5j\n"
- + "b20vY3BzIChjKTA2MSowKAYDVQQDEyF0aGF3dGUgRXh0ZW5kZWQgVmFsaWRhdGlv\n"
- + "biBTU0wgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1jUf3sEh2\n"
- + "m737qcu/BDGiPZp+MCnTKLj+aM7P6TBqU5UOUGWAJsmYv/IU/wZ8anvcUAfimPrf\n"
- + "zzBdyqi5ipstLX5Zixr3s8nDaYAPiRkId7JSVa14g51ruYfkUyQ3LPwZDot5FE2+\n"
- + "gJ60m3N0MfI47IqvKjaOZM4xJhQDVFOO+4QIwX5HMj1x4Lq6jIJYlk1oQ1Ya80Za\n"
- + "MpmVsGBv6UGKSMwWDURosYrd3Rc9pJt4fy4pBvDc1dITP8A2Bf3HtbmAG4pGdC/x\n"
- + "q3mel274pRNa8/y118iWGTfuBrzGJxSBBRQzOBafS+IP2zi78wHvNS7er/Hkb2/3\n"
- + "lgBWXo9glB0vAgMBAAGjggFIMIIBRDA7BggrBgEFBQcBAQQvMC0wKwYIKwYBBQUH\n"
- + "MAGGH2h0dHA6Ly9FVlNlY3VyZS1vY3NwLnRoYXd0ZS5jb20wEgYDVR0TAQH/BAgw\n"
- + "BgEB/wIBADA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cHM6\n"
- + "Ly93d3cudGhhd3RlLmNvbS9jcHMwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL2Ny\n"
- + "bC50aGF3dGUuY29tL1RoYXd0ZVBDQS5jcmwwDgYDVR0PAQH/BAQDAgEGMC4GA1Ud\n"
- + "EQQnMCWkIzAhMR8wHQYDVQQDExZQcml2YXRlTGFiZWwzLTIwNDgtMjM0MB0GA1Ud\n"
- + "DgQWBBTNMuLyXSVHAqqPeUsy7gOZ/TBJ0TAfBgNVHSMEGDAWgBR7W0XPr87Lev0x\n"
- + "khpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAC7SWzgMM0Z2vy+M5Vg3GIqDJ\n"
- + "cX3qZZUx8dy2HvKNMV1hs1SEE8wrPwJcxx8VAYKQHjElBuMyDIfww76axABB9saR\n"
- + "5Ww+kl2j5D0fMi0xHlDBAiG0I+MHdZpSRVH60x39AW9gbSXZv0Oxp0NsrYy7vPeZ\n"
- + "QevWlc8gXH5vxCraS00bW8KfsJTUv0eX/Z1JeWCOrpYZobDr6N9CxyJ0YQwlo3+P\n"
- + "RdJ+50puHU9Iu8LaGn5KWYH6HOP7FHNBA6F3+psG/HwzvUY9DAYXhXsqe+M26IPf\n"
- + "+qrLMgx5qoZ0bERU9tgHns2Y9CMFCS+iU7XbCoHMXyPLeRHFEVuFaycBifMOuw==\n"
- + "-----END CERTIFICATE-----";
+ private final X509Certificate md5ChainLeaf = loadCertificate("md5ChainLeaf.pem");
- public void testVerifyMD5() throws Exception {
- Provider[] providers = Security.getProviders("CertificateFactory.X509");
- for (Provider provider : providers) {
- CertificateFactory certificateFactory = CertificateFactory.getInstance("X509", provider);
+ /*
+ * A self-signed root certificate using SHA-1: https://crt.sh/?id=88
+ *
+ * Signature Algorithm: sha1WithRSAEncryption
+ * Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA
+ * Validity
+ * Not Before: Sep 1 12:00:00 1998 GMT
+ * Not After : Jan 28 12:00:00 2028 GMT
+ * Subject: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA
+ */
+ private final X509Certificate sha1ChainRoot = loadCertificate("sha1ChainRoot.pem");
- Certificate certificate = certificateFactory
- .generateCertificate(new ByteArrayInputStream(selfSignedCertMD5
- .getBytes()));
+ /*
+ * Intermediate certificate signed by sha1ChainRoot: https://crt.sh/?id=234
+ *
+ * Signature Algorithm: sha1WithRSAEncryption
+ * Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA
+ * Validity
+ * Not Before: Apr 13 10:00:00 2011 GMT
+ * Not After : Apr 13 10:00:00 2022 GMT
+ * Subject: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Organization Validation CA - G2
+ */
+ private final X509Certificate sha1ChainIntermediate
+ = loadCertificate("sha1ChainIntermediate.pem");
- certificate.verify(certificate.getPublicKey());
- }
+ /*
+ * Leaf certificate signed by sha1ChainIntermediate: https://crt.sh/?id=38169079
+ *
+ * Signature Algorithm: sha1WithRSAEncryption
+ * Issuer: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Organization Validation CA - G2
+ * Validity
+ * Not Before: Aug 25 14:51:20 2011 GMT
+ * Not After : Jun 28 16:04:51 2012 GMT
+ * Subject: C=GB, ST=London, L=London, OU=Internet Operations, O=British Broadcasting Corporation, CN=www.bbc.co.uk
+ */
+ private final X509Certificate sha1ChainLeaf = loadCertificate("sha1ChainLeaf.pem");
+
+ private final boolean md5SignatureSupported = isMd5Supported();
+
+ public CertificateTest()
+ throws CertificateException, SignatureException, InvalidKeyException, NoSuchProviderException {
}
- public void testVerifyMD2() throws Exception {
- Provider[] providers = Security.getProviders("CertificateFactory.X509");
- for (Provider provider : providers) {
- CertificateFactory certificateFactory = CertificateFactory.getInstance("X509", provider);
-
- Certificate certificate = certificateFactory
- .generateCertificate(new ByteArrayInputStream(selfSignedCertMD2
- .getBytes()));
- try {
- certificate.verify(certificate.getPublicKey());
- fail("MD2 should not be allowed");
- } catch (NoSuchAlgorithmException e) {
- // expected
- } catch (Throwable e) {
- throw new AssertionError(provider.getName(), e);
- }
- }
+ @Test
+ public void verifySha1Supported() throws Exception {
+ sha1ChainRoot.verify(sha1ChainRoot.getPublicKey());
}
- public void testVerifyMD2_chain() throws Exception {
- CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
+ @Test
+ public void verifyMd2NotSupported() {
+ assertThrows(NoSuchAlgorithmException.class, () ->
+ md2Root.verify(md2Root.getPublicKey()));
+ }
- // First check with the trust anchor not included in the chain
- CertPath path = certificateFactory.generateCertPath(getCertList(true, false));
+ @Test
+ public void verifyMd5Chain_rootNotIncluded() throws Exception {
+ Assume.assumeTrue(md5SignatureSupported);
+
+ CertPath path = certificateFactory.generateCertPath(
+ List.of(md5ChainLeaf, md5ChainIntermediate));
CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX");
- PKIXParameters params = createPKIXParams();
+ PKIXParameters params = createPkixParams(md5ChainRoot);
+ backdate(params, 2016);
- CertPathValidatorResult res = certPathValidator.validate(path, params);
- assertTrue("wrong result type",
- res instanceof PKIXCertPathValidatorResult);
-
- PKIXCertPathValidatorResult r = (PKIXCertPathValidatorResult) res;
- assertTrue("Wrong trust anchor returned",
- params.getTrustAnchors().contains(r.getTrustAnchor()));
-
- // Now check with the trust anchor included in the chain
- path = certificateFactory.generateCertPath(getCertList(true, true));
-
- certPathValidator = CertPathValidator.getInstance("PKIX");
- params = createPKIXParams();
-
- if (StandardNames.IS_RI) {
- res = certPathValidator.validate(path, params);
- assertTrue("wrong result type", res instanceof PKIXCertPathValidatorResult);
-
- r = (PKIXCertPathValidatorResult) res;
- assertTrue("Wrong trust anchor returned",
- params.getTrustAnchors().contains(r.getTrustAnchor()));
- } else {
- try {
- certPathValidator.validate(path, params);
- fail();
- } catch (CertPathValidatorException expected) {
- }
- }
+ validate(path, certPathValidator, params);
}
- public void testVerifyMD5_chain() throws Exception {
- CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
+ @Test
+ public void verifyMd5Chain_rootIncluded() throws Exception {
+ Assume.assumeTrue(md5SignatureSupported);
- // First check with the trust anchor not included in the chain
- CertPath path = certificateFactory.generateCertPath(getCertList(false, false));
+ CertPath path = certificateFactory.generateCertPath(
+ List.of(md5ChainLeaf, md5ChainIntermediate, md5ChainRoot));
CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX");
- PKIXParameters params = createPKIXParams();
+ PKIXParameters params = createPkixParams(md5ChainRoot);
+ backdate(params, 2016);
- CertPathValidatorResult res = certPathValidator.validate(path, params);
- assertTrue("wrong result type",
- res instanceof PKIXCertPathValidatorResult);
-
- PKIXCertPathValidatorResult r = (PKIXCertPathValidatorResult) res;
- assertTrue("Wrong trust anchor returned",
- params.getTrustAnchors().contains(r.getTrustAnchor()));
-
- // Now check with the trust anchor included in the chain
- path = certificateFactory.generateCertPath(getCertList(false, true));
-
- certPathValidator = CertPathValidator.getInstance("PKIX");
- params = createPKIXParams();
-
- res = certPathValidator.validate(path, params);
- assertTrue("wrong result type",
- res instanceof PKIXCertPathValidatorResult);
-
- r = (PKIXCertPathValidatorResult) res;
- assertTrue("Wrong trust anchor returned",
- params.getTrustAnchors().contains(r.getTrustAnchor()));
+ validate(path, certPathValidator, params);
}
- private X509Certificate[] certs= new X509Certificate[3];
+ @Test
+ public void verifyMd5ChainExceptionWhenUnsupported() throws Exception {
+ Assume.assumeFalse(md5SignatureSupported);
- private List<Certificate> getCertList(boolean useMD2root,
- boolean includeRootInChain) throws Exception {
+ CertPath path = certificateFactory.generateCertPath(
+ List.of(md5ChainLeaf, md5ChainIntermediate, md5ChainRoot));
- CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
+ CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX");
+ PKIXParameters params = createPkixParams(md5ChainRoot);
+ backdate(params, 2016);
- if (useMD2root) {
- certs[0] = (X509Certificate) certificateFactory
- .generateCertificate(new ByteArrayInputStream(
- selfSignedCertMD2.getBytes()));
- certs[1] = (X509Certificate) certificateFactory
- .generateCertificate(new ByteArrayInputStream(
- signedCert1Chain1.getBytes()));
- certs[2] = (X509Certificate) certificateFactory
- .generateCertificate(new ByteArrayInputStream(
- signedCert2Chain1.getBytes()));
- } else {
- certs[0] = (X509Certificate) certificateFactory
- .generateCertificate(new ByteArrayInputStream(
- selfSignedCertMD5.getBytes()));
- certs[1] = (X509Certificate) certificateFactory
- .generateCertificate(new ByteArrayInputStream(
- signedCert1Chain2.getBytes()));
- certs[2] = (X509Certificate) certificateFactory
- .generateCertificate(new ByteArrayInputStream(
- signedCert2Chain2.getBytes()));
- }
+ Exception exception = assertThrows(CertPathValidatorException.class,
+ () -> validate(path, certPathValidator, params));
+ // Correct cause should be NoSuchAlgorithmException but older Conscrypt modules
+ // may throw CertificateException.
+ assertTrue(exception.getCause().getClass() == CertificateException.class ||
+ exception.getCause().getClass() == NoSuchAlgorithmException.class);
- ArrayList<Certificate> result = new ArrayList<Certificate>();
- result.add(certs[2]);
- result.add(certs[1]);
- if (includeRootInChain) {
- result.add(certs[0]);
- }
- return result;
}
- private PKIXParameters createPKIXParams() throws Exception {
- KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
- keyStore.load(null, null);
- keyStore.setCertificateEntry("selfSignedCert", certs[0]);
+ @Test
+ public void verifySha1Chain_rootNotIncluded() throws Exception {
+ CertPath path = certificateFactory.generateCertPath(
+ List.of(sha1ChainLeaf, sha1ChainIntermediate));
- PKIXParameters params;
- params = new PKIXParameters(keyStore);
+ CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX");
+ PKIXParameters params = createPkixParams(sha1ChainRoot);
+ backdate(params, 2012);
+
+ validate(path, certPathValidator, params);
+ }
+
+ @Test
+ public void verifySha1Chain_rootIncluded() throws Exception {
+ CertPath path = certificateFactory.generateCertPath(
+ List.of(sha1ChainLeaf, sha1ChainIntermediate, sha1ChainRoot));
+
+ CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX");
+ PKIXParameters params = createPkixParams(sha1ChainRoot);
+ backdate(params, 2012);
+
+ validate(path, certPathValidator, params);
+ }
+
+ private PKIXParameters createPkixParams(X509Certificate rootCa) throws Exception {
+ Set<TrustAnchor> anchors = Set.of(new TrustAnchor(rootCa, null));
+ PKIXParameters params = new PKIXParameters(anchors);
params.setRevocationEnabled(false);
+ return params;
+ }
- // All the tests are using pre-generated certificates with set expirations.
- // In order to avoid the test failing when the certificates expire,
- // explicitly set the time to check their validity against.
+ // The test certificates above are long expired, so allow checking at a point in time
+ // when they weren't.
+ private void backdate(PKIXParameters params, int year) {
Calendar calendar = Calendar.getInstance();
calendar.clear();
- calendar.set(2016, Calendar.JANUARY, 1);
+ calendar.set(year, Calendar.JANUARY, 1);
params.setDate(calendar.getTime());
+ }
- return params;
+ // Checks that a CertPath validates and matches the expected trust anchor.
+ private void validate(CertPath path, CertPathValidator certPathValidator,
+ PKIXParameters params) throws Exception {
+ CertPathValidatorResult result = certPathValidator.validate(path, params);
+ assertTrue("wrong result type",
+ result instanceof PKIXCertPathValidatorResult);
+
+ PKIXCertPathValidatorResult pkixResult = (PKIXCertPathValidatorResult) result;
+ assertTrue("Wrong trust anchor returned",
+ params.getTrustAnchors().contains(pkixResult.getTrustAnchor()));
+ }
+
+
+ // Returns true if the version of BoringSSL in use allows MD5-signed certificates.
+ // Depending on the version of BoringSSL in use, which in turn depends on the version
+ // of the Conscrypt module, MD5-signed certificates may or may not be rejected by BoringSSL.
+ private boolean isMd5Supported() throws SignatureException, InvalidKeyException,
+ NoSuchProviderException {
+ try {
+ md5ChainRoot.verify(md5ChainRoot.getPublicKey());
+ return true;
+ } catch (NoSuchAlgorithmException | CertificateException e) {
+ // TODO(prb): After Conscrypt PR 1117 should only throw NoSuchAlgorithmException.
+ return false;
+ }
+ }
+
+ // There should only be a single x.509 Certificate Provider (Conscrypt).
+ private CertificateFactory onlyX509CertificateFactory() throws CertificateException {
+ Provider[] providers = Security.getProviders("CertificateFactory.X509");
+ if (providers.length != 1) {
+ throw new IllegalStateException("There should be exactly one X.509 CertificateFactory");
+ }
+ return CertificateFactory.getInstance("X509", providers[0]);
+ }
+
+ // Loads an X509Certificate from a PEM or DER resource.
+ private X509Certificate loadCertificate(String name) throws CertificateException {
+ InputStream inputStream = getClass().getResourceAsStream("/certpath/" + name);
+ return (X509Certificate) certificateFactory.generateCertificate(inputStream);
}
}
diff --git a/luni/src/test/java17language/Android.bp b/luni/src/test/java17language/Android.bp
new file mode 100644
index 0000000..a9f9477
--- /dev/null
+++ b/luni/src/test/java17language/Android.bp
@@ -0,0 +1,83 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Android tests related to Java 17 language features.
+
+// Use jarjar to repackage Java17LanguageFeatures, to be used in tests below.
+package {
+ // http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // the below license kinds from "libcore_luni_license":
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["libcore_luni_license"],
+}
+
+java_library {
+ name: "core-java-17-language-features-repackaged-for-test",
+ hostdex: true,
+
+ srcs: [":core-java-17-language-features-source"],
+ jarjar_rules: "jarjar_rules_java17_language_features.txt",
+ java_version: "17",
+
+ sdk_version: "none",
+ system_modules: "core-all-system-modules",
+ patch_module: "java.base",
+
+ visibility: ["//visibility:private"],
+}
+
+// Generate a clone of Java17LanguageFeaturesTest which uses a version of
+// Java17LanguageFeatures repackaged by jarjar. This ensures that jarjar is able
+// to handle a class file which must be at least v55 and includes bytecode
+// compiled from Java 17 language features.
+filegroup {
+ name: "core-rewrite-java-17-test-for-jarjar-sed-script",
+ srcs: ["rewrite-test-for-jarjar.sed"],
+ visibility: ["//visibility:private"],
+}
+
+filegroup {
+ name: "core-java-17-language-features-test-src",
+ srcs: ["java/libcore/libcore/internal/Java17LanguageFeaturesTest.java"],
+ visibility: ["//visibility:private"],
+}
+
+genrule {
+ name: "core-gen-test-repackaged-java-17-language-features",
+ srcs: [
+ ":core-rewrite-java-17-test-for-jarjar-sed-script",
+ ":core-java-17-language-features-test-src",
+ ],
+ out: ["libcore/libcore/internal/Java17LanguageFeaturesJarjarTest.java"],
+ cmd: "sed -r -f $(location :core-rewrite-java-17-test-for-jarjar-sed-script) $(location :core-java-17-language-features-test-src) > $(out)",
+ visibility: ["//visibility:private"],
+}
+
+java_library {
+ name: "core-java-17-language-tests",
+ hostdex: true,
+ srcs: [
+ "java/**/*.java",
+ ":core-gen-test-repackaged-java-17-language-features",
+ ],
+ sdk_version: "none",
+ system_modules: "core-all-system-modules",
+ static_libs: [
+ "core-java-17-language-features-repackaged-for-test",
+ "junit",
+ ],
+ visibility: ["//libcore"],
+ java_version: "17",
+}
diff --git a/luni/src/test/java17language/jarjar_rules_java17_language_features.txt b/luni/src/test/java17language/jarjar_rules_java17_language_features.txt
new file mode 100644
index 0000000..dee72bc
--- /dev/null
+++ b/luni/src/test/java17language/jarjar_rules_java17_language_features.txt
@@ -0,0 +1 @@
+rule libcore.internal.** libcore.internal.repackaged.@1
diff --git a/luni/src/test/java17language/java/libcore/libcore/internal/Java17LanguageFeaturesTest.java b/luni/src/test/java17language/java/libcore/libcore/internal/Java17LanguageFeaturesTest.java
new file mode 100644
index 0000000..6d70348
--- /dev/null
+++ b/luni/src/test/java17language/java/libcore/libcore/internal/Java17LanguageFeaturesTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.libcore.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import libcore.internal.Java17LanguageFeatures;
+
+import org.junit.Test;
+import org.junit.Ignore;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class Java17LanguageFeaturesTest {
+
+ @Test
+ public void testMultilineString() {
+ assertEquals("This is a\nmultiline\nstring.",
+ Java17LanguageFeatures.getTextBlock());
+ }
+
+ @Test
+ public void testPatternMatchingInstanceof() {
+ Java17LanguageFeatures.Shape s = new Java17LanguageFeatures.Triangle(6, 10);
+ assertEquals(30, Java17LanguageFeatures.calculateApproximateArea(s));
+ s = new Java17LanguageFeatures.Rectangle(4, 5);
+ assertEquals(20, Java17LanguageFeatures.calculateApproximateArea(s));
+ s = new Java17LanguageFeatures.Circle(5);
+ assertEquals(75, Java17LanguageFeatures.calculateApproximateArea(s));
+ }
+
+ @Test
+ public void testRecord() {
+ Java17LanguageFeatures.Point p1 = Java17LanguageFeatures.buildPoint(1, 2);
+ Java17LanguageFeatures.Point p2 = Java17LanguageFeatures.buildPoint(1, 2);
+ Java17LanguageFeatures.Point p3 = Java17LanguageFeatures.buildPoint(1, 3);
+
+ assertEquals(1, p1.x());
+ assertEquals(2, p1.y());
+ assertEquals(1, p2.x());
+ assertEquals(2, p2.y());
+ assertEquals(1, p3.x());
+ assertEquals(3, p3.y());
+
+ assertEquals("Point[x=1, y=2]", p1.toString());
+ assertEquals("Point[x=1, y=2]", p2.toString());
+ assertEquals("Point[x=1, y=3]", p3.toString());
+
+ assertTrue(p1.equals(p2));
+ assertEquals(p1.hashCode(), p2.hashCode());
+
+ assertFalse(p1.equals(p3));
+ assertNotEquals(p1.hashCode(), p3.hashCode());
+
+ assertFalse(p2.equals(p3));
+ assertNotEquals(p2.hashCode(), p3.hashCode());
+ }
+
+ @Test
+ public void testSealedClass() {
+ Java17LanguageFeatures.BaseSealedClass obj = new Java17LanguageFeatures.BaseSealedClass();
+ assertEquals(0, Java17LanguageFeatures.getSealedClassId(obj));
+ obj = new Java17LanguageFeatures.FinalDerivedClass();
+ assertEquals(1, Java17LanguageFeatures.getSealedClassId(obj));
+ obj = new Java17LanguageFeatures.NonSealedDerivedClass();
+ assertEquals(2, Java17LanguageFeatures.getSealedClassId(obj));
+ obj = new DerivedClass();
+ assertEquals(3, Java17LanguageFeatures.getSealedClassId(obj));
+ }
+
+ private static class DerivedClass extends Java17LanguageFeatures.NonSealedDerivedClass {
+ @Override
+ public int getId() {
+ return 3;
+ }
+ }
+}
diff --git a/luni/src/test/java17language/rewrite-test-for-jarjar.sed b/luni/src/test/java17language/rewrite-test-for-jarjar.sed
new file mode 100644
index 0000000..eb350b1
--- /dev/null
+++ b/luni/src/test/java17language/rewrite-test-for-jarjar.sed
@@ -0,0 +1,21 @@
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This is a sed script that modifies Java source code in two ways.
+
+# Replace libcore.internal with libcore.internal.repackaged in imports:
+s/import libcore.internal/import libcore.internal.repackaged/
+
+# Replace Test with JarjarTest in class declarations.
+s/class ([A-Za-z0-9_]+)Test/class \1JarjarTest/
diff --git a/luni/src/test/resources/certpath/md2Root.pem b/luni/src/test/resources/certpath/md2Root.pem
new file mode 100644
index 0000000..0f53b71
--- /dev/null
+++ b/luni/src/test/resources/certpath/md2Root.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
+BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
+I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
+lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
+AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
+-----END CERTIFICATE-----
+
diff --git a/luni/src/test/resources/certpath/md5ChainIntermediate.pem b/luni/src/test/resources/certpath/md5ChainIntermediate.pem
new file mode 100644
index 0000000..ce95226
--- /dev/null
+++ b/luni/src/test/resources/certpath/md5ChainIntermediate.pem
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFUTCCBLqgAwIBAgIQX6a+gLaGxi8B7QyrsZahBTANBgkqhkiG9w0BAQUFADCB
+zjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ
+Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE
+CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhh
+d3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl
+cnZlckB0aGF3dGUuY29tMB4XDTA2MTExNzAwMDAwMFoXDTIwMTIzMDIzNTk1OVow
+gakxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUsIEluYy4xKDAmBgNVBAsT
+H0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xODA2BgNVBAsTLyhjKSAy
+MDA2IHRoYXd0ZSwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYD
+VQQDExZ0aGF3dGUgUHJpbWFyeSBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEArKDw+4BZ1JzHpM+doVlzCRBFDA0sbmjxbFtIaElZN/wLMxnC
+d3/MEC2VNBzm600JpxzSuMmXNgK3idQkXwbAzESUlI0CYm/rWt0RjSiaXISQEHoN
+vXRmL2o4oOLVVETrHQefB7pv7un9Tgsp9T6EoAHxnKv4HH6JpOih2HFlDaNRe+68
+0iJgDblbnd+6/FFbC6+Ysuku6QToYofeK8jXTsFMZB7dz4dYukpPymgHHRydSsbV
+L5HMfHFyHMXAZ+sy/cmSXJTahcCbv1N9Kwn0jJ2RH5dqUsveCTakd9h7h1BE1T5u
+KWn7OUkmHgmlgHtALevoJ4XJ/mH9fuZ8lx3VnQIDAQABo4IBzTCCAckwDwYDVR0T
+AQH/BAUwAwEB/zA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0
+cHM6Ly93d3cudGhhd3RlLmNvbS9jcHMwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQW
+BBR7W0XPr87Lev0xkhpqtvNG61dIUDBABgNVHR8EOTA3MDWgM6Axhi9odHRwOi8v
+Y3JsLnRoYXd0ZS5jb20vVGhhd3RlUHJlbWl1bVNlcnZlckNBLmNybDAgBgNVHSUE
+GTAXBglghkgBhvhCBAEGCmCGSAGG+EUBCAEwgeUGA1UdIwSB3TCB2qGB1KSB0TCB
+zjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ
+Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE
+CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhh
+d3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl
+cnZlckB0aGF3dGUuY29tggEBMA0GCSqGSIb3DQEBBQUAA4GBACvKEsnd18xjHJsx
+NUrd5Lf2ndGk+x74R/muB44NWBL72u21zDPll2hHYULVZqluHke/hdt9WNF3WsyQ
+YZiaKfWdsc+43PN7gEdI0X30aIzEQcu06f3wI+Cxm3YqbShWo4zN6ewhAHHwX91Q
+pWlCG4MRXYQo0yeu7CqrL2BCxcR4
+-----END CERTIFICATE-----
+
diff --git a/luni/src/test/resources/certpath/md5ChainLeaf.pem b/luni/src/test/resources/certpath/md5ChainLeaf.pem
new file mode 100644
index 0000000..0d5824c
--- /dev/null
+++ b/luni/src/test/resources/certpath/md5ChainLeaf.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFCjCCA/KgAwIBAgIQexFV63iakIW1jJL/Qrf+VjANBgkqhkiG9w0BAQUFADCB
+qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
+Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
+MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
+BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMTYx
+MTE2MjM1OTU5WjCBizELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
+LjE5MDcGA1UECxMwVGVybXMgb2YgdXNlIGF0IGh0dHBzOi8vd3d3LnRoYXd0ZS5j
+b20vY3BzIChjKTA2MSowKAYDVQQDEyF0aGF3dGUgRXh0ZW5kZWQgVmFsaWRhdGlv
+biBTU0wgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1jUf3sEh2
+m737qcu/BDGiPZp+MCnTKLj+aM7P6TBqU5UOUGWAJsmYv/IU/wZ8anvcUAfimPrf
+zzBdyqi5ipstLX5Zixr3s8nDaYAPiRkId7JSVa14g51ruYfkUyQ3LPwZDot5FE2+
+gJ60m3N0MfI47IqvKjaOZM4xJhQDVFOO+4QIwX5HMj1x4Lq6jIJYlk1oQ1Ya80Za
+MpmVsGBv6UGKSMwWDURosYrd3Rc9pJt4fy4pBvDc1dITP8A2Bf3HtbmAG4pGdC/x
+q3mel274pRNa8/y118iWGTfuBrzGJxSBBRQzOBafS+IP2zi78wHvNS7er/Hkb2/3
+lgBWXo9glB0vAgMBAAGjggFIMIIBRDA7BggrBgEFBQcBAQQvMC0wKwYIKwYBBQUH
+MAGGH2h0dHA6Ly9FVlNlY3VyZS1vY3NwLnRoYXd0ZS5jb20wEgYDVR0TAQH/BAgw
+BgEB/wIBADA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cHM6
+Ly93d3cudGhhd3RlLmNvbS9jcHMwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL2Ny
+bC50aGF3dGUuY29tL1RoYXd0ZVBDQS5jcmwwDgYDVR0PAQH/BAQDAgEGMC4GA1Ud
+EQQnMCWkIzAhMR8wHQYDVQQDExZQcml2YXRlTGFiZWwzLTIwNDgtMjM0MB0GA1Ud
+DgQWBBTNMuLyXSVHAqqPeUsy7gOZ/TBJ0TAfBgNVHSMEGDAWgBR7W0XPr87Lev0x
+khpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAC7SWzgMM0Z2vy+M5Vg3GIqDJ
+cX3qZZUx8dy2HvKNMV1hs1SEE8wrPwJcxx8VAYKQHjElBuMyDIfww76axABB9saR
+5Ww+kl2j5D0fMi0xHlDBAiG0I+MHdZpSRVH60x39AW9gbSXZv0Oxp0NsrYy7vPeZ
+QevWlc8gXH5vxCraS00bW8KfsJTUv0eX/Z1JeWCOrpYZobDr6N9CxyJ0YQwlo3+P
+RdJ+50puHU9Iu8LaGn5KWYH6HOP7FHNBA6F3+psG/HwzvUY9DAYXhXsqe+M26IPf
++qrLMgx5qoZ0bERU9tgHns2Y9CMFCS+iU7XbCoHMXyPLeRHFEVuFaycBifMOuw==
+-----END CERTIFICATE-----
+
diff --git a/luni/src/test/resources/certpath/md5ChainRoot.pem b/luni/src/test/resources/certpath/md5ChainRoot.pem
new file mode 100644
index 0000000..a7bef73
--- /dev/null
+++ b/luni/src/test/resources/certpath/md5ChainRoot.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
+dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
+MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
+MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
+A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
+cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
+bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
+VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
+ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
+uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
+hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
+pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
+-----END CERTIFICATE-----
+
diff --git a/luni/src/test/resources/certpath/sha1ChainIntermediate.pem b/luni/src/test/resources/certpath/sha1ChainIntermediate.pem
new file mode 100644
index 0000000..90a5ddc
--- /dev/null
+++ b/luni/src/test/resources/certpath/sha1ChainIntermediate.pem
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEizCCA3OgAwIBAgILBAAAAAABL07hQvkwDQYJKoZIhvcNAQEFBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xMTA0MTMxMDAw
+MDBaFw0yMjA0MTMxMDAwMDBaMF0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMTMwMQYDVQQDEypHbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBW
+YWxpZGF0aW9uIENBIC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQDdNR3yIFQmGtDvpW+Bdllw3Of01AMkHyQOnSKf1Ccyeit87ovjYWI4F6+0S3qf
+ZyEcLZVUunm6tsTyDSF0F2d04rFkCJlgePtnwkv3J41vNnbPMYzl8QbX3FcOW6zu
+zi2rqqlwLwKGyLHQCAeV6irs0Z7kNlw7pja1Q4ur944+ABv/hVlrYgGNguhKujiz
+4MP0bRmn6gXdhGfCZsckAnNate6kGdn8AM62pI3ffr1fsjqdhDFPyGMM5NgNUqN+
+ARvUZ6UYKOsBp4I82Y4d5UcNuotZFKMfH0vq4idGhs6dOcRmQafiFSNrVkfB7cVT
+5NSAH2v6gEaYsgmmD5W+ZoiTAgMBAAGjggFQMIIBTDAOBgNVHQ8BAf8EBAMCAQYw
+EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUXUayjcRLdBy77fVztjq3OI91
+nn4wRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3
+Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMDMGA1UdHwQsMCowKKAmoCSGImh0
+dHA6Ly9jcmwuZ2xvYmFsc2lnbi5uZXQvcm9vdC5jcmwwPQYIKwYBBQUHAQEEMTAv
+MC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290cjEw
+KQYDVR0lBCIwIAYIKwYBBQUHAwEGCCsGAQUFBwMCBgorBgEEAYI3CgMDMB8GA1Ud
+IwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA0GCSqGSIb3DQEBBQUAA4IBAQBz
+euwBLBcikZrKsWcYorrIBYmSJN4fuKtEn/dAVWXy4PQux96wP5kVH5VwgumbSmQk
+IBbwdhfSG/6s+ga0d8+Y2CrsVxXYXk7di5bhUzMZkdWEbiXvD8utv9tLa1bMtdRA
+PiZetln0xZDJCcSE37wmfYLp6/Rb/MgV3gkYRYazi03HazUnm2D2pFoqWEmx2DVD
+xjK7XjvESiHBoDtewSOpztvVuv5dbf0AfvrxlDdhuQA5ZpapnLQeEe9V2LTYsMSl
+rjIKL/gt9KKn/zbTXmOLThL3tSiAde6UL3CgVnc5qjmXF/wA889m56JxkqsFm3Mu
+eufnIVkJjTChrFzKGXr4
+-----END CERTIFICATE-----
diff --git a/luni/src/test/resources/certpath/sha1ChainLeaf.pem b/luni/src/test/resources/certpath/sha1ChainLeaf.pem
new file mode 100644
index 0000000..18cd16c
--- /dev/null
+++ b/luni/src/test/resources/certpath/sha1ChainLeaf.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFHDCCBASgAwIBAgISESH0dWFGXrhAD9AxMf1edTQoMA0GCSqGSIb3DQEBBQUA
+MF0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTMwMQYD
+VQQDEypHbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBWYWxpZGF0aW9uIENBIC0gRzIw
+HhcNMTEwODI1MTQ1MTIwWhcNMTIwNjI4MTYwNDUxWjCBkDELMAkGA1UEBhMCR0Ix
+DzANBgNVBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMRwwGgYDVQQLExNJbnRl
+cm5ldCBPcGVyYXRpb25zMSkwJwYDVQQKEyBCcml0aXNoIEJyb2FkY2FzdGluZyBD
+b3Jwb3JhdGlvbjEWMBQGA1UEAxMNd3d3LmJiYy5jby51azCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBANV5S0vt2sHoWVTeiQ14L6aZi/Ul1ehOrr58QgC9
+Z5YIfA0QZkt6cuPNWJXL5j/Wt2YqgVgg7Xsuw4x60jnvvFCBwwrjk424Kmn3fat0
+k9LqLzqBlLWBK4MM3YoJWL5kNZK3RaH6+H97OFIGARzzpOpDqHHhrwQqZ5YXH3Pm
+lnZgwele1ce1onaBeyFfPdZ+H89dFs0FcanOnEBjgg/vMQXbh2JIbY2IJWRXNKqm
+GMSbMm7huoyEEFFeD0DhgJaGGpA+pMIn4YX7rC+4BGDswdYu/QoP7+QKucsOUo6F
+tDiyU1jETqQV4n4DgR0YnLK90MkkK/wQTrSb8ZniEpt5000CAwEAAaOCAaAwggGc
+MA4GA1UdDwEB/wQEAwIFoDBMBgNVHSAERTBDMEEGCSsGAQQBoDIBFDA0MDIGCCsG
+AQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAj
+BgNVHREEHDAagg13d3cuYmJjLmNvLnVrggliYmMuY28udWswCQYDVR0TBAIwADAp
+BgNVHSUEIjAgBggrBgEFBQcDAQYIKwYBBQUHAwIGCisGAQQBgjcKAwMwRQYDVR0f
+BD4wPDA6oDigNoY0aHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9ncy9nc29yZ2Fu
+aXphdGlvbnZhbGcyLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0
+dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dzb3JnYW5pemF0aW9u
+dmFsZzJla3UuY3J0MB0GA1UdDgQWBBREjjQvK9/U/naSWETM1BTOgcu4UzAfBgNV
+HSMEGDAWgBRdRrKNxEt0HLvt9XO2Orc4j3WefjANBgkqhkiG9w0BAQUFAAOCAQEA
+UWXYJpQhoSDN2hEfCXS22UTC3MErP3vMa6t4TiKzkIS17bNOk01Cn4oHVF1PUd/X
+DZ7SjGj4qJMGSFqXzPMKEuTo4JT4ZGyRuwOJZBzMisBVc3GvqY0t0ctsksiGQ1s5
+IZyc+DofcakzDQDvhMAk3504L2SWisJhZ1Nkc5LniMhEX+tH7O10f54EhH6AooIJ
+kTYqVO6WBFcEQajZTt3YvrnLL/eoIUrXqKDIB6eluBte1+LEazufKFXE88DGsjsg
+UKD1ZqC3Cohk2lK1BG7pIUczayvSx39XulaKiH7mW7SezJZUHZA8mZyNPGvabrXN
+XsKxxy/OGhr+Qx09LBDzaw==
+-----END CERTIFICATE-----
diff --git a/luni/src/test/resources/certpath/sha1ChainRoot.pem b/luni/src/test/resources/certpath/sha1ChainRoot.pem
new file mode 100644
index 0000000..f4ce4ca
--- /dev/null
+++ b/luni/src/test/resources/certpath/sha1ChainRoot.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
+AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
+yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
+38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
+AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
+DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
+HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
diff --git a/metrictests/memory/host/Android.bp b/metrictests/memory/host/Android.bp
index 10ee832..15b32c4 100644
--- a/metrictests/memory/host/Android.bp
+++ b/metrictests/memory/host/Android.bp
@@ -31,4 +31,7 @@
test_options: {
unit_test: false,
},
+ data: [
+ ":LibcoreHeapDumper",
+ ],
}
diff --git a/non_openjdk_java_files.bp b/non_openjdk_java_files.bp
index 6fd9339..3d67cd7 100644
--- a/non_openjdk_java_files.bp
+++ b/non_openjdk_java_files.bp
@@ -363,6 +363,7 @@
"luni/src/main/java/java/net/AddressCache.java",
"luni/src/main/java/libcore/icu/CollationKeyICU.java",
"luni/src/main/java/libcore/internal/Java11LanguageFeatures.java",
+ "luni/src/main/java/libcore/internal/Java17LanguageFeatures.java",
"luni/src/main/java/libcore/internal/Java9LanguageFeatures.java",
"luni/src/main/java/libcore/internal/StringPool.java",
"luni/src/main/java/libcore/io/ClassPathURLStreamHandler.java",
diff --git a/nullability_warnings.txt b/nullability_warnings.txt
index e69de29..647cfc3 100644
--- a/nullability_warnings.txt
+++ b/nullability_warnings.txt
@@ -0,0 +1,43 @@
+WARNING: method java.lang.invoke.MethodType.appendParameterTypes(Class<?>...), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.appendParameterTypes(java.util.List<java.lang.Class<?>>), parameter ptypesToInsert, MISSING
+WARNING: method java.lang.invoke.MethodType.appendParameterTypes(java.util.List<java.lang.Class<?>>), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.changeParameterType(int, Class<?>), parameter nptype, MISSING
+WARNING: method java.lang.invoke.MethodType.changeParameterType(int, Class<?>), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.changeReturnType(Class<?>), parameter nrtype, MISSING
+WARNING: method java.lang.invoke.MethodType.changeReturnType(Class<?>), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.dropParameterTypes(int, int), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.equals(Object), parameter x, MISSING
+WARNING: method java.lang.invoke.MethodType.erase(), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.fromMethodDescriptorString(String, ClassLoader), parameter descriptor, MISSING
+WARNING: method java.lang.invoke.MethodType.fromMethodDescriptorString(String, ClassLoader), parameter loader, MISSING
+WARNING: method java.lang.invoke.MethodType.fromMethodDescriptorString(String, ClassLoader), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.generic(), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.genericMethodType(int), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.genericMethodType(int, boolean), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.insertParameterTypes(int, Class<?>...), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.insertParameterTypes(int, java.util.List<java.lang.Class<?>>), parameter ptypesToInsert, MISSING
+WARNING: method java.lang.invoke.MethodType.insertParameterTypes(int, java.util.List<java.lang.Class<?>>), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.lastParameterType(), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>), parameter rtype, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>, Class<?>), parameter ptype0, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>, Class<?>), parameter rtype, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>, Class<?>), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>, Class<?>, Class<?>...), parameter ptype0, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>, Class<?>, Class<?>...), parameter rtype, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>, Class<?>, Class<?>...), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>, Class<?>[]), parameter rtype, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>, Class<?>[]), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>, java.lang.invoke.MethodType), parameter ptypes, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>, java.lang.invoke.MethodType), parameter rtype, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>, java.lang.invoke.MethodType), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>, java.util.List<java.lang.Class<?>>), parameter ptypes, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>, java.util.List<java.lang.Class<?>>), parameter rtype, MISSING
+WARNING: method java.lang.invoke.MethodType.methodType(Class<?>, java.util.List<java.lang.Class<?>>), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.parameterList(), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.parameterType(int), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.returnType(), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.toMethodDescriptorString(), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.toString(), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.unwrap(), return value, MISSING
+WARNING: method java.lang.invoke.MethodType.wrap(), return value, MISSING
diff --git a/ojluni/annotations/sdk/nullability/java/lang/Class.annotated.java b/ojluni/annotations/sdk/nullability/java/lang/Class.annotated.java
index 32d44db..a06dd00 100644
--- a/ojluni/annotations/sdk/nullability/java/lang/Class.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/lang/Class.annotated.java
@@ -37,6 +37,7 @@
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
+import java.lang.reflect.RecordComponent;
import java.io.InputStream;
import java.util.HashMap;
@@ -181,4 +182,12 @@
public @libcore.util.Nullable Class<?> @libcore.util.NonNull [] getPermittedSubclasses();
public boolean isSealed() { throw new RuntimeException("Stub!"); }
+
+public @libcore.util.Nullable Class<?> componentType();
+
+public @libcore.util.NonNull Class<?> arrayType();
+
+public @libcore.util.NonNull String descriptorString();
+
+public @libcore.util.Nullable java.lang.reflect.RecordComponent @libcore.util.NonNull [] getRecordComponents();
}
diff --git a/ojluni/annotations/sdk/nullability/java/lang/Record.annotated.java b/ojluni/annotations/sdk/nullability/java/lang/Record.annotated.java
new file mode 100644
index 0000000..dbe5991
--- /dev/null
+++ b/ojluni/annotations/sdk/nullability/java/lang/Record.annotated.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class Record {
+
+protected Record() { throw new RuntimeException("Stub!"); }
+
+public abstract boolean equals(@libcore.util.Nullable java.lang.Object obj);
+
+public abstract int hashCode();
+
+public abstract @libcore.util.NonNull java.lang.String toString();
+}
+
diff --git a/ojluni/annotations/sdk/nullability/java/lang/invoke/MethodType.annotated.java b/ojluni/annotations/sdk/nullability/java/lang/invoke/MethodType.annotated.java
new file mode 100644
index 0000000..3a8b275
--- /dev/null
+++ b/ojluni/annotations/sdk/nullability/java/lang/invoke/MethodType.annotated.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.invoke;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class MethodType implements java.lang.invoke.TypeDescriptor.OfMethod<java.lang.Class<?>,java.lang.invoke.MethodType>, java.io.Serializable {
+
+MethodType() { throw new RuntimeException("Stub!"); }
+
+public static java.lang.invoke.MethodType methodType(java.lang.Class<?> rtype, java.lang.Class<?>[] ptypes) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.invoke.MethodType methodType(java.lang.Class<?> rtype, java.util.List<java.lang.Class<?>> ptypes) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.invoke.MethodType methodType(java.lang.Class<?> rtype, java.lang.Class<?> ptype0, java.lang.Class<?>... ptypes) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.invoke.MethodType methodType(java.lang.Class<?> rtype) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.invoke.MethodType methodType(java.lang.Class<?> rtype, java.lang.Class<?> ptype0) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.invoke.MethodType methodType(java.lang.Class<?> rtype, java.lang.invoke.MethodType ptypes) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.invoke.MethodType genericMethodType(int objectArgCount, boolean finalArray) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.invoke.MethodType genericMethodType(int objectArgCount) { throw new RuntimeException("Stub!"); }
+
+public java.lang.invoke.MethodType changeParameterType(int num, java.lang.Class<?> nptype) { throw new RuntimeException("Stub!"); }
+
+public java.lang.invoke.MethodType insertParameterTypes(int num, java.lang.Class<?>... ptypesToInsert) { throw new RuntimeException("Stub!"); }
+
+public java.lang.invoke.MethodType appendParameterTypes(java.lang.Class<?>... ptypesToInsert) { throw new RuntimeException("Stub!"); }
+
+public java.lang.invoke.MethodType insertParameterTypes(int num, java.util.List<java.lang.Class<?>> ptypesToInsert) { throw new RuntimeException("Stub!"); }
+
+public java.lang.invoke.MethodType appendParameterTypes(java.util.List<java.lang.Class<?>> ptypesToInsert) { throw new RuntimeException("Stub!"); }
+
+public java.lang.invoke.MethodType dropParameterTypes(int start, int end) { throw new RuntimeException("Stub!"); }
+
+public java.lang.invoke.MethodType changeReturnType(java.lang.Class<?> nrtype) { throw new RuntimeException("Stub!"); }
+
+public boolean hasPrimitives() { throw new RuntimeException("Stub!"); }
+
+public boolean hasWrappers() { throw new RuntimeException("Stub!"); }
+
+public java.lang.invoke.MethodType erase() { throw new RuntimeException("Stub!"); }
+
+public java.lang.invoke.MethodType generic() { throw new RuntimeException("Stub!"); }
+
+public java.lang.invoke.MethodType wrap() { throw new RuntimeException("Stub!"); }
+
+public java.lang.invoke.MethodType unwrap() { throw new RuntimeException("Stub!"); }
+
+public java.lang.Class<?> parameterType(int num) { throw new RuntimeException("Stub!"); }
+
+public int parameterCount() { throw new RuntimeException("Stub!"); }
+
+public java.lang.Class<?> returnType() { throw new RuntimeException("Stub!"); }
+
+public java.util.List<java.lang.Class<?>> parameterList() { throw new RuntimeException("Stub!"); }
+
+public java.lang.Class<?> lastParameterType() { throw new RuntimeException("Stub!"); }
+
+public java.lang.Class<?>[] parameterArray() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(java.lang.Object x) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public static java.lang.invoke.MethodType fromMethodDescriptorString(java.lang.String descriptor, java.lang.ClassLoader loader) throws java.lang.IllegalArgumentException, java.lang.TypeNotPresentException { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toMethodDescriptorString() { throw new RuntimeException("Stub!"); }
+
+public @libcore.util.NonNull java.lang.String descriptorString() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/ojluni/annotations/sdk/nullability/java/lang/reflect/RecordComponent.annotated.java b/ojluni/annotations/sdk/nullability/java/lang/reflect/RecordComponent.annotated.java
new file mode 100644
index 0000000..9a2ebce
--- /dev/null
+++ b/ojluni/annotations/sdk/nullability/java/lang/reflect/RecordComponent.annotated.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class RecordComponent implements java.lang.reflect.AnnotatedElement {
+
+RecordComponent() { throw new RuntimeException("Stub!"); }
+
+public @libcore.util.NonNull java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
+public @libcore.util.NonNull java.lang.Class<?> getType() { throw new RuntimeException("Stub!"); }
+
+public @libcore.util.Nullable java.lang.String getGenericSignature() { throw new RuntimeException("Stub!"); }
+
+public @libcore.util.NonNull java.lang.reflect.Type getGenericType() { throw new RuntimeException("Stub!"); }
+
+public @libcore.util.NonNull java.lang.reflect.Method getAccessor() { throw new RuntimeException("Stub!"); }
+
+public <T extends java.lang.annotation.Annotation> @libcore.util.Nullable T getAnnotation(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public @libcore.util.NonNull java.lang.annotation.Annotation @libcore.util.NonNull [] getAnnotations() { throw new RuntimeException("Stub!"); }
+
+public @libcore.util.NonNull java.lang.annotation.Annotation @libcore.util.NonNull [] getDeclaredAnnotations() { throw new RuntimeException("Stub!"); }
+
+public @libcore.util.NonNull java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public @libcore.util.NonNull java.lang.Class<?> getDeclaringRecord() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/ojluni/annotations/sdk/nullability/java/lang/runtime/ObjectMethods.annotated.java b/ojluni/annotations/sdk/nullability/java/lang/runtime/ObjectMethods.annotated.java
new file mode 100644
index 0000000..dcb3b0f
--- /dev/null
+++ b/ojluni/annotations/sdk/nullability/java/lang/runtime/ObjectMethods.annotated.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.runtime;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ObjectMethods {
+
+ObjectMethods() { throw new RuntimeException("Stub!"); }
+
+public static @libcore.util.NonNull java.lang.Object bootstrap(
+ @libcore.util.NonNull java.lang.invoke.MethodHandles.Lookup lookup,
+ @libcore.util.NonNull java.lang.String methodName,
+ @libcore.util.NonNull java.lang.invoke.TypeDescriptor type,
+ @libcore.util.NonNull java.lang.Class<?> recordClass,
+ @libcore.util.Nullable java.lang.String names,
+ @libcore.util.NonNull java.lang.invoke.MethodHandle... getters)
+ throws java.lang.Throwable { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/ojluni/src/main/java/java/io/PrintStream.java b/ojluni/src/main/java/java/io/PrintStream.java
index 878a852..e7f43e4 100644
--- a/ojluni/src/main/java/java/io/PrintStream.java
+++ b/ojluni/src/main/java/java/io/PrintStream.java
@@ -497,8 +497,7 @@
public boolean checkError() {
if (out != null)
flush();
- if (out instanceof java.io.PrintStream) {
- PrintStream ps = (PrintStream) out;
+ if (out instanceof PrintStream ps) {
return ps.checkError();
}
return trouble;
diff --git a/ojluni/src/main/java/java/lang/Boolean.java b/ojluni/src/main/java/java/lang/Boolean.java
index 82e02d4..bafbc80 100644
--- a/ojluni/src/main/java/java/lang/Boolean.java
+++ b/ojluni/src/main/java/java/lang/Boolean.java
@@ -63,8 +63,7 @@
* @author Arthur van Hoff
* @since 1.0
*/
-// Android-removed: ValueBased
-// @jdk.internal.ValueBased
+@jdk.internal.ValueBased
public final class Boolean implements java.io.Serializable,
Comparable<Boolean>
// Android-removed: no Constable support.
diff --git a/ojluni/src/main/java/java/lang/Byte.java b/ojluni/src/main/java/java/lang/Byte.java
index 8d3111d..9229595 100644
--- a/ojluni/src/main/java/java/lang/Byte.java
+++ b/ojluni/src/main/java/java/lang/Byte.java
@@ -68,8 +68,7 @@
* @see java.lang.Number
* @since 1.1
*/
-// Android-removed: ValueBased
-// @jdk.internal.ValueBased
+@jdk.internal.ValueBased
public final class Byte extends Number implements Comparable<Byte>
// Android-removed: no Constable support.
// , Constable
diff --git a/ojluni/src/main/java/java/lang/Character.java b/ojluni/src/main/java/java/lang/Character.java
index 834fe92..4ffea4c 100644
--- a/ojluni/src/main/java/java/lang/Character.java
+++ b/ojluni/src/main/java/java/lang/Character.java
@@ -193,8 +193,7 @@
* @author Ulf Zibis
* @since 1.0
*/
-// Android-removed: ValueBased
-// @jdk.internal.ValueBased
+@jdk.internal.ValueBased
public final
class Character implements java.io.Serializable, Comparable<Character> {
// Android-removed: no Constable support.
diff --git a/ojluni/src/main/java/java/lang/Class.java b/ojluni/src/main/java/java/lang/Class.java
index 9178ebd..cecf117 100644
--- a/ojluni/src/main/java/java/lang/Class.java
+++ b/ojluni/src/main/java/java/lang/Class.java
@@ -36,6 +36,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectStreamField;
+import java.lang.invoke.TypeDescriptor;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
@@ -47,7 +48,9 @@
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.lang.reflect.Parameter;
import java.lang.reflect.Proxy;
+import java.lang.reflect.RecordComponent;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.net.URL;
@@ -75,6 +78,8 @@
import libcore.util.EmptyArray;
import sun.security.util.SecurityConstants;
+import dalvik.system.ClassExt;
+import sun.invoke.util.Wrapper;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.reflect.misc.ReflectUtil;
@@ -167,7 +172,8 @@
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
- AnnotatedElement {
+ AnnotatedElement,
+ TypeDescriptor.OfField<Class<?>> {
private static final int ANNOTATION= 0x00002000;
private static final int ENUM = 0x00004000;
private static final int SYNTHETIC = 0x00001000;
@@ -1411,6 +1417,97 @@
*/
return componentType;
}
+ /**
+ * Returns the component type of this {@code Class}, if it describes
+ * an array type, or {@code null} otherwise.
+ *
+ * @implSpec
+ * Equivalent to {@link Class#getComponentType()}.
+ *
+ * @return a {@code Class} describing the component type, or {@code null}
+ * if this {@code Class} does not describe an array type
+ * @since 12
+ */
+ @Override
+ public Class<?> componentType() {
+ return isArray() ? componentType : null;
+ }
+
+ /**
+ * Returns a {@code Class} for an array type whose component type
+ * is described by this {@linkplain Class}.
+ *
+ * @return a {@code Class} describing the array type
+ * @since 12
+ */
+ @Override
+ public Class<?> arrayType() {
+ return Array.newInstance(this, 0).getClass();
+ }
+
+ // Android-changed: Remove Class#isHidden() and ClassDesc from javadoc.
+ /**
+ * Returns the descriptor string of the entity (class, interface, array class,
+ * primitive type, or {@code void}) represented by this {@code Class} object.
+ *
+ * <p> If this {@code Class} object represents a class or interface,
+ * not an array class, then:
+ * <ul>
+ * <li> The result is a field descriptor (JVMS {@jvms 4.3.2})
+ * for the class or interface.
+ * </ul>
+ *
+ * <p> If this {@code Class} object represents an array class, then
+ * the result is a string consisting of one or more '{@code [}' characters
+ * representing the depth of the array nesting, followed by the
+ * descriptor string of the element type.
+ * <ul>
+ * <li> This array class can be described nominally.
+ * </ul>
+ *
+ * <p> If this {@code Class} object represents a primitive type or
+ * {@code void}, then the result is a field descriptor string which
+ * is a one-letter code corresponding to a primitive type or {@code void}
+ * ({@code "B", "C", "D", "F", "I", "J", "S", "Z", "V"}) (JVMS {@jvms 4.3.2}).
+ *
+ * @apiNote
+ * This is not a strict inverse of {@link #forName};
+ * distinct classes which share a common name but have different class loaders
+ * will have identical descriptor strings.
+ *
+ * @return the descriptor string for this {@code Class} object
+ * @jvms 4.3.2 Field Descriptors
+ * @since 12
+ */
+ @Override
+ public String descriptorString() {
+ if (isPrimitive())
+ return Wrapper.forPrimitiveType(this).basicTypeString();
+
+ if (isArray()) {
+ return "[" + componentType.descriptorString();
+ // Android-changed: Remove check for isHidden()
+ /*
+ } else if (isHidden()) {
+ String name = getName();
+ int index = name.indexOf('/');
+ return new StringBuilder(name.length() + 2)
+ .append('L')
+ .append(name.substring(0, index).replace('.', '/'))
+ .append('.')
+ .append(name, index + 1, name.length())
+ .append(';')
+ .toString();
+ */
+ } else {
+ String name = getName().replace('.', '/');
+ return new StringBuilder(name.length() + 2)
+ .append('L')
+ .append(name)
+ .append(';')
+ .toString();
+ }
+ }
/**
* Returns the Java language modifiers for this class or interface, encoded
@@ -2494,6 +2591,74 @@
public native Field[] getDeclaredFields();
/**
+ * Returns an array of {@code RecordComponent} objects representing all the
+ * record components of this record class, or {@code null} if this class is
+ * not a record class.
+ *
+ * <p> The components are returned in the same order that they are declared
+ * in the record header. The array is empty if this record class has no
+ * components. If the class is not a record class, that is {@link
+ * #isRecord()} returns {@code false}, then this method returns {@code null}.
+ * Conversely, if {@link #isRecord()} returns {@code true}, then this method
+ * returns a non-null value.
+ *
+ * @apiNote
+ * <p> The following method can be used to find the record canonical constructor:
+ *
+ * <pre>{@code
+ * static <T extends Record> Constructor<T> getCanonicalConstructor(Class<T> cls)
+ * throws NoSuchMethodException {
+ * Class<?>[] paramTypes =
+ * Arrays.stream(cls.getRecordComponents())
+ * .map(RecordComponent::getType)
+ * .toArray(Class<?>[]::new);
+ * return cls.getDeclaredConstructor(paramTypes);
+ * }}</pre>
+ *
+ * @return An array of {@code RecordComponent} objects representing all the
+ * record components of this record class, or {@code null} if this
+ * class is not a record class
+ * @throws SecurityException
+ * If a security manager, <i>s</i>, is present and any of the
+ * following conditions is met:
+ *
+ * <ul>
+ *
+ * <li> the caller's class loader is not the same as the
+ * class loader of this class and invocation of
+ * {@link SecurityManager#checkPermission
+ * s.checkPermission} method with
+ * {@code RuntimePermission("accessDeclaredMembers")}
+ * denies access to the declared methods within this class
+ *
+ * <li> the caller's class loader is not the same as or an
+ * ancestor of the class loader for the current class and
+ * invocation of {@link SecurityManager#checkPackageAccess
+ * s.checkPackageAccess()} denies access to the package
+ * of this class
+ *
+ * </ul>
+ *
+ * @jls 8.10 Record Classes
+ * @since 16
+ */
+ @CallerSensitive
+ public RecordComponent[] getRecordComponents() {
+ // Android-removed: Android doesn't support SecurityManager.
+ /*
+ @SuppressWarnings("removal")
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
+ }
+ */
+ if (!isRecord()) {
+ return null;
+ }
+ return getRecordComponents0();
+ }
+
+ /**
* Populates a list of fields without performing any security or type
* resolution checks first. If no fields exist, the list is not modified.
*
@@ -3673,7 +3838,92 @@
private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);
private native Class<?>[] getDeclaredClasses0();
- *//**
+ */
+
+ /*
+ * Returns an array containing the components of the Record attribute,
+ * or null if the attribute is not present.
+ *
+ * Note that this method returns non-null array on a class with
+ * the Record attribute even if this class is not a record.
+ */
+ // BEGIN Android-changed: Re-implement getRecordComponents0() on ART.
+ // TODO: Use dalvik.annotation.Record instead of named parameters in the constructor.
+ // private native RecordComponent[] getRecordComponents0();
+ private RecordComponent[] getRecordComponents0() {
+ Constructor<?> constructor = getRecordCanonicalConstructor();
+ if (constructor == null) {
+ // Return non-null array as per getRecordComponent() javadoc if isRecord()
+ // returns true. However, it's not ideal, but the implementation will be replaced
+ // when reading it from dalvik.annotation.Record annotation.
+ return new RecordComponent[0];
+ }
+ Parameter[] parameters = constructor.getParameters();
+ RecordComponent[] components = new RecordComponent[parameters.length];
+ Map<String, Field> fields = new HashMap<>(parameters.length);
+ for (Field f : getDeclaredFields()) {
+ fields.put(f.getName(), f);
+ }
+ int i = 0;
+ for (Parameter p : parameters) {
+ String name = p.getName();
+ Method accessor = null;
+ try {
+ accessor = getDeclaredMethod(name);
+ } catch (NoSuchMethodException e) {
+ }
+ Field field = fields.get(name);
+ components[i] = new RecordComponent(this, name, p.getType(), accessor, field);
+ i++;
+ }
+ return components;
+ }
+
+ private Constructor<?> getRecordCanonicalConstructor() {
+ for (Constructor<?> c : getDeclaredConstructors()) {
+ boolean areAllNamed = true;
+ Parameter[] parameters = c.getParameters();
+ for (Parameter p : parameters) {
+ if (!p.isNamePresent()) {
+ areAllNamed = false;
+ break;
+ }
+ }
+ if (!areAllNamed) {
+ continue;
+ }
+
+ // Record has the same number of fields and parameters in constructor.
+ Field[] fields = getDeclaredFields();
+ if (fields.length != parameters.length) {
+ continue;
+ }
+
+ // Record should have the same list param
+ HashMap<String, Parameter> parameterMap = new HashMap<>(parameters.length);
+ for (Parameter p : parameters) {
+ parameterMap.put(p.getName(), p);
+ }
+ for (Field f : fields) {
+ String name = f.getName();
+ Parameter p = parameterMap.get(name);
+ if (p == null || !name.equals(p.getName())) {
+ areAllNamed = false;
+ break;
+ }
+ }
+ if (areAllNamed) {
+ return c;
+ }
+ }
+ return null;
+ }
+ // END Android-changed: Re-implement getRecordComponents0() on ART.
+
+ @FastNative
+ private native boolean isRecord0();
+
+ /**
* Helper method to get the method name from arguments.
*//*
private String methodToString(String name, Class<?>[] argTypes) {
@@ -3757,6 +4007,30 @@
this.getSuperclass() == java.lang.Enum.class;
}
+ /**
+ * Returns {@code true} if and only if this class is a record class.
+ *
+ * <p> The {@linkplain #getSuperclass() direct superclass} of a record
+ * class is {@code java.lang.Record}. A record class is {@linkplain
+ * Modifier#FINAL final}. A record class has (possibly zero) record
+ * components; {@link #getRecordComponents()} returns a non-null but
+ * possibly empty value for a record.
+ *
+ * <p> Note that class {@link Record} is not a record class and thus
+ * invoking this method on class {@code Record} returns {@code false}.
+ *
+ * @return true if and only if this class is a record class, otherwise false
+ * @jls 8.10 Record Classes
+ * @since 16
+ */
+ public boolean isRecord() {
+ // this superclass and final modifier check is not strictly necessary
+ // they are intrinsified and serve as a fast-path check
+ return getSuperclass() == java.lang.Record.class &&
+ (this.getModifiers() & Modifier.FINAL) != 0 &&
+ isRecord0();
+ }
+
// Android-remvoed: Remove unsupported ReflectionFactory.
/*
// Fetches the factory for reflective objects
diff --git a/ojluni/src/main/java/java/lang/Double.java b/ojluni/src/main/java/java/lang/Double.java
index 13db3c3..84cccd6 100644
--- a/ojluni/src/main/java/java/lang/Double.java
+++ b/ojluni/src/main/java/java/lang/Double.java
@@ -158,8 +158,7 @@
* @author Joseph D. Darcy
* @since 1.0
*/
-// Android-removed: ValueBased
-// @jdk.internal.ValueBased
+@jdk.internal.ValueBased
public final class Double extends Number
implements Comparable<Double>
// Android-removed: no Constable support.
diff --git a/ojluni/src/main/java/java/lang/Enum.java b/ojluni/src/main/java/java/lang/Enum.java
index 6a8a3d4..1d1a11e 100644
--- a/ojluni/src/main/java/java/lang/Enum.java
+++ b/ojluni/src/main/java/java/lang/Enum.java
@@ -31,6 +31,11 @@
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
+import java.lang.constant.ClassDesc;
+import java.lang.constant.Constable;
+import java.lang.constant.ConstantDescs;
+import java.lang.constant.DynamicConstantDesc;
+import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import libcore.util.BasicLruCache;
@@ -350,8 +355,7 @@
throw new InvalidObjectException("can't deserialize enum");
}
- // BEGIN Android-removed: dynamic constants not supported on Android.
- /*
+ // Android-changed: Hide EnumDesc API until master switches away from Android U dev. b/270028670
/**
* A <a href="{@docRoot}/java.base/java/lang/constant/package-summary.html#nominal">nominal descriptor</a> for an
* {@code enum} constant.
@@ -359,7 +363,8 @@
* @param <E> the type of the enum constant
*
* @since 12
- *
+ * @hide
+ */
public static final class EnumDesc<E extends Enum<E>>
extends DynamicConstantDesc<E> {
@@ -370,7 +375,7 @@
* @param constantName the unqualified name of the enum constant
* @throws NullPointerException if any argument is null
* @jvms 4.2.2 Unqualified Names
- *
+ */
private EnumDesc(ClassDesc constantClass, String constantName) {
super(ConstantDescs.BSM_ENUM_CONSTANT, requireNonNull(constantName), requireNonNull(constantClass));
}
@@ -385,7 +390,7 @@
* @throws NullPointerException if any argument is null
* @jvms 4.2.2 Unqualified Names
* @since 12
- *
+ */
public static<E extends Enum<E>> EnumDesc<E> of(ClassDesc enumClass,
String constantName) {
return new EnumDesc<>(enumClass, constantName);
@@ -403,6 +408,4 @@
return String.format("EnumDesc[%s.%s]", constantType().displayName(), constantName());
}
}
- */
- // END Android-removed: dynamic constants not supported on Android.
}
diff --git a/ojluni/src/main/java/java/lang/Float.java b/ojluni/src/main/java/java/lang/Float.java
index f563754..78c4327 100644
--- a/ojluni/src/main/java/java/lang/Float.java
+++ b/ojluni/src/main/java/java/lang/Float.java
@@ -70,8 +70,7 @@
* @author Joseph D. Darcy
* @since 1.0
*/
-// Android-removed: ValueBased
-// @jdk.internal.ValueBased
+@jdk.internal.ValueBased
public final class Float extends Number
implements Comparable<Float>
// Android-removed: no Constable support.
diff --git a/ojluni/src/main/java/java/lang/Integer.java b/ojluni/src/main/java/java/lang/Integer.java
index cb3e781..ef5de7e 100644
--- a/ojluni/src/main/java/java/lang/Integer.java
+++ b/ojluni/src/main/java/java/lang/Integer.java
@@ -77,8 +77,7 @@
* @author Joseph D. Darcy
* @since 1.0
*/
-// Android-removed: ValueBased
-// @jdk.internal.ValueBased
+@jdk.internal.ValueBased
public final class Integer extends Number
implements Comparable<Integer>
// Android-removed: no Constable support.
diff --git a/ojluni/src/main/java/java/lang/Long.java b/ojluni/src/main/java/java/lang/Long.java
index eddabaa..0eed16c 100644
--- a/ojluni/src/main/java/java/lang/Long.java
+++ b/ojluni/src/main/java/java/lang/Long.java
@@ -75,8 +75,7 @@
* @author Joseph D. Darcy
* @since 1.0
*/
-// Android-removed: ValueBased
-// @jdk.internal.ValueBased
+@jdk.internal.ValueBased
public final class Long extends Number
implements Comparable<Long>
// Android-removed: no Constable support.
@@ -235,12 +234,11 @@
if (i >= 0)
return toString(i, radix);
else {
- // Android-changed: use `switch (radix)` `switch return (radix)` until javac 17 lands.
- switch (radix) {
- case 2: return toBinaryString(i);
- case 4: return toUnsignedString0(i, 2);
- case 8: return toOctalString(i);
- case 10: {
+ return switch (radix) {
+ case 2 -> toBinaryString(i);
+ case 4 -> toUnsignedString0(i, 2);
+ case 8 -> toOctalString(i);
+ case 10 -> {
/*
* We can get the effect of an unsigned division by 10
* on a long value by first shifting right, yielding a
@@ -251,12 +249,12 @@
*/
long quot = (i >>> 1) / 5;
long rem = i - quot * 10;
- return toString(quot) + rem;
+ yield toString(quot) + rem;
}
- case 16: return toHexString(i);
- case 32: return toUnsignedString0(i, 5);
- default: return toUnsignedBigInteger(i).toString(radix);
- }
+ case 16 -> toHexString(i);
+ case 32 -> toUnsignedString0(i, 5);
+ default -> toUnsignedBigInteger(i).toString(radix);
+ };
}
}
diff --git a/ojluni/src/main/java/java/lang/Math.java b/ojluni/src/main/java/java/lang/Math.java
index f928c72..19b3e6b 100644
--- a/ojluni/src/main/java/java/lang/Math.java
+++ b/ojluni/src/main/java/java/lang/Math.java
@@ -2089,29 +2089,25 @@
public static double ulp(double d) {
int exp = getExponent(d);
- switch(exp) {
- case Double.MAX_EXPONENT + 1: // NaN or infinity
- return Math.abs(d);
+ return switch(exp) {
+ case Double.MAX_EXPONENT + 1 -> Math.abs(d); // NaN or infinity
+ case Double.MIN_EXPONENT - 1 -> Double.MIN_VALUE; // zero or subnormal
+ default -> {
+ assert exp <= Double.MAX_EXPONENT && exp >= Double.MIN_EXPONENT;
- case Double.MIN_EXPONENT - 1: // zero or subnormal
- return Double.MIN_VALUE;
-
- default:
- assert exp <= Double.MAX_EXPONENT && exp >= Double.MIN_EXPONENT;
-
- // ulp(x) is usually 2^(SIGNIFICAND_WIDTH-1)*(2^ilogb(x))
- exp = exp - (DoubleConsts.SIGNIFICAND_WIDTH-1);
- if (exp >= Double.MIN_EXPONENT) {
- return powerOfTwoD(exp);
+ // ulp(x) is usually 2^(SIGNIFICAND_WIDTH-1)*(2^ilogb(x))
+ exp = exp - (DoubleConsts.SIGNIFICAND_WIDTH - 1);
+ if (exp >= Double.MIN_EXPONENT) {
+ yield powerOfTwoD(exp);
+ } else {
+ // return a subnormal result; left shift integer
+ // representation of Double.MIN_VALUE appropriate
+ // number of positions
+ yield Double.longBitsToDouble(1L <<
+ (exp - (Double.MIN_EXPONENT - (DoubleConsts.SIGNIFICAND_WIDTH - 1))));
+ }
}
- else {
- // return a subnormal result; left shift integer
- // representation of Double.MIN_VALUE appropriate
- // number of positions
- return Double.longBitsToDouble(1L <<
- (exp - (Double.MIN_EXPONENT - (DoubleConsts.SIGNIFICAND_WIDTH-1)) ));
- }
- }
+ };
}
/**
@@ -2140,28 +2136,25 @@
public static float ulp(float f) {
int exp = getExponent(f);
- switch(exp) {
- case Float.MAX_EXPONENT+1: // NaN or infinity
- return Math.abs(f);
+ return switch(exp) {
+ case Float.MAX_EXPONENT + 1 -> Math.abs(f); // NaN or infinity
+ case Float.MIN_EXPONENT - 1 -> Float.MIN_VALUE; // zero or subnormal
+ default -> {
+ assert exp <= Float.MAX_EXPONENT && exp >= Float.MIN_EXPONENT;
- case Float.MIN_EXPONENT-1: // zero or subnormal
- return Float.MIN_VALUE;
-
- default:
- assert exp <= Float.MAX_EXPONENT && exp >= Float.MIN_EXPONENT;
-
- // ulp(x) is usually 2^(SIGNIFICAND_WIDTH-1)*(2^ilogb(x))
- exp = exp - (FloatConsts.SIGNIFICAND_WIDTH-1);
- if (exp >= Float.MIN_EXPONENT) {
- return powerOfTwoF(exp);
- } else {
- // return a subnormal result; left shift integer
- // representation of FloatConsts.MIN_VALUE appropriate
- // number of positions
- return Float.intBitsToFloat(1 <<
- (exp - (Float.MIN_EXPONENT - (FloatConsts.SIGNIFICAND_WIDTH-1)) ));
+ // ulp(x) is usually 2^(SIGNIFICAND_WIDTH-1)*(2^ilogb(x))
+ exp = exp - (FloatConsts.SIGNIFICAND_WIDTH - 1);
+ if (exp >= Float.MIN_EXPONENT) {
+ yield powerOfTwoF(exp);
+ } else {
+ // return a subnormal result; left shift integer
+ // representation of FloatConsts.MIN_VALUE appropriate
+ // number of positions
+ yield Float.intBitsToFloat(1 <<
+ (exp - (Float.MIN_EXPONENT - (FloatConsts.SIGNIFICAND_WIDTH - 1))));
+ }
}
- }
+ };
}
/**
diff --git a/ojluni/src/main/java/java/lang/Record.java b/ojluni/src/main/java/java/lang/Record.java
new file mode 100644
index 0000000..2f8bd60
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/Record.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang;
+
+/**
+ * This is the common base class of all Java language record classes.
+ *
+ * <p>More information about records, including descriptions of the
+ * implicitly declared methods synthesized by the compiler, can be
+ * found in section 8.10 of
+ * <cite>The Java Language Specification</cite>.
+ *
+ * <p>A <em>record class</em> is a shallowly immutable, transparent carrier for
+ * a fixed set of values, called the <em>record components</em>. The Java
+ * language provides concise syntax for declaring record classes, whereby the
+ * record components are declared in the record header. The list of record
+ * components declared in the record header form the <em>record descriptor</em>.
+ *
+ * <p>A record class has the following mandated members: a <em>canonical
+ * constructor</em>, which must provide at least as much access as the record
+ * class and whose descriptor is the same as the record descriptor;
+ * a private final field corresponding to each component, whose name and
+ * type are the same as that of the component; a public accessor method
+ * corresponding to each component, whose name and return type are the same as
+ * that of the component. If not explicitly declared in the body of the record,
+ * implicit implementations for these members are provided.
+ *
+ * <p>The implicit declaration of the canonical constructor has the same accessibility
+ * as the record class and initializes the component fields from the corresponding
+ * constructor arguments. The implicit declaration of the accessor methods returns
+ * the value of the corresponding component field. The implicit declaration of the
+ * {@link Object#equals(Object)}, {@link Object#hashCode()}, and {@link Object#toString()}
+ * methods are derived from all of the component fields.
+ *
+ * <p>The primary reasons to provide an explicit declaration for the
+ * canonical constructor or accessor methods are to validate constructor
+ * arguments, perform defensive copies on mutable components, or normalize groups
+ * of components (such as reducing a rational number to lowest terms.)
+ *
+ * <p>For all record classes, the following invariant must hold: if a record R's
+ * components are {@code c1, c2, ... cn}, then if a record instance is copied
+ * as follows:
+ * <pre>
+ * R copy = new R(r.c1(), r.c2(), ..., r.cn());
+ * </pre>
+ * then it must be the case that {@code r.equals(copy)}.
+ *
+ * @apiNote
+ * A record class that {@code implements} {@link java.io.Serializable} is said
+ * to be a <i>serializable record</i>. Serializable records are serialized and
+ * deserialized differently than ordinary serializable objects. During
+ * deserialization the record's canonical constructor is invoked to construct
+ * the record object. Certain serialization-related methods, such as readObject
+ * and writeObject, are ignored for serializable records. More information about
+ * serializable records can be found in the
+ * <a href="{@docRoot}/../specs/serialization/serial-arch.html#serialization-of-records">
+ * <cite>Java Object Serialization Specification,</cite> Section 1.13,
+ * "Serialization of Records"</a>.
+ *
+ * @apiNote
+ * A record class structure can be obtained at runtime via reflection.
+ * See {@link Class#isRecord()} and {@link Class#getRecordComponents()} for more details.
+ *
+ * @jls 8.10 Record Types
+ * @since 16
+ */
+public abstract class Record {
+ /**
+ * Constructor for record classes to call.
+ */
+ protected Record() {}
+
+ /**
+ * Indicates whether some other object is "equal to" this one. In addition
+ * to the general contract of {@link Object#equals(Object) Object.equals},
+ * record classes must further obey the invariant that when
+ * a record instance is "copied" by passing the result of the record component
+ * accessor methods to the canonical constructor, as follows:
+ * <pre>
+ * R copy = new R(r.c1(), r.c2(), ..., r.cn());
+ * </pre>
+ * then it must be the case that {@code r.equals(copy)}.
+ *
+ * @implSpec
+ * The implicitly provided implementation returns {@code true} if
+ * and only if the argument is an instance of the same record class
+ * as this record, and each component of this record is equal to
+ * the corresponding component of the argument; otherwise, {@code
+ * false} is returned. Equality of a component {@code c} is
+ * determined as follows:
+ * <ul>
+ *
+ * <li> If the component is of a reference type, the component is
+ * considered equal if and only if {@link
+ * java.util.Objects#equals(Object,Object)
+ * Objects.equals(this.c, r.c} would return {@code true}.
+ *
+ * <li> If the component is of a primitive type, using the
+ * corresponding primitive wrapper class {@code PW} (the
+ * corresponding wrapper class for {@code int} is {@code
+ * java.lang.Integer}, and so on), the component is considered
+ * equal if and only if {@code
+ * PW.compare(this.c, r.c)} would return {@code 0}.
+ *
+ * </ul>
+ *
+ * Apart from the semantics described above, the precise algorithm
+ * used in the implicitly provided implementation is unspecified
+ * and is subject to change. The implementation may or may not use
+ * calls to the particular methods listed, and may or may not
+ * perform comparisons in the order of component declaration.
+ *
+ * @see java.util.Objects#equals(Object,Object)
+ *
+ * @param obj the reference object with which to compare.
+ * @return {@code true} if this record is equal to the
+ * argument; {@code false} otherwise.
+ */
+ @Override
+ public abstract boolean equals(Object obj);
+
+ /**
+ * Returns a hash code value for the record.
+ * Obeys the general contract of {@link Object#hashCode Object.hashCode}.
+ * For records, hashing behavior is constrained by the refined contract
+ * of {@link Record#equals Record.equals}, so that any two records
+ * created from the same components must have the same hash code.
+ *
+ * @implSpec
+ * The implicitly provided implementation returns a hash code value derived
+ * by combining appropriate hashes from each component.
+ * The precise algorithm used in the implicitly provided implementation
+ * is unspecified and is subject to change within the above limits.
+ * The resulting integer need not remain consistent from one
+ * execution of an application to another execution of the same
+ * application, even if the hashes of the component values were to
+ * remain consistent in this way. Also, a component of primitive
+ * type may contribute its bits to the hash code differently than
+ * the {@code hashCode} of its primitive wrapper class.
+ *
+ * @see Object#hashCode()
+ *
+ * @return a hash code value for this record.
+ */
+ @Override
+ public abstract int hashCode();
+
+ /**
+ * Returns a string representation of the record.
+ * In accordance with the general contract of {@link Object#toString()},
+ * the {@code toString} method returns a string that
+ * "textually represents" this record. The result should
+ * be a concise but informative representation that is easy for a
+ * person to read.
+ * <p>
+ * In addition to this general contract, record classes must further
+ * participate in the invariant that any two records which are
+ * {@linkplain Record#equals(Object) equal} must produce equal
+ * strings. This invariant is necessarily relaxed in the rare
+ * case where corresponding equal component values might fail
+ * to produce equal strings for themselves.
+ *
+ * @implSpec
+ * The implicitly provided implementation returns a string which
+ * contains the name of the record class, the names of components
+ * of the record, and string representations of component values,
+ * so as to fulfill the contract of this method.
+ * The precise format produced by this implicitly provided implementation
+ * is subject to change, so the present syntax should not be parsed
+ * by applications to recover record component values.
+ *
+ * @see Object#toString()
+ *
+ * @return a string representation of the object.
+ */
+ @Override
+ public abstract String toString();
+}
diff --git a/ojluni/src/main/java/java/lang/Short.java b/ojluni/src/main/java/java/lang/Short.java
index 05fcd88..5608d47 100644
--- a/ojluni/src/main/java/java/lang/Short.java
+++ b/ojluni/src/main/java/java/lang/Short.java
@@ -65,8 +65,7 @@
* @see java.lang.Number
* @since 1.1
*/
-// Android-removed: ValueBased
-// @jdk.internal.ValueBased
+@jdk.internal.ValueBased
public final class Short extends Number implements Comparable<Short> {
// Android-removed: no Constable support.
// , Constable {
diff --git a/ojluni/src/main/java/java/lang/String.java b/ojluni/src/main/java/java/lang/String.java
index b165137..d6d0275 100644
--- a/ojluni/src/main/java/java/lang/String.java
+++ b/ojluni/src/main/java/java/lang/String.java
@@ -3688,12 +3688,7 @@
}
char lastChar = charAt(length - 1);
boolean optOut = lastChar == '\n' || lastChar == '\r';
- // BEGIN Android-changed: Stream#toList() is not yet imported. See http://b/241231766.
- /*
List<String> lines = lines().toList();
- */
- List<String> lines = lines().collect(Collectors.toList());
- // END Android-changed: Stream#toList() is not yet imported. See http://b/241231766.
final int outdent = optOut ? 0 : outdent(lines);
return lines.stream()
.map(line -> {
diff --git a/ojluni/src/main/java/java/lang/constant/AsTypeMethodHandleDesc.java b/ojluni/src/main/java/java/lang/constant/AsTypeMethodHandleDesc.java
new file mode 100644
index 0000000..b2fe912
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/AsTypeMethodHandleDesc.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+import static java.lang.constant.ConstantDescs.BSM_INVOKE;
+import static java.lang.constant.ConstantDescs.CD_MethodHandle;
+import static java.util.Objects.requireNonNull;
+
+/**
+ * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
+ * {@link MethodHandle} constant that performs a {@link MethodHandle#asType(MethodType)}
+ * adaptation on another {@link MethodHandle}.
+ */
+final class AsTypeMethodHandleDesc extends DynamicConstantDesc<MethodHandle>
+ implements MethodHandleDesc {
+
+ private final MethodHandleDesc underlying;
+ private final MethodTypeDesc type;
+
+ AsTypeMethodHandleDesc(MethodHandleDesc underlying, MethodTypeDesc type) {
+ super(BSM_INVOKE, ConstantDescs.DEFAULT_NAME, CD_MethodHandle,
+ ConstantDescs.MHD_METHODHANDLE_ASTYPE, underlying, type);
+ this.underlying = requireNonNull(underlying);
+ this.type = requireNonNull(type);
+ }
+
+ @Override
+ public MethodTypeDesc invocationType() {
+ return type;
+ }
+
+ @Override
+ public MethodHandle resolveConstantDesc(MethodHandles.Lookup lookup)
+ throws ReflectiveOperationException {
+ MethodHandle handle = (MethodHandle) underlying.resolveConstantDesc(lookup);
+ MethodType methodType = (MethodType) type.resolveConstantDesc(lookup);
+ return handle.asType(methodType);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s.asType%s", underlying.toString(), type.displayDescriptor());
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/constant/ClassDesc.java b/ojluni/src/main/java/java/lang/constant/ClassDesc.java
new file mode 100644
index 0000000..435d992
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/ClassDesc.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.lang.invoke.TypeDescriptor;
+import java.util.stream.Stream;
+
+import sun.invoke.util.Wrapper;
+
+import static java.lang.constant.ConstantUtils.binaryToInternal;
+import static java.lang.constant.ConstantUtils.dropLastChar;
+import static java.lang.constant.ConstantUtils.internalToBinary;
+import static java.lang.constant.ConstantUtils.validateMemberName;
+import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.joining;
+
+/**
+ * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
+ * {@link Class} constant.
+ *
+ * <p>For common system types, including all the primitive types, there are
+ * predefined {@linkplain ClassDesc} constants in {@link ConstantDescs}.
+ * (The {@code java.lang.constant} APIs consider {@code void} to be a primitive type.)
+ * To create a {@linkplain ClassDesc} for a class or interface type, use {@link #of} or
+ * {@link #ofDescriptor(String)}; to create a {@linkplain ClassDesc} for an array
+ * type, use {@link #ofDescriptor(String)}, or first obtain a
+ * {@linkplain ClassDesc} for the component type and then call the {@link #arrayType()}
+ * or {@link #arrayType(int)} methods.
+ *
+ * @see ConstantDescs
+ *
+ * @since 12
+ */
+public sealed interface ClassDesc
+ extends ConstantDesc,
+ TypeDescriptor.OfField<ClassDesc>
+ permits PrimitiveClassDescImpl,
+ ReferenceClassDescImpl {
+
+ /**
+ * Returns a {@linkplain ClassDesc} for a class or interface type,
+ * given the name of the class or interface, such as {@code "java.lang.String"}.
+ * (To create a descriptor for an array type, either use {@link #ofDescriptor(String)}
+ * or {@link #arrayType()}; to create a descriptor for a primitive type, use
+ * {@link #ofDescriptor(String)} or use the predefined constants in
+ * {@link ConstantDescs}).
+ *
+ * @param name the fully qualified (dot-separated) binary class name
+ * @return a {@linkplain ClassDesc} describing the desired class
+ * @throws NullPointerException if the argument is {@code null}
+ * @throws IllegalArgumentException if the name string is not in the
+ * correct format
+ */
+ static ClassDesc of(String name) {
+ ConstantUtils.validateBinaryClassName(requireNonNull(name));
+ return ClassDesc.ofDescriptor("L" + binaryToInternal(name) + ";");
+ }
+
+ /**
+ * Returns a {@linkplain ClassDesc} for a class or interface type,
+ * given a package name and the unqualified (simple) name for the
+ * class or interface.
+ *
+ * @param packageName the package name (dot-separated); if the package
+ * name is the empty string, the class is considered to
+ * be in the unnamed package
+ * @param className the unqualified (simple) class name
+ * @return a {@linkplain ClassDesc} describing the desired class
+ * @throws NullPointerException if any argument is {@code null}
+ * @throws IllegalArgumentException if the package name or class name are
+ * not in the correct format
+ */
+ static ClassDesc of(String packageName, String className) {
+ ConstantUtils.validateBinaryClassName(requireNonNull(packageName));
+ if (packageName.isEmpty()) {
+ return of(className);
+ }
+ validateMemberName(requireNonNull(className), false);
+ return ofDescriptor("L" + binaryToInternal(packageName) +
+ (packageName.length() > 0 ? "/" : "") + className + ";");
+ }
+
+ /**
+ * Returns a {@linkplain ClassDesc} given a descriptor string for a class,
+ * interface, array, or primitive type.
+ *
+ * @apiNote
+ *
+ * A field type descriptor string for a non-array type is either
+ * a one-letter code corresponding to a primitive type
+ * ({@code "J", "I", "C", "S", "B", "D", "F", "Z", "V"}), or the letter {@code "L"}, followed
+ * by the fully qualified binary name of a class, followed by {@code ";"}.
+ * A field type descriptor for an array type is the character {@code "["}
+ * followed by the field descriptor for the component type. Examples of
+ * valid type descriptor strings include {@code "Ljava/lang/String;"}, {@code "I"},
+ * {@code "[I"}, {@code "V"}, {@code "[Ljava/lang/String;"}, etc.
+ * See JVMS 4.3.2 ("Field Descriptors") for more detail.
+ *
+ * @param descriptor a field descriptor string
+ * @return a {@linkplain ClassDesc} describing the desired class
+ * @throws NullPointerException if the argument is {@code null}
+ * @throws IllegalArgumentException if the name string is not in the
+ * correct format
+ * @jvms 4.3.2 Field Descriptors
+ * @jvms 4.4.1 The CONSTANT_Class_info Structure
+ */
+ static ClassDesc ofDescriptor(String descriptor) {
+ requireNonNull(descriptor);
+ if (descriptor.isEmpty()) {
+ throw new IllegalArgumentException(
+ "not a valid reference type descriptor: " + descriptor);
+ }
+ int depth = ConstantUtils.arrayDepth(descriptor);
+ if (depth > ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) {
+ throw new IllegalArgumentException(
+ "Cannot create an array type descriptor with more than " +
+ ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS + " dimensions");
+ }
+ return (descriptor.length() == 1)
+ ? new PrimitiveClassDescImpl(descriptor)
+ : new ReferenceClassDescImpl(descriptor);
+ }
+
+ /**
+ * Returns a {@linkplain ClassDesc} for an array type whose component type
+ * is described by this {@linkplain ClassDesc}.
+ *
+ * @return a {@linkplain ClassDesc} describing the array type
+ * @throws IllegalStateException if the resulting {@linkplain ClassDesc} would have an array rank of greater than 255
+ * @jvms 4.4.1 The CONSTANT_Class_info Structure
+ */
+ default ClassDesc arrayType() {
+ int depth = ConstantUtils.arrayDepth(descriptorString());
+ if (depth >= ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) {
+ throw new IllegalStateException(
+ "Cannot create an array type descriptor with more than " +
+ ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS + " dimensions");
+ }
+ return arrayType(1);
+ }
+
+ /**
+ * Returns a {@linkplain ClassDesc} for an array type of the specified rank,
+ * whose component type is described by this {@linkplain ClassDesc}.
+ *
+ * @param rank the rank of the array
+ * @return a {@linkplain ClassDesc} describing the array type
+ * @throws IllegalArgumentException if the rank is less than or equal to zero or if the rank of the resulting array type is
+ * greater than 255
+ * @jvms 4.4.1 The CONSTANT_Class_info Structure
+ */
+ default ClassDesc arrayType(int rank) {
+ int currentDepth = ConstantUtils.arrayDepth(descriptorString());
+ if (rank <= 0 || currentDepth + rank > ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS)
+ throw new IllegalArgumentException("rank: " + currentDepth + rank);
+ return ClassDesc.ofDescriptor("[".repeat(rank) + descriptorString());
+ }
+
+ /**
+ * Returns a {@linkplain ClassDesc} for a nested class of the class or
+ * interface type described by this {@linkplain ClassDesc}.
+ *
+ * @apiNote
+ *
+ * Example: If descriptor {@code d} describes the class {@code java.util.Map}, a
+ * descriptor for the class {@code java.util.Map.Entry} could be obtained
+ * by {@code d.nested("Entry")}.
+ *
+ * @param nestedName the unqualified name of the nested class
+ * @return a {@linkplain ClassDesc} describing the nested class
+ * @throws NullPointerException if the argument is {@code null}
+ * @throws IllegalStateException if this {@linkplain ClassDesc} does not
+ * describe a class or interface type
+ * @throws IllegalArgumentException if the nested class name is invalid
+ */
+ default ClassDesc nested(String nestedName) {
+ validateMemberName(nestedName, false);
+ if (!isClassOrInterface())
+ throw new IllegalStateException("Outer class is not a class or interface type");
+ return ClassDesc.ofDescriptor(dropLastChar(descriptorString()) + "$" + nestedName + ";");
+ }
+
+ /**
+ * Returns a {@linkplain ClassDesc} for a nested class of the class or
+ * interface type described by this {@linkplain ClassDesc}.
+ *
+ * @param firstNestedName the unqualified name of the first level of nested class
+ * @param moreNestedNames the unqualified name(s) of the remaining levels of
+ * nested class
+ * @return a {@linkplain ClassDesc} describing the nested class
+ * @throws NullPointerException if any argument or its contents is {@code null}
+ * @throws IllegalStateException if this {@linkplain ClassDesc} does not
+ * describe a class or interface type
+ * @throws IllegalArgumentException if the nested class name is invalid
+ */
+ default ClassDesc nested(String firstNestedName, String... moreNestedNames) {
+ if (!isClassOrInterface())
+ throw new IllegalStateException("Outer class is not a class or interface type");
+ validateMemberName(firstNestedName, false);
+ requireNonNull(moreNestedNames);
+ for (String addNestedNames : moreNestedNames) {
+ validateMemberName(addNestedNames, false);
+ }
+ return moreNestedNames.length == 0
+ ? nested(firstNestedName)
+ : nested(firstNestedName + Stream.of(moreNestedNames).collect(joining("$", "$", "")));
+ }
+
+ /**
+ * Returns whether this {@linkplain ClassDesc} describes an array type.
+ *
+ * @return whether this {@linkplain ClassDesc} describes an array type
+ */
+ default boolean isArray() {
+ return descriptorString().startsWith("[");
+ }
+
+ /**
+ * Returns whether this {@linkplain ClassDesc} describes a primitive type.
+ *
+ * @return whether this {@linkplain ClassDesc} describes a primitive type
+ */
+ default boolean isPrimitive() {
+ return descriptorString().length() == 1;
+ }
+
+ /**
+ * Returns whether this {@linkplain ClassDesc} describes a class or interface type.
+ *
+ * @return whether this {@linkplain ClassDesc} describes a class or interface type
+ */
+ default boolean isClassOrInterface() {
+ return descriptorString().startsWith("L");
+ }
+
+ /**
+ * Returns the component type of this {@linkplain ClassDesc}, if it describes
+ * an array type, or {@code null} otherwise.
+ *
+ * @return a {@linkplain ClassDesc} describing the component type, or {@code null}
+ * if this descriptor does not describe an array type
+ */
+ default ClassDesc componentType() {
+ return isArray() ? ClassDesc.ofDescriptor(descriptorString().substring(1)) : null;
+ }
+
+ /**
+ * Returns the package name of this {@linkplain ClassDesc}, if it describes
+ * a class or interface type.
+ *
+ * @return the package name, or the empty string if the class is in the
+ * default package, or this {@linkplain ClassDesc} does not describe a class or interface type
+ */
+ default String packageName() {
+ if (!isClassOrInterface())
+ return "";
+ String className = internalToBinary(ConstantUtils.dropFirstAndLastChar(descriptorString()));
+ int index = className.lastIndexOf('.');
+ return (index == -1) ? "" : className.substring(0, index);
+ }
+
+ /**
+ * Returns a human-readable name for the type described by this descriptor.
+ *
+ * @implSpec
+ * <p>The default implementation returns the simple name
+ * (e.g., {@code int}) for primitive types, the unqualified class name
+ * for class or interface types, or the display name of the component type
+ * suffixed with the appropriate number of {@code []} pairs for array types.
+ *
+ * @return the human-readable name
+ */
+ default String displayName() {
+ if (isPrimitive())
+ return Wrapper.forBasicType(descriptorString().charAt(0)).primitiveSimpleName();
+ else if (isClassOrInterface()) {
+ return descriptorString().substring(Math.max(1, descriptorString().lastIndexOf('/') + 1),
+ descriptorString().length() - 1);
+ }
+ else if (isArray()) {
+ int depth = ConstantUtils.arrayDepth(descriptorString());
+ ClassDesc c = this;
+ for (int i=0; i<depth; i++)
+ c = c.componentType();
+ return c.displayName() + "[]".repeat(depth);
+ }
+ else
+ throw new IllegalStateException(descriptorString());
+ }
+
+ /**
+ * Returns a field type descriptor string for this type
+ *
+ * @return the descriptor string
+ * @jvms 4.3.2 Field Descriptors
+ */
+ String descriptorString();
+
+ /**
+ * Compare the specified object with this descriptor for equality. Returns
+ * {@code true} if and only if the specified object is also a
+ * {@linkplain ClassDesc} and both describe the same type.
+ *
+ * @param o the other object
+ * @return whether this descriptor is equal to the other object
+ */
+ boolean equals(Object o);
+}
diff --git a/ojluni/src/main/java/java/lang/constant/Constable.java b/ojluni/src/main/java/java/lang/constant/Constable.java
new file mode 100644
index 0000000..3387565
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/Constable.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.VarHandle;
+import java.util.Optional;
+
+/**
+ * Represents a type which is <em>constable</em>. A constable type is one whose
+ * values are constants that can be represented in the constant pool of a Java
+ * classfile as described in JVMS 4.4, and whose instances can describe themselves
+ * nominally as a {@link ConstantDesc}.
+ *
+ * <p>Some constable types have a native representation in the constant pool:
+ * {@link String}, {@link Integer}, {@link Long}, {@link Float},
+ * {@link Double}, {@link Class}, {@link MethodType}, and {@link MethodHandle}.
+ * The types {@link String}, {@link Integer}, {@link Long}, {@link Float},
+ * and {@link Double} serve as their own nominal descriptors; {@link Class},
+ * {@link MethodType}, and {@link MethodHandle} have corresponding nominal
+ * descriptors {@link ClassDesc}, {@link MethodTypeDesc}, and {@link MethodHandleDesc}.
+ *
+ * <p>Other reference types can be constable if their instances can describe
+ * themselves in nominal form as a {@link ConstantDesc}. Examples in the Java SE
+ * Platform API are types that support Java language features such as {@link Enum},
+ * and runtime support classes such as {@link VarHandle}. These are typically
+ * described with a {@link DynamicConstantDesc}, which describes dynamically
+ * generated constants (JVMS 4.4.10).
+ *
+ * <p>The nominal form of an instance of a constable type is obtained via
+ * {@link #describeConstable()}. A {@linkplain Constable} need
+ * not be able to (or may choose not to) describe all its instances in the form of
+ * a {@link ConstantDesc}; this method returns an {@link Optional} that can be
+ * empty to indicate that a nominal descriptor could not be created for an instance.
+ * (For example, {@link MethodHandle} will produce nominal descriptors for direct
+ * method handles, but not necessarily those produced by method handle
+ * combinators.)
+ * @jvms 4.4 The Constant Pool
+ * @jvms 4.4.10 The {@code CONSTANT_Dynamic_info} and {@code CONSTANT_InvokeDynamic_info} Structures
+ *
+ * @since 12
+ */
+public interface Constable {
+ /**
+ * Returns an {@link Optional} containing the nominal descriptor for this
+ * instance, if one can be constructed, or an empty {@link Optional}
+ * if one cannot be constructed.
+ *
+ * @return An {@link Optional} containing the resulting nominal descriptor,
+ * or an empty {@link Optional} if one cannot be constructed.
+ */
+ Optional<? extends ConstantDesc> describeConstable();
+}
diff --git a/ojluni/src/main/java/java/lang/constant/ConstantDesc.java b/ojluni/src/main/java/java/lang/constant/ConstantDesc.java
new file mode 100644
index 0000000..bacd1ac
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/ConstantDesc.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.lang.Enum.EnumDesc;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.VarHandle.VarHandleDesc;
+
+/**
+ * A <a href="package-summary.html#nominal">nominal descriptor</a> for a loadable
+ * constant value, as defined in JVMS 4.4. Such a descriptor can be resolved via
+ * {@link ConstantDesc#resolveConstantDesc(MethodHandles.Lookup)} to yield the
+ * constant value itself.
+ *
+ * <p>Class names in a nominal descriptor, like class names in the constant pool
+ * of a classfile, must be interpreted with respect to a particular class
+ * loader, which is not part of the nominal descriptor.
+ *
+ * <p>Static constants that are expressible natively in the constant pool ({@link String},
+ * {@link Integer}, {@link Long}, {@link Float}, and {@link Double}) implement
+ * {@link ConstantDesc}, and serve as nominal descriptors for themselves.
+ * Native linkable constants ({@link Class}, {@link MethodType}, and
+ * {@link MethodHandle}) have counterpart {@linkplain ConstantDesc} types:
+ * {@link ClassDesc}, {@link MethodTypeDesc}, and {@link MethodHandleDesc}.
+ * Other constants are represented by subtypes of {@link DynamicConstantDesc}.
+ *
+ * <p>APIs that perform generation or parsing of bytecode are encouraged to use
+ * {@linkplain ConstantDesc} to describe the operand of an {@code ldc} instruction
+ * (including dynamic constants), the static bootstrap arguments of
+ * dynamic constants and {@code invokedynamic} instructions, and other
+ * bytecodes or classfile structures that make use of the constant pool.
+ *
+ * <p>Constants describing various common constants (such as {@link ClassDesc}
+ * instances for platform types) can be found in {@link ConstantDescs}.
+ *
+ * <p>Implementations of {@linkplain ConstantDesc} should be immutable
+ * and their behavior should not rely on object identity.
+ *
+ * <p>Non-platform classes should not implement {@linkplain ConstantDesc} directly.
+ * Instead, they should extend {@link DynamicConstantDesc} (as {@link EnumDesc}
+ * and {@link VarHandleDesc} do.)
+ *
+ * <p>Nominal descriptors should be compared using the
+ * {@link Object#equals(Object)} method. There is no guarantee that any
+ * particular entity will always be represented by the same descriptor instance.
+ *
+ * @see Constable
+ * @see ConstantDescs
+ *
+ * @jvms 4.4 The Constant Pool
+ *
+ * @since 12
+ */
+public sealed interface ConstantDesc
+ permits ClassDesc,
+ MethodHandleDesc,
+ MethodTypeDesc,
+ // Android-changed: Remove the below boxed types until they implement this.
+ // Double,
+ // DynamicConstantDesc,
+ // Float,
+ // Integer,
+ // Long,
+ // String {
+ DynamicConstantDesc {
+
+ /**
+ * Resolves this descriptor reflectively, emulating the resolution behavior
+ * of JVMS 5.4.3 and the access control behavior of JVMS 5.4.4. The resolution
+ * and access control context is provided by the {@link MethodHandles.Lookup}
+ * parameter. No caching of the resulting value is performed.
+ *
+ * @param lookup The {@link MethodHandles.Lookup} to provide name resolution
+ * and access control context
+ * @return the resolved constant value
+ * @throws ReflectiveOperationException if a class, method, or field
+ * could not be reflectively resolved in the course of resolution
+ * @throws LinkageError if a linkage error occurs
+ *
+ * @apiNote {@linkplain MethodTypeDesc} can represent method type descriptors
+ * that are not representable by {@linkplain MethodType}, such as methods with
+ * more than 255 parameter slots, so attempts to resolve these may result in errors.
+ *
+ * @jvms 5.4.3 Resolution
+ * @jvms 5.4.4 Access Control
+ */
+ Object resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException;
+}
diff --git a/ojluni/src/main/java/java/lang/constant/ConstantDescs.java b/ojluni/src/main/java/java/lang/constant/ConstantDescs.java
new file mode 100644
index 0000000..3a000d1
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/ConstantDescs.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.lang.Enum.EnumDesc;
+import java.lang.invoke.CallSite;
+import java.lang.invoke.ConstantBootstraps;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.VarHandle;
+import java.lang.invoke.VarHandle.VarHandleDesc;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static java.lang.constant.DirectMethodHandleDesc.*;
+import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC;
+
+/**
+ * Predefined values of <a href="package-summary.html#nominal">nominal descriptor</a>
+ * for common constants, including descriptors for primitive class types and
+ * other common platform types, and descriptors for method handles for standard
+ * bootstrap methods.
+ *
+ * @see ConstantDesc
+ *
+ * @since 12
+ */
+public final class ConstantDescs {
+ // No instances
+ private ConstantDescs() { }
+
+ /** Invocation name to use when no name is needed, such as the name of a
+ * constructor, or the invocation name of a dynamic constant or dynamic
+ * callsite when the bootstrap is known to ignore the invocation name.
+ */
+ public static final String DEFAULT_NAME = "_";
+
+ // Don't change the order of these declarations!
+
+ /** {@link ClassDesc} representing {@link Object} */
+ public static final ClassDesc CD_Object = ClassDesc.of("java.lang.Object");
+
+ /** {@link ClassDesc} representing {@link String} */
+ public static final ClassDesc CD_String = ClassDesc.of("java.lang.String");
+
+ /** {@link ClassDesc} representing {@link Class} */
+ public static final ClassDesc CD_Class = ClassDesc.of("java.lang.Class");
+
+ /** {@link ClassDesc} representing {@link Number} */
+ public static final ClassDesc CD_Number = ClassDesc.of("java.lang.Number");
+
+ /** {@link ClassDesc} representing {@link Integer} */
+ public static final ClassDesc CD_Integer = ClassDesc.of("java.lang.Integer");
+
+ /** {@link ClassDesc} representing {@link Long} */
+ public static final ClassDesc CD_Long = ClassDesc.of("java.lang.Long");
+
+ /** {@link ClassDesc} representing {@link Float} */
+ public static final ClassDesc CD_Float = ClassDesc.of("java.lang.Float");
+
+ /** {@link ClassDesc} representing {@link Double} */
+ public static final ClassDesc CD_Double = ClassDesc.of("java.lang.Double");
+
+ /** {@link ClassDesc} representing {@link Short} */
+ public static final ClassDesc CD_Short = ClassDesc.of("java.lang.Short");
+
+ /** {@link ClassDesc} representing {@link Byte} */
+ public static final ClassDesc CD_Byte = ClassDesc.of("java.lang.Byte");
+
+ /** {@link ClassDesc} representing {@link Character} */
+ public static final ClassDesc CD_Character = ClassDesc.of("java.lang.Character");
+
+ /** {@link ClassDesc} representing {@link Boolean} */
+ public static final ClassDesc CD_Boolean = ClassDesc.of("java.lang.Boolean");
+
+ /** {@link ClassDesc} representing {@link Void} */
+ public static final ClassDesc CD_Void = ClassDesc.of("java.lang.Void");
+
+ /** {@link ClassDesc} representing {@link Throwable} */
+ public static final ClassDesc CD_Throwable = ClassDesc.of("java.lang.Throwable");
+
+ /** {@link ClassDesc} representing {@link Exception} */
+ public static final ClassDesc CD_Exception = ClassDesc.of("java.lang.Exception");
+
+ /** {@link ClassDesc} representing {@link Enum} */
+ public static final ClassDesc CD_Enum = ClassDesc.of("java.lang.Enum");
+
+ /** {@link ClassDesc} representing {@link VarHandle} */
+ public static final ClassDesc CD_VarHandle = ClassDesc.of("java.lang.invoke.VarHandle");
+
+ /** {@link ClassDesc} representing {@link MethodHandles} */
+ public static final ClassDesc CD_MethodHandles = ClassDesc.of("java.lang.invoke.MethodHandles");
+
+ /** {@link ClassDesc} representing {@link MethodHandles.Lookup} */
+ public static final ClassDesc CD_MethodHandles_Lookup = CD_MethodHandles.nested("Lookup");
+
+ /** {@link ClassDesc} representing {@link MethodHandle} */
+ public static final ClassDesc CD_MethodHandle = ClassDesc.of("java.lang.invoke.MethodHandle");
+
+ /** {@link ClassDesc} representing {@link MethodType} */
+ public static final ClassDesc CD_MethodType = ClassDesc.of("java.lang.invoke.MethodType");
+
+ /** {@link ClassDesc} representing {@link CallSite} */
+ public static final ClassDesc CD_CallSite = ClassDesc.of("java.lang.invoke.CallSite");
+
+ /** {@link ClassDesc} representing {@link Collection} */
+ public static final ClassDesc CD_Collection = ClassDesc.of("java.util.Collection");
+
+ /** {@link ClassDesc} representing {@link List} */
+ public static final ClassDesc CD_List = ClassDesc.of("java.util.List");
+
+ /** {@link ClassDesc} representing {@link Set} */
+ public static final ClassDesc CD_Set = ClassDesc.of("java.util.Set");
+
+ /** {@link ClassDesc} representing {@link Map} */
+ public static final ClassDesc CD_Map = ClassDesc.of("java.util.Map");
+
+ /** {@link ClassDesc} representing {@link ConstantDesc} */
+ public static final ClassDesc CD_ConstantDesc = ClassDesc.of("java.lang.constant.ConstantDesc");
+
+ /** {@link ClassDesc} representing {@link ClassDesc} */
+ public static final ClassDesc CD_ClassDesc = ClassDesc.of("java.lang.constant.ClassDesc");
+
+ /** {@link ClassDesc} representing {@link EnumDesc} */
+ public static final ClassDesc CD_EnumDesc = CD_Enum.nested("EnumDesc");
+
+ /** {@link ClassDesc} representing {@link MethodTypeDesc} */
+ public static final ClassDesc CD_MethodTypeDesc = ClassDesc.of("java.lang.constant.MethodTypeDesc");
+
+ /** {@link ClassDesc} representing {@link MethodHandleDesc} */
+ public static final ClassDesc CD_MethodHandleDesc = ClassDesc.of("java.lang.constant.MethodHandleDesc");
+
+ /** {@link ClassDesc} representing {@link DirectMethodHandleDesc} */
+ public static final ClassDesc CD_DirectMethodHandleDesc = ClassDesc.of("java.lang.constant.DirectMethodHandleDesc");
+
+ /** {@link ClassDesc} representing {@link VarHandleDesc} */
+ public static final ClassDesc CD_VarHandleDesc = CD_VarHandle.nested("VarHandleDesc");
+
+ /** {@link ClassDesc} representing {@link DirectMethodHandleDesc.Kind} */
+ public static final ClassDesc CD_MethodHandleDesc_Kind = CD_DirectMethodHandleDesc.nested("Kind");
+
+ /** {@link ClassDesc} representing {@link DynamicConstantDesc} */
+ public static final ClassDesc CD_DynamicConstantDesc = ClassDesc.of("java.lang.constant.DynamicConstantDesc");
+
+ /** {@link ClassDesc} representing {@link DynamicCallSiteDesc} */
+ public static final ClassDesc CD_DynamicCallSiteDesc = ClassDesc.of("java.lang.constant.DynamicCallSiteDesc");
+
+ /** {@link ClassDesc} representing {@link ConstantBootstraps} */
+ public static final ClassDesc CD_ConstantBootstraps = ClassDesc.of("java.lang.invoke.ConstantBootstraps");
+
+ private static final ClassDesc[] INDY_BOOTSTRAP_ARGS = {
+ ConstantDescs.CD_MethodHandles_Lookup,
+ ConstantDescs.CD_String,
+ ConstantDescs.CD_MethodType};
+
+ private static final ClassDesc[] CONDY_BOOTSTRAP_ARGS = {
+ ConstantDescs.CD_MethodHandles_Lookup,
+ ConstantDescs.CD_String,
+ ConstantDescs.CD_Class};
+
+ /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#primitiveClass(Lookup, String, Class) ConstantBootstraps.primitiveClass} */
+ public static final DirectMethodHandleDesc BSM_PRIMITIVE_CLASS
+ = ofConstantBootstrap(CD_ConstantBootstraps, "primitiveClass",
+ CD_Class);
+
+ /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#enumConstant(Lookup, String, Class) ConstantBootstraps.enumConstant} */
+ public static final DirectMethodHandleDesc BSM_ENUM_CONSTANT
+ = ofConstantBootstrap(CD_ConstantBootstraps, "enumConstant",
+ CD_Enum);
+
+ /**
+ * {@link MethodHandleDesc} representing {@link ConstantBootstraps#getStaticFinal(Lookup, String, Class, Class) ConstantBootstraps.getStaticFinal}
+ * @since 15
+ */
+ public static final DirectMethodHandleDesc BSM_GET_STATIC_FINAL
+ = ofConstantBootstrap(CD_ConstantBootstraps, "getStaticFinal",
+ CD_Object, CD_Class);
+
+ /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#nullConstant(Lookup, String, Class) ConstantBootstraps.nullConstant} */
+ public static final DirectMethodHandleDesc BSM_NULL_CONSTANT
+ = ofConstantBootstrap(CD_ConstantBootstraps, "nullConstant",
+ CD_Object);
+
+ /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#fieldVarHandle(Lookup, String, Class, Class, Class) ConstantBootstraps.fieldVarHandle} */
+ public static final DirectMethodHandleDesc BSM_VARHANDLE_FIELD
+ = ofConstantBootstrap(CD_ConstantBootstraps, "fieldVarHandle",
+ CD_VarHandle, CD_Class, CD_Class);
+
+ /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#staticFieldVarHandle(Lookup, String, Class, Class, Class) ConstantBootstraps.staticVarHandle} */
+ public static final DirectMethodHandleDesc BSM_VARHANDLE_STATIC_FIELD
+ = ofConstantBootstrap(CD_ConstantBootstraps, "staticFieldVarHandle",
+ CD_VarHandle, CD_Class, CD_Class);
+
+ /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#arrayVarHandle(Lookup, String, Class, Class) ConstantBootstraps.arrayVarHandle} */
+ public static final DirectMethodHandleDesc BSM_VARHANDLE_ARRAY
+ = ofConstantBootstrap(CD_ConstantBootstraps, "arrayVarHandle",
+ CD_VarHandle, CD_Class);
+
+ /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#invoke(Lookup, String, Class, MethodHandle, Object...) ConstantBootstraps.invoke} */
+ public static final DirectMethodHandleDesc BSM_INVOKE
+ = ofConstantBootstrap(CD_ConstantBootstraps, "invoke",
+ CD_Object, CD_MethodHandle, CD_Object.arrayType());
+
+ /**
+ * {@link MethodHandleDesc} representing {@link ConstantBootstraps#explicitCast(Lookup, String, Class, Object)} ConstantBootstraps.explicitCast}
+ * @since 15
+ */
+ public static final DirectMethodHandleDesc BSM_EXPLICIT_CAST
+ = ofConstantBootstrap(CD_ConstantBootstraps, "explicitCast",
+ CD_Object, CD_Object);
+
+ /** {@link ClassDesc} representing the primitive type {@code int} */
+ public static final ClassDesc CD_int = ClassDesc.ofDescriptor("I");
+
+ /** {@link ClassDesc} representing the primitive type {@code long} */
+ public static final ClassDesc CD_long = ClassDesc.ofDescriptor("J");
+
+ /** {@link ClassDesc} representing the primitive type {@code float} */
+ public static final ClassDesc CD_float = ClassDesc.ofDescriptor("F");
+
+ /** {@link ClassDesc} representing the primitive type {@code double} */
+ public static final ClassDesc CD_double = ClassDesc.ofDescriptor("D");
+
+ /** {@link ClassDesc} representing the primitive type {@code short} */
+ public static final ClassDesc CD_short = ClassDesc.ofDescriptor("S");
+
+ /** {@link ClassDesc} representing the primitive type {@code byte} */
+ public static final ClassDesc CD_byte = ClassDesc.ofDescriptor("B");
+
+ /** {@link ClassDesc} representing the primitive type {@code char} */
+ public static final ClassDesc CD_char = ClassDesc.ofDescriptor("C");
+
+ /** {@link ClassDesc} representing the primitive type {@code boolean} */
+ public static final ClassDesc CD_boolean = ClassDesc.ofDescriptor("Z");
+
+ /** {@link ClassDesc} representing the primitive type {@code void} */
+ public static final ClassDesc CD_void = ClassDesc.ofDescriptor("V");
+
+ /** Nominal descriptor representing the constant {@code null} */
+ public static final ConstantDesc NULL
+ = DynamicConstantDesc.ofNamed(ConstantDescs.BSM_NULL_CONSTANT,
+ DEFAULT_NAME, ConstantDescs.CD_Object);
+
+ /**
+ * Nominal descriptor representing the constant {@linkplain Boolean#TRUE}
+ * @since 15
+ */
+ public static final DynamicConstantDesc<Boolean> TRUE
+ = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL,
+ "TRUE", CD_Boolean, CD_Boolean);
+
+ /**
+ * Nominal descriptor representing the constant {@linkplain Boolean#FALSE}
+ * @since 15
+ */
+ public static final DynamicConstantDesc<Boolean> FALSE
+ = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL,
+ "FALSE", CD_Boolean, CD_Boolean);
+
+ static final DirectMethodHandleDesc MHD_METHODHANDLE_ASTYPE
+ = MethodHandleDesc.ofMethod(Kind.VIRTUAL, CD_MethodHandle, "asType",
+ MethodTypeDesc.of(CD_MethodHandle, CD_MethodType));
+ /**
+ * Returns a {@link MethodHandleDesc} corresponding to a bootstrap method for
+ * an {@code invokedynamic} callsite, which is a static method whose leading
+ * parameter types are {@code Lookup}, {@code String}, and {@code MethodType}.
+ *
+ * @param owner the class declaring the method
+ * @param name the unqualified name of the method
+ * @param returnType the return type of the method
+ * @param paramTypes the types of the static bootstrap arguments, if any
+ * @return the {@link MethodHandleDesc}
+ * @throws NullPointerException if any of the arguments are null
+ * @jvms 4.2.2 Unqualified Names
+ */
+ public static DirectMethodHandleDesc ofCallsiteBootstrap(ClassDesc owner,
+ String name,
+ ClassDesc returnType,
+ ClassDesc... paramTypes) {
+ return MethodHandleDesc.ofMethod(STATIC, owner, name, MethodTypeDesc.of(returnType, paramTypes)
+ .insertParameterTypes(0, INDY_BOOTSTRAP_ARGS));
+ }
+
+ /**
+ * Returns a {@link MethodHandleDesc} corresponding to a bootstrap method for a
+ * dynamic constant, which is a static method whose leading arguments are
+ * {@code Lookup}, {@code String}, and {@code Class}.
+ *
+ * @param owner the class declaring the method
+ * @param name the unqualified name of the method
+ * @param returnType the return type of the method
+ * @param paramTypes the types of the static bootstrap arguments, if any
+ * @return the {@link MethodHandleDesc}
+ * @throws NullPointerException if any of the arguments are null
+ * @jvms 4.2.2 Unqualified Names
+ */
+ public static DirectMethodHandleDesc ofConstantBootstrap(ClassDesc owner,
+ String name,
+ ClassDesc returnType,
+ ClassDesc... paramTypes) {
+ return MethodHandleDesc.ofMethod(STATIC, owner, name, MethodTypeDesc.of(returnType, paramTypes)
+ .insertParameterTypes(0, CONDY_BOOTSTRAP_ARGS));
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/constant/ConstantUtils.java b/ojluni/src/main/java/java/lang/constant/ConstantUtils.java
new file mode 100644
index 0000000..ab63166
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/ConstantUtils.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Helper methods for the implementation of {@code java.lang.constant}.
+ */
+class ConstantUtils {
+ /** an empty constant descriptor */
+ public static final ConstantDesc[] EMPTY_CONSTANTDESC = new ConstantDesc[0];
+ static final Constable[] EMPTY_CONSTABLE = new Constable[0];
+ static final int MAX_ARRAY_TYPE_DESC_DIMENSIONS = 255;
+
+ private static final Set<String> pointyNames = Set.of("<init>", "<clinit>");
+
+ /**
+ * Validates the correctness of a binary class name. In particular checks for the presence of
+ * invalid characters in the name.
+ *
+ * @param name the class name
+ * @return the class name passed if valid
+ * @throws IllegalArgumentException if the class name is invalid
+ */
+ static String validateBinaryClassName(String name) {
+ for (int i=0; i<name.length(); i++) {
+ char ch = name.charAt(i);
+ if (ch == ';' || ch == '[' || ch == '/')
+ throw new IllegalArgumentException("Invalid class name: " + name);
+ }
+ return name;
+ }
+
+ /**
+ * Validates a member name
+ *
+ * @param name the name of the member
+ * @return the name passed if valid
+ * @throws IllegalArgumentException if the member name is invalid
+ */
+ public static String validateMemberName(String name, boolean method) {
+ requireNonNull(name);
+ if (name.length() == 0)
+ throw new IllegalArgumentException("zero-length member name");
+ for (int i=0; i<name.length(); i++) {
+ char ch = name.charAt(i);
+ if (ch == '.' || ch == ';' || ch == '[' || ch == '/')
+ throw new IllegalArgumentException("Invalid member name: " + name);
+ if (method && (ch == '<' || ch == '>')) {
+ if (!pointyNames.contains(name))
+ throw new IllegalArgumentException("Invalid member name: " + name);
+ }
+ }
+ return name;
+ }
+
+ static void validateClassOrInterface(ClassDesc classDesc) {
+ if (!classDesc.isClassOrInterface())
+ throw new IllegalArgumentException("not a class or interface type: " + classDesc);
+ }
+
+ static int arrayDepth(String descriptorString) {
+ int depth = 0;
+ while (descriptorString.charAt(depth) == '[')
+ depth++;
+ return depth;
+ }
+
+ static String binaryToInternal(String name) {
+ return name.replace('.', '/');
+ }
+
+ static String internalToBinary(String name) {
+ return name.replace('/', '.');
+ }
+
+ static String dropLastChar(String s) {
+ return s.substring(0, s.length() - 1);
+ }
+
+ static String dropFirstAndLastChar(String s) {
+ return s.substring(1, s.length() - 1);
+ }
+
+ /**
+ * Parses a method descriptor string, and return a list of field descriptor
+ * strings, return type first, then parameter types
+ *
+ * @param descriptor the descriptor string
+ * @return the list of types
+ * @throws IllegalArgumentException if the descriptor string is not valid
+ */
+ static List<String> parseMethodDescriptor(String descriptor) {
+ int cur = 0, end = descriptor.length();
+ ArrayList<String> ptypes = new ArrayList<>();
+
+ if (cur >= end || descriptor.charAt(cur) != '(')
+ throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
+
+ ++cur; // skip '('
+ while (cur < end && descriptor.charAt(cur) != ')') {
+ int len = skipOverFieldSignature(descriptor, cur, end, false);
+ if (len == 0)
+ throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
+ ptypes.add(descriptor.substring(cur, cur + len));
+ cur += len;
+ }
+ if (cur >= end)
+ throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
+ ++cur; // skip ')'
+
+ int rLen = skipOverFieldSignature(descriptor, cur, end, true);
+ if (rLen == 0 || cur + rLen != end)
+ throw new IllegalArgumentException("Bad method descriptor: " + descriptor);
+ ptypes.add(0, descriptor.substring(cur, cur + rLen));
+ return ptypes;
+ }
+
+ private static final char JVM_SIGNATURE_ARRAY = '[';
+ private static final char JVM_SIGNATURE_BYTE = 'B';
+ private static final char JVM_SIGNATURE_CHAR = 'C';
+ private static final char JVM_SIGNATURE_CLASS = 'L';
+ private static final char JVM_SIGNATURE_ENDCLASS = ';';
+ private static final char JVM_SIGNATURE_ENUM = 'E';
+ private static final char JVM_SIGNATURE_FLOAT = 'F';
+ private static final char JVM_SIGNATURE_DOUBLE = 'D';
+ private static final char JVM_SIGNATURE_FUNC = '(';
+ private static final char JVM_SIGNATURE_ENDFUNC = ')';
+ private static final char JVM_SIGNATURE_INT = 'I';
+ private static final char JVM_SIGNATURE_LONG = 'J';
+ private static final char JVM_SIGNATURE_SHORT = 'S';
+ private static final char JVM_SIGNATURE_VOID = 'V';
+ private static final char JVM_SIGNATURE_BOOLEAN = 'Z';
+
+ /**
+ * Validates that the characters at [start, end) within the provided string
+ * describe a valid field type descriptor.
+ * @param descriptor the descriptor string
+ * @param start the starting index into the string
+ * @param end the ending index within the string
+ * @param voidOK is void acceptable?
+ * @return the length of the descriptor, or 0 if it is not a descriptor
+ * @throws IllegalArgumentException if the descriptor string is not valid
+ */
+ @SuppressWarnings("fallthrough")
+ static int skipOverFieldSignature(String descriptor, int start, int end, boolean voidOK) {
+ int arrayDim = 0;
+ int index = start;
+ while (index < end) {
+ switch (descriptor.charAt(index)) {
+ case JVM_SIGNATURE_VOID: if (!voidOK) { return index; }
+ case JVM_SIGNATURE_BOOLEAN:
+ case JVM_SIGNATURE_BYTE:
+ case JVM_SIGNATURE_CHAR:
+ case JVM_SIGNATURE_SHORT:
+ case JVM_SIGNATURE_INT:
+ case JVM_SIGNATURE_FLOAT:
+ case JVM_SIGNATURE_LONG:
+ case JVM_SIGNATURE_DOUBLE:
+ return index - start + 1;
+ case JVM_SIGNATURE_CLASS:
+ // Skip leading 'L' and ignore first appearance of ';'
+ index++;
+ int indexOfSemi = descriptor.indexOf(';', index);
+ if (indexOfSemi != -1) {
+ String unqualifiedName = descriptor.substring(index, indexOfSemi);
+ boolean legal = verifyUnqualifiedClassName(unqualifiedName);
+ if (!legal) {
+ return 0;
+ }
+ return index - start + unqualifiedName.length() + 1;
+ }
+ return 0;
+ case JVM_SIGNATURE_ARRAY:
+ arrayDim++;
+ if (arrayDim > MAX_ARRAY_TYPE_DESC_DIMENSIONS) {
+ throw new IllegalArgumentException(String.format("Cannot create an array type descriptor with more than %d dimensions",
+ ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS));
+ }
+ // The rest of what's there better be a legal descriptor
+ index++;
+ voidOK = false;
+ break;
+ default:
+ return 0;
+ }
+ }
+ return 0;
+ }
+
+ static boolean verifyUnqualifiedClassName(String name) {
+ for (int index = 0; index < name.length(); index++) {
+ char ch = name.charAt(index);
+ if (ch < 128) {
+ if (ch == '.' || ch == ';' || ch == '[' ) {
+ return false; // do not permit '.', ';', or '['
+ }
+ if (ch == '/') {
+ // check for '//' or leading or trailing '/' which are not legal
+ // unqualified name must not be empty
+ if (index == 0 || index + 1 >= name.length() || name.charAt(index + 1) == '/') {
+ return false;
+ }
+ }
+ } else {
+ index ++;
+ }
+ }
+ return true;
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/constant/DirectMethodHandleDesc.java b/ojluni/src/main/java/java/lang/constant/DirectMethodHandleDesc.java
new file mode 100644
index 0000000..7d7ec71
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/DirectMethodHandleDesc.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandleInfo;
+import java.util.OptionalInt;
+import java.util.stream.Stream;
+
+import jdk.internal.vm.annotation.Stable;
+
+import static java.lang.invoke.MethodHandleInfo.REF_getField;
+import static java.lang.invoke.MethodHandleInfo.REF_getStatic;
+import static java.lang.invoke.MethodHandleInfo.REF_invokeInterface;
+import static java.lang.invoke.MethodHandleInfo.REF_invokeSpecial;
+import static java.lang.invoke.MethodHandleInfo.REF_invokeStatic;
+import static java.lang.invoke.MethodHandleInfo.REF_invokeVirtual;
+import static java.lang.invoke.MethodHandleInfo.REF_newInvokeSpecial;
+import static java.lang.invoke.MethodHandleInfo.REF_putField;
+import static java.lang.invoke.MethodHandleInfo.REF_putStatic;
+
+/**
+ * A <a href="package-summary.html#nominal">nominal descriptor</a> for a direct
+ * {@link MethodHandle}. A {@linkplain DirectMethodHandleDesc} corresponds to
+ * a {@code Constant_MethodHandle_info} entry in the constant pool of a classfile.
+ *
+ * @since 12
+ */
+public sealed interface DirectMethodHandleDesc
+ extends MethodHandleDesc
+ permits DirectMethodHandleDescImpl {
+ /**
+ * Kinds of method handles that can be described with {@linkplain DirectMethodHandleDesc}.
+ *
+ * @since 12
+ */
+ enum Kind {
+ /** A method handle for a method invoked as with {@code invokestatic} */
+ STATIC(REF_invokeStatic),
+ /** A method handle for a method invoked as with {@code invokestatic} */
+ INTERFACE_STATIC(REF_invokeStatic, true),
+ /** A method handle for a method invoked as with {@code invokevirtual} */
+ VIRTUAL(REF_invokeVirtual),
+ /** A method handle for a method invoked as with {@code invokeinterface} */
+ INTERFACE_VIRTUAL(REF_invokeInterface, true),
+ /** A method handle for a method invoked as with {@code invokespecial} */
+ SPECIAL(REF_invokeSpecial),
+ /** A method handle for an interface method invoked as with {@code invokespecial} */
+ INTERFACE_SPECIAL(REF_invokeSpecial, true),
+ /** A method handle for a constructor */
+ CONSTRUCTOR(REF_newInvokeSpecial),
+ /** A method handle for a read accessor for an instance field */
+ GETTER(REF_getField),
+ /** A method handle for a write accessor for an instance field */
+ SETTER(REF_putField),
+ /** A method handle for a read accessor for a static field */
+ STATIC_GETTER(REF_getStatic),
+ /** A method handle for a write accessor for a static field */
+ STATIC_SETTER(REF_putStatic);
+
+ /** The corresponding {@code refKind} value for this kind of method handle,
+ * as defined by {@link MethodHandleInfo}
+ */
+ public final int refKind;
+
+ /** Is this an interface
+ */
+ public final boolean isInterface;
+ Kind(int refKind) {
+ this(refKind, false);
+ }
+
+ Kind(int refKind, boolean isInterface) { this.refKind = refKind; this.isInterface = isInterface; }
+
+ /**
+ * Returns the enumeration member with the given {@code refKind} field.
+ * Behaves as if {@code valueOf(refKind, false)}. As a special case,
+ * if {@code refKind} is {@code REF_invokeInterface} (9) then the
+ * {@code isInterface} field will be true.
+ *
+ * @param refKind refKind of desired member
+ * @return the matching enumeration member
+ * @throws IllegalArgumentException if there is no such member
+ */
+ public static Kind valueOf(int refKind) {
+ return valueOf(refKind, refKind == REF_invokeInterface);
+ }
+
+ /**
+ * Returns the enumeration member with the given the {@code refKind} and
+ * {@code isInterface} arguments.
+ * For most values of {@code refKind} there is an exact match regardless of the value of {@code isInterface}.
+ * These are:
+ * <UL>
+ * <LI>{@code REF_invokeVirtual} which matches to {@code VIRTUAL}
+ * <LI>{@code REF_invokeInterface} which matches to {@code INTERFACE_VIRTUAL}
+ * <LI>{@code REF_newInvokeSpecial} which matches to {@code CONSTRUCTOR}
+ * <LI>{@code REF_getField} which matches to {@code GETTER}
+ * <LI>{@code REF_putField} which matches to {@code SETTER}
+ * <LI>{@code REF_getStatic} which matches to {@code STATIC_GETTER}
+ * <LI>{@code REF_putStatic} which matches to {@code STATIC_SETTER}
+ * </UL>
+ * As for the rest, the returned kind will depend on the value (false or true accordingly) of {@code isInterface}:
+ * <UL>
+ * <LI>{@code REF_invokeStatic} which matches to {@code STATIC} or {@code INTERFACE_STATIC}
+ * <LI>{@code REF_invokeSpecial} which matches to {@code SPECIAL} or {@code INTERFACE_SPECIAL}
+ * </UL>
+ * @param refKind refKind of desired member
+ * @param isInterface whether desired member is for interface methods
+ * @return the matching enumeration member
+ * @throws IllegalArgumentException if there is no such member
+ */
+ public static Kind valueOf(int refKind, boolean isInterface) {
+ int i = tableIndex(refKind, isInterface);
+ if (i >= 2 && i < TABLE.length) {
+ return TABLE[i];
+ }
+ throw new IllegalArgumentException(String.format("refKind=%d isInterface=%s", refKind, isInterface));
+ }
+
+ private static int tableIndex(int refKind, boolean isInterface) {
+ if (refKind < 0) return refKind;
+ return (refKind * 2) + (isInterface ? 1 : 0);
+ }
+
+ private static final @Stable Kind[] TABLE;
+
+ static {
+ // Pack the static table.
+ int max = 0;
+ for (Kind k : values())
+ max = Math.max(max, tableIndex(k.refKind, true));
+
+ TABLE = new Kind[max+1];
+ for (Kind kind : values()) {
+ int i = tableIndex(kind.refKind, kind.isInterface);
+ if (i >= TABLE.length || TABLE[i] != null)
+ throw new AssertionError("TABLE entry for " + kind);
+ TABLE[i] = kind;
+ }
+
+ // Pack in some aliases also.
+ int ii = tableIndex(REF_invokeInterface, false);
+ if (TABLE[ii] != null)
+ throw new AssertionError("TABLE entry for (invokeInterface, false) used by " + TABLE[ii]);
+ TABLE[ii] = INTERFACE_VIRTUAL;
+
+ for (Kind kind : values()) {
+ if (!kind.isInterface) {
+ // Add extra cache entry to alias the isInterface case.
+ // For example, (REF_getStatic, X) will produce STATIC_GETTER
+ // for either truth value of X.
+ int i = tableIndex(kind.refKind, true);
+ if (TABLE[i] == null) {
+ TABLE[i] = kind;
+ }
+ }
+ }
+ }
+
+ /**
+ * Does this {@code Kind} correspond to a virtual method invocation?
+ *
+ * @return if this {@code Kind} corresponds to a virtual method invocation
+ */
+ boolean isVirtualMethod() {
+ switch (this) {
+ case VIRTUAL:
+ case SPECIAL:
+ case INTERFACE_VIRTUAL:
+ case INTERFACE_SPECIAL:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Returns the {@code kind} of the method handle described by this nominal
+ * descriptor.
+ *
+ * @return the {@link Kind}
+ */
+ Kind kind();
+
+ /**
+ * Returns the {@code refKind} of the method handle described by this nominal
+ * reference, as defined by {@link MethodHandleInfo}.
+ *
+ * @return the reference kind
+ */
+ int refKind();
+
+ /**
+ * Indicates if the method is declared by an interface
+ *
+ * @return true if the method is declared by an interface
+ */
+ boolean isOwnerInterface();
+
+ /**
+ * Returns a {@link ClassDesc} describing the class declaring the
+ * method or field described by this nominal descriptor.
+ *
+ * @return the class declaring the method or field
+ */
+ ClassDesc owner();
+
+ /**
+ * Returns the name of the method or field described by this nominal descriptor.
+ * For constructors, returns the reserved name {@code "<init>"}.
+ *
+ * @return the name of the method or field
+ */
+ String methodName();
+
+ /**
+ * Returns the lookup descriptor of the method handle described by this descriptor,
+ * after adjusting for the invocation mode. This will correspond to either
+ * a method type descriptor string (for methods and constructors), or a field
+ * descriptor string (for field access method handles). The lookup descriptor
+ * string is in the same format as accepted by {@link MethodHandleDesc#of(Kind, ClassDesc, String, String)}.
+ *
+ * @return the lookup descriptor string
+ */
+ String lookupDescriptor();
+}
diff --git a/ojluni/src/main/java/java/lang/constant/DirectMethodHandleDescImpl.java b/ojluni/src/main/java/java/lang/constant/DirectMethodHandleDescImpl.java
new file mode 100644
index 0000000..cb8c8c3
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/DirectMethodHandleDescImpl.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.Objects;
+
+import static java.lang.constant.ConstantDescs.CD_void;
+import static java.lang.constant.ConstantUtils.validateClassOrInterface;
+import static java.lang.constant.ConstantUtils.validateMemberName;
+import static java.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR;
+import static java.util.Objects.requireNonNull;
+
+/**
+ * A <a href="package-summary.html#nominal">nominal descriptor</a> for a direct
+ * {@link MethodHandle}. A {@linkplain DirectMethodHandleDescImpl} corresponds to
+ * a {@code Constant_MethodHandle_info} entry in the constant pool of a classfile.
+ */
+final class DirectMethodHandleDescImpl implements DirectMethodHandleDesc {
+
+ private final Kind kind;
+ private final ClassDesc owner;
+ private final String name;
+ private final MethodTypeDesc invocationType;
+
+ /**
+ * Constructs a {@linkplain DirectMethodHandleDescImpl} for a method or field
+ * from a kind, owner, name, and type
+ *
+ * @param kind the kind of the method handle
+ * @param owner the declaring class or interface for the method
+ * @param name the unqualified name of the method (ignored if {@code kind} is {@code CONSTRUCTOR})
+ * @param type the lookup type of the method
+ * @throws NullPointerException if any non-ignored argument is null
+ * @throws IllegalArgumentException if {@code kind} describes a field accessor,
+ * and {@code type} is not consistent with that kind of field accessor, or if
+ * {@code kind} describes a constructor, and the return type of {@code type}
+ * is not {@code void}
+ * @jvms 4.2.2 Unqualified Names
+ */
+ DirectMethodHandleDescImpl(Kind kind, ClassDesc owner, String name, MethodTypeDesc type) {
+ if (kind == CONSTRUCTOR)
+ name = "<init>";
+
+ requireNonNull(kind);
+ validateClassOrInterface(requireNonNull(owner));
+ validateMemberName(requireNonNull(name), true);
+ requireNonNull(type);
+
+ switch (kind) {
+ case CONSTRUCTOR -> validateConstructor(type);
+ case GETTER -> validateFieldType(type, false, true);
+ case SETTER -> validateFieldType(type, true, true);
+ case STATIC_GETTER -> validateFieldType(type, false, false);
+ case STATIC_SETTER -> validateFieldType(type, true, false);
+ }
+
+ this.kind = kind;
+ this.owner = owner;
+ this.name = name;
+ if (kind.isVirtualMethod())
+ this.invocationType = type.insertParameterTypes(0, owner);
+ else if (kind == CONSTRUCTOR)
+ this.invocationType = type.changeReturnType(owner);
+ else
+ this.invocationType = type;
+ }
+
+ private static void validateFieldType(MethodTypeDesc type, boolean isSetter, boolean isVirtual) {
+ boolean isVoid = type.returnType().descriptorString().equals("V");
+ int expectedParams = (isSetter ? 1 : 0) + (isVirtual ? 1 : 0);
+ if (isVoid != isSetter
+ || type.parameterCount() != expectedParams
+ || (isVirtual && type.parameterType(0).isPrimitive())) {
+ String expectedType = String.format("(%s%s)%s", (isVirtual ? "R" : ""),
+ (isSetter ? "T" : ""), (isSetter ? "V" : "T"));
+ throw new IllegalArgumentException(String.format("Expected type of %s for getter, found %s", expectedType, type));
+ }
+ }
+
+ private static void validateConstructor(MethodTypeDesc type) {
+ if (!type.returnType().descriptorString().equals("V")) {
+ throw new IllegalArgumentException(String.format("Expected type of (T*)V for constructor, found %s", type));
+ }
+ }
+
+ @Override
+ public Kind kind() { return kind; }
+
+ @Override
+ public int refKind() { return kind.refKind; }
+
+ @Override
+ public boolean isOwnerInterface() { return kind.isInterface; }
+
+ @Override
+ public ClassDesc owner() {
+ return owner;
+ }
+
+ @Override
+ public String methodName() {
+ return name;
+ }
+
+ @Override
+ public MethodTypeDesc invocationType() {
+ return invocationType;
+ }
+
+ @Override
+ public String lookupDescriptor() {
+ return switch (kind) {
+ case VIRTUAL,
+ SPECIAL,
+ INTERFACE_VIRTUAL,
+ INTERFACE_SPECIAL -> invocationType.dropParameterTypes(0, 1).descriptorString();
+ case STATIC,
+ INTERFACE_STATIC -> invocationType.descriptorString();
+ case CONSTRUCTOR -> invocationType.changeReturnType(CD_void).descriptorString();
+ case GETTER,
+ STATIC_GETTER -> invocationType.returnType().descriptorString();
+ case SETTER -> invocationType.parameterType(1).descriptorString();
+ case STATIC_SETTER -> invocationType.parameterType(0).descriptorString();
+ default -> throw new IllegalStateException(kind.toString());
+ };
+ }
+
+ public MethodHandle resolveConstantDesc(MethodHandles.Lookup lookup)
+ throws ReflectiveOperationException {
+ Class<?> resolvedOwner = (Class<?>) owner.resolveConstantDesc(lookup);
+ MethodType invocationType = (MethodType) this.invocationType().resolveConstantDesc(lookup);
+ return switch (kind) {
+ case STATIC,
+ INTERFACE_STATIC -> lookup.findStatic(resolvedOwner, name, invocationType);
+ case VIRTUAL,
+ INTERFACE_VIRTUAL -> lookup.findVirtual(resolvedOwner, name, invocationType.dropParameterTypes(0, 1));
+ case SPECIAL,
+ INTERFACE_SPECIAL -> lookup.findSpecial(resolvedOwner, name, invocationType.dropParameterTypes(0, 1), lookup.lookupClass());
+ case CONSTRUCTOR -> lookup.findConstructor(resolvedOwner, invocationType.changeReturnType(void.class));
+ case GETTER -> lookup.findGetter(resolvedOwner, name, invocationType.returnType());
+ case STATIC_GETTER -> lookup.findStaticGetter(resolvedOwner, name, invocationType.returnType());
+ case SETTER -> lookup.findSetter(resolvedOwner, name, invocationType.parameterType(1));
+ case STATIC_SETTER -> lookup.findStaticSetter(resolvedOwner, name, invocationType.parameterType(0));
+ default -> throw new IllegalStateException(kind.name());
+ };
+ }
+
+ /**
+ * Returns {@code true} if this {@linkplain DirectMethodHandleDescImpl} is
+ * equal to another {@linkplain DirectMethodHandleDescImpl}. Equality is
+ * determined by the two descriptors having equal kind, owner, name, and type
+ * descriptor.
+ * @param o a {@code DirectMethodHandleDescImpl} to compare to this
+ * {@code DirectMethodHandleDescImpl}
+ * @return {@code true} if the specified {@code DirectMethodHandleDescImpl}
+ * is equal to this {@code DirectMethodHandleDescImpl}.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DirectMethodHandleDescImpl desc = (DirectMethodHandleDescImpl) o;
+ return kind == desc.kind &&
+ Objects.equals(owner, desc.owner) &&
+ Objects.equals(name, desc.name) &&
+ Objects.equals(invocationType, desc.invocationType);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(kind, owner, name, invocationType);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("MethodHandleDesc[%s/%s::%s%s]", kind, owner.displayName(), name, invocationType.displayDescriptor());
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/constant/DynamicCallSiteDesc.java b/ojluni/src/main/java/java/lang/constant/DynamicCallSiteDesc.java
new file mode 100644
index 0000000..cf6d09c
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/DynamicCallSiteDesc.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+import static java.lang.constant.ConstantDescs.CD_String;
+import static java.lang.constant.ConstantUtils.EMPTY_CONSTANTDESC;
+import static java.lang.constant.ConstantUtils.validateMemberName;
+import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.joining;
+
+/**
+ * A <a href="package-summary.html#nominal">nominal descriptor</a> for an
+ * {@code invokedynamic} call site.
+ *
+ * <p>Concrete subtypes of {@linkplain DynamicCallSiteDesc} should be immutable
+ * and their behavior should not rely on object identity.
+ *
+ * @since 12
+ */
+public class DynamicCallSiteDesc {
+
+ private final DirectMethodHandleDesc bootstrapMethod;
+ private final ConstantDesc[] bootstrapArgs;
+ private final String invocationName;
+ private final MethodTypeDesc invocationType;
+
+ /**
+ * Creates a nominal descriptor for an {@code invokedynamic} call site.
+ *
+ * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
+ * bootstrap method for the {@code invokedynamic}
+ * @param invocationName The unqualified name that would appear in the {@code NameAndType}
+ * operand of the {@code invokedynamic}
+ * @param invocationType a {@link MethodTypeDesc} describing the invocation
+ * type that would appear in the {@code NameAndType}
+ * operand of the {@code invokedynamic}
+ * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
+ * to the bootstrap, that would appear in the
+ * {@code BootstrapMethods} attribute
+ * @throws NullPointerException if any parameter or its contents are {@code null}
+ * @throws IllegalArgumentException if the invocation name has the incorrect
+ * format
+ * @jvms 4.2.2 Unqualified Names
+ */
+ private DynamicCallSiteDesc(DirectMethodHandleDesc bootstrapMethod,
+ String invocationName,
+ MethodTypeDesc invocationType,
+ ConstantDesc[] bootstrapArgs) {
+ this.invocationName = validateMemberName(requireNonNull(invocationName), true);
+ this.invocationType = requireNonNull(invocationType);
+ this.bootstrapMethod = requireNonNull(bootstrapMethod);
+ this.bootstrapArgs = requireNonNull(bootstrapArgs.clone());
+ for (int i = 0; i < this.bootstrapArgs.length; i++) {
+ requireNonNull(this.bootstrapArgs[i]);
+ }
+ if (invocationName.length() == 0)
+ throw new IllegalArgumentException("Illegal invocation name: " + invocationName);
+ }
+
+ /**
+ * Creates a nominal descriptor for an {@code invokedynamic} call site.
+ *
+ * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
+ * bootstrap method for the {@code invokedynamic}
+ * @param invocationName The unqualified name that would appear in the {@code NameAndType}
+ * operand of the {@code invokedynamic}
+ * @param invocationType a {@link MethodTypeDesc} describing the invocation
+ * type that would appear in the {@code NameAndType}
+ * operand of the {@code invokedynamic}
+ * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
+ * to the bootstrap, that would appear in the
+ * {@code BootstrapMethods} attribute
+ * @return the nominal descriptor
+ * @throws NullPointerException if any parameter or its contents are {@code null}
+ * @throws IllegalArgumentException if the invocation name has the incorrect
+ * format
+ * @jvms 4.2.2 Unqualified Names
+ */
+ public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod,
+ String invocationName,
+ MethodTypeDesc invocationType,
+ ConstantDesc... bootstrapArgs) {
+ return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, bootstrapArgs);
+ }
+
+ /**
+ * Creates a nominal descriptor for an {@code invokedynamic} call site whose
+ * bootstrap method has no static arguments.
+ *
+ * @param bootstrapMethod The bootstrap method for the {@code invokedynamic}
+ * @param invocationName The invocationName that would appear in the
+ * {@code NameAndType} operand of the {@code invokedynamic}
+ * @param invocationType The invocation invocationType that would appear
+ * in the {@code NameAndType} operand of the {@code invokedynamic}
+ * @return the nominal descriptor
+ * @throws NullPointerException if any parameter is null
+ * @throws IllegalArgumentException if the invocation name has the incorrect
+ * format
+ */
+ public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod,
+ String invocationName,
+ MethodTypeDesc invocationType) {
+ return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, EMPTY_CONSTANTDESC);
+ }
+
+ /**
+ * Creates a nominal descriptor for an {@code invokedynamic} call site whose
+ * bootstrap method has no static arguments and for which the name parameter
+ * is {@link ConstantDescs#DEFAULT_NAME}.
+ *
+ * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
+ * bootstrap method for the {@code invokedynamic}
+ * @param invocationType a {@link MethodTypeDesc} describing the invocation
+ * type that would appear in the {@code NameAndType}
+ * operand of the {@code invokedynamic}
+ * @return the nominal descriptor
+ * @throws NullPointerException if any parameter is null
+ */
+ public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod,
+ MethodTypeDesc invocationType) {
+ return of(bootstrapMethod, ConstantDescs.DEFAULT_NAME, invocationType);
+ }
+
+ /**
+ * Returns a nominal descriptor for an {@code invokedynamic} call site whose
+ * bootstrap method, name, and invocation type are the same as this one, but
+ * with the specified bootstrap arguments.
+ *
+ * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
+ * to the bootstrap, that would appear in the
+ * {@code BootstrapMethods} attribute
+ * @return the nominal descriptor
+ * @throws NullPointerException if the argument or its contents are {@code null}
+ */
+ public DynamicCallSiteDesc withArgs(ConstantDesc... bootstrapArgs) {
+ return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, bootstrapArgs);
+ }
+
+ /**
+ * Returns a nominal descriptor for an {@code invokedynamic} call site whose
+ * bootstrap and bootstrap arguments are the same as this one, but with the
+ * specified invocationName and invocation invocationType
+ *
+ * @param invocationName The unqualified name that would appear in the {@code NameAndType}
+ * operand of the {@code invokedynamic}
+ * @param invocationType a {@link MethodTypeDesc} describing the invocation
+ * type that would appear in the {@code NameAndType}
+ * operand of the {@code invokedynamic}
+ * @return the nominal descriptor
+ * @throws NullPointerException if any parameter is null
+ * @throws IllegalArgumentException if the invocation name has the incorrect
+ * format
+ * @jvms 4.2.2 Unqualified Names
+ */
+ public DynamicCallSiteDesc withNameAndType(String invocationName,
+ MethodTypeDesc invocationType) {
+ return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, bootstrapArgs);
+ }
+
+ /**
+ * Returns the invocation name that would appear in the {@code NameAndType}
+ * operand of the {@code invokedynamic}.
+ *
+ * @return the invocation name
+ */
+ public String invocationName() {
+ return invocationName;
+ }
+
+ /**
+ * Returns a {@link MethodTypeDesc} describing the invocation type that
+ * would appear in the {@code NameAndType} operand of the {@code invokedynamic}.
+ *
+ * @return the invocation type
+ */
+ public MethodTypeDesc invocationType() {
+ return invocationType;
+ }
+
+ /**
+ * Returns a {@link MethodHandleDesc} describing the bootstrap method for
+ * the {@code invokedynamic}.
+ *
+ * @return the bootstrap method for the {@code invokedynamic}
+ */
+ public MethodHandleDesc bootstrapMethod() { return bootstrapMethod; }
+
+ /**
+ * Returns {@link ConstantDesc}s describing the bootstrap arguments for the
+ * {@code invokedynamic}. The returned array is always non-null. A zero
+ * length array is returned if this {@linkplain DynamicCallSiteDesc} has no
+ * bootstrap arguments.
+ *
+ * @return the bootstrap arguments for the {@code invokedynamic}
+ */
+ public ConstantDesc[] bootstrapArgs() { return bootstrapArgs.clone(); }
+
+ /**
+ * Reflectively invokes the bootstrap method with the specified arguments,
+ * and return the resulting {@link CallSite}
+ *
+ * @param lookup The {@link MethodHandles.Lookup} used to resolve class names
+ * @return the {@link CallSite}
+ * @throws Throwable if any exception is thrown by the bootstrap method
+ */
+ public CallSite resolveCallSiteDesc(MethodHandles.Lookup lookup) throws Throwable {
+ assert bootstrapMethod.invocationType().parameterType(1).equals(CD_String);
+ MethodHandle bsm = (MethodHandle) bootstrapMethod.resolveConstantDesc(lookup);
+ Object[] args = new Object[bootstrapArgs.length + 3];
+ args[0] = lookup;
+ args[1] = invocationName;
+ args[2] = invocationType.resolveConstantDesc(lookup);
+ System.arraycopy(bootstrapArgs, 0, args, 3, bootstrapArgs.length);
+ return (CallSite) bsm.invokeWithArguments(args);
+ }
+
+ /**
+ * Compares the specified object with this descriptor for equality. Returns
+ * {@code true} if and only if the specified object is also a
+ * {@linkplain DynamicCallSiteDesc}, and both descriptors have equal
+ * bootstrap methods, bootstrap argument lists, invocation name, and
+ * invocation type.
+ *
+ * @param o the {@code DynamicCallSiteDesc} to compare to this
+ * {@code DynamicCallSiteDesc}
+ * @return {@code true} if the specified {@code DynamicCallSiteDesc}
+ * is equal to this {@code DynamicCallSiteDesc}.
+ */
+ @Override
+ public final boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DynamicCallSiteDesc specifier = (DynamicCallSiteDesc) o;
+ return Objects.equals(bootstrapMethod, specifier.bootstrapMethod) &&
+ Arrays.equals(bootstrapArgs, specifier.bootstrapArgs) &&
+ Objects.equals(invocationName, specifier.invocationName) &&
+ Objects.equals(invocationType, specifier.invocationType);
+ }
+
+ @Override
+ public final int hashCode() {
+ int result = Objects.hash(bootstrapMethod, invocationName, invocationType);
+ result = 31 * result + Arrays.hashCode(bootstrapArgs);
+ return result;
+ }
+
+ /**
+ * Returns a compact textual description of this call site description,
+ * including the bootstrap method, the invocation name and type, and
+ * the static bootstrap arguments.
+ *
+ * @return A compact textual description of this call site descriptor
+ */
+ @Override
+ public String toString() {
+ return String.format("DynamicCallSiteDesc[%s::%s(%s%s):%s]",
+ bootstrapMethod.owner().displayName(),
+ bootstrapMethod.methodName(),
+ invocationName.equals(ConstantDescs.DEFAULT_NAME) ? "" : invocationName + "/",
+ Stream.of(bootstrapArgs).map(Object::toString).collect(joining(",")),
+ invocationType.displayDescriptor());
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/constant/DynamicConstantDesc.java b/ojluni/src/main/java/java/lang/constant/DynamicConstantDesc.java
new file mode 100644
index 0000000..82f5bd6
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/DynamicConstantDesc.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.lang.Enum.EnumDesc;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.lang.invoke.VarHandle.VarHandleDesc;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import static java.lang.constant.ConstantDescs.CD_Class;
+import static java.lang.constant.ConstantDescs.CD_VarHandle;
+import static java.lang.constant.ConstantDescs.DEFAULT_NAME;
+import static java.lang.constant.ConstantUtils.EMPTY_CONSTANTDESC;
+import static java.lang.constant.ConstantUtils.validateMemberName;
+import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.joining;
+
+/**
+ * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
+ * dynamic constant (one described in the constant pool with
+ * {@code Constant_Dynamic_info}.)
+ *
+ * <p>Concrete subtypes of {@linkplain DynamicConstantDesc} should be immutable
+ * and their behavior should not rely on object identity.
+ *
+ * @param <T> the type of the dynamic constant
+ *
+ * @since 12
+ */
+public abstract non-sealed class DynamicConstantDesc<T>
+ implements ConstantDesc {
+
+ private final DirectMethodHandleDesc bootstrapMethod;
+ private final ConstantDesc[] bootstrapArgs;
+ private final String constantName;
+ private final ClassDesc constantType;
+
+ /**
+ * Creates a nominal descriptor for a dynamic constant.
+ *
+ * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
+ * bootstrap method for the constant
+ * @param constantName The unqualified name that would appear in the {@code NameAndType}
+ * operand of the {@code LDC} for this constant
+ * @param constantType a {@link ClassDesc} describing the type
+ * that would appear in the {@code NameAndType} operand
+ * of the {@code LDC} for this constant
+ * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
+ * to the bootstrap, that would appear in the
+ * {@code BootstrapMethods} attribute
+ * @throws NullPointerException if any argument is null
+ * @throws IllegalArgumentException if the {@code name} has the incorrect
+ * format
+ * @jvms 4.2.2 Unqualified Names
+ */
+ protected DynamicConstantDesc(DirectMethodHandleDesc bootstrapMethod,
+ String constantName,
+ ClassDesc constantType,
+ ConstantDesc... bootstrapArgs) {
+ this.bootstrapMethod = requireNonNull(bootstrapMethod);
+ this.constantName = validateMemberName(requireNonNull(constantName), true);
+ this.constantType = requireNonNull(constantType);
+ this.bootstrapArgs = requireNonNull(bootstrapArgs).clone();
+
+ if (constantName.length() == 0)
+ throw new IllegalArgumentException("Illegal invocation name: " + constantName);
+ }
+
+ /**
+ * Returns a nominal descriptor for a dynamic constant, transforming it into
+ * a more specific type if the constant bootstrap is a well-known one and a
+ * more specific nominal descriptor type (e.g., ClassDesc) is available.
+ *
+ * <p>Classes whose {@link Constable#describeConstable()} method produce
+ * a {@linkplain DynamicConstantDesc} with a well-known bootstrap including
+ * {@link Class} (for instances describing primitive types), {@link Enum},
+ * and {@link VarHandle}.
+ *
+ * <p>Bytecode-reading APIs that process the constant pool and wish to expose
+ * entries as {@link ConstantDesc} to their callers should generally use this
+ * method in preference to {@link #ofNamed(DirectMethodHandleDesc, String, ClassDesc, ConstantDesc...)}
+ * because this may result in a more specific type that can be provided to
+ * callers.
+ *
+ * @param <T> the type of the dynamic constant
+ * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
+ * bootstrap method for the constant
+ * @param constantName The unqualified name that would appear in the {@code NameAndType}
+ * operand of the {@code LDC} for this constant
+ * @param constantType a {@link ClassDesc} describing the type
+ * that would appear in the {@code NameAndType} operand
+ * of the {@code LDC} for this constant
+ * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
+ * to the bootstrap, that would appear in the
+ * {@code BootstrapMethods} attribute
+ * @return the nominal descriptor
+ * @throws NullPointerException if any argument is null
+ * @throws IllegalArgumentException if the {@code name} has the incorrect
+ * format
+ * @jvms 4.2.2 Unqualified Names
+ */
+ // Do not call this method from the static initialization of java.lang.constant.ConstantDescs
+ // since that can lead to potential deadlock during multi-threaded concurrent execution
+ public static<T> ConstantDesc ofCanonical(DirectMethodHandleDesc bootstrapMethod,
+ String constantName,
+ ClassDesc constantType,
+ ConstantDesc[] bootstrapArgs) {
+ return DynamicConstantDesc.<T>ofNamed(bootstrapMethod, constantName, constantType, bootstrapArgs)
+ .tryCanonicalize();
+ }
+
+ /**
+ * Returns a nominal descriptor for a dynamic constant.
+ *
+ * @param <T> the type of the dynamic constant
+ * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
+ * bootstrap method for the constant
+ * @param constantName The unqualified name that would appear in the {@code NameAndType}
+ * operand of the {@code LDC} for this constant
+ * @param constantType a {@link ClassDesc} describing the type
+ * that would appear in the {@code NameAndType} operand
+ * of the {@code LDC} for this constant
+ * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
+ * to the bootstrap, that would appear in the
+ * {@code BootstrapMethods} attribute
+ * @return the nominal descriptor
+ * @throws NullPointerException if any argument is null
+ * @throws IllegalArgumentException if the {@code name} has the incorrect
+ * format
+ * @jvms 4.2.2 Unqualified Names
+ */
+
+ public static<T> DynamicConstantDesc<T> ofNamed(DirectMethodHandleDesc bootstrapMethod,
+ String constantName,
+ ClassDesc constantType,
+ ConstantDesc... bootstrapArgs) {
+ return new AnonymousDynamicConstantDesc<>(bootstrapMethod, constantName, constantType, bootstrapArgs);
+ }
+
+ /**
+ * Returns a nominal descriptor for a dynamic constant whose name parameter
+ * is {@link ConstantDescs#DEFAULT_NAME}, and whose type parameter is always
+ * the same as the bootstrap method return type.
+ *
+ * @param <T> the type of the dynamic constant
+ * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
+ * bootstrap method for the constant
+ * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
+ * to the bootstrap, that would appear in the
+ * {@code BootstrapMethods} attribute
+ * @return the nominal descriptor
+ * @throws NullPointerException if any argument is null
+ * @jvms 4.2.2 Unqualified Names
+ */
+ public static<T> DynamicConstantDesc<T> of(DirectMethodHandleDesc bootstrapMethod,
+ ConstantDesc... bootstrapArgs) {
+ return ofNamed(bootstrapMethod, DEFAULT_NAME, bootstrapMethod.invocationType().returnType(), bootstrapArgs);
+ }
+
+ /**
+ * Returns a nominal descriptor for a dynamic constant whose bootstrap has
+ * no static arguments, whose name parameter is {@link ConstantDescs#DEFAULT_NAME},
+ * and whose type parameter is always the same as the bootstrap method return type.
+ *
+ * @param <T> the type of the dynamic constant
+ * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
+ * bootstrap method for the constant
+ * @return the nominal descriptor
+ * @throws NullPointerException if any argument is null
+ */
+ public static<T> DynamicConstantDesc<T> of(DirectMethodHandleDesc bootstrapMethod) {
+ return of(bootstrapMethod, EMPTY_CONSTANTDESC);
+ }
+
+ /**
+ * Returns the name that would appear in the {@code NameAndType} operand
+ * of the {@code LDC} for this constant.
+ *
+ * @return the constant name
+ */
+ public String constantName() {
+ return constantName;
+ }
+
+ /**
+ * Returns a {@link ClassDesc} describing the type that would appear in the
+ * {@code NameAndType} operand of the {@code LDC} for this constant.
+ *
+ * @return the constant type
+ */
+ public ClassDesc constantType() {
+ return constantType;
+ }
+
+ /**
+ * Returns a {@link MethodHandleDesc} describing the bootstrap method for
+ * this constant.
+ *
+ * @return the bootstrap method
+ */
+ public DirectMethodHandleDesc bootstrapMethod() {
+ return bootstrapMethod;
+ }
+
+ /**
+ * Returns the bootstrap arguments for this constant.
+ *
+ * @return the bootstrap arguments
+ */
+ public ConstantDesc[] bootstrapArgs() {
+ return bootstrapArgs.clone();
+ }
+
+ /**
+ * Returns the bootstrap arguments for this constant as an immutable {@link List}.
+ *
+ * @return a {@link List} of the bootstrap arguments
+ */
+ public List<ConstantDesc> bootstrapArgsList() {
+ return List.of(bootstrapArgs);
+ }
+
+ @SuppressWarnings("unchecked")
+ public T resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException {
+ try {
+ MethodHandle bsm = (MethodHandle) bootstrapMethod.resolveConstantDesc(lookup);
+ if (bsm.type().parameterCount() < 2 ||
+ !MethodHandles.Lookup.class.isAssignableFrom(bsm.type().parameterType(0))) {
+ throw new BootstrapMethodError(
+ "Invalid bootstrap method declared for resolving a dynamic constant: " + bootstrapMethod);
+ }
+ Object[] bsmArgs = new Object[3 + bootstrapArgs.length];
+ bsmArgs[0] = lookup;
+ bsmArgs[1] = constantName;
+ bsmArgs[2] = constantType.resolveConstantDesc(lookup);
+ for (int i = 0; i < bootstrapArgs.length; i++)
+ bsmArgs[3 + i] = bootstrapArgs[i].resolveConstantDesc(lookup);
+
+ return (T) bsm.invokeWithArguments(bsmArgs);
+ } catch (Error e) {
+ throw e;
+ } catch (Throwable t) {
+ throw new BootstrapMethodError(t);
+ }
+ }
+
+ private ConstantDesc tryCanonicalize() {
+ Function<DynamicConstantDesc<?>, ConstantDesc> f = CanonicalMapHolder.CANONICAL_MAP.get(bootstrapMethod);
+ if (f != null) {
+ try {
+ return f.apply(this);
+ }
+ catch (Throwable t) {
+ return this;
+ }
+ }
+ return this;
+ }
+
+ private static ConstantDesc canonicalizeNull(DynamicConstantDesc<?> desc) {
+ if (desc.bootstrapArgs.length != 0)
+ return desc;
+ return ConstantDescs.NULL;
+ }
+
+ private static ConstantDesc canonicalizeEnum(DynamicConstantDesc<?> desc) {
+ if (desc.bootstrapArgs.length != 0
+ || desc.constantName == null)
+ return desc;
+ return EnumDesc.of(desc.constantType, desc.constantName);
+ }
+
+ private static ConstantDesc canonicalizePrimitiveClass(DynamicConstantDesc<?> desc) {
+ if (desc.bootstrapArgs.length != 0
+ || !desc.constantType().equals(CD_Class)
+ || desc.constantName == null)
+ return desc;
+ return ClassDesc.ofDescriptor(desc.constantName);
+ }
+
+ private static ConstantDesc canonicalizeStaticFieldVarHandle(DynamicConstantDesc<?> desc) {
+ if (desc.bootstrapArgs.length != 2
+ || !desc.constantType().equals(CD_VarHandle))
+ return desc;
+ return VarHandleDesc.ofStaticField((ClassDesc) desc.bootstrapArgs[0],
+ desc.constantName,
+ (ClassDesc) desc.bootstrapArgs[1]);
+ }
+
+ private static ConstantDesc canonicalizeFieldVarHandle(DynamicConstantDesc<?> desc) {
+ if (desc.bootstrapArgs.length != 2
+ || !desc.constantType().equals(CD_VarHandle))
+ return desc;
+ return VarHandleDesc.ofField((ClassDesc) desc.bootstrapArgs[0],
+ desc.constantName,
+ (ClassDesc) desc.bootstrapArgs[1]);
+ }
+
+ private static ConstantDesc canonicalizeArrayVarHandle(DynamicConstantDesc<?> desc) {
+ if (desc.bootstrapArgs.length != 1
+ || !desc.constantType().equals(CD_VarHandle))
+ return desc;
+ return VarHandleDesc.ofArray((ClassDesc) desc.bootstrapArgs[0]);
+ }
+
+ // @@@ To eventually support in canonicalization: DCR with BSM=MHR_METHODHANDLEDESC_ASTYPE becomes AsTypeMHDesc
+
+ /**
+ * Compares the specified object with this descriptor for equality. Returns
+ * {@code true} if and only if the specified object is also a
+ * {@linkplain DynamicConstantDesc}, and both descriptors have equal
+ * bootstrap methods, bootstrap argument lists, constant name, and
+ * constant type.
+ *
+ * @param o the {@code DynamicConstantDesc} to compare to this
+ * {@code DynamicConstantDesc}
+ * @return {@code true} if the specified {@code DynamicConstantDesc}
+ * is equal to this {@code DynamicConstantDesc}.
+ *
+ */
+ @Override
+ public final boolean equals(Object o) {
+ if (this == o) return true;
+ return (o instanceof DynamicConstantDesc<?> desc)
+ && Objects.equals(bootstrapMethod, desc.bootstrapMethod)
+ && Arrays.equals(bootstrapArgs, desc.bootstrapArgs)
+ && Objects.equals(constantName, desc.constantName)
+ && Objects.equals(constantType, desc.constantType);
+ }
+
+ @Override
+ public final int hashCode() {
+ int result = Objects.hash(bootstrapMethod, constantName, constantType);
+ result = 31 * result + Arrays.hashCode(bootstrapArgs);
+ return result;
+ }
+
+ /**
+ * Returns a compact textual description of this constant description,
+ * including the bootstrap method, the constant name and type, and
+ * the static bootstrap arguments.
+ *
+ * @return A compact textual description of this call site descriptor
+ */
+ @Override
+ public String toString() {
+ return String.format("DynamicConstantDesc[%s::%s(%s%s)%s]",
+ bootstrapMethod.owner().displayName(),
+ bootstrapMethod.methodName(),
+ constantName.equals(ConstantDescs.DEFAULT_NAME) ? "" : constantName + "/",
+ Stream.of(bootstrapArgs).map(Object::toString).collect(joining(",")),
+ constantType.displayName());
+ }
+
+ private static class AnonymousDynamicConstantDesc<T> extends DynamicConstantDesc<T> {
+ AnonymousDynamicConstantDesc(DirectMethodHandleDesc bootstrapMethod, String constantName, ClassDesc constantType, ConstantDesc... bootstrapArgs) {
+ super(bootstrapMethod, constantName, constantType, bootstrapArgs);
+ }
+ }
+
+ private static final class CanonicalMapHolder {
+ static final Map<MethodHandleDesc, Function<DynamicConstantDesc<?>, ConstantDesc>> CANONICAL_MAP =
+ Map.ofEntries(
+ Map.entry(ConstantDescs.BSM_PRIMITIVE_CLASS, DynamicConstantDesc::canonicalizePrimitiveClass),
+ Map.entry(ConstantDescs.BSM_ENUM_CONSTANT, DynamicConstantDesc::canonicalizeEnum),
+ Map.entry(ConstantDescs.BSM_NULL_CONSTANT, DynamicConstantDesc::canonicalizeNull),
+ Map.entry(ConstantDescs.BSM_VARHANDLE_STATIC_FIELD, DynamicConstantDesc::canonicalizeStaticFieldVarHandle),
+ Map.entry(ConstantDescs.BSM_VARHANDLE_FIELD, DynamicConstantDesc::canonicalizeFieldVarHandle),
+ Map.entry(ConstantDescs.BSM_VARHANDLE_ARRAY, DynamicConstantDesc::canonicalizeArrayVarHandle));
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/constant/MethodHandleDesc.java b/ojluni/src/main/java/java/lang/constant/MethodHandleDesc.java
new file mode 100644
index 0000000..8c9ee15
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/MethodHandleDesc.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+import static java.lang.constant.ConstantDescs.CD_void;
+import static java.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR;
+
+/**
+ * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
+ * {@link MethodHandle} constant.
+ *
+ * @since 12
+ */
+public sealed interface MethodHandleDesc
+ extends ConstantDesc
+ permits AsTypeMethodHandleDesc,
+ DirectMethodHandleDesc {
+
+ /**
+ * Creates a {@linkplain MethodHandleDesc} corresponding to an invocation of a
+ * declared method, invocation of a constructor, or access to a field.
+ *
+ * <p>The lookup descriptor string has the same format as for the various
+ * variants of {@code CONSTANT_MethodHandle_info} and for the lookup
+ * methods on {@link MethodHandles.Lookup}. For a method or constructor
+ * invocation, it is interpreted as a method type descriptor; for field
+ * access, it is interpreted as a field descriptor. If {@code kind} is
+ * {@code CONSTRUCTOR}, the {@code name} parameter is ignored and the return
+ * type of the lookup descriptor must be {@code void}. If {@code kind}
+ * corresponds to a virtual method invocation, the lookup type includes the
+ * method parameters but not the receiver type.
+ *
+ * @param kind The kind of method handle to be described
+ * @param owner a {@link ClassDesc} describing the class containing the
+ * method, constructor, or field
+ * @param name the unqualified name of the method or field (ignored if
+ * {@code kind} is {@code CONSTRUCTOR})
+ * @param lookupDescriptor a method descriptor string the lookup type,
+ * if the request is for a method invocation, or
+ * describing the invocation type, if the request is
+ * for a field or constructor
+ * @return the {@linkplain MethodHandleDesc}
+ * @throws NullPointerException if any of the non-ignored arguments are null
+ * @throws IllegalArgumentException if the descriptor string is not a valid
+ * method or field descriptor
+ * @jvms 4.4.8 The CONSTANT_MethodHandle_info Structure
+ * @jvms 4.2.2 Unqualified Names
+ * @jvms 4.3.2 Field Descriptors
+ * @jvms 4.3.3 Method Descriptors
+ */
+ static DirectMethodHandleDesc of(DirectMethodHandleDesc.Kind kind,
+ ClassDesc owner,
+ String name,
+ String lookupDescriptor) {
+ switch (kind) {
+ case GETTER:
+ case SETTER:
+ case STATIC_GETTER:
+ case STATIC_SETTER:
+ return ofField(kind, owner, name, ClassDesc.ofDescriptor(lookupDescriptor));
+ default:
+ return new DirectMethodHandleDescImpl(kind, owner, name, MethodTypeDesc.ofDescriptor(lookupDescriptor));
+ }
+ }
+
+ /**
+ * Creates a {@linkplain MethodHandleDesc} corresponding to an invocation of a
+ * declared method or constructor.
+ *
+ * <p>The lookup descriptor string has the same format as for the lookup
+ * methods on {@link MethodHandles.Lookup}. If {@code kind} is
+ * {@code CONSTRUCTOR}, the name is ignored and the return type of the lookup
+ * type must be {@code void}. If {@code kind} corresponds to a virtual method
+ * invocation, the lookup type includes the method parameters but not the
+ * receiver type.
+ *
+ * @param kind The kind of method handle to be described; must be one of
+ * {@code SPECIAL, VIRTUAL, STATIC, INTERFACE_SPECIAL,
+ * INTERFACE_VIRTUAL, INTERFACE_STATIC, CONSTRUCTOR}
+ * @param owner a {@link ClassDesc} describing the class containing the
+ * method or constructor
+ * @param name the unqualified name of the method (ignored if {@code kind}
+ * is {@code CONSTRUCTOR})
+ * @param lookupMethodType a {@link MethodTypeDesc} describing the lookup type
+ * @return the {@linkplain MethodHandleDesc}
+ * @throws NullPointerException if any non-ignored arguments are null
+ * @throws IllegalArgumentException if the {@code name} has the incorrect
+ * format, or the kind is invalid
+ * @jvms 4.2.2 Unqualified Names
+ */
+ static DirectMethodHandleDesc ofMethod(DirectMethodHandleDesc.Kind kind,
+ ClassDesc owner,
+ String name,
+ MethodTypeDesc lookupMethodType) {
+ switch (kind) {
+ case GETTER:
+ case SETTER:
+ case STATIC_GETTER:
+ case STATIC_SETTER:
+ throw new IllegalArgumentException(kind.toString());
+ case VIRTUAL:
+ case SPECIAL:
+ case INTERFACE_VIRTUAL:
+ case INTERFACE_SPECIAL:
+ case INTERFACE_STATIC:
+ case STATIC:
+ case CONSTRUCTOR:
+ return new DirectMethodHandleDescImpl(kind, owner, name, lookupMethodType);
+ default:
+ throw new IllegalArgumentException(kind.toString());
+ }
+ }
+
+ /**
+ * Creates a {@linkplain MethodHandleDesc} corresponding to a method handle
+ * that accesses a field.
+ *
+ * @param kind the kind of the method handle to be described; must be one of {@code GETTER},
+ * {@code SETTER}, {@code STATIC_GETTER}, or {@code STATIC_SETTER}
+ * @param owner a {@link ClassDesc} describing the class containing the field
+ * @param fieldName the unqualified name of the field
+ * @param fieldType a {@link ClassDesc} describing the type of the field
+ * @return the {@linkplain MethodHandleDesc}
+ * @throws NullPointerException if any of the arguments are null
+ * @throws IllegalArgumentException if the {@code kind} is not one of the
+ * valid values or if the field name is not valid
+ * @jvms 4.2.2 Unqualified Names
+ */
+ static DirectMethodHandleDesc ofField(DirectMethodHandleDesc.Kind kind,
+ ClassDesc owner,
+ String fieldName,
+ ClassDesc fieldType) {
+ MethodTypeDesc mtr = switch (kind) {
+ case GETTER -> MethodTypeDesc.of(fieldType, owner);
+ case SETTER -> MethodTypeDesc.of(CD_void, owner, fieldType);
+ case STATIC_GETTER -> MethodTypeDesc.of(fieldType);
+ case STATIC_SETTER -> MethodTypeDesc.of(CD_void, fieldType);
+ default -> throw new IllegalArgumentException(kind.toString());
+ };
+ return new DirectMethodHandleDescImpl(kind, owner, fieldName, mtr);
+ }
+
+ /**
+ * Returns a {@linkplain MethodHandleDesc} corresponding to invocation of a constructor
+ *
+ * @param owner a {@link ClassDesc} describing the class containing the
+ * constructor
+ * @param paramTypes {@link ClassDesc}s describing the parameter types of
+ * the constructor
+ * @return the {@linkplain MethodHandleDesc}
+ * @throws NullPointerException if any argument or its contents is {@code null}
+ */
+ static DirectMethodHandleDesc ofConstructor(ClassDesc owner,
+ ClassDesc... paramTypes) {
+ return MethodHandleDesc.ofMethod(CONSTRUCTOR, owner, ConstantDescs.DEFAULT_NAME,
+ MethodTypeDesc.of(CD_void, paramTypes));
+ }
+
+ /**
+ * Returns a {@linkplain MethodHandleDesc} that describes this method handle
+ * adapted to a different type, as if by {@link MethodHandle#asType(MethodType)}.
+ *
+ * @param type a {@link MethodHandleDesc} describing the new method type
+ * @return a {@linkplain MethodHandleDesc} for the adapted method handle
+ * @throws NullPointerException if the argument is {@code null}
+ */
+ default MethodHandleDesc asType(MethodTypeDesc type) {
+ return (invocationType().equals(type)) ? this : new AsTypeMethodHandleDesc(this, type);
+ }
+
+ /**
+ * Returns a {@link MethodTypeDesc} describing the invocation type of the
+ * method handle described by this nominal descriptor. The invocation type
+ * describes the full set of stack values that are consumed by the invocation
+ * (including the receiver, if any).
+ *
+ * @return a {@linkplain MethodHandleDesc} describing the method handle type
+ */
+ MethodTypeDesc invocationType();
+
+ /**
+ * Compares the specified object with this descriptor for equality. Returns
+ * {@code true} if and only if the specified object is also a
+ * {@linkplain MethodHandleDesc}, and both encode the same nominal description
+ * of a method handle.
+ *
+ * @param o the other object
+ * @return whether this descriptor is equal to the other object
+ */
+ boolean equals(Object o);
+}
diff --git a/ojluni/src/main/java/java/lang/constant/MethodTypeDesc.java b/ojluni/src/main/java/java/lang/constant/MethodTypeDesc.java
new file mode 100644
index 0000000..4750231
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/MethodTypeDesc.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.lang.invoke.MethodType;
+import java.lang.invoke.TypeDescriptor;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
+ * {@linkplain MethodType} constant.
+ *
+ * @since 12
+ */
+public sealed interface MethodTypeDesc
+ extends ConstantDesc,
+ TypeDescriptor.OfMethod<ClassDesc, MethodTypeDesc>
+ permits MethodTypeDescImpl {
+ /**
+ * Creates a {@linkplain MethodTypeDesc} given a method descriptor string.
+ *
+ * @param descriptor a method descriptor string
+ * @return a {@linkplain MethodTypeDesc} describing the desired method type
+ * @throws NullPointerException if the argument is {@code null}
+ * @throws IllegalArgumentException if the descriptor string is not a valid
+ * method descriptor
+ * @jvms 4.3.3 Method Descriptors
+ */
+ static MethodTypeDesc ofDescriptor(String descriptor) {
+ return MethodTypeDescImpl.ofDescriptor(descriptor);
+ }
+
+ /**
+ * Returns a {@linkplain MethodTypeDesc} given the return type and parameter
+ * types.
+ *
+ * @param returnDesc a {@linkplain ClassDesc} describing the return type
+ * @param paramDescs {@linkplain ClassDesc}s describing the argument types
+ * @return a {@linkplain MethodTypeDesc} describing the desired method type
+ * @throws NullPointerException if any argument or its contents are {@code null}
+ * @throws IllegalArgumentException if any element of {@code paramDescs} is a
+ * {@link ClassDesc} for {@code void}
+ */
+ static MethodTypeDesc of(ClassDesc returnDesc, ClassDesc... paramDescs) {
+ return new MethodTypeDescImpl(returnDesc, paramDescs);
+ }
+
+ /**
+ * Gets the return type of the method type described by this {@linkplain MethodTypeDesc}.
+ *
+ * @return a {@link ClassDesc} describing the return type of the method type
+ */
+ ClassDesc returnType();
+
+ /**
+ * Returns the number of parameters of the method type described by
+ * this {@linkplain MethodTypeDesc}.
+ * @return the number of parameters
+ */
+ int parameterCount();
+
+ /**
+ * Returns the parameter type of the {@code index}'th parameter of the method type
+ * described by this {@linkplain MethodTypeDesc}.
+ *
+ * @param index the index of the parameter to retrieve
+ * @return a {@link ClassDesc} describing the desired parameter type
+ * @throws IndexOutOfBoundsException if the index is outside the half-open
+ * range {[0, parameterCount())}
+ */
+ ClassDesc parameterType(int index);
+
+ /**
+ * Returns the parameter types as an immutable {@link List}.
+ *
+ * @return a {@link List} of {@link ClassDesc} describing the parameter types
+ */
+ List<ClassDesc> parameterList();
+
+ /**
+ * Returns the parameter types as an array.
+ *
+ * @return an array of {@link ClassDesc} describing the parameter types
+ */
+ ClassDesc[] parameterArray();
+
+ /**
+ * Returns a {@linkplain MethodTypeDesc} that is identical to
+ * this one, except with the specified return type.
+ *
+ * @param returnType a {@link ClassDesc} describing the new return type
+ * @return a {@linkplain MethodTypeDesc} describing the desired method type
+ * @throws NullPointerException if the argument is {@code null}
+ */
+ MethodTypeDesc changeReturnType(ClassDesc returnType);
+
+ /**
+ * Returns a {@linkplain MethodTypeDesc} that is identical to this one,
+ * except that a single parameter type has been changed to the specified type.
+ *
+ * @param index the index of the parameter to change
+ * @param paramType a {@link ClassDesc} describing the new parameter type
+ * @return a {@linkplain MethodTypeDesc} describing the desired method type
+ * @throws NullPointerException if any argument is {@code null}
+ * @throws IndexOutOfBoundsException if the index is outside the half-open
+ * range {[0, parameterCount)}
+ */
+ MethodTypeDesc changeParameterType(int index, ClassDesc paramType);
+
+ /**
+ * Returns a {@linkplain MethodTypeDesc} that is identical to this one,
+ * except that a range of parameter types have been removed.
+ *
+ * @param start the index of the first parameter to remove
+ * @param end the index after the last parameter to remove
+ * @return a {@linkplain MethodTypeDesc} describing the desired method type
+ * @throws IndexOutOfBoundsException if {@code start} is outside the half-open
+ * range {@code [0, parameterCount)}, or {@code end} is outside the closed range
+ * {@code [0, parameterCount]}, or if {@code start > end}
+ */
+ MethodTypeDesc dropParameterTypes(int start, int end);
+
+ /**
+ * Returns a {@linkplain MethodTypeDesc} that is identical to this one,
+ * except that a range of additional parameter types have been inserted.
+ *
+ * @param pos the index at which to insert the first inserted parameter
+ * @param paramTypes {@link ClassDesc}s describing the new parameter types
+ * to insert
+ * @return a {@linkplain MethodTypeDesc} describing the desired method type
+ * @throws NullPointerException if any argument or its contents are {@code null}
+ * @throws IndexOutOfBoundsException if {@code pos} is outside the closed
+ * range {[0, parameterCount]}
+ * @throws IllegalArgumentException if any element of {@code paramTypes}
+ * is a {@link ClassDesc} for {@code void}
+ */
+ MethodTypeDesc insertParameterTypes(int pos, ClassDesc... paramTypes);
+
+ /**
+ * Returns the method type descriptor string.
+ *
+ * @return the method type descriptor string
+ * @jvms 4.3.3 Method Descriptors
+ */
+ default String descriptorString() {
+ return String.format("(%s)%s",
+ Stream.of(parameterArray())
+ .map(ClassDesc::descriptorString)
+ .collect(Collectors.joining()),
+ returnType().descriptorString());
+ }
+
+ /**
+ * Returns a human-readable descriptor for this method type, using the
+ * canonical names for parameter and return types.
+ *
+ * @return the human-readable descriptor for this method type
+ */
+ default String displayDescriptor() {
+ return String.format("(%s)%s",
+ Stream.of(parameterArray())
+ .map(ClassDesc::displayName)
+ .collect(Collectors.joining(",")),
+ returnType().displayName());
+ }
+
+ /**
+ * Compares the specified object with this descriptor for equality. Returns
+ * {@code true} if and only if the specified object is also a
+ * {@linkplain MethodTypeDesc} both have the same arity, their return types
+ * are equal, and each pair of corresponding parameter types are equal.
+ *
+ * @param o the other object
+ * @return whether this descriptor is equal to the other object
+ */
+ boolean equals(Object o);
+}
diff --git a/ojluni/src/main/java/java/lang/constant/MethodTypeDescImpl.java b/ojluni/src/main/java/java/lang/constant/MethodTypeDescImpl.java
new file mode 100644
index 0000000..76c936d
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/MethodTypeDescImpl.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Arrays;
+import java.util.List;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
+ * {@link MethodType}. A {@linkplain MethodTypeDescImpl} corresponds to a
+ * {@code Constant_MethodType_info} entry in the constant pool of a classfile.
+ */
+final class MethodTypeDescImpl implements MethodTypeDesc {
+ private final ClassDesc returnType;
+ private final ClassDesc[] argTypes;
+
+ /**
+ * Constructs a {@linkplain MethodTypeDesc} with the specified return type
+ * and parameter types
+ *
+ * @param returnType a {@link ClassDesc} describing the return type
+ * @param argTypes {@link ClassDesc}s describing the parameter types
+ */
+ MethodTypeDescImpl(ClassDesc returnType, ClassDesc[] argTypes) {
+ this.returnType = requireNonNull(returnType);
+ this.argTypes = requireNonNull(argTypes);
+
+ for (ClassDesc cr : argTypes)
+ if (cr.isPrimitive() && cr.descriptorString().equals("V"))
+ throw new IllegalArgumentException("Void parameters not permitted");
+ }
+
+ /**
+ * Creates a {@linkplain MethodTypeDescImpl} given a method descriptor string.
+ *
+ * @param descriptor the method descriptor string
+ * @return a {@linkplain MethodTypeDescImpl} describing the desired method type
+ * @throws IllegalArgumentException if the descriptor string is not a valid
+ * method descriptor
+ * @jvms 4.3.3 Method Descriptors
+ */
+ static MethodTypeDescImpl ofDescriptor(String descriptor) {
+ requireNonNull(descriptor);
+ List<String> types = ConstantUtils.parseMethodDescriptor(descriptor);
+ ClassDesc[] paramTypes = types.stream().skip(1).map(ClassDesc::ofDescriptor).toArray(ClassDesc[]::new);
+ return new MethodTypeDescImpl(ClassDesc.ofDescriptor(types.get(0)), paramTypes);
+ }
+
+ @Override
+ public ClassDesc returnType() {
+ return returnType;
+ }
+
+ @Override
+ public int parameterCount() {
+ return argTypes.length;
+ }
+
+ @Override
+ public ClassDesc parameterType(int index) {
+ return argTypes[index];
+ }
+
+ @Override
+ public List<ClassDesc> parameterList() {
+ return List.of(argTypes);
+ }
+
+ @Override
+ public ClassDesc[] parameterArray() {
+ return argTypes.clone();
+ }
+
+ @Override
+ public MethodTypeDesc changeReturnType(ClassDesc returnType) {
+ return MethodTypeDesc.of(returnType, argTypes);
+ }
+
+ @Override
+ public MethodTypeDesc changeParameterType(int index, ClassDesc paramType) {
+ ClassDesc[] newArgs = argTypes.clone();
+ newArgs[index] = paramType;
+ return MethodTypeDesc.of(returnType, newArgs);
+ }
+
+ @Override
+ public MethodTypeDesc dropParameterTypes(int start, int end) {
+ if (start < 0 || start >= argTypes.length || end < 0 || end > argTypes.length || start > end)
+ throw new IndexOutOfBoundsException();
+ ClassDesc[] newArgs = new ClassDesc[argTypes.length - (end - start)];
+ System.arraycopy(argTypes, 0, newArgs, 0, start);
+ System.arraycopy(argTypes, end, newArgs, start, argTypes.length - end);
+ return MethodTypeDesc.of(returnType, newArgs);
+ }
+
+ @Override
+ public MethodTypeDesc insertParameterTypes(int pos, ClassDesc... paramTypes) {
+ if (pos < 0 || pos > argTypes.length)
+ throw new IndexOutOfBoundsException(pos);
+ ClassDesc[] newArgs = new ClassDesc[argTypes.length + paramTypes.length];
+ System.arraycopy(argTypes, 0, newArgs, 0, pos);
+ System.arraycopy(paramTypes, 0, newArgs, pos, paramTypes.length);
+ System.arraycopy(argTypes, pos, newArgs, pos+paramTypes.length, argTypes.length - pos);
+ return MethodTypeDesc.of(returnType, newArgs);
+ }
+
+ @Override
+ public MethodType resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException {
+ @SuppressWarnings("removal")
+ MethodType mtype = AccessController.doPrivileged(new PrivilegedAction<>() {
+ @Override
+ public MethodType run() {
+ return MethodType.fromMethodDescriptorString(descriptorString(),
+ lookup.lookupClass().getClassLoader());
+ }
+ });
+
+ // let's check that the lookup has access to all the types in the method type
+ lookup.accessClass(mtype.returnType());
+ for (Class<?> paramType: mtype.parameterArray()) {
+ lookup.accessClass(paramType);
+ }
+ return mtype;
+ }
+
+ /**
+ * Returns {@code true} if this {@linkplain MethodTypeDescImpl} is
+ * equal to another {@linkplain MethodTypeDescImpl}. Equality is
+ * determined by the two descriptors having equal return types and argument
+ * types.
+ *
+ * @param o the {@code MethodTypeDescImpl} to compare to this
+ * {@code MethodTypeDescImpl}
+ * @return {@code true} if the specified {@code MethodTypeDescImpl}
+ * is equal to this {@code MethodTypeDescImpl}.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ MethodTypeDescImpl constant = (MethodTypeDescImpl) o;
+
+ return returnType.equals(constant.returnType)
+ && Arrays.equals(argTypes, constant.argTypes);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = returnType.hashCode();
+ result = 31 * result + Arrays.hashCode(argTypes);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("MethodTypeDesc[%s]", displayDescriptor());
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/constant/PrimitiveClassDescImpl.java b/ojluni/src/main/java/java/lang/constant/PrimitiveClassDescImpl.java
new file mode 100644
index 0000000..0478fbe
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/PrimitiveClassDescImpl.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.lang.invoke.MethodHandles;
+
+import sun.invoke.util.Wrapper;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * A <a href="package-summary.html#nominal">nominal descriptor</a> for the class
+ * constant corresponding to a primitive type (e.g., {@code int.class}).
+ */
+final class PrimitiveClassDescImpl
+ extends DynamicConstantDesc<Class<?>> implements ClassDesc {
+
+ private final String descriptor;
+
+ /**
+ * Creates a {@linkplain ClassDesc} given a descriptor string for a primitive
+ * type.
+ *
+ * @param descriptor the descriptor string, which must be a one-character
+ * string corresponding to one of the nine base types
+ * @throws IllegalArgumentException if the descriptor string does not
+ * describe a valid primitive type
+ * @jvms 4.3 Descriptors
+ */
+ PrimitiveClassDescImpl(String descriptor) {
+ super(ConstantDescs.BSM_PRIMITIVE_CLASS, requireNonNull(descriptor), ConstantDescs.CD_Class);
+ if (descriptor.length() != 1
+ || "VIJCSBFDZ".indexOf(descriptor.charAt(0)) < 0)
+ throw new IllegalArgumentException(String.format("not a valid primitive type descriptor: %s", descriptor));
+ this.descriptor = descriptor;
+ }
+
+ @Override
+ public String descriptorString() {
+ return descriptor;
+ }
+
+ @Override
+ public Class<?> resolveConstantDesc(MethodHandles.Lookup lookup) {
+ return Wrapper.forBasicType(descriptorString().charAt(0)).primitiveType();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("PrimitiveClassDesc[%s]", displayName());
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/constant/ReferenceClassDescImpl.java b/ojluni/src/main/java/java/lang/constant/ReferenceClassDescImpl.java
new file mode 100644
index 0000000..6c677fa
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/ReferenceClassDescImpl.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.constant;
+
+import java.lang.invoke.MethodHandles;
+
+import static java.lang.constant.ConstantUtils.dropFirstAndLastChar;
+import static java.lang.constant.ConstantUtils.internalToBinary;
+import static java.util.Objects.requireNonNull;
+
+/**
+ * A <a href="package-summary.html#nominal">nominal descriptor</a> for a class,
+ * interface, or array type. A {@linkplain ReferenceClassDescImpl} corresponds to a
+ * {@code Constant_Class_info} entry in the constant pool of a classfile.
+ */
+final class ReferenceClassDescImpl implements ClassDesc {
+ private final String descriptor;
+
+ /**
+ * Creates a {@linkplain ClassDesc} from a descriptor string for a class or
+ * interface type
+ *
+ * @param descriptor a field descriptor string for a class or interface type
+ * @throws IllegalArgumentException if the descriptor string is not a valid
+ * field descriptor string, or does not describe a class or interface type
+ * @jvms 4.3.2 Field Descriptors
+ */
+ ReferenceClassDescImpl(String descriptor) {
+ requireNonNull(descriptor);
+ int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, descriptor.length(), false);
+ if (len == 0 || len == 1
+ || len != descriptor.length())
+ throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor));
+ this.descriptor = descriptor;
+ }
+
+ @Override
+ public String descriptorString() {
+ return descriptor;
+ }
+
+ @Override
+ public Class<?> resolveConstantDesc(MethodHandles.Lookup lookup)
+ throws ReflectiveOperationException {
+ ClassDesc c = this;
+ int depth = ConstantUtils.arrayDepth(descriptorString());
+ for (int i=0; i<depth; i++)
+ c = c.componentType();
+
+ if (c.isPrimitive())
+ return lookup.findClass(descriptorString());
+ else {
+ Class<?> clazz = lookup.findClass(internalToBinary(dropFirstAndLastChar(c.descriptorString())));
+ for (int i = 0; i < depth; i++)
+ clazz = clazz.arrayType();
+ return clazz;
+ }
+ }
+
+ /**
+ * Returns {@code true} if this {@linkplain ReferenceClassDescImpl} is
+ * equal to another {@linkplain ReferenceClassDescImpl}. Equality is
+ * determined by the two class descriptors having equal class descriptor
+ * strings.
+ *
+ * @param o the {@code ClassDesc} to compare to this
+ * {@code ClassDesc}
+ * @return {@code true} if the specified {@code ClassDesc}
+ * is equal to this {@code ClassDesc}.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ClassDesc constant = (ClassDesc) o;
+ return descriptor.equals(constant.descriptorString());
+ }
+
+ @Override
+ public int hashCode() {
+ return descriptor.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("ClassDesc[%s]", displayName());
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/constant/package-info.java b/ojluni/src/main/java/java/lang/constant/package-info.java
new file mode 100644
index 0000000..9bc978e
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/constant/package-info.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+/**
+ * Classes and interfaces to represent <em>nominal descriptors</em> for run-time
+ * entities such as classes or method handles, and classfile entities such as
+ * constant pool entries or {@code invokedynamic} call sites. These classes
+ * are suitable for use in bytecode reading and writing APIs, {@code invokedynamic}
+ * bootstraps, bytecode intrinsic APIs, and compile-time or link-time program
+ * analysis tools.
+ *
+ * <p>Every API that reads and writes bytecode instructions needs to model the
+ * operands to these instructions and other classfile structures (such as entries
+ * in the bootstrap methods table or stack maps, which frequently reference
+ * entries in the classfile constant pool.) Such entries can denote values of
+ * fundamental types, such as strings or integers; parts of a program, such as
+ * classes or method handles; or values of arbitrary user-defined types. The
+ * {@link java.lang.constant.ConstantDesc} hierarchy provides a representation of
+ * constant pool entries in nominal form that is convenient for APIs to model
+ * operands of bytecode instructions.
+ *
+ * <h2><a id="nominal"></a>Nominal Descriptors</h2>
+ *
+ * <p>A {@link java.lang.constant.ConstantDesc} is a description of a constant
+ * value. Such a description is the <em>nominal form</em> of the constant value;
+ * it is not the value itself, but rather a "recipe" for describing the value,
+ * storing the value in a constant pool entry, or reconstituting the value given
+ * a class loading context. Every {@link java.lang.constant.ConstantDesc}
+ * knows how to <em>resolve</em> itself -- compute the value that it describes --
+ * via {@link java.lang.constant.ConstantDesc#resolveConstantDesc(java.lang.invoke.MethodHandles.Lookup) ConstantDesc.resolveConstantDesc}.
+ * This allows an API which accepts {@link java.lang.constant.ConstantDesc}
+ * objects to evaluate them reflectively, provided that the classes and methods
+ * referenced in their nominal description are present and accessible.
+ *
+ * <p>The subtypes of {@link java.lang.constant.ConstantDesc} describe various kinds
+ * of constant values. For each type of loadable constant pool entry defined in JVMS 4.4,
+ * there is a corresponding subtype of {@link java.lang.constant.ConstantDesc}:
+ * {@link java.lang.constant.ClassDesc}, {@link java.lang.constant.MethodTypeDesc},
+ * {@link java.lang.constant.DirectMethodHandleDesc}, {@link java.lang.String},
+ * {@link java.lang.Integer}, {@link java.lang.Long}, {@link java.lang.Float},
+ * {@link java.lang.Double}, and {@link java.lang.constant.DynamicConstantDesc}. These classes
+ * provide type-specific accessor methods to extract the nominal information for
+ * that kind of constant. When a bytecode-writing API encounters a {@link java.lang.constant.ConstantDesc},
+ * it should examine it to see which of these types it is, cast it, extract
+ * its nominal information, and generate the corresponding entry to the constant pool.
+ * When a bytecode-reading API encounters a constant pool entry, it can
+ * convert it to the appropriate type of nominal descriptor. For dynamic
+ * constants, bytecode-reading APIs may wish to use the factory
+ * {@link java.lang.constant.DynamicConstantDesc#ofCanonical(DirectMethodHandleDesc, java.lang.String, ClassDesc, ConstantDesc[]) DynamicConstantDesc.ofCanonical},
+ * which will inspect the bootstrap and, for well-known bootstraps, return
+ * a more specific subtype of {@link java.lang.constant.DynamicConstantDesc}, such as
+ * {@link java.lang.Enum.EnumDesc}.
+ *
+ * <p>Another way to obtain the nominal description of a value is to ask the value
+ * itself. A {@link java.lang.constant.Constable} is a type whose values
+ * can describe themselves in nominal form as a {@link java.lang.constant.ConstantDesc}.
+ * Fundamental types such as {@link java.lang.String} and {@link java.lang.Class}
+ * implement {@link java.lang.constant.Constable}, as can user-defined
+ * classes. Entities that generate classfiles (such as compilers) can introspect
+ * over constable objects to obtain a more efficient way to represent their values
+ * in classfiles.
+ *
+ * <p>This package also includes {@link java.lang.constant.DynamicCallSiteDesc},
+ * which represents a (non-loadable) {@code Constant_InvokeDynamic_info} constant
+ * pool entry. It describes the bootstrap method, invocation name and type,
+ * and bootstrap arguments associated with an {@code invokedynamic} instruction.
+ * It is also suitable for describing {@code invokedynamic} call sites in bytecode
+ * reading and writing APIs.
+ *
+ * @jvms 4.4 The Constant Pool
+ *
+ * @since 12
+ */
+package java.lang.constant;
diff --git a/ojluni/src/main/java/java/lang/invoke/ConstantBootstraps.java b/ojluni/src/main/java/java/lang/invoke/ConstantBootstraps.java
new file mode 100644
index 0000000..7e414b1
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/invoke/ConstantBootstraps.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.invoke;
+
+import sun.invoke.util.Wrapper;
+
+import static java.lang.invoke.MethodHandleNatives.mapLookupExceptionToError;
+import static java.util.Objects.requireNonNull;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * Bootstrap methods for dynamically-computed constants.
+ *
+ * <p>The bootstrap methods in this class will throw a
+ * {@code NullPointerException} for any reference argument that is {@code null},
+ * unless the argument is specified to be unused or specified to accept a
+ * {@code null} value.
+ *
+ * @since 11
+ */
+public final class ConstantBootstraps {
+ /**
+ * Do not call.
+ */
+ private ConstantBootstraps() {throw new AssertionError();}
+
+ // implements the upcall from the JVM, MethodHandleNatives.linkDynamicConstant:
+ /*non-public*/
+ // BEGIN Android-removed: Remove unused implementation.
+ /*
+ static Object makeConstant(MethodHandle bootstrapMethod,
+ // Callee information:
+ String name, Class<?> type,
+ // Extra arguments for BSM, if any:
+ Object info,
+ // Caller information:
+ Class<?> callerClass) {
+ // Restrict bootstrap methods to those whose first parameter is Lookup
+ // The motivation here is, in the future, to possibly support BSMs
+ // that do not accept the meta-data of lookup/name/type, thereby
+ // allowing the co-opting of existing methods to be used as BSMs as
+ // long as the static arguments can be passed as method arguments
+ MethodType mt = bootstrapMethod.type();
+ if (mt.parameterCount() < 2 ||
+ !MethodHandles.Lookup.class.isAssignableFrom(mt.parameterType(0))) {
+ throw new BootstrapMethodError(
+ "Invalid bootstrap method declared for resolving a dynamic constant: " + bootstrapMethod);
+ }
+
+ // BSMI.invoke handles all type checking and exception translation.
+ // If type is not a reference type, the JVM is expecting a boxed
+ // version, and will manage unboxing on the other side.
+ return BootstrapMethodInvoker.invoke(
+ type, bootstrapMethod, name, type, info, callerClass);
+ }
+ */
+ // END Android-removed: Remove unused implementation.
+
+ /**
+ * Returns a {@code null} object reference for the reference type specified
+ * by {@code type}.
+ *
+ * @param lookup unused
+ * @param name unused
+ * @param type a reference type
+ * @return a {@code null} value
+ * @throws IllegalArgumentException if {@code type} is not a reference type
+ */
+ public static Object nullConstant(MethodHandles.Lookup lookup, String name, Class<?> type) {
+ if (requireNonNull(type).isPrimitive()) {
+ throw new IllegalArgumentException(String.format("not reference: %s", type));
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a {@link Class} mirror for the primitive type whose type
+ * descriptor is specified by {@code name}.
+ *
+ * @param lookup unused
+ * @param name the descriptor (JVMS 4.3) of the desired primitive type
+ * @param type the required result type (must be {@code Class.class})
+ * @return the {@link Class} mirror
+ * @throws IllegalArgumentException if the name is not a descriptor for a
+ * primitive type or the type is not {@code Class.class}
+ */
+ public static Class<?> primitiveClass(MethodHandles.Lookup lookup, String name, Class<?> type) {
+ requireNonNull(name);
+ requireNonNull(type);
+ if (type != Class.class) {
+ throw new IllegalArgumentException();
+ }
+ if (name.length() != 1) {
+ throw new IllegalArgumentException(String.format("not primitive: %s", name));
+ }
+
+ return Wrapper.forPrimitiveType(name.charAt(0)).primitiveType();
+ }
+
+ /**
+ * Returns an {@code enum} constant of the type specified by {@code type}
+ * with the name specified by {@code name}.
+ *
+ * @param lookup the lookup context describing the class performing the
+ * operation (normally stacked by the JVM)
+ * @param name the name of the constant to return, which must exactly match
+ * an enum constant in the specified type.
+ * @param type the {@code Class} object describing the enum type for which
+ * a constant is to be returned
+ * @param <E> The enum type for which a constant value is to be returned
+ * @return the enum constant of the specified enum type with the
+ * specified name
+ * @throws IllegalAccessError if the declaring class or the field is not
+ * accessible to the class performing the operation
+ * @throws IllegalArgumentException if the specified enum type has
+ * no constant with the specified name, or the specified
+ * class object does not represent an enum type
+ * @see Enum#valueOf(Class, String)
+ */
+ public static <E extends Enum<E>> E enumConstant(MethodHandles.Lookup lookup, String name, Class<E> type) {
+ requireNonNull(lookup);
+ requireNonNull(name);
+ requireNonNull(type);
+ validateClassAccess(lookup, type);
+
+ return Enum.valueOf(type, name);
+ }
+
+ /**
+ * Returns the value of a static final field.
+ *
+ * @param lookup the lookup context describing the class performing the
+ * operation (normally stacked by the JVM)
+ * @param name the name of the field
+ * @param type the type of the field
+ * @param declaringClass the class in which the field is declared
+ * @return the value of the field
+ * @throws IllegalAccessError if the declaring class or the field is not
+ * accessible to the class performing the operation
+ * @throws NoSuchFieldError if the specified field does not exist
+ * @throws IncompatibleClassChangeError if the specified field is not
+ * {@code final}
+ */
+ public static Object getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type,
+ Class<?> declaringClass) {
+ requireNonNull(lookup);
+ requireNonNull(name);
+ requireNonNull(type);
+ requireNonNull(declaringClass);
+
+ MethodHandle mh;
+ try {
+ mh = lookup.findStaticGetter(declaringClass, name, type);
+ // Android-changed: Re-implement final modifier check with existing APIs.
+ // MemberName member = mh.internalMemberName();
+ // if (!member.isFinal()) {
+ MethodHandleInfo info = lookup.revealDirect(mh);
+ if (!Modifier.isFinal(info.getModifiers())) {
+ throw new IncompatibleClassChangeError("not a final field: " + name);
+ }
+ }
+ catch (ReflectiveOperationException ex) {
+ throw mapLookupExceptionToError(ex);
+ }
+
+ // Since mh is a handle to a static field only instances of
+ // VirtualMachineError are anticipated to be thrown, such as a
+ // StackOverflowError or an InternalError from the j.l.invoke code
+ try {
+ return mh.invoke();
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable e) {
+ throw new LinkageError("Unexpected throwable", e);
+ }
+ }
+
+ /**
+ * Returns the value of a static final field declared in the class which
+ * is the same as the field's type (or, for primitive-valued fields,
+ * declared in the wrapper class.) This is a simplified form of
+ * {@link #getStaticFinal(MethodHandles.Lookup, String, Class, Class)}
+ * for the case where a class declares distinguished constant instances of
+ * itself.
+ *
+ * @param lookup the lookup context describing the class performing the
+ * operation (normally stacked by the JVM)
+ * @param name the name of the field
+ * @param type the type of the field
+ * @return the value of the field
+ * @throws IllegalAccessError if the declaring class or the field is not
+ * accessible to the class performing the operation
+ * @throws NoSuchFieldError if the specified field does not exist
+ * @throws IncompatibleClassChangeError if the specified field is not
+ * {@code final}
+ * @see #getStaticFinal(MethodHandles.Lookup, String, Class, Class)
+ */
+ public static Object getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type) {
+ requireNonNull(type);
+
+ Class<?> declaring = type.isPrimitive()
+ ? Wrapper.forPrimitiveType(type).wrapperType()
+ : type;
+ return getStaticFinal(lookup, name, type, declaring);
+ }
+
+
+ /**
+ * Returns the result of invoking a method handle with the provided
+ * arguments.
+ * <p>
+ * This method behaves as if the method handle to be invoked is the result
+ * of adapting the given method handle, via {@link MethodHandle#asType}, to
+ * adjust the return type to the desired type.
+ *
+ * @param lookup unused
+ * @param name unused
+ * @param type the desired type of the value to be returned, which must be
+ * compatible with the return type of the method handle
+ * @param handle the method handle to be invoked
+ * @param args the arguments to pass to the method handle, as if with
+ * {@link MethodHandle#invokeWithArguments}. Each argument may be
+ * {@code null}.
+ * @return the result of invoking the method handle
+ * @throws WrongMethodTypeException if the handle's method type cannot be
+ * adjusted to take the given number of arguments, or if the handle's return
+ * type cannot be adjusted to the desired type
+ * @throws ClassCastException if an argument or the result produced by
+ * invoking the handle cannot be converted by reference casting
+ * @throws Throwable anything thrown by the method handle invocation
+ */
+ public static Object invoke(MethodHandles.Lookup lookup, String name, Class<?> type,
+ MethodHandle handle, Object... args) throws Throwable {
+ requireNonNull(type);
+ requireNonNull(handle);
+ requireNonNull(args);
+
+ if (type != handle.type().returnType()) {
+ // Adjust the return type of the handle to be invoked while
+ // preserving variable arity if present
+ handle = handle.asType(handle.type().changeReturnType(type)).
+ withVarargs(handle.isVarargsCollector());
+ }
+
+ return handle.invokeWithArguments(args);
+ }
+
+ /**
+ * Finds a {@link VarHandle} for an instance field.
+ *
+ * @param lookup the lookup context describing the class performing the
+ * operation (normally stacked by the JVM)
+ * @param name the name of the field
+ * @param type the required result type (must be {@code Class<VarHandle>})
+ * @param declaringClass the class in which the field is declared
+ * @param fieldType the type of the field
+ * @return the {@link VarHandle}
+ * @throws IllegalAccessError if the declaring class or the field is not
+ * accessible to the class performing the operation
+ * @throws NoSuchFieldError if the specified field does not exist
+ * @throws IllegalArgumentException if the type is not {@code VarHandle}
+ */
+ public static VarHandle fieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type,
+ Class<?> declaringClass, Class<?> fieldType) {
+ requireNonNull(lookup);
+ requireNonNull(name);
+ requireNonNull(type);
+ requireNonNull(declaringClass);
+ requireNonNull(fieldType);
+ if (type != VarHandle.class) {
+ throw new IllegalArgumentException();
+ }
+
+ try {
+ return lookup.findVarHandle(declaringClass, name, fieldType);
+ }
+ catch (ReflectiveOperationException e) {
+ throw mapLookupExceptionToError(e);
+ }
+ }
+
+ /**
+ * Finds a {@link VarHandle} for a static field.
+ *
+ * @param lookup the lookup context describing the class performing the
+ * operation (normally stacked by the JVM)
+ * @param name the name of the field
+ * @param type the required result type (must be {@code Class<VarHandle>})
+ * @param declaringClass the class in which the field is declared
+ * @param fieldType the type of the field
+ * @return the {@link VarHandle}
+ * @throws IllegalAccessError if the declaring class or the field is not
+ * accessible to the class performing the operation
+ * @throws NoSuchFieldError if the specified field does not exist
+ * @throws IllegalArgumentException if the type is not {@code VarHandle}
+ */
+ public static VarHandle staticFieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type,
+ Class<?> declaringClass, Class<?> fieldType) {
+ requireNonNull(lookup);
+ requireNonNull(name);
+ requireNonNull(type);
+ requireNonNull(declaringClass);
+ requireNonNull(fieldType);
+ if (type != VarHandle.class) {
+ throw new IllegalArgumentException();
+ }
+
+ try {
+ return lookup.findStaticVarHandle(declaringClass, name, fieldType);
+ }
+ catch (ReflectiveOperationException e) {
+ throw mapLookupExceptionToError(e);
+ }
+ }
+
+ /**
+ * Finds a {@link VarHandle} for an array type.
+ *
+ * @param lookup the lookup context describing the class performing the
+ * operation (normally stacked by the JVM)
+ * @param name unused
+ * @param type the required result type (must be {@code Class<VarHandle>})
+ * @param arrayClass the type of the array
+ * @return the {@link VarHandle}
+ * @throws IllegalAccessError if the component type of the array is not
+ * accessible to the class performing the operation
+ * @throws IllegalArgumentException if the type is not {@code VarHandle}
+ */
+ public static VarHandle arrayVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type,
+ Class<?> arrayClass) {
+ requireNonNull(lookup);
+ requireNonNull(type);
+ requireNonNull(arrayClass);
+ if (type != VarHandle.class) {
+ throw new IllegalArgumentException();
+ }
+
+ return MethodHandles.arrayElementVarHandle(validateClassAccess(lookup, arrayClass));
+ }
+
+ /**
+ * Applies a conversion from a source type to a destination type.
+ * <p>
+ * Given a destination type {@code dstType} and an input
+ * value {@code value}, one of the following will happen:
+ * <ul>
+ * <li>If {@code dstType} is {@code void.class},
+ * a {@link ClassCastException} is thrown.
+ * <li>If {@code dstType} is {@code Object.class}, {@code value} is returned as is.
+ * </ul>
+ * <p>
+ * Otherwise one of the following conversions is applied to {@code value}:
+ * <ol>
+ * <li>If {@code dstType} is a reference type, a reference cast
+ * is applied to {@code value} as if by calling {@code dstType.cast(value)}.
+ * <li>If {@code dstType} is a primitive type, then, if the runtime type
+ * of {@code value} is a primitive wrapper type (such as {@link Integer}),
+ * a Java unboxing conversion is applied {@jls 5.1.8} followed by a
+ * Java casting conversion {@jls 5.5} converting either directly to
+ * {@code dstType}, or, if {@code dstType} is {@code boolean},
+ * to {@code int}, which is then converted to either {@code true}
+ * or {@code false} depending on whether the least-significant-bit
+ * is 1 or 0 respectively. If the runtime type of {@code value} is
+ * not a primitive wrapper type a {@link ClassCastException} is thrown.
+ * </ol>
+ * <p>
+ * The result is the same as when using the following code:
+ * <blockquote><pre>{@code
+ * MethodHandle id = MethodHandles.identity(dstType);
+ * MethodType mt = MethodType.methodType(dstType, Object.class);
+ * MethodHandle conv = MethodHandles.explicitCastArguments(id, mt);
+ * return conv.invoke(value);
+ * }</pre></blockquote>
+ *
+ * @param lookup unused
+ * @param name unused
+ * @param dstType the destination type of the conversion
+ * @param value the value to be converted
+ * @return the converted value
+ * @throws ClassCastException when {@code dstType} is {@code void},
+ * when a cast per (1) fails, or when {@code dstType} is a primitive type
+ * and the runtime type of {@code value} is not a primitive wrapper type
+ * (such as {@link Integer})
+ *
+ * @since 15
+ */
+ public static Object explicitCast(MethodHandles.Lookup lookup, String name, Class<?> dstType, Object value)
+ throws ClassCastException {
+ if (dstType == void.class)
+ throw new ClassCastException("Can not convert to void");
+ if (dstType == Object.class)
+ return value;
+
+ MethodHandle id = MethodHandles.identity(dstType);
+ MethodType mt = MethodType.methodType(dstType, Object.class);
+ MethodHandle conv = MethodHandles.explicitCastArguments(id, mt);
+ try {
+ return conv.invoke(value);
+ } catch (RuntimeException|Error e) {
+ throw e; // let specified CCE and other runtime exceptions/errors through
+ } catch (Throwable throwable) {
+ throw new InternalError(throwable); // Not specified, throw InternalError
+ }
+ }
+
+ private static <T> Class<T> validateClassAccess(MethodHandles.Lookup lookup, Class<T> type) {
+ try {
+ lookup.accessClass(type);
+ return type;
+ }
+ catch (ReflectiveOperationException ex) {
+ throw mapLookupExceptionToError(ex);
+ }
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodHandleNatives.java b/ojluni/src/main/java/java/lang/invoke/MethodHandleNatives.java
index 87f95ff..94e17bb 100644
--- a/ojluni/src/main/java/java/lang/invoke/MethodHandleNatives.java
+++ b/ojluni/src/main/java/java/lang/invoke/MethodHandleNatives.java
@@ -503,19 +503,48 @@
throw initCauseFrom(err, ex);
}
}
+ */
+ // END Android-removed: Unused implementation code.
+
+ // BEGIN Android-added: Add mapLookupExceptionToError(ex) from OpenJDK 17. http://b/270028670
+ /**
+ * Map a reflective exception to a linkage error.
+ */
+ static LinkageError mapLookupExceptionToError(ReflectiveOperationException ex) {
+ LinkageError err;
+ if (ex instanceof IllegalAccessException) {
+ Throwable cause = ex.getCause();
+ if (cause instanceof AbstractMethodError) {
+ return (AbstractMethodError) cause;
+ } else {
+ err = new IllegalAccessError(ex.getMessage());
+ }
+ } else if (ex instanceof NoSuchMethodException) {
+ err = new NoSuchMethodError(ex.getMessage());
+ } else if (ex instanceof NoSuchFieldException) {
+ err = new NoSuchFieldError(ex.getMessage());
+ } else {
+ err = new IncompatibleClassChangeError();
+ }
+ return initCauseFrom(err, ex);
+ }
/**
* Use best possible cause for err.initCause(), substituting the
* cause for err itself if the cause has the same (or better) type.
- *
- static private Error initCauseFrom(Error err, Exception ex) {
+ */
+ static <E extends Error> E initCauseFrom(E err, Exception ex) {
Throwable th = ex.getCause();
- if (err.getClass().isInstance(th))
- return (Error) th;
+ @SuppressWarnings("unchecked")
+ final Class<E> Eclass = (Class<E>) err.getClass();
+ if (Eclass.isInstance(th))
+ return Eclass.cast(th);
err.initCause(th == null ? ex : th);
return err;
}
+ // END Android-added: Add mapLookupExceptionToError(ex) from OpenJDK 17. http://b/270028670
+ // BEGIN Android-removed: Unused implementation code.
/**
* Is this method a caller-sensitive method?
* I.e., does it call Reflection.getCallerClass or a similer method
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
index 9f68d6c..2e18359 100644
--- a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
+++ b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
@@ -735,6 +735,8 @@
lookupClass.getClassLoader() == Object.class.getClassLoader()) {
if ((name.startsWith("java.")
&& !name.startsWith("java.util.concurrent.")
+ && !name.equals("java.lang.Daemons$FinalizerWatchdogDaemon")
+ && !name.equals("java.lang.runtime.ObjectMethods")
&& !name.equals("java.lang.Thread")) ||
(name.startsWith("sun.")
&& !name.startsWith("sun.invoke.")
@@ -1048,6 +1050,36 @@
return createMethodHandleForConstructor(constructor);
}
+ // BEGIN Android-added: Add findClass(String) from OpenJDK 17. http://b/270028670
+ // TODO: Unhide this method.
+ /**
+ * Looks up a class by name from the lookup context defined by this {@code Lookup} object,
+ * <a href="MethodHandles.Lookup.html#equiv">as if resolved</a> by an {@code ldc} instruction.
+ * Such a resolution, as specified in JVMS 5.4.3.1 section, attempts to locate and load the class,
+ * and then determines whether the class is accessible to this lookup object.
+ * <p>
+ * The lookup context here is determined by the {@linkplain #lookupClass() lookup class},
+ * its class loader, and the {@linkplain #lookupModes() lookup modes}.
+ *
+ * @param targetName the fully qualified name of the class to be looked up.
+ * @return the requested class.
+ * @throws SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws LinkageError if the linkage fails
+ * @throws ClassNotFoundException if the class cannot be loaded by the lookup class' loader.
+ * @throws IllegalAccessException if the class is not accessible, using the allowed access
+ * modes.
+ * @throws NullPointerException if {@code targetName} is null
+ * @since 9
+ * @jvms 5.4.3.1 Class and Interface Resolution
+ * @hide
+ */
+ public Class<?> findClass(String targetName) throws ClassNotFoundException, IllegalAccessException {
+ Class<?> targetClass = Class.forName(targetName, false, lookupClass.getClassLoader());
+ return accessClass(targetClass);
+ }
+ // END Android-added: Add findClass(String) from OpenJDK 17. http://b/270028670
+
private MethodHandle createMethodHandleForConstructor(Constructor constructor) {
Class<?> refc = constructor.getDeclaringClass();
MethodType constructorType =
@@ -1092,6 +1124,135 @@
return MethodType.methodType(void.class, initPtypes);
}
+ // BEGIN Android-added: Add accessClass(Class) from OpenJDK 17. http://b/270028670
+ /*
+ * Returns IllegalAccessException due to access violation to the given targetClass.
+ *
+ * This method is called by {@link Lookup#accessClass} and {@link Lookup#ensureInitialized}
+ * which verifies access to a class rather a member.
+ */
+ private IllegalAccessException makeAccessException(Class<?> targetClass) {
+ String message = "access violation: "+ targetClass;
+ if (this == MethodHandles.publicLookup()) {
+ message += ", from public Lookup";
+ } else {
+ // Android-changed: Remove unsupported module name.
+ // Module m = lookupClass().getModule();
+ // message += ", from " + lookupClass() + " (" + m + ")";
+ message += ", from " + lookupClass();
+ // Android-removed: Remove prevLookupClass until supported by Lookup in OpenJDK 17.
+ // if (prevLookupClass != null) {
+ // message += ", previous lookup " +
+ // prevLookupClass.getName() + " (" + prevLookupClass.getModule() + ")";
+ // }
+ }
+ return new IllegalAccessException(message);
+ }
+
+ // TODO: Unhide this method.
+ /**
+ * Determines if a class can be accessed from the lookup context defined by
+ * this {@code Lookup} object. The static initializer of the class is not run.
+ * If {@code targetClass} is an array class, {@code targetClass} is accessible
+ * if the element type of the array class is accessible. Otherwise,
+ * {@code targetClass} is determined as accessible as follows.
+ *
+ * <p>
+ * If {@code targetClass} is in the same module as the lookup class,
+ * the lookup class is {@code LC} in module {@code M1} and
+ * the previous lookup class is in module {@code M0} or
+ * {@code null} if not present,
+ * {@code targetClass} is accessible if and only if one of the following is true:
+ * <ul>
+ * <li>If this lookup has {@link #PRIVATE} access, {@code targetClass} is
+ * {@code LC} or other class in the same nest of {@code LC}.</li>
+ * <li>If this lookup has {@link #PACKAGE} access, {@code targetClass} is
+ * in the same runtime package of {@code LC}.</li>
+ * <li>If this lookup has {@link #MODULE} access, {@code targetClass} is
+ * a public type in {@code M1}.</li>
+ * <li>If this lookup has {@link #PUBLIC} access, {@code targetClass} is
+ * a public type in a package exported by {@code M1} to at least {@code M0}
+ * if the previous lookup class is present; otherwise, {@code targetClass}
+ * is a public type in a package exported by {@code M1} unconditionally.</li>
+ * </ul>
+ *
+ * <p>
+ * Otherwise, if this lookup has {@link #UNCONDITIONAL} access, this lookup
+ * can access public types in all modules when the type is in a package
+ * that is exported unconditionally.
+ * <p>
+ * Otherwise, {@code targetClass} is in a different module from {@code lookupClass},
+ * and if this lookup does not have {@code PUBLIC} access, {@code lookupClass}
+ * is inaccessible.
+ * <p>
+ * Otherwise, if this lookup has no {@linkplain #previousLookupClass() previous lookup class},
+ * {@code M1} is the module containing {@code lookupClass} and
+ * {@code M2} is the module containing {@code targetClass},
+ * then {@code targetClass} is accessible if and only if
+ * <ul>
+ * <li>{@code M1} reads {@code M2}, and
+ * <li>{@code targetClass} is public and in a package exported by
+ * {@code M2} at least to {@code M1}.
+ * </ul>
+ * <p>
+ * Otherwise, if this lookup has a {@linkplain #previousLookupClass() previous lookup class},
+ * {@code M1} and {@code M2} are as before, and {@code M0} is the module
+ * containing the previous lookup class, then {@code targetClass} is accessible
+ * if and only if one of the following is true:
+ * <ul>
+ * <li>{@code targetClass} is in {@code M0} and {@code M1}
+ * {@linkplain Module#reads reads} {@code M0} and the type is
+ * in a package that is exported to at least {@code M1}.
+ * <li>{@code targetClass} is in {@code M1} and {@code M0}
+ * {@linkplain Module#reads reads} {@code M1} and the type is
+ * in a package that is exported to at least {@code M0}.
+ * <li>{@code targetClass} is in a third module {@code M2} and both {@code M0}
+ * and {@code M1} reads {@code M2} and the type is in a package
+ * that is exported to at least both {@code M0} and {@code M2}.
+ * </ul>
+ * <p>
+ * Otherwise, {@code targetClass} is not accessible.
+ *
+ * @param targetClass the class to be access-checked
+ * @return the class that has been access-checked
+ * @throws IllegalAccessException if the class is not accessible from the lookup class
+ * and previous lookup class, if present, using the allowed access modes.
+ * @throws SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if {@code targetClass} is {@code null}
+ * @since 9
+ * @see <a href="#cross-module-lookup">Cross-module lookups</a>
+ * @hide
+ */
+ public Class<?> accessClass(Class<?> targetClass) throws IllegalAccessException {
+ if (!isClassAccessible(targetClass)) {
+ throw makeAccessException(targetClass);
+ }
+ // Android-removed: SecurityManager is unnecessary on Android.
+ // checkSecurityManager(targetClass);
+ return targetClass;
+ }
+
+ boolean isClassAccessible(Class<?> refc) {
+ Objects.requireNonNull(refc);
+ Class<?> caller = lookupClassOrNull();
+ Class<?> type = refc;
+ while (type.isArray()) {
+ type = type.getComponentType();
+ }
+ // Android-removed: Remove prevLookupClass until supported by Lookup in OpenJDK 17.
+ // return caller == null || VerifyAccess.isClassAccessible(type, caller, prevLookupClass, allowedModes);
+ return caller == null || VerifyAccess.isClassAccessible(type, caller, allowedModes);
+ }
+
+ // This is just for calling out to MethodHandleImpl.
+ private Class<?> lookupClassOrNull() {
+ // Android-changed: Android always returns lookupClass and has no concept of TRUSTED.
+ // return (allowedModes == TRUSTED) ? null : lookupClass;
+ return lookupClass;
+ }
+ // END Android-added: Add accessClass(Class) from OpenJDK 17. http://b/270028670
+
/**
* Produces an early-bound method handle for a virtual method.
* It will bypass checks for overriding methods on the receiver,
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodType.java b/ojluni/src/main/java/java/lang/invoke/MethodType.java
index a1b3a9c..b23b51c 100644
--- a/ojluni/src/main/java/java/lang/invoke/MethodType.java
+++ b/ojluni/src/main/java/java/lang/invoke/MethodType.java
@@ -87,7 +87,9 @@
* @author John Rose, JSR 292 EG
*/
public final
-class MethodType implements java.io.Serializable {
+class MethodType
+ implements TypeDescriptor.OfMethod<Class<?>, MethodType>,
+ java.io.Serializable {
private static final long serialVersionUID = 292L; // {rtype, {ptype...}}
// The rtype and ptypes fields define the structural identity of the method type:
@@ -1163,7 +1165,34 @@
return desc;
}
- /*non-public*/ static String toFieldDescriptorString(Class<?> cls) {
+ // Android-changed: Remove MethodTypeDesc from javadoc until MethodTypeDesc is added.
+ /**
+ * Returns a descriptor string for this method type.
+ *
+ * <p>
+ * If this method type can be <a href="#descriptor">described nominally</a>,
+ * then the result is a method type descriptor (JVMS {@jvms 4.3.3}).
+ * <p>
+ * If this method type cannot be <a href="#descriptor">described nominally</a>
+ * and the result is a string of the form:
+ * <blockquote>{@code "(<parameter-descriptors>)<return-descriptor>"}</blockquote>
+ * where {@code <parameter-descriptors>} is the concatenation of the
+ * {@linkplain Class#descriptorString() descriptor string} of all
+ * of the parameter types and the {@linkplain Class#descriptorString() descriptor string}
+ * of the return type.
+ *
+ * @return the descriptor string for this method type
+ * @since 12
+ * @jvms 4.3.3 Method Descriptors
+ * @see <a href="#descriptor">Nominal Descriptor for {@code MethodType}</a>
+ */
+ @Override
+ public String descriptorString() {
+ return toMethodDescriptorString();
+ }
+
+ /*non-public*/
+ static String toFieldDescriptorString(Class<?> cls) {
return BytecodeDescriptor.unparse(cls);
}
diff --git a/ojluni/src/main/java/java/lang/invoke/TypeDescriptor.java b/ojluni/src/main/java/java/lang/invoke/TypeDescriptor.java
new file mode 100644
index 0000000..24f48d2
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/invoke/TypeDescriptor.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.invoke;
+
+import java.util.List;
+
+/**
+ * An entity that has a type descriptor.
+ *
+ * @since 12
+ */
+public interface TypeDescriptor {
+ /**
+ * Returns the descriptor string for this {@code TypeDescriptor} object.
+ *
+ * If this {@code TypeDescriptor} object can be described in nominal form,
+ * then this method returns a type descriptor as specified in JVMS {@jvms 4.3}.
+ * The result descriptor string can be used to produce
+ * a {@linkplain java.lang.constant.ConstantDesc nominal descriptor}.
+ *
+ * Otherwise, the result string is not a type descriptor.
+ * No {@linkplain java.lang.constant.ConstantDesc nominal descriptor}
+ * can be produced from the result string.
+ *
+ * @return the descriptor string for this {@code TypeDescriptor} object
+ * @jvms 4.3.2 Field Descriptors
+ * @jvms 4.3.3 Method Descriptors
+ */
+ String descriptorString();
+
+
+ // Android-changed: Remove Class#describeConstable from javadoc until MethodType is updated
+ /**
+ * An entity that has a field type descriptor.
+ * Field descriptors conforming to JVMS {@jvms 4.3.2} can be described
+ *
+ * @param <F> the class implementing {@linkplain TypeDescriptor.OfField}
+ * @jvms 4.3.2 Field Descriptors
+ * @since 12
+ */
+ interface OfField<F extends TypeDescriptor.OfField<F>> extends TypeDescriptor {
+ /**
+ * Does this field descriptor describe an array type?
+ * @return whether this field descriptor describes an array type
+ */
+ boolean isArray();
+
+ /**
+ * Does this field descriptor describe a primitive type (including void.)
+ *
+ * @return whether this field descriptor describes a primitive type
+ */
+ boolean isPrimitive();
+
+ /**
+ * If this field descriptor describes an array type, return
+ * a descriptor for its component type, otherwise return {@code null}.
+ * @return the component type, or {@code null} if this field descriptor does
+ * not describe an array type
+ */
+ F componentType();
+
+ /**
+ * Return a descriptor for the array type whose component type is described by this
+ * descriptor
+ * @return the descriptor for the array type
+ */
+ F arrayType();
+ }
+
+
+ // Android-changed: Remove MethodType#describeConstable from javadoc until MethodType is updated
+ /**
+ * An entity that has a method type descriptor
+ * Method descriptors conforming to JVMS {@jvms 4.3.3} can be described
+ *
+ * @param <F> the type representing field type descriptors
+ * @param <M> the class implementing {@linkplain TypeDescriptor.OfMethod}
+ * @jvms 4.3.2 Field Descriptors
+ * @jvms 4.3.3 Method Descriptors
+ * @since 12
+ */
+ interface OfMethod<F extends TypeDescriptor.OfField<F>, M extends TypeDescriptor.OfMethod<F, M>>
+ extends TypeDescriptor {
+
+ /**
+ * Return the number of parameters in the method type
+ * @return the number of parameters
+ */
+ int parameterCount();
+
+ /**
+ * Return a field descriptor describing the requested parameter of the method type
+ * described by this descriptor
+ * @param i the index of the parameter
+ * @return a field descriptor for the requested parameter type
+ * @throws IndexOutOfBoundsException if the index is outside the half-open
+ * range {[0, parameterCount)}
+ */
+ F parameterType(int i);
+
+ /**
+ * Return a field descriptor describing the return type of the method type described
+ * by this descriptor
+ * @return a field descriptor for the return type
+ */
+ F returnType();
+
+ /**
+ * Return an array of field descriptors for the parameter types of the method type
+ * described by this descriptor
+ * @return field descriptors for the parameter types
+ */
+ F[] parameterArray();
+
+ /**
+ * Return an immutable list of field descriptors for the parameter types of the method type
+ * described by this descriptor
+ * @return field descriptors for the parameter types
+ */
+ List<F> parameterList();
+
+ /**
+ * Return a method descriptor that is identical to this one, except that the return
+ * type has been changed to the specified type
+ *
+ * @param newReturn a field descriptor for the new return type
+ * @throws NullPointerException if any argument is {@code null}
+ * @return the new method descriptor
+ */
+ M changeReturnType(F newReturn);
+
+ /**
+ * Return a method descriptor that is identical to this one,
+ * except that a single parameter type has been changed to the specified type.
+ *
+ * @param index the index of the parameter to change
+ * @param paramType a field descriptor describing the new parameter type
+ * @return the new method descriptor
+ * @throws NullPointerException if any argument is {@code null}
+ * @throws IndexOutOfBoundsException if the index is outside the half-open
+ * range {[0, parameterCount)}
+ */
+ M changeParameterType(int index, F paramType);
+
+ /**
+ * Return a method descriptor that is identical to this one,
+ * except that a range of parameter types have been removed.
+ *
+ * @param start the index of the first parameter to remove
+ * @param end the index after the last parameter to remove
+ * @return the new method descriptor
+ *
+ * @throws IndexOutOfBoundsException if {@code start} is outside the half-open
+ * range {@code [0, parameterCount)}, or {@code end} is outside the closed range
+ * {@code [0, parameterCount]}, or if {@code start > end}
+ */
+ M dropParameterTypes(int start, int end);
+
+ /**
+ * Return a method descriptor that is identical to this one,
+ * except that a range of additional parameter types have been inserted.
+ *
+ * @param pos the index at which to insert the first inserted parameter
+ * @param paramTypes field descriptors describing the new parameter types
+ * to insert
+ * @return the new method descriptor
+ * @throws NullPointerException if any argument is {@code null}
+ * @throws IndexOutOfBoundsException if {@code pos} is outside the closed
+ * range {[0, parameterCount]}
+ */
+ @SuppressWarnings("unchecked")
+ M insertParameterTypes(int pos, F... paramTypes);
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/invoke/VarHandle.java b/ojluni/src/main/java/java/lang/invoke/VarHandle.java
index 219729c..e11d617 100644
--- a/ojluni/src/main/java/java/lang/invoke/VarHandle.java
+++ b/ojluni/src/main/java/java/lang/invoke/VarHandle.java
@@ -27,6 +27,12 @@
import dalvik.system.VMRuntime;
import jdk.internal.vm.annotation.IntrinsicCandidate;
+import java.lang.constant.ClassDesc;
+import java.lang.constant.Constable;
+import java.lang.constant.ConstantDesc;
+import java.lang.constant.ConstantDescs;
+import java.lang.constant.DirectMethodHandleDesc;
+import java.lang.constant.DynamicConstantDesc;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
@@ -2349,4 +2355,161 @@
return bitMask;
}
// END Android-added: helper state for VarHandle properties.
+
+ // BEGIN Android-added: Add VarHandleDesc from OpenJDK 17. http://b/270028670
+ /**
+ * A <a href="{@docRoot}/java.base/java/lang/constant/package-summary.html#nominal">nominal descriptor</a> for a
+ * {@link VarHandle} constant.
+ *
+ * @since 12
+ * @hide
+ */
+ public static final class VarHandleDesc extends DynamicConstantDesc<VarHandle> {
+
+ /**
+ * Kinds of variable handle descs
+ */
+ private enum Kind {
+ FIELD(ConstantDescs.BSM_VARHANDLE_FIELD),
+ STATIC_FIELD(ConstantDescs.BSM_VARHANDLE_STATIC_FIELD),
+ ARRAY(ConstantDescs.BSM_VARHANDLE_ARRAY);
+
+ final DirectMethodHandleDesc bootstrapMethod;
+
+ Kind(DirectMethodHandleDesc bootstrapMethod) {
+ this.bootstrapMethod = bootstrapMethod;
+ }
+
+ ConstantDesc[] toBSMArgs(ClassDesc declaringClass, ClassDesc varType) {
+ return switch (this) {
+ case FIELD, STATIC_FIELD -> new ConstantDesc[]{declaringClass, varType};
+ case ARRAY -> new ConstantDesc[]{declaringClass};
+ default -> throw new InternalError("Cannot reach here");
+ };
+ }
+ }
+
+ private final Kind kind;
+ private final ClassDesc declaringClass;
+ private final ClassDesc varType;
+
+ /**
+ * Construct a {@linkplain VarHandleDesc} given a kind, name, and declaring
+ * class.
+ *
+ * @param kind the kind of the var handle
+ * @param name the unqualified name of the field, for field var handles; otherwise ignored
+ * @param declaringClass a {@link ClassDesc} describing the declaring class,
+ * for field var handles
+ * @param varType a {@link ClassDesc} describing the type of the variable
+ * @throws NullPointerException if any required argument is null
+ * @jvms 4.2.2 Unqualified Names
+ */
+ private VarHandleDesc(Kind kind, String name, ClassDesc declaringClass, ClassDesc varType) {
+ super(kind.bootstrapMethod, name,
+ ConstantDescs.CD_VarHandle,
+ kind.toBSMArgs(declaringClass, varType));
+ this.kind = kind;
+ this.declaringClass = declaringClass;
+ this.varType = varType;
+ }
+
+ /**
+ * Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
+ * for an instance field.
+ *
+ * @param name the unqualified name of the field
+ * @param declaringClass a {@link ClassDesc} describing the declaring class,
+ * for field var handles
+ * @param fieldType a {@link ClassDesc} describing the type of the field
+ * @return the {@linkplain VarHandleDesc}
+ * @throws NullPointerException if any of the arguments are null
+ * @jvms 4.2.2 Unqualified Names
+ */
+ public static VarHandleDesc ofField(ClassDesc declaringClass, String name, ClassDesc fieldType) {
+ Objects.requireNonNull(declaringClass);
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(fieldType);
+ return new VarHandleDesc(Kind.FIELD, name, declaringClass, fieldType);
+ }
+
+ /**
+ * Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
+ * for a static field.
+ *
+ * @param name the unqualified name of the field
+ * @param declaringClass a {@link ClassDesc} describing the declaring class,
+ * for field var handles
+ * @param fieldType a {@link ClassDesc} describing the type of the field
+ * @return the {@linkplain VarHandleDesc}
+ * @throws NullPointerException if any of the arguments are null
+ * @jvms 4.2.2 Unqualified Names
+ */
+ public static VarHandleDesc ofStaticField(ClassDesc declaringClass, String name, ClassDesc fieldType) {
+ Objects.requireNonNull(declaringClass);
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(fieldType);
+ return new VarHandleDesc(Kind.STATIC_FIELD, name, declaringClass, fieldType);
+ }
+
+ /**
+ * Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
+ * for an array type.
+ *
+ * @param arrayClass a {@link ClassDesc} describing the type of the array
+ * @return the {@linkplain VarHandleDesc}
+ * @throws NullPointerException if any of the arguments are null
+ */
+ public static VarHandleDesc ofArray(ClassDesc arrayClass) {
+ Objects.requireNonNull(arrayClass);
+ if (!arrayClass.isArray())
+ throw new IllegalArgumentException("Array class argument not an array: " + arrayClass);
+ return new VarHandleDesc(Kind.ARRAY, ConstantDescs.DEFAULT_NAME, arrayClass, arrayClass.componentType());
+ }
+
+ /**
+ * Returns a {@link ClassDesc} describing the type of the variable described
+ * by this descriptor.
+ *
+ * @return the variable type
+ */
+ public ClassDesc varType() {
+ return varType;
+ }
+
+ @Override
+ public VarHandle resolveConstantDesc(MethodHandles.Lookup lookup)
+ throws ReflectiveOperationException {
+ return switch (kind) {
+ case FIELD -> lookup.findVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup),
+ constantName(),
+ (Class<?>) varType.resolveConstantDesc(lookup));
+ case STATIC_FIELD -> lookup.findStaticVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup),
+ constantName(),
+ (Class<?>) varType.resolveConstantDesc(lookup));
+ case ARRAY -> MethodHandles.arrayElementVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup));
+ default -> throw new InternalError("Cannot reach here");
+ };
+ }
+
+ /**
+ * Returns a compact textual description of this constant description.
+ * For a field {@linkplain VarHandle}, includes the owner, name, and type
+ * of the field, and whether it is static; for an array {@linkplain VarHandle},
+ * the name of the component type.
+ *
+ * @return A compact textual description of this descriptor
+ */
+ @Override
+ public String toString() {
+ return switch (kind) {
+ case FIELD, STATIC_FIELD -> String.format("VarHandleDesc[%s%s.%s:%s]",
+ (kind == Kind.STATIC_FIELD) ? "static " : "",
+ declaringClass.displayName(), constantName(), varType.displayName());
+ case ARRAY -> String.format("VarHandleDesc[%s[]]", declaringClass.displayName());
+ default -> throw new InternalError("Cannot reach here");
+ };
+ }
+ }
+ // END Android-added: Add VarHandleDesc from OpenJDK 17. http://b/270028670
}
diff --git a/ojluni/src/main/java/java/lang/ref/Cleaner.java b/ojluni/src/main/java/java/lang/ref/Cleaner.java
index 04e2101..1377360 100644
--- a/ojluni/src/main/java/java/lang/ref/Cleaner.java
+++ b/ojluni/src/main/java/java/lang/ref/Cleaner.java
@@ -31,6 +31,7 @@
import java.util.concurrent.ThreadFactory;
import java.util.function.Function;
+// Android-changed: Use the shared SystemCleaner instance on Android.
/**
* {@code Cleaner} manages a set of object references and corresponding cleaning actions.
* <p>
@@ -86,8 +87,8 @@
* by the Cleaner when the CleaningExample instance has become phantom reachable.
* <pre>{@code
* public class CleaningExample implements AutoCloseable {
- * // A cleaner, preferably one shared within a library
- * private static final Cleaner cleaner = <cleaner>;
+ * // Use the shared android.system.SystemCleaner instance on Android.
+ * private static final Cleaner cleaner = SystemCleaner.cleaner();
*
* static class State implements Runnable {
*
@@ -151,6 +152,10 @@
impl = new CleanerImpl();
}
+ private Cleaner(ReferenceQueue queue) {
+ impl = new CleanerImpl(queue);
+ }
+
/**
* Returns a new {@code Cleaner}.
* <p>
@@ -204,6 +209,18 @@
return cleaner;
}
+ // Android-added: objects registered in the system cleaner are cleaned
+ // by the finalizer daemon thread, not in a InnocuousThread.
+ /**
+ * Returns a new {@code Cleaner} associated with the finalizer thread.
+ * @hide
+ */
+ public static Cleaner createSystemCleaner() {
+ Cleaner cleaner = new Cleaner(FinalizerReference.queue);
+ cleaner.impl.start(cleaner);
+ return cleaner;
+ }
+
/**
* Registers an object and a cleaning action to run when the object
* becomes phantom reachable.
diff --git a/ojluni/src/main/java/java/lang/reflect/Field.java b/ojluni/src/main/java/java/lang/reflect/Field.java
index ca5857a..1bea47f 100644
--- a/ojluni/src/main/java/java/lang/reflect/Field.java
+++ b/ojluni/src/main/java/java/lang/reflect/Field.java
@@ -188,7 +188,7 @@
}
// BEGIN Android-added: getGenericType() implemented differently.
- private String getSignatureAttribute() {
+ String getSignatureAttribute() {
String[] annotation = getSignatureAnnotation();
if (annotation == null) {
return null;
diff --git a/ojluni/src/main/java/java/lang/reflect/RecordComponent.java b/ojluni/src/main/java/java/lang/reflect/RecordComponent.java
new file mode 100644
index 0000000..5d19c42
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/reflect/RecordComponent.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+import libcore.util.EmptyArray;
+
+import java.lang.annotation.Annotation;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A {@code RecordComponent} provides information about, and dynamic access to, a
+ * component of a record class.
+ *
+ * @see Class#getRecordComponents()
+ * @see java.lang.Record
+ * @jls 8.10 Record Classes
+ * @since 16
+ */
+public final class RecordComponent implements AnnotatedElement {
+ // declaring class
+ private Class<?> clazz;
+ private String name;
+ private Class<?> type;
+ private Method accessor;
+ // generic info repository; lazily initialized
+ // Android-remove: Remove unused fields.
+ // private String signature;
+ // private transient FieldRepository genericInfo;
+ // private byte[] annotations;
+ // private byte[] typeAnnotations;
+ // private RecordComponent root;
+
+ // Android-added: field for annotations
+ private Field field;
+
+ // only the JVM can create record components
+ private RecordComponent() {}
+
+ // Android-added: Constructor used by libcore.
+ /**
+ * @hide
+ */
+ public RecordComponent(Class<?> clazz, String name, Class<?> type, Method accessor,
+ Field field) {
+ this.clazz = clazz;
+ this.name = name;
+ this.type = type;
+ this.accessor = accessor;
+ this.field = field;
+ }
+
+ /**
+ * Returns the name of this record component.
+ *
+ * @return the name of this record component
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns a {@code Class} that identifies the declared type for this
+ * record component.
+ *
+ * @return a {@code Class} identifying the declared type of the component
+ * represented by this record component
+ */
+ public Class<?> getType() {
+ return type;
+ }
+
+ /**
+ * Returns a {@code String} that describes the generic type signature for
+ * this record component.
+ *
+ * @return a {@code String} that describes the generic type signature for
+ * this record component
+ *
+ * @jvms 4.7.9.1 Signatures
+ */
+ public String getGenericSignature() {
+ // Android-changed: Re-implement on top of ART.
+ // return signature;
+ return field.getSignatureAttribute();
+ }
+
+ /**
+ * Returns a {@code Type} object that represents the declared type for
+ * this record component.
+ *
+ * <p>If the declared type of the record component is a parameterized type,
+ * the {@code Type} object returned reflects the actual type arguments used
+ * in the source code.
+ *
+ * <p>If the type of the underlying record component is a type variable or a
+ * parameterized type, it is created. Otherwise, it is resolved.
+ *
+ * @return a {@code Type} object that represents the declared type for
+ * this record component
+ * @throws GenericSignatureFormatError if the generic record component
+ * signature does not conform to the format specified in
+ * <cite>The Java Virtual Machine Specification</cite>
+ * @throws TypeNotPresentException if the generic type
+ * signature of the underlying record component refers to a non-existent
+ * type declaration
+ * @throws MalformedParameterizedTypeException if the generic
+ * signature of the underlying record component refers to a parameterized
+ * type that cannot be instantiated for any reason
+ */
+ public Type getGenericType() {
+ // Android-changed: Re-implement on top of ART.
+ /*
+ if (getGenericSignature() != null)
+ return getGenericInfo().getGenericType();
+ else
+ return getType();
+ */
+ return field.getGenericType();
+ }
+
+ // BEGIN Android-removed: Unused code on ART.
+ /*
+ // Accessor for generic info repository
+ private FieldRepository getGenericInfo() {
+ // lazily initialize repository if necessary
+ if (genericInfo == null) {
+ // create and cache generic info repository
+ genericInfo = FieldRepository.make(getGenericSignature(), getFactory());
+ }
+ return genericInfo; //return cached repository
+ }
+
+ // Accessor for factory
+ private GenericsFactory getFactory() {
+ Class<?> c = getDeclaringRecord();
+ // create scope and factory
+ return CoreReflectionFactory.make(c, ClassScope.make(c));
+ }
+ */
+ // END Android-removed: Unused code on ART.
+
+ // BEGIN Android-removed: Annotated type isn't supported on Android.
+ /*
+ * Returns an {@code AnnotatedType} object that represents the use of a type to specify
+ * the declared type of this record component.
+ *
+ * @return an object representing the declared type of this record component
+ *//*
+ public AnnotatedType getAnnotatedType() {
+ return TypeAnnotationParser.buildAnnotatedType(typeAnnotations,
+ SharedSecrets.getJavaLangAccess().
+ getConstantPool(getDeclaringRecord()),
+ this,
+ getDeclaringRecord(),
+ getGenericType(),
+ TypeAnnotation.TypeAnnotationTarget.FIELD);
+ }
+ */
+ // END Android-removed: Annotated type isn't supported on Android.
+
+ /**
+ * Returns a {@code Method} that represents the accessor for this record
+ * component.
+ *
+ * @return a {@code Method} that represents the accessor for this record
+ * component
+ */
+ public Method getAccessor() {
+ return accessor;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>Note that any annotation returned by this method is a
+ * declaration annotation.
+ * @throws NullPointerException {@inheritDoc}
+ */
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+ Objects.requireNonNull(annotationClass);
+ return annotationClass.cast(declaredAnnotations().get(annotationClass));
+ }
+
+ private transient volatile Map<Class<? extends Annotation>, Annotation> declaredAnnotations;
+
+ private Map<Class<? extends Annotation>, Annotation> declaredAnnotations() {
+ Map<Class<? extends Annotation>, Annotation> declAnnos;
+ if ((declAnnos = declaredAnnotations) == null) {
+ synchronized (this) {
+ if ((declAnnos = declaredAnnotations) == null) {
+ // Android-changed: Re-implement on top of ART.
+ /*
+ RecordComponent root = this.root;
+ if (root != null) {
+ declAnnos = root.declaredAnnotations();
+ } else {
+ declAnnos = AnnotationParser.parseAnnotations(
+ annotations,
+ SharedSecrets.getJavaLangAccess()
+ .getConstantPool(getDeclaringRecord()),
+ getDeclaringRecord());
+ }
+ */
+ Annotation[] annotations = field.getDeclaredAnnotations();
+ declAnnos = new HashMap<>(annotations.length);
+ for (Annotation a : annotations) {
+ declAnnos.put(a.annotationType(), a);
+ }
+ declaredAnnotations = declAnnos;
+ }
+ }
+ }
+ return declAnnos;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>Note that any annotations returned by this method are
+ * declaration annotations.
+ */
+ @Override
+ public Annotation[] getAnnotations() {
+ return getDeclaredAnnotations();
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>Note that any annotations returned by this method are
+ * declaration annotations.
+ */
+ @Override
+ public Annotation[] getDeclaredAnnotations() {
+ // Android-changed: Re-implement on top of ART.
+ // return AnnotationParser.toArray(declaredAnnotations());
+ return declaredAnnotations().values().toArray(EmptyArray.ANNOTATION);
+ }
+
+ /**
+ * Returns a string describing this record component. The format is
+ * the record component type, followed by a space, followed by the name
+ * of the record component.
+ * For example:
+ * <pre>
+ * java.lang.String name
+ * int age
+ * </pre>
+ *
+ * @return a string describing this record component
+ */
+ public String toString() {
+ return (getType().getTypeName() + " " + getName());
+ }
+
+ /**
+ * Returns the record class which declares this record component.
+ *
+ * @return The record class declaring this record component.
+ */
+ public Class<?> getDeclaringRecord() {
+ return clazz;
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/runtime/ObjectMethods.java b/ojluni/src/main/java/java/lang/runtime/ObjectMethods.java
new file mode 100644
index 0000000..baad8fa
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/runtime/ObjectMethods.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.runtime;
+
+import java.lang.invoke.ConstantCallSite;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.TypeDescriptor;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Bootstrap methods for state-driven implementations of core methods,
+ * including {@link Object#equals(Object)}, {@link Object#hashCode()}, and
+ * {@link Object#toString()}. These methods may be used, for example, by
+ * Java compiler implementations to implement the bodies of {@link Object}
+ * methods for record classes.
+ *
+ * @since 16
+ */
+public class ObjectMethods {
+
+ private ObjectMethods() { }
+
+ private static final MethodType DESCRIPTOR_MT = MethodType.methodType(MethodType.class);
+ private static final MethodType NAMES_MT = MethodType.methodType(List.class);
+ private static final MethodHandle FALSE = MethodHandles.constant(boolean.class, false);
+ private static final MethodHandle TRUE = MethodHandles.constant(boolean.class, true);
+ private static final MethodHandle ZERO = MethodHandles.constant(int.class, 0);
+ private static final MethodHandle CLASS_IS_INSTANCE;
+ private static final MethodHandle OBJECT_EQUALS;
+ private static final MethodHandle OBJECTS_EQUALS;
+ private static final MethodHandle OBJECTS_HASHCODE;
+ private static final MethodHandle OBJECTS_TOSTRING;
+ private static final MethodHandle OBJECT_EQ;
+ private static final MethodHandle OBJECT_HASHCODE;
+ private static final MethodHandle OBJECT_TO_STRING;
+ private static final MethodHandle STRING_FORMAT;
+ private static final MethodHandle HASH_COMBINER;
+
+ private static final HashMap<Class<?>, MethodHandle> primitiveEquals = new HashMap<>();
+ private static final HashMap<Class<?>, MethodHandle> primitiveHashers = new HashMap<>();
+ private static final HashMap<Class<?>, MethodHandle> primitiveToString = new HashMap<>();
+
+ static {
+ try {
+ Class<ObjectMethods> OBJECT_METHODS_CLASS = ObjectMethods.class;
+ MethodHandles.Lookup publicLookup = MethodHandles.publicLookup();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ // Android-changed: Use the "normal" class loader
+ /*
+ @SuppressWarnings("removal")
+ ClassLoader loader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ @Override public ClassLoader run() { return ClassLoader.getPlatformClassLoader(); }
+ });
+ */
+ ClassLoader loader = ObjectMethods.class.getClassLoader();
+
+ CLASS_IS_INSTANCE = publicLookup.findVirtual(Class.class, "isInstance",
+ MethodType.methodType(boolean.class, Object.class));
+ OBJECT_EQUALS = publicLookup.findVirtual(Object.class, "equals",
+ MethodType.methodType(boolean.class, Object.class));
+ OBJECT_HASHCODE = publicLookup.findVirtual(Object.class, "hashCode",
+ MethodType.fromMethodDescriptorString("()I", loader));
+ OBJECT_TO_STRING = publicLookup.findVirtual(Object.class, "toString",
+ MethodType.methodType(String.class));
+ STRING_FORMAT = publicLookup.findStatic(String.class, "format",
+ MethodType.methodType(String.class, String.class, Object[].class));
+ OBJECTS_EQUALS = publicLookup.findStatic(Objects.class, "equals",
+ MethodType.methodType(boolean.class, Object.class, Object.class));
+ OBJECTS_HASHCODE = publicLookup.findStatic(Objects.class, "hashCode",
+ MethodType.methodType(int.class, Object.class));
+ OBJECTS_TOSTRING = publicLookup.findStatic(Objects.class, "toString",
+ MethodType.methodType(String.class, Object.class));
+
+ OBJECT_EQ = lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
+ MethodType.methodType(boolean.class, Object.class, Object.class));
+ HASH_COMBINER = lookup.findStatic(OBJECT_METHODS_CLASS, "hashCombiner",
+ MethodType.fromMethodDescriptorString("(II)I", loader));
+
+ primitiveEquals.put(byte.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
+ MethodType.fromMethodDescriptorString("(BB)Z", loader)));
+ primitiveEquals.put(short.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
+ MethodType.fromMethodDescriptorString("(SS)Z", loader)));
+ primitiveEquals.put(char.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
+ MethodType.fromMethodDescriptorString("(CC)Z", loader)));
+ primitiveEquals.put(int.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
+ MethodType.fromMethodDescriptorString("(II)Z", loader)));
+ primitiveEquals.put(long.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
+ MethodType.fromMethodDescriptorString("(JJ)Z", loader)));
+ primitiveEquals.put(float.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
+ MethodType.fromMethodDescriptorString("(FF)Z", loader)));
+ primitiveEquals.put(double.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
+ MethodType.fromMethodDescriptorString("(DD)Z", loader)));
+ primitiveEquals.put(boolean.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
+ MethodType.fromMethodDescriptorString("(ZZ)Z", loader)));
+
+ primitiveHashers.put(byte.class, lookup.findStatic(Byte.class, "hashCode",
+ MethodType.fromMethodDescriptorString("(B)I", loader)));
+ primitiveHashers.put(short.class, lookup.findStatic(Short.class, "hashCode",
+ MethodType.fromMethodDescriptorString("(S)I", loader)));
+ primitiveHashers.put(char.class, lookup.findStatic(Character.class, "hashCode",
+ MethodType.fromMethodDescriptorString("(C)I", loader)));
+ primitiveHashers.put(int.class, lookup.findStatic(Integer.class, "hashCode",
+ MethodType.fromMethodDescriptorString("(I)I", loader)));
+ primitiveHashers.put(long.class, lookup.findStatic(Long.class, "hashCode",
+ MethodType.fromMethodDescriptorString("(J)I", loader)));
+ primitiveHashers.put(float.class, lookup.findStatic(Float.class, "hashCode",
+ MethodType.fromMethodDescriptorString("(F)I", loader)));
+ primitiveHashers.put(double.class, lookup.findStatic(Double.class, "hashCode",
+ MethodType.fromMethodDescriptorString("(D)I", loader)));
+ primitiveHashers.put(boolean.class, lookup.findStatic(Boolean.class, "hashCode",
+ MethodType.fromMethodDescriptorString("(Z)I", loader)));
+
+ primitiveToString.put(byte.class, lookup.findStatic(Byte.class, "toString",
+ MethodType.methodType(String.class, byte.class)));
+ primitiveToString.put(short.class, lookup.findStatic(Short.class, "toString",
+ MethodType.methodType(String.class, short.class)));
+ primitiveToString.put(char.class, lookup.findStatic(Character.class, "toString",
+ MethodType.methodType(String.class, char.class)));
+ primitiveToString.put(int.class, lookup.findStatic(Integer.class, "toString",
+ MethodType.methodType(String.class, int.class)));
+ primitiveToString.put(long.class, lookup.findStatic(Long.class, "toString",
+ MethodType.methodType(String.class, long.class)));
+ primitiveToString.put(float.class, lookup.findStatic(Float.class, "toString",
+ MethodType.methodType(String.class, float.class)));
+ primitiveToString.put(double.class, lookup.findStatic(Double.class, "toString",
+ MethodType.methodType(String.class, double.class)));
+ primitiveToString.put(boolean.class, lookup.findStatic(Boolean.class, "toString",
+ MethodType.methodType(String.class, boolean.class)));
+ }
+ catch (ReflectiveOperationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static int hashCombiner(int x, int y) {
+ return x*31 + y;
+ }
+
+ private static boolean eq(Object a, Object b) { return a == b; }
+ private static boolean eq(byte a, byte b) { return a == b; }
+ private static boolean eq(short a, short b) { return a == b; }
+ private static boolean eq(char a, char b) { return a == b; }
+ private static boolean eq(int a, int b) { return a == b; }
+ private static boolean eq(long a, long b) { return a == b; }
+ private static boolean eq(float a, float b) { return Float.compare(a, b) == 0; }
+ private static boolean eq(double a, double b) { return Double.compare(a, b) == 0; }
+ private static boolean eq(boolean a, boolean b) { return a == b; }
+
+ /** Get the method handle for combining two values of a given type */
+ private static MethodHandle equalator(Class<?> clazz) {
+ return (clazz.isPrimitive()
+ ? primitiveEquals.get(clazz)
+ : OBJECTS_EQUALS.asType(MethodType.methodType(boolean.class, clazz, clazz)));
+ }
+
+ /** Get the hasher for a value of a given type */
+ private static MethodHandle hasher(Class<?> clazz) {
+ return (clazz.isPrimitive()
+ ? primitiveHashers.get(clazz)
+ : OBJECTS_HASHCODE.asType(MethodType.methodType(int.class, clazz)));
+ }
+
+ /** Get the stringifier for a value of a given type */
+ private static MethodHandle stringifier(Class<?> clazz) {
+ return (clazz.isPrimitive()
+ ? primitiveToString.get(clazz)
+ : OBJECTS_TOSTRING.asType(MethodType.methodType(String.class, clazz)));
+ }
+
+ /**
+ * Generates a method handle for the {@code equals} method for a given data class
+ * @param receiverClass the data class
+ * @param getters the list of getters
+ * @return the method handle
+ */
+ private static MethodHandle makeEquals(Class<?> receiverClass,
+ List<MethodHandle> getters) {
+ MethodType rr = MethodType.methodType(boolean.class, receiverClass, receiverClass);
+ MethodType ro = MethodType.methodType(boolean.class, receiverClass, Object.class);
+ MethodHandle instanceFalse = MethodHandles.dropArguments(FALSE, 0, receiverClass, Object.class); // (RO)Z
+ MethodHandle instanceTrue = MethodHandles.dropArguments(TRUE, 0, receiverClass, Object.class); // (RO)Z
+ MethodHandle isSameObject = OBJECT_EQ.asType(ro); // (RO)Z
+ MethodHandle isInstance = MethodHandles.dropArguments(CLASS_IS_INSTANCE.bindTo(receiverClass), 0, receiverClass); // (RO)Z
+ MethodHandle accumulator = MethodHandles.dropArguments(TRUE, 0, receiverClass, receiverClass); // (RR)Z
+
+ for (MethodHandle getter : getters) {
+ MethodHandle equalator = equalator(getter.type().returnType()); // (TT)Z
+ MethodHandle thisFieldEqual = MethodHandles.filterArguments(equalator, 0, getter, getter); // (RR)Z
+ accumulator = MethodHandles.guardWithTest(thisFieldEqual, accumulator, instanceFalse.asType(rr));
+ }
+
+ return MethodHandles.guardWithTest(isSameObject,
+ instanceTrue,
+ MethodHandles.guardWithTest(isInstance, accumulator.asType(ro), instanceFalse));
+ }
+
+ /**
+ * Generates a method handle for the {@code hashCode} method for a given data class
+ * @param receiverClass the data class
+ * @param getters the list of getters
+ * @return the method handle
+ */
+ private static MethodHandle makeHashCode(Class<?> receiverClass,
+ List<MethodHandle> getters) {
+ MethodHandle accumulator = MethodHandles.dropArguments(ZERO, 0, receiverClass); // (R)I
+
+ // @@@ Use loop combinator instead?
+ for (MethodHandle getter : getters) {
+ MethodHandle hasher = hasher(getter.type().returnType()); // (T)I
+ MethodHandle hashThisField = MethodHandles.filterArguments(hasher, 0, getter); // (R)I
+ MethodHandle combineHashes = MethodHandles.filterArguments(HASH_COMBINER, 0, accumulator, hashThisField); // (RR)I
+ accumulator = MethodHandles.permuteArguments(combineHashes, accumulator.type(), 0, 0); // adapt (R)I to (RR)I
+ }
+
+ return accumulator;
+ }
+
+ /**
+ * Generates a method handle for the {@code toString} method for a given data class
+ * @param receiverClass the data class
+ * @param getters the list of getters
+ * @param names the names
+ * @return the method handle
+ */
+ private static MethodHandle makeToString(Class<?> receiverClass,
+ List<MethodHandle> getters,
+ List<String> names) {
+ // This is a pretty lousy algorithm; we spread the receiver over N places,
+ // apply the N getters, apply N toString operations, and concat the result with String.format
+ // Better to use String.format directly, or delegate to StringConcatFactory
+ // Also probably want some quoting around String components
+
+ assert getters.size() == names.size();
+
+ int[] invArgs = new int[getters.size()];
+ Arrays.fill(invArgs, 0);
+ MethodHandle[] filters = new MethodHandle[getters.size()];
+ StringBuilder sb = new StringBuilder();
+ sb.append(receiverClass.getSimpleName()).append("[");
+ for (int i=0; i<getters.size(); i++) {
+ MethodHandle getter = getters.get(i); // (R)T
+ MethodHandle stringify = stringifier(getter.type().returnType()); // (T)String
+ MethodHandle stringifyThisField = MethodHandles.filterArguments(stringify, 0, getter); // (R)String
+ filters[i] = stringifyThisField;
+ sb.append(names.get(i)).append("=%s");
+ if (i != getters.size() - 1)
+ sb.append(", ");
+ }
+ sb.append(']');
+ String formatString = sb.toString();
+ MethodHandle formatter = MethodHandles.insertArguments(STRING_FORMAT, 0, formatString)
+ .asCollector(String[].class, getters.size()); // (R*)String
+ if (getters.size() == 0) {
+ // Add back extra R
+ formatter = MethodHandles.dropArguments(formatter, 0, receiverClass);
+ }
+ else {
+ MethodHandle filtered = MethodHandles.filterArguments(formatter, 0, filters);
+ formatter = MethodHandles.permuteArguments(filtered, MethodType.methodType(String.class, receiverClass), invArgs);
+ }
+
+ return formatter;
+ }
+
+ /**
+ * Bootstrap method to generate the {@link Object#equals(Object)},
+ * {@link Object#hashCode()}, and {@link Object#toString()} methods, based
+ * on a description of the component names and accessor methods, for either
+ * {@code invokedynamic} call sites or dynamic constant pool entries.
+ *
+ * For more detail on the semantics of the generated methods see the specification
+ * of {@link java.lang.Record#equals(Object)}, {@link java.lang.Record#hashCode()} and
+ * {@link java.lang.Record#toString()}.
+ *
+ *
+ * @param lookup Every bootstrap method is expected to have a {@code lookup}
+ * which usually represents a lookup context with the
+ * accessibility privileges of the caller. This is because
+ * {@code invokedynamic} call sites always provide a {@code lookup}
+ * to the corresponding bootstrap method, but this method just
+ * ignores the {@code lookup} parameter
+ * @param methodName the name of the method to generate, which must be one of
+ * {@code "equals"}, {@code "hashCode"}, or {@code "toString"}
+ * @param type a {@link MethodType} corresponding the descriptor type
+ * for the method, which must correspond to the descriptor
+ * for the corresponding {@link Object} method, if linking
+ * an {@code invokedynamic} call site, or the
+ * constant {@code MethodHandle.class}, if linking a
+ * dynamic constant
+ * @param recordClass the record class hosting the record components
+ * @param names the list of component names, joined into a string
+ * separated by ";", or the empty string if there are no
+ * components. Maybe be null, if the {@code methodName}
+ * is {@code "equals"} or {@code "hashCode"}.
+ * @param getters method handles for the accessor methods for the components
+ * @return a call site if invoked by indy, or a method handle
+ * if invoked by a condy
+ * @throws IllegalArgumentException if the bootstrap arguments are invalid
+ * or inconsistent
+ * @throws Throwable if any exception is thrown during call site construction
+ */
+ public static Object bootstrap(MethodHandles.Lookup lookup, String methodName, TypeDescriptor type,
+ Class<?> recordClass,
+ String names,
+ MethodHandle... getters) throws Throwable {
+ MethodType methodType;
+ if (type instanceof MethodType)
+ methodType = (MethodType) type;
+ else {
+ methodType = null;
+ if (!MethodHandle.class.equals(type))
+ throw new IllegalArgumentException(type.toString());
+ }
+ List<MethodHandle> getterList = List.of(getters);
+ MethodHandle handle = switch (methodName) {
+ case "equals" -> {
+ if (methodType != null && !methodType.equals(MethodType.methodType(boolean.class, recordClass, Object.class)))
+ throw new IllegalArgumentException("Bad method type: " + methodType);
+ yield makeEquals(recordClass, getterList);
+ }
+ case "hashCode" -> {
+ if (methodType != null && !methodType.equals(MethodType.methodType(int.class, recordClass)))
+ throw new IllegalArgumentException("Bad method type: " + methodType);
+ yield makeHashCode(recordClass, getterList);
+ }
+ case "toString" -> {
+ if (methodType != null && !methodType.equals(MethodType.methodType(String.class, recordClass)))
+ throw new IllegalArgumentException("Bad method type: " + methodType);
+ List<String> nameList = "".equals(names) ? List.of() : List.of(names.split(";"));
+ if (nameList.size() != getterList.size())
+ throw new IllegalArgumentException("Name list and accessor list do not match");
+ yield makeToString(recordClass, getterList, nameList);
+ }
+ default -> throw new IllegalArgumentException(methodName);
+ };
+ return methodType != null ? new ConstantCallSite(handle) : handle;
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/runtime/package-info.java b/ojluni/src/main/java/java/lang/runtime/package-info.java
new file mode 100644
index 0000000..9e19ef9
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/runtime/package-info.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019, 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.
+ */
+
+/**
+ * The {@code java.lang.runtime} package provides low-level runtime support
+ * for the Java language.
+ *
+ * @since 14
+ */
+
+package java.lang.runtime;
diff --git a/ojluni/src/main/java/java/math/BigDecimal.java b/ojluni/src/main/java/java/math/BigDecimal.java
index c09019e..fe33c5f 100644
--- a/ojluni/src/main/java/java/math/BigDecimal.java
+++ b/ojluni/src/main/java/java/math/BigDecimal.java
@@ -3224,9 +3224,8 @@
*/
@Override
public boolean equals(Object x) {
- if (!(x instanceof BigDecimal))
+ if (!(x instanceof BigDecimal xDec))
return false;
- BigDecimal xDec = (BigDecimal) x;
if (x == this)
return true;
if (scale != xDec.scale)
@@ -4760,19 +4759,13 @@
else { // half-way
assert cmpFracHalf == 0;
- switch(roundingMode) {
- case ROUND_HALF_DOWN:
- return false;
+ return switch (roundingMode) {
+ case ROUND_HALF_DOWN -> false;
+ case ROUND_HALF_UP -> true;
+ case ROUND_HALF_EVEN -> oddQuot;
- case ROUND_HALF_UP:
- return true;
-
- case ROUND_HALF_EVEN:
- return oddQuot;
-
- default:
- throw new AssertionError("Unexpected rounding mode" + roundingMode);
- }
+ default -> throw new AssertionError("Unexpected rounding mode" + roundingMode);
+ };
}
}
}
diff --git a/ojluni/src/main/java/java/math/BigInteger.java b/ojluni/src/main/java/java/math/BigInteger.java
index 8197ebf..cc9b890 100644
--- a/ojluni/src/main/java/java/math/BigInteger.java
+++ b/ojluni/src/main/java/java/math/BigInteger.java
@@ -3938,14 +3938,11 @@
*/
public int compareTo(BigInteger val) {
if (signum == val.signum) {
- switch (signum) {
- case 1:
- return compareMagnitude(val);
- case -1:
- return val.compareMagnitude(this);
- default:
- return 0;
- }
+ return switch (signum) {
+ case 1 -> compareMagnitude(val);
+ case -1 -> val.compareMagnitude(this);
+ default -> 0;
+ };
}
return signum > val.signum ? 1 : -1;
}
@@ -4031,10 +4028,9 @@
if (x == this)
return true;
- if (!(x instanceof BigInteger))
+ if (!(x instanceof BigInteger xInt))
return false;
- BigInteger xInt = (BigInteger) x;
if (xInt.signum != signum)
return false;
diff --git a/ojluni/src/main/java/java/math/MathContext.java b/ojluni/src/main/java/java/math/MathContext.java
index 212f628..e53db0f 100644
--- a/ojluni/src/main/java/java/math/MathContext.java
+++ b/ojluni/src/main/java/java/math/MathContext.java
@@ -248,10 +248,8 @@
* settings as this object
*/
public boolean equals(Object x){
- MathContext mc;
- if (!(x instanceof MathContext))
+ if (!(x instanceof MathContext mc))
return false;
- mc = (MathContext) x;
return mc.precision == this.precision
&& mc.roundingMode == this.roundingMode; // no need for .equals()
}
diff --git a/ojluni/src/main/java/java/math/RoundingMode.java b/ojluni/src/main/java/java/math/RoundingMode.java
index 630fc03..04c71de 100644
--- a/ojluni/src/main/java/java/math/RoundingMode.java
+++ b/ojluni/src/main/java/java/math/RoundingMode.java
@@ -377,34 +377,16 @@
* @throws IllegalArgumentException integer is out of range
*/
public static RoundingMode valueOf(int rm) {
- switch(rm) {
-
- case BigDecimal.ROUND_UP:
- return UP;
-
- case BigDecimal.ROUND_DOWN:
- return DOWN;
-
- case BigDecimal.ROUND_CEILING:
- return CEILING;
-
- case BigDecimal.ROUND_FLOOR:
- return FLOOR;
-
- case BigDecimal.ROUND_HALF_UP:
- return HALF_UP;
-
- case BigDecimal.ROUND_HALF_DOWN:
- return HALF_DOWN;
-
- case BigDecimal.ROUND_HALF_EVEN:
- return HALF_EVEN;
-
- case BigDecimal.ROUND_UNNECESSARY:
- return UNNECESSARY;
-
- default:
- throw new IllegalArgumentException("argument out of range");
- }
+ return switch (rm) {
+ case BigDecimal.ROUND_UP -> UP;
+ case BigDecimal.ROUND_DOWN -> DOWN;
+ case BigDecimal.ROUND_CEILING -> CEILING;
+ case BigDecimal.ROUND_FLOOR -> FLOOR;
+ case BigDecimal.ROUND_HALF_UP -> HALF_UP;
+ case BigDecimal.ROUND_HALF_DOWN -> HALF_DOWN;
+ case BigDecimal.ROUND_HALF_EVEN -> HALF_EVEN;
+ case BigDecimal.ROUND_UNNECESSARY -> UNNECESSARY;
+ default -> throw new IllegalArgumentException("argument out of range");
+ };
}
}
diff --git a/ojluni/src/main/java/java/net/InetSocketAddress.java b/ojluni/src/main/java/java/net/InetSocketAddress.java
index bf69bfb..16ce41f 100644
--- a/ojluni/src/main/java/java/net/InetSocketAddress.java
+++ b/ojluni/src/main/java/java/net/InetSocketAddress.java
@@ -334,7 +334,7 @@
InetSocketAddressHolder h = new InetSocketAddressHolder(oisHostname,
oisAddr,
oisPort);
- UNSAFE.putObject(this, FIELDS_OFFSET, h);
+ UNSAFE.putReference(this, FIELDS_OFFSET, h);
}
/**
diff --git a/ojluni/src/main/java/java/net/URI.java b/ojluni/src/main/java/java/net/URI.java
index ebba41b..cd4ab1e 100644
--- a/ojluni/src/main/java/java/net/URI.java
+++ b/ojluni/src/main/java/java/net/URI.java
@@ -2682,6 +2682,12 @@
private static final long H_URIC_NO_SLASH
= H_UNRESERVED | H_ESCAPED | highMask(";?:@&=+$,");
+ // Android-changed: cherry-picked from Java 9 to allow _ and . in scope ID.
+ // scope_id = alpha | digit | "_" | "."
+ private static final long L_SCOPE_ID
+ = L_ALPHANUM | lowMask("_.");
+ private static final long H_SCOPE_ID
+ = H_ALPHANUM | highMask("_.");
// -- Escaping and encoding --
@@ -3265,7 +3271,9 @@
if (r+1 == q) {
fail ("scope id expected");
}
- checkChars (r+1, q, L_ALPHANUM, H_ALPHANUM,
+ // Android-changed: cherry-picked from Java 9 to allow _ and . in scope ID.
+ // checkChars (r+1, q, L_ALPHANUM, H_ALPHANUM,
+ checkChars (r+1, q, L_SCOPE_ID, H_SCOPE_ID,
"scope id");
} else {
parseIPv6Reference(p, q);
diff --git a/ojluni/src/main/java/java/nio/charset/CharacterCodingException.java b/ojluni/src/main/java/java/nio/charset/CharacterCodingException.java
index 1cfeb5f..8a97ae1 100644
--- a/ojluni/src/main/java/java/nio/charset/CharacterCodingException.java
+++ b/ojluni/src/main/java/java/nio/charset/CharacterCodingException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -41,6 +41,7 @@
extends java.io.IOException
{
+ @java.io.Serial
private static final long serialVersionUID = 8421532232154627783L;
/**
diff --git a/ojluni/src/main/java/java/nio/charset/Charset-X-Coder.java.template b/ojluni/src/main/java/java/nio/charset/Charset-X-Coder.java.template
index 55705a4..73beaa6 100644
--- a/ojluni/src/main/java/java/nio/charset/Charset-X-Coder.java.template
+++ b/ojluni/src/main/java/java/nio/charset/Charset-X-Coder.java.template
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2020, 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
@@ -36,6 +36,7 @@
import java.lang.ref.WeakReference;
import java.nio.charset.CoderMalfunctionError; // javadoc
import java.util.Arrays;
+import java.util.Objects;
/**
@@ -206,10 +207,12 @@
// END Android-added: A hidden constructor for the CharsetEncoderICU subclass.
#end[encoder]
this.charset = cs;
- if (average$ItypesPerOtype$ <= 0.0f)
+ // Use !(a > 0.0f) rather than (a <= 0.0f) to exclude NaN values
+ if (!(average$ItypesPerOtype$ > 0.0f))
throw new IllegalArgumentException("Non-positive "
+ "average$ItypesPerOtype$");
- if (max$ItypesPerOtype$ <= 0.0f)
+ // Use !(a > 0.0f) rather than (a <= 0.0f) to exclude NaN values
+ if (!(max$ItypesPerOtype$ > 0.0f))
throw new IllegalArgumentException("Non-positive "
+ "max$ItypesPerOtype$");
if (average$ItypesPerOtype$ > max$ItypesPerOtype$)
@@ -482,7 +485,14 @@
/**
* Returns the maximum number of $otype$s that will be produced for each
* $itype$ of input. This value may be used to compute the worst-case size
- * of the output buffer required for a given input sequence.
+ * of the output buffer required for a given input sequence. This value
+ * accounts for any necessary content-independent prefix or suffix
+#if[encoder]
+ * $otype$s, such as byte-order marks.
+#end[encoder]
+#if[decoder]
+ * $otype$s.
+#end[decoder]
*
* @return The maximum number of $otype$s that will be produced per
* $itype$ of input
@@ -491,6 +501,7 @@
return max$ItypesPerOtype$;
}
+ // Android-changed: Keep compat behavior. Document NPE thrown for null arguments.
/**
* $Code$s as many $itype$s as possible from the given input buffer,
* writing the results to the given output buffer.
@@ -588,10 +599,16 @@
* @throws CoderMalfunctionError
* If an invocation of the $code$Loop method threw
* an unexpected exception
+ *
+ * @throws NullPointerException if input or output buffer is null
*/
public final CoderResult $code$($Itype$Buffer in, $Otype$Buffer out,
boolean endOfInput)
{
+ // Android-added: Keep compat behavior. libcore throws NPE for null arguments.
+ Objects.requireNonNull(in, "in");
+ Objects.requireNonNull(out, "out");
+
int newState = endOfInput ? ST_END : ST_CODING;
if ((state != ST_RESET) && (state != ST_CODING)
&& !(endOfInput && (state == ST_END)))
@@ -603,9 +620,7 @@
CoderResult cr;
try {
cr = $code$Loop(in, out);
- } catch (BufferUnderflowException x) {
- throw new CoderMalfunctionError(x);
- } catch (BufferOverflowException x) {
+ } catch (RuntimeException x) {
throw new CoderMalfunctionError(x);
}
@@ -783,6 +798,7 @@
protected abstract CoderResult $code$Loop($Itype$Buffer in,
$Otype$Buffer out);
+ // Android-changed: Document CoderMalfunctionError and NPE thrown for null input buffer.
/**
* Convenience method that $code$s the remaining content of a single input
* $itype$ buffer into a newly-allocated $otype$ buffer.
@@ -813,6 +829,12 @@
* position cannot be mapped to an equivalent $otype$ sequence and
* the current unmappable-character action is {@link
* CodingErrorAction#REPORT}
+ *
+ * @throws CoderMalfunctionError
+ * If an invocation of the $code$Loop method threw
+ * an unexpected exception
+ *
+ * @throws NullPointerException if input buffer is null
*/
public final $Otype$Buffer $code$($Itype$Buffer in)
throws CharacterCodingException
diff --git a/ojluni/src/main/java/java/nio/charset/CharsetDecoder.java b/ojluni/src/main/java/java/nio/charset/CharsetDecoder.java
index 2a94b52..29b7b5f 100644
--- a/ojluni/src/main/java/java/nio/charset/CharsetDecoder.java
+++ b/ojluni/src/main/java/java/nio/charset/CharsetDecoder.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2020, 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
@@ -36,6 +36,7 @@
import java.lang.ref.WeakReference;
import java.nio.charset.CoderMalfunctionError; // javadoc
import java.util.Arrays;
+import java.util.Objects;
/**
@@ -206,10 +207,12 @@
this.charset = cs;
- if (averageCharsPerByte <= 0.0f)
+ // Use !(a > 0.0f) rather than (a <= 0.0f) to exclude NaN values
+ if (!(averageCharsPerByte > 0.0f))
throw new IllegalArgumentException("Non-positive "
+ "averageCharsPerByte");
- if (maxCharsPerByte <= 0.0f)
+ // Use !(a > 0.0f) rather than (a <= 0.0f) to exclude NaN values
+ if (!(maxCharsPerByte > 0.0f))
throw new IllegalArgumentException("Non-positive "
+ "maxCharsPerByte");
if (averageCharsPerByte > maxCharsPerByte)
@@ -482,7 +485,14 @@
/**
* Returns the maximum number of characters that will be produced for each
* byte of input. This value may be used to compute the worst-case size
- * of the output buffer required for a given input sequence.
+ * of the output buffer required for a given input sequence. This value
+ * accounts for any necessary content-independent prefix or suffix
+
+
+
+
+ * characters.
+
*
* @return The maximum number of characters that will be produced per
* byte of input
@@ -491,6 +501,7 @@
return maxCharsPerByte;
}
+ // Android-changed: Keep compat behavior. Document NPE thrown for null arguments.
/**
* Decodes as many bytes as possible from the given input buffer,
* writing the results to the given output buffer.
@@ -588,10 +599,16 @@
* @throws CoderMalfunctionError
* If an invocation of the decodeLoop method threw
* an unexpected exception
+ *
+ * @throws NullPointerException if input or output buffer is null
*/
public final CoderResult decode(ByteBuffer in, CharBuffer out,
boolean endOfInput)
{
+ // Android-added: Keep compat behavior. libcore throws NPE for null arguments.
+ Objects.requireNonNull(in, "in");
+ Objects.requireNonNull(out, "out");
+
int newState = endOfInput ? ST_END : ST_CODING;
if ((state != ST_RESET) && (state != ST_CODING)
&& !(endOfInput && (state == ST_END)))
@@ -603,9 +620,7 @@
CoderResult cr;
try {
cr = decodeLoop(in, out);
- } catch (BufferUnderflowException x) {
- throw new CoderMalfunctionError(x);
- } catch (BufferOverflowException x) {
+ } catch (RuntimeException x) {
throw new CoderMalfunctionError(x);
}
@@ -783,6 +798,7 @@
protected abstract CoderResult decodeLoop(ByteBuffer in,
CharBuffer out);
+ // Android-changed: Document CoderMalfunctionError and NPE thrown for null input buffer.
/**
* Convenience method that decodes the remaining content of a single input
* byte buffer into a newly-allocated character buffer.
@@ -813,6 +829,12 @@
* position cannot be mapped to an equivalent character sequence and
* the current unmappable-character action is {@link
* CodingErrorAction#REPORT}
+ *
+ * @throws CoderMalfunctionError
+ * If an invocation of the decodeLoop method threw
+ * an unexpected exception
+ *
+ * @throws NullPointerException if input buffer is null
*/
public final CharBuffer decode(ByteBuffer in)
throws CharacterCodingException
diff --git a/ojluni/src/main/java/java/nio/charset/CharsetEncoder.java b/ojluni/src/main/java/java/nio/charset/CharsetEncoder.java
index 67901af..8f5667d 100644
--- a/ojluni/src/main/java/java/nio/charset/CharsetEncoder.java
+++ b/ojluni/src/main/java/java/nio/charset/CharsetEncoder.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2020, 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
@@ -36,6 +36,7 @@
import java.lang.ref.WeakReference;
import java.nio.charset.CoderMalfunctionError; // javadoc
import java.util.Arrays;
+import java.util.Objects;
/**
@@ -206,10 +207,12 @@
// END Android-added: A hidden constructor for the CharsetEncoderICU subclass.
this.charset = cs;
- if (averageBytesPerChar <= 0.0f)
+ // Use !(a > 0.0f) rather than (a <= 0.0f) to exclude NaN values
+ if (!(averageBytesPerChar > 0.0f))
throw new IllegalArgumentException("Non-positive "
+ "averageBytesPerChar");
- if (maxBytesPerChar <= 0.0f)
+ // Use !(a > 0.0f) rather than (a <= 0.0f) to exclude NaN values
+ if (!(maxBytesPerChar > 0.0f))
throw new IllegalArgumentException("Non-positive "
+ "maxBytesPerChar");
if (averageBytesPerChar > maxBytesPerChar)
@@ -482,7 +485,14 @@
/**
* Returns the maximum number of bytes that will be produced for each
* character of input. This value may be used to compute the worst-case size
- * of the output buffer required for a given input sequence.
+ * of the output buffer required for a given input sequence. This value
+ * accounts for any necessary content-independent prefix or suffix
+
+ * bytes, such as byte-order marks.
+
+
+
+
*
* @return The maximum number of bytes that will be produced per
* character of input
@@ -491,6 +501,7 @@
return maxBytesPerChar;
}
+ // Android-changed: Keep compat behavior. Document NPE thrown for null arguments.
/**
* Encodes as many characters as possible from the given input buffer,
* writing the results to the given output buffer.
@@ -588,10 +599,16 @@
* @throws CoderMalfunctionError
* If an invocation of the encodeLoop method threw
* an unexpected exception
+ *
+ * @throws NullPointerException if input or output buffer is null
*/
public final CoderResult encode(CharBuffer in, ByteBuffer out,
boolean endOfInput)
{
+ // Android-added: Keep compat behavior. libcore throws NPE for null arguments.
+ Objects.requireNonNull(in, "in");
+ Objects.requireNonNull(out, "out");
+
int newState = endOfInput ? ST_END : ST_CODING;
if ((state != ST_RESET) && (state != ST_CODING)
&& !(endOfInput && (state == ST_END)))
@@ -603,9 +620,7 @@
CoderResult cr;
try {
cr = encodeLoop(in, out);
- } catch (BufferUnderflowException x) {
- throw new CoderMalfunctionError(x);
- } catch (BufferOverflowException x) {
+ } catch (RuntimeException x) {
throw new CoderMalfunctionError(x);
}
@@ -783,6 +798,7 @@
protected abstract CoderResult encodeLoop(CharBuffer in,
ByteBuffer out);
+ // Android-changed: Document CoderMalfunctionError and NPE thrown for null input buffer.
/**
* Convenience method that encodes the remaining content of a single input
* character buffer into a newly-allocated byte buffer.
@@ -813,6 +829,12 @@
* position cannot be mapped to an equivalent byte sequence and
* the current unmappable-character action is {@link
* CodingErrorAction#REPORT}
+ *
+ * @throws CoderMalfunctionError
+ * If an invocation of the encodeLoop method threw
+ * an unexpected exception
+ *
+ * @throws NullPointerException if input buffer is null
*/
public final ByteBuffer encode(CharBuffer in)
throws CharacterCodingException
diff --git a/ojluni/src/main/java/java/nio/charset/IllegalCharsetNameException.java b/ojluni/src/main/java/java/nio/charset/IllegalCharsetNameException.java
index 9124282..cc7a291 100644
--- a/ojluni/src/main/java/java/nio/charset/IllegalCharsetNameException.java
+++ b/ojluni/src/main/java/java/nio/charset/IllegalCharsetNameException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -41,8 +41,12 @@
extends IllegalArgumentException
{
+ @java.io.Serial
private static final long serialVersionUID = 1457525358470002989L;
+ /**
+ * The illegal charset name.
+ */
private String charsetName;
/**
diff --git a/ojluni/src/main/java/java/nio/charset/UnsupportedCharsetException.java b/ojluni/src/main/java/java/nio/charset/UnsupportedCharsetException.java
index 1774fc0..aac05c6 100644
--- a/ojluni/src/main/java/java/nio/charset/UnsupportedCharsetException.java
+++ b/ojluni/src/main/java/java/nio/charset/UnsupportedCharsetException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -41,8 +41,12 @@
extends IllegalArgumentException
{
+ @java.io.Serial
private static final long serialVersionUID = 1490765524727386367L;
+ /**
+ * The name of the unsupported charset.
+ */
private String charsetName;
/**
diff --git a/ojluni/src/main/java/java/nio/charset/exceptions b/ojluni/src/main/java/java/nio/charset/exceptions
index 22dfa3c..c477309 100644
--- a/ojluni/src/main/java/java/nio/charset/exceptions
+++ b/ojluni/src/main/java/java/nio/charset/exceptions
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2000, 2021, 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
@@ -28,7 +28,7 @@
SINCE=1.4
PACKAGE=java.nio.charset
# This year should only change if the generated source is modified.
-COPYRIGHT_YEARS="2000, 2007,"
+COPYRIGHT_YEARS="2000, 2021,"
SUPER=java.io.IOException
diff --git a/ojluni/src/main/java/java/security/DrbgParameters.java b/ojluni/src/main/java/java/security/DrbgParameters.java
new file mode 100644
index 0000000..9b141a0
--- /dev/null
+++ b/ojluni/src/main/java/java/security/DrbgParameters.java
@@ -0,0 +1,555 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * This class specifies the parameters used by a DRBG (Deterministic
+ * Random Bit Generator).
+ * <p>
+ * According to
+ * <a href="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf">
+ * NIST Special Publication 800-90A Revision 1, Recommendation for Random
+ * Number Generation Using Deterministic Random Bit Generators</a> (800-90Ar1),
+ * <blockquote>
+ * A DRBG is based on a DRBG mechanism as specified in this Recommendation
+ * and includes a source of randomness. A DRBG mechanism uses an algorithm
+ * (i.e., a DRBG algorithm) that produces a sequence of bits from an initial
+ * value that is determined by a seed that is determined from the output of
+ * the randomness source."
+ * </blockquote>
+ * <p>
+ * The 800-90Ar1 specification allows for a variety of DRBG implementation
+ * choices, such as:
+ * <ul>
+ * <li> an entropy source,
+ * <li> a DRBG mechanism (for example, Hash_DRBG),
+ * <li> a DRBG algorithm (for example, SHA-256 for Hash_DRBG and AES-256
+ * for CTR_DRBG. Please note that it is not the algorithm used in
+ * {@link SecureRandom#getInstance}, which we will call a
+ * <em>SecureRandom algorithm</em> below),
+ * <li> optional features, including prediction resistance
+ * and reseeding supports,
+ * <li> highest security strength.
+ * </ul>
+ * <p>
+ * These choices are set in each implementation and are not directly
+ * managed by the {@code SecureRandom} API. Check your DRBG provider's
+ * documentation to find an appropriate implementation for the situation.
+ * <p>
+ * On the other hand, the 800-90Ar1 specification does have some configurable
+ * options, such as:
+ * <ul>
+ * <li> required security strength,
+ * <li> if prediction resistance is required,
+ * <li> personalization string and additional input.
+ * </ul>
+ * <p>
+ * A DRBG instance can be instantiated with parameters from an
+ * {@link DrbgParameters.Instantiation} object and other information
+ * (for example, the nonce, which is not managed by this API). This maps
+ * to the {@code Instantiate_function} defined in NIST SP 800-90Ar1.
+ * <p>
+ * A DRBG instance can be reseeded with parameters from a
+ * {@link DrbgParameters.Reseed} object. This maps to the
+ * {@code Reseed_function} defined in NIST SP 800-90Ar1. Calling
+ * {@link SecureRandom#reseed()} is equivalent to calling
+ * {@link SecureRandom#reseed(SecureRandomParameters)} with the effective
+ * instantiated prediction resistance flag (as returned by
+ * {@link SecureRandom#getParameters()}) with no additional input.
+ * <p>
+ * A DRBG instance generates data with additional parameters from a
+ * {@link DrbgParameters.NextBytes} object. This maps to the
+ * {@code Generate_function} defined in NIST SP 800-90Ar1. Calling
+ * {@link SecureRandom#nextBytes(byte[])} is equivalent to calling
+ * {@link SecureRandom#nextBytes(byte[], SecureRandomParameters)}
+ * with the effective instantiated strength and prediction resistance flag
+ * (as returned by {@link SecureRandom#getParameters()}) with no
+ * additional input.
+ * <p>
+ * A DRBG should be implemented as a subclass of {@link SecureRandomSpi}.
+ * It is recommended that the implementation contain the 1-arg
+ * {@linkplain SecureRandomSpi#SecureRandomSpi(SecureRandomParameters) constructor}
+ * that takes a {@code DrbgParameters.Instantiation} argument. If implemented
+ * this way, this implementation can be chosen by any
+ * {@code SecureRandom.getInstance()} method. If it is chosen by a
+ * {@code SecureRandom.getInstance()} with a {@link SecureRandomParameters}
+ * parameter, the parameter is passed into this constructor. If it is chosen
+ * by a {@code SecureRandom.getInstance()} without a
+ * {@code SecureRandomParameters} parameter, the constructor is called with
+ * a {@code null} argument and the implementation should choose its own
+ * parameters. Its {@link SecureRandom#getParameters()} must always return a
+ * non-null effective {@code DrbgParameters.Instantiation} object that reflects
+ * how the DRBG is actually instantiated. A caller can use this information
+ * to determine whether a {@code SecureRandom} object is a DRBG and what
+ * features it supports. Please note that the returned value does not
+ * necessarily equal to the {@code DrbgParameters.Instantiation} object passed
+ * into the {@code SecureRandom.getInstance()} call. For example,
+ * the requested capability can be {@link DrbgParameters.Capability#NONE}
+ * but the effective value can be {@link DrbgParameters.Capability#RESEED_ONLY}
+ * if the implementation supports reseeding. The implementation must implement
+ * the {@link SecureRandomSpi#engineNextBytes(byte[], SecureRandomParameters)}
+ * method which takes a {@code DrbgParameters.NextBytes} parameter. Unless
+ * the result of {@link SecureRandom#getParameters()} has its
+ * {@linkplain DrbgParameters.Instantiation#getCapability() capability} being
+ * {@link Capability#NONE NONE}, it must implement
+ * {@link SecureRandomSpi#engineReseed(SecureRandomParameters)} which takes
+ * a {@code DrbgParameters.Reseed} parameter.
+ * <p>
+ * On the other hand, if a DRBG implementation does not contain a constructor
+ * that has an {@code DrbgParameters.Instantiation} argument (not recommended),
+ * it can only be chosen by a {@code SecureRandom.getInstance()} without
+ * a {@code SecureRandomParameters} parameter, but will not be chosen if
+ * a {@code getInstance} method with a {@code SecureRandomParameters} parameter
+ * is called. If implemented this way, its {@link SecureRandom#getParameters()}
+ * must return {@code null}, and it does not need to implement either
+ * {@link SecureRandomSpi#engineNextBytes(byte[], SecureRandomParameters)}
+ * or {@link SecureRandomSpi#engineReseed(SecureRandomParameters)}.
+ * <p>
+ * A DRBG might reseed itself automatically if the seed period is bigger
+ * than the maximum seed life defined by the DRBG mechanism.
+ * <p>
+ * A DRBG implementation should support serialization and deserialization
+ * by retaining the configuration and effective parameters, but the internal
+ * state must not be serialized and the deserialized object must be
+ * reinstantiated.
+ * <p>
+ * Examples:
+ * <blockquote><pre>
+ * SecureRandom drbg;
+ * byte[] buffer = new byte[32];
+ *
+ * // Any DRBG is OK
+ * drbg = SecureRandom.getInstance("DRBG");
+ * drbg.nextBytes(buffer);
+ *
+ * SecureRandomParameters params = drbg.getParameters();
+ * if (params instanceof DrbgParameters.Instantiation) {
+ * DrbgParameters.Instantiation ins = (DrbgParameters.Instantiation) params;
+ * if (ins.getCapability().supportsReseeding()) {
+ * drbg.reseed();
+ * }
+ * }
+ *
+ * // The following call requests a weak DRBG instance. It is only
+ * // guaranteed to support 112 bits of security strength.
+ * drbg = SecureRandom.getInstance("DRBG",
+ * DrbgParameters.instantiation(112, NONE, null));
+ *
+ * // Both the next two calls will likely fail, because drbg could be
+ * // instantiated with a smaller strength with no prediction resistance
+ * // support.
+ * drbg.nextBytes(buffer,
+ * DrbgParameters.nextBytes(256, false, "more".getBytes()));
+ * drbg.nextBytes(buffer,
+ * DrbgParameters.nextBytes(112, true, "more".getBytes()));
+ *
+ * // The following call requests a strong DRBG instance, with a
+ * // personalization string. If it successfully returns an instance,
+ * // that instance is guaranteed to support 256 bits of security strength
+ * // with prediction resistance available.
+ * drbg = SecureRandom.getInstance("DRBG", DrbgParameters.instantiation(
+ * 256, PR_AND_RESEED, "hello".getBytes()));
+ *
+ * // Prediction resistance is not requested in this single call,
+ * // but an additional input is used.
+ * drbg.nextBytes(buffer,
+ * DrbgParameters.nextBytes(-1, false, "more".getBytes()));
+ *
+ * // Same for this call.
+ * drbg.reseed(DrbgParameters.reseed(false, "extra".getBytes()));</pre>
+ * </blockquote>
+ *
+ * @implSpec
+ * By convention, a provider should name its primary DRBG implementation
+ * with the <a href=
+ * "{@docRoot}/../specs/security/standard-names.html#securerandom-number-generation-algorithms">
+ * standard {@code SecureRandom} algorithm name</a> "DRBG".
+ *
+ * @implNote
+ * The following notes apply to the "DRBG" implementation in the SUN provider
+ * of the JDK reference implementation.
+ * <p>
+ * This implementation supports the Hash_DRBG and HMAC_DRBG mechanisms with
+ * DRBG algorithm SHA-224, SHA-512/224, SHA-256, SHA-512/256, SHA-384 and
+ * SHA-512, and CTR_DRBG (both using derivation function and not using
+ * derivation function) with DRBG algorithm AES-128, AES-192 and AES-256.
+ * <p>
+ * The mechanism name and DRBG algorithm name are determined by the
+ * {@linkplain Security#getProperty(String) security property}
+ * {@code securerandom.drbg.config}. The default choice is Hash_DRBG
+ * with SHA-256.
+ * <p>
+ * For each combination, the security strength can be requested from 112
+ * up to the highest strength it supports. Both reseeding and prediction
+ * resistance are supported.
+ * <p>
+ * Personalization string is supported through the
+ * {@link DrbgParameters.Instantiation} class and additional input is supported
+ * through the {@link DrbgParameters.NextBytes} and
+ * {@link DrbgParameters.Reseed} classes.
+ * <p>
+ * If a DRBG is not instantiated with a {@link DrbgParameters.Instantiation}
+ * object explicitly, this implementation instantiates it with a default
+ * requested strength of 128 bits, no prediction resistance request, and
+ * no personalization string. These default instantiation parameters can also
+ * be customized with the {@code securerandom.drbg.config} security property.
+ * <p>
+ * This implementation reads fresh entropy from the system default entropy
+ * source determined by the security property {@code securerandom.source}.
+ * <p>
+ * Calling {@link SecureRandom#generateSeed(int)} will directly read
+ * from this system default entropy source.
+ *
+ * @since 9
+ */
+public class DrbgParameters {
+
+ private DrbgParameters() {
+ // This class should not be instantiated
+ }
+
+ /**
+ * The reseedable and prediction resistance capabilities of a DRBG.
+ * <p>
+ * When this object is passed to a {@code SecureRandom.getInstance()} call,
+ * it is the requested minimum capability. When it's returned from
+ * {@code SecureRandom.getParameters()}, it is the effective capability.
+ * <p>
+ * Please note that while the {@code Instantiate_function} defined in
+ * NIST SP 800-90Ar1 only includes a {@code prediction_resistance_flag}
+ * parameter, the {@code Capability} type includes an extra value
+ * {@link #RESEED_ONLY} because reseeding is an optional function.
+ * If {@code NONE} is used in an {@code Instantiation} object in calling the
+ * {@code SecureRandom.getInstance} method, the returned DRBG instance
+ * is not guaranteed to support reseeding. If {@code RESEED_ONLY} or
+ * {@code PR_AND_RESEED} is used, the instance must support reseeding.
+ * <p>
+ * The table below lists possible effective values if a certain
+ * capability is requested, i.e.
+ * <blockquote><pre>
+ * Capability requested = ...;
+ * SecureRandom s = SecureRandom.getInstance("DRBG",
+ * DrbgParameters(-1, requested, null));
+ * Capability effective = ((DrbgParametes.Initiate) s.getParameters())
+ * .getCapability();</pre>
+ * </blockquote>
+ * <table class="striped">
+ * <caption style="display:none">requested and effective capabilities</caption>
+ * <thead>
+ * <tr>
+ * <th scope="col">Requested Value</th>
+ * <th scope="col">Possible Effective Values</th>
+ * </tr>
+ * </thead>
+ * <tbody style="text-align:left">
+ * <tr><th scope="row">NONE</th><td>NONE, RESEED_ONLY, PR_AND_RESEED</td></tr>
+ * <tr><th scope="row">RESEED_ONLY</th><td>RESEED_ONLY, PR_AND_RESEED</td></tr>
+ * <tr><th scope="row">PR_AND_RESEED</th><td>PR_AND_RESEED</td></tr>
+ * </tbody>
+ * </table>
+ * <p>
+ * A DRBG implementation supporting prediction resistance must also
+ * support reseeding.
+ *
+ * @since 9
+ */
+ public enum Capability {
+
+ /**
+ * Both prediction resistance and reseed.
+ */
+ PR_AND_RESEED,
+
+ /**
+ * Reseed but no prediction resistance.
+ */
+ RESEED_ONLY,
+
+ /**
+ * Neither prediction resistance nor reseed.
+ */
+ NONE;
+
+ @Override
+ public String toString() {
+ return name().toLowerCase(Locale.ROOT);
+ }
+
+ /**
+ * Returns whether this capability supports reseeding.
+ *
+ * @return {@code true} for {@link #PR_AND_RESEED} and
+ * {@link #RESEED_ONLY}, and {@code false} for {@link #NONE}
+ */
+ public boolean supportsReseeding() {
+ return this != NONE;
+ }
+
+ /**
+ * Returns whether this capability supports prediction resistance.
+ *
+ * @return {@code true} for {@link #PR_AND_RESEED}, and {@code false}
+ * for {@link #RESEED_ONLY} and {@link #NONE}
+ */
+ public boolean supportsPredictionResistance() {
+ return this == PR_AND_RESEED;
+ }
+ }
+
+ /**
+ * DRBG parameters for instantiation.
+ * <p>
+ * When used in
+ * {@link SecureRandom#getInstance(String, SecureRandomParameters)}
+ * or one of the other similar {@code getInstance} calls that take a
+ * {@code SecureRandomParameters} parameter, it means the
+ * requested instantiate parameters the newly created {@code SecureRandom}
+ * object must minimally support. When used as the return value of the
+ * {@link SecureRandom#getParameters()} method, it means the effective
+ * instantiate parameters of the {@code SecureRandom} object.
+ *
+ * @since 9
+ */
+ public static final class Instantiation
+ implements SecureRandomParameters {
+
+ private final int strength;
+ private final Capability capability;
+ private final byte[] personalizationString;
+
+ /**
+ * Returns the security strength in bits.
+ *
+ * @return If used in {@code getInstance}, returns the minimum strength
+ * requested, or -1 if there is no specific request on the strength.
+ * If used in {@code getParameters}, returns the effective strength.
+ * The effective strength must be greater than or equal to the minimum
+ * strength requested.
+ */
+ public int getStrength() {
+ return strength;
+ }
+
+ /**
+ * Returns the capability.
+ *
+ * @return If used in {@code getInstance}, returns the minimum
+ * capability requested. If used in {@code getParameters}, returns
+ * information on the effective prediction resistance flag and
+ * whether it supports reseeding.
+ */
+ public Capability getCapability() {
+ return capability;
+ }
+
+ /**
+ * Returns the personalization string as a byte array.
+ *
+ * @return If used in {@code getInstance}, returns the requested
+ * personalization string as a newly allocated array, or {@code null}
+ * if no personalization string is requested. The same string should
+ * be returned in {@code getParameters} as a new copy, or {@code null}
+ * if no personalization string is requested in {@code getInstance}.
+ */
+ public byte[] getPersonalizationString() {
+ return (personalizationString == null) ?
+ null : personalizationString.clone();
+ }
+
+ private Instantiation(int strength, Capability capability,
+ byte[] personalizationString) {
+ if (strength < -1) {
+ throw new IllegalArgumentException(
+ "Illegal security strength: " + strength);
+ }
+ this.strength = strength;
+ this.capability = capability;
+ this.personalizationString = (personalizationString == null) ?
+ null : personalizationString.clone();
+ }
+
+ /**
+ * Returns a Human-readable string representation of this
+ * {@code Instantiation}.
+ *
+ * @return the string representation
+ */
+ @Override
+ public String toString() {
+ // I don't care what personalizationString looks like
+ // Android-changed: Fix ErrorProne build error due to concatenation with a byte[].
+ // return strength + "," + capability + "," + personalizationString;
+ return strength + "," + capability + "," + Arrays.toString(personalizationString);
+ }
+ }
+
+ /**
+ * DRBG parameters for random bits generation. It is used in
+ * {@link SecureRandom#nextBytes(byte[], SecureRandomParameters)}.
+ *
+ * @since 9
+ */
+ public static final class NextBytes
+ implements SecureRandomParameters {
+ private final int strength;
+ private final boolean predictionResistance;
+ private final byte[] additionalInput;
+
+ /**
+ * Returns the security strength requested in bits.
+ *
+ * @return the strength requested, or -1 if the effective strength
+ * should be used.
+ */
+ public int getStrength() {
+ return strength;
+ }
+
+ /**
+ * Returns whether prediction resistance is requested.
+ *
+ * @return whether prediction resistance is requested
+ */
+ public boolean getPredictionResistance() {
+ return predictionResistance;
+ }
+
+ /**
+ * Returns the requested additional input.
+ *
+ * @return the requested additional input, {@code null} if not
+ * requested. A new byte array is returned each time this method
+ * is called.
+ */
+ public byte[] getAdditionalInput() {
+ return additionalInput == null? null: additionalInput.clone();
+ }
+
+ private NextBytes(int strength, boolean predictionResistance,
+ byte[] additionalInput) {
+ if (strength < -1) {
+ throw new IllegalArgumentException(
+ "Illegal security strength: " + strength);
+ }
+ this.strength = strength;
+ this.predictionResistance = predictionResistance;
+ this.additionalInput = (additionalInput == null) ?
+ null : additionalInput.clone();
+ }
+ }
+
+ /**
+ * DRBG parameters for reseed. It is used in
+ * {@link SecureRandom#reseed(SecureRandomParameters)}.
+ *
+ * @since 9
+ */
+ public static final class Reseed implements SecureRandomParameters {
+
+ private final byte[] additionalInput;
+ private final boolean predictionResistance;
+
+ /**
+ * Returns whether prediction resistance is requested.
+ *
+ * @return whether prediction resistance is requested
+ */
+ public boolean getPredictionResistance() {
+ return predictionResistance;
+ }
+
+ /**
+ * Returns the requested additional input.
+ *
+ * @return the requested additional input, or {@code null} if
+ * not requested. A new byte array is returned each time this method
+ * is called.
+ */
+ public byte[] getAdditionalInput() {
+ return additionalInput == null ? null : additionalInput.clone();
+ }
+
+ private Reseed(boolean predictionResistance, byte[] additionalInput) {
+ this.predictionResistance = predictionResistance;
+ this.additionalInput = (additionalInput == null) ?
+ null : additionalInput.clone();
+ }
+ }
+
+ /**
+ * Generates a {@link DrbgParameters.Instantiation} object.
+ *
+ * @param strength security strength in bits, -1 for default strength
+ * if used in {@code getInstance}.
+ * @param capability capability
+ * @param personalizationString personalization string as a byte array,
+ * can be {@code null}. The content of this
+ * byte array will be copied.
+ * @return a new {@code Instantiation} object
+ * @throws NullPointerException if {@code capability} is {@code null}
+ * @throws IllegalArgumentException if {@code strength} is less than -1
+ */
+ public static Instantiation instantiation(int strength,
+ Capability capability,
+ byte[] personalizationString) {
+ return new Instantiation(strength, Objects.requireNonNull(capability),
+ personalizationString);
+ }
+
+ /**
+ * Generates a {@link NextBytes} object.
+ *
+ * @param strength requested security strength in bits. If set to -1, the
+ * effective strength will be used.
+ * @param predictionResistance prediction resistance requested
+ * @param additionalInput additional input, can be {@code null}.
+ * The content of this byte array will be copied.
+ * @throws IllegalArgumentException if {@code strength} is less than -1
+ * @return a new {@code NextBytes} object
+ */
+ public static NextBytes nextBytes(int strength,
+ boolean predictionResistance,
+ byte[] additionalInput) {
+ return new NextBytes(strength, predictionResistance, additionalInput);
+ }
+
+ /**
+ * Generates a {@link Reseed} object.
+ *
+ * @param predictionResistance prediction resistance requested
+ * @param additionalInput additional input, can be {@code null}.
+ * The content of this byte array will be copied.
+ * @return a new {@code Reseed} object
+ */
+ public static Reseed reseed(
+ boolean predictionResistance, byte[] additionalInput) {
+ return new Reseed(predictionResistance, additionalInput);
+ }
+}
diff --git a/ojluni/src/main/java/java/security/SecureRandomParameters.java b/ojluni/src/main/java/java/security/SecureRandomParameters.java
new file mode 100644
index 0000000..f83491c
--- /dev/null
+++ b/ojluni/src/main/java/java/security/SecureRandomParameters.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security;
+
+/**
+ * A marker interface for parameters used in various {@code SecureRandom}
+ * methods.
+ * <p>
+ * Some {@code SecureRandom} implementations might require additional
+ * operational parameters. Objects of classes which implement this interface
+ * can be passed to those implementations that support them.
+ *
+ * @see DrbgParameters
+ * @since 9
+ */
+public interface SecureRandomParameters {
+}
diff --git a/ojluni/src/main/java/java/security/interfaces/DSAKeyPairGenerator.java b/ojluni/src/main/java/java/security/interfaces/DSAKeyPairGenerator.java
index 96e55eb..09c9131 100644
--- a/ojluni/src/main/java/java/security/interfaces/DSAKeyPairGenerator.java
+++ b/ojluni/src/main/java/java/security/interfaces/DSAKeyPairGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
@@ -85,7 +85,7 @@
* @param random the random bit source to use to generate key bits;
* can be null.
*
- * @exception InvalidParameterException if the {@code params}
+ * @throws InvalidParameterException if the {@code params}
* value is invalid, null, or unsupported.
*/
public void initialize(DSAParams params, SecureRandom random)
@@ -112,7 +112,7 @@
* @param genParams whether or not to generate new parameters for
* the modulus length requested.
*
- * @exception InvalidParameterException if {@code modlen} is
+ * @throws InvalidParameterException if {@code modlen} is
* invalid, or unsupported, or if {@code genParams} is false and there
* are no precomputed parameters for the requested modulus length.
*/
diff --git a/ojluni/src/main/java/java/security/interfaces/DSAPrivateKey.java b/ojluni/src/main/java/java/security/interfaces/DSAPrivateKey.java
index b23a5c1..5c442f1 100644
--- a/ojluni/src/main/java/java/security/interfaces/DSAPrivateKey.java
+++ b/ojluni/src/main/java/java/security/interfaces/DSAPrivateKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
@@ -48,6 +48,13 @@
* serialization compatibility with a previous
* version of the class.
*/
+ // Android-removed: (b/260847206) revert once aosp/master is marked as V.
+ // * @deprecated A {@code serialVersionUID} field in an interface is
+ // * ineffectual. Do not use; no replacement.
+ // */
+ // @Deprecated
+ // @SuppressWarnings("serial")
+ // @java.io.Serial
static final long serialVersionUID = 7776497482533790279L;
/**
diff --git a/ojluni/src/main/java/java/security/interfaces/DSAPublicKey.java b/ojluni/src/main/java/java/security/interfaces/DSAPublicKey.java
index fb4a2f3..74159c3 100644
--- a/ojluni/src/main/java/java/security/interfaces/DSAPublicKey.java
+++ b/ojluni/src/main/java/java/security/interfaces/DSAPublicKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, 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
@@ -48,6 +48,13 @@
* serialization compatibility with a previous
* version of the class.
*/
+ // Android-removed: (b/260847206) revert once aosp/master is marked as V.
+ // * @deprecated A {@code serialVersionUID} field in an interface is
+ // * ineffectual. Do not use; no replacement.
+ // */
+ // @Deprecated
+ // @SuppressWarnings("serial")
+ // @java.io.Serial
static final long serialVersionUID = 1234526332779022332L;
/**
diff --git a/ojluni/src/main/java/java/security/interfaces/ECPrivateKey.java b/ojluni/src/main/java/java/security/interfaces/ECPrivateKey.java
index 0ccdc2d..a7565cd 100644
--- a/ojluni/src/main/java/java/security/interfaces/ECPrivateKey.java
+++ b/ojluni/src/main/java/java/security/interfaces/ECPrivateKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -43,6 +43,13 @@
* The class fingerprint that is set to indicate
* serialization compatibility.
*/
+ // Android-removed: (b/260847206) revert once aosp/master is marked as V.
+ // * @deprecated A {@code serialVersionUID} field in an interface is
+ // * ineffectual. Do not use; no replacement.
+ // */
+ // @Deprecated
+ // @SuppressWarnings("serial")
+ // @java.io.Serial
static final long serialVersionUID = -7896394956925609184L;
/**
diff --git a/ojluni/src/main/java/java/security/interfaces/ECPublicKey.java b/ojluni/src/main/java/java/security/interfaces/ECPublicKey.java
index 6d16157..258c4c5 100644
--- a/ojluni/src/main/java/java/security/interfaces/ECPublicKey.java
+++ b/ojluni/src/main/java/java/security/interfaces/ECPublicKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -45,6 +45,13 @@
* The class fingerprint that is set to indicate
* serialization compatibility.
*/
+ // Android-removed: (b/260847206) revert once aosp/master is marked as V.
+ // * @deprecated A {@code serialVersionUID} field in an interface is
+ // * ineffectual. Do not use; no replacement.
+ // */
+ // @Deprecated
+ // @SuppressWarnings("serial")
+ // @java.io.Serial
static final long serialVersionUID = -3314988629879632826L;
/**
diff --git a/ojluni/src/main/java/java/security/interfaces/RSAKey.java b/ojluni/src/main/java/java/security/interfaces/RSAKey.java
index 67fbe2b..39b0e59 100644
--- a/ojluni/src/main/java/java/security/interfaces/RSAKey.java
+++ b/ojluni/src/main/java/java/security/interfaces/RSAKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,9 +26,12 @@
package java.security.interfaces;
import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
/**
- * The interface to an RSA public or private key.
+ * The interface to a public or private key in
+ * <a href="https://tools.ietf.org/rfc/rfc8017.txt">PKCS#1 v2.2</a> standard,
+ * such as those for RSA, or RSASSA-PSS algorithms.
*
* @author Jan Luehe
*
@@ -46,4 +49,22 @@
* @return the modulus
*/
public BigInteger getModulus();
+
+ // Android-removed: (b/260847206) remove @hide once aosp/master is marked as V.
+ /**
+ * Returns the parameters associated with this key.
+ * The parameters are optional and may be either
+ * explicitly specified or implicitly created during
+ * key pair generation.
+ *
+ * @implSpec
+ * The default implementation returns {@code null}.
+ *
+ * @return the associated parameters, may be null
+ * @since 11
+ * @hide
+ */
+ default AlgorithmParameterSpec getParams() {
+ return null;
+ }
}
diff --git a/ojluni/src/main/java/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java b/ojluni/src/main/java/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java
index fd42c5c..1f60683 100644
--- a/ojluni/src/main/java/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java
+++ b/ojluni/src/main/java/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2020, 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
@@ -51,6 +51,13 @@
* serialization compatibility with a previous
* version of the type.
*/
+ // Android-removed: (b/260847206) revert once aosp/master is marked as V.
+ // * @deprecated A {@code serialVersionUID} field in an interface is
+ // * ineffectual. Do not use; no replacement.
+ // */
+ // @Deprecated
+ // @SuppressWarnings("serial")
+ // @java.io.Serial
static final long serialVersionUID = 618058533534628008L;
/**
diff --git a/ojluni/src/main/java/java/security/interfaces/RSAPrivateCrtKey.java b/ojluni/src/main/java/java/security/interfaces/RSAPrivateCrtKey.java
index e6acef1..6057880 100644
--- a/ojluni/src/main/java/java/security/interfaces/RSAPrivateCrtKey.java
+++ b/ojluni/src/main/java/java/security/interfaces/RSAPrivateCrtKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,6 +46,13 @@
* serialization compatibility with a previous
* version of the type.
*/
+ // Android-removed: (b/260847206) revert once aosp/master is marked as V.
+ // * @deprecated A {@code serialVersionUID} field in an interface is
+ // * ineffectual. Do not use; no replacement.
+ // */
+ // @Deprecated
+ // @SuppressWarnings("serial")
+ // @java.io.Serial
static final long serialVersionUID = -5682214253527700368L;
/**
@@ -57,7 +64,7 @@
/**
* Returns the primeP.
-
+ *
* @return the primeP
*/
public BigInteger getPrimeP();
diff --git a/ojluni/src/main/java/java/security/interfaces/RSAPrivateKey.java b/ojluni/src/main/java/java/security/interfaces/RSAPrivateKey.java
index 390da4e..b280222 100644
--- a/ojluni/src/main/java/java/security/interfaces/RSAPrivateKey.java
+++ b/ojluni/src/main/java/java/security/interfaces/RSAPrivateKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, 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
@@ -45,6 +45,13 @@
* serialization compatibility with a previous
* version of the type.
*/
+ // Android-removed: (b/260847206) revert once aosp/master is marked as V.
+ // * @deprecated A {@code serialVersionUID} field in an interface is
+ // * ineffectual. Do not use; no replacement.
+ // */
+ // @Deprecated
+ // @SuppressWarnings("serial")
+ // @java.io.Serial
static final long serialVersionUID = 5187144804936595022L;
/**
diff --git a/ojluni/src/main/java/java/security/interfaces/RSAPublicKey.java b/ojluni/src/main/java/java/security/interfaces/RSAPublicKey.java
index f195306..e20adc8 100644
--- a/ojluni/src/main/java/java/security/interfaces/RSAPublicKey.java
+++ b/ojluni/src/main/java/java/security/interfaces/RSAPublicKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, 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,6 +42,13 @@
* serialization compatibility with a previous
* version of the type.
*/
+ // Android-removed: (b/260847206) revert once aosp/master is marked as V.
+ // * @deprecated A {@code serialVersionUID} field in an interface is
+ // * ineffectual. Do not use; no replacement.
+ // */
+ // @Deprecated
+ // @SuppressWarnings("serial")
+ // @java.io.Serial
static final long serialVersionUID = -8727434096241101194L;
/**
diff --git a/ojluni/src/main/java/java/security/interfaces/package-info.java b/ojluni/src/main/java/java/security/interfaces/package-info.java
index 54c9397..0c0a9b2 100644
--- a/ojluni/src/main/java/java/security/interfaces/package-info.java
+++ b/ojluni/src/main/java/java/security/interfaces/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, 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,17 +42,16 @@
* {@code Key} classes for hardware devices, please refer
* to these cryptographic provider developer guides:
* <ul>
- * <li><a href=
- * "{@docRoot}/../technotes/guides/security/crypto/HowToImplAProvider.html">
- * <b>How to Implement a Provider for the
- * Java™ Cryptography Architecture
- * </b></a></li>
+ * <li>
+ * {@extLink security_guide_impl_provider
+ * How to Implement a Provider in the Java Cryptography Architecture}
+ * </li>
* </ul>
*
* <h2>Package Specification</h2>
*
* <ul>
- * <li>PKCS #1: RSA Encryption Standard, Version 1.5, November 1993 </li>
+ * <li>PKCS #1: RSA Cryptography Specifications, Version 2.2 (RFC 8017)</li>
* <li>Federal Information Processing Standards Publication (FIPS PUB) 186:
* Digital Signature Standard (DSS) </li>
* </ul>
@@ -61,14 +60,10 @@
*
* For further documentation, please see:
* <ul>
- * <li>
- * <a href=
- * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
- * <b>Java™
- * Cryptography Architecture API Specification and Reference
- * </b></a></li>
+ * <li> {extLink security_guide_jca
+ * Java Cryptography Architecture Reference Guide}</li>
* </ul>
*
- * @since JDK1.1
+ * @since 1.1
*/
package java.security.interfaces;
diff --git a/ojluni/src/main/java/java/security/spec/DSAGenParameterSpec.java b/ojluni/src/main/java/java/security/spec/DSAGenParameterSpec.java
new file mode 100644
index 0000000..b51f1f5
--- /dev/null
+++ b/ojluni/src/main/java/java/security/spec/DSAGenParameterSpec.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security.spec;
+
+/**
+ * This immutable class specifies the set of parameters used for
+ * generating DSA parameters as specified in
+ * <a href="http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf">FIPS 186-3 Digital Signature Standard (DSS)</a>.
+ *
+ * @see AlgorithmParameterSpec
+ *
+ * @since 1.8
+ */
+public final class DSAGenParameterSpec implements AlgorithmParameterSpec {
+
+ private final int pLen;
+ private final int qLen;
+ private final int seedLen;
+
+ /**
+ * Creates a domain parameter specification for DSA parameter
+ * generation using {@code primePLen} and {@code subprimeQLen}.
+ * The value of {@code subprimeQLen} is also used as the default
+ * length of the domain parameter seed in bits.
+ * @param primePLen the desired length of the prime P in bits.
+ * @param subprimeQLen the desired length of the sub-prime Q in bits.
+ * @throws IllegalArgumentException if {@code primePLen}
+ * or {@code subprimeQLen} is illegal per the specification of
+ * FIPS 186-3.
+ */
+ public DSAGenParameterSpec(int primePLen, int subprimeQLen) {
+ this(primePLen, subprimeQLen, subprimeQLen);
+ }
+
+ /**
+ * Creates a domain parameter specification for DSA parameter
+ * generation using {@code primePLen}, {@code subprimeQLen},
+ * and {@code seedLen}.
+ * @param primePLen the desired length of the prime P in bits.
+ * @param subprimeQLen the desired length of the sub-prime Q in bits.
+ * @param seedLen the desired length of the domain parameter seed in bits,
+ * shall be equal to or greater than {@code subprimeQLen}.
+ * @throws IllegalArgumentException if {@code primePLenLen},
+ * {@code subprimeQLen}, or {@code seedLen} is illegal per the
+ * specification of FIPS 186-3.
+ */
+ public DSAGenParameterSpec(int primePLen, int subprimeQLen, int seedLen) {
+ switch (primePLen) {
+ case 1024:
+ if (subprimeQLen != 160) {
+ throw new IllegalArgumentException
+ ("subprimeQLen must be 160 when primePLen=1024");
+ }
+ break;
+ case 2048:
+ if (subprimeQLen != 224 && subprimeQLen != 256) {
+ throw new IllegalArgumentException
+ ("subprimeQLen must be 224 or 256 when primePLen=2048");
+ }
+ break;
+ case 3072:
+ if (subprimeQLen != 256) {
+ throw new IllegalArgumentException
+ ("subprimeQLen must be 256 when primePLen=3072");
+ }
+ break;
+ default:
+ throw new IllegalArgumentException
+ ("primePLen must be 1024, 2048, or 3072");
+ }
+ if (seedLen < subprimeQLen) {
+ throw new IllegalArgumentException
+ ("seedLen must be equal to or greater than subprimeQLen");
+ }
+ this.pLen = primePLen;
+ this.qLen = subprimeQLen;
+ this.seedLen = seedLen;
+ }
+
+ /**
+ * Returns the desired length of the prime P of the
+ * to-be-generated DSA domain parameters in bits.
+ * @return the length of the prime P.
+ */
+ public int getPrimePLength() {
+ return pLen;
+ }
+
+ /**
+ * Returns the desired length of the sub-prime Q of the
+ * to-be-generated DSA domain parameters in bits.
+ * @return the length of the sub-prime Q.
+ */
+ public int getSubprimeQLength() {
+ return qLen;
+ }
+
+ /**
+ * Returns the desired length of the domain parameter seed in bits.
+ * @return the length of the domain parameter seed.
+ */
+ public int getSeedLength() {
+ return seedLen;
+ }
+}
diff --git a/ojluni/src/main/java/java/security/spec/EdDSAParameterSpec.java b/ojluni/src/main/java/java/security/spec/EdDSAParameterSpec.java
new file mode 100644
index 0000000..d66689b
--- /dev/null
+++ b/ojluni/src/main/java/java/security/spec/EdDSAParameterSpec.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.security.InvalidParameterException;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * A class used to specify EdDSA signature and verification parameters. All
+ * algorithm modes in <a href="https://tools.ietf.org/html/rfc8032">RFC 8032:
+ * Edwards-Curve Digital Signature Algorithm (EdDSA)</a> can be specified using
+ * combinations of the settings in this class.
+ *
+ * <ul>
+ * <li>If prehash is true, then the mode is Ed25519ph or Ed448ph</li>
+ * <li>Otherwise, if a context is present, the mode is Ed25519ctx or Ed448</li>
+ * <li>Otherwise, the mode is Ed25519 or Ed448</li>
+ * </ul>
+ *
+ * @since 15
+ */
+
+public class EdDSAParameterSpec implements AlgorithmParameterSpec {
+
+ private final boolean prehash;
+ private final byte[] context;
+
+ /**
+ * Construct an {@code EdDSAParameterSpec} by specifying whether the prehash mode
+ * is used. No context is provided so this constructor specifies a mode
+ * in which the context is null. Note that this mode may be different
+ * than the mode in which an empty array is used as the context.
+ *
+ * @param prehash whether the prehash mode is specified.
+ */
+ public EdDSAParameterSpec(boolean prehash) {
+ this.prehash = prehash;
+ this.context = null;
+ }
+
+ /**
+ * Construct an {@code EdDSAParameterSpec} by specifying a context and whether the
+ * prehash mode is used. The context may not be null, but it may be an
+ * empty array. The mode used when the context is an empty array may not be
+ * the same as the mode used when the context is absent.
+ *
+ * @param prehash whether the prehash mode is specified.
+ * @param context the context is copied and bound to the signature.
+ * @throws NullPointerException if context is null.
+ * @throws InvalidParameterException if context length is greater than 255.
+ */
+ public EdDSAParameterSpec(boolean prehash, byte[] context) {
+
+ Objects.requireNonNull(context, "context may not be null");
+ if (context.length > 255) {
+ throw new InvalidParameterException("context length cannot be " +
+ "greater than 255");
+ }
+
+ this.prehash = prehash;
+ this.context = context.clone();
+ }
+
+ /**
+ * Get whether the prehash mode is specified.
+ *
+ * @return whether the prehash mode is specified.
+ */
+ public boolean isPrehash() {
+ return prehash;
+ }
+
+ /**
+ * Get the context that the signature will use.
+ *
+ * @return {@code Optional} contains a copy of the context or empty
+ * if context is null.
+ */
+ public Optional<byte[]> getContext() {
+ if (context == null) {
+ return Optional.empty();
+ } else {
+ return Optional.of(context.clone());
+ }
+ }
+}
diff --git a/ojluni/src/main/java/java/text/AttributedString.java b/ojluni/src/main/java/java/text/AttributedString.java
index dcfb995..16e9a28 100644
--- a/ojluni/src/main/java/java/text/AttributedString.java
+++ b/ojluni/src/main/java/java/text/AttributedString.java
@@ -776,10 +776,9 @@
if (this == obj) {
return true;
}
- if (!(obj instanceof AttributedStringIterator)) {
+ if (!(obj instanceof AttributedStringIterator that)) {
return false;
}
- AttributedStringIterator that = (AttributedStringIterator) obj;
if (AttributedString.this != that.getString())
return false;
@@ -1095,10 +1094,9 @@
}
public boolean equals(Object o) {
- if (!(o instanceof AttributeEntry)) {
+ if (!(o instanceof AttributeEntry other)) {
return false;
}
- AttributeEntry other = (AttributeEntry) o;
return other.key.equals(key) && Objects.equals(other.value, value);
}
diff --git a/ojluni/src/main/java/java/text/FieldPosition.java b/ojluni/src/main/java/java/text/FieldPosition.java
index 271065c..26d7da7 100644
--- a/ojluni/src/main/java/java/text/FieldPosition.java
+++ b/ojluni/src/main/java/java/text/FieldPosition.java
@@ -221,9 +221,8 @@
public boolean equals(Object obj)
{
if (obj == null) return false;
- if (!(obj instanceof FieldPosition))
+ if (!(obj instanceof FieldPosition other))
return false;
- FieldPosition other = (FieldPosition) obj;
if (attribute == null) {
if (other.attribute != null) {
return false;
diff --git a/ojluni/src/main/java/java/text/ParsePosition.java b/ojluni/src/main/java/java/text/ParsePosition.java
index 454cf46..e24c1bc 100644
--- a/ojluni/src/main/java/java/text/ParsePosition.java
+++ b/ojluni/src/main/java/java/text/ParsePosition.java
@@ -125,9 +125,8 @@
public boolean equals(Object obj)
{
if (obj == null) return false;
- if (!(obj instanceof ParsePosition))
+ if (!(obj instanceof ParsePosition other))
return false;
- ParsePosition other = (ParsePosition) obj;
return (index == other.index && errorIndex == other.errorIndex);
}
diff --git a/ojluni/src/main/java/java/text/PatternEntry.java b/ojluni/src/main/java/java/text/PatternEntry.java
index 09c5b42..858c315 100644
--- a/ojluni/src/main/java/java/text/PatternEntry.java
+++ b/ojluni/src/main/java/java/text/PatternEntry.java
@@ -130,29 +130,15 @@
if (showWhiteSpace)
toAddTo.append(' ');
}
- final char c;
- switch (strength) {
- case Collator.IDENTICAL:
- c = '=';
- break;
- case Collator.TERTIARY:
- c = ',';
- break;
- case Collator.SECONDARY:
- c = ';';
- break;
- case Collator.PRIMARY:
- c = '<';
- break;
- case RESET:
- c = '&';
- break;
- case UNSET:
- c = '?';
- break;
+ var c = switch (strength) {
+ case Collator.IDENTICAL -> '=';
+ case Collator.TERTIARY -> ',';
+ case Collator.SECONDARY -> ';';
+ case Collator.PRIMARY -> '<';
+ case RESET -> '&';
+ case UNSET -> '?';
- default:
- throw new IllegalStateException("Unexpected value: " + strength);
+ default -> throw new IllegalStateException("Unexpected value: " + strength);
};
toAddTo.append(c);
diff --git a/ojluni/src/main/java/java/text/StringCharacterIterator.java b/ojluni/src/main/java/java/text/StringCharacterIterator.java
index 5b8dd3f..bddd466 100644
--- a/ojluni/src/main/java/java/text/StringCharacterIterator.java
+++ b/ojluni/src/main/java/java/text/StringCharacterIterator.java
@@ -240,10 +240,9 @@
{
if (this == obj)
return true;
- if (!(obj instanceof StringCharacterIterator))
+ if (!(obj instanceof StringCharacterIterator that))
return false;
- StringCharacterIterator that = (StringCharacterIterator) obj;
if (hashCode() != that.hashCode())
return false;
if (!text.equals(that.text))
diff --git a/ojluni/src/main/java/java/time/Clock.java b/ojluni/src/main/java/java/time/Clock.java
index 91fa32b..665e681 100644
--- a/ojluni/src/main/java/java/time/Clock.java
+++ b/ojluni/src/main/java/java/time/Clock.java
@@ -664,11 +664,9 @@
}
@Override
public boolean equals(Object obj) {
- if (obj instanceof FixedClock) {
- FixedClock other = (FixedClock) obj;
- return instant.equals(other.instant) && zone.equals(other.zone);
- }
- return false;
+ return obj instanceof FixedClock other
+ && instant.equals(other.instant)
+ && zone.equals(other.zone);
}
@Override
public int hashCode() {
@@ -716,11 +714,9 @@
}
@Override
public boolean equals(Object obj) {
- if (obj instanceof OffsetClock) {
- OffsetClock other = (OffsetClock) obj;
- return baseClock.equals(other.baseClock) && offset.equals(other.offset);
- }
- return false;
+ return obj instanceof OffsetClock other
+ && baseClock.equals(other.baseClock)
+ && offset.equals(other.offset);
}
@Override
public int hashCode() {
@@ -776,11 +772,9 @@
}
@Override
public boolean equals(Object obj) {
- if (obj instanceof TickClock) {
- TickClock other = (TickClock) obj;
- return baseClock.equals(other.baseClock) && tickNanos == other.tickNanos;
- }
- return false;
+ return (obj instanceof TickClock other)
+ && tickNanos == other.tickNanos
+ && baseClock.equals(other.baseClock);
}
@Override
public int hashCode() {
@@ -828,12 +822,9 @@
}
@Override
public boolean equals(Object obj) {
- if (obj instanceof SourceClock) {
- SourceClock other = (SourceClock) obj;
- return zone.equals(other.zone)
- && baseSource.equals(other.baseSource);
- }
- return false;
+ return (obj instanceof SourceClock other)
+ && zone.equals(other.zone)
+ && baseSource.equals(other.baseSource);
}
@Override
public int hashCode() {
diff --git a/ojluni/src/main/java/java/time/Duration.java b/ojluni/src/main/java/java/time/Duration.java
index fe19c3c..48f46ff 100644
--- a/ojluni/src/main/java/java/time/Duration.java
+++ b/ojluni/src/main/java/java/time/Duration.java
@@ -700,8 +700,7 @@
if (amountToAdd == 0) {
return this;
}
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
switch (chronoUnit) {
case NANOS: return plusNanos(amountToAdd);
case MICROS: return plusSeconds((amountToAdd / (1000_000L * 1000)) * 1000).plusNanos((amountToAdd % (1000_000L * 1000)) * 1000);
@@ -1395,12 +1394,9 @@
if (this == other) {
return true;
}
- if (other instanceof Duration) {
- Duration otherDuration = (Duration) other;
- return this.seconds == otherDuration.seconds &&
- this.nanos == otherDuration.nanos;
- }
- return false;
+ return (other instanceof Duration otherDuration)
+ && this.seconds == otherDuration.seconds
+ && this.nanos == otherDuration.nanos;
}
/**
diff --git a/ojluni/src/main/java/java/time/Instant.java b/ojluni/src/main/java/java/time/Instant.java
index d6b6a72..64d4ff3 100644
--- a/ojluni/src/main/java/java/time/Instant.java
+++ b/ojluni/src/main/java/java/time/Instant.java
@@ -696,8 +696,7 @@
*/
@Override
public Instant with(TemporalField field, long newValue) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
chronoField.checkValidValue(newValue);
switch (chronoField) {
case MILLI_OF_SECOND: {
@@ -1136,8 +1135,7 @@
@Override
public long until(Temporal endExclusive, TemporalUnit unit) {
Instant end = Instant.from(endExclusive);
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
switch (chronoUnit) {
case NANOS: return nanosUntil(end);
case MICROS: return nanosUntil(end) / 1000;
@@ -1293,12 +1291,9 @@
if (this == other) {
return true;
}
- if (other instanceof Instant) {
- Instant otherInstant = (Instant) other;
- return this.seconds == otherInstant.seconds &&
- this.nanos == otherInstant.nanos;
- }
- return false;
+ return (other instanceof Instant otherInstant)
+ && this.seconds == otherInstant.seconds
+ && this.nanos == otherInstant.nanos;
}
/**
diff --git a/ojluni/src/main/java/java/time/LocalDate.java b/ojluni/src/main/java/java/time/LocalDate.java
index 89ad3b1..8bf8c45 100644
--- a/ojluni/src/main/java/java/time/LocalDate.java
+++ b/ojluni/src/main/java/java/time/LocalDate.java
@@ -597,8 +597,7 @@
*/
@Override
public ValueRange range(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
if (chronoField.isDateBased()) {
switch (chronoField) {
case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
@@ -1042,8 +1041,7 @@
*/
@Override
public LocalDate with(TemporalField field, long newValue) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
chronoField.checkValidValue(newValue);
switch (chronoField) {
case DAY_OF_WEEK: return plusDays(newValue - getDayOfWeek().getValue());
@@ -1165,8 +1163,7 @@
*/
@Override
public LocalDate plus(TemporalAmount amountToAdd) {
- if (amountToAdd instanceof Period) {
- Period periodToAdd = (Period) amountToAdd;
+ if (amountToAdd instanceof Period periodToAdd) {
return plusMonths(periodToAdd.toTotalMonths()).plusDays(periodToAdd.getDays());
}
Objects.requireNonNull(amountToAdd, "amountToAdd");
@@ -1256,8 +1253,7 @@
*/
@Override
public LocalDate plus(long amountToAdd, TemporalUnit unit) {
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
switch (chronoUnit) {
case DAYS: return plusDays(amountToAdd);
case WEEKS: return plusWeeks(amountToAdd);
@@ -1415,8 +1411,7 @@
*/
@Override
public LocalDate minus(TemporalAmount amountToSubtract) {
- if (amountToSubtract instanceof Period) {
- Period periodToSubtract = (Period) amountToSubtract;
+ if (amountToSubtract instanceof Period periodToSubtract) {
return minusMonths(periodToSubtract.toTotalMonths()).minusDays(periodToSubtract.getDays());
}
Objects.requireNonNull(amountToSubtract, "amountToSubtract");
diff --git a/ojluni/src/main/java/java/time/LocalDateTime.java b/ojluni/src/main/java/java/time/LocalDateTime.java
index 3fa8a14..bfe1874 100644
--- a/ojluni/src/main/java/java/time/LocalDateTime.java
+++ b/ojluni/src/main/java/java/time/LocalDateTime.java
@@ -567,8 +567,7 @@
*/
@Override
public boolean isSupported(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
return chronoField.isDateBased() || chronoField.isTimeBased();
}
return field != null && field.isSupportedBy(this);
@@ -641,8 +640,7 @@
*/
@Override
public ValueRange range(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
return (chronoField.isTimeBased() ? time.range(field) : date.range(field));
}
return field.rangeRefinedBy(this);
@@ -678,8 +676,7 @@
*/
@Override
public int get(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
return (chronoField.isTimeBased() ? time.get(field) : date.get(field));
}
return ChronoLocalDateTime.super.get(field);
@@ -710,8 +707,7 @@
*/
@Override
public long getLong(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
return (chronoField.isTimeBased() ? time.getLong(field) : date.getLong(field));
}
return field.getFrom(this);
@@ -957,8 +953,7 @@
*/
@Override
public LocalDateTime with(TemporalField field, long newValue) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
if (chronoField.isTimeBased()) {
return with(date, time.with(field, newValue));
} else {
@@ -1139,8 +1134,7 @@
*/
@Override
public LocalDateTime plus(TemporalAmount amountToAdd) {
- if (amountToAdd instanceof Period) {
- Period periodToAdd = (Period) amountToAdd;
+ if (amountToAdd instanceof Period periodToAdd) {
return with(date.plus(periodToAdd), time);
}
Objects.requireNonNull(amountToAdd, "amountToAdd");
@@ -1175,8 +1169,7 @@
*/
@Override
public LocalDateTime plus(long amountToAdd, TemporalUnit unit) {
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
switch (chronoUnit) {
case NANOS: return plusNanos(amountToAdd);
case MICROS: return plusDays(amountToAdd / MICROS_PER_DAY).plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
@@ -1358,8 +1351,7 @@
*/
@Override
public LocalDateTime minus(TemporalAmount amountToSubtract) {
- if (amountToSubtract instanceof Period) {
- Period periodToSubtract = (Period) amountToSubtract;
+ if (amountToSubtract instanceof Period periodToSubtract) {
return with(date.minus(periodToSubtract), time);
}
Objects.requireNonNull(amountToSubtract, "amountToSubtract");
@@ -1676,8 +1668,7 @@
@Override
public long until(Temporal endExclusive, TemporalUnit unit) {
LocalDateTime end = LocalDateTime.from(endExclusive);
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
if (unit.isTimeBased()) {
long amount = date.daysUntil(end.date);
if (amount == 0) {
@@ -1929,11 +1920,9 @@
if (this == obj) {
return true;
}
- if (obj instanceof LocalDateTime) {
- LocalDateTime other = (LocalDateTime) obj;
- return date.equals(other.date) && time.equals(other.time);
- }
- return false;
+ return (obj instanceof LocalDateTime other)
+ && date.equals(other.date)
+ && time.equals(other.time);
}
/**
diff --git a/ojluni/src/main/java/java/time/LocalTime.java b/ojluni/src/main/java/java/time/LocalTime.java
index 91fb967..419d920 100644
--- a/ojluni/src/main/java/java/time/LocalTime.java
+++ b/ojluni/src/main/java/java/time/LocalTime.java
@@ -849,8 +849,7 @@
*/
@Override
public LocalTime with(TemporalField field, long newValue) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
chronoField.checkValidValue(newValue);
switch (chronoField) {
case NANO_OF_SECOND: return withNano((int) newValue);
@@ -1060,8 +1059,7 @@
*/
@Override
public LocalTime plus(long amountToAdd, TemporalUnit unit) {
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
switch (chronoUnit) {
case NANOS: return plusNanos(amountToAdd);
case MICROS: return plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
@@ -1402,8 +1400,7 @@
@Override
public long until(Temporal endExclusive, TemporalUnit unit) {
LocalTime end = LocalTime.from(endExclusive);
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
long nanosUntil = end.toNanoOfDay() - toNanoOfDay(); // no overflow
switch (chronoUnit) {
case NANOS: return nanosUntil;
@@ -1582,12 +1579,11 @@
if (this == obj) {
return true;
}
- if (obj instanceof LocalTime) {
- LocalTime other = (LocalTime) obj;
- return hour == other.hour && minute == other.minute &&
- second == other.second && nano == other.nano;
- }
- return false;
+ return (obj instanceof LocalTime other)
+ && hour == other.hour
+ && minute == other.minute
+ && second == other.second
+ && nano == other.nano;
}
/**
diff --git a/ojluni/src/main/java/java/time/MonthDay.java b/ojluni/src/main/java/java/time/MonthDay.java
index 4f06f45..7e3eda0 100644
--- a/ojluni/src/main/java/java/time/MonthDay.java
+++ b/ojluni/src/main/java/java/time/MonthDay.java
@@ -437,8 +437,7 @@
*/
@Override
public long getLong(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
switch (chronoField) {
// alignedDOW and alignedWOM not supported because they cannot be set in with()
case DAY_OF_MONTH: return day;
@@ -714,11 +713,9 @@
if (this == obj) {
return true;
}
- if (obj instanceof MonthDay) {
- MonthDay other = (MonthDay) obj;
- return month == other.month && day == other.day;
- }
- return false;
+ return (obj instanceof MonthDay other)
+ && month == other.month
+ && day == other.day;
}
/**
diff --git a/ojluni/src/main/java/java/time/OffsetDateTime.java b/ojluni/src/main/java/java/time/OffsetDateTime.java
index 4fde272..957dc40 100644
--- a/ojluni/src/main/java/java/time/OffsetDateTime.java
+++ b/ojluni/src/main/java/java/time/OffsetDateTime.java
@@ -589,8 +589,7 @@
*/
@Override
public int get(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
switch (chronoField) {
case INSTANT_SECONDS:
throw new UnsupportedTemporalTypeException("Invalid field 'InstantSeconds' for get() method, use getLong() instead");
@@ -627,8 +626,7 @@
*/
@Override
public long getLong(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
switch (chronoField) {
case INSTANT_SECONDS: return toEpochSecond();
case OFFSET_SECONDS: return getOffset().getTotalSeconds();
@@ -962,8 +960,7 @@
*/
@Override
public OffsetDateTime with(TemporalField field, long newValue) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
switch (chronoField) {
case INSTANT_SECONDS: return ofInstant(Instant.ofEpochSecond(newValue, getNano()), offset);
case OFFSET_SECONDS: {
@@ -1876,11 +1873,9 @@
if (this == obj) {
return true;
}
- if (obj instanceof OffsetDateTime) {
- OffsetDateTime other = (OffsetDateTime) obj;
- return dateTime.equals(other.dateTime) && offset.equals(other.offset);
- }
- return false;
+ return (obj instanceof OffsetDateTime other)
+ && dateTime.equals(other.dateTime)
+ && offset.equals(other.offset);
}
/**
diff --git a/ojluni/src/main/java/java/time/OffsetTime.java b/ojluni/src/main/java/java/time/OffsetTime.java
index 3b05852..c569393 100644
--- a/ojluni/src/main/java/java/time/OffsetTime.java
+++ b/ojluni/src/main/java/java/time/OffsetTime.java
@@ -1171,8 +1171,7 @@
@Override
public long until(Temporal endExclusive, TemporalUnit unit) {
OffsetTime end = OffsetTime.from(endExclusive);
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
long nanosUntil = end.toEpochNano() - toEpochNano(); // no overflow
switch (chronoUnit) {
case NANOS: return nanosUntil;
@@ -1354,11 +1353,9 @@
if (this == obj) {
return true;
}
- if (obj instanceof OffsetTime) {
- OffsetTime other = (OffsetTime) obj;
- return time.equals(other.time) && offset.equals(other.offset);
- }
- return false;
+ return (obj instanceof OffsetTime other)
+ && time.equals(other.time)
+ && offset.equals(other.offset);
}
/**
diff --git a/ojluni/src/main/java/java/time/Period.java b/ojluni/src/main/java/java/time/Period.java
index b89596d..3e671d1 100644
--- a/ojluni/src/main/java/java/time/Period.java
+++ b/ojluni/src/main/java/java/time/Period.java
@@ -985,13 +985,10 @@
if (this == obj) {
return true;
}
- if (obj instanceof Period) {
- Period other = (Period) obj;
- return years == other.years &&
- months == other.months &&
- days == other.days;
- }
- return false;
+ return (obj instanceof Period other)
+ && years == other.years
+ && months == other.months
+ && days == other.days;
}
/**
diff --git a/ojluni/src/main/java/java/time/Year.java b/ojluni/src/main/java/java/time/Year.java
index 218bf65..b5fa51b 100644
--- a/ojluni/src/main/java/java/time/Year.java
+++ b/ojluni/src/main/java/java/time/Year.java
@@ -489,8 +489,7 @@
*/
@Override
public long getLong(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
switch (chronoField) {
case YEAR_OF_ERA: return (year < 1 ? 1 - year : year);
case YEAR: return year;
@@ -613,8 +612,7 @@
*/
@Override
public Year with(TemporalField field, long newValue) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
chronoField.checkValidValue(newValue);
switch (chronoField) {
case YEAR_OF_ERA: return Year.of((int) (year < 1 ? 1 - newValue : newValue));
@@ -702,8 +700,7 @@
*/
@Override
public Year plus(long amountToAdd, TemporalUnit unit) {
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
switch (chronoUnit) {
case YEARS: return plusYears(amountToAdd);
case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
@@ -909,8 +906,7 @@
@Override
public long until(Temporal endExclusive, TemporalUnit unit) {
Year end = Year.from(endExclusive);
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
long yearsUntil = ((long) end.year) - year; // no overflow
switch (chronoUnit) {
case YEARS: return yearsUntil;
diff --git a/ojluni/src/main/java/java/time/YearMonth.java b/ojluni/src/main/java/java/time/YearMonth.java
index 5402eb8..769199f 100644
--- a/ojluni/src/main/java/java/time/YearMonth.java
+++ b/ojluni/src/main/java/java/time/YearMonth.java
@@ -478,8 +478,7 @@
*/
@Override
public long getLong(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
switch (chronoField) {
case MONTH_OF_YEAR: return month;
case PROLEPTIC_MONTH: return getProlepticMonth();
@@ -676,8 +675,7 @@
*/
@Override
public YearMonth with(TemporalField field, long newValue) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
chronoField.checkValidValue(newValue);
switch (chronoField) {
case MONTH_OF_YEAR: return withMonth((int) newValue);
@@ -799,8 +797,7 @@
*/
@Override
public YearMonth plus(long amountToAdd, TemporalUnit unit) {
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
switch (chronoUnit) {
case MONTHS: return plusMonths(amountToAdd);
case YEARS: return plusYears(amountToAdd);
@@ -1041,8 +1038,7 @@
@Override
public long until(Temporal endExclusive, TemporalUnit unit) {
YearMonth end = YearMonth.from(endExclusive);
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
long monthsUntil = end.getProlepticMonth() - getProlepticMonth(); // no overflow
switch (chronoUnit) {
case MONTHS: return monthsUntil;
@@ -1164,11 +1160,9 @@
if (this == obj) {
return true;
}
- if (obj instanceof YearMonth) {
- YearMonth other = (YearMonth) obj;
- return year == other.year && month == other.month;
- }
- return false;
+ return (obj instanceof YearMonth other)
+ && year == other.year
+ && month == other.month;
}
/**
diff --git a/ojluni/src/main/java/java/time/ZoneId.java b/ojluni/src/main/java/java/time/ZoneId.java
index d5c302b..5a83651 100644
--- a/ojluni/src/main/java/java/time/ZoneId.java
+++ b/ojluni/src/main/java/java/time/ZoneId.java
@@ -592,12 +592,8 @@
if (this == obj) {
return true;
}
-
- if (obj instanceof ZoneId) {
- ZoneId other = (ZoneId) obj;
- return getId().equals(other.getId());
- }
- return false;
+ return (obj instanceof ZoneId other)
+ && getId().equals(other.getId());
}
/**
diff --git a/ojluni/src/main/java/java/time/ZonedDateTime.java b/ojluni/src/main/java/java/time/ZonedDateTime.java
index d96d544..bbafda9 100644
--- a/ojluni/src/main/java/java/time/ZonedDateTime.java
+++ b/ojluni/src/main/java/java/time/ZonedDateTime.java
@@ -806,8 +806,7 @@
*/
@Override // override for Javadoc and performance
public int get(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
switch (chronoField) {
case INSTANT_SECONDS:
throw new UnsupportedTemporalTypeException("Invalid field 'InstantSeconds' for get() method, use getLong() instead");
@@ -844,8 +843,7 @@
*/
@Override
public long getLong(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
switch (chronoField) {
case INSTANT_SECONDS: return toEpochSecond();
case OFFSET_SECONDS: return getOffset().getTotalSeconds();
@@ -1231,11 +1229,9 @@
return resolveLocal(LocalDateTime.of(dateTime.toLocalDate(), (LocalTime) adjuster));
} else if (adjuster instanceof LocalDateTime) {
return resolveLocal((LocalDateTime) adjuster);
- } else if (adjuster instanceof OffsetDateTime) {
- OffsetDateTime odt = (OffsetDateTime) adjuster;
+ } else if (adjuster instanceof OffsetDateTime odt) {
return ofLocal(odt.toLocalDateTime(), zone, odt.getOffset());
- } else if (adjuster instanceof Instant) {
- Instant instant = (Instant) adjuster;
+ } else if (adjuster instanceof Instant instant) {
return create(instant.getEpochSecond(), instant.getNano(), zone);
} else if (adjuster instanceof ZoneOffset) {
return resolveOffset((ZoneOffset) adjuster);
@@ -1297,8 +1293,7 @@
*/
@Override
public ZonedDateTime with(TemporalField field, long newValue) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
switch (chronoField) {
case INSTANT_SECONDS:
return create(newValue, getNano(), zone);
@@ -1548,8 +1543,7 @@
*/
@Override
public ZonedDateTime plus(TemporalAmount amountToAdd) {
- if (amountToAdd instanceof Period) {
- Period periodToAdd = (Period) amountToAdd;
+ if (amountToAdd instanceof Period periodToAdd) {
return resolveLocal(dateTime.plus(periodToAdd));
}
Objects.requireNonNull(amountToAdd, "amountToAdd");
@@ -1805,8 +1799,7 @@
*/
@Override
public ZonedDateTime minus(TemporalAmount amountToSubtract) {
- if (amountToSubtract instanceof Period) {
- Period periodToSubtract = (Period) amountToSubtract;
+ if (amountToSubtract instanceof Period periodToSubtract) {
return resolveLocal(dateTime.minus(periodToSubtract));
}
Objects.requireNonNull(amountToSubtract, "amountToSubtract");
@@ -2185,13 +2178,10 @@
if (this == obj) {
return true;
}
- if (obj instanceof ZonedDateTime) {
- ZonedDateTime other = (ZonedDateTime) obj;
- return dateTime.equals(other.dateTime) &&
- offset.equals(other.offset) &&
- zone.equals(other.zone);
- }
- return false;
+ return obj instanceof ZonedDateTime other
+ && dateTime.equals(other.dateTime)
+ && offset.equals(other.offset)
+ && zone.equals(other.zone);
}
/**
diff --git a/ojluni/src/main/java/java/time/chrono/ChronoLocalDateImpl.java b/ojluni/src/main/java/java/time/chrono/ChronoLocalDateImpl.java
index 5ed0ef2..e0ee6ec 100644
--- a/ojluni/src/main/java/java/time/chrono/ChronoLocalDateImpl.java
+++ b/ojluni/src/main/java/java/time/chrono/ChronoLocalDateImpl.java
@@ -197,8 +197,7 @@
@Override
@SuppressWarnings("unchecked")
public D plus(long amountToAdd, TemporalUnit unit) {
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
switch (chronoUnit) {
case DAYS: return plusDays(amountToAdd);
case WEEKS: return plusDays(Math.multiplyExact(amountToAdd, 7));
@@ -377,8 +376,7 @@
public long until(Temporal endExclusive, TemporalUnit unit) {
Objects.requireNonNull(endExclusive, "endExclusive");
ChronoLocalDate end = getChronology().date(endExclusive);
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
switch (chronoUnit) {
case DAYS: return daysUntil(end);
case WEEKS: return daysUntil(end) / 7;
diff --git a/ojluni/src/main/java/java/time/chrono/ChronoLocalDateTimeImpl.java b/ojluni/src/main/java/java/time/chrono/ChronoLocalDateTimeImpl.java
index 0221551..655dfec 100644
--- a/ojluni/src/main/java/java/time/chrono/ChronoLocalDateTimeImpl.java
+++ b/ojluni/src/main/java/java/time/chrono/ChronoLocalDateTimeImpl.java
@@ -238,8 +238,7 @@
//-----------------------------------------------------------------------
@Override
public boolean isSupported(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
return chronoField.isDateBased() || chronoField.isTimeBased();
}
return field != null && field.isSupportedBy(this);
@@ -247,8 +246,7 @@
@Override
public ValueRange range(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
return (chronoField.isTimeBased() ? time.range(field) : date.range(field));
}
return field.rangeRefinedBy(this);
@@ -256,8 +254,7 @@
@Override
public int get(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
return (chronoField.isTimeBased() ? time.get(field) : date.get(field));
}
return range(field).checkValidIntValue(getLong(field), field);
@@ -265,8 +262,7 @@
@Override
public long getLong(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
return (chronoField.isTimeBased() ? time.getLong(field) : date.getLong(field));
}
return field.getFrom(this);
@@ -289,8 +285,7 @@
@Override
public ChronoLocalDateTimeImpl<D> with(TemporalField field, long newValue) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
if (chronoField.isTimeBased()) {
return with(date, time.with(field, newValue));
} else {
@@ -303,8 +298,7 @@
//-----------------------------------------------------------------------
@Override
public ChronoLocalDateTimeImpl<D> plus(long amountToAdd, TemporalUnit unit) {
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
switch (chronoUnit) {
case NANOS: return plusNanos(amountToAdd);
case MICROS: return plusDays(amountToAdd / MICROS_PER_DAY).plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
@@ -373,8 +367,7 @@
Objects.requireNonNull(endExclusive, "endExclusive");
@SuppressWarnings("unchecked")
ChronoLocalDateTime<D> end = (ChronoLocalDateTime<D>) getChronology().localDateTime(endExclusive);
- if (unit instanceof ChronoUnit) {
- ChronoUnit chronoUnit = (ChronoUnit) unit;
+ if (unit instanceof ChronoUnit chronoUnit) {
if (unit.isTimeBased()) {
long amount = end.getLong(EPOCH_DAY) - date.getLong(EPOCH_DAY);
switch (chronoUnit) {
diff --git a/ojluni/src/main/java/java/time/chrono/ChronoPeriodImpl.java b/ojluni/src/main/java/java/time/chrono/ChronoPeriodImpl.java
index 2867468..6a41a13 100644
--- a/ojluni/src/main/java/java/time/chrono/ChronoPeriodImpl.java
+++ b/ojluni/src/main/java/java/time/chrono/ChronoPeriodImpl.java
@@ -199,10 +199,9 @@
*/
private ChronoPeriodImpl validateAmount(TemporalAmount amount) {
Objects.requireNonNull(amount, "amount");
- if (!(amount instanceof ChronoPeriodImpl)) {
+ if (!(amount instanceof ChronoPeriodImpl period)) {
throw new DateTimeException("Unable to obtain ChronoPeriod from TemporalAmount: " + amount.getClass());
}
- ChronoPeriodImpl period = (ChronoPeriodImpl) amount;
if (!(chrono.equals(period.getChronology()))) {
throw new ClassCastException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + period.getChronology().getId());
}
@@ -320,12 +319,9 @@
if (this == obj) {
return true;
}
- if (obj instanceof ChronoPeriodImpl) {
- ChronoPeriodImpl other = (ChronoPeriodImpl) obj;
- return years == other.years && months == other.months &&
- days == other.days && chrono.equals(other.chrono);
- }
- return false;
+ return (obj instanceof ChronoPeriodImpl other)
+ && years == other.years && months == other.months
+ && days == other.days && chrono.equals(other.chrono);
}
@Override
diff --git a/ojluni/src/main/java/java/time/chrono/ChronoZonedDateTime.java b/ojluni/src/main/java/java/time/chrono/ChronoZonedDateTime.java
index 237082f..aeaa324 100644
--- a/ojluni/src/main/java/java/time/chrono/ChronoZonedDateTime.java
+++ b/ojluni/src/main/java/java/time/chrono/ChronoZonedDateTime.java
@@ -195,8 +195,7 @@
@Override
default int get(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
switch (chronoField) {
case INSTANT_SECONDS:
throw new UnsupportedTemporalTypeException("Invalid field 'InstantSeconds' for get() method, use getLong() instead");
@@ -210,8 +209,7 @@
@Override
default long getLong(TemporalField field) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
switch (chronoField) {
case INSTANT_SECONDS: return toEpochSecond();
case OFFSET_SECONDS: return getOffset().getTotalSeconds();
diff --git a/ojluni/src/main/java/java/time/chrono/ChronoZonedDateTimeImpl.java b/ojluni/src/main/java/java/time/chrono/ChronoZonedDateTimeImpl.java
index 59cc307..dc0698f 100644
--- a/ojluni/src/main/java/java/time/chrono/ChronoZonedDateTimeImpl.java
+++ b/ojluni/src/main/java/java/time/chrono/ChronoZonedDateTimeImpl.java
@@ -283,8 +283,7 @@
//-----------------------------------------------------------------------
@Override
public ChronoZonedDateTime<D> with(TemporalField field, long newValue) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
switch (chronoField) {
case INSTANT_SECONDS: return plus(newValue - toEpochSecond(), SECONDS);
case OFFSET_SECONDS: {
diff --git a/ojluni/src/main/java/java/time/chrono/HijrahDate.java b/ojluni/src/main/java/java/time/chrono/HijrahDate.java
index 3e02b0a..28ef39e 100644
--- a/ojluni/src/main/java/java/time/chrono/HijrahDate.java
+++ b/ojluni/src/main/java/java/time/chrono/HijrahDate.java
@@ -387,8 +387,7 @@
@Override
public HijrahDate with(TemporalField field, long newValue) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
// not using checkValidIntValue so EPOCH_DAY and PROLEPTIC_MONTH work
chrono.range(chronoField).checkValidValue(newValue, chronoField); // TODO: validate value
int nvalue = (int) newValue;
@@ -621,14 +620,11 @@
if (this == obj) {
return true;
}
- if (obj instanceof HijrahDate) {
- HijrahDate otherDate = (HijrahDate) obj;
- return prolepticYear == otherDate.prolepticYear
- && this.monthOfYear == otherDate.monthOfYear
- && this.dayOfMonth == otherDate.dayOfMonth
- && getChronology().equals(otherDate.getChronology());
- }
- return false;
+ return (obj instanceof HijrahDate otherDate)
+ && prolepticYear == otherDate.prolepticYear
+ && this.monthOfYear == otherDate.monthOfYear
+ && this.dayOfMonth == otherDate.dayOfMonth
+ && getChronology().equals(otherDate.getChronology());
}
/**
diff --git a/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java b/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java
index fa2b65b..6e311d8 100644
--- a/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java
+++ b/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java
@@ -209,10 +209,9 @@
*/
@Override
public JapaneseDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
- if (!(era instanceof JapaneseEra)) {
+ if (!(era instanceof JapaneseEra jera)) {
throw new ClassCastException("Era must be JapaneseEra");
}
- JapaneseEra jera = (JapaneseEra) era;
return JapaneseDate.of(jera, yearOfEra, month, dayOfMonth);
}
diff --git a/ojluni/src/main/java/java/time/chrono/JapaneseDate.java b/ojluni/src/main/java/java/time/chrono/JapaneseDate.java
index c290075..5135b81 100644
--- a/ojluni/src/main/java/java/time/chrono/JapaneseDate.java
+++ b/ojluni/src/main/java/java/time/chrono/JapaneseDate.java
@@ -510,8 +510,7 @@
//-----------------------------------------------------------------------
@Override
public JapaneseDate with(TemporalField field, long newValue) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
if (getLong(chronoField) == newValue) { // getLong() validates for supported fields
return this;
}
@@ -693,11 +692,8 @@
if (this == obj) {
return true;
}
- if (obj instanceof JapaneseDate) {
- JapaneseDate otherDate = (JapaneseDate) obj;
- return this.isoDate.equals(otherDate.isoDate);
- }
- return false;
+ return (obj instanceof JapaneseDate otherDate)
+ && this.isoDate.equals(otherDate.isoDate);
}
/**
diff --git a/ojluni/src/main/java/java/time/chrono/MinguoDate.java b/ojluni/src/main/java/java/time/chrono/MinguoDate.java
index 9264c99..363841f 100644
--- a/ojluni/src/main/java/java/time/chrono/MinguoDate.java
+++ b/ojluni/src/main/java/java/time/chrono/MinguoDate.java
@@ -304,8 +304,7 @@
//-----------------------------------------------------------------------
@Override
public MinguoDate with(TemporalField field, long newValue) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
if (getLong(chronoField) == newValue) {
return this;
}
@@ -452,11 +451,8 @@
if (this == obj) {
return true;
}
- if (obj instanceof MinguoDate) {
- MinguoDate otherDate = (MinguoDate) obj;
- return this.isoDate.equals(otherDate.isoDate);
- }
- return false;
+ return (obj instanceof MinguoDate otherDate)
+ && this.isoDate.equals(otherDate.isoDate);
}
/**
diff --git a/ojluni/src/main/java/java/time/chrono/ThaiBuddhistDate.java b/ojluni/src/main/java/java/time/chrono/ThaiBuddhistDate.java
index 2321276..0341c8c 100644
--- a/ojluni/src/main/java/java/time/chrono/ThaiBuddhistDate.java
+++ b/ojluni/src/main/java/java/time/chrono/ThaiBuddhistDate.java
@@ -304,8 +304,7 @@
//-----------------------------------------------------------------------
@Override
public ThaiBuddhistDate with(TemporalField field, long newValue) {
- if (field instanceof ChronoField) {
- ChronoField chronoField = (ChronoField) field;
+ if (field instanceof ChronoField chronoField) {
if (getLong(chronoField) == newValue) {
return this;
}
@@ -452,11 +451,8 @@
if (this == obj) {
return true;
}
- if (obj instanceof ThaiBuddhistDate) {
- ThaiBuddhistDate otherDate = (ThaiBuddhistDate) obj;
- return this.isoDate.equals(otherDate.isoDate);
- }
- return false;
+ return (obj instanceof ThaiBuddhistDate otherDate)
+ && this.isoDate.equals(otherDate.isoDate);
}
/**
diff --git a/ojluni/src/main/java/java/time/format/DateTimeFormatterBuilder.java b/ojluni/src/main/java/java/time/format/DateTimeFormatterBuilder.java
index 95cb481..4028d22 100644
--- a/ojluni/src/main/java/java/time/format/DateTimeFormatterBuilder.java
+++ b/ojluni/src/main/java/java/time/format/DateTimeFormatterBuilder.java
@@ -5383,21 +5383,21 @@
* @return the array index
*/
static long mapToIndex(String type) {
- switch (type) {
- case "am": return Calendar.AM;
- case "pm": return Calendar.PM;
- case "midnight": return 2;
- case "noon": return 3;
- case "morning1": return 4;
- case "morning2": return 5;
- case "afternoon1": return 6;
- case "afternoon2": return 7;
- case "evening1": return 8;
- case "evening2": return 9;
- case "night1": return 10;
- case "night2": return 11;
- default: throw new InternalError("invalid day period type");
- }
+ return switch (type) {
+ case "am" -> Calendar.AM;
+ case "pm" -> Calendar.PM;
+ case "midnight" -> 2;
+ case "noon" -> 3;
+ case "morning1" -> 4;
+ case "morning2" -> 5;
+ case "afternoon1" -> 6;
+ case "afternoon2" -> 7;
+ case "evening1" -> 8;
+ case "evening2" -> 9;
+ case "night1" -> 10;
+ case "night2" -> 11;
+ default -> throw new InternalError("invalid day period type");
+ };
}
// BEGIN Android-removed: Remove day period support.
diff --git a/ojluni/src/main/java/java/time/format/DecimalStyle.java b/ojluni/src/main/java/java/time/format/DecimalStyle.java
index 632eac5..e969aef 100644
--- a/ojluni/src/main/java/java/time/format/DecimalStyle.java
+++ b/ojluni/src/main/java/java/time/format/DecimalStyle.java
@@ -353,12 +353,11 @@
if (this == obj) {
return true;
}
- if (obj instanceof DecimalStyle) {
- DecimalStyle other = (DecimalStyle) obj;
- return (zeroDigit == other.zeroDigit && positiveSign == other.positiveSign &&
- negativeSign == other.negativeSign && decimalSeparator == other.decimalSeparator);
- }
- return false;
+ return (obj instanceof DecimalStyle other
+ && zeroDigit == other.zeroDigit
+ && positiveSign == other.positiveSign
+ && negativeSign == other.negativeSign
+ && decimalSeparator == other.decimalSeparator);
}
/**
diff --git a/ojluni/src/main/java/java/time/format/Parsed.java b/ojluni/src/main/java/java/time/format/Parsed.java
index 774a3ab..567c270 100644
--- a/ojluni/src/main/java/java/time/format/Parsed.java
+++ b/ojluni/src/main/java/java/time/format/Parsed.java
@@ -282,8 +282,7 @@
TemporalField targetField = entry.getKey();
TemporalAccessor resolvedObject = targetField.resolve(fieldValues, this, resolverStyle);
if (resolvedObject != null) {
- if (resolvedObject instanceof ChronoZonedDateTime<?>) {
- ChronoZonedDateTime<?> czdt = (ChronoZonedDateTime<?>) resolvedObject;
+ if (resolvedObject instanceof ChronoZonedDateTime<?> czdt) {
if (zone == null) {
zone = czdt.getZone();
} else if (zone.equals(czdt.getZone()) == false) {
@@ -291,8 +290,7 @@
}
resolvedObject = czdt.toLocalDateTime();
}
- if (resolvedObject instanceof ChronoLocalDateTime<?>) {
- ChronoLocalDateTime<?> cldt = (ChronoLocalDateTime<?>) resolvedObject;
+ if (resolvedObject instanceof ChronoLocalDateTime<?> cldt) {
updateCheckConflict(cldt.toLocalTime(), Period.ZERO);
updateCheckConflict(cldt.toLocalDate());
changedCount++;
diff --git a/ojluni/src/main/java/java/time/temporal/ValueRange.java b/ojluni/src/main/java/java/time/temporal/ValueRange.java
index 022e2c4..b17f56c 100644
--- a/ojluni/src/main/java/java/time/temporal/ValueRange.java
+++ b/ojluni/src/main/java/java/time/temporal/ValueRange.java
@@ -393,12 +393,11 @@
if (obj == this) {
return true;
}
- if (obj instanceof ValueRange) {
- ValueRange other = (ValueRange) obj;
- return minSmallest == other.minSmallest && minLargest == other.minLargest &&
- maxSmallest == other.maxSmallest && maxLargest == other.maxLargest;
- }
- return false;
+ return (obj instanceof ValueRange other)
+ && minSmallest == other.minSmallest
+ && minLargest == other.minLargest
+ && maxSmallest == other.maxSmallest
+ && maxLargest == other.maxLargest;
}
/**
diff --git a/ojluni/src/main/java/java/time/zone/ZoneOffsetTransition.java b/ojluni/src/main/java/java/time/zone/ZoneOffsetTransition.java
index aae552a..3119458 100644
--- a/ojluni/src/main/java/java/time/zone/ZoneOffsetTransition.java
+++ b/ojluni/src/main/java/java/time/zone/ZoneOffsetTransition.java
@@ -421,12 +421,10 @@
if (other == this) {
return true;
}
- if (other instanceof ZoneOffsetTransition) {
- ZoneOffsetTransition d = (ZoneOffsetTransition) other;
- return epochSecond == d.epochSecond &&
- offsetBefore.equals(d.offsetBefore) && offsetAfter.equals(d.offsetAfter);
- }
- return false;
+ return (other instanceof ZoneOffsetTransition d)
+ && epochSecond == d.epochSecond
+ && offsetBefore.equals(d.offsetBefore)
+ && offsetAfter.equals(d.offsetAfter);
}
/**
diff --git a/ojluni/src/main/java/java/time/zone/ZoneOffsetTransitionRule.java b/ojluni/src/main/java/java/time/zone/ZoneOffsetTransitionRule.java
index 9a14ff8..8eb2320 100644
--- a/ojluni/src/main/java/java/time/zone/ZoneOffsetTransitionRule.java
+++ b/ojluni/src/main/java/java/time/zone/ZoneOffsetTransitionRule.java
@@ -519,17 +519,16 @@
if (otherRule == this) {
return true;
}
- if (otherRule instanceof ZoneOffsetTransitionRule) {
- ZoneOffsetTransitionRule other = (ZoneOffsetTransitionRule) otherRule;
- return month == other.month && dom == other.dom && dow == other.dow &&
- timeDefinition == other.timeDefinition &&
- time.equals(other.time) &&
- timeEndOfDay == other.timeEndOfDay &&
- standardOffset.equals(other.standardOffset) &&
- offsetBefore.equals(other.offsetBefore) &&
- offsetAfter.equals(other.offsetAfter);
- }
- return false;
+ return (otherRule instanceof ZoneOffsetTransitionRule other)
+ && month == other.month
+ && dom == other.dom
+ && dow == other.dow
+ && timeDefinition == other.timeDefinition
+ && timeEndOfDay == other.timeEndOfDay
+ && time.equals(other.time)
+ && standardOffset.equals(other.standardOffset)
+ && offsetBefore.equals(other.offsetBefore)
+ && offsetAfter.equals(other.offsetAfter);
}
/**
diff --git a/ojluni/src/main/java/java/time/zone/ZoneRules.java b/ojluni/src/main/java/java/time/zone/ZoneRules.java
index 087f6ba..ebe9fac 100644
--- a/ojluni/src/main/java/java/time/zone/ZoneRules.java
+++ b/ojluni/src/main/java/java/time/zone/ZoneRules.java
@@ -1039,15 +1039,12 @@
if (this == otherRules) {
return true;
}
- if (otherRules instanceof ZoneRules) {
- ZoneRules other = (ZoneRules) otherRules;
- return Arrays.equals(standardTransitions, other.standardTransitions) &&
- Arrays.equals(standardOffsets, other.standardOffsets) &&
- Arrays.equals(savingsInstantTransitions, other.savingsInstantTransitions) &&
- Arrays.equals(wallOffsets, other.wallOffsets) &&
- Arrays.equals(lastRules, other.lastRules);
- }
- return false;
+ return (otherRules instanceof ZoneRules other)
+ && Arrays.equals(standardTransitions, other.standardTransitions)
+ && Arrays.equals(standardOffsets, other.standardOffsets)
+ && Arrays.equals(savingsInstantTransitions, other.savingsInstantTransitions)
+ && Arrays.equals(wallOffsets, other.wallOffsets)
+ && Arrays.equals(lastRules, other.lastRules);
}
/**
diff --git a/ojluni/src/main/java/java/util/AbstractCollection.java b/ojluni/src/main/java/java/util/AbstractCollection.java
index 0fa05a2..4912ac5 100644
--- a/ojluni/src/main/java/java/util/AbstractCollection.java
+++ b/ojluni/src/main/java/java/util/AbstractCollection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
package java.util;
+import jdk.internal.util.ArraysSupport;
+
/**
* This class provides a skeletal implementation of the {@code Collection}
* interface, to minimize the effort required to implement this interface. <p>
@@ -204,14 +206,6 @@
}
/**
- * The maximum size of array to allocate.
- * Some VMs reserve some header words in an array.
- * Attempts to allocate larger arrays may result in
- * OutOfMemoryError: Requested array size exceeds VM limit
- */
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
-
- /**
* Reallocates the array being used within toArray when the iterator
* returned more elements than expected, and finishes filling it from
* the iterator.
@@ -223,29 +217,19 @@
*/
@SuppressWarnings("unchecked")
private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
- int i = r.length;
+ int len = r.length;
+ int i = len;
while (it.hasNext()) {
- int cap = r.length;
- if (i == cap) {
- int newCap = cap + (cap >> 1) + 1;
- // overflow-conscious code
- if (newCap - MAX_ARRAY_SIZE > 0)
- newCap = hugeCapacity(cap + 1);
- r = Arrays.copyOf(r, newCap);
+ if (i == len) {
+ len = ArraysSupport.newLength(len,
+ 1, /* minimum growth */
+ (len >> 1) + 1 /* preferred growth */);
+ r = Arrays.copyOf(r, len);
}
r[i++] = (T)it.next();
}
// trim if overallocated
- return (i == r.length) ? r : Arrays.copyOf(r, i);
- }
-
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError
- ("Required array size too large");
- return (minCapacity > MAX_ARRAY_SIZE) ?
- Integer.MAX_VALUE :
- MAX_ARRAY_SIZE;
+ return (i == len) ? r : Arrays.copyOf(r, i);
}
// Modification Operations
diff --git a/ojluni/src/main/java/java/util/AbstractMap.java b/ojluni/src/main/java/java/util/AbstractMap.java
index 7109d318..925e360 100644
--- a/ojluni/src/main/java/java/util/AbstractMap.java
+++ b/ojluni/src/main/java/java/util/AbstractMap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
@@ -476,9 +476,8 @@
if (o == this)
return true;
- if (!(o instanceof Map))
+ if (!(o instanceof Map<?, ?> m))
return false;
- Map<?,?> m = (Map<?,?>) o;
if (m.size() != size())
return false;
@@ -593,8 +592,11 @@
/**
* An Entry maintaining a key and a value. The value may be
- * changed using the {@code setValue} method. This class
- * facilitates the process of building custom map
+ * changed using the {@code setValue} method. Instances of
+ * this class are not associated with any map's entry-set view.
+ *
+ * @apiNote
+ * This class facilitates the process of building custom map
* implementations. For example, it may be convenient to return
* arrays of {@code SimpleEntry} instances in method
* {@code Map.entrySet().toArray}.
@@ -604,9 +606,12 @@
public static class SimpleEntry<K,V>
implements Entry<K,V>, java.io.Serializable
{
+ @java.io.Serial
private static final long serialVersionUID = -8499721149061103585L;
+ @SuppressWarnings("serial") // Conditionally serializable
private final K key;
+ @SuppressWarnings("serial") // Conditionally serializable
private V value;
/**
@@ -685,10 +690,9 @@
* @see #hashCode
*/
public boolean equals(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry<?,?> e = (Map.Entry<?,?>)o;
- return eq(key, e.getKey()) && eq(value, e.getValue());
+ return o instanceof Map.Entry<?, ?> e
+ && eq(key, e.getKey())
+ && eq(value, e.getValue());
}
/**
@@ -724,19 +728,33 @@
}
/**
- * An Entry maintaining an immutable key and value. This class
- * does not support method {@code setValue}. This class may be
- * convenient in methods that return thread-safe snapshots of
- * key-value mappings.
+ * An unmodifiable Entry maintaining a key and a value. This class
+ * does not support the {@code setValue} method. Instances of
+ * this class are not associated with any map's entry-set view.
+ *
+ * @apiNote
+ * Instances of this class are not necessarily immutable, as the key
+ * and value may be mutable. An instance of <i>this specific class</i>
+ * is unmodifiable, because the key and value references cannot be
+ * changed. A reference of this <i>type</i> may not be unmodifiable,
+ * as a subclass may be modifiable or may provide the appearance of modifiability.
+ * <p>
+ * This class may be convenient in methods that return thread-safe snapshots of
+ * key-value mappings. For alternatives, see the
+ * {@link Map#entry Map::entry} and {@link Map.Entry#copyOf Map.Entry::copyOf}
+ * methods.
*
* @since 1.6
*/
public static class SimpleImmutableEntry<K,V>
implements Entry<K,V>, java.io.Serializable
{
+ @java.io.Serial
private static final long serialVersionUID = 7138329143949025153L;
+ @SuppressWarnings("serial") // Not statically typed as Serializable
private final K key;
+ @SuppressWarnings("serial") // Not statically typed as Serializable
private final V value;
/**
@@ -784,7 +802,10 @@
* Replaces the value corresponding to this entry with the specified
* value (optional operation). This implementation simply throws
* {@code UnsupportedOperationException}, as this class implements
- * an <i>immutable</i> map entry.
+ * an unmodifiable map entry.
+ *
+ * @implSpec
+ * The implementation in this class always throws {@code UnsupportedOperationException}.
*
* @param value new value to be stored in this entry
* @return (Does not return)
@@ -816,10 +837,9 @@
* @see #hashCode
*/
public boolean equals(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry<?,?> e = (Map.Entry<?,?>)o;
- return eq(key, e.getKey()) && eq(value, e.getValue());
+ return o instanceof Map.Entry<?, ?> e
+ && eq(key, e.getKey())
+ && eq(value, e.getValue());
}
/**
diff --git a/ojluni/src/main/java/java/util/ArrayDeque.java b/ojluni/src/main/java/java/util/ArrayDeque.java
index f6e9822..5bf9a87 100644
--- a/ojluni/src/main/java/java/util/ArrayDeque.java
+++ b/ojluni/src/main/java/java/util/ArrayDeque.java
@@ -37,7 +37,6 @@
import java.io.Serializable;
import java.util.function.Consumer;
import java.util.function.Predicate;
-import java.util.function.UnaryOperator;
import jdk.internal.misc.SharedSecrets;
/**
@@ -188,7 +187,7 @@
* sufficient to hold 16 elements.
*/
public ArrayDeque() {
- elements = new Object[16];
+ elements = new Object[16 + 1];
}
/**
@@ -1167,6 +1166,7 @@
}
}
+ @java.io.Serial
private static final long serialVersionUID = 2340985798034038923L;
/**
@@ -1178,6 +1178,7 @@
* followed by all of its elements (each an object reference) in
* first-to-last order.
*/
+ @java.io.Serial
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();
@@ -1202,6 +1203,7 @@
* could not be found
* @throws java.io.IOException if an I/O error occurs
*/
+ @java.io.Serial
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
diff --git a/ojluni/src/main/java/java/util/ArrayList.java b/ojluni/src/main/java/java/util/ArrayList.java
index 21bd134..350acf3 100644
--- a/ojluni/src/main/java/java/util/ArrayList.java
+++ b/ojluni/src/main/java/java/util/ArrayList.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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.util.function.Predicate;
import java.util.function.UnaryOperator;
import jdk.internal.misc.SharedSecrets;
+import jdk.internal.util.ArraysSupport;
/**
* Resizable-array implementation of the {@code List} interface. Implements
@@ -114,6 +115,7 @@
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
+ @java.io.Serial
private static final long serialVersionUID = 8683452581122892189L;
/**
@@ -227,14 +229,6 @@
}
/**
- * The maximum size of array to allocate (unless necessary).
- * Some VMs reserve some header words in an array.
- * Attempts to allocate larger arrays may result in
- * OutOfMemoryError: Requested array size exceeds VM limit
- */
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
-
- /**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
@@ -242,8 +236,15 @@
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private Object[] grow(int minCapacity) {
- return elementData = Arrays.copyOf(elementData,
- newCapacity(minCapacity));
+ int oldCapacity = elementData.length;
+ if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
+ int newCapacity = ArraysSupport.newLength(oldCapacity,
+ minCapacity - oldCapacity, /* minimum growth */
+ oldCapacity >> 1 /* preferred growth */);
+ return elementData = Arrays.copyOf(elementData, newCapacity);
+ } else {
+ return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
+ }
}
private Object[] grow() {
@@ -251,39 +252,6 @@
}
/**
- * Returns a capacity at least as large as the given minimum capacity.
- * Returns the current capacity increased by 50% if that suffices.
- * Will not return a capacity greater than MAX_ARRAY_SIZE unless
- * the given minimum capacity is greater than MAX_ARRAY_SIZE.
- *
- * @param minCapacity the desired minimum capacity
- * @throws OutOfMemoryError if minCapacity is less than zero
- */
- private int newCapacity(int minCapacity) {
- // overflow-conscious code
- int oldCapacity = elementData.length;
- int newCapacity = oldCapacity + (oldCapacity >> 1);
- if (newCapacity - minCapacity <= 0) {
- if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
- return Math.max(DEFAULT_CAPACITY, minCapacity);
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return minCapacity;
- }
- return (newCapacity - MAX_ARRAY_SIZE <= 0)
- ? newCapacity
- : hugeCapacity(minCapacity);
- }
-
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return (minCapacity > MAX_ARRAY_SIZE)
- ? Integer.MAX_VALUE
- : MAX_ARRAY_SIZE;
- }
-
- /**
* Returns the number of elements in this list.
*
* @return the number of elements in this list
@@ -890,6 +858,7 @@
* instance is emitted (int), followed by all of its elements
* (each an {@code Object}) in the proper order.
*/
+ @java.io.Serial
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out element count, and any hidden stuff
@@ -917,6 +886,7 @@
* could not be found
* @throws java.io.IOException if an I/O error occurs
*/
+ @java.io.Serial
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
@@ -1747,6 +1717,7 @@
@Override
public void replaceAll(UnaryOperator<E> operator) {
replaceAllRange(operator, 0, size);
+ // TODO(8203662): remove increment of modCount from ...
modCount++;
}
diff --git a/ojluni/src/main/java/java/util/ArrayPrefixHelpers.java b/ojluni/src/main/java/java/util/ArrayPrefixHelpers.java
index 87c04d1..303c779 100644
--- a/ojluni/src/main/java/java/util/ArrayPrefixHelpers.java
+++ b/ojluni/src/main/java/java/util/ArrayPrefixHelpers.java
@@ -103,10 +103,15 @@
static final int MIN_PARTITION = 16;
static final class CumulateTask<T> extends CountedCompleter<Void> {
+ @SuppressWarnings("serial") // Not statically typed as Serializable
final T[] array;
+ @SuppressWarnings("serial") // Not statically typed as Serializable
final BinaryOperator<T> function;
CumulateTask<T> left, right;
- T in, out;
+ @SuppressWarnings("serial") // Not statically typed as Serializable
+ T in;
+ @SuppressWarnings("serial") // Not statically typed as Serializable
+ T out;
final int lo, hi, origin, fence, threshold;
/** Root task constructor */
@@ -251,11 +256,13 @@
}
}
}
+ @java.io.Serial
private static final long serialVersionUID = 5293554502939613543L;
}
static final class LongCumulateTask extends CountedCompleter<Void> {
final long[] array;
+ @SuppressWarnings("serial") // Not statically typed as Serializable
final LongBinaryOperator function;
LongCumulateTask left, right;
long in, out;
@@ -401,11 +408,13 @@
}
}
}
+ @java.io.Serial
private static final long serialVersionUID = -5074099945909284273L;
}
static final class DoubleCumulateTask extends CountedCompleter<Void> {
final double[] array;
+ @SuppressWarnings("serial") // Not statically typed as Serializable
final DoubleBinaryOperator function;
DoubleCumulateTask left, right;
double in, out;
@@ -551,11 +560,13 @@
}
}
}
+ @java.io.Serial
private static final long serialVersionUID = -586947823794232033L;
}
static final class IntCumulateTask extends CountedCompleter<Void> {
final int[] array;
+ @SuppressWarnings("serial") // Not statically typed as Serializable
final IntBinaryOperator function;
IntCumulateTask left, right;
int in, out;
@@ -701,6 +712,7 @@
}
}
}
+ @java.io.Serial
private static final long serialVersionUID = 3731755594596840961L;
}
}
diff --git a/ojluni/src/main/java/java/util/Base64.java b/ojluni/src/main/java/java/util/Base64.java
index ceb7b04..3fe4572 100644
--- a/ojluni/src/main/java/java/util/Base64.java
+++ b/ojluni/src/main/java/java/util/Base64.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,10 +32,7 @@
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
-// Android-removed: class is not present in Android.
-// import sun.nio.cs.ISO_8859_1;
-
-import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.vm.annotation.IntrinsicCandidate;
/**
* This class consists exclusively of static methods for obtaining
@@ -190,6 +187,10 @@
* a method of this class will cause a
* {@link java.lang.NullPointerException NullPointerException} to
* be thrown.
+ * <p> If the encoded byte output of the needed size can not
+ * be allocated, the encode methods of this class will
+ * cause an {@link java.lang.OutOfMemoryError OutOfMemoryError}
+ * to be thrown.
*
* @see Decoder
* @since 1.8
@@ -241,16 +242,37 @@
static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true);
static final Encoder RFC2045 = new Encoder(false, CRLF, MIMELINEMAX, true);
- private final int outLength(int srclen) {
+ /**
+ * Calculates the length of the encoded output bytes.
+ *
+ * @param srclen length of the bytes to encode
+ * @param throwOOME if true, throws OutOfMemoryError if the length of
+ * the encoded bytes overflows; else returns the
+ * length
+ * @return length of the encoded bytes, or -1 if the length overflows
+ *
+ */
+ private final int encodedOutLength(int srclen, boolean throwOOME) {
int len = 0;
- if (doPadding) {
- len = 4 * ((srclen + 2) / 3);
- } else {
- int n = srclen % 3;
- len = 4 * (srclen / 3) + (n == 0 ? 0 : n + 1);
+ try {
+ if (doPadding) {
+ len = Math.multiplyExact(4, (Math.addExact(srclen, 2) / 3));
+ } else {
+ int n = srclen % 3;
+ len = Math.addExact(Math.multiplyExact(4, (srclen / 3)), (n == 0 ? 0 : n + 1));
+ }
+ if (linemax > 0) { // line separators
+ len = Math.addExact(len, (len - 1) / linemax * newline.length);
+ }
+ } catch (ArithmeticException ex) {
+ if (throwOOME) {
+ throw new OutOfMemoryError("Encoded size is too large");
+ } else {
+ // let the caller know that encoded bytes length
+ // is too large
+ len = -1;
+ }
}
- if (linemax > 0) // line separators
- len += (len - 1) / linemax * newline.length;
return len;
}
@@ -265,7 +287,7 @@
* encoded bytes.
*/
public byte[] encode(byte[] src) {
- int len = outLength(src.length); // dst array size
+ int len = encodedOutLength(src.length, true); // dst array size
byte[] dst = new byte[len];
int ret = encode0(src, 0, src.length, dst);
if (ret != dst.length)
@@ -293,8 +315,8 @@
* space for encoding all input bytes.
*/
public int encode(byte[] src, byte[] dst) {
- int len = outLength(src.length); // dst array size
- if (dst.length < len)
+ int len = encodedOutLength(src.length, false); // dst array size
+ if (dst.length < len || len == -1)
throw new IllegalArgumentException(
"Output byte array is too small for encoding all input bytes");
return encode0(src, 0, src.length, dst);
@@ -338,7 +360,7 @@
* @return A newly-allocated byte buffer containing the encoded bytes.
*/
public ByteBuffer encode(ByteBuffer buffer) {
- int len = outLength(buffer.remaining());
+ int len = encodedOutLength(buffer.remaining(), true);
byte[] dst = new byte[len];
int ret = 0;
if (buffer.hasArray()) {
@@ -395,7 +417,7 @@
return new Encoder(isURL, newline, linemax, false);
}
- @HotSpotIntrinsicCandidate
+ @IntrinsicCandidate
private void encodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp, boolean isURL) {
char[] base64 = isURL ? toBase64URL : toBase64;
for (int sp0 = sp, dp0 = dp ; sp0 < sl; ) {
@@ -473,6 +495,10 @@
* a method of this class will cause a
* {@link java.lang.NullPointerException NullPointerException} to
* be thrown.
+ * <p> If the decoded byte output of the needed size can not
+ * be allocated, the decode methods of this class will
+ * cause an {@link java.lang.OutOfMemoryError OutOfMemoryError}
+ * to be thrown.
*
* @see Encoder
* @since 1.8
@@ -535,7 +561,7 @@
* if {@code src} is not in valid Base64 scheme
*/
public byte[] decode(byte[] src) {
- byte[] dst = new byte[outLength(src, 0, src.length)];
+ byte[] dst = new byte[decodedOutLength(src, 0, src.length)];
int ret = decode0(src, 0, src.length, dst);
if (ret != dst.length) {
dst = Arrays.copyOf(dst, ret);
@@ -590,8 +616,8 @@
* does not have enough space for decoding all input bytes.
*/
public int decode(byte[] src, byte[] dst) {
- int len = outLength(src, 0, src.length);
- if (dst.length < len)
+ int len = decodedOutLength(src, 0, src.length);
+ if (dst.length < len || len == -1)
throw new IllegalArgumentException(
"Output byte array is too small for decoding all input bytes");
return decode0(src, 0, src.length, dst);
@@ -616,7 +642,7 @@
* @return A newly-allocated byte buffer containing the decoded bytes
*
* @throws IllegalArgumentException
- * if {@code src} is not in valid Base64 scheme.
+ * if {@code buffer} is not in valid Base64 scheme
*/
public ByteBuffer decode(ByteBuffer buffer) {
int pos0 = buffer.position();
@@ -634,7 +660,7 @@
sp = 0;
sl = src.length;
}
- byte[] dst = new byte[outLength(src, sp, sl)];
+ byte[] dst = new byte[decodedOutLength(src, sp, sl)];
return ByteBuffer.wrap(dst, 0, decode0(src, sp, sl, dst));
} catch (IllegalArgumentException iae) {
buffer.position(pos0);
@@ -662,7 +688,17 @@
return new DecInputStream(is, isURL ? fromBase64URL : fromBase64, isMIME);
}
- private int outLength(byte[] src, int sp, int sl) {
+ /**
+ * Calculates the length of the decoded output bytes.
+ *
+ * @param src the byte array to decode
+ * @param sp the source position
+ * @param sl the source limit
+ *
+ * @return length of the decoded bytes
+ *
+ */
+ private int decodedOutLength(byte[] src, int sp, int sl) {
int[] base64 = isURL ? fromBase64URL : fromBase64;
int paddings = 0;
int len = sl - sp;
@@ -697,7 +733,75 @@
}
if (paddings == 0 && (len & 0x3) != 0)
paddings = 4 - (len & 0x3);
- return 3 * ((len + 3) / 4) - paddings;
+
+ // If len is near to Integer.MAX_VALUE, (len + 3)
+ // can possibly overflow, perform this operation as
+ // long and cast it back to integer when the value comes under
+ // integer limit. The final value will always be in integer
+ // limits
+ return 3 * (int) ((len + 3L) / 4) - paddings;
+ }
+
+ /**
+ * Decodes base64 characters, and returns the number of data bytes
+ * written into the destination array.
+ *
+ * It is the fast path for full 4-byte to 3-byte decoding w/o errors.
+ *
+ * decodeBlock() can be overridden by an arch-specific intrinsic.
+ * decodeBlock can choose to decode all, none, or a variable-sized
+ * prefix of the src bytes. This allows the intrinsic to decode in
+ * chunks of the src that are of a favorable size for the specific
+ * processor it's running on.
+ *
+ * If any illegal base64 bytes are encountered in src by the
+ * intrinsic, the intrinsic must return the actual number of valid
+ * data bytes already written to dst. Note that the '=' pad
+ * character is treated as an illegal Base64 character by
+ * decodeBlock, so it will not process a block of 4 bytes
+ * containing pad characters. However, MIME decoding ignores
+ * illegal characters, so any intrinsic overriding decodeBlock
+ * can choose how to handle illegal characters based on the isMIME
+ * parameter.
+ *
+ * Given the parameters, no length check is possible on dst, so dst
+ * is assumed to be large enough to store the decoded bytes.
+ *
+ * @param src
+ * the source byte array of Base64 encoded bytes
+ * @param sp
+ * the offset into src array to begin reading
+ * @param sl
+ * the offset (exclusive) past the last byte to be converted.
+ * @param dst
+ * the destination byte array of decoded data bytes
+ * @param dp
+ * the offset into dst array to begin writing
+ * @param isURL
+ * boolean, when true decode RFC4648 URL-safe base64 characters
+ * @param isMIME
+ * boolean, when true decode according to RFC2045 (ignore illegal chars)
+ * @return the number of destination data bytes produced
+ */
+ @IntrinsicCandidate
+ private int decodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp, boolean isURL, boolean isMIME) {
+ int[] base64 = isURL ? fromBase64URL : fromBase64;
+ int sl0 = sp + ((sl - sp) & ~0b11);
+ int new_dp = dp;
+ while (sp < sl0) {
+ int b1 = base64[src[sp++] & 0xff];
+ int b2 = base64[src[sp++] & 0xff];
+ int b3 = base64[src[sp++] & 0xff];
+ int b4 = base64[src[sp++] & 0xff];
+ if ((b1 | b2 | b3 | b4) < 0) { // non base64 byte
+ return new_dp - dp;
+ }
+ int bits0 = b1 << 18 | b2 << 12 | b3 << 6 | b4;
+ dst[new_dp++] = (byte)(bits0 >> 16);
+ dst[new_dp++] = (byte)(bits0 >> 8);
+ dst[new_dp++] = (byte)(bits0);
+ }
+ return new_dp - dp;
}
private int decode0(byte[] src, int sp, int sl, byte[] dst) {
@@ -707,24 +811,20 @@
int shiftto = 18; // pos of first byte of 4-byte atom
while (sp < sl) {
- if (shiftto == 18 && sp + 4 < sl) { // fast path
- int sl0 = sp + ((sl - sp) & ~0b11);
- while (sp < sl0) {
- int b1 = base64[src[sp++] & 0xff];
- int b2 = base64[src[sp++] & 0xff];
- int b3 = base64[src[sp++] & 0xff];
- int b4 = base64[src[sp++] & 0xff];
- if ((b1 | b2 | b3 | b4) < 0) { // non base64 byte
- sp -= 4;
- break;
- }
- int bits0 = b1 << 18 | b2 << 12 | b3 << 6 | b4;
- dst[dp++] = (byte)(bits0 >> 16);
- dst[dp++] = (byte)(bits0 >> 8);
- dst[dp++] = (byte)(bits0);
- }
- if (sp >= sl)
- break;
+ if (shiftto == 18 && sp < sl - 4) { // fast path
+ int dl = decodeBlock(src, sp, sl, dst, dp, isURL, isMIME);
+ /*
+ * Calculate how many characters were processed by how many
+ * bytes of data were returned.
+ */
+ int chars_decoded = ((dl + 2) / 3) * 4;
+
+ sp += chars_decoded;
+ dp += dl;
+ }
+ if (sp >= sl) {
+ // we're done
+ break;
}
int b = src[sp++] & 0xff;
if ((b = base64[b]) < 0) {
@@ -919,12 +1019,15 @@
private final InputStream is;
private final boolean isMIME;
- private final int[] base64; // base64 -> byte mapping
- private int bits = 0; // 24-bit buffer for decoding
- private int nextin = 18; // next available "off" in "bits" for input;
- // -> 18, 12, 6, 0
- private int nextout = -8; // next available "off" in "bits" for output;
- // -> 8, 0, -8 (no byte for output)
+ private final int[] base64; // base64 -> byte mapping
+ private int bits = 0; // 24-bit buffer for decoding
+
+ /* writing bit pos inside bits; one of 24 (left, msb), 18, 12, 6, 0 */
+ private int wpos = 0;
+
+ /* reading bit pos inside bits: one of 24 (left, msb), 16, 8, 0 */
+ private int rpos = 0;
+
private boolean eof = false;
private boolean closed = false;
@@ -941,107 +1044,153 @@
return read(sbBuf, 0, 1) == -1 ? -1 : sbBuf[0] & 0xff;
}
- private int eof(byte[] b, int off, int len, int oldOff)
- throws IOException
- {
+ private int leftovers(byte[] b, int off, int pos, int limit) {
eof = true;
- if (nextin != 18) {
- if (nextin == 12)
- throw new IOException("Base64 stream has one un-decoded dangling byte.");
- // treat ending xx/xxx without padding character legal.
- // same logic as v == '=' below
- b[off++] = (byte)(bits >> (16));
- if (nextin == 0) { // only one padding byte
- if (len == 1) { // no enough output space
- bits >>= 8; // shift to lowest byte
- nextout = 0;
- } else {
- b[off++] = (byte) (bits >> 8);
- }
- }
+
+ /*
+ * We use a loop here, as this method is executed only a few times.
+ * Unrolling the loop would probably not contribute much here.
+ */
+ while (rpos - 8 >= wpos && pos != limit) {
+ rpos -= 8;
+ b[pos++] = (byte) (bits >> rpos);
}
- return off == oldOff ? -1 : off - oldOff;
+ return pos - off != 0 || rpos - 8 >= wpos ? pos - off : -1;
}
- private int padding(byte[] b, int off, int len, int oldOff)
- throws IOException
- {
- // = shiftto==18 unnecessary padding
- // x= shiftto==12 dangling x, invalid unit
- // xx= shiftto==6 && missing last '='
- // xx=y or last is not '='
- if (nextin == 18 || nextin == 12 ||
- nextin == 6 && is.read() != '=') {
- throw new IOException("Illegal base64 ending sequence:" + nextin);
+ private int eof(byte[] b, int off, int pos, int limit) throws IOException {
+ /*
+ * pos != limit
+ *
+ * wpos == 18: x dangling single x, invalid unit
+ * accept ending xx or xxx without padding characters
+ */
+ if (wpos == 18) {
+ throw new IOException("Base64 stream has one un-decoded dangling byte.");
}
- b[off++] = (byte)(bits >> (16));
- if (nextin == 0) { // only one padding byte
- if (len == 1) { // no enough output space
- bits >>= 8; // shift to lowest byte
- nextout = 0;
- } else {
- b[off++] = (byte) (bits >> 8);
- }
+ rpos = 24;
+ return leftovers(b, off, pos, limit);
+ }
+
+ private int padding(byte[] b, int off, int pos, int limit) throws IOException {
+ /*
+ * pos != limit
+ *
+ * wpos == 24: = (unnecessary padding)
+ * wpos == 18: x= (dangling single x, invalid unit)
+ * wpos == 12 and missing last '=': xx= (invalid padding)
+ * wpos == 12 and last is not '=': xx=x (invalid padding)
+ */
+ if (wpos >= 18 || wpos == 12 && is.read() != '=') {
+ throw new IOException("Illegal base64 ending sequence:" + wpos);
}
- eof = true;
- return off - oldOff;
+ rpos = 24;
+ return leftovers(b, off, pos, limit);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
- if (closed)
+ if (closed) {
throw new IOException("Stream is closed");
- if (eof && nextout < 0) // eof and no leftover
- return -1;
- if (off < 0 || len < 0 || len > b.length - off)
- throw new IndexOutOfBoundsException();
- int oldOff = off;
- while (nextout >= 0) { // leftover output byte(s) in bits buf
- if (len == 0)
- return off - oldOff;
- b[off++] = (byte)(bits >> nextout);
- len--;
- nextout -= 8;
}
+ Objects.checkFromIndexSize(off, len, b.length);
+ if (len == 0) {
+ return 0;
+ }
+
+ /*
+ * Rather than keeping 2 running vars (e.g., off and len),
+ * we only keep one (pos), while definitely fixing the boundaries
+ * of the range [off, limit).
+ * More specifically, each use of pos as an index in b meets
+ * pos - off >= 0 & limit - pos > 0
+ *
+ * Note that limit can overflow to Integer.MIN_VALUE. However,
+ * as long as comparisons with pos are as coded, there's no harm.
+ */
+ int pos = off;
+ final int limit = off + len;
+ if (eof) {
+ return leftovers(b, off, pos, limit);
+ }
+
+ /*
+ * Leftovers from previous invocation; here, wpos = 0.
+ * There can be at most 2 leftover bytes (rpos <= 16).
+ * Further, b has at least one free place.
+ *
+ * The logic could be coded as a loop, (as in method leftovers())
+ * but the explicit "unrolling" makes it possible to generate
+ * better byte extraction code.
+ */
+ if (rpos == 16) {
+ b[pos++] = (byte) (bits >> 8);
+ rpos = 8;
+ if (pos == limit) {
+ return len;
+ }
+ }
+ if (rpos == 8) {
+ b[pos++] = (byte) bits;
+ rpos = 0;
+ if (pos == limit) {
+ return len;
+ }
+ }
+
bits = 0;
- while (len > 0) {
- int v = is.read();
- if (v == -1) {
- return eof(b, off, len, oldOff);
+ wpos = 24;
+ for (;;) {
+ /* pos != limit & rpos == 0 */
+ final int i = is.read();
+ if (i < 0) {
+ return eof(b, off, pos, limit);
}
- if ((v = base64[v]) < 0) {
- if (v == -2) { // padding byte(s)
- return padding(b, off, len, oldOff);
- }
+ final int v = base64[i];
+ if (v < 0) {
+ /*
+ * i not in alphabet, thus
+ * v == -2: i is '=', the padding
+ * v == -1: i is something else, typically CR or LF
+ */
if (v == -1) {
- if (!isMIME)
- throw new IOException("Illegal base64 character " +
- Integer.toString(v, 16));
- continue; // skip if for rfc2045
+ if (isMIME) {
+ continue;
+ }
+ throw new IOException("Illegal base64 character 0x" +
+ Integer.toHexString(i));
}
- // neve be here
+ return padding(b, off, pos, limit);
}
- bits |= (v << nextin);
- if (nextin == 0) {
- nextin = 18; // clear for next in
- b[off++] = (byte)(bits >> 16);
- if (len == 1) {
- nextout = 8; // 2 bytes left in bits
- break;
- }
- b[off++] = (byte)(bits >> 8);
- if (len == 2) {
- nextout = 0; // 1 byte left in bits
- break;
- }
- b[off++] = (byte)bits;
- len -= 3;
+ wpos -= 6;
+ bits |= v << wpos;
+ if (wpos != 0) {
+ continue;
+ }
+ if (limit - pos >= 3) {
+ /* frequently taken fast path, no need to track rpos */
+ b[pos++] = (byte) (bits >> 16);
+ b[pos++] = (byte) (bits >> 8);
+ b[pos++] = (byte) bits;
bits = 0;
- } else {
- nextin -= 6;
+ wpos = 24;
+ if (pos == limit) {
+ return len;
+ }
+ continue;
}
+
+ /* b has either 1 or 2 free places */
+ b[pos++] = (byte) (bits >> 16);
+ if (pos == limit) {
+ rpos = 16;
+ return len;
+ }
+ b[pos++] = (byte) (bits >> 8);
+ /* pos == limit, no need for an if */
+ rpos = 8;
+ return len;
}
- return off - oldOff;
}
@Override
diff --git a/ojluni/src/main/java/java/util/BitSet.java b/ojluni/src/main/java/java/util/BitSet.java
index c72970d..e0dc042 100644
--- a/ojluni/src/main/java/java/util/BitSet.java
+++ b/ojluni/src/main/java/java/util/BitSet.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -83,6 +83,7 @@
* bit position i % 64 (where bit position 0 refers to the least
* significant bit and 63 refers to the most significant bit).
*/
+ @java.io.Serial
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("bits", long[].class),
};
@@ -104,6 +105,7 @@
private transient boolean sizeIsSticky = false;
/* use serialVersionUID from JDK 1.0.2 for interoperability */
+ @java.io.Serial
private static final long serialVersionUID = 7997698588986878753L;
/**
@@ -293,7 +295,7 @@
* @return a byte array containing a little-endian representation
* of all the bits in this bit set
* @since 1.7
- */
+ */
public byte[] toByteArray() {
int n = wordsInUse;
if (n == 0)
@@ -322,7 +324,7 @@
* @return a long array containing a little-endian representation
* of all the bits in this bit set
* @since 1.7
- */
+ */
public long[] toLongArray() {
return Arrays.copyOf(words, wordsInUse);
}
@@ -1052,7 +1054,7 @@
/**
* Compares this object against the specified object.
* The result is {@code true} if and only if the argument is
- * not {@code null} and is a {@code Bitset} object that has
+ * not {@code null} and is a {@code BitSet} object that has
* exactly the same set of bits set to {@code true} as this bit
* set. That is, for every nonnegative {@code int} index {@code k},
* <pre>((BitSet)obj).get(k) == this.get(k)</pre>
@@ -1064,13 +1066,11 @@
* @see #size()
*/
public boolean equals(Object obj) {
- if (!(obj instanceof BitSet))
+ if (!(obj instanceof BitSet set))
return false;
if (this == obj)
return true;
- BitSet set = (BitSet) obj;
-
checkInvariants();
set.checkInvariants();
@@ -1124,6 +1124,7 @@
* Save the state of the {@code BitSet} instance to a stream (i.e.,
* serialize it).
*/
+ @java.io.Serial
private void writeObject(ObjectOutputStream s)
throws IOException {
@@ -1141,6 +1142,7 @@
* Reconstitute the {@code BitSet} instance from a stream (i.e.,
* deserialize it).
*/
+ @java.io.Serial
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
@@ -1182,9 +1184,13 @@
public String toString() {
checkInvariants();
+ final int MAX_INITIAL_CAPACITY = Integer.MAX_VALUE - 8;
int numBits = (wordsInUse > 128) ?
cardinality() : wordsInUse * BITS_PER_WORD;
- StringBuilder b = new StringBuilder(6*numBits + 2);
+ // Avoid overflow in the case of a humongous numBits
+ int initialCapacity = (numBits <= (MAX_INITIAL_CAPACITY - 2) / 6) ?
+ 6 * numBits + 2 : MAX_INITIAL_CAPACITY;
+ StringBuilder b = new StringBuilder(initialCapacity);
b.append('{');
int i = nextSetBit(0);
diff --git a/ojluni/src/main/java/java/util/Calendar.java b/ojluni/src/main/java/java/util/Calendar.java
index 6658cee..00fb182 100644
--- a/ojluni/src/main/java/java/util/Calendar.java
+++ b/ojluni/src/main/java/java/util/Calendar.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2021, 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
@@ -58,10 +58,10 @@
// Android-changed: Remove "rg" support in the javadoc. See http://b/228322300.
// Android-changed: Support the "fw" extension since Android 13.
/**
- * The <code>Calendar</code> class is an abstract class that provides methods
+ * The {@code Calendar} class is an abstract class that provides methods
* for converting between a specific instant in time and a set of {@link
- * #fields calendar fields} such as <code>YEAR</code>, <code>MONTH</code>,
- * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, and so on, and for
+ * #fields calendar fields} such as {@code YEAR}, {@code MONTH},
+ * {@code DAY_OF_MONTH}, {@code HOUR}, and so on, and for
* manipulating the calendar fields, such as getting the date of the next
* week. An instant in time can be represented by a millisecond value that is
* an offset from the <a id="Epoch"><em>Epoch</em></a>, January 1, 1970
@@ -69,13 +69,13 @@
*
* <p>The class also provides additional fields and methods for
* implementing a concrete calendar system outside the package. Those
- * fields and methods are defined as <code>protected</code>.
+ * fields and methods are defined as {@code protected}.
*
* <p>
- * Like other locale-sensitive classes, <code>Calendar</code> provides a
- * class method, <code>getInstance</code>, for getting a generally useful
- * object of this type. <code>Calendar</code>'s <code>getInstance</code> method
- * returns a <code>Calendar</code> object whose
+ * Like other locale-sensitive classes, {@code Calendar} provides a
+ * class method, {@code getInstance}, for getting a generally useful
+ * object of this type. {@code Calendar}'s {@code getInstance} method
+ * returns a {@code Calendar} object whose
* calendar fields have been initialized with the current date and time:
* <blockquote>
* <pre>
@@ -83,47 +83,47 @@
* </pre>
* </blockquote>
*
- * <p>A <code>Calendar</code> object can produce all the calendar field values
+ * <p>A {@code Calendar} object can produce all the calendar field values
* needed to implement the date-time formatting for a particular language and
* calendar style (for example, Japanese-Gregorian, Japanese-Traditional).
- * <code>Calendar</code> defines the range of values returned by
+ * {@code Calendar} defines the range of values returned by
* certain calendar fields, as well as their meaning. For example,
* the first month of the calendar system has value <code>MONTH ==
* JANUARY</code> for all calendars. Other values are defined by the
- * concrete subclass, such as <code>ERA</code>. See individual field
+ * concrete subclass, such as {@code ERA}. See individual field
* documentation and subclass documentation for details.
*
- * <h3>Getting and Setting Calendar Field Values</h3>
+ * <h2>Getting and Setting Calendar Field Values</h2>
*
- * <p>The calendar field values can be set by calling the <code>set</code>
- * methods. Any field values set in a <code>Calendar</code> will not be
+ * <p>The calendar field values can be set by calling the {@code set}
+ * methods. Any field values set in a {@code Calendar} will not be
* interpreted until it needs to calculate its time value (milliseconds from
* the Epoch) or values of the calendar fields. Calling the
- * <code>get</code>, <code>getTimeInMillis</code>, <code>getTime</code>,
- * <code>add</code> and <code>roll</code> involves such calculation.
+ * {@code get}, {@code getTimeInMillis}, {@code getTime},
+ * {@code add} and {@code roll} involves such calculation.
*
- * <h4>Leniency</h4>
+ * <h3>Leniency</h3>
*
- * <p><code>Calendar</code> has two modes for interpreting the calendar
+ * <p>{@code Calendar} has two modes for interpreting the calendar
* fields, <em>lenient</em> and <em>non-lenient</em>. When a
- * <code>Calendar</code> is in lenient mode, it accepts a wider range of
- * calendar field values than it produces. When a <code>Calendar</code>
- * recomputes calendar field values for return by <code>get()</code>, all of
+ * {@code Calendar} is in lenient mode, it accepts a wider range of
+ * calendar field values than it produces. When a {@code Calendar}
+ * recomputes calendar field values for return by {@code get()}, all of
* the calendar fields are normalized. For example, a lenient
- * <code>GregorianCalendar</code> interprets <code>MONTH == JANUARY</code>,
- * <code>DAY_OF_MONTH == 32</code> as February 1.
-
- * <p>When a <code>Calendar</code> is in non-lenient mode, it throws an
+ * {@code GregorianCalendar} interprets {@code MONTH == JANUARY},
+ * {@code DAY_OF_MONTH == 32} as February 1.
+ *
+ * <p>When a {@code Calendar} is in non-lenient mode, it throws an
* exception if there is any inconsistency in its calendar fields. For
- * example, a <code>GregorianCalendar</code> always produces
- * <code>DAY_OF_MONTH</code> values between 1 and the length of the month. A
- * non-lenient <code>GregorianCalendar</code> throws an exception upon
+ * example, a {@code GregorianCalendar} always produces
+ * {@code DAY_OF_MONTH} values between 1 and the length of the month. A
+ * non-lenient {@code GregorianCalendar} throws an exception upon
* calculating its time or calendar field values if any out-of-range field
* value has been set.
*
- * <h4><a id="first_week">First Week</a></h4>
+ * <h3><a id="first_week">First Week</a></h3>
*
- * <code>Calendar</code> defines a locale-specific seven day week using two
+ * {@code Calendar} defines a locale-specific seven day week using two
* parameters: the first day of the week and the minimal days in first week
* (from 1 to 7). These numbers are taken from the locale resource data or the
* locale itself when a {@code Calendar} is constructed. If the designated
@@ -133,30 +133,30 @@
* They may also be specified explicitly through the methods for setting their
* values.
*
- * <p>When setting or getting the <code>WEEK_OF_MONTH</code> or
- * <code>WEEK_OF_YEAR</code> fields, <code>Calendar</code> must determine the
+ * <p>When setting or getting the {@code WEEK_OF_MONTH} or
+ * {@code WEEK_OF_YEAR} fields, {@code Calendar} must determine the
* first week of the month or year as a reference point. The first week of a
* month or year is defined as the earliest seven day period beginning on
- * <code>getFirstDayOfWeek()</code> and containing at least
- * <code>getMinimalDaysInFirstWeek()</code> days of that month or year. Weeks
+ * {@code getFirstDayOfWeek()} and containing at least
+ * {@code getMinimalDaysInFirstWeek()} days of that month or year. Weeks
* numbered ..., -1, 0 precede the first week; weeks numbered 2, 3,... follow
- * it. Note that the normalized numbering returned by <code>get()</code> may be
- * different. For example, a specific <code>Calendar</code> subclass may
+ * it. Note that the normalized numbering returned by {@code get()} may be
+ * different. For example, a specific {@code Calendar} subclass may
* designate the week before week 1 of a year as week <code><i>n</i></code> of
* the previous year.
*
- * <h4>Calendar Fields Resolution</h4>
+ * <h3>Calendar Fields Resolution</h3>
*
* When computing a date and time from the calendar fields, there
* may be insufficient information for the computation (such as only
* year and month with no day of month), or there may be inconsistent
* information (such as Tuesday, July 15, 1996 (Gregorian) -- July 15,
- * 1996 is actually a Monday). <code>Calendar</code> will resolve
+ * 1996 is actually a Monday). {@code Calendar} will resolve
* calendar field values to determine the date and time in the
* following way.
*
* <p><a id="resolution">If there is any conflict in calendar field values,
- * <code>Calendar</code> gives priorities to calendar fields that have been set
+ * {@code Calendar} gives priorities to calendar fields that have been set
* more recently.</a> The following are the default combinations of the
* calendar fields. The most recent combination, as determined by the
* most recently set single field, will be used.
@@ -179,11 +179,11 @@
* </pre></blockquote>
*
* <p>If there are any calendar fields whose values haven't been set in the selected
- * field combination, <code>Calendar</code> uses their default values. The default
+ * field combination, {@code Calendar} uses their default values. The default
* value of each field may vary by concrete calendar systems. For example, in
- * <code>GregorianCalendar</code>, the default of a field is the same as that
- * of the start of the Epoch: i.e., <code>YEAR = 1970</code>, <code>MONTH =
- * JANUARY</code>, <code>DAY_OF_MONTH = 1</code>, etc.
+ * {@code GregorianCalendar}, the default of a field is the same as that
+ * of the start of the Epoch: i.e., {@code YEAR = 1970}, <code>MONTH =
+ * JANUARY</code>, {@code DAY_OF_MONTH = 1}, etc.
*
* <p>
* <strong>Note:</strong> There are certain possible ambiguities in
@@ -205,101 +205,101 @@
* runtime. Use {@link DateFormat}
* to format dates.
*
- * <h4>Field Manipulation</h4>
+ * <h3>Field Manipulation</h3>
*
* The calendar fields can be changed using three methods:
- * <code>set()</code>, <code>add()</code>, and <code>roll()</code>.
+ * {@code set()}, {@code add()}, and {@code roll()}.
*
- * <p><strong><code>set(f, value)</code></strong> changes calendar field
- * <code>f</code> to <code>value</code>. In addition, it sets an
- * internal member variable to indicate that calendar field <code>f</code> has
- * been changed. Although calendar field <code>f</code> is changed immediately,
+ * <p><strong>{@code set(f, value)}</strong> changes calendar field
+ * {@code f} to {@code value}. In addition, it sets an
+ * internal member variable to indicate that calendar field {@code f} has
+ * been changed. Although calendar field {@code f} is changed immediately,
* the calendar's time value in milliseconds is not recomputed until the next call to
- * <code>get()</code>, <code>getTime()</code>, <code>getTimeInMillis()</code>,
- * <code>add()</code>, or <code>roll()</code> is made. Thus, multiple calls to
- * <code>set()</code> do not trigger multiple, unnecessary
+ * {@code get()}, {@code getTime()}, {@code getTimeInMillis()},
+ * {@code add()}, or {@code roll()} is made. Thus, multiple calls to
+ * {@code set()} do not trigger multiple, unnecessary
* computations. As a result of changing a calendar field using
- * <code>set()</code>, other calendar fields may also change, depending on the
+ * {@code set()}, other calendar fields may also change, depending on the
* calendar field, the calendar field value, and the calendar system. In addition,
- * <code>get(f)</code> will not necessarily return <code>value</code> set by
- * the call to the <code>set</code> method
+ * {@code get(f)} will not necessarily return {@code value} set by
+ * the call to the {@code set} method
* after the calendar fields have been recomputed. The specifics are determined by
* the concrete calendar class.</p>
*
- * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
+ * <p><em>Example</em>: Consider a {@code GregorianCalendar}
* originally set to August 31, 1999. Calling <code>set(Calendar.MONTH,
* Calendar.SEPTEMBER)</code> sets the date to September 31,
* 1999. This is a temporary internal representation that resolves to
- * October 1, 1999 if <code>getTime()</code>is then called. However, a
- * call to <code>set(Calendar.DAY_OF_MONTH, 30)</code> before the call to
- * <code>getTime()</code> sets the date to September 30, 1999, since
- * no recomputation occurs after <code>set()</code> itself.</p>
+ * October 1, 1999 if {@code getTime()} is then called. However, a
+ * call to {@code set(Calendar.DAY_OF_MONTH, 30)} before the call to
+ * {@code getTime()} sets the date to September 30, 1999, since
+ * no recomputation occurs after {@code set()} itself.</p>
*
- * <p><strong><code>add(f, delta)</code></strong> adds <code>delta</code>
- * to field <code>f</code>. This is equivalent to calling <code>set(f,
+ * <p><strong>{@code add(f, delta)}</strong> adds {@code delta}
+ * to field {@code f}. This is equivalent to calling <code>set(f,
* get(f) + delta)</code> with two adjustments:</p>
*
* <blockquote>
- * <p><strong>Add rule 1</strong>. The value of field <code>f</code>
- * after the call minus the value of field <code>f</code> before the
- * call is <code>delta</code>, modulo any overflow that has occurred in
- * field <code>f</code>. Overflow occurs when a field value exceeds its
+ * <p><strong>Add rule 1</strong>. The value of field {@code f}
+ * after the call minus the value of field {@code f} before the
+ * call is {@code delta}, modulo any overflow that has occurred in
+ * field {@code f}. Overflow occurs when a field value exceeds its
* range and, as a result, the next larger field is incremented or
* decremented and the field value is adjusted back into its range.</p>
*
* <p><strong>Add rule 2</strong>. If a smaller field is expected to be
* invariant, but it is impossible for it to be equal to its
* prior value because of changes in its minimum or maximum after field
- * <code>f</code> is changed or other constraints, such as time zone
+ * {@code f} is changed or other constraints, such as time zone
* offset changes, then its value is adjusted to be as close
* as possible to its expected value. A smaller field represents a
- * smaller unit of time. <code>HOUR</code> is a smaller field than
- * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
+ * smaller unit of time. {@code HOUR} is a smaller field than
+ * {@code DAY_OF_MONTH}. No adjustment is made to smaller fields
* that are not expected to be invariant. The calendar system
* determines what fields are expected to be invariant.</p>
* </blockquote>
*
- * <p>In addition, unlike <code>set()</code>, <code>add()</code> forces
+ * <p>In addition, unlike {@code set()}, {@code add()} forces
* an immediate recomputation of the calendar's milliseconds and all
* fields.</p>
*
- * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
+ * <p><em>Example</em>: Consider a {@code GregorianCalendar}
* originally set to August 31, 1999. Calling <code>add(Calendar.MONTH,
* 13)</code> sets the calendar to September 30, 2000. <strong>Add rule
- * 1</strong> sets the <code>MONTH</code> field to September, since
+ * 1</strong> sets the {@code MONTH} field to September, since
* adding 13 months to August gives September of the next year. Since
- * <code>DAY_OF_MONTH</code> cannot be 31 in September in a
- * <code>GregorianCalendar</code>, <strong>add rule 2</strong> sets the
- * <code>DAY_OF_MONTH</code> to 30, the closest possible value. Although
- * it is a smaller field, <code>DAY_OF_WEEK</code> is not adjusted by
+ * {@code DAY_OF_MONTH} cannot be 31 in September in a
+ * {@code GregorianCalendar}, <strong>add rule 2</strong> sets the
+ * {@code DAY_OF_MONTH} to 30, the closest possible value. Although
+ * it is a smaller field, {@code DAY_OF_WEEK} is not adjusted by
* rule 2, since it is expected to change when the month changes in a
- * <code>GregorianCalendar</code>.</p>
+ * {@code GregorianCalendar}.</p>
*
- * <p><strong><code>roll(f, delta)</code></strong> adds
- * <code>delta</code> to field <code>f</code> without changing larger
- * fields. This is equivalent to calling <code>add(f, delta)</code> with
+ * <p><strong>{@code roll(f, delta)}</strong> adds
+ * {@code delta} to field {@code f} without changing larger
+ * fields. This is equivalent to calling {@code add(f, delta)} with
* the following adjustment:</p>
*
* <blockquote>
* <p><strong>Roll rule</strong>. Larger fields are unchanged after the
* call. A larger field represents a larger unit of
- * time. <code>DAY_OF_MONTH</code> is a larger field than
- * <code>HOUR</code>.</p>
+ * time. {@code DAY_OF_MONTH} is a larger field than
+ * {@code HOUR}.</p>
* </blockquote>
*
* <p><em>Example</em>: See {@link java.util.GregorianCalendar#roll(int, int)}.
*
* <p><strong>Usage model</strong>. To motivate the behavior of
- * <code>add()</code> and <code>roll()</code>, consider a user interface
+ * {@code add()} and {@code roll()}, consider a user interface
* component with increment and decrement buttons for the month, day, and
- * year, and an underlying <code>GregorianCalendar</code>. If the
+ * year, and an underlying {@code GregorianCalendar}. If the
* interface reads January 31, 1999 and the user presses the month
* increment button, what should it read? If the underlying
- * implementation uses <code>set()</code>, it might read March 3, 1999. A
+ * implementation uses {@code set()}, it might read March 3, 1999. A
* better result would be February 28, 1999. Furthermore, if the user
* presses the month increment button again, it should read March 31,
* 1999, not March 28, 1999. By saving the original date and using either
- * <code>add()</code> or <code>roll()</code>, depending on whether larger
+ * {@code add()} or {@code roll()}, depending on whether larger
* fields should be affected, the user interface can behave as most users
* will intuitively expect.</p>
*
@@ -364,7 +364,7 @@
// ranges when they are regenerated.
/**
- * Field number for <code>get</code> and <code>set</code> indicating the
+ * Field number for {@code get} and {@code set} indicating the
* era, e.g., AD or BC in the Julian calendar. This is a calendar-specific
* value; see subclass documentation.
*
@@ -374,16 +374,16 @@
public static final int ERA = 0;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the
+ * Field number for {@code get} and {@code set} indicating the
* year. This is a calendar-specific value; see subclass documentation.
*/
public static final int YEAR = 1;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the
+ * Field number for {@code get} and {@code set} indicating the
* month. This is a calendar-specific value. The first month of
* the year in the Gregorian and Julian calendars is
- * <code>JANUARY</code> which is 0; the last depends on the number
+ * {@code JANUARY} which is 0; the last depends on the number
* of months in a year.
*
* @see #JANUARY
@@ -403,11 +403,11 @@
public static final int MONTH = 2;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the
+ * Field number for {@code get} and {@code set} indicating the
* week number within the current year. The first week of the year, as
- * defined by <code>getFirstDayOfWeek()</code> and
- * <code>getMinimalDaysInFirstWeek()</code>, has value 1. Subclasses define
- * the value of <code>WEEK_OF_YEAR</code> for days before the first week of
+ * defined by {@code getFirstDayOfWeek()} and
+ * {@code getMinimalDaysInFirstWeek()}, has value 1. Subclasses define
+ * the value of {@code WEEK_OF_YEAR} for days before the first week of
* the year.
*
* @see #getFirstDayOfWeek
@@ -416,11 +416,11 @@
public static final int WEEK_OF_YEAR = 3;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the
+ * Field number for {@code get} and {@code set} indicating the
* week number within the current month. The first week of the month, as
- * defined by <code>getFirstDayOfWeek()</code> and
- * <code>getMinimalDaysInFirstWeek()</code>, has value 1. Subclasses define
- * the value of <code>WEEK_OF_MONTH</code> for days before the first week of
+ * defined by {@code getFirstDayOfWeek()} and
+ * {@code getMinimalDaysInFirstWeek()}, has value 1. Subclasses define
+ * the value of {@code WEEK_OF_MONTH} for days before the first week of
* the month.
*
* @see #getFirstDayOfWeek
@@ -429,8 +429,8 @@
public static final int WEEK_OF_MONTH = 4;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the
- * day of the month. This is a synonym for <code>DAY_OF_MONTH</code>.
+ * Field number for {@code get} and {@code set} indicating the
+ * day of the month. This is a synonym for {@code DAY_OF_MONTH}.
* The first day of the month has value 1.
*
* @see #DAY_OF_MONTH
@@ -438,8 +438,8 @@
public static final int DATE = 5;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the
- * day of the month. This is a synonym for <code>DATE</code>.
+ * Field number for {@code get} and {@code set} indicating the
+ * day of the month. This is a synonym for {@code DATE}.
* The first day of the month has value 1.
*
* @see #DATE
@@ -447,16 +447,16 @@
public static final int DAY_OF_MONTH = 5;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the day
+ * Field number for {@code get} and {@code set} indicating the day
* number within the current year. The first day of the year has value 1.
*/
public static final int DAY_OF_YEAR = 6;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the day
- * of the week. This field takes values <code>SUNDAY</code>,
- * <code>MONDAY</code>, <code>TUESDAY</code>, <code>WEDNESDAY</code>,
- * <code>THURSDAY</code>, <code>FRIDAY</code>, and <code>SATURDAY</code>.
+ * Field number for {@code get} and {@code set} indicating the day
+ * of the week. This field takes values {@code SUNDAY},
+ * {@code MONDAY}, {@code TUESDAY}, {@code WEDNESDAY},
+ * {@code THURSDAY}, {@code FRIDAY}, and {@code SATURDAY}.
*
* @see #SUNDAY
* @see #MONDAY
@@ -469,24 +469,24 @@
public static final int DAY_OF_WEEK = 7;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the
+ * Field number for {@code get} and {@code set} indicating the
* ordinal number of the day of the week within the current month. Together
- * with the <code>DAY_OF_WEEK</code> field, this uniquely specifies a day
- * within a month. Unlike <code>WEEK_OF_MONTH</code> and
- * <code>WEEK_OF_YEAR</code>, this field's value does <em>not</em> depend on
- * <code>getFirstDayOfWeek()</code> or
- * <code>getMinimalDaysInFirstWeek()</code>. <code>DAY_OF_MONTH 1</code>
- * through <code>7</code> always correspond to <code>DAY_OF_WEEK_IN_MONTH
- * 1</code>; <code>8</code> through <code>14</code> correspond to
- * <code>DAY_OF_WEEK_IN_MONTH 2</code>, and so on.
- * <code>DAY_OF_WEEK_IN_MONTH 0</code> indicates the week before
- * <code>DAY_OF_WEEK_IN_MONTH 1</code>. Negative values count back from the
+ * with the {@code DAY_OF_WEEK} field, this uniquely specifies a day
+ * within a month. Unlike {@code WEEK_OF_MONTH} and
+ * {@code WEEK_OF_YEAR}, this field's value does <em>not</em> depend on
+ * {@code getFirstDayOfWeek()} or
+ * {@code getMinimalDaysInFirstWeek()}. {@code DAY_OF_MONTH 1}
+ * through {@code 7} always correspond to <code>DAY_OF_WEEK_IN_MONTH
+ * 1</code>; {@code 8} through {@code 14} correspond to
+ * {@code DAY_OF_WEEK_IN_MONTH 2}, and so on.
+ * {@code DAY_OF_WEEK_IN_MONTH 0} indicates the week before
+ * {@code DAY_OF_WEEK_IN_MONTH 1}. Negative values count back from the
* end of the month, so the last Sunday of a month is specified as
- * <code>DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1</code>. Because
+ * {@code DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1}. Because
* negative values count backward they will usually be aligned differently
* within the month than positive values. For example, if a month has 31
- * days, <code>DAY_OF_WEEK_IN_MONTH -1</code> will overlap
- * <code>DAY_OF_WEEK_IN_MONTH 5</code> and the end of <code>4</code>.
+ * days, {@code DAY_OF_WEEK_IN_MONTH -1} will overlap
+ * {@code DAY_OF_WEEK_IN_MONTH 5} and the end of {@code 4}.
*
* @see #DAY_OF_WEEK
* @see #WEEK_OF_MONTH
@@ -494,9 +494,9 @@
public static final int DAY_OF_WEEK_IN_MONTH = 8;
/**
- * Field number for <code>get</code> and <code>set</code> indicating
- * whether the <code>HOUR</code> is before or after noon.
- * E.g., at 10:04:15.250 PM the <code>AM_PM</code> is <code>PM</code>.
+ * Field number for {@code get} and {@code set} indicating
+ * whether the {@code HOUR} is before or after noon.
+ * E.g., at 10:04:15.250 PM the {@code AM_PM} is {@code PM}.
*
* @see #AM
* @see #PM
@@ -505,10 +505,10 @@
public static final int AM_PM = 9;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the
- * hour of the morning or afternoon. <code>HOUR</code> is used for the
+ * Field number for {@code get} and {@code set} indicating the
+ * hour of the morning or afternoon. {@code HOUR} is used for the
* 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12.
- * E.g., at 10:04:15.250 PM the <code>HOUR</code> is 10.
+ * E.g., at 10:04:15.250 PM the {@code HOUR} is 10.
*
* @see #AM_PM
* @see #HOUR_OF_DAY
@@ -516,60 +516,60 @@
public static final int HOUR = 10;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the
- * hour of the day. <code>HOUR_OF_DAY</code> is used for the 24-hour clock.
- * E.g., at 10:04:15.250 PM the <code>HOUR_OF_DAY</code> is 22.
+ * Field number for {@code get} and {@code set} indicating the
+ * hour of the day. {@code HOUR_OF_DAY} is used for the 24-hour clock.
+ * E.g., at 10:04:15.250 PM the {@code HOUR_OF_DAY} is 22.
*
* @see #HOUR
*/
public static final int HOUR_OF_DAY = 11;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the
+ * Field number for {@code get} and {@code set} indicating the
* minute within the hour.
- * E.g., at 10:04:15.250 PM the <code>MINUTE</code> is 4.
+ * E.g., at 10:04:15.250 PM the {@code MINUTE} is 4.
*/
public static final int MINUTE = 12;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the
+ * Field number for {@code get} and {@code set} indicating the
* second within the minute.
- * E.g., at 10:04:15.250 PM the <code>SECOND</code> is 15.
+ * E.g., at 10:04:15.250 PM the {@code SECOND} is 15.
*/
public static final int SECOND = 13;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the
+ * Field number for {@code get} and {@code set} indicating the
* millisecond within the second.
- * E.g., at 10:04:15.250 PM the <code>MILLISECOND</code> is 250.
+ * E.g., at 10:04:15.250 PM the {@code MILLISECOND} is 250.
*/
public static final int MILLISECOND = 14;
/**
- * Field number for <code>get</code> and <code>set</code>
+ * Field number for {@code get} and {@code set}
* indicating the raw offset from GMT in milliseconds.
* <p>
* This field reflects the correct GMT offset value of the time
- * zone of this <code>Calendar</code> if the
- * <code>TimeZone</code> implementation subclass supports
+ * zone of this {@code Calendar} if the
+ * {@code TimeZone} implementation subclass supports
* historical GMT offset changes.
*/
public static final int ZONE_OFFSET = 15;
/**
- * Field number for <code>get</code> and <code>set</code> indicating the
+ * Field number for {@code get} and {@code set} indicating the
* daylight saving offset in milliseconds.
* <p>
* This field reflects the correct daylight saving offset value of
- * the time zone of this <code>Calendar</code> if the
- * <code>TimeZone</code> implementation subclass supports
+ * the time zone of this {@code Calendar} if the
+ * {@code TimeZone} implementation subclass supports
* historical Daylight Saving Time schedule changes.
*/
public static final int DST_OFFSET = 16;
/**
- * The number of distinct fields recognized by <code>get</code> and <code>set</code>.
- * Field numbers range from <code>0..FIELD_COUNT-1</code>.
+ * The number of distinct fields recognized by {@code get} and {@code set}.
+ * Field numbers range from {@code 0..FIELD_COUNT-1}.
*/
public static final int FIELD_COUNT = 17;
@@ -689,7 +689,7 @@
/**
* Value of the {@link #MONTH} field indicating the
- * thirteenth month of the year. Although <code>GregorianCalendar</code>
+ * thirteenth month of the year. Although {@code GregorianCalendar}
* does not use this value, lunar calendars do.
*/
public static final int UNDECIMBER = 12;
@@ -834,8 +834,8 @@
/**
* The calendar field values for the currently set time for this calendar.
- * This is an array of <code>FIELD_COUNT</code> integers, with index values
- * <code>ERA</code> through <code>DST_OFFSET</code>.
+ * This is an array of {@code FIELD_COUNT} integers, with index values
+ * {@code ERA} through {@code DST_OFFSET}.
* @serial
*/
@SuppressWarnings("ProtectedField")
@@ -845,8 +845,8 @@
* The flags which tell if a specified calendar field for the calendar is set.
* A new object has no fields set. After the first call to a method
* which generates the fields, they all remain set after that.
- * This is an array of <code>FIELD_COUNT</code> booleans, with index values
- * <code>ERA</code> through <code>DST_OFFSET</code>.
+ * This is an array of {@code FIELD_COUNT} booleans, with index values
+ * {@code ERA} through {@code DST_OFFSET}.
* @serial
*/
@SuppressWarnings("ProtectedField")
@@ -869,8 +869,8 @@
protected long time;
/**
- * True if then the value of <code>time</code> is valid.
- * The time is made invalid by a change to an item of <code>field[]</code>.
+ * True if then the value of {@code time} is valid.
+ * The time is made invalid by a change to an item of {@code field[]}.
* @see #time
* @serial
*/
@@ -878,10 +878,10 @@
protected boolean isTimeSet;
/**
- * True if <code>fields[]</code> are in sync with the currently set time.
+ * True if {@code fields[]} are in sync with the currently set time.
* If false, then the next attempt to get the value of a field will
* force a recomputation of all fields from the current value of
- * <code>time</code>.
+ * {@code time}.
* @serial
*/
@SuppressWarnings("ProtectedField")
@@ -894,8 +894,8 @@
transient boolean areAllFieldsSet;
/**
- * <code>True</code> if this calendar allows out-of-range field values during computation
- * of <code>time</code> from <code>fields[]</code>.
+ * {@code True} if this calendar allows out-of-range field values during computation
+ * of {@code time} from {@code fields[]}.
* @see #setLenient
* @see #isLenient
* @serial
@@ -903,20 +903,20 @@
private boolean lenient = true;
/**
- * The <code>TimeZone</code> used by this calendar. <code>Calendar</code>
+ * The {@code TimeZone} used by this calendar. {@code Calendar}
* uses the time zone data to translate between locale and GMT time.
* @serial
*/
private TimeZone zone;
/**
- * <code>True</code> if zone references to a shared TimeZone object.
+ * {@code True} if zone references to a shared TimeZone object.
*/
private transient boolean sharedZone = false;
/**
- * The first day of the week, with possible values <code>SUNDAY</code>,
- * <code>MONDAY</code>, etc. This is a locale-dependent value.
+ * The first day of the week, with possible values {@code SUNDAY},
+ * {@code MONDAY}, etc. This is a locale-dependent value.
* @serial
*/
private int firstDayOfWeek;
@@ -959,10 +959,10 @@
static final int ALL_FIELDS = (1 << FIELD_COUNT) - 1;
/**
- * The next available value for <code>stamp[]</code>, an internal array.
+ * The next available value for {@code stamp[]}, an internal array.
* This actually should not be written out to the stream, and will probably
* be removed from the stream in the near future. In the meantime,
- * a value of <code>MINIMUM_USER_STAMP</code> should be used.
+ * a value of {@code MINIMUM_USER_STAMP} should be used.
* @serial
*/
private int nextStamp = MINIMUM_USER_STAMP;
@@ -992,7 +992,7 @@
* </dd>
* </dl>
* When streaming out this class, the most recent format
- * and the highest allowable <code>serialVersionOnStream</code>
+ * and the highest allowable {@code serialVersionOnStream}
* is written.
* @serial
* @since 1.1.6
@@ -1000,6 +1000,7 @@
private int serialVersionOnStream = currentSerialVersion;
// Proclaim serialization compatibility with JDK 1.1
+ @java.io.Serial
static final long serialVersionUID = -1807547505821590642L;
// Mask values for calendar fields
@@ -1302,7 +1303,7 @@
* Sets the time zone parameter to the given {@code zone}. If no time
* zone parameter is given to this {@code Calendar.Builder}, the
* {@linkplain TimeZone#getDefault() default
- * <code>TimeZone</code>} will be used in the {@link #build() build}
+ * {@code TimeZone}} will be used in the {@link #build() build}
* method.
*
* @param zone the {@link TimeZone}
@@ -1373,7 +1374,7 @@
/**
* Sets the locale parameter to the given {@code locale}. If no locale
* is given to this {@code Calendar.Builder}, the {@linkplain
- * Locale#getDefault(Locale.Category) default <code>Locale</code>}
+ * Locale#getDefault(Locale.Category) default {@code Locale}}
* for {@link Locale.Category#FORMAT} will be used.
*
* <p>If no calendar type is explicitly given by a call to the
@@ -1473,7 +1474,6 @@
if (zone == null) {
zone = defaultTimeZone(locale);
}
- Calendar cal;
if (type == null) {
type = locale.getUnicodeLocaleType("ca");
}
@@ -1491,30 +1491,28 @@
type = "gregory";
// END Android-changed: don't switch to buddhist calendar based on locale.
}
- switch (type) {
- case "gregory":
- cal = new GregorianCalendar(zone, locale, true);
- break;
- case "iso8601":
- GregorianCalendar gcal = new GregorianCalendar(zone, locale, true);
- // make gcal a proleptic Gregorian
- gcal.setGregorianChange(new Date(Long.MIN_VALUE));
- // and week definition to be compatible with ISO 8601
- setWeekDefinition(MONDAY, 4);
- cal = gcal;
- break;
-// BEGIN Android-changed: removed support for "buddhist" and "japanese".
-// case "buddhist":
-// cal = new BuddhistCalendar(zone, locale);
-// cal.clear();
-// break;
-// case "japanese":
-// cal = new JapaneseImperialCalendar(zone, locale, true);
-// break;
-// END Android-changed: removed support for "buddhist" and "japanese".
- default:
- throw new IllegalArgumentException("unknown calendar type: " + type);
- }
+ final Calendar cal = switch (type) {
+ case "gregory" -> new GregorianCalendar(zone, locale, true);
+ case "iso8601" -> {
+ GregorianCalendar gcal = new GregorianCalendar(zone, locale, true);
+ // make gcal a proleptic Gregorian
+ gcal.setGregorianChange(new Date(Long.MIN_VALUE));
+ // and week definition to be compatible with ISO 8601
+ setWeekDefinition(MONDAY, 4);
+ yield gcal;
+ }
+ // BEGIN Android-changed: removed support for "buddhist" and "japanese".
+ /*
+ case "buddhist" -> {
+ var buddhistCalendar = new BuddhistCalendar(zone, locale);
+ buddhistCalendar.clear();
+ yield buddhistCalendar;
+ }
+ case "japanese" -> new JapaneseImperialCalendar(zone, locale, true);
+ */
+ // END Android-changed: removed support for "buddhist" and "japanese".
+ default -> throw new IllegalArgumentException("unknown calendar type: " + type);
+ };
cal.setLenient(lenient);
if (firstDayOfWeek != 0) {
cal.setFirstDayOfWeek(firstDayOfWeek);
@@ -1628,7 +1626,7 @@
// Android-changed: Support the "tz" extension since Android 13.
/**
* Gets a calendar using the default time zone and locale. The
- * <code>Calendar</code> returned is based on the current time
+ * {@code Calendar} returned is based on the current time
* in the default time zone with the default
* {@link Locale.Category#FORMAT FORMAT} locale.
* <p>
@@ -1646,7 +1644,7 @@
/**
* Gets a calendar using the specified time zone and default locale.
- * The <code>Calendar</code> returned is based on the current time
+ * The {@code Calendar} returned is based on the current time
* in the given time zone with the default
* {@link Locale.Category#FORMAT FORMAT} locale.
*
@@ -1661,7 +1659,7 @@
// Android-changed: Support the "tz" extension since Android 13.
/**
* Gets a calendar using the default time zone and specified locale.
- * The <code>Calendar</code> returned is based on the current time
+ * The {@code Calendar} returned is based on the current time
* in the default time zone with the given locale.
* <p>
* Since Android 13, if the locale contains the time zone with "tz"
@@ -1678,7 +1676,7 @@
/**
* Gets a calendar with the specified time zone and locale.
- * The <code>Calendar</code> returned is based on the current time
+ * The {@code Calendar} returned is based on the current time
* in the given time zone with the given locale.
*
* @param zone the time zone to use
@@ -1721,18 +1719,61 @@
Locale aLocale)
{
// BEGIN Android-changed: only support GregorianCalendar here.
+ /*
+ CalendarProvider provider =
+ LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
+ .getCalendarProvider();
+ if (provider != null) {
+ try {
+ return provider.getInstance(zone, aLocale);
+ } catch (IllegalArgumentException iae) {
+ // fall back to the default instantiation
+ }
+ }
+
+ Calendar cal = null;
+
+ if (aLocale.hasExtensions()) {
+ String caltype = aLocale.getUnicodeLocaleType("ca");
+ if (caltype != null) {
+ cal = switch (caltype) {
+ case "buddhist" -> new BuddhistCalendar(zone, aLocale);
+ case "japanese" -> new JapaneseImperialCalendar(zone, aLocale);
+ case "gregory" -> new GregorianCalendar(zone, aLocale);
+ default -> null;
+ };
+ }
+ }
+ if (cal == null) {
+ // If no known calendar type is explicitly specified,
+ // perform the traditional way to create a Calendar:
+ // create a BuddhistCalendar for th_TH locale,
+ // a JapaneseImperialCalendar for ja_JP_JP locale, or
+ // a GregorianCalendar for any other locales.
+ // NOTE: The language, country and variant strings are interned.
+ if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
+ cal = new BuddhistCalendar(zone, aLocale);
+ } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
+ && aLocale.getCountry() == "JP") {
+ cal = new JapaneseImperialCalendar(zone, aLocale);
+ } else {
+ cal = new GregorianCalendar(zone, aLocale);
+ }
+ }
+ return cal;
+ */
return new GregorianCalendar(zone, aLocale);
// END Android-changed: only support GregorianCalendar here.
}
/**
- * Returns an array of all locales for which the <code>getInstance</code>
+ * Returns an array of all locales for which the {@code getInstance}
* methods of this class can return localized instances.
- * The array returned must contain at least a <code>Locale</code>
+ * The array returned must contain at least a {@code Locale}
* instance equal to {@link java.util.Locale#US Locale.US}.
*
* @return An array of locales for which localized
- * <code>Calendar</code> instances are available.
+ * {@code Calendar} instances are available.
*/
public static synchronized Locale[] getAvailableLocales()
{
@@ -1762,11 +1803,11 @@
protected abstract void computeFields();
/**
- * Returns a <code>Date</code> object representing this
- * <code>Calendar</code>'s time value (millisecond offset from the <a
+ * Returns a {@code Date} object representing this
+ * {@code Calendar}'s time value (millisecond offset from the <a
* href="#Epoch">Epoch</a>").
*
- * @return a <code>Date</code> representing the time value.
+ * @return a {@code Date} representing the time value.
* @see #setTime(Date)
* @see #getTimeInMillis()
*/
@@ -1775,17 +1816,19 @@
}
/**
- * Sets this Calendar's time with the given <code>Date</code>.
+ * Sets this Calendar's time with the given {@code Date}.
* <p>
- * Note: Calling <code>setTime()</code> with
- * <code>Date(Long.MAX_VALUE)</code> or <code>Date(Long.MIN_VALUE)</code>
- * may yield incorrect field values from <code>get()</code>.
+ * Note: Calling {@code setTime()} with
+ * {@code Date(Long.MAX_VALUE)} or {@code Date(Long.MIN_VALUE)}
+ * may yield incorrect field values from {@code get()}.
*
* @param date the given Date.
* @see #getTime()
* @see #setTimeInMillis(long)
+ * @throws NullPointerException if {@code date} is {@code null}
*/
public final void setTime(Date date) {
+ Objects.requireNonNull(date, "date must not be null");
setTimeInMillis(date.getTime());
}
@@ -1866,7 +1909,7 @@
/**
* Sets the value of the given calendar field. This method does
* not affect any setting state of the field in this
- * <code>Calendar</code> instance.
+ * {@code Calendar} instance.
*
* @throws IndexOutOfBoundsException if the specified field is out of range
* (<code>field < 0 || field >= FIELD_COUNT</code>).
@@ -1912,15 +1955,15 @@
}
/**
- * Sets the values for the calendar fields <code>YEAR</code>,
- * <code>MONTH</code>, and <code>DAY_OF_MONTH</code>.
+ * Sets the values for the calendar fields {@code YEAR},
+ * {@code MONTH}, and {@code DAY_OF_MONTH}.
* Previous values of other calendar fields are retained. If this is not desired,
* call {@link #clear()} first.
*
- * @param year the value used to set the <code>YEAR</code> calendar field.
- * @param month the value used to set the <code>MONTH</code> calendar field.
+ * @param year the value used to set the {@code YEAR} calendar field.
+ * @param month the value used to set the {@code MONTH} calendar field.
* Month value is 0-based. e.g., 0 for January.
- * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
+ * @param date the value used to set the {@code DAY_OF_MONTH} calendar field.
* @see #set(int,int)
* @see #set(int,int,int,int,int)
* @see #set(int,int,int,int,int,int)
@@ -1933,18 +1976,18 @@
}
/**
- * Sets the values for the calendar fields <code>YEAR</code>,
- * <code>MONTH</code>, <code>DAY_OF_MONTH</code>,
- * <code>HOUR_OF_DAY</code>, and <code>MINUTE</code>.
+ * Sets the values for the calendar fields {@code YEAR},
+ * {@code MONTH}, {@code DAY_OF_MONTH},
+ * {@code HOUR_OF_DAY}, and {@code MINUTE}.
* Previous values of other fields are retained. If this is not desired,
* call {@link #clear()} first.
*
- * @param year the value used to set the <code>YEAR</code> calendar field.
- * @param month the value used to set the <code>MONTH</code> calendar field.
+ * @param year the value used to set the {@code YEAR} calendar field.
+ * @param month the value used to set the {@code MONTH} calendar field.
* Month value is 0-based. e.g., 0 for January.
- * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
- * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
- * @param minute the value used to set the <code>MINUTE</code> calendar field.
+ * @param date the value used to set the {@code DAY_OF_MONTH} calendar field.
+ * @param hourOfDay the value used to set the {@code HOUR_OF_DAY} calendar field.
+ * @param minute the value used to set the {@code MINUTE} calendar field.
* @see #set(int,int)
* @see #set(int,int,int)
* @see #set(int,int,int,int,int,int)
@@ -1959,19 +2002,19 @@
}
/**
- * Sets the values for the fields <code>YEAR</code>, <code>MONTH</code>,
- * <code>DAY_OF_MONTH</code>, <code>HOUR_OF_DAY</code>, <code>MINUTE</code>, and
- * <code>SECOND</code>.
+ * Sets the values for the fields {@code YEAR}, {@code MONTH},
+ * {@code DAY_OF_MONTH}, {@code HOUR_OF_DAY}, {@code MINUTE}, and
+ * {@code SECOND}.
* Previous values of other fields are retained. If this is not desired,
* call {@link #clear()} first.
*
- * @param year the value used to set the <code>YEAR</code> calendar field.
- * @param month the value used to set the <code>MONTH</code> calendar field.
+ * @param year the value used to set the {@code YEAR} calendar field.
+ * @param month the value used to set the {@code MONTH} calendar field.
* Month value is 0-based. e.g., 0 for January.
- * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
- * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
- * @param minute the value used to set the <code>MINUTE</code> calendar field.
- * @param second the value used to set the <code>SECOND</code> calendar field.
+ * @param date the value used to set the {@code DAY_OF_MONTH} calendar field.
+ * @param hourOfDay the value used to set the {@code HOUR_OF_DAY} calendar field.
+ * @param minute the value used to set the {@code MINUTE} calendar field.
+ * @param second the value used to set the {@code SECOND} calendar field.
* @see #set(int,int)
* @see #set(int,int,int)
* @see #set(int,int,int,int,int)
@@ -1990,14 +2033,14 @@
/**
* Sets all the calendar field values and the time value
* (millisecond offset from the <a href="#Epoch">Epoch</a>) of
- * this <code>Calendar</code> undefined. This means that {@link
- * #isSet(int) isSet()} will return <code>false</code> for all the
+ * this {@code Calendar} undefined. This means that {@link
+ * #isSet(int) isSet()} will return {@code false} for all the
* calendar fields, and the date and time calculations will treat
* the fields as if they had never been set. A
- * <code>Calendar</code> implementation class may use its specific
+ * {@code Calendar} implementation class may use its specific
* default field values for date/time calculations. For example,
- * <code>GregorianCalendar</code> uses 1970 if the
- * <code>YEAR</code> field value is undefined.
+ * {@code GregorianCalendar} uses 1970 if the
+ * {@code YEAR} field value is undefined.
*
* @see #clear(int)
*/
@@ -2014,10 +2057,10 @@
/**
* Sets the given calendar field value and the time value
* (millisecond offset from the <a href="#Epoch">Epoch</a>) of
- * this <code>Calendar</code> undefined. This means that {@link
- * #isSet(int) isSet(field)} will return <code>false</code>, and
+ * this {@code Calendar} undefined. This means that {@link
+ * #isSet(int) isSet(field)} will return {@code false}, and
* the date and time calculations will treat the field as if it
- * had never been set. A <code>Calendar</code> implementation
+ * had never been set. A {@code Calendar} implementation
* class may use the field's specific default value for date and
* time calculations.
*
@@ -2025,7 +2068,7 @@
* fields are handled independently and the <a
* href="#time_resolution">the resolution rule for the time of
* day</a> is applied. Clearing one of the fields doesn't reset
- * the hour of day value of this <code>Calendar</code>. Use {@link
+ * the hour of day value of this {@code Calendar}. Use {@link
* #set(int,int) set(Calendar.HOUR_OF_DAY, 0)} to reset the hour
* value.
*
@@ -2045,11 +2088,11 @@
/**
* Determines if the given calendar field has a value set,
* including cases that the value has been set by internal fields
- * calculations triggered by a <code>get</code> method call.
+ * calculations triggered by a {@code get} method call.
*
* @param field the calendar field to test
- * @return <code>true</code> if the given calendar field has a value set;
- * <code>false</code> otherwise.
+ * @return {@code true} if the given calendar field has a value set;
+ * {@code false} otherwise.
*/
public final boolean isSet(int field)
{
@@ -2058,24 +2101,24 @@
/**
* Returns the string representation of the calendar
- * <code>field</code> value in the given <code>style</code> and
- * <code>locale</code>. If no string representation is
- * applicable, <code>null</code> is returned. This method calls
+ * {@code field} value in the given {@code style} and
+ * {@code locale}. If no string representation is
+ * applicable, {@code null} is returned. This method calls
* {@link Calendar#get(int) get(field)} to get the calendar
- * <code>field</code> value if the string representation is
- * applicable to the given calendar <code>field</code>.
+ * {@code field} value if the string representation is
+ * applicable to the given calendar {@code field}.
*
- * <p>For example, if this <code>Calendar</code> is a
- * <code>GregorianCalendar</code> and its date is 2005-01-01, then
+ * <p>For example, if this {@code Calendar} is a
+ * {@code GregorianCalendar} and its date is 2005-01-01, then
* the string representation of the {@link #MONTH} field would be
* "January" in the long style in an English locale or "Jan" in
* the short style. However, no string representation would be
* available for the {@link #DAY_OF_MONTH} field, and this method
- * would return <code>null</code>.
+ * would return {@code null}.
*
* <p>The default implementation supports the calendar fields for
* which a {@link DateFormatSymbols} has names in the given
- * <code>locale</code>.
+ * {@code locale}.
*
* @param field
* the calendar field for which the string representation
@@ -2092,11 +2135,11 @@
* {@code field} in the given {@code style}, or
* {@code null} if no string representation is
* applicable.
- * @exception IllegalArgumentException
+ * @throws IllegalArgumentException
* if {@code field} or {@code style} is invalid,
* or if this {@code Calendar} is non-lenient and any
* of the calendar fields have invalid values
- * @exception NullPointerException
+ * @throws NullPointerException
* if {@code locale} is null
* @since 1.6
*/
@@ -2190,11 +2233,11 @@
* {@code style} and {@code locale} and their
* field values, or {@code null} if no display names
* are defined for {@code field}
- * @exception IllegalArgumentException
+ * @throws IllegalArgumentException
* if {@code field} or {@code style} is invalid,
* or if this {@code Calendar} is non-lenient and any
* of the calendar fields have invalid values
- * @exception NullPointerException
+ * @throws NullPointerException
* if {@code locale} is null
* @since 1.6
*/
@@ -2272,25 +2315,13 @@
return null;
}
- String[] strings = null;
- switch (field) {
- case ERA:
- strings = symbols.getEras();
- break;
-
- case MONTH:
- strings = (baseStyle == LONG) ? symbols.getMonths() : symbols.getShortMonths();
- break;
-
- case DAY_OF_WEEK:
- strings = (baseStyle == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays();
- break;
-
- case AM_PM:
- strings = symbols.getAmPmStrings();
- break;
- }
- return strings;
+ return switch (field) {
+ case ERA -> symbols.getEras();
+ case MONTH -> (baseStyle == LONG) ? symbols.getMonths() : symbols.getShortMonths();
+ case DAY_OF_WEEK -> (baseStyle == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays();
+ case AM_PM -> symbols.getAmPmStrings();
+ default -> null;
+ };
}
/**
@@ -2316,10 +2347,10 @@
* externally by calling one of the setter methods rather than by the
* internal time calculation.
*
- * @return <code>true</code> if the field has been set externally,
- * <code>false</code> otherwise.
- * @exception IndexOutOfBoundsException if the specified
- * <code>field</code> is out of range
+ * @return {@code true} if the field has been set externally,
+ * {@code false} otherwise.
+ * @throws IndexOutOfBoundsException if the specified
+ * {@code field} is out of range
* (<code>field < 0 || field >= FIELD_COUNT</code>).
* @see #selectFields()
* @see #setFieldsComputed(int)
@@ -2351,8 +2382,8 @@
* rather than by calling one of the setter methods.
*
* @param fieldMask the field to be marked as computed.
- * @exception IndexOutOfBoundsException if the specified
- * <code>field</code> is out of range
+ * @throws IndexOutOfBoundsException if the specified
+ * {@code field} is out of range
* (<code>field < 0 || field >= FIELD_COUNT</code>).
* @see #isExternallySet(int)
* @see #selectFields()
@@ -2381,15 +2412,15 @@
/**
* Sets the state of the calendar fields that are <em>not</em> specified
- * by <code>fieldMask</code> to <em>unset</em>. If <code>fieldMask</code>
+ * by {@code fieldMask} to <em>unset</em>. If {@code fieldMask}
* specifies all the calendar fields, then the state of this
- * <code>Calendar</code> becomes that all the calendar fields are in sync
+ * {@code Calendar} becomes that all the calendar fields are in sync
* with the time value (millisecond offset from the Epoch).
*
* @param fieldMask the field mask indicating which calendar fields are in
* sync with the time value.
- * @exception IndexOutOfBoundsException if the specified
- * <code>field</code> is out of range
+ * @throws IndexOutOfBoundsException if the specified
+ * {@code field} is out of range
* (<code>field < 0 || field >= FIELD_COUNT</code>).
* @see #isExternallySet(int)
* @see #selectFields()
@@ -2435,8 +2466,8 @@
}
/**
- * Returns whether the specified <code>field</code> is on in the
- * <code>fieldMask</code>.
+ * Returns whether the specified {@code field} is on in the
+ * {@code fieldMask}.
*/
static boolean isFieldSet(int fieldMask, int field) {
return (fieldMask & (1 << field)) != 0;
@@ -2446,16 +2477,16 @@
* Returns a field mask indicating which calendar field values
* to be used to calculate the time value. The calendar fields are
* returned as a bit mask, each bit of which corresponds to a field, i.e.,
- * the mask value of <code>field</code> is <code>(1 <<
- * field)</code>. For example, 0x26 represents the <code>YEAR</code>,
- * <code>MONTH</code>, and <code>DAY_OF_MONTH</code> fields (i.e., 0x26 is
+ * the mask value of {@code field} is <code>(1 <<
+ * field)</code>. For example, 0x26 represents the {@code YEAR},
+ * {@code MONTH}, and {@code DAY_OF_MONTH} fields (i.e., 0x26 is
* equal to
* <code>(1<<YEAR)|(1<<MONTH)|(1<<DAY_OF_MONTH))</code>.
*
* <p>This method supports the calendar fields resolution as described in
* the class description. If the bit mask for a given field is on and its
- * field has not been set (i.e., <code>isSet(field)</code> is
- * <code>false</code>), then the default value of the field has to be
+ * field has not been set (i.e., {@code isSet(field)} is
+ * {@code false}), then the default value of the field has to be
* used, which case means that the field has been selected because the
* selected combination involves the field.
*
@@ -2706,26 +2737,26 @@
}
/**
- * Compares this <code>Calendar</code> to the specified
- * <code>Object</code>. The result is <code>true</code> if and only if
- * the argument is a <code>Calendar</code> object of the same calendar
+ * Compares this {@code Calendar} to the specified
+ * {@code Object}. The result is {@code true} if and only if
+ * the argument is a {@code Calendar} object of the same calendar
* system that represents the same time value (millisecond offset from the
* <a href="#Epoch">Epoch</a>) under the same
- * <code>Calendar</code> parameters as this object.
+ * {@code Calendar} parameters as this object.
*
- * <p>The <code>Calendar</code> parameters are the values represented
- * by the <code>isLenient</code>, <code>getFirstDayOfWeek</code>,
- * <code>getMinimalDaysInFirstWeek</code> and <code>getTimeZone</code>
+ * <p>The {@code Calendar} parameters are the values represented
+ * by the {@code isLenient}, {@code getFirstDayOfWeek},
+ * {@code getMinimalDaysInFirstWeek} and {@code getTimeZone}
* methods. If there is any difference in those parameters
- * between the two <code>Calendar</code>s, this method returns
- * <code>false</code>.
+ * between the two {@code Calendar}s, this method returns
+ * {@code false}.
*
* <p>Use the {@link #compareTo(Calendar) compareTo} method to
* compare only the time values.
*
* @param obj the object to compare with.
- * @return <code>true</code> if this object is equal to <code>obj</code>;
- * <code>false</code> otherwise.
+ * @return {@code true} if this object is equal to {@code obj};
+ * {@code false} otherwise.
*/
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
@Override
@@ -2770,19 +2801,19 @@
}
/**
- * Returns whether this <code>Calendar</code> represents a time
+ * Returns whether this {@code Calendar} represents a time
* before the time represented by the specified
- * <code>Object</code>. This method is equivalent to:
+ * {@code Object}. This method is equivalent to:
* <pre>{@code
* compareTo(when) < 0
* }</pre>
- * if and only if <code>when</code> is a <code>Calendar</code>
- * instance. Otherwise, the method returns <code>false</code>.
+ * if and only if {@code when} is a {@code Calendar}
+ * instance. Otherwise, the method returns {@code false}.
*
- * @param when the <code>Object</code> to be compared
- * @return <code>true</code> if the time of this
- * <code>Calendar</code> is before the time represented by
- * <code>when</code>; <code>false</code> otherwise.
+ * @param when the {@code Object} to be compared
+ * @return {@code true} if the time of this
+ * {@code Calendar} is before the time represented by
+ * {@code when}; {@code false} otherwise.
* @see #compareTo(Calendar)
*/
public boolean before(Object when) {
@@ -2791,18 +2822,18 @@
}
/**
- * Returns whether this <code>Calendar</code> represents a time
+ * Returns whether this {@code Calendar} represents a time
* after the time represented by the specified
- * <code>Object</code>. This method is equivalent to:
+ * {@code Object}. This method is equivalent to:
* <pre>{@code
* compareTo(when) > 0
* }</pre>
- * if and only if <code>when</code> is a <code>Calendar</code>
- * instance. Otherwise, the method returns <code>false</code>.
+ * if and only if {@code when} is a {@code Calendar}
+ * instance. Otherwise, the method returns {@code false}.
*
- * @param when the <code>Object</code> to be compared
- * @return <code>true</code> if the time of this <code>Calendar</code> is
- * after the time represented by <code>when</code>; <code>false</code>
+ * @param when the {@code Object} to be compared
+ * @return {@code true} if the time of this {@code Calendar} is
+ * after the time represented by {@code when}; {@code false}
* otherwise.
* @see #compareTo(Calendar)
*/
@@ -2814,19 +2845,19 @@
/**
* Compares the time values (millisecond offsets from the <a
* href="#Epoch">Epoch</a>) represented by two
- * <code>Calendar</code> objects.
+ * {@code Calendar} objects.
*
- * @param anotherCalendar the <code>Calendar</code> to be compared.
- * @return the value <code>0</code> if the time represented by the argument
- * is equal to the time represented by this <code>Calendar</code>; a value
- * less than <code>0</code> if the time of this <code>Calendar</code> is
+ * @param anotherCalendar the {@code Calendar} to be compared.
+ * @return the value {@code 0} if the time represented by the argument
+ * is equal to the time represented by this {@code Calendar}; a value
+ * less than {@code 0} if the time of this {@code Calendar} is
* before the time represented by the argument; and a value greater than
- * <code>0</code> if the time of this <code>Calendar</code> is after the
+ * {@code 0} if the time of this {@code Calendar} is after the
* time represented by the argument.
- * @exception NullPointerException if the specified <code>Calendar</code> is
- * <code>null</code>.
- * @exception IllegalArgumentException if the time value of the
- * specified <code>Calendar</code> object can't be obtained due to
+ * @throws NullPointerException if the specified {@code Calendar} is
+ * {@code null}.
+ * @throws IllegalArgumentException if the time value of the
+ * specified {@code Calendar} object can't be obtained due to
* any invalid calendar values.
* @since 1.5
*/
@@ -2839,7 +2870,7 @@
* Adds or subtracts the specified amount of time to the given calendar field,
* based on the calendar's rules. For example, to subtract 5 days from
* the current time of the calendar, you can achieve it by calling:
- * <p><code>add(Calendar.DAY_OF_MONTH, -5)</code>.
+ * <p>{@code add(Calendar.DAY_OF_MONTH, -5)}.
*
* @param field the calendar field.
* @param amount the amount of date or time to be added to the field.
@@ -2855,7 +2886,7 @@
* <p>roll(Calendar.DATE, true).
* When rolling on the year or Calendar.YEAR field, it will roll the year
* value in the range between 1 and the value returned by calling
- * <code>getMaximum(Calendar.YEAR)</code>.
+ * {@code getMaximum(Calendar.YEAR)}.
* When rolling on the month or Calendar.MONTH field, other fields like
* date might conflict and, need to be changed. For instance,
* rolling the month on the date 01/31/96 will result in 02/29/96.
@@ -2875,15 +2906,15 @@
* without changing larger fields. A negative amount means to roll
* down.
*
- * <p>NOTE: This default implementation on <code>Calendar</code> just repeatedly calls the
+ * <p>NOTE: This default implementation on {@code Calendar} just repeatedly calls the
* version of {@link #roll(int,boolean) roll()} that rolls by one unit. This may not
- * always do the right thing. For example, if the <code>DAY_OF_MONTH</code> field is 31,
- * rolling through February will leave it set to 28. The <code>GregorianCalendar</code>
+ * always do the right thing. For example, if the {@code DAY_OF_MONTH} field is 31,
+ * rolling through February will leave it set to 28. The {@code GregorianCalendar}
* version of this function takes care of this problem. Other subclasses
* should also provide overrides of this function that do the right thing.
*
* @param field the calendar field.
- * @param amount the signed amount to add to the calendar <code>field</code>.
+ * @param amount the signed amount to add to the calendar {@code field}.
* @since 1.2
* @see #roll(int,boolean)
* @see #add(int,int)
@@ -2946,7 +2977,7 @@
}
/**
- * Sets the sharedZone flag to <code>shared</code>.
+ * Sets the sharedZone flag to {@code shared}.
*/
void setZoneShared(boolean shared) {
sharedZone = shared;
@@ -2959,8 +2990,8 @@
* With strict (non-lenient) interpretation, such dates will cause an exception to be
* thrown. The default is lenient.
*
- * @param lenient <code>true</code> if the lenient mode is to be turned
- * on; <code>false</code> if it is to be turned off.
+ * @param lenient {@code true} if the lenient mode is to be turned
+ * on; {@code false} if it is to be turned off.
* @see #isLenient()
* @see java.text.DateFormat#setLenient
*/
@@ -2972,8 +3003,8 @@
/**
* Tells whether date/time interpretation is to be lenient.
*
- * @return <code>true</code> if the interpretation mode of this calendar is lenient;
- * <code>false</code> otherwise.
+ * @return {@code true} if the interpretation mode of this calendar is lenient;
+ * {@code false} otherwise.
* @see #setLenient(boolean)
*/
public boolean isLenient()
@@ -2982,8 +3013,8 @@
}
/**
- * Sets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
- * <code>MONDAY</code> in France.
+ * Sets what the first day of the week is; e.g., {@code SUNDAY} in the U.S.,
+ * {@code MONDAY} in France.
*
* @param value the given first day of the week.
* @see #getFirstDayOfWeek()
@@ -2999,8 +3030,8 @@
}
/**
- * Gets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
- * <code>MONDAY</code> in France.
+ * Gets what the first day of the week is; e.g., {@code SUNDAY} in the U.S.,
+ * {@code MONDAY} in France.
*
* @return the first day of the week.
* @see #setFirstDayOfWeek(int)
@@ -3071,7 +3102,7 @@
* {@link UnsupportedOperationException}.
*
* @return the week year of this {@code Calendar}
- * @exception UnsupportedOperationException
+ * @throws UnsupportedOperationException
* if any week year numbering isn't supported
* in this {@code Calendar}.
* @see #isWeekDateSupported()
@@ -3103,11 +3134,11 @@
* @param dayOfWeek the day of week value: one of the constants
* for the {@link #DAY_OF_WEEK} field: {@link
* #SUNDAY}, ..., {@link #SATURDAY}.
- * @exception IllegalArgumentException
+ * @throws IllegalArgumentException
* if any of the given date specifiers is invalid
* or any of the calendar fields are inconsistent
* with the given date specifiers in non-lenient mode
- * @exception UnsupportedOperationException
+ * @throws UnsupportedOperationException
* if any week year numbering isn't supported in this
* {@code Calendar}.
* @see #isWeekDateSupported()
@@ -3127,7 +3158,7 @@
* {@code UnsupportedOperationException}.
*
* @return the number of weeks in the week year.
- * @exception UnsupportedOperationException
+ * @throws UnsupportedOperationException
* if any week year numbering isn't supported in this
* {@code Calendar}.
* @see #WEEK_OF_YEAR
@@ -3142,7 +3173,7 @@
/**
* Returns the minimum value for the given calendar field of this
- * <code>Calendar</code> instance. The minimum value is defined as
+ * {@code Calendar} instance. The minimum value is defined as
* the smallest value returned by the {@link #get(int) get} method
* for any possible time value. The minimum value depends on
* calendar system specific parameters of the instance.
@@ -3159,7 +3190,7 @@
/**
* Returns the maximum value for the given calendar field of this
- * <code>Calendar</code> instance. The maximum value is defined as
+ * {@code Calendar} instance. The maximum value is defined as
* the largest value returned by the {@link #get(int) get} method
* for any possible time value. The maximum value depends on
* calendar system specific parameters of the instance.
@@ -3176,7 +3207,7 @@
/**
* Returns the highest minimum value for the given calendar field
- * of this <code>Calendar</code> instance. The highest minimum
+ * of this {@code Calendar} instance. The highest minimum
* value is defined as the largest value returned by {@link
* #getActualMinimum(int)} for any possible time value. The
* greatest minimum value depends on calendar system specific
@@ -3194,13 +3225,13 @@
/**
* Returns the lowest maximum value for the given calendar field
- * of this <code>Calendar</code> instance. The lowest maximum
+ * of this {@code Calendar} instance. The lowest maximum
* value is defined as the smallest value returned by {@link
* #getActualMaximum(int)} for any possible time value. The least
* maximum value depends on calendar system specific parameters of
- * the instance. For example, a <code>Calendar</code> for the
+ * the instance. For example, a {@code Calendar} for the
* Gregorian calendar system returns 28 for the
- * <code>DAY_OF_MONTH</code> field, because the 28th is the last
+ * {@code DAY_OF_MONTH} field, because the 28th is the last
* day of the shortest month of this calendar, February in a
* common year.
*
@@ -3216,17 +3247,17 @@
/**
* Returns the minimum value that the specified calendar field
- * could have, given the time value of this <code>Calendar</code>.
+ * could have, given the time value of this {@code Calendar}.
*
* <p>The default implementation of this method uses an iterative
* algorithm to determine the actual minimum value for the
* calendar field. Subclasses should, if possible, override this
* with a more efficient implementation - in many cases, they can
- * simply return <code>getMinimum()</code>.
+ * simply return {@code getMinimum()}.
*
* @param field the calendar field
* @return the minimum of the given calendar field for the time
- * value of this <code>Calendar</code>
+ * value of this {@code Calendar}
* @see #getMinimum(int)
* @see #getMaximum(int)
* @see #getGreatestMinimum(int)
@@ -3269,8 +3300,8 @@
/**
* Returns the maximum value that the specified calendar field
* could have, given the time value of this
- * <code>Calendar</code>. For example, the actual maximum value of
- * the <code>MONTH</code> field is 12 in some years, and 13 in
+ * {@code Calendar}. For example, the actual maximum value of
+ * the {@code MONTH} field is 12 in some years, and 13 in
* other years in the Hebrew calendar system.
*
* <p>The default implementation of this method uses an iterative
@@ -3280,7 +3311,7 @@
*
* @param field the calendar field
* @return the maximum of the given calendar field for the time
- * value of this <code>Calendar</code>
+ * value of this {@code Calendar}
* @see #getMinimum(int)
* @see #getMaximum(int)
* @see #getGreatestMinimum(int)
@@ -3345,7 +3376,9 @@
other.stamp[i] = stamp[i];
other.isSet[i] = isSet[i];
}
- other.zone = (TimeZone) zone.clone();
+ if (!sharedZone) {
+ other.zone = (TimeZone) zone.clone();
+ }
return other;
}
catch (CloneNotSupportedException e) {
@@ -3366,7 +3399,7 @@
*
* @param field the calendar field
* @return the calendar field name
- * @exception IndexOutOfBoundsException if <code>field</code> is negative,
+ * @throws IndexOutOfBoundsException if {@code field} is negative,
* equal to or greater than {@code FIELD_COUNT}.
*/
static String getFieldName(int field) {
@@ -3377,7 +3410,7 @@
* Return a string representation of this calendar. This method
* is intended to be used only for debugging purposes, and the
* format of the returned string may vary between implementations.
- * The returned string may be empty but may not be <code>null</code>.
+ * The returned string may be empty but may not be {@code null}.
*
* @return a string representation of this calendar.
*/
@@ -3538,16 +3571,17 @@
/**
* Save the state of this object to a stream (i.e., serialize it).
*
- * Ideally, <code>Calendar</code> would only write out its state data and
+ * Ideally, {@code Calendar} would only write out its state data and
* the current time, and not write any field data out, such as
- * <code>fields[]</code>, <code>isTimeSet</code>, <code>areFieldsSet</code>,
- * and <code>isSet[]</code>. <code>nextStamp</code> also should not be part
+ * {@code fields[]}, {@code isTimeSet}, {@code areFieldsSet},
+ * and {@code isSet[]}. {@code nextStamp} also should not be part
* of the persistent state. Unfortunately, this didn't happen before JDK 1.1
* shipped. To be compatible with JDK 1.1, we will always have to write out
- * the field values and state flags. However, <code>nextStamp</code> can be
+ * the field values and state flags. However, {@code nextStamp} can be
* removed from the serialization stream; this will probably happen in the
* near future.
*/
+ @java.io.Serial
private synchronized void writeObject(ObjectOutputStream stream)
throws IOException
{
@@ -3565,6 +3599,7 @@
stream.defaultWriteObject();
}
+ @SuppressWarnings("removal")
private static class CalendarAccessControlContext {
private static final AccessControlContext INSTANCE;
static {
@@ -3582,6 +3617,8 @@
/**
* Reconstitutes this object from a stream (i.e., deserialize it).
*/
+ @SuppressWarnings("removal")
+ @java.io.Serial
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException
{
diff --git a/ojluni/src/main/java/java/util/Collection.java b/ojluni/src/main/java/java/util/Collection.java
index dd773bc..b647526 100644
--- a/ojluni/src/main/java/java/util/Collection.java
+++ b/ojluni/src/main/java/java/util/Collection.java
@@ -188,6 +188,38 @@
* or if the only reference to the backing collection is through an
* unmodifiable view, the view can be considered effectively immutable.
*
+ * <h2><a id="serializable">Serializability of Collections</a></h2>
+ *
+ * <p>Serializability of collections is optional. As such, none of the collections
+ * interfaces are declared to implement the {@link java.io.Serializable} interface.
+ * However, serializability is regarded as being generally useful, so most collection
+ * implementations are serializable.
+ *
+ * <p>The collection implementations that are public classes (such as {@code ArrayList}
+ * or {@code HashMap}) are declared to implement the {@code Serializable} interface if they
+ * are in fact serializable. Some collections implementations are not public classes,
+ * such as the <a href="#unmodifiable">unmodifiable collections.</a> In such cases, the
+ * serializability of such collections is described in the specification of the method
+ * that creates them, or in some other suitable place. In cases where the serializability
+ * of a collection is not specified, there is no guarantee about the serializability of such
+ * collections. In particular, many <a href="#view">view collections</a> are not serializable.
+ *
+ * <p>A collection implementation that implements the {@code Serializable} interface cannot
+ * be guaranteed to be serializable. The reason is that in general, collections
+ * contain elements of other types, and it is not possible to determine statically
+ * whether instances of some element type are actually serializable. For example, consider
+ * a serializable {@code Collection<E>}, where {@code E} does not implement the
+ * {@code Serializable} interface. The collection may be serializable, if it contains only
+ * elements of some serializable subtype of {@code E}, or if it is empty. Collections are
+ * thus said to be <i>conditionally serializable,</i> as the serializability of the collection
+ * as a whole depends on whether the collection itself is serializable and on whether all
+ * contained elements are also serializable.
+ *
+ * <p>An additional case occurs with instances of {@link SortedSet} and {@link SortedMap}.
+ * These collections can be created with a {@link Comparator} that imposes an ordering on
+ * the set elements or map keys. Such a collection is serializable only if the provided
+ * {@code Comparator} is also serializable.
+ *
* <p>This interface is a member of the
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
* Java Collections Framework</a>.
diff --git a/ojluni/src/main/java/java/util/Comparator.java b/ojluni/src/main/java/java/util/Comparator.java
index 0516559..6e0420d 100644
--- a/ojluni/src/main/java/java/util/Comparator.java
+++ b/ojluni/src/main/java/java/util/Comparator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2021, 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,14 +33,16 @@
import java.util.Comparators;
/**
- * A comparison function, which imposes a <i>total ordering</i> on some
- * collection of objects. Comparators can be passed to a sort method (such
- * as {@link Collections#sort(List,Comparator) Collections.sort} or {@link
- * Arrays#sort(Object[],Comparator) Arrays.sort}) to allow precise control
- * over the sort order. Comparators can also be used to control the order of
- * certain data structures (such as {@link SortedSet sorted sets} or {@link
- * SortedMap sorted maps}), or to provide an ordering for collections of
- * objects that don't have a {@link Comparable natural ordering}.<p>
+ * A comparison function, which imposes a <i>total ordering</i> on
+ * some collection of objects. Comparators can be passed to a sort
+ * method (such as {@link Collections#sort(List,Comparator)
+ * Collections.sort} or {@link Arrays#sort(Object[],Comparator)
+ * Arrays.sort}) to allow precise control over the sort order.
+ * Comparators can also be used to control the order of certain data
+ * structures (such as {@linkplain SortedSet sorted sets} or
+ * {@linkplain SortedMap sorted maps}), or to provide an ordering for
+ * collections of objects that don't have a {@linkplain Comparable
+ * natural ordering}.<p>
*
* The ordering imposed by a comparator {@code c} on a set of elements
* {@code S} is said to be <i>consistent with equals</i> if and only if
@@ -89,6 +91,11 @@
* equals(Object)} method(s):<pre>
* {(x, y) such that x.equals(y)}. </pre>
*
+ * In other words, when the imposed ordering is consistent with
+ * equals, the equivalence classes defined by the equivalence relation
+ * of the {@code equals} method and the equivalence classes defined by
+ * the quotient of the {@code compare} method are the same.
+
* <p>Unlike {@code Comparable}, a comparator may optionally permit
* comparison of null arguments, while maintaining the requirements for
* an equivalence relation.
@@ -112,30 +119,26 @@
* zero, or a positive integer as the first argument is less than, equal
* to, or greater than the second.<p>
*
- * The implementor must ensure that {@code sgn(compare(x, y)) ==
- * -sgn(compare(y, x))} for all {@code x} and {@code y}. (This
- * implies that {@code compare(x, y)} must throw an exception if and only
- * if {@code compare(y, x)} throws an exception.)<p>
+ * The implementor must ensure that {@link Integer#signum
+ * signum}{@code (compare(x, y)) == -signum(compare(y, x))} for
+ * all {@code x} and {@code y}. (This implies that {@code
+ * compare(x, y)} must throw an exception if and only if {@code
+ * compare(y, x)} throws an exception.)<p>
*
* The implementor must also ensure that the relation is transitive:
* {@code ((compare(x, y)>0) && (compare(y, z)>0))} implies
* {@code compare(x, z)>0}.<p>
*
- * Finally, the implementor must ensure that {@code compare(x, y)==0}
- * implies that {@code sgn(compare(x, z))==sgn(compare(y, z))} for all
- * {@code z}.<p>
+ * Finally, the implementor must ensure that {@code compare(x,
+ * y)==0} implies that {@code signum(compare(x,
+ * z))==signum(compare(y, z))} for all {@code z}.
*
+ * @apiNote
* It is generally the case, but <i>not</i> strictly required that
* {@code (compare(x, y)==0) == (x.equals(y))}. Generally speaking,
* any comparator that violates this condition should clearly indicate
* this fact. The recommended language is "Note: this comparator
- * imposes orderings that are inconsistent with equals."<p>
- *
- * In the foregoing description, the notation
- * {@code sgn(}<i>expression</i>{@code )} designates the mathematical
- * <i>signum</i> function, which is defined to return one of {@code -1},
- * {@code 0}, or {@code 1} according to whether the value of
- * <i>expression</i> is negative, zero, or positive, respectively.
+ * imposes orderings that are inconsistent with equals."
*
* @param o1 the first object to be compared.
* @param o2 the second object to be compared.
@@ -150,13 +153,14 @@
int compare(T o1, T o2);
/**
- * Indicates whether some other object is "equal to" this
- * comparator. This method must obey the general contract of
- * {@link Object#equals(Object)}. Additionally, this method can return
- * {@code true} <i>only</i> if the specified object is also a comparator
- * and it imposes the same ordering as this comparator. Thus,
- * {@code comp1.equals(comp2)} implies that {@code sgn(comp1.compare(o1,
- * o2))==sgn(comp2.compare(o1, o2))} for every object reference
+ * Indicates whether some other object is "equal to"
+ * this comparator. This method must obey the general contract of
+ * {@link Object#equals(Object)}. Additionally, this method can
+ * return {@code true} <i>only</i> if the specified object is also
+ * a comparator and it imposes the same ordering as this
+ * comparator. Thus, {@code comp1.equals(comp2)} implies that
+ * {@link Integer#signum signum}{@code (comp1.compare(o1,
+ * o2))==signum(comp2.compare(o1, o2))} for every object reference
* {@code o1} and {@code o2}.<p>
*
* Note that it is <i>always</i> safe <i>not</i> to override
@@ -403,7 +407,7 @@
* Accepts a function that extracts a sort key from a type {@code T}, and
* returns a {@code Comparator<T>} that compares by that sort key using
* the specified {@link Comparator}.
- *
+ *
* <p>The returned comparator is serializable if the specified function
* and comparator are both serializable.
*
diff --git a/ojluni/src/main/java/java/util/Comparators.java b/ojluni/src/main/java/java/util/Comparators.java
index 8104f99..bca2bb6 100644
--- a/ojluni/src/main/java/java/util/Comparators.java
+++ b/ojluni/src/main/java/java/util/Comparators.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -62,9 +62,11 @@
* Null-friendly comparators
*/
static final class NullComparator<T> implements Comparator<T>, Serializable {
+ @java.io.Serial
private static final long serialVersionUID = -7569533591570686392L;
private final boolean nullFirst;
// if null, non-null Ts are considered equal
+ @SuppressWarnings("serial") // Not statically typed as Serializable
private final Comparator<T> real;
@SuppressWarnings("unchecked")
diff --git a/ojluni/src/main/java/java/util/ConcurrentModificationException.java b/ojluni/src/main/java/java/util/ConcurrentModificationException.java
index 7e65d2a..7161225 100644
--- a/ojluni/src/main/java/java/util/ConcurrentModificationException.java
+++ b/ojluni/src/main/java/java/util/ConcurrentModificationException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
@@ -68,6 +68,7 @@
* @since 1.2
*/
public class ConcurrentModificationException extends RuntimeException {
+ @java.io.Serial
private static final long serialVersionUID = -3666751008965953603L;
/**
@@ -106,7 +107,7 @@
* Constructs a new exception with the specified detail message and
* cause.
*
- * <p>Note that the detail message associated with <code>cause</code> is
+ * <p>Note that the detail message associated with {@code cause} is
* <i>not</i> automatically incorporated in this exception's detail
* message.
*
diff --git a/ojluni/src/main/java/java/util/Currency.java b/ojluni/src/main/java/java/util/Currency.java
index 8ceb03b..b2daecd 100644
--- a/ojluni/src/main/java/java/util/Currency.java
+++ b/ojluni/src/main/java/java/util/Currency.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2021, 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
@@ -51,9 +51,9 @@
* ISO web site</a> for more information.
* <p>
* The class is designed so that there's never more than one
- * <code>Currency</code> instance for any given currency. Therefore, there's
- * no public constructor. You obtain a <code>Currency</code> instance using
- * the <code>getInstance</code> methods.
+ * {@code Currency} instance for any given currency. Therefore, there's
+ * no public constructor. You obtain a {@code Currency} instance using
+ * the {@code getInstance} methods.
*
* <p>
* It is recommended to use {@link java.math.BigDecimal} class while dealing
@@ -64,8 +64,10 @@
* @since 1.4
*/
// END Android-changed: Removed docs about superseding runtime currency data.
+@SuppressWarnings("removal")
public final class Currency implements Serializable {
+ @java.io.Serial
private static final long serialVersionUID = -158308464356906721L;
/**
@@ -237,7 +239,7 @@
// END Android-removed: Use ICU.
/**
- * Constructs a <code>Currency</code> instance. The constructor is private
+ * Constructs a {@code Currency} instance. The constructor is private
* so that we can insure that there's never more than one instance for a
* given currency.
*/
@@ -257,12 +259,12 @@
// END Android-changed: Use ICU.
/**
- * Returns the <code>Currency</code> instance for the given currency code.
+ * Returns the {@code Currency} instance for the given currency code.
*
* @param currencyCode the ISO 4217 code of the currency
- * @return the <code>Currency</code> instance for the given currency code
- * @exception NullPointerException if <code>currencyCode</code> is null
- * @exception IllegalArgumentException if <code>currencyCode</code> is not
+ * @return the {@code Currency} instance for the given currency code
+ * @throws NullPointerException if {@code currencyCode} is null
+ * @throws IllegalArgumentException if {@code currencyCode} is not
* a supported ISO 4217 code.
*/
public static Currency getInstance(String currencyCode) {
@@ -323,7 +325,7 @@
// Android-changed: Remove "rg" support in the javadoc. See http://b/228322300.
/**
- * Returns the <code>Currency</code> instance for the country of the
+ * Returns the {@code Currency} instance for the country of the
* given locale. The language and variant components of the locale
* are ignored. The result may vary over time, as countries change their
* currencies. For example, for the original member countries of the
@@ -336,16 +338,16 @@
* the instance returned from this method reflects
* the values specified with those extensions.
* <p>
- * The method returns <code>null</code> for territories that don't
+ * The method returns {@code null} for territories that don't
* have a currency, such as Antarctica.
*
- * @param locale the locale for whose country a <code>Currency</code>
+ * @param locale the locale for whose country a {@code Currency}
* instance is needed
- * @return the <code>Currency</code> instance for the country of the given
+ * @return the {@code Currency} instance for the country of the given
* locale, or {@code null}
- * @exception NullPointerException if <code>locale</code>
+ * @throws NullPointerException if {@code locale}
* is {@code null}
- * @exception IllegalArgumentException if the country of the given {@code locale}
+ * @throws IllegalArgumentException if the country of the given {@code locale}
* is not a supported ISO 3166 country code.
*/
public static Currency getInstance(Locale locale) {
@@ -539,7 +541,7 @@
* @param locale the locale for which a display name for this currency is
* needed
* @return the symbol of this currency for the specified locale
- * @exception NullPointerException if <code>locale</code> is null
+ * @throws NullPointerException if {@code locale} is null
*/
public String getSymbol(Locale locale) {
// BEGIN Android-changed: Use ICU.
@@ -574,7 +576,7 @@
* -1 is returned.
*
* @return the default number of fraction digits used with this currency
- */
+ */
public int getDefaultFractionDigits() {
// BEGIN Android-changed: Use ICU.
// return defaultFractionDigits;
@@ -652,7 +654,7 @@
* @param locale the locale for which a display name for this currency is
* needed
* @return the display name of this currency for the specified locale
- * @exception NullPointerException if <code>locale</code> is null
+ * @throws NullPointerException if {@code locale} is null
* @since 1.7
*/
public String getDisplayName(Locale locale) {
@@ -688,6 +690,7 @@
/**
* Resolves instances being deserialized to a single instance per currency.
*/
+ @java.io.Serial
private Object readResolve() {
return getInstance(currencyCode);
}
@@ -969,13 +972,13 @@
*
private static class SpecialCaseEntry {
- final private long cutOverTime;
- final private String oldCurrency;
- final private String newCurrency;
- final private int oldCurrencyFraction;
- final private int newCurrencyFraction;
- final private int oldCurrencyNumericCode;
- final private int newCurrencyNumericCode;
+ private final long cutOverTime;
+ private final String oldCurrency;
+ private final String newCurrency;
+ private final int oldCurrencyFraction;
+ private final int newCurrencyFraction;
+ private final int oldCurrencyNumericCode;
+ private final int newCurrencyNumericCode;
private SpecialCaseEntry(long cutOverTime, String oldCurrency, String newCurrency,
int oldCurrencyFraction, int newCurrencyFraction,
@@ -1068,9 +1071,9 @@
*
private static class OtherCurrencyEntry {
- final private String currencyCode;
- final private int fraction;
- final private int numericCode;
+ private final String currencyCode;
+ private final int fraction;
+ private final int numericCode;
private OtherCurrencyEntry(String currencyCode, int fraction,
int numericCode) {
@@ -1105,11 +1108,11 @@
* - date: cutover date
*
private static class CurrencyProperty {
- final private String country;
- final private String currencyCode;
- final private int fraction;
- final private int numericCode;
- final private String date;
+ private final String country;
+ private final String currencyCode;
+ private final int fraction;
+ private final int numericCode;
+ private final String date;
private CurrencyProperty(String country, String currencyCode,
int fraction, int numericCode, String date) {
@@ -1224,5 +1227,3 @@
}
*/
}
-
-
diff --git a/ojluni/src/main/java/java/util/Dictionary.java b/ojluni/src/main/java/java/util/Dictionary.java
index c9825b4..6538947 100644
--- a/ojluni/src/main/java/java/util/Dictionary.java
+++ b/ojluni/src/main/java/java/util/Dictionary.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2020, 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
@@ -39,7 +39,6 @@
* <strong>NOTE: This class is obsolete. New implementations should
* implement the Map interface, rather than extending this class.</strong>
*
- * @author unascribed
* @see java.util.Map
* @see java.lang.Object#equals(java.lang.Object)
* @see java.lang.Object#hashCode()
@@ -106,7 +105,7 @@
* @param key a key in this dictionary.
* {@code null} if the key is not mapped to any value in
* this dictionary.
- * @exception NullPointerException if the {@code key} is {@code null}.
+ * @throws NullPointerException if the {@code key} is {@code null}.
* @see java.util.Dictionary#put(java.lang.Object, java.lang.Object)
*/
public abstract V get(Object key);
@@ -133,7 +132,7 @@
* @return the previous value to which the {@code key} was mapped
* in this dictionary, or {@code null} if the key did not
* have a previous mapping.
- * @exception NullPointerException if the {@code key} or
+ * @throws NullPointerException if the {@code key} or
* {@code value} is {@code null}.
* @see java.lang.Object#equals(java.lang.Object)
* @see java.util.Dictionary#get(java.lang.Object)
@@ -149,7 +148,7 @@
* @return the value to which the {@code key} had been mapped in this
* dictionary, or {@code null} if the key did not have a
* mapping.
- * @exception NullPointerException if {@code key} is {@code null}.
+ * @throws NullPointerException if {@code key} is {@code null}.
*/
public abstract V remove(Object key);
}
diff --git a/ojluni/src/main/java/java/util/DuplicateFormatFlagsException.java b/ojluni/src/main/java/java/util/DuplicateFormatFlagsException.java
index ec016a5..356ea20 100644
--- a/ojluni/src/main/java/java/util/DuplicateFormatFlagsException.java
+++ b/ojluni/src/main/java/java/util/DuplicateFormatFlagsException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -37,6 +37,7 @@
*/
public class DuplicateFormatFlagsException extends IllegalFormatException {
+ @java.io.Serial
private static final long serialVersionUID = 18890531L;
private String flags;
diff --git a/ojluni/src/main/java/java/util/EmptyStackException.java b/ojluni/src/main/java/java/util/EmptyStackException.java
index 53dcacd..6c74521 100644
--- a/ojluni/src/main/java/java/util/EmptyStackException.java
+++ b/ojluni/src/main/java/java/util/EmptyStackException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, 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 @@
* @see java.util.Stack
* @since 1.0
*/
-public
-class EmptyStackException extends RuntimeException {
+public class EmptyStackException extends RuntimeException {
+ @java.io.Serial
private static final long serialVersionUID = 5084686378493302095L;
/**
diff --git a/ojluni/src/main/java/java/util/EnumMap.java b/ojluni/src/main/java/java/util/EnumMap.java
index 66a767d..745dd2b 100644
--- a/ojluni/src/main/java/java/util/EnumMap.java
+++ b/ojluni/src/main/java/java/util/EnumMap.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,8 @@
package java.util;
+import jdk.internal.misc.SharedSecrets;
+
/**
* A specialized {@link Map} implementation for use with enum type keys. All
* of the keys in an enum map must come from a single enum type that is
@@ -47,7 +49,7 @@
* throw {@link NullPointerException}. Attempts to test for the
* presence of a null key or to remove one will, however, function properly.
* Null values are permitted.
-
+ *
* <P>Like most collection implementations {@code EnumMap} is not
* synchronized. If multiple threads access an enum map concurrently, and at
* least one of the threads modifies the map, it should be synchronized
@@ -327,8 +329,7 @@
* one or more keys in the specified map are null
*/
public void putAll(Map<? extends K, ? extends V> m) {
- if (m instanceof EnumMap) {
- EnumMap<?, ?> em = (EnumMap<?, ?>)m;
+ if (m instanceof EnumMap<?, ?> em) {
if (em.keyType != keyType) {
if (em.isEmpty())
return;
@@ -472,16 +473,12 @@
}
public boolean contains(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
- return containsMapping(entry.getKey(), entry.getValue());
+ return o instanceof Map.Entry<?, ?> entry
+ && containsMapping(entry.getKey(), entry.getValue());
}
public boolean remove(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
- return removeMapping(entry.getKey(), entry.getValue());
+ return o instanceof Map.Entry<?, ?> entry
+ && removeMapping(entry.getKey(), entry.getValue());
}
public int size() {
return size;
@@ -605,10 +602,9 @@
if (index < 0)
return o == this;
- if (!(o instanceof Map.Entry))
+ if (!(o instanceof Map.Entry<?, ?> e))
return false;
- Map.Entry<?,?> e = (Map.Entry<?,?>)o;
V ourValue = unmaskNull(vals[index]);
Object hisValue = e.getValue();
return (e.getKey() == keyUniverse[index] &&
@@ -654,10 +650,9 @@
return true;
if (o instanceof EnumMap)
return equals((EnumMap<?,?>)o);
- if (!(o instanceof Map))
+ if (!(o instanceof Map<?, ?> m))
return false;
- Map<?,?> m = (Map<?,?>)o;
if (size != m.size())
return false;
@@ -754,6 +749,7 @@
return keyType.getEnumConstantsShared();
}
+ @java.io.Serial
private static final long serialVersionUID = 458661240069192865L;
/**
@@ -765,6 +761,7 @@
* and value (Object) for each key-value mapping represented
* by the enum map.
*/
+ @java.io.Serial
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException
{
@@ -790,6 +787,7 @@
* deserialize it).
*/
@SuppressWarnings("unchecked")
+ @java.io.Serial
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException
{
diff --git a/ojluni/src/main/java/java/util/EnumSet.java b/ojluni/src/main/java/java/util/EnumSet.java
index cef74b7..527c4b7 100644
--- a/ojluni/src/main/java/java/util/EnumSet.java
+++ b/ojluni/src/main/java/java/util/EnumSet.java
@@ -26,6 +26,8 @@
package java.util;
+import jdk.internal.misc.SharedSecrets;
+
/**
* A specialized {@link Set} implementation for use with enum types. All of
* the elements in an enum set must come from a single enum type that is
@@ -75,26 +77,22 @@
* @since 1.5
* @see EnumMap
*/
-@SuppressWarnings("serial") // No serialVersionUID declared
public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
implements Cloneable, java.io.Serializable
{
- // The following must be present in order to preserve the same computed
- // serialVersionUID value as JDK 8, and to prevent the appearance of
- // the fields in the Serialized Form documentation. See JDK-8227368.
- static Enum<?>[] access$000() { return null; }
- private static final java.io.ObjectStreamField[] serialPersistentFields
- = new java.io.ObjectStreamField[0];
+ // declare EnumSet.class serialization compatibility with JDK 8
+ @java.io.Serial
+ private static final long serialVersionUID = 1009687484059888093L;
/**
* The class of all the elements of this set.
*/
- final Class<E> elementType;
+ final transient Class<E> elementType;
/**
* All of the values comprising E. (Cached for performance.)
*/
- final Enum<?>[] universe;
+ final transient Enum<?>[] universe;
EnumSet(Class<E>elementType, Enum<?>[] universe) {
this.elementType = elementType;
@@ -454,6 +452,7 @@
* held by this proxy
*/
@SuppressWarnings("unchecked")
+ @java.io.Serial
private Object readResolve() {
// instead of cast to E, we should perhaps use elementType.cast()
// to avoid injection of forged stream, but it will slow the
@@ -464,28 +463,42 @@
return result;
}
+ @java.io.Serial
private static final long serialVersionUID = 362491234563181265L;
}
/**
* Returns a
- * <a href="../../serialized-form.html#java.util.EnumSet.SerializationProxy">
+ * <a href="{@docRoot}/serialized-form.html#java.util.EnumSet.SerializationProxy">
* SerializationProxy</a>
* representing the state of this instance.
*
* @return a {@link SerializationProxy}
* representing the state of this instance
*/
+ @java.io.Serial
Object writeReplace() {
return new SerializationProxy<>(this);
}
/**
+ * Throws {@code InvalidObjectException}.
* @param s the stream
* @throws java.io.InvalidObjectException always
*/
+ @java.io.Serial
private void readObject(java.io.ObjectInputStream s)
throws java.io.InvalidObjectException {
throw new java.io.InvalidObjectException("Proxy required");
}
+
+ /**
+ * Throws {@code InvalidObjectException}.
+ * @throws java.io.InvalidObjectException always
+ */
+ @java.io.Serial
+ private void readObjectNoData()
+ throws java.io.InvalidObjectException {
+ throw new java.io.InvalidObjectException("Proxy required");
+ }
}
diff --git a/ojluni/src/main/java/java/util/Enumeration.java b/ojluni/src/main/java/java/util/Enumeration.java
index 96aa3a9..8d920c8 100644
--- a/ojluni/src/main/java/java/util/Enumeration.java
+++ b/ojluni/src/main/java/java/util/Enumeration.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2020, 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
@@ -76,7 +76,7 @@
* object has at least one more element to provide.
*
* @return the next element of this enumeration.
- * @exception NoSuchElementException if no more elements exist.
+ * @throws NoSuchElementException if no more elements exist.
*/
E nextElement();
@@ -88,7 +88,7 @@
* @apiNote
* This method is intended to help adapt code that produces
* {@code Enumeration} instances to code that consumes {@code Iterator}
- * instances. For example, the {@link java.util.jar.JarFile#entries
+ * instances. For example, the {@link java.util.jar.JarFile#entries()
* JarFile.entries()} method returns an {@code Enumeration<JarEntry>}.
* This can be turned into an {@code Iterator}, and then the
* {@code forEachRemaining()} method can be used:
@@ -98,7 +98,7 @@
* jarFile.entries().asIterator().forEachRemaining(entry -> { ... });
* }</pre>
*
- * (Note that there is also a {@link java.util.jar.JarFile#stream
+ * (Note that there is also a {@link java.util.jar.JarFile#stream()
* JarFile.stream()} method that returns a {@code Stream} of entries,
* which may be more convenient in some cases.)
*
diff --git a/ojluni/src/main/java/java/util/EventObject.java b/ojluni/src/main/java/java/util/EventObject.java
index ff89754..a90688b 100644
--- a/ojluni/src/main/java/java/util/EventObject.java
+++ b/ojluni/src/main/java/java/util/EventObject.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, 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
@@ -38,6 +38,7 @@
public class EventObject implements java.io.Serializable {
+ @java.io.Serial
private static final long serialVersionUID = 5516075349620653480L;
/**
diff --git a/ojluni/src/main/java/java/util/FormatFlagsConversionMismatchException.java b/ojluni/src/main/java/java/util/FormatFlagsConversionMismatchException.java
index 664cd39..6f2464d 100644
--- a/ojluni/src/main/java/java/util/FormatFlagsConversionMismatchException.java
+++ b/ojluni/src/main/java/java/util/FormatFlagsConversionMismatchException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -37,6 +37,7 @@
public class FormatFlagsConversionMismatchException
extends IllegalFormatException
{
+ @java.io.Serial
private static final long serialVersionUID = 19120414L;
private String f;
diff --git a/ojluni/src/main/java/java/util/FormatterClosedException.java b/ojluni/src/main/java/java/util/FormatterClosedException.java
index 856dc97..c75f3ff 100644
--- a/ojluni/src/main/java/java/util/FormatterClosedException.java
+++ b/ojluni/src/main/java/java/util/FormatterClosedException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -36,6 +36,7 @@
*/
public class FormatterClosedException extends IllegalStateException {
+ @java.io.Serial
private static final long serialVersionUID = 18111216L;
/**
diff --git a/ojluni/src/main/java/java/util/HashMap.java b/ojluni/src/main/java/java/util/HashMap.java
index 9d1e283..b5ae2ef 100644
--- a/ojluni/src/main/java/java/util/HashMap.java
+++ b/ojluni/src/main/java/java/util/HashMap.java
@@ -307,20 +307,9 @@
if (o == this)
return true;
- // BEGIN Android-changed: Patternmatching for instanceof is not available yet.
- /*
return o instanceof Map.Entry<?, ?> e
&& Objects.equals(key, e.getKey())
&& Objects.equals(value, e.getValue());
- */
- if (o instanceof Map.Entry) {
- Map.Entry<?,?> e = (Map.Entry<?,?>)o;
- if (Objects.equals(key, e.getKey()) &&
- Objects.equals(value, e.getValue()))
- return true;
- }
- return false;
- // END Android-changed: Patternmatching for instanceof is not available yet.
}
}
@@ -1109,26 +1098,14 @@
return new EntryIterator();
}
public final boolean contains(Object o) {
- // BEGIN Android-changed: Patternmatching for instanceof is not available yet.
- /*
if (!(o instanceof Map.Entry<?, ?> e))
- */
- if (!(o instanceof Map.Entry))
- // END Android-changed: Patternmatching for instanceof is not available yet.
return false;
- Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Node<K,V> candidate = getNode(key);
return candidate != null && candidate.equals(e);
}
public final boolean remove(Object o) {
- // BEGIN Android-changed: Patternmatching for instanceof is not available yet.
- /*
if (o instanceof Map.Entry<?, ?> e) {
- */
- if (o instanceof Map.Entry) {
- Map.Entry<?,?> e = (Map.Entry<?,?>) o;
- // END Android-changed: Patternmatching for instanceof is not available yet.
Object key = e.getKey();
Object value = e.getValue();
return removeNode(hash(key), key, value, true, true) != null;
diff --git a/ojluni/src/main/java/java/util/IdentityHashMap.java b/ojluni/src/main/java/java/util/IdentityHashMap.java
index b958539..197aee4 100644
--- a/ojluni/src/main/java/java/util/IdentityHashMap.java
+++ b/ojluni/src/main/java/java/util/IdentityHashMap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
package java.util;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
@@ -115,17 +117,19 @@
* exception for its correctness: <i>fail-fast iterators should be used only
* to detect bugs.</i>
*
- * <p>Implementation note: This is a simple <i>linear-probe</i> hash table,
- * as described for example in texts by Sedgewick and Knuth. The array
- * alternates holding keys and values. (This has better locality for large
- * tables than does using separate arrays.) For many JRE implementations
- * and operation mixes, this class will yield better performance than
- * {@link HashMap} (which uses <i>chaining</i> rather than linear-probing).
- *
* <p>This class is a member of the
* <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
* Java Collections Framework</a>.
*
+ * @implNote
+ * <p>This is a simple <i>linear-probe</i> hash table,
+ * as described for example in texts by Sedgewick and Knuth. The array
+ * contains alternating keys and values, with keys at even indexes and values
+ * at odd indexes. (This arrangement has better locality for large
+ * tables than does using separate arrays.) For many Java implementations
+ * and operation mixes, this class will yield better performance than
+ * {@link HashMap}, which uses <i>chaining</i> rather than linear-probing.
+ *
* @see System#identityHashCode(Object)
* @see Object#hashCode()
* @see Collection
@@ -293,7 +297,7 @@
*/
private static int hash(Object x, int length) {
int h = System.identityHashCode(x);
- // Multiply by -127, and left-shift to use least bit as part of hash
+ // Multiply by -254 to use the hash LSB and to ensure index is even
return ((h << 1) - (h << 8)) & (length - 1);
}
@@ -640,8 +644,7 @@
public boolean equals(Object o) {
if (o == this) {
return true;
- } else if (o instanceof IdentityHashMap) {
- IdentityHashMap<?,?> m = (IdentityHashMap<?,?>) o;
+ } else if (o instanceof IdentityHashMap<?, ?> m) {
if (m.size() != size)
return false;
@@ -652,8 +655,7 @@
return false;
}
return true;
- } else if (o instanceof Map) {
- Map<?,?> m = (Map<?,?>)o;
+ } else if (o instanceof Map<?, ?> m) {
return entrySet().equals(m.entrySet());
} else {
return false; // o is not a Map
@@ -886,11 +888,9 @@
if (index < 0)
return super.equals(o);
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry<?,?> e = (Map.Entry<?,?>)o;
- return (e.getKey() == unmaskNull(traversalTable[index]) &&
- e.getValue() == traversalTable[index+1]);
+ return o instanceof Map.Entry<?, ?> e
+ && e.getKey() == unmaskNull(traversalTable[index])
+ && e.getValue() == traversalTable[index+1];
}
public int hashCode() {
@@ -1187,16 +1187,12 @@
return new EntryIterator();
}
public boolean contains(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
- return containsMapping(entry.getKey(), entry.getValue());
+ return o instanceof Entry<?, ?> entry
+ && containsMapping(entry.getKey(), entry.getValue());
}
public boolean remove(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
- return removeMapping(entry.getKey(), entry.getValue());
+ return o instanceof Entry<?, ?> entry
+ && removeMapping(entry.getKey(), entry.getValue());
}
public int size() {
return size;
@@ -1259,7 +1255,7 @@
}
}
-
+ @java.io.Serial
private static final long serialVersionUID = 8188218128353913216L;
/**
@@ -1272,12 +1268,13 @@
* IdentityHashMap. The key-value mappings are emitted in no
* particular order.
*/
- private void writeObject(java.io.ObjectOutputStream s)
+ @java.io.Serial
+ private void writeObject(ObjectOutputStream s)
throws java.io.IOException {
- // Write out and any hidden stuff
+ // Write out size (number of mappings) and any hidden stuff
s.defaultWriteObject();
- // Write out size (number of Mappings)
+ // Write out size again (maintained for backward compatibility)
s.writeInt(size);
// Write out keys and values (alternating)
@@ -1295,18 +1292,21 @@
* Reconstitutes the {@code IdentityHashMap} instance from a stream (i.e.,
* deserializes it).
*/
- private void readObject(java.io.ObjectInputStream s)
+ @java.io.Serial
+ private void readObject(ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
- // Read in any hidden stuff
- s.defaultReadObject();
+ // Size (number of mappings) is written to the stream twice
+ // Read first size value and ignore it
+ s.readFields();
- // Read in size (number of Mappings)
+ // Read second size value, validate and assign to size field
int size = s.readInt();
if (size < 0)
throw new java.io.StreamCorruptedException
("Illegal mappings count: " + size);
int cap = capacity(size);
- SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, cap);
+ SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, cap*2);
+ this.size = size;
init(cap);
// Read the keys and values, and put the mappings in the table
diff --git a/ojluni/src/main/java/java/util/IllegalFormatCodePointException.java b/ojluni/src/main/java/java/util/IllegalFormatCodePointException.java
index d79d4997..14ec913 100644
--- a/ojluni/src/main/java/java/util/IllegalFormatCodePointException.java
+++ b/ojluni/src/main/java/java/util/IllegalFormatCodePointException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -38,6 +38,7 @@
*/
public class IllegalFormatCodePointException extends IllegalFormatException {
+ @java.io.Serial
private static final long serialVersionUID = 19080630L;
private int c;
diff --git a/ojluni/src/main/java/java/util/IllegalFormatConversionException.java b/ojluni/src/main/java/java/util/IllegalFormatConversionException.java
index 09ee5c4..2dacf20 100644
--- a/ojluni/src/main/java/java/util/IllegalFormatConversionException.java
+++ b/ojluni/src/main/java/java/util/IllegalFormatConversionException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -37,6 +37,7 @@
*/
public class IllegalFormatConversionException extends IllegalFormatException {
+ @java.io.Serial
private static final long serialVersionUID = 17000126L;
private char c;
diff --git a/ojluni/src/main/java/java/util/IllegalFormatException.java b/ojluni/src/main/java/java/util/IllegalFormatException.java
index 8f1d926..97b85cc1 100644
--- a/ojluni/src/main/java/java/util/IllegalFormatException.java
+++ b/ojluni/src/main/java/java/util/IllegalFormatException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -35,6 +35,7 @@
*/
public class IllegalFormatException extends IllegalArgumentException {
+ @java.io.Serial
private static final long serialVersionUID = 18830826L;
// package-private to prevent explicit instantiation
diff --git a/ojluni/src/main/java/java/util/IllegalFormatFlagsException.java b/ojluni/src/main/java/java/util/IllegalFormatFlagsException.java
index 5374f59..38e4e2d 100644
--- a/ojluni/src/main/java/java/util/IllegalFormatFlagsException.java
+++ b/ojluni/src/main/java/java/util/IllegalFormatFlagsException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -36,6 +36,7 @@
*/
public class IllegalFormatFlagsException extends IllegalFormatException {
+ @java.io.Serial
private static final long serialVersionUID = 790824L;
private String flags;
diff --git a/ojluni/src/main/java/java/util/IllegalFormatPrecisionException.java b/ojluni/src/main/java/java/util/IllegalFormatPrecisionException.java
index bc9c621..bdf3de6 100644
--- a/ojluni/src/main/java/java/util/IllegalFormatPrecisionException.java
+++ b/ojluni/src/main/java/java/util/IllegalFormatPrecisionException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -28,12 +28,15 @@
/**
* Unchecked exception thrown when the precision is a negative value other than
* {@code -1}, the conversion does not support a precision, or the value is
- * otherwise unsupported.
+ * otherwise unsupported. If the precision is not representable by an
+ * {@code int} type, then the value {@code Integer.MIN_VALUE} will be used
+ * in the exception.
*
* @since 1.5
*/
public class IllegalFormatPrecisionException extends IllegalFormatException {
+ @java.io.Serial
private static final long serialVersionUID = 18711008L;
private int p;
@@ -49,7 +52,8 @@
}
/**
- * Returns the precision
+ * Returns the precision. If the precision isn't representable by an
+ * {@code int}, then will return {@code Integer.MIN_VALUE}.
*
* @return The precision
*/
diff --git a/ojluni/src/main/java/java/util/IllegalFormatWidthException.java b/ojluni/src/main/java/java/util/IllegalFormatWidthException.java
index c7b7823..e00ec01 100644
--- a/ojluni/src/main/java/java/util/IllegalFormatWidthException.java
+++ b/ojluni/src/main/java/java/util/IllegalFormatWidthException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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,12 +27,15 @@
/**
* Unchecked exception thrown when the format width is a negative value other
- * than {@code -1} or is otherwise unsupported.
+ * than {@code -1} or is otherwise unsupported. If a given format width is not
+ * representable by an {@code int} type, then the value
+ * {@code Integer.MIN_VALUE} will be used in the exception.
*
* @since 1.5
*/
public class IllegalFormatWidthException extends IllegalFormatException {
+ @java.io.Serial
private static final long serialVersionUID = 16660902L;
private int w;
@@ -48,7 +51,8 @@
}
/**
- * Returns the width
+ * Returns the width. If the width is not representable by an {@code int},
+ * then returns {@code Integer.MIN_VALUE}.
*
* @return The width
*/
diff --git a/ojluni/src/main/java/java/util/IllformedLocaleException.java b/ojluni/src/main/java/java/util/IllformedLocaleException.java
index 5c0c4da..47febaa 100644
--- a/ojluni/src/main/java/java/util/IllformedLocaleException.java
+++ b/ojluni/src/main/java/java/util/IllformedLocaleException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2019, 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
@@ -41,12 +41,13 @@
*/
public class IllformedLocaleException extends RuntimeException {
+ @java.io.Serial
private static final long serialVersionUID = -5245986824925681401L;
private int _errIdx = -1;
/**
- * Constructs a new <code>IllformedLocaleException</code> with no
+ * Constructs a new {@code IllformedLocaleException} with no
* detail message and -1 as the error index.
*/
public IllformedLocaleException() {
@@ -54,7 +55,7 @@
}
/**
- * Constructs a new <code>IllformedLocaleException</code> with the
+ * Constructs a new {@code IllformedLocaleException} with the
* given message and -1 as the error index.
*
* @param message the message
@@ -64,7 +65,7 @@
}
/**
- * Constructs a new <code>IllformedLocaleException</code> with the
+ * Constructs a new {@code IllformedLocaleException} with the
* given message and the error index. The error index is the approximate
* offset from the start of the ill-formed value to the point where the
* parse first detected an error. A negative error index value indicates
diff --git a/ojluni/src/main/java/java/util/ImmutableCollections.java b/ojluni/src/main/java/java/util/ImmutableCollections.java
index 7db25a9..a3d8a5e 100644
--- a/ojluni/src/main/java/java/util/ImmutableCollections.java
+++ b/ojluni/src/main/java/java/util/ImmutableCollections.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2020, 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,12 +31,12 @@
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
+import java.lang.reflect.Array;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import jdk.internal.misc.SharedSecrets;
-import jdk.internal.misc.VM;
import jdk.internal.vm.annotation.Stable;
/**
@@ -54,12 +54,92 @@
* it needs to vary sufficiently from one run to the next so that iteration order
* will vary between JVM runs.
*/
- static final int SALT;
+ private static final long SALT32L;
+
+ /**
+ * For set and map iteration, we will iterate in "reverse" stochastically,
+ * decided at bootstrap time.
+ */
+ private static final boolean REVERSE;
static {
- long nt = System.nanoTime();
- SALT = (int)((nt >>> 32) ^ nt);
+ // to generate a reasonably random and well-mixed SALT, use an arbitrary
+ // value (a slice of pi), multiply with a random seed, then pick
+ // the mid 32-bits from the product. By picking a SALT value in the
+ // [0 ... 0xFFFF_FFFFL == 2^32-1] range, we ensure that for any positive
+ // int N, (SALT32L * N) >> 32 is a number in the [0 ... N-1] range. This
+ // property will be used to avoid more expensive modulo-based
+ // calculations.
+ long color = 0x243F_6A88_85A3_08D3L; // slice of pi
+
+ // BEGIN Android-changed: set seed directly, as CDS is not available.
+ // When running with -Xshare:dump, the VM will supply a "random" seed that's
+ // derived from the JVM build/version, so can we generate the exact same
+ // CDS archive for the same JDK build. This makes it possible to verify the
+ // consistency of the JDK build.
+ // long seed = CDS.getRandomSeedForDumping();
+ // if (seed == 0) {
+ // seed = System.nanoTime();
+ // }
+ long seed = System.nanoTime();
+ // END Android-changed: set seed directly, as CDS is not available.
+ SALT32L = (int)((color * seed) >> 16) & 0xFFFF_FFFFL;
+ // use the lowest bit to determine if we should reverse iteration
+ REVERSE = (SALT32L & 1) == 0;
}
+ // BEGIN Android-changed: always initialize empty collections.
+ /*
+ * Constants following this might be initialized from the CDS archive via
+ * this array.
+ *
+ // private static Object[] archivedObjects;
+ */
+
+ private static final Object EMPTY = new Object();
+ static final ListN<?> EMPTY_LIST = new ListN<>(new Object[0], false);
+ static final ListN<?> EMPTY_LIST_NULLS = new ListN<>(new Object[0], true);
+ static final SetN<?> EMPTY_SET = new SetN<>();
+ static final MapN<?,?> EMPTY_MAP = new MapN<>();
+
+ /*
+ static {
+ CDS.initializeFromArchive(ImmutableCollections.class);
+ if (archivedObjects == null) {
+ EMPTY = new Object();
+ EMPTY_LIST = new ListN<>(new Object[0], false);
+ EMPTY_LIST_NULLS = new ListN<>(new Object[0], true);
+ EMPTY_SET = new SetN<>();
+ EMPTY_MAP = new MapN<>();
+ archivedObjects =
+ new Object[] { EMPTY, EMPTY_LIST, EMPTY_LIST_NULLS, EMPTY_SET, EMPTY_MAP };
+ } else {
+ EMPTY = archivedObjects[0];
+ EMPTY_LIST = (ListN)archivedObjects[1];
+ EMPTY_LIST_NULLS = (ListN)archivedObjects[2];
+ EMPTY_SET = (SetN)archivedObjects[3];
+ EMPTY_MAP = (MapN)archivedObjects[4];
+ }
+ }
+ */
+ // END Android-changed: always initialize empty collections.
+
+ // BEGIN Android-changed: JavaUtilCollectionAccess is not yet imported.
+ /*
+ static class Access {
+ static {
+ SharedSecrets.setJavaUtilCollectionAccess(new JavaUtilCollectionAccess() {
+ public <E> List<E> listFromTrustedArray(Object[] array) {
+ return ImmutableCollections.listFromTrustedArray(array);
+ }
+ public <E> List<E> listFromTrustedArrayNullsAllowed(Object[] array) {
+ return ImmutableCollections.listFromTrustedArrayNullsAllowed(array);
+ }
+ });
+ }
+ }
+ */
+ // END Android-changed: JavaUtilCollectionAccess is not yet imported.
+
/** No instances. */
private ImmutableCollections() { }
@@ -71,6 +151,7 @@
static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
+ @jdk.internal.ValueBased
static abstract class AbstractImmutableCollection<E> extends AbstractCollection<E> {
// all mutating methods throw UnsupportedOperationException
@Override public boolean add(E e) { throw uoe(); }
@@ -82,23 +163,102 @@
@Override public boolean retainAll(Collection<?> c) { throw uoe(); }
}
- // ---------- List Implementations ----------
+ // ---------- List Static Factory Methods ----------
- // make a copy, short-circuiting based on implementation class
+ /**
+ * Copies a collection into a new List, unless the arg is already a safe,
+ * null-prohibiting unmodifiable list, in which case the arg itself is returned.
+ * Null argument or null elements in the argument will result in NPE.
+ *
+ * @param <E> the List's element type
+ * @param input the input array
+ * @return the new list
+ */
@SuppressWarnings("unchecked")
static <E> List<E> listCopy(Collection<? extends E> coll) {
- if (coll instanceof AbstractImmutableList && coll.getClass() != SubList.class) {
+ if (coll instanceof List12 || (coll instanceof ListN && ! ((ListN<?>)coll).allowNulls)) {
return (List<E>)coll;
} else {
- return (List<E>)List.of(coll.toArray());
+ return (List<E>)List.of(coll.toArray()); // implicit nullcheck of coll
}
}
- @SuppressWarnings("unchecked")
- static <E> List<E> emptyList() {
- return (List<E>) ListN.EMPTY_LIST;
+ /**
+ * Creates a new List from an untrusted array, creating a new array for internal
+ * storage, and checking for and rejecting null elements.
+ *
+ * @param <E> the List's element type
+ * @param input the input array
+ * @return the new list
+ */
+ @SafeVarargs
+ static <E> List<E> listFromArray(E... input) {
+ // copy and check manually to avoid TOCTOU
+ @SuppressWarnings("unchecked")
+ E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
+ for (int i = 0; i < input.length; i++) {
+ tmp[i] = Objects.requireNonNull(input[i]);
+ }
+ return new ListN<>(tmp, false);
}
+ /**
+ * Creates a new List from a trusted array, checking for and rejecting null
+ * elements.
+ *
+ * <p>A trusted array has no references retained by the caller. It can therefore be
+ * safely reused as the List's internal storage, avoiding a defensive copy. The array's
+ * class must be Object[].class. This method is declared with a parameter type of
+ * Object... instead of E... so that a varargs call doesn't accidentally create an array
+ * of some class other than Object[].class.
+ *
+ * @param <E> the List's element type
+ * @param input the input array
+ * @return the new list
+ */
+ @SuppressWarnings("unchecked")
+ static <E> List<E> listFromTrustedArray(Object... input) {
+ assert input.getClass() == Object[].class;
+ for (Object o : input) { // implicit null check of 'input' array
+ Objects.requireNonNull(o);
+ }
+
+ return switch (input.length) {
+ case 0 -> (List<E>) ImmutableCollections.EMPTY_LIST;
+ case 1 -> (List<E>) new List12<>(input[0]);
+ case 2 -> (List<E>) new List12<>(input[0], input[1]);
+ default -> (List<E>) new ListN<>(input, false);
+ };
+ }
+
+ /**
+ * Creates a new List from a trusted array, allowing null elements.
+ *
+ * <p>A trusted array has no references retained by the caller. It can therefore be
+ * safely reused as the List's internal storage, avoiding a defensive copy. The array's
+ * class must be Object[].class. This method is declared with a parameter type of
+ * Object... instead of E... so that a varargs call doesn't accidentally create an array
+ * of some class other than Object[].class.
+ *
+ * <p>Avoids creating a List12 instance, as it cannot accommodate null elements.
+ *
+ * @param <E> the List's element type
+ * @param input the input array
+ * @return the new list
+ */
+ @SuppressWarnings("unchecked")
+ static <E> List<E> listFromTrustedArrayNullsAllowed(Object... input) {
+ assert input.getClass() == Object[].class;
+ if (input.length == 0) {
+ return (List<E>) EMPTY_LIST_NULLS;
+ } else {
+ return new ListN<>((E[])input, true);
+ }
+ }
+
+ // ---------- List Implementations ----------
+
+ @jdk.internal.ValueBased
static abstract class AbstractImmutableList<E> extends AbstractImmutableCollection<E>
implements List<E>, RandomAccess {
@@ -158,7 +318,7 @@
Iterator<?> oit = ((List<?>) o).iterator();
for (int i = 0, s = size(); i < s; i++) {
- if (!oit.hasNext() || !get(i).equals(oit.next())) {
+ if (!oit.hasNext() || !Objects.equals(get(i), oit.next())) {
return false;
}
}
@@ -166,32 +326,10 @@
}
@Override
- public int indexOf(Object o) {
- Objects.requireNonNull(o);
- for (int i = 0, s = size(); i < s; i++) {
- if (o.equals(get(i))) {
- return i;
- }
- }
- return -1;
- }
-
- @Override
- public int lastIndexOf(Object o) {
- Objects.requireNonNull(o);
- for (int i = size() - 1; i >= 0; i--) {
- if (o.equals(get(i))) {
- return i;
- }
- }
- return -1;
- }
-
- @Override
public int hashCode() {
int hash = 1;
for (int i = 0, s = size(); i < s; i++) {
- hash = 31 * hash + get(i).hashCode();
+ hash = 31 * hash + Objects.hashCode(get(i));
}
return hash;
}
@@ -300,7 +438,7 @@
implements RandomAccess {
@Stable
- private final List<E> root;
+ private final AbstractImmutableList<E> root;
@Stable
private final int offset;
@@ -308,7 +446,8 @@
@Stable
private final int size;
- private SubList(List<E> root, int offset, int size) {
+ private SubList(AbstractImmutableList<E> root, int offset, int size) {
+ assert root instanceof List12 || root instanceof ListN;
this.root = root;
this.offset = offset;
this.size = size;
@@ -325,7 +464,7 @@
* Constructs a sublist of an arbitrary AbstractImmutableList, which is
* not a SubList itself.
*/
- static <E> SubList<E> fromList(List<E> list, int fromIndex, int toIndex) {
+ static <E> SubList<E> fromList(AbstractImmutableList<E> list, int fromIndex, int toIndex) {
return new SubList<>(list, fromIndex, toIndex - fromIndex);
}
@@ -357,8 +496,63 @@
throw outOfBounds(index);
}
}
+
+ private boolean allowNulls() {
+ return root instanceof ListN && ((ListN<?>)root).allowNulls;
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ if (!allowNulls() && o == null) {
+ throw new NullPointerException();
+ }
+ for (int i = 0, s = size(); i < s; i++) {
+ if (Objects.equals(o, get(i))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ if (!allowNulls() && o == null) {
+ throw new NullPointerException();
+ }
+ for (int i = size() - 1; i >= 0; i--) {
+ if (Objects.equals(o, get(i))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public Object[] toArray() {
+ Object[] array = new Object[size];
+ for (int i = 0; i < size; i++) {
+ array[i] = get(i);
+ }
+ return array;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T[] toArray(T[] a) {
+ T[] array = a.length >= size ? a :
+ (T[])java.lang.reflect.Array
+ .newInstance(a.getClass().getComponentType(), size);
+ for (int i = 0; i < size; i++) {
+ array[i] = (T)get(i);
+ }
+ if (array.length > size) {
+ array[size] = null; // null-terminate
+ }
+ return array;
+ }
}
+ @jdk.internal.ValueBased
static final class List12<E> extends AbstractImmutableList<E>
implements Serializable {
@@ -366,11 +560,13 @@
private final E e0;
@Stable
- private final E e1;
+ private final Object e1;
List12(E e0) {
this.e0 = Objects.requireNonNull(e0);
- this.e1 = null;
+ // Use EMPTY as a sentinel for an unused element: not using null
+ // enables constant folding optimizations over single-element lists
+ this.e1 = EMPTY;
}
List12(E e0, E e1) {
@@ -380,64 +576,108 @@
@Override
public int size() {
- return e1 != null ? 2 : 1;
+ return e1 != EMPTY ? 2 : 1;
}
@Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
public E get(int index) {
if (index == 0) {
return e0;
- } else if (index == 1 && e1 != null) {
- return e1;
+ } else if (index == 1 && e1 != EMPTY) {
+ return (E)e1;
}
throw outOfBounds(index);
}
+ @Override
+ public int indexOf(Object o) {
+ Objects.requireNonNull(o);
+ if (o.equals(e0)) {
+ return 0;
+ } else if (e1 != EMPTY && o.equals(e1)) {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ Objects.requireNonNull(o);
+ if (e1 != EMPTY && o.equals(e1)) {
+ return 1;
+ } else if (o.equals(e0)) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+
+ @java.io.Serial
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
throw new InvalidObjectException("not serial proxy");
}
+ @java.io.Serial
private Object writeReplace() {
- if (e1 == null) {
+ if (e1 == EMPTY) {
return new CollSer(CollSer.IMM_LIST, e0);
} else {
return new CollSer(CollSer.IMM_LIST, e0, e1);
}
}
- }
-
- static final class ListN<E> extends AbstractImmutableList<E>
- implements Serializable {
-
- // EMPTY_LIST may be initialized from the CDS archive.
- static @Stable List<?> EMPTY_LIST;
-
- static {
- // Android-removed: CDS is not supported.
- // VM.initializeFromArchive(ListN.class);
- if (EMPTY_LIST == null) {
- EMPTY_LIST = new ListN<>();
+ @Override
+ public Object[] toArray() {
+ if (e1 == EMPTY) {
+ return new Object[] { e0 };
+ } else {
+ return new Object[] { e0, e1 };
}
}
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T[] toArray(T[] a) {
+ int size = size();
+ T[] array = a.length >= size ? a :
+ (T[])Array.newInstance(a.getClass().getComponentType(), size);
+ array[0] = (T)e0;
+ if (size == 2) {
+ array[1] = (T)e1;
+ }
+ if (array.length > size) {
+ array[size] = null; // null-terminate
+ }
+ return array;
+ }
+ }
+
+ @jdk.internal.ValueBased
+ static final class ListN<E> extends AbstractImmutableList<E>
+ implements Serializable {
+
@Stable
private final E[] elements;
- @SafeVarargs
- ListN(E... input) {
- // copy and check manually to avoid TOCTOU
- @SuppressWarnings("unchecked")
- E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
- for (int i = 0; i < input.length; i++) {
- tmp[i] = Objects.requireNonNull(input[i]);
- }
- elements = tmp;
+ @Stable
+ private final boolean allowNulls;
+
+ // caller must ensure that elements has no nulls if allowNulls is false
+ private ListN(E[] elements, boolean allowNulls) {
+ this.elements = elements;
+ this.allowNulls = allowNulls;
}
@Override
public boolean isEmpty() {
- return size() == 0;
+ return elements.length == 0;
}
@Override
@@ -450,17 +690,68 @@
return elements[index];
}
+ @java.io.Serial
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
throw new InvalidObjectException("not serial proxy");
}
+ @java.io.Serial
private Object writeReplace() {
- return new CollSer(CollSer.IMM_LIST, elements);
+ return new CollSer(allowNulls ? CollSer.IMM_LIST_NULLS : CollSer.IMM_LIST, elements);
+ }
+
+ @Override
+ public Object[] toArray() {
+ return Arrays.copyOf(elements, elements.length);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T[] toArray(T[] a) {
+ int size = elements.length;
+ if (a.length < size) {
+ // Make a new array of a's runtime type, but my contents:
+ return (T[]) Arrays.copyOf(elements, size, a.getClass());
+ }
+ System.arraycopy(elements, 0, a, 0, size);
+ if (a.length > size) {
+ a[size] = null; // null-terminate
+ }
+ return a;
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ if (!allowNulls && o == null) {
+ throw new NullPointerException();
+ }
+ Object[] es = elements;
+ for (int i = 0; i < es.length; i++) {
+ if (Objects.equals(o, es[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ if (!allowNulls && o == null) {
+ throw new NullPointerException();
+ }
+ Object[] es = elements;
+ for (int i = es.length - 1; i >= 0; i--) {
+ if (Objects.equals(o, es[i])) {
+ return i;
+ }
+ }
+ return -1;
}
}
// ---------- Set Implementations ----------
+ @jdk.internal.ValueBased
static abstract class AbstractImmutableSet<E> extends AbstractImmutableCollection<E>
implements Set<E> {
@@ -488,22 +779,21 @@
public abstract int hashCode();
}
- @SuppressWarnings("unchecked")
- static <E> Set<E> emptySet() {
- return (Set<E>) SetN.EMPTY_SET;
- }
-
+ @jdk.internal.ValueBased
static final class Set12<E> extends AbstractImmutableSet<E>
implements Serializable {
@Stable
- final E e0;
+ private final E e0;
+
@Stable
- final E e1;
+ private final Object e1;
Set12(E e0) {
this.e0 = Objects.requireNonNull(e0);
- this.e1 = null;
+ // Use EMPTY as a sentinel for an unused element: not using null
+ // enable constant folding optimizations over single-element sets
+ this.e1 = EMPTY;
}
Set12(E e0, E e1) {
@@ -517,23 +807,28 @@
@Override
public int size() {
- return (e1 == null) ? 1 : 2;
+ return (e1 == EMPTY) ? 1 : 2;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
}
@Override
public boolean contains(Object o) {
- return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
+ return o.equals(e0) || e1.equals(o); // implicit nullcheck of o
}
@Override
public int hashCode() {
- return e0.hashCode() + (e1 == null ? 0 : e1.hashCode());
+ return e0.hashCode() + (e1 == EMPTY ? 0 : e1.hashCode());
}
@Override
public Iterator<E> iterator() {
return new Iterator<>() {
- private int idx = size();
+ private int idx = (e1 == EMPTY) ? 1 : 2;
@Override
public boolean hasNext() {
@@ -541,13 +836,14 @@
}
@Override
+ @SuppressWarnings("unchecked")
public E next() {
if (idx == 1) {
idx = 0;
- return SALT >= 0 || e1 == null ? e0 : e1;
+ return (REVERSE || e1 == EMPTY) ? e0 : (E)e1;
} else if (idx == 2) {
idx = 1;
- return SALT >= 0 ? e1 : e0;
+ return REVERSE ? (E)e1 : e0;
} else {
throw new NoSuchElementException();
}
@@ -555,41 +851,67 @@
};
}
+ @java.io.Serial
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
throw new InvalidObjectException("not serial proxy");
}
+ @java.io.Serial
private Object writeReplace() {
- if (e1 == null) {
+ if (e1 == EMPTY) {
return new CollSer(CollSer.IMM_SET, e0);
} else {
return new CollSer(CollSer.IMM_SET, e0, e1);
}
}
+
+ @Override
+ public Object[] toArray() {
+ if (e1 == EMPTY) {
+ return new Object[] { e0 };
+ } else if (REVERSE) {
+ return new Object[] { e1, e0 };
+ } else {
+ return new Object[] { e0, e1 };
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T[] toArray(T[] a) {
+ int size = size();
+ T[] array = a.length >= size ? a :
+ (T[])Array.newInstance(a.getClass().getComponentType(), size);
+ if (size == 1) {
+ array[0] = (T)e0;
+ } else if (REVERSE) {
+ array[0] = (T)e1;
+ array[1] = (T)e0;
+ } else {
+ array[0] = (T)e0;
+ array[1] = (T)e1;
+ }
+ if (array.length > size) {
+ array[size] = null; // null-terminate
+ }
+ return array;
+ }
}
+
/**
* An array-based Set implementation. The element array must be strictly
* larger than the size (the number of contained elements) so that at
* least one null is always present.
* @param <E> the element type
*/
+ @jdk.internal.ValueBased
static final class SetN<E> extends AbstractImmutableSet<E>
implements Serializable {
- // EMPTY_SET may be initialized from the CDS archive.
- static @Stable Set<?> EMPTY_SET;
-
- static {
- // Android-removed: CDS is not supported.
- // VM.initializeFromArchive(SetN.class);
- if (EMPTY_SET == null) {
- EMPTY_SET = new SetN<>();
- }
- }
-
@Stable
final E[] elements;
+
@Stable
final int size;
@@ -616,6 +938,11 @@
}
@Override
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
+ @Override
public boolean contains(Object o) {
Objects.requireNonNull(o);
return size > 0 && probe(o) >= 0;
@@ -628,10 +955,10 @@
private int idx;
SetNIterator() {
- remaining = size();
- if (remaining > 0) {
- idx = Math.floorMod(SALT, elements.length);
- }
+ remaining = size;
+ // pick a starting index in the [0 .. element.length-1] range
+ // randomly based on SALT32L
+ idx = (int) ((SALT32L * elements.length) >>> 32);
}
@Override
@@ -639,26 +966,25 @@
return remaining > 0;
}
- private int nextIndex() {
- int idx = this.idx;
- if (SALT >= 0) {
- if (++idx >= elements.length) {
- idx = 0;
- }
- } else {
- if (--idx < 0) {
- idx = elements.length - 1;
- }
- }
- return this.idx = idx;
- }
-
@Override
public E next() {
- if (hasNext()) {
+ if (remaining > 0) {
E element;
- // skip null elements
- while ((element = elements[nextIndex()]) == null) {}
+ int idx = this.idx;
+ int len = elements.length;
+ // step to the next element; skip null elements
+ do {
+ if (REVERSE) {
+ if (++idx >= len) {
+ idx = 0;
+ }
+ } else {
+ if (--idx < 0) {
+ idx = len - 1;
+ }
+ }
+ } while ((element = elements[idx]) == null);
+ this.idx = idx;
remaining--;
return element;
} else {
@@ -701,10 +1027,12 @@
}
}
+ @java.io.Serial
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
throw new InvalidObjectException("not serial proxy");
}
+ @java.io.Serial
private Object writeReplace() {
Object[] array = new Object[size];
int dest = 0;
@@ -715,15 +1043,36 @@
}
return new CollSer(CollSer.IMM_SET, array);
}
+
+ @Override
+ public Object[] toArray() {
+ Object[] array = new Object[size];
+ Iterator<E> it = iterator();
+ for (int i = 0; i < size; i++) {
+ array[i] = it.next();
+ }
+ return array;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T[] toArray(T[] a) {
+ T[] array = a.length >= size ? a :
+ (T[])Array.newInstance(a.getClass().getComponentType(), size);
+ Iterator<E> it = iterator();
+ for (int i = 0; i < size; i++) {
+ array[i] = (T)it.next();
+ }
+ if (array.length > size) {
+ array[size] = null; // null-terminate
+ }
+ return array;
+ }
}
// ---------- Map Implementations ----------
- @SuppressWarnings("unchecked")
- static <K,V> Map<K,V> emptyMap() {
- return (Map<K,V>) MapN.EMPTY_MAP;
- }
-
+ @jdk.internal.ValueBased
abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
@Override public void clear() { throw uoe(); }
@Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
@@ -738,8 +1087,23 @@
@Override public V replace(K key, V value) { throw uoe(); }
@Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
@Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
+
+ /**
+ * @implNote {@code null} values are disallowed in these immutable maps,
+ * so we can improve upon the default implementation since a
+ * {@code null} return from {@code get(key)} always means the default
+ * value should be returned.
+ */
+ @Override
+ public V getOrDefault(Object key, V defaultValue) {
+ V v;
+ return ((v = get(key)) != null)
+ ? v
+ : defaultValue;
+ }
}
+ @jdk.internal.ValueBased
static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
@Stable
private final K k0;
@@ -771,10 +1135,22 @@
return o.equals(v0); // implicit nullcheck of o
}
+ @Override
+ public int size() {
+ return 1;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @java.io.Serial
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
throw new InvalidObjectException("not serial proxy");
}
+ @java.io.Serial
private Object writeReplace() {
return new CollSer(CollSer.IMM_MAP, k0, v0);
}
@@ -794,19 +1170,9 @@
* @param <K> the key type
* @param <V> the value type
*/
+ @jdk.internal.ValueBased
static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
- // EMPTY_MAP may be initialized from the CDS archive.
- static @Stable Map<?,?> EMPTY_MAP;
-
- static {
- // Android-removed: CDS is not supported.
- // VM.initializeFromArchive(MapN.class);
- if (EMPTY_MAP == null) {
- EMPTY_MAP = new MapN<>();
- }
- }
-
@Stable
final Object[] table; // pairs of key, value
@@ -889,6 +1255,11 @@
return size;
}
+ @Override
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
class MapNIterator implements Iterator<Map.Entry<K,V>> {
private int remaining;
@@ -896,10 +1267,10 @@
private int idx;
MapNIterator() {
- remaining = size();
- if (remaining > 0) {
- idx = Math.floorMod(SALT, table.length >> 1) << 1;
- }
+ remaining = size;
+ // pick an even starting index in the [0 .. table.length-1]
+ // range randomly based on SALT32L
+ idx = (int) ((SALT32L * (table.length >> 1)) >>> 32) << 1;
}
@Override
@@ -909,7 +1280,7 @@
private int nextIndex() {
int idx = this.idx;
- if (SALT >= 0) {
+ if (REVERSE) {
if ((idx += 2) >= table.length) {
idx = 0;
}
@@ -923,8 +1294,9 @@
@Override
public Map.Entry<K,V> next() {
- if (hasNext()) {
- while (table[nextIndex()] == null) {}
+ if (remaining > 0) {
+ int idx;
+ while (table[idx = nextIndex()] == null) {}
@SuppressWarnings("unchecked")
Map.Entry<K,V> e =
new KeyValueHolder<>((K)table[idx], (V)table[idx+1]);
@@ -978,10 +1350,12 @@
}
}
+ @java.io.Serial
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
throw new InvalidObjectException("not serial proxy");
}
+ @java.io.Serial
private Object writeReplace() {
Object[] array = new Object[2 * size];
int len = table.length;
@@ -1006,17 +1380,22 @@
* @since 9
*/
final class CollSer implements Serializable {
+ @java.io.Serial
private static final long serialVersionUID = 6309168927139932177L;
- static final int IMM_LIST = 1;
- static final int IMM_SET = 2;
- static final int IMM_MAP = 3;
+ static final int IMM_LIST = 1;
+ static final int IMM_SET = 2;
+ static final int IMM_MAP = 3;
+ static final int IMM_LIST_NULLS = 4;
/**
* Indicates the type of collection that is serialized.
* The low order 8 bits have the value 1 for an immutable
- * {@code List}, 2 for an immutable {@code Set}, and 3 for
- * an immutable {@code Map}. Any other value causes an
+ * {@code List}, 2 for an immutable {@code Set}, 3 for
+ * an immutable {@code Map}, and 4 for an immutable
+ * {@code List} that allows null elements.
+ *
+ * Any other value causes an
* {@link InvalidObjectException} to be thrown. The high
* order 24 bits are zero when an instance is serialized,
* and they are ignored when an instance is deserialized.
@@ -1066,6 +1445,7 @@
* @throws InvalidObjectException if the count is negative
* @since 9
*/
+ @java.io.Serial
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
int len = ois.readInt();
@@ -1095,6 +1475,7 @@
* @throws IOException if an I/O error occurs
* @since 9
*/
+ @java.io.Serial
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeInt(array.length);
@@ -1107,9 +1488,9 @@
* Creates and returns an immutable collection from this proxy class.
* The instance returned is created as if by calling one of the
* static factory methods for
- * <a href="List.html#immutable">List</a>,
- * <a href="Map.html#immutable">Map</a>, or
- * <a href="Set.html#immutable">Set</a>.
+ * <a href="List.html#unmodifiable">List</a>,
+ * <a href="Map.html#unmodifiable">Map</a>, or
+ * <a href="Set.html#unmodifiable">Set</a>.
* This proxy class is the serial form for all immutable collection instances,
* regardless of implementation type. This is necessary to ensure that the
* existence of any particular implementation type is kept out of the
@@ -1121,6 +1502,7 @@
* @throws ObjectStreamException if another serialization error has occurred
* @since 9
*/
+ @java.io.Serial
private Object readResolve() throws ObjectStreamException {
try {
if (array == null) {
@@ -1132,11 +1514,14 @@
switch (tag & 0xff) {
case IMM_LIST:
return List.of(array);
+ case IMM_LIST_NULLS:
+ return ImmutableCollections.listFromTrustedArrayNullsAllowed(
+ Arrays.copyOf(array, array.length, Object[].class));
case IMM_SET:
return Set.of(array);
case IMM_MAP:
if (array.length == 0) {
- return ImmutableCollections.emptyMap();
+ return ImmutableCollections.EMPTY_MAP;
} else if (array.length == 2) {
return new ImmutableCollections.Map1<>(array[0], array[1]);
} else {
diff --git a/ojluni/src/main/java/java/util/InputMismatchException.java b/ojluni/src/main/java/java/util/InputMismatchException.java
index c101c65..522a553 100644
--- a/ojluni/src/main/java/java/util/InputMismatchException.java
+++ b/ojluni/src/main/java/java/util/InputMismatchException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2020, 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,12 +30,11 @@
* retrieved does not match the pattern for the expected type, or
* that the token is out of range for the expected type.
*
- * @author unascribed
* @see java.util.Scanner
* @since 1.5
*/
-public
-class InputMismatchException extends NoSuchElementException {
+public class InputMismatchException extends NoSuchElementException {
+ @java.io.Serial
private static final long serialVersionUID = 8811230760997066428L;
/**
diff --git a/ojluni/src/main/java/java/util/InvalidPropertiesFormatException.java b/ojluni/src/main/java/java/util/InvalidPropertiesFormatException.java
index bacab3d..3b1801b 100644
--- a/ojluni/src/main/java/java/util/InvalidPropertiesFormatException.java
+++ b/ojluni/src/main/java/java/util/InvalidPropertiesFormatException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -45,6 +45,7 @@
public class InvalidPropertiesFormatException extends IOException {
+ @java.io.Serial
private static final long serialVersionUID = 7763056076009360219L;
/**
@@ -74,6 +75,7 @@
* Throws NotSerializableException, since InvalidPropertiesFormatException
* objects are not intended to be serializable.
*/
+ @java.io.Serial
private void writeObject(java.io.ObjectOutputStream out)
throws NotSerializableException
{
@@ -84,6 +86,7 @@
* Throws NotSerializableException, since InvalidPropertiesFormatException
* objects are not intended to be serializable.
*/
+ @java.io.Serial
private void readObject(java.io.ObjectInputStream in)
throws NotSerializableException
{
diff --git a/ojluni/src/main/java/java/util/JumboEnumSet.java b/ojluni/src/main/java/java/util/JumboEnumSet.java
index 20e8222..f80e505 100644
--- a/ojluni/src/main/java/java/util/JumboEnumSet.java
+++ b/ojluni/src/main/java/java/util/JumboEnumSet.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -34,6 +34,7 @@
* @serial exclude
*/
class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {
+ @java.io.Serial
private static final long serialVersionUID = 334349849919042784L;
/**
@@ -247,10 +248,9 @@
* @throws NullPointerException if the specified collection is null
*/
public boolean containsAll(Collection<?> c) {
- if (!(c instanceof JumboEnumSet))
+ if (!(c instanceof JumboEnumSet<?> es))
return super.containsAll(c);
- JumboEnumSet<?> es = (JumboEnumSet<?>)c;
if (es.elementType != elementType)
return es.isEmpty();
@@ -269,10 +269,9 @@
* its elements are null
*/
public boolean addAll(Collection<? extends E> c) {
- if (!(c instanceof JumboEnumSet))
+ if (!(c instanceof JumboEnumSet<?> es))
return super.addAll(c);
- JumboEnumSet<?> es = (JumboEnumSet<?>)c;
if (es.elementType != elementType) {
if (es.isEmpty())
return false;
@@ -295,10 +294,9 @@
* @throws NullPointerException if the specified collection is null
*/
public boolean removeAll(Collection<?> c) {
- if (!(c instanceof JumboEnumSet))
+ if (!(c instanceof JumboEnumSet<?> es))
return super.removeAll(c);
- JumboEnumSet<?> es = (JumboEnumSet<?>)c;
if (es.elementType != elementType)
return false;
@@ -316,10 +314,9 @@
* @throws NullPointerException if the specified collection is null
*/
public boolean retainAll(Collection<?> c) {
- if (!(c instanceof JumboEnumSet))
+ if (!(c instanceof JumboEnumSet<?> es))
return super.retainAll(c);
- JumboEnumSet<?> es = (JumboEnumSet<?>)c;
if (es.elementType != elementType) {
boolean changed = (size != 0);
clear();
@@ -349,10 +346,9 @@
* @return {@code true} if the specified object is equal to this set
*/
public boolean equals(Object o) {
- if (!(o instanceof JumboEnumSet))
+ if (!(o instanceof JumboEnumSet<?> es))
return super.equals(o);
- JumboEnumSet<?> es = (JumboEnumSet<?>)o;
if (es.elementType != elementType)
return size == 0 && es.size == 0;
diff --git a/ojluni/src/main/java/java/util/KeyValueHolder.java b/ojluni/src/main/java/java/util/KeyValueHolder.java
index 3b7250e..9dbce95 100644
--- a/ojluni/src/main/java/java/util/KeyValueHolder.java
+++ b/ojluni/src/main/java/java/util/KeyValueHolder.java
@@ -31,10 +31,11 @@
* An immutable container for a key and a value, suitable for use
* in creating and populating {@code Map} instances.
*
- * <p>This is a <a href="../lang/doc-files/ValueBased.html">value-based</a>
- * class; use of identity-sensitive operations (including reference equality
- * ({@code ==}), identity hash code, or synchronization) on instances of
- * {@code KeyValueHolder} may have unpredictable results and should be avoided.
+ * <p>This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
+ * class; programmers should treat instances that are
+ * {@linkplain #equals(Object) equal} as interchangeable and should not
+ * use instances for synchronization, or unpredictable behavior may
+ * occur. For example, in a future release, synchronization may fail.
*
* @apiNote
* This class is not public. Instances can be created using the
@@ -49,6 +50,7 @@
* @see Map#ofEntries Map.ofEntries()
* @since 9
*/
+@jdk.internal.ValueBased
final class KeyValueHolder<K,V> implements Map.Entry<K,V> {
@Stable
final K key;
@@ -99,10 +101,9 @@
*/
@Override
public boolean equals(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry<?,?> e = (Map.Entry<?,?>)o;
- return key.equals(e.getKey()) && value.equals(e.getValue());
+ return o instanceof Map.Entry<?, ?> e
+ && key.equals(e.getKey())
+ && value.equals(e.getValue());
}
/**
diff --git a/ojluni/src/main/java/java/util/LinkedHashSet.java b/ojluni/src/main/java/java/util/LinkedHashSet.java
index 48b1e4f..e7c7c38 100644
--- a/ojluni/src/main/java/java/util/LinkedHashSet.java
+++ b/ojluni/src/main/java/java/util/LinkedHashSet.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2020, 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,12 +42,12 @@
* increased cost associated with {@link TreeSet}. It can be used to
* produce a copy of a set that has the same order as the original, regardless
* of the original set's implementation:
- * <pre>
- * void foo(Set s) {
- * Set copy = new LinkedHashSet(s);
+ * <pre>{@code
+ * void foo(Set<String> s) {
+ * Set<String> copy = new LinkedHashSet<>(s);
* ...
* }
- * </pre>
+ * }</pre>
* This technique is particularly useful if a module takes a set on input,
* copies it, and later returns results whose order is determined by that of
* the copy. (Clients generally appreciate having things returned in the same
@@ -119,6 +119,7 @@
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
+ @java.io.Serial
private static final long serialVersionUID = -2851667679971038690L;
/**
diff --git a/ojluni/src/main/java/java/util/LinkedList.java b/ojluni/src/main/java/java/util/LinkedList.java
index 8dd1d12..a504b4e 100644
--- a/ojluni/src/main/java/java/util/LinkedList.java
+++ b/ojluni/src/main/java/java/util/LinkedList.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
@@ -1112,6 +1112,7 @@
return a;
}
+ @java.io.Serial
private static final long serialVersionUID = 876323262645176354L;
/**
@@ -1122,6 +1123,7 @@
* contains) is emitted (int), followed by all of its
* elements (each an Object) in the proper order.
*/
+ @java.io.Serial
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out any hidden serialization magic
@@ -1140,6 +1142,7 @@
* (that is, deserializes it).
*/
@SuppressWarnings("unchecked")
+ @java.io.Serial
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in any hidden serialization magic
diff --git a/ojluni/src/main/java/java/util/List.java b/ojluni/src/main/java/java/util/List.java
index fca40ac..cdb80f7 100644
--- a/ojluni/src/main/java/java/util/List.java
+++ b/ojluni/src/main/java/java/util/List.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -105,11 +105,15 @@
* <li>They are serializable if all elements are serializable.
* <li>The order of elements in the list is the same as the order of the
* provided arguments, or of the elements in the provided array.
+ * <li>The lists and their {@link #subList(int, int) subList} views implement the
+ * {@link RandomAccess} interface.
* <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
- * Callers should make no assumptions about the identity of the returned instances.
- * Factories are free to create new instances or reuse existing ones. Therefore,
- * identity-sensitive operations on these instances (reference equality ({@code ==}),
- * identity hash code, and synchronization) are unreliable and should be avoided.
+ * Programmers should treat instances that are {@linkplain #equals(Object) equal}
+ * as interchangeable and should not use them for synchronization, or
+ * unpredictable behavior may occur. For example, in a future release,
+ * synchronization may fail. Callers should make no assumptions about the
+ * identity of the returned instances. Factories are free to
+ * create new instances or reuse existing ones.
* <li>They are serialized as specified on the
* <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
* page.
@@ -806,8 +810,9 @@
*
* @since 9
*/
+ @SuppressWarnings("unchecked")
static <E> List<E> of() {
- return ImmutableCollections.emptyList();
+ return (List<E>) ImmutableCollections.EMPTY_LIST;
}
/**
@@ -858,7 +863,7 @@
* @since 9
*/
static <E> List<E> of(E e1, E e2, E e3) {
- return new ImmutableCollections.ListN<>(e1, e2, e3);
+ return ImmutableCollections.listFromTrustedArray(e1, e2, e3);
}
/**
@@ -877,7 +882,7 @@
* @since 9
*/
static <E> List<E> of(E e1, E e2, E e3, E e4) {
- return new ImmutableCollections.ListN<>(e1, e2, e3, e4);
+ return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4);
}
/**
@@ -897,7 +902,7 @@
* @since 9
*/
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5) {
- return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5);
+ return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5);
}
/**
@@ -918,8 +923,8 @@
* @since 9
*/
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
- return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
- e6);
+ return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
+ e6);
}
/**
@@ -941,8 +946,8 @@
* @since 9
*/
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
- return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
- e6, e7);
+ return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
+ e6, e7);
}
/**
@@ -965,8 +970,8 @@
* @since 9
*/
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
- return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
- e6, e7, e8);
+ return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
+ e6, e7, e8);
}
/**
@@ -990,8 +995,8 @@
* @since 9
*/
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
- return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
- e6, e7, e8, e9);
+ return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
+ e6, e7, e8, e9);
}
/**
@@ -1016,8 +1021,8 @@
* @since 9
*/
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
- return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
- e6, e7, e8, e9, e10);
+ return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
+ e6, e7, e8, e9, e10);
}
/**
@@ -1050,13 +1055,15 @@
static <E> List<E> of(E... elements) {
switch (elements.length) { // implicit null check of elements
case 0:
- return ImmutableCollections.emptyList();
+ @SuppressWarnings("unchecked")
+ var list = (List<E>) ImmutableCollections.EMPTY_LIST;
+ return list;
case 1:
return new ImmutableCollections.List12<>(elements[0]);
case 2:
return new ImmutableCollections.List12<>(elements[0], elements[1]);
default:
- return new ImmutableCollections.ListN<>(elements);
+ return ImmutableCollections.listFromArray(elements);
}
}
diff --git a/ojluni/src/main/java/java/util/Map.java b/ojluni/src/main/java/java/util/Map.java
index 1148e63..8413441 100644
--- a/ojluni/src/main/java/java/util/Map.java
+++ b/ojluni/src/main/java/java/util/Map.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2020, 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
@@ -131,10 +131,12 @@
* passed to a static factory method result in {@code IllegalArgumentException}.
* <li>The iteration order of mappings is unspecified and is subject to change.
* <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
- * Callers should make no assumptions about the identity of the returned instances.
- * Factories are free to create new instances or reuse existing ones. Therefore,
- * identity-sensitive operations on these instances (reference equality ({@code ==}),
- * identity hash code, and synchronization) are unreliable and should be avoided.
+ * Programmers should treat instances that are {@linkplain #equals(Object) equal}
+ * as interchangeable and should not use them for synchronization, or
+ * unpredictable behavior may occur. For example, in a future release,
+ * synchronization may fail. Callers should make no assumptions
+ * about the identity of the returned instances. Factories are free to
+ * create new instances or reuse existing ones.
* <li>They are serialized as specified on the
* <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
* page.
@@ -391,14 +393,24 @@
Set<Map.Entry<K, V>> entrySet();
/**
- * A map entry (key-value pair). The {@code Map.entrySet} method returns
- * a collection-view of the map, whose elements are of this class. The
- * <i>only</i> way to obtain a reference to a map entry is from the
- * iterator of this collection-view. These {@code Map.Entry} objects are
- * valid <i>only</i> for the duration of the iteration; more formally,
- * the behavior of a map entry is undefined if the backing map has been
- * modified after the entry was returned by the iterator, except through
- * the {@code setValue} operation on the map entry.
+ * A map entry (key-value pair). The Entry may be unmodifiable, or the
+ * value may be modifiable if the optional {@code setValue} method is
+ * implemented. The Entry may be independent of any map, or it may represent
+ * an entry of the entry-set view of a map.
+ * <p>
+ * Instances of the {@code Map.Entry} interface may be obtained by iterating
+ * the entry-set view of a map. These instances maintain a connection to the
+ * original, backing map. This connection to the backing map is valid
+ * <i>only</i> for the duration of iteration over the entry-set view.
+ * During iteration of the entry-set view, if supported by the backing map,
+ * a change to a {@code Map.Entry}'s value via the
+ * {@link Map.Entry#setValue setValue} method will be visible in the backing map.
+ * The behavior of such a {@code Map.Entry} instance is undefined outside of
+ * iteration of the map's entry-set view. It is also undefined if the backing
+ * map has been modified after the {@code Map.Entry} was returned by the
+ * iterator, except through the {@code Map.Entry.setValue} method. In particular,
+ * a change to the value of a mapping in the backing map might or might not be
+ * visible in the corresponding {@code Map.Entry} element of the entry-set view.
*
* @see Map#entrySet()
* @since 1.2
@@ -557,6 +569,38 @@
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
}
+
+ /**
+ * Returns a copy of the given {@code Map.Entry}. The returned instance is not
+ * associated with any map. The returned instance has the same characteristics
+ * as instances returned by the {@link Map#entry Map::entry} method.
+ *
+ * @apiNote
+ * An instance obtained from a map's entry-set view has a connection to that map.
+ * The {@code copyOf} method may be used to create a {@code Map.Entry} instance,
+ * containing the same key and value, that is independent of any map.
+ *
+ * @implNote
+ * If the given entry was obtained from a call to {@code copyOf} or {@code Map::entry},
+ * calling {@code copyOf} will generally not create another copy.
+ *
+ * @param <K> the type of the key
+ * @param <V> the type of the value
+ * @param e the entry to be copied
+ * @return a map entry equal to the given entry
+ * @throws NullPointerException if e is null or if either of its key or value is null
+ * @since 17
+ * @hide
+ */
+ @SuppressWarnings("unchecked")
+ public static <K, V> Map.Entry<K, V> copyOf(Map.Entry<? extends K, ? extends V> e) {
+ Objects.requireNonNull(e);
+ if (e instanceof KeyValueHolder) {
+ return (Map.Entry<K, V>) e;
+ } else {
+ return Map.entry(e.getKey(), e.getValue());
+ }
+ }
}
// Comparison and hashing
@@ -732,8 +776,7 @@
* {@code null}, else returns the current value.
*
* @implSpec
- * The default implementation is equivalent to, for this {@code
- * map}:
+ * The default implementation is equivalent to, for this {@code map}:
*
* <pre> {@code
* V v = map.get(key);
@@ -830,7 +873,7 @@
* The default implementation is equivalent to, for this {@code map}:
*
* <pre> {@code
- * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
+ * if (map.containsKey(key) && Objects.equals(map.get(key), oldValue)) {
* map.put(key, newValue);
* return true;
* } else
@@ -1108,23 +1151,17 @@
*
* @implSpec
* The default implementation is equivalent to performing the following
- * steps for this {@code map}, then returning the current value or
- * {@code null} if absent:
+ * steps for this {@code map}:
*
* <pre> {@code
* V oldValue = map.get(key);
* V newValue = remappingFunction.apply(key, oldValue);
- * if (oldValue != null) {
- * if (newValue != null)
- * map.put(key, newValue);
- * else
- * map.remove(key);
- * } else {
- * if (newValue != null)
- * map.put(key, newValue);
- * else
- * return null;
+ * if (newValue != null) {
+ * map.put(key, newValue);
+ * } else if (oldValue != null || map.containsKey(key)) {
+ * map.remove(key);
* }
+ * return newValue;
* }</pre>
*
* <p>The default implementation makes no guarantees about detecting if the
@@ -1286,8 +1323,9 @@
*
* @since 9
*/
+ @SuppressWarnings("unchecked")
static <K, V> Map<K, V> of() {
- return ImmutableCollections.emptyMap();
+ return (Map<K,V>) ImmutableCollections.EMPTY_MAP;
}
/**
@@ -1604,7 +1642,9 @@
@SuppressWarnings("varargs")
static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
if (entries.length == 0) { // implicit null check of entries array
- return ImmutableCollections.emptyMap();
+ @SuppressWarnings("unchecked")
+ var map = (Map<K,V>) ImmutableCollections.EMPTY_MAP;
+ return map;
} else if (entries.length == 1) {
// implicit null check of the array slot
return new ImmutableCollections.Map1<>(entries[0].getKey(),
@@ -1634,10 +1674,12 @@
* on a returned {@code Entry} result in {@code UnsupportedOperationException}.
* <li>They are not serializable.
* <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
- * Callers should make no assumptions about the identity of the returned instances.
- * This method is free to create new instances or reuse existing ones. Therefore,
- * identity-sensitive operations on these instances (reference equality ({@code ==}),
- * identity hash code, and synchronization) are unreliable and should be avoided.
+ * Programmers should treat instances that are {@linkplain #equals(Object) equal}
+ * as interchangeable and should not use them for synchronization, or
+ * unpredictable behavior may occur. For example, in a future release,
+ * synchronization may fail. Callers should make no assumptions
+ * about the identity of the returned instances. This method is free to
+ * create new instances or reuse existing ones.
* </ul>
*
* @apiNote
diff --git a/ojluni/src/main/java/java/util/MissingFormatArgumentException.java b/ojluni/src/main/java/java/util/MissingFormatArgumentException.java
index 926a697..dcb0847 100644
--- a/ojluni/src/main/java/java/util/MissingFormatArgumentException.java
+++ b/ojluni/src/main/java/java/util/MissingFormatArgumentException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -38,6 +38,7 @@
*/
public class MissingFormatArgumentException extends IllegalFormatException {
+ @java.io.Serial
private static final long serialVersionUID = 19190115L;
private String s;
diff --git a/ojluni/src/main/java/java/util/MissingFormatWidthException.java b/ojluni/src/main/java/java/util/MissingFormatWidthException.java
index e748695..0ce9c3a 100644
--- a/ojluni/src/main/java/java/util/MissingFormatWidthException.java
+++ b/ojluni/src/main/java/java/util/MissingFormatWidthException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -36,6 +36,7 @@
*/
public class MissingFormatWidthException extends IllegalFormatException {
+ @java.io.Serial
private static final long serialVersionUID = 15560123L;
private String s;
diff --git a/ojluni/src/main/java/java/util/MissingResourceException.java b/ojluni/src/main/java/java/util/MissingResourceException.java
index 3e09dfa..ea93fd8 100644
--- a/ojluni/src/main/java/java/util/MissingResourceException.java
+++ b/ojluni/src/main/java/java/util/MissingResourceException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, 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
@@ -47,8 +47,7 @@
* @author Mark Davis
* @since 1.1
*/
-public
-class MissingResourceException extends RuntimeException {
+public class MissingResourceException extends RuntimeException {
/**
* Constructs a MissingResourceException with the specified information.
@@ -108,6 +107,7 @@
//============ privates ============
// serialization compatibility with JDK1.1
+ @java.io.Serial
private static final long serialVersionUID = -4876345176062000401L;
/**
diff --git a/ojluni/src/main/java/java/util/Optional.java b/ojluni/src/main/java/java/util/Optional.java
index a7b98a6..03bb99e 100644
--- a/ojluni/src/main/java/java/util/Optional.java
+++ b/ojluni/src/main/java/java/util/Optional.java
@@ -30,7 +30,7 @@
import java.util.function.Supplier;
import java.util.stream.Stream;
-// Android-changed: removed ValueBased paragraph and annotation.
+// Android-changed: removed ValueBased paragraph.
/**
* A container object which may or may not contain a non-{@code null} value.
* If a value is present, {@code isPresent()} returns {@code true}. If no
@@ -59,7 +59,7 @@
* @param <T> the type of value
* @since 1.8
*/
-// @jdk.internal.ValueBased
+@jdk.internal.ValueBased
public final class Optional<T> {
/**
* Common instance for {@code empty()}.
diff --git a/ojluni/src/main/java/java/util/OptionalDouble.java b/ojluni/src/main/java/java/util/OptionalDouble.java
index 4539fa9..b8b5b00 100644
--- a/ojluni/src/main/java/java/util/OptionalDouble.java
+++ b/ojluni/src/main/java/java/util/OptionalDouble.java
@@ -289,14 +289,10 @@
return true;
}
- if (!(obj instanceof OptionalDouble)) {
- return false;
- }
-
- OptionalDouble other = (OptionalDouble) obj;
- return (isPresent && other.isPresent)
- ? Double.compare(value, other.value) == 0
- : isPresent == other.isPresent;
+ return obj instanceof OptionalDouble other
+ && (isPresent && other.isPresent
+ ? Double.compare(value, other.value) == 0
+ : isPresent == other.isPresent);
}
/**
diff --git a/ojluni/src/main/java/java/util/OptionalInt.java b/ojluni/src/main/java/java/util/OptionalInt.java
index d28bd02..c0976c0 100644
--- a/ojluni/src/main/java/java/util/OptionalInt.java
+++ b/ojluni/src/main/java/java/util/OptionalInt.java
@@ -288,14 +288,10 @@
return true;
}
- if (!(obj instanceof OptionalInt)) {
- return false;
- }
-
- OptionalInt other = (OptionalInt) obj;
- return (isPresent && other.isPresent)
+ return obj instanceof OptionalInt other
+ && (isPresent && other.isPresent
? value == other.value
- : isPresent == other.isPresent;
+ : isPresent == other.isPresent);
}
/**
diff --git a/ojluni/src/main/java/java/util/OptionalLong.java b/ojluni/src/main/java/java/util/OptionalLong.java
index 5558afa..842f76a 100644
--- a/ojluni/src/main/java/java/util/OptionalLong.java
+++ b/ojluni/src/main/java/java/util/OptionalLong.java
@@ -288,14 +288,10 @@
return true;
}
- if (!(obj instanceof OptionalLong)) {
- return false;
- }
-
- OptionalLong other = (OptionalLong) obj;
- return (isPresent && other.isPresent)
+ return obj instanceof OptionalLong other
+ && (isPresent && other.isPresent
? value == other.value
- : isPresent == other.isPresent;
+ : isPresent == other.isPresent);
}
/**
diff --git a/ojluni/src/main/java/java/util/PrimitiveIterator.java b/ojluni/src/main/java/java/util/PrimitiveIterator.java
index 2bc864a..e6fd3a5 100644
--- a/ojluni/src/main/java/java/util/PrimitiveIterator.java
+++ b/ojluni/src/main/java/java/util/PrimitiveIterator.java
@@ -68,10 +68,18 @@
public interface PrimitiveIterator<T, T_CONS> extends Iterator<T> {
/**
- * Performs the given action for each remaining element, in the order
- * elements occur when iterating, until all elements have been processed
- * or the action throws an exception. Errors or runtime exceptions
- * thrown by the action are relayed to the caller.
+ * Performs the given action for each remaining element until all elements
+ * have been processed or the action throws an exception. Actions are
+ * performed in the order of iteration, if that order is specified.
+ * Exceptions thrown by the action are relayed to the caller.
+ * <p>
+ * The behavior of an iterator is unspecified if the action modifies the
+ * source of elements in any way (even by calling the {@link #remove remove}
+ * method or other mutator methods of {@code Iterator} subtypes),
+ * unless an overriding class has specified a concurrent modification policy.
+ * <p>
+ * Subsequent behavior of an iterator is unspecified if the action throws an
+ * exception.
*
* @param action The action to be performed for each element
* @throws NullPointerException if the specified action is null
@@ -94,20 +102,13 @@
int nextInt();
/**
- * Performs the given action for each remaining element until all elements
- * have been processed or the action throws an exception. Actions are
- * performed in the order of iteration, if that order is specified.
- * Exceptions thrown by the action are relayed to the caller.
- *
+ * {@inheritDoc}
* @implSpec
* <p>The default implementation behaves as if:
* <pre>{@code
* while (hasNext())
* action.accept(nextInt());
* }</pre>
- *
- * @param action The action to be performed for each element
- * @throws NullPointerException if the specified action is null
*/
default void forEachRemaining(IntConsumer action) {
Objects.requireNonNull(action);
@@ -168,20 +169,13 @@
long nextLong();
/**
- * Performs the given action for each remaining element until all elements
- * have been processed or the action throws an exception. Actions are
- * performed in the order of iteration, if that order is specified.
- * Exceptions thrown by the action are relayed to the caller.
- *
+ * {@inheritDoc}
* @implSpec
* <p>The default implementation behaves as if:
* <pre>{@code
* while (hasNext())
* action.accept(nextLong());
* }</pre>
- *
- * @param action The action to be performed for each element
- * @throws NullPointerException if the specified action is null
*/
default void forEachRemaining(LongConsumer action) {
Objects.requireNonNull(action);
@@ -241,20 +235,13 @@
double nextDouble();
/**
- * Performs the given action for each remaining element until all elements
- * have been processed or the action throws an exception. Actions are
- * performed in the order of iteration, if that order is specified.
- * Exceptions thrown by the action are relayed to the caller.
- *
+ * {@inheritDoc}
* @implSpec
* <p>The default implementation behaves as if:
* <pre>{@code
* while (hasNext())
* action.accept(nextDouble());
* }</pre>
- *
- * @param action The action to be performed for each element
- * @throws NullPointerException if the specified action is null
*/
default void forEachRemaining(DoubleConsumer action) {
Objects.requireNonNull(action);
diff --git a/ojluni/src/main/java/java/util/PriorityQueue.java b/ojluni/src/main/java/java/util/PriorityQueue.java
index 66e8dc7..70c99bf 100644
--- a/ojluni/src/main/java/java/util/PriorityQueue.java
+++ b/ojluni/src/main/java/java/util/PriorityQueue.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -28,6 +28,7 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
import jdk.internal.misc.SharedSecrets;
+import jdk.internal.util.ArraysSupport;
/**
* An unbounded priority {@linkplain Queue queue} based on a priority heap.
@@ -86,6 +87,7 @@
public class PriorityQueue<E> extends AbstractQueue<E>
implements java.io.Serializable {
+ @java.io.Serial
private static final long serialVersionUID = -7720805057305804111L;
private static final int DEFAULT_INITIAL_CAPACITY = 11;
@@ -109,6 +111,7 @@
* The comparator, or null if priority queue uses elements'
* natural ordering.
*/
+ @SuppressWarnings("serial") // Conditionally serializable
private final Comparator<? super E> comparator;
/**
@@ -281,14 +284,6 @@
}
/**
- * The maximum size of array to allocate.
- * Some VMs reserve some header words in an array.
- * Attempts to allocate larger arrays may result in
- * OutOfMemoryError: Requested array size exceeds VM limit
- */
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
-
- /**
* Increases the capacity of the array.
*
* @param minCapacity the desired minimum capacity
@@ -296,23 +291,13 @@
private void grow(int minCapacity) {
int oldCapacity = queue.length;
// Double size if small; else grow by 50%
- int newCapacity = oldCapacity + ((oldCapacity < 64) ?
- (oldCapacity + 2) :
- (oldCapacity >> 1));
- // overflow-conscious code
- if (newCapacity - MAX_ARRAY_SIZE > 0)
- newCapacity = hugeCapacity(minCapacity);
+ int newCapacity = ArraysSupport.newLength(oldCapacity,
+ minCapacity - oldCapacity, /* minimum growth */
+ oldCapacity < 64 ? oldCapacity + 2 : oldCapacity >> 1
+ /* preferred growth */);
queue = Arrays.copyOf(queue, newCapacity);
}
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return (minCapacity > MAX_ARRAY_SIZE) ?
- Integer.MAX_VALUE :
- MAX_ARRAY_SIZE;
- }
-
/**
* Inserts the specified element into this priority queue.
*
@@ -771,6 +756,7 @@
* emitted (int), followed by all of its elements
* (each an {@code Object}) in the proper order.
*/
+ @java.io.Serial
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out element count, and any hidden stuff
@@ -794,6 +780,7 @@
* could not be found
* @throws java.io.IOException if an I/O error occurs
*/
+ @java.io.Serial
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
diff --git a/ojluni/src/main/java/java/util/Random.java b/ojluni/src/main/java/java/util/Random.java
index f9c3c75..0569034 100644
--- a/ojluni/src/main/java/java/util/Random.java
+++ b/ojluni/src/main/java/java/util/Random.java
@@ -1222,6 +1222,6 @@
} catch (Exception ex) { throw new Error(ex); }
}
private void resetSeed(long seedVal) {
- unsafe.putObjectVolatile(this, seedOffset, new AtomicLong(seedVal));
+ unsafe.putReferenceVolatile(this, seedOffset, new AtomicLong(seedVal));
}
}
diff --git a/ojluni/src/main/java/java/util/RegularEnumSet.java b/ojluni/src/main/java/java/util/RegularEnumSet.java
index eef447e..1deda8a 100644
--- a/ojluni/src/main/java/java/util/RegularEnumSet.java
+++ b/ojluni/src/main/java/java/util/RegularEnumSet.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -34,6 +34,7 @@
* @serial exclude
*/
class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
+ @java.io.Serial
private static final long serialVersionUID = 3411599620347842686L;
/**
* Bit vector representation of this set. The 2^k bit indicates the
@@ -195,10 +196,9 @@
* @throws NullPointerException if the specified collection is null
*/
public boolean containsAll(Collection<?> c) {
- if (!(c instanceof RegularEnumSet))
+ if (!(c instanceof RegularEnumSet<?> es))
return super.containsAll(c);
- RegularEnumSet<?> es = (RegularEnumSet<?>)c;
if (es.elementType != elementType)
return es.isEmpty();
@@ -214,10 +214,9 @@
* of its elements are null
*/
public boolean addAll(Collection<? extends E> c) {
- if (!(c instanceof RegularEnumSet))
+ if (!(c instanceof RegularEnumSet<?> es))
return super.addAll(c);
- RegularEnumSet<?> es = (RegularEnumSet<?>)c;
if (es.elementType != elementType) {
if (es.isEmpty())
return false;
@@ -240,10 +239,9 @@
* @throws NullPointerException if the specified collection is null
*/
public boolean removeAll(Collection<?> c) {
- if (!(c instanceof RegularEnumSet))
+ if (!(c instanceof RegularEnumSet<?> es))
return super.removeAll(c);
- RegularEnumSet<?> es = (RegularEnumSet<?>)c;
if (es.elementType != elementType)
return false;
@@ -261,10 +259,9 @@
* @throws NullPointerException if the specified collection is null
*/
public boolean retainAll(Collection<?> c) {
- if (!(c instanceof RegularEnumSet))
+ if (!(c instanceof RegularEnumSet<?> es))
return super.retainAll(c);
- RegularEnumSet<?> es = (RegularEnumSet<?>)c;
if (es.elementType != elementType) {
boolean changed = (elements != 0);
elements = 0;
@@ -293,10 +290,9 @@
* @return {@code true} if the specified object is equal to this set
*/
public boolean equals(Object o) {
- if (!(o instanceof RegularEnumSet))
+ if (!(o instanceof RegularEnumSet<?> es))
return super.equals(o);
- RegularEnumSet<?> es = (RegularEnumSet<?>)o;
if (es.elementType != elementType)
return elements == 0 && es.elements == 0;
return es.elements == elements;
diff --git a/ojluni/src/main/java/java/util/Scanner.java b/ojluni/src/main/java/java/util/Scanner.java
index 7ee2ff9..7471c3b 100644
--- a/ojluni/src/main/java/java/util/Scanner.java
+++ b/ojluni/src/main/java/java/util/Scanner.java
@@ -2687,9 +2687,8 @@
*/
public BigInteger nextBigInteger(int radix) {
// Check cached result
- if ((typeCache != null) && (typeCache instanceof BigInteger)
+ if ((typeCache != null) && (typeCache instanceof BigInteger val)
&& this.radix == radix) {
- var val = (BigInteger) typeCache;
useTypeCache();
return val;
}
@@ -2753,8 +2752,7 @@
*/
public BigDecimal nextBigDecimal() {
// Check cached result
- if ((typeCache != null) && (typeCache instanceof BigDecimal)) {
- var val = (BigDecimal)typeCache;
+ if ((typeCache != null) && (typeCache instanceof BigDecimal val)) {
useTypeCache();
return val;
}
diff --git a/ojluni/src/main/java/java/util/ServiceConfigurationError.java b/ojluni/src/main/java/java/util/ServiceConfigurationError.java
index 2852384..0645f00 100644
--- a/ojluni/src/main/java/java/util/ServiceConfigurationError.java
+++ b/ojluni/src/main/java/java/util/ServiceConfigurationError.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, 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
@@ -39,6 +39,7 @@
extends Error
{
+ @java.io.Serial
private static final long serialVersionUID = 74132770414881L;
/**
diff --git a/ojluni/src/main/java/java/util/Set.java b/ojluni/src/main/java/java/util/Set.java
index 504904f..4c70300 100644
--- a/ojluni/src/main/java/java/util/Set.java
+++ b/ojluni/src/main/java/java/util/Set.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2020, 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
@@ -82,10 +82,12 @@
* passed to a static factory method result in {@code IllegalArgumentException}.
* <li>The iteration order of set elements is unspecified and is subject to change.
* <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
- * Callers should make no assumptions about the identity of the returned instances.
- * Factories are free to create new instances or reuse existing ones. Therefore,
- * identity-sensitive operations on these instances (reference equality ({@code ==}),
- * identity hash code, and synchronization) are unreliable and should be avoided.
+ * Programmers should treat instances that are {@linkplain #equals(Object) equal}
+ * as interchangeable and should not use them for synchronization, or
+ * unpredictable behavior may occur. For example, in a future release,
+ * synchronization may fail. Callers should make no assumptions
+ * about the identity of the returned instances. Factories are free to
+ * create new instances or reuse existing ones.
* <li>They are serialized as specified on the
* <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
* page.
@@ -448,8 +450,9 @@
*
* @since 9
*/
+ @SuppressWarnings("unchecked")
static <E> Set<E> of() {
- return ImmutableCollections.emptySet();
+ return (Set<E>) ImmutableCollections.EMPTY_SET;
}
/**
@@ -692,7 +695,9 @@
static <E> Set<E> of(E... elements) {
switch (elements.length) { // implicit null check of elements
case 0:
- return ImmutableCollections.emptySet();
+ @SuppressWarnings("unchecked")
+ var set = (Set<E>) ImmutableCollections.EMPTY_SET;
+ return set;
case 1:
return new ImmutableCollections.Set12<>(elements[0]);
case 2:
diff --git a/ojluni/src/main/java/java/util/SimpleTimeZone.java b/ojluni/src/main/java/java/util/SimpleTimeZone.java
index d72594e..72ce744 100644
--- a/ojluni/src/main/java/java/util/SimpleTimeZone.java
+++ b/ojluni/src/main/java/java/util/SimpleTimeZone.java
@@ -738,8 +738,6 @@
cdate.setNormalizedYear(year);
cdate.setMonth(month + 1);
switch (mode) {
- // Android-changed: instanceof pattern variable is not yet supported
- /*
case DOM_MODE -> cdate.setDayOfMonth(dayOfMonth);
case DOW_IN_MONTH_MODE -> {
cdate.setDayOfMonth(1);
@@ -756,28 +754,6 @@
cdate.setDayOfMonth(dayOfMonth);
cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(-1, dayOfWeek, cdate);
}
- */
- case DOM_MODE:
- cdate.setDayOfMonth(dayOfMonth);
- break;
-
- case DOW_IN_MONTH_MODE:
- cdate.setDayOfMonth(1);
- if (dayOfMonth < 0) {
- cdate.setDayOfMonth(cal.getMonthLength(cdate));
- }
- cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(dayOfMonth, dayOfWeek, cdate);
- break;
-
- case DOW_GE_DOM_MODE:
- cdate.setDayOfMonth(dayOfMonth);
- cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(1, dayOfWeek, cdate);
- break;
-
- case DOW_LE_DOM_MODE:
- cdate.setDayOfMonth(dayOfMonth);
- cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(-1, dayOfWeek, cdate);
- break;
}
return cal.getTime(cdate) + timeOfDay;
}
@@ -902,20 +878,9 @@
return true;
}
- // Android-changed: instanceof pattern variable is not yet supported.
- /*
return obj instanceof SimpleTimeZone that
&& getID().equals(that.getID())
&& hasSameRules(that);
- */
- if (!(obj instanceof SimpleTimeZone)) {
- return false;
- }
-
- SimpleTimeZone that = (SimpleTimeZone) obj;
-
- return getID().equals(that.getID()) &&
- hasSameRules(that);
}
/**
@@ -929,8 +894,6 @@
if (this == other) {
return true;
}
- // Android-changed: instanceof pattern variable is not yet supported
- /*
return other instanceof SimpleTimeZone that
&& rawOffset == that.rawOffset
&& useDaylight == that.useDaylight
@@ -951,29 +914,6 @@
&& endTimeMode == that.endTimeMode
&& startYear == that.startYear)
);
- */
- if (!(other instanceof SimpleTimeZone)) {
- return false;
- }
- SimpleTimeZone that = (SimpleTimeZone) other;
- return rawOffset == that.rawOffset &&
- useDaylight == that.useDaylight &&
- (!useDaylight
- // Only check rules if using DST
- || (dstSavings == that.dstSavings &&
- startMode == that.startMode &&
- startMonth == that.startMonth &&
- startDay == that.startDay &&
- startDayOfWeek == that.startDayOfWeek &&
- startTime == that.startTime &&
- startTimeMode == that.startTimeMode &&
- endMode == that.endMode &&
- endMonth == that.endMonth &&
- endDay == that.endDay &&
- endDayOfWeek == that.endDayOfWeek &&
- endTime == that.endTime &&
- endTimeMode == that.endTimeMode &&
- startYear == that.startYear));
}
/**
@@ -1582,11 +1522,7 @@
* rules anyway.
*/
switch (startTimeMode) {
- // Android-change: instanceof pattern variable is not yet supported
- // case UTC_TIME -> startTime += rawOffset;
- case UTC_TIME:
- startTime += rawOffset;
- break;
+ case UTC_TIME -> startTime += rawOffset;
}
while (startTime < 0) {
startTime += millisPerDay;
@@ -1598,14 +1534,8 @@
}
switch (endTimeMode) {
- // Android-change: instanceof pattern variable is not yet supported
- // case UTC_TIME -> endTime += rawOffset + dstSavings;
- // case STANDARD_TIME -> endTime += dstSavings;
- case UTC_TIME:
- endTime += rawOffset + dstSavings;
- break;
- case STANDARD_TIME:
- endTime += dstSavings;
+ case UTC_TIME -> endTime += rawOffset + dstSavings;
+ case STANDARD_TIME -> endTime += dstSavings;
}
while (endTime < 0) {
endTime += millisPerDay;
diff --git a/ojluni/src/main/java/java/util/Spliterator.java b/ojluni/src/main/java/java/util/Spliterator.java
index 4851879..0f49a18 100644
--- a/ojluni/src/main/java/java/util/Spliterator.java
+++ b/ojluni/src/main/java/java/util/Spliterator.java
@@ -284,7 +284,7 @@
* }}</pre>
*
* @implNote
- * If the boolean system property {@code org.openjdk.java.util.stream.tripwire}
+ * If the boolean system property {@systemProperty org.openjdk.java.util.stream.tripwire}
* is set to {@code true} then diagnostic warnings are reported if boxing of
* primitive values occur when operating on primitive subtype specializations.
*
@@ -300,6 +300,9 @@
* Spliterator is {@link #ORDERED} the action is performed on the
* next element in encounter order. Exceptions thrown by the
* action are relayed to the caller.
+ * <p>
+ * Subsequent behavior of a spliterator is unspecified if the action throws
+ * an exception.
*
* @param action The action
* @return {@code false} if no remaining elements existed
@@ -314,6 +317,9 @@
* throws an exception. If this Spliterator is {@link #ORDERED}, actions
* are performed in encounter order. Exceptions thrown by the action
* are relayed to the caller.
+ * <p>
+ * Subsequent behavior of a spliterator is unspecified if the action throws
+ * an exception.
*
* @implSpec
* The default implementation repeatedly invokes {@link #tryAdvance} until
@@ -613,6 +619,9 @@
* Spliterator is {@link #ORDERED} the action is performed on the
* next element in encounter order. Exceptions thrown by the
* action are relayed to the caller.
+ * <p>
+ * Subsequent behavior of a spliterator is unspecified if the action throws
+ * an exception.
*
* @param action The action
* @return {@code false} if no remaining elements existed
@@ -628,6 +637,9 @@
* action throws an exception. If this Spliterator is {@link #ORDERED},
* actions are performed in encounter order. Exceptions thrown by the
* action are relayed to the caller.
+ * <p>
+ * Subsequent behavior of a spliterator is unspecified if the action throws
+ * an exception.
*
* @implSpec
* The default implementation repeatedly invokes {@link #tryAdvance}
diff --git a/ojluni/src/main/java/java/util/Spliterators.java b/ojluni/src/main/java/java/util/Spliterators.java
index 3b5fe86..c5d9bd7 100644
--- a/ojluni/src/main/java/java/util/Spliterators.java
+++ b/ojluni/src/main/java/java/util/Spliterators.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2021, 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
@@ -688,9 +688,23 @@
throw new NoSuchElementException();
else {
valueReady = false;
- return nextElement;
+ T t = nextElement;
+ nextElement = null;
+ return t;
}
}
+
+ @Override
+ public void forEachRemaining(Consumer<? super T> action) {
+ Objects.requireNonNull(action);
+ if (valueReady) {
+ valueReady = false;
+ T t = nextElement;
+ nextElement = null;
+ action.accept(t);
+ }
+ spliterator.forEachRemaining(action);
+ }
}
return new Adapter();
@@ -736,6 +750,16 @@
return nextElement;
}
}
+
+ @Override
+ public void forEachRemaining(IntConsumer action) {
+ Objects.requireNonNull(action);
+ if (valueReady) {
+ valueReady = false;
+ action.accept(nextElement);
+ }
+ spliterator.forEachRemaining(action);
+ }
}
return new Adapter();
@@ -781,6 +805,16 @@
return nextElement;
}
}
+
+ @Override
+ public void forEachRemaining(LongConsumer action) {
+ Objects.requireNonNull(action);
+ if (valueReady) {
+ valueReady = false;
+ action.accept(nextElement);
+ }
+ spliterator.forEachRemaining(action);
+ }
}
return new Adapter();
@@ -826,6 +860,16 @@
return nextElement;
}
}
+
+ @Override
+ public void forEachRemaining(DoubleConsumer action) {
+ Objects.requireNonNull(action);
+ if (valueReady) {
+ valueReady = false;
+ action.accept(nextElement);
+ }
+ spliterator.forEachRemaining(action);
+ }
}
return new Adapter();
@@ -1843,7 +1887,7 @@
static final class IntIteratorSpliterator implements Spliterator.OfInt {
static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
- private PrimitiveIterator.OfInt it;
+ private final PrimitiveIterator.OfInt it;
private final int characteristics;
private long est; // size estimate
private int batch; // batch size for splits
@@ -1937,7 +1981,7 @@
static final class LongIteratorSpliterator implements Spliterator.OfLong {
static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
- private PrimitiveIterator.OfLong it;
+ private final PrimitiveIterator.OfLong it;
private final int characteristics;
private long est; // size estimate
private int batch; // batch size for splits
@@ -2031,7 +2075,7 @@
static final class DoubleIteratorSpliterator implements Spliterator.OfDouble {
static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
- private PrimitiveIterator.OfDouble it;
+ private final PrimitiveIterator.OfDouble it;
private final int characteristics;
private long est; // size estimate
private int batch; // batch size for splits
diff --git a/ojluni/src/main/java/java/util/Stack.java b/ojluni/src/main/java/java/util/Stack.java
index 2573276..b807d73 100644
--- a/ojluni/src/main/java/java/util/Stack.java
+++ b/ojluni/src/main/java/java/util/Stack.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, 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
@@ -45,8 +45,7 @@
* @author Jonathan Payne
* @since 1.0
*/
-public
-class Stack<E> extends Vector<E> {
+public class Stack<E> extends Vector<E> {
/**
* Creates an empty Stack.
*/
@@ -137,5 +136,6 @@
}
/** use serialVersionUID from JDK 1.0.2 for interoperability */
+ @java.io.Serial
private static final long serialVersionUID = 1224463164541339165L;
}
diff --git a/ojluni/src/main/java/java/util/StringTokenizer.java b/ojluni/src/main/java/java/util/StringTokenizer.java
index 5d55ae0..f30f7b8 100644
--- a/ojluni/src/main/java/java/util/StringTokenizer.java
+++ b/ojluni/src/main/java/java/util/StringTokenizer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2020, 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
@@ -95,12 +95,10 @@
* test
* </pre></blockquote>
*
- * @author unascribed
* @see java.io.StreamTokenizer
* @since 1.0
*/
-public
-class StringTokenizer implements Enumeration<Object> {
+public class StringTokenizer implements Enumeration<Object> {
private int currentPosition;
private int newPosition;
private int maxPosition;
@@ -189,7 +187,7 @@
* @param delim the delimiters.
* @param returnDelims flag indicating whether to return the delimiters
* as tokens.
- * @exception NullPointerException if str is {@code null}
+ * @throws NullPointerException if str is {@code null}
*/
public StringTokenizer(String str, String delim, boolean returnDelims) {
currentPosition = 0;
@@ -215,7 +213,7 @@
*
* @param str a string to be parsed.
* @param delim the delimiters.
- * @exception NullPointerException if str is {@code null}
+ * @throws NullPointerException if str is {@code null}
*/
public StringTokenizer(String str, String delim) {
this(str, delim, false);
@@ -230,7 +228,7 @@
* not be treated as tokens.
*
* @param str a string to be parsed.
- * @exception NullPointerException if str is {@code null}
+ * @throws NullPointerException if str is {@code null}
*/
public StringTokenizer(String str) {
this(str, " \t\n\r\f", false);
@@ -328,7 +326,7 @@
* Returns the next token from this string tokenizer.
*
* @return the next token from this string tokenizer.
- * @exception NoSuchElementException if there are no more tokens in this
+ * @throws NoSuchElementException if there are no more tokens in this
* tokenizer's string.
*/
public String nextToken() {
@@ -363,9 +361,9 @@
*
* @param delim the new delimiters.
* @return the next token, after switching to the new delimiter set.
- * @exception NoSuchElementException if there are no more tokens in this
+ * @throws NoSuchElementException if there are no more tokens in this
* tokenizer's string.
- * @exception NullPointerException if delim is {@code null}
+ * @throws NullPointerException if delim is {@code null}
*/
public String nextToken(String delim) {
delimiters = delim;
@@ -398,7 +396,7 @@
* {@code Enumeration} interface.
*
* @return the next token in the string.
- * @exception NoSuchElementException if there are no more tokens in this
+ * @throws NoSuchElementException if there are no more tokens in this
* tokenizer's string.
* @see java.util.Enumeration
* @see java.util.StringTokenizer#nextToken()
diff --git a/ojluni/src/main/java/java/util/TooManyListenersException.java b/ojluni/src/main/java/java/util/TooManyListenersException.java
index 9635a5c..d3fd668 100644
--- a/ojluni/src/main/java/java/util/TooManyListenersException.java
+++ b/ojluni/src/main/java/java/util/TooManyListenersException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, 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 @@
/**
* <p>
- * The <code> TooManyListenersException </code> Exception is used as part of
+ * The {@code TooManyListenersException } Exception is used as part of
* the Java Event model to annotate and implement a unicast special case of
* a multicast Event Source.
* </p>
@@ -48,6 +48,7 @@
*/
public class TooManyListenersException extends Exception {
+ @java.io.Serial
private static final long serialVersionUID = 5074640544770687831L;
/**
diff --git a/ojluni/src/main/java/java/util/TreeSet.java b/ojluni/src/main/java/java/util/TreeSet.java
index faf394c..f189bb4 100644
--- a/ojluni/src/main/java/java/util/TreeSet.java
+++ b/ojluni/src/main/java/java/util/TreeSet.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, 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
@@ -299,12 +299,9 @@
// Use linear-time version if applicable
if (m.size()==0 && c.size() > 0 &&
c instanceof SortedSet &&
- m instanceof TreeMap) {
+ m instanceof TreeMap<E, Object> map) {
SortedSet<? extends E> set = (SortedSet<? extends E>) c;
- TreeMap<E,Object> map = (TreeMap<E, Object>) m;
- Comparator<?> cc = set.comparator();
- Comparator<? super E> mc = map.comparator();
- if (cc==mc || (cc != null && cc.equals(mc))) {
+ if (Objects.equals(set.comparator(), map.comparator())) {
map.addAllForTreeSet(set, PRESENT);
return true;
}
@@ -494,6 +491,7 @@
* set's Comparator, or by the elements' natural ordering if
* the set has no Comparator).
*/
+ @java.io.Serial
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out any hidden stuff
@@ -514,6 +512,7 @@
* Reconstitute the {@code TreeSet} instance from a stream (that is,
* deserialize it).
*/
+ @java.io.Serial
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in any hidden stuff
@@ -556,5 +555,6 @@
return TreeMap.keySpliteratorFor(m);
}
+ @java.io.Serial
private static final long serialVersionUID = -2479143000061671589L;
}
diff --git a/ojluni/src/main/java/java/util/Tripwire.java b/ojluni/src/main/java/java/util/Tripwire.java
index d1bd39e..c807a41 100644
--- a/ojluni/src/main/java/java/util/Tripwire.java
+++ b/ojluni/src/main/java/java/util/Tripwire.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2021, 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
@@ -49,6 +49,7 @@
private static final String TRIPWIRE_PROPERTY = "org.openjdk.java.util.stream.tripwire";
/** Should debugging checks be enabled? */
+ @SuppressWarnings("removal")
static final boolean ENABLED = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) () -> Boolean.getBoolean(TRIPWIRE_PROPERTY));
diff --git a/ojluni/src/main/java/java/util/UnknownFormatConversionException.java b/ojluni/src/main/java/java/util/UnknownFormatConversionException.java
index 1278c6e..07519ad 100644
--- a/ojluni/src/main/java/java/util/UnknownFormatConversionException.java
+++ b/ojluni/src/main/java/java/util/UnknownFormatConversionException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -36,6 +36,7 @@
*/
public class UnknownFormatConversionException extends IllegalFormatException {
+ @java.io.Serial
private static final long serialVersionUID = 19060418L;
private String s;
diff --git a/ojluni/src/main/java/java/util/UnknownFormatFlagsException.java b/ojluni/src/main/java/java/util/UnknownFormatFlagsException.java
index 8549566..c498711 100644
--- a/ojluni/src/main/java/java/util/UnknownFormatFlagsException.java
+++ b/ojluni/src/main/java/java/util/UnknownFormatFlagsException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -36,6 +36,7 @@
*/
public class UnknownFormatFlagsException extends IllegalFormatException {
+ @java.io.Serial
private static final long serialVersionUID = 19370506L;
private String flags;
diff --git a/ojluni/src/main/java/java/util/Vector.java b/ojluni/src/main/java/java/util/Vector.java
index 0b264b7..a11a96e 100644
--- a/ojluni/src/main/java/java/util/Vector.java
+++ b/ojluni/src/main/java/java/util/Vector.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,8 @@
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
+import jdk.internal.util.ArraysSupport;
+
/**
* The {@code Vector} class implements a growable array of
* objects. Like an array, it contains components that can be
@@ -100,6 +102,7 @@
*
* @serial
*/
+ @SuppressWarnings("serial") // Conditionally serializable
protected Object[] elementData;
/**
@@ -122,6 +125,7 @@
protected int capacityIncrement;
/** use serialVersionUID from JDK 1.0.2 for interoperability */
+ @java.io.Serial
private static final long serialVersionUID = -2767605614048989439L;
/**
@@ -243,14 +247,6 @@
}
/**
- * The maximum size of array to allocate (unless necessary).
- * Some VMs reserve some header words in an array.
- * Attempts to allocate larger arrays may result in
- * OutOfMemoryError: Requested array size exceeds VM limit
- */
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
-
- /**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
@@ -258,8 +254,12 @@
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private Object[] grow(int minCapacity) {
- return elementData = Arrays.copyOf(elementData,
- newCapacity(minCapacity));
+ int oldCapacity = elementData.length;
+ int newCapacity = ArraysSupport.newLength(oldCapacity,
+ minCapacity - oldCapacity, /* minimum growth */
+ capacityIncrement > 0 ? capacityIncrement : oldCapacity
+ /* preferred growth */);
+ return elementData = Arrays.copyOf(elementData, newCapacity);
}
private Object[] grow() {
@@ -267,37 +267,6 @@
}
/**
- * Returns a capacity at least as large as the given minimum capacity.
- * Will not return a capacity greater than MAX_ARRAY_SIZE unless
- * the given minimum capacity is greater than MAX_ARRAY_SIZE.
- *
- * @param minCapacity the desired minimum capacity
- * @throws OutOfMemoryError if minCapacity is less than zero
- */
- private int newCapacity(int minCapacity) {
- // overflow-conscious code
- int oldCapacity = elementData.length;
- int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
- capacityIncrement : oldCapacity);
- if (newCapacity - minCapacity <= 0) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return minCapacity;
- }
- return (newCapacity - MAX_ARRAY_SIZE <= 0)
- ? newCapacity
- : hugeCapacity(minCapacity);
- }
-
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return (minCapacity > MAX_ARRAY_SIZE) ?
- Integer.MAX_VALUE :
- MAX_ARRAY_SIZE;
- }
-
- /**
* Sets the size of this vector. If the new size is greater than the
* current size, new {@code null} items are added to the end of
* the vector. If the new size is less than the current size, all
@@ -1191,11 +1160,18 @@
* @throws ClassNotFoundException if the stream contains data
* of a non-existing class
*/
+ @java.io.Serial
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
ObjectInputStream.GetField gfields = in.readFields();
int count = gfields.get("elementCount", 0);
Object[] data = (Object[])gfields.get("elementData", null);
+ if (data == null && !gfields.defaulted("elementData") && count > 0) {
+ // If elementData is null due to 8276665 throwing this exception will not
+ // overwrite the original ClassNotFoundException exception.
+ // That exception has been recorded and will be thrown from OIS.readObject.
+ throw new ClassNotFoundException("elementData is null");
+ }
if (count < 0 || data == null || count > data.length) {
throw new StreamCorruptedException("Inconsistent vector internals");
}
@@ -1212,6 +1188,7 @@
* @param s the stream
* @throws java.io.IOException if an I/O error occurs
*/
+ @java.io.Serial
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
final java.io.ObjectOutputStream.PutField fields = s.putFields();
@@ -1429,6 +1406,7 @@
es[i] = operator.apply(elementAt(es, i));
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
+ // TODO(8203662): remove increment of modCount from ...
modCount++;
}
diff --git a/ojluni/src/main/java/java/util/WeakHashMap.java b/ojluni/src/main/java/java/util/WeakHashMap.java
index 81d870b..03aee09 100644
--- a/ojluni/src/main/java/java/util/WeakHashMap.java
+++ b/ojluni/src/main/java/java/util/WeakHashMap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, 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,6 @@
import java.lang.ref.WeakReference;
import java.lang.ref.ReferenceQueue;
-import java.util.concurrent.ThreadLocalRandom;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@@ -252,7 +251,7 @@
* @since 1.3
*/
public WeakHashMap(Map<? extends K, ? extends V> m) {
- this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
+ this(Math.max((int) ((float)m.size() / DEFAULT_LOAD_FACTOR + 1.0F),
DEFAULT_INITIAL_CAPACITY),
DEFAULT_LOAD_FACTOR);
putAll(m);
@@ -283,8 +282,14 @@
* Checks for equality of non-null reference x and possibly-null y. By
* default uses Object.equals.
*/
- private static boolean eq(Object x, Object y) {
- return x == y || x.equals(y);
+ private boolean matchesKey(Entry<K,V> e, Object key) {
+ // check if the given entry refers to the given key without
+ // keeping a strong reference to the entry's referent
+ if (e.refersTo(key)) return true;
+
+ // then check for equality if the referent is not cleared
+ Object k = e.get();
+ return k != null && key.equals(k);
}
/**
@@ -399,7 +404,7 @@
int index = indexFor(h, tab.length);
Entry<K,V> e = tab[index];
while (e != null) {
- if (e.hash == h && eq(k, e.get()))
+ if (e.hash == h && matchesKey(e, k))
return e.value;
e = e.next;
}
@@ -428,7 +433,7 @@
Entry<K,V>[] tab = getTable();
int index = indexFor(h, tab.length);
Entry<K,V> e = tab[index];
- while (e != null && !(e.hash == h && eq(k, e.get())))
+ while (e != null && !(e.hash == h && matchesKey(e, k)))
e = e.next;
return e;
}
@@ -452,7 +457,7 @@
int i = indexFor(h, tab.length);
for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
- if (h == e.hash && eq(k, e.get())) {
+ if (h == e.hash && matchesKey(e, k)) {
V oldValue = e.value;
if (value != oldValue)
e.value = value;
@@ -515,8 +520,7 @@
src[j] = null;
while (e != null) {
Entry<K,V> next = e.next;
- Object key = e.get();
- if (key == null) {
+ if (e.refersTo(null)) {
e.next = null; // Help GC
e.value = null; // " "
size--;
@@ -597,7 +601,7 @@
while (e != null) {
Entry<K,V> next = e.next;
- if (h == e.hash && eq(k, e.get())) {
+ if (h == e.hash && matchesKey(e, k)) {
modCount++;
size--;
if (prev == e)
@@ -615,10 +619,9 @@
/** Special version of remove needed by Entry set */
boolean removeMapping(Object o) {
- if (!(o instanceof Map.Entry))
+ if (!(o instanceof Map.Entry<?, ?> entry))
return false;
Entry<K,V>[] tab = getTable();
- Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
Object k = maskNull(entry.getKey());
int h = hash(k);
int i = indexFor(h, tab.length);
@@ -733,9 +736,8 @@
}
public boolean equals(Object o) {
- if (!(o instanceof Map.Entry))
+ if (!(o instanceof Map.Entry<?, ?> e))
return false;
- Map.Entry<?,?> e = (Map.Entry<?,?>)o;
K k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
@@ -973,11 +975,9 @@
}
public boolean contains(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry<?,?> e = (Map.Entry<?,?>)o;
- Entry<K,V> candidate = getEntry(e.getKey());
- return candidate != null && candidate.equals(e);
+ return o instanceof Map.Entry<?, ?> e
+ && getEntry(e.getKey()) != null
+ && getEntry(e.getKey()).equals(e);
}
public boolean remove(Object o) {
diff --git a/ojluni/src/main/java/javax/crypto/spec/ChaCha20ParameterSpec.java b/ojluni/src/main/java/javax/crypto/spec/ChaCha20ParameterSpec.java
new file mode 100644
index 0000000..75c0526
--- /dev/null
+++ b/ojluni/src/main/java/javax/crypto/spec/ChaCha20ParameterSpec.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.crypto.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Objects;
+
+/**
+ * This class specifies the parameters used with the
+ * <a href="https://tools.ietf.org/html/rfc7539"><i>ChaCha20</i></a>
+ * algorithm.
+ *
+ * <p> The parameters consist of a 12-byte nonce and an initial
+ * counter value expressed as a 32-bit integer.
+ *
+ * <p> This class can be used to initialize a {@code Cipher} object that
+ * implements the <i>ChaCha20</i> algorithm.
+ *
+ * @since 11
+ */
+public final class ChaCha20ParameterSpec implements AlgorithmParameterSpec {
+
+ // The nonce length is defined by the spec as 96 bits (12 bytes) in length.
+ private static final int NONCE_LENGTH = 12;
+
+ private final byte[] nonce;
+ private final int counter;
+
+ /**
+ * Constructs a parameter set for ChaCha20 from the given nonce
+ * and counter.
+ *
+ * @param nonce a 12-byte nonce value
+ * @param counter the initial counter value
+ *
+ * @throws NullPointerException if {@code nonce} is {@code null}
+ * @throws IllegalArgumentException if {@code nonce} is not 12 bytes
+ * in length
+ */
+ public ChaCha20ParameterSpec(byte[] nonce, int counter) {
+ this.counter = counter;
+
+ Objects.requireNonNull(nonce, "Nonce must be non-null");
+ this.nonce = nonce.clone();
+ if (this.nonce.length != NONCE_LENGTH) {
+ throw new IllegalArgumentException(
+ "Nonce must be 12-bytes in length");
+ }
+ }
+
+ /**
+ * Returns the nonce value.
+ *
+ * @return the nonce value. This method returns a new array each time
+ * this method is called.
+ */
+ public byte[] getNonce() {
+ return nonce.clone();
+ }
+
+ /**
+ * Returns the configured counter value.
+ *
+ * @return the counter value
+ */
+ public int getCounter() {
+ return counter;
+ }
+}
diff --git a/ojluni/src/main/java/javax/security/auth/x500/X500PrivateCredential.java b/ojluni/src/main/java/javax/security/auth/x500/X500PrivateCredential.java
new file mode 100644
index 0000000..ae8d709
--- /dev/null
+++ b/ojluni/src/main/java/javax/security/auth/x500/X500PrivateCredential.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.security.auth.x500;
+
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import javax.security.auth.Destroyable;
+
+/**
+ * <p> This class represents an {@code X500PrivateCredential}.
+ * It associates an X.509 certificate, corresponding private key and the
+ * KeyStore alias used to reference that exact key pair in the KeyStore.
+ * This enables looking up the private credentials for an X.500 principal
+ * in a subject.
+ *
+ * @since 1.4
+ */
+public final class X500PrivateCredential implements Destroyable {
+ private X509Certificate cert;
+ private PrivateKey key;
+ private String alias;
+
+ /**
+ * Creates an X500PrivateCredential that associates an X.509 certificate,
+ * a private key and the KeyStore alias.
+ *
+ * @param cert X509Certificate
+ * @param key PrivateKey for the certificate
+ * @exception IllegalArgumentException if either {@code cert} or
+ * {@code key} is null
+ *
+ */
+
+ public X500PrivateCredential(X509Certificate cert, PrivateKey key) {
+ if (cert == null || key == null )
+ throw new IllegalArgumentException();
+ this.cert = cert;
+ this.key = key;
+ this.alias=null;
+ }
+
+ /**
+ * Creates an X500PrivateCredential that associates an X.509 certificate,
+ * a private key and the KeyStore alias.
+ *
+ * @param cert X509Certificate
+ * @param key PrivateKey for the certificate
+ * @param alias KeyStore alias
+ * @exception IllegalArgumentException if either {@code cert},
+ * {@code key} or {@code alias} is null
+ *
+ */
+ public X500PrivateCredential(X509Certificate cert, PrivateKey key,
+ String alias) {
+ if (cert == null || key == null|| alias == null )
+ throw new IllegalArgumentException();
+ this.cert = cert;
+ this.key = key;
+ this.alias=alias;
+ }
+
+ /**
+ * Returns the X.509 certificate.
+ *
+ * @return the X509Certificate
+ */
+
+ public X509Certificate getCertificate() {
+ return cert;
+ }
+
+ /**
+ * Returns the PrivateKey.
+ *
+ * @return the PrivateKey
+ */
+ public PrivateKey getPrivateKey() {
+ return key;
+ }
+
+ /**
+ * Returns the KeyStore alias.
+ *
+ * @return the KeyStore alias
+ */
+
+ public String getAlias() {
+ return alias;
+ }
+
+ /**
+ * Clears the references to the X.509 certificate, private key and the
+ * KeyStore alias in this object.
+ */
+
+ public void destroy() {
+ cert = null;
+ key = null;
+ alias =null;
+ }
+
+ /**
+ * Determines if the references to the X.509 certificate and private key
+ * in this object have been cleared.
+ *
+ * @return true if X509Certificate and the PrivateKey are null
+ */
+ public boolean isDestroyed() {
+ return cert == null && key == null && alias==null;
+ }
+}
diff --git a/ojluni/src/main/java/jdk/internal/ValueBased.java b/ojluni/src/main/java/jdk/internal/ValueBased.java
new file mode 100644
index 0000000..1599649
--- /dev/null
+++ b/ojluni/src/main/java/jdk/internal/ValueBased.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+/**
+ * Indicates the API declaration in question is associated with a Value Based class.
+ * References to <a href="../lang/doc-files/ValueBased.html">value-based classes</a>
+ * should produce warnings about behavior that is inconsistent with value based semantics.
+ *
+ * Note this internal annotation is handled specially by the javac compiler.
+ * To work properly with {@code --release older-release}, it requires special
+ * handling in {@code make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java}
+ * and {@code src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java}.
+ *
+ * @since 16
+ */
+// Android-changed: RetentionPolicy.SOURCE is sufficient as this is no-op on Android.
+// @Retention(RetentionPolicy.RUNTIME)
+@Retention(RetentionPolicy.SOURCE)
+@Target(value={TYPE})
+public @interface ValueBased {
+}
+
diff --git a/ojluni/src/main/java/jdk/internal/misc/InnocuousThread.java b/ojluni/src/main/java/jdk/internal/misc/InnocuousThread.java
index e62a032..4c50d6f 100644
--- a/ojluni/src/main/java/jdk/internal/misc/InnocuousThread.java
+++ b/ojluni/src/main/java/jdk/internal/misc/InnocuousThread.java
@@ -98,8 +98,8 @@
private InnocuousThread(ThreadGroup group, Runnable target, String name, ClassLoader tccl) {
super(group, target, name, 0L, false);
- UNSAFE.putObjectRelease(this, INHERITEDACCESSCONTROLCONTEXT, ACC);
- UNSAFE.putObjectRelease(this, CONTEXTCLASSLOADER, tccl);
+ UNSAFE.putReferenceRelease(this, INHERITEDACCESSCONTROLCONTEXT, ACC);
+ UNSAFE.putReferenceRelease(this, CONTEXTCLASSLOADER, tccl);
}
@Override
@@ -120,8 +120,8 @@
* Drops all thread locals (and inherited thread locals).
*/
public final void eraseThreadLocals() {
- UNSAFE.putObject(this, THREAD_LOCALS, null);
- UNSAFE.putObject(this, INHERITABLE_THREAD_LOCALS, null);
+ UNSAFE.putReference(this, THREAD_LOCALS, null);
+ UNSAFE.putReference(this, INHERITABLE_THREAD_LOCALS, null);
}
// ensure run method is run only once
@@ -158,10 +158,10 @@
long tg = UNSAFE.objectFieldOffset(tk, "group");
long gp = UNSAFE.objectFieldOffset(gk, "parent");
ThreadGroup group = (ThreadGroup)
- UNSAFE.getObject(Thread.currentThread(), tg);
+ UNSAFE.getReference(Thread.currentThread(), tg);
while (group != null) {
- ThreadGroup parent = (ThreadGroup)UNSAFE.getObject(group, gp);
+ ThreadGroup parent = (ThreadGroup)UNSAFE.getReference(group, gp);
if (parent == null)
break;
group = parent;
diff --git a/ojluni/src/main/java/jdk/internal/ref/CleanerFactory.java b/ojluni/src/main/java/jdk/internal/ref/CleanerFactory.java
index a4d3a0f..c6001a5 100644
--- a/ojluni/src/main/java/jdk/internal/ref/CleanerFactory.java
+++ b/ojluni/src/main/java/jdk/internal/ref/CleanerFactory.java
@@ -25,14 +25,7 @@
package jdk.internal.ref;
-import dalvik.system.ZygoteHooks;
-
-import jdk.internal.misc.InnocuousThread;
-
import java.lang.ref.Cleaner;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.concurrent.ThreadFactory;
/**
* CleanerFactory provides a Cleaner for use within system modules.
@@ -41,14 +34,12 @@
public final class CleanerFactory {
/* The common Cleaner. */
+ // Android-changed: objects registered in the system cleaner are cleaned
+ // by the finalizer daemon thread, not in a InnocuousThread.
+ /*
private final static Cleaner commonCleaner = Cleaner.create(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
- // Android-added: Fail immediately if we try this in the zygote, where we are
- // not allowed to create additional threads.
- if (ZygoteHooks.inZygote()) {
- throw new AssertionError("Erroneously trying to create Cleaner in zygote");
- }
return AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public Thread run() {
@@ -59,6 +50,8 @@
});
}
});
+ */
+ private static final Cleaner commonCleaner = Cleaner.createSystemCleaner();
/**
* Cleaner for use within system modules.
diff --git a/ojluni/src/main/java/jdk/internal/ref/CleanerImpl.java b/ojluni/src/main/java/jdk/internal/ref/CleanerImpl.java
index 16a82fe..88c476f 100644
--- a/ojluni/src/main/java/jdk/internal/ref/CleanerImpl.java
+++ b/ojluni/src/main/java/jdk/internal/ref/CleanerImpl.java
@@ -30,6 +30,7 @@
import java.lang.ref.ReferenceQueue;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.Objects;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
@@ -95,6 +96,14 @@
}
/**
+ * @hide
+ */
+ public CleanerImpl(ReferenceQueue<Object> queue) {
+ this.queue = queue;
+ this.phantomCleanableList = new PhantomCleanableRef();
+ }
+
+ /**
* Starts the Cleaner implementation.
* Ensure this is the CleanerImpl for the Cleaner.
* When started waits for Cleanables to be queued.
@@ -121,6 +130,19 @@
thread.start();
}
+ // Android-added: start system cleaner which does not need a thread factory.
+ /**
+ * Starts the Cleaner implementation. Does not need a thread factory as it
+ * should be used in the system cleaner only.
+ * @param cleaner the cleaner
+ * @hide
+ */
+ public void start(Cleaner cleaner) {
+ if (getCleanerImpl(cleaner) != this) {
+ throw new AssertionError("wrong cleaner");
+ }
+ }
+
/**
* Process queued Cleanables as long as the cleanable lists are not empty.
* A Cleanable is in one of the lists for each Object and for the Cleaner
diff --git a/ojluni/src/main/java/sun/invoke/util/Wrapper.java b/ojluni/src/main/java/sun/invoke/util/Wrapper.java
index a9005ed..4e2efa5 100644
--- a/ojluni/src/main/java/sun/invoke/util/Wrapper.java
+++ b/ojluni/src/main/java/sun/invoke/util/Wrapper.java
@@ -47,6 +47,7 @@
private final Class<?> wrapperType;
private final Class<?> primitiveType;
private final char basicTypeChar;
+ private final String basicTypeString;
private final Object emptyArray;
private final int format;
private final String wrapperSimpleName;
@@ -56,6 +57,7 @@
this.wrapperType = wtype;
this.primitiveType = ptype;
this.basicTypeChar = tchar;
+ this.basicTypeString = String.valueOf(this.basicTypeChar);
this.emptyArray = emptyArray;
this.format = format;
this.wrapperSimpleName = wtypeName;
@@ -459,6 +461,11 @@
*/
public char basicTypeChar() { return basicTypeChar; }
+ /** What is the bytecode signature string for this wrapper's
+ * primitive type?
+ */
+ public String basicTypeString() { return basicTypeString; }
+
/** What is the simple name of the wrapper type?
*/
public String wrapperSimpleName() { return wrapperSimpleName; }
diff --git a/ojluni/src/main/native/Adler32.c b/ojluni/src/main/native/Adler32.c
index 14680a6..137dc84 100644
--- a/ojluni/src/main/native/Adler32.c
+++ b/ojluni/src/main/native/Adler32.c
@@ -61,4 +61,19 @@
adler = adler32(adler, buf + off, len);
}
return adler;
-}
\ No newline at end of file
+}
+
+// Android-changed: register native methods.
+#include <nativehelper/JNIHelp.h>
+#define NATIVE_METHOD(className, functionName, signature) \
+{ #functionName, signature, (void*)(className ## _ ## functionName) }
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Java_java_util_zip_Adler32, update, "(II)I"),
+ NATIVE_METHOD(Java_java_util_zip_Adler32, updateBytes, "(I[BII)I"),
+ NATIVE_METHOD(Java_java_util_zip_Adler32, updateByteBuffer, "(IJII)I"),
+};
+
+void register_java_util_zip_Adler32(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/util/zip/Adler32", gMethods, NELEM(gMethods));
+}
diff --git a/ojluni/src/main/native/CRC32.c b/ojluni/src/main/native/CRC32.c
index a9d3ad0..adfb9f9 100644
--- a/ojluni/src/main/native/CRC32.c
+++ b/ojluni/src/main/native/CRC32.c
@@ -67,4 +67,19 @@
crc = crc32(crc, buf + off, len);
}
return crc;
-}
\ No newline at end of file
+}
+
+// Android-changed: register native methods.
+#include <nativehelper/JNIHelp.h>
+#define NATIVE_METHOD(className, functionName, signature) \
+{ #functionName, signature, (void*)(className ## _ ## functionName) }
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Java_java_util_zip_CRC32, update, "(II)I"),
+ NATIVE_METHOD(Java_java_util_zip_CRC32, updateBytes0, "(I[BII)I"),
+ NATIVE_METHOD(Java_java_util_zip_CRC32, updateByteBuffer0, "(IJII)I"),
+};
+
+void register_java_util_zip_CRC32(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/util/zip/CRC32", gMethods, NELEM(gMethods));
+}
diff --git a/ojluni/src/main/native/OnLoad.cpp b/ojluni/src/main/native/OnLoad.cpp
index 665a4c9..dd60a74 100644
--- a/ojluni/src/main/native/OnLoad.cpp
+++ b/ojluni/src/main/native/OnLoad.cpp
@@ -60,6 +60,10 @@
extern "C" void register_java_lang_UNIXProcess(JNIEnv* env);
void register_java_lang_Character(JNIEnv* env);
void register_jdk_internal_misc_VM(JNIEnv* env);
+extern "C" void register_java_util_zip_CRC32(JNIEnv* env);
+extern "C" void register_java_util_zip_Adler32(JNIEnv* env);
+extern "C" void register_java_sun_nio_fs_UnixNativeDispatcher(JNIEnv* env);
+extern "C" void register_java_sun_nio_ch_PollArrayWrapper(JNIEnv* env);
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
jint version = JNI_VERSION_1_6;
@@ -130,6 +134,11 @@
register_java_lang_Character(env);
register_jdk_internal_misc_VM(env);
+ register_java_util_zip_CRC32(env);
+ register_java_util_zip_Adler32(env);
+ register_java_sun_nio_fs_UnixNativeDispatcher(env);
+ register_java_sun_nio_ch_PollArrayWrapper(env);
+
env->PopLocalFrame(/* result */ nullptr); // Pop the local frame.
return version;
}
diff --git a/ojluni/src/main/native/PollArrayWrapper.c b/ojluni/src/main/native/PollArrayWrapper.c
index 2e97492..696f172 100644
--- a/ojluni/src/main/native/PollArrayWrapper.c
+++ b/ojluni/src/main/native/PollArrayWrapper.c
@@ -100,3 +100,17 @@
"Write to interrupt fd failed");
}
}
+
+// Android-changed: register native methods.
+#include <nativehelper/JNIHelp.h>
+#define NATIVE_METHOD(className, functionName, signature) \
+{ #functionName, signature, (void*)(className ## _ ## functionName) }
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Java_sun_nio_ch_PollArrayWrapper, interrupt, "(I)V"),
+ NATIVE_METHOD(Java_sun_nio_ch_PollArrayWrapper, poll0, "(JIJ)I"),
+};
+
+void register_java_sun_nio_ch_PollArrayWrapper(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "sun/nio/ch/PollArrayWrapper", gMethods, NELEM(gMethods));
+}
diff --git a/ojluni/src/main/native/UnixNativeDispatcher.c b/ojluni/src/main/native/UnixNativeDispatcher.c
index f373e8f..6710e13 100644
--- a/ojluni/src/main/native/UnixNativeDispatcher.c
+++ b/ojluni/src/main/native/UnixNativeDispatcher.c
@@ -1227,3 +1227,62 @@
return gid;
}
+
+// Android-changed: register native methods.
+#include <nativehelper/JNIHelp.h>
+#define NATIVE_METHOD(className, functionName, signature) \
+{ #functionName, signature, (void*)(className ## _ ## functionName) }
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, getcwd, "()[B"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, dup, "(I)I"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, open0, "(JII)I"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, openat0, "(IJII)I"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, close, "(I)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, fopen0, "(JJ)J"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, fclose, "(J)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, link0, "(JJ)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, unlink0, "(J)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, unlinkat0, "(IJI)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, mknod0, "(JIJ)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, rename0, "(JJ)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, renameat0, "(IJIJ)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, mkdir0, "(JI)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, rmdir0, "(J)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, readlink0, "(J)[B"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, realpath0, "(J)[B"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, symlink0, "(JJ)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, stat0, "(JLsun/nio/fs/UnixFileAttributes;)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, stat1, "(J)I"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, lstat0, "(JLsun/nio/fs/UnixFileAttributes;)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, fstat, "(ILsun/nio/fs/UnixFileAttributes;)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, fstatat0, "(IJILsun/nio/fs/UnixFileAttributes;)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, chown0, "(JII)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, lchown0, "(JII)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, fchown, "(III)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, chmod0, "(JI)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, fchmod, "(II)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, utimes0, "(JJJ)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, futimes, "(IJJ)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, opendir0, "(J)J"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, fdopendir, "(I)J"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, closedir, "(J)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, readdir, "(J)[B"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, read, "(IJI)I"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, write, "(IJI)I"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, access0, "(JI)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, exists0, "(J)Z"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, getpwuid, "(I)[B"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, getgrgid, "(I)[B"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, getpwnam0, "(J)I"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, getgrnam0, "(J)I"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, statvfs0, "(JLsun/nio/fs/UnixFileStoreAttributes;)V"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, pathconf0, "(JI)J"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, fpathconf, "(II)J"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, strerror, "(I)[B"),
+ NATIVE_METHOD(Java_sun_nio_fs_UnixNativeDispatcher, init, "()I"),
+};
+
+void register_java_sun_nio_fs_UnixNativeDispatcher(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "sun/nio/fs/UnixNativeDispatcher", gMethods, NELEM(gMethods));
+}
diff --git a/ojluni/src/test/java/lang/constant/ConvertTest.java b/ojluni/src/test/java/lang/constant/ConvertTest.java
new file mode 100644
index 0000000..069740e
--- /dev/null
+++ b/ojluni/src/test/java/lang/constant/ConvertTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @run testng ConvertTest
+ */
+package test.java.lang.constant;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.lang.invoke.ConstantBootstraps;
+import java.math.BigInteger;
+
+import static org.testng.Assert.assertEquals;
+
+public class ConvertTest {
+
+ @DataProvider
+ public static Object[][] cceInputs() {
+ return new Object[][]{
+ { void.class, null },
+ { Integer.class, "a" },
+ { int.class, BigInteger.ZERO },
+ };
+ }
+
+ @Test(dataProvider = "cceInputs", expectedExceptions = ClassCastException.class)
+ public void testBadConversion(Class<?> dstType, Object value) {
+ ConstantBootstraps.explicitCast(null, null, dstType, value);
+ }
+
+ @DataProvider
+ public static Object[][] goodInputs() {
+ Object o = new Object();
+ return new Object[][]{
+ { Object.class, null, null },
+ { Object.class, o, o },
+ { String.class, "abc", "abc" },
+ { short.class, 10, (short) 10 },
+ { int.class, (short) 10, 10 },
+ { boolean.class, 1, true },
+ { boolean.class, 2, false },
+ { int.class, true, 1 },
+ { int.class, false, 0 },
+ { int.class, 10, 10 },
+ { Integer.class, 10, 10 },
+ { Object.class, 10, 10 },
+ { Number.class, 10, 10 },
+ };
+ }
+
+ @Test(dataProvider = "goodInputs")
+ public void testSuccess(Class<?> dstType, Object value, Object expected) {
+ Object actual = ConstantBootstraps.explicitCast(null, null, dstType, value);
+ assertEquals(actual, expected);
+ }
+
+}
diff --git a/ojluni/src/test/java/lang/constant/DynamicConstantDescTest.java b/ojluni/src/test/java/lang/constant/DynamicConstantDescTest.java
new file mode 100644
index 0000000..ab1ce4e
--- /dev/null
+++ b/ojluni/src/test/java/lang/constant/DynamicConstantDescTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.lang.constant;
+
+import java.lang.constant.ClassDesc;
+import java.lang.constant.ConstantDesc;
+import java.lang.constant.DirectMethodHandleDesc;
+import java.lang.constant.DynamicConstantDesc;
+import java.lang.constant.MethodHandleDesc;
+import java.lang.constant.MethodTypeDesc;
+import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+/**
+ * @test
+ * @bug 8263108
+ * @summary Verify that concurrent classloading of java.lang.constant.DynamicConstantDesc and
+ * java.lang.constant.ConstantDescs doesn't lead to a deadlock
+ * @run main/othervm DynamicConstantDescTest
+ * @run main/othervm DynamicConstantDescTest
+ * @run main/othervm DynamicConstantDescTest
+ * @run main/othervm DynamicConstantDescTest
+ * @run main/othervm DynamicConstantDescTest
+ */
+// Implementation note: This test cannot use testng, since by the time this test gets a chance
+// to trigger a concurrent classloading of the classes it's interested in, the testng infrastructure
+// would already have loaded those classes in a single main thread.
+public class DynamicConstantDescTest {
+
+ /**
+ * Loads {@code java.lang.constant.DynamicConstantDesc} and {@code java.lang.constant.ConstantDescs}
+ * and invokes {@code java.lang.constant.DynamicConstantDesc#ofCanonical()} concurrently in a thread
+ * of their own and expects the classloading of both those classes
+ * to succeed.
+ */
+ public static void main(final String[] args) throws Exception {
+ final CountDownLatch taskTriggerLatch = new CountDownLatch(4);
+ final List<Callable<?>> tasks = new ArrayList<>();
+ // a bunch of tasks - some doing just Class.forName and some
+ // invoking DynamicConstantDesc.ofCanonical
+ tasks.add(new Task("java.lang.constant.DynamicConstantDesc", taskTriggerLatch));
+ tasks.add(new InvokeOfCanonical(taskTriggerLatch));
+ tasks.add(new Task("java.lang.constant.ConstantDescs", taskTriggerLatch));
+ tasks.add(new InvokeOfCanonical(taskTriggerLatch));
+ final ExecutorService executor = Executors.newFixedThreadPool(tasks.size());
+ try {
+ final Future<?>[] results = new Future[tasks.size()];
+ // submit
+ int i = 0;
+ for (final Callable<?> task : tasks) {
+ results[i++] = executor.submit(task);
+ }
+ // wait for completion
+ for (i = 0; i < tasks.size(); i++) {
+ results[i].get();
+ }
+ } finally {
+ executor.shutdownNow();
+ }
+ }
+
+ private static class Task implements Callable<Class<?>> {
+ private final String className;
+ private final CountDownLatch latch;
+
+ private Task(final String className, final CountDownLatch latch) {
+ this.className = className;
+ this.latch = latch;
+ }
+
+ @Override
+ public Class<?> call() {
+ System.out.println(Thread.currentThread().getName() + " loading " + this.className);
+ try {
+ // let the other tasks know we are ready to trigger our work
+ latch.countDown();
+ // wait for the other task to let us know they are ready to trigger their work too
+ latch.await();
+ return Class.forName(this.className);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ enum MyEnum {A, B}
+
+ private static class InvokeOfCanonical implements Callable<Object> {
+ private final CountDownLatch latch;
+
+ private InvokeOfCanonical(final CountDownLatch latch) {
+ this.latch = latch;
+ }
+
+ @Override
+ public Object call() {
+ System.out.println(Thread.currentThread().getName()
+ + " calling DynamicConstantDesc.ofCanonical()");
+ try {
+ // let the other tasks know we are ready to trigger our work
+ latch.countDown();
+ // wait for the other task to let us know they are ready to trigger their work too
+ latch.await();
+ ConstantDesc desc = DynamicConstantDesc.ofCanonical(boostrapMethodForEnumConstant(),
+ "A", ClassDesc.of("test.java.lang.constant.DynamicConstantDescTest").nested("MyEnum"),
+ new ConstantDesc[0]);
+ if (desc == null) {
+ throw new Exception("DynamicConstantDesc.ofCanonical unexpectedly returned null");
+ }
+ if (!MyEnum.A.equals(desc.resolveConstantDesc(MethodHandles.lookup()))) {
+ throw new Exception("DynamicConstantDesc.ofCanonical returned unexpected result " + desc);
+ }
+ return desc;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static DirectMethodHandleDesc boostrapMethodForEnumConstant() {
+ ClassDesc[] args = {ClassDesc.of("java.lang.invoke.MethodHandles").nested("Lookup"),
+ ClassDesc.of("java.lang.String"),
+ ClassDesc.of("java.lang.Class")};
+ return MethodHandleDesc.ofMethod(java.lang.constant.DirectMethodHandleDesc.Kind.STATIC,
+ ClassDesc.of("java.lang.invoke.ConstantBootstraps"),
+ "enumConstant", MethodTypeDesc.of(ClassDesc.of("java.lang.Enum"), new ClassDesc[0])
+ .insertParameterTypes(0, args));
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/ojluni/src/test/java/lang/constant/NameValidationTest.java b/ojluni/src/test/java/lang/constant/NameValidationTest.java
new file mode 100644
index 0000000..7e07099
--- /dev/null
+++ b/ojluni/src/test/java/lang/constant/NameValidationTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8215510
+ * @compile NameValidationTest.java
+ * @run testng NameValidationTest
+ * @summary unit tests for verifying member names
+ */
+package test.java.lang.constant;
+
+import java.lang.constant.*;
+import java.lang.invoke.*;
+
+import org.testng.annotations.Test;
+
+import static java.lang.constant.DirectMethodHandleDesc.*;
+import static java.lang.constant.ConstantDescs.*;
+import static java.lang.constant.DirectMethodHandleDesc.Kind.VIRTUAL;
+
+import static org.testng.Assert.fail;
+
+@Test
+public class NameValidationTest {
+
+ private static final String[] badMemberNames = new String[] {"xx.xx", "zz;zz", "[l", "aa/aa", "<cinit>"};
+ private static final String[] goodMemberNames = new String[] {"<clinit>", "<init>", "3", "~", "$", "qq"};
+
+ private static final String[] badClassNames = new String[] {"zz;zz", "[l", "aa/aa", ".", "a..b"};
+ private static final String[] goodClassNames = new String[] {"3", "~", "$", "qq", "a.a"};
+
+ public void testMemberNames() {
+ DirectMethodHandleDesc mh = MethodHandleDesc.of(Kind.VIRTUAL, CD_String, "isEmpty", "()Z");
+ for (String badName : badMemberNames) {
+ try {
+ memberNamesHelper(badName, mh, CD_int, null);
+ fail("Expected failure for name " + badName);
+ } catch (IllegalArgumentException iae) {
+ // expected
+ }
+ try {
+ memberNamesHelper(badName, mh, CD_int, new ConstantDesc[0]);
+ fail("Expected failure for name " + badName);
+ } catch (IllegalArgumentException iae) {
+ // expected
+ }
+ }
+
+ for (String badName : goodMemberNames) {
+ memberNamesHelper(badName, mh, CD_int, null);
+ memberNamesHelper(badName, mh, CD_int, new ConstantDesc[0]);
+ }
+ }
+
+ private void memberNamesHelper(String constantName,
+ DirectMethodHandleDesc bootstrapMethod,
+ ClassDesc constantType,
+ ConstantDesc... bootstrapArgs) {
+ if (bootstrapArgs == null) {
+ DynamicConstantDesc.ofNamed(bootstrapMethod, constantName, constantType);
+ } else {
+ DynamicConstantDesc.ofNamed(bootstrapMethod, constantName, constantType, bootstrapArgs);
+ }
+ }
+
+ public void testClassNames() {
+ for (String badName : badClassNames) {
+ try {
+ ClassDesc.of(badName);
+ fail("Expected failure for name " + badName);
+ } catch (IllegalArgumentException iae) {
+ // expected
+ }
+ }
+
+ for (String goodName : goodClassNames) {
+ ClassDesc.of(goodName);
+ }
+ }
+}
diff --git a/ojluni/src/test/java/lang/constant/access_test/pkg1/MethodTypeDescriptorAccessTest.java b/ojluni/src/test/java/lang/constant/access_test/pkg1/MethodTypeDescriptorAccessTest.java
new file mode 100644
index 0000000..b49e3f8
--- /dev/null
+++ b/ojluni/src/test/java/lang/constant/access_test/pkg1/MethodTypeDescriptorAccessTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8226709
+ * @summary MethodTypeDesc::resolveConstantDesc needs access check per the specification
+ * @compile ../pkg2/PublicClass.java ../pkg2/NonPublicClass.java
+ * @run main pkg1.MethodTypeDescriptorAccessTest
+ */
+
+// package pkg1;
+package test.java.lang.constant.access_test.pkg1;
+
+import java.lang.invoke.*;
+import java.lang.invoke.MethodType;
+import java.lang.constant.*;
+
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodHandles.Lookup.*;
+import static java.lang.invoke.MethodType.*;
+
+public class MethodTypeDescriptorAccessTest {
+ public static void main(String... args) throws Throwable {
+ new MethodTypeDescriptorAccessTest().test();
+ }
+
+ void test() {
+ Lookup selfLookup = MethodHandles.lookup();
+ //first test PublicClass
+ String descriptorpub = "(Ltest/java/lang/constant/access_test/pkg2/PublicClass;)Ltest/java/lang/constant/access_test/pkg2/PublicClass;";
+ MethodTypeDesc mtdpub = MethodTypeDesc.ofDescriptor(descriptorpub);
+ checkValidAccess(mtdpub, selfLookup);
+
+ // test NonPublicClass in the return type
+ String descriptornp = "()Ltest/java/lang/constant/access_test/pkg2/NonPublicClass;";
+ MethodTypeDesc mtdnp = MethodTypeDesc.ofDescriptor(descriptornp);
+ checkInvalidAccess(mtdnp, selfLookup);
+
+ // test NonPublicClass in the parameters
+ descriptornp = "(Ltest/java/lang/constant/access_test/pkg2/NonPublicClass;)I";
+ mtdnp = MethodTypeDesc.ofDescriptor(descriptornp);
+ checkInvalidAccess(mtdnp, selfLookup);
+
+ MethodType mt = MethodType.fromMethodDescriptorString("(Ltest/java/lang/constant/access_test/pkg2/NonPublicClass;)I", selfLookup.lookupClass().getClassLoader());
+ }
+
+ private void checkValidAccess(MethodTypeDesc mtd, Lookup lookup) {
+ try {
+ MethodType mt = (MethodType)mtd.resolveConstantDesc(lookup);
+ } catch (ReflectiveOperationException unexpected) {
+ throw new Error("resolveConstantDesc() threw ReflectiveOperationException unexpectedly with cause " +
+ unexpected.getCause() + " for " + mtd);
+ }
+ }
+
+ private void checkInvalidAccess(MethodTypeDesc mtd, Lookup lookup) {
+ try {
+ MethodType mt = (MethodType)mtd.resolveConstantDesc(lookup);
+ throw new Error("resolveConstantDesc() succeeded unexpectedly " + mtd);
+ } catch (ReflectiveOperationException expected) {
+ if (expected.getClass() != IllegalAccessException.class) {
+ throw new Error("resolveConstantDesc() threw unexpected ReflectiveOperationException with cause " +
+ expected.getCause() + " for " + mtd);
+ }
+ }
+ }
+
+}
diff --git a/ojluni/src/test/java/lang/constant/access_test/pkg2/NonPublicClass.java b/ojluni/src/test/java/lang/constant/access_test/pkg2/NonPublicClass.java
new file mode 100644
index 0000000..0f55c63
--- /dev/null
+++ b/ojluni/src/test/java/lang/constant/access_test/pkg2/NonPublicClass.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test.java.lang.constant.access_test.pkg2;
+
+class NonPublicClass {}
diff --git a/ojluni/src/test/java/lang/constant/access_test/pkg2/PublicClass.java b/ojluni/src/test/java/lang/constant/access_test/pkg2/PublicClass.java
new file mode 100644
index 0000000..6513e42
--- /dev/null
+++ b/ojluni/src/test/java/lang/constant/access_test/pkg2/PublicClass.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test.java.lang.constant.access_test.pkg2;
+
+public class PublicClass {}
diff --git a/ojluni/src/test/java/lang/reflect/records/CheckEqualityIsBasedOnFields.java b/ojluni/src/test/java/lang/reflect/records/CheckEqualityIsBasedOnFields.java
new file mode 100644
index 0000000..bcc5bd7
--- /dev/null
+++ b/ojluni/src/test/java/lang/reflect/records/CheckEqualityIsBasedOnFields.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8257598
+ * @summary check that Record::equals uses the fields and not the accessors for the comparison
+ * @run testng CheckEqualityIsBasedOnFields
+ */
+package test.java.lang.reflect.records;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+public class CheckEqualityIsBasedOnFields {
+ public record R01(boolean x) {
+ public boolean x() {
+ return x ? x : !x;
+ }
+ }
+
+ public record R02(byte x) {
+ public byte x() {
+ return (x >= 50) ? (byte)(x - 50) : x;
+ }
+ }
+
+ public record R03(short x) {
+ public short x() {
+ return (x >= 50) ? (short)(x - 50) : x;
+ }
+ }
+
+ public record R04(char x) {
+ public char x() {
+ return (x >= 50) ? (char)(x - 50) : x;
+ }
+ }
+
+ public record R05(int x) {
+ public int x() {
+ return (x >= 50) ? (x - 50) : x;
+ }
+ }
+
+ public record R06(long x) {
+ public long x() {
+ return (x >= 50) ? (long)(x - 50) : x;
+ }
+ }
+
+ public record R07(float x) {
+ public float x() {
+ return (x >= 50) ? (float)(x - 50) : x;
+ }
+ }
+ public record R08(double x) {
+ public double x() {
+ return (x >= 50) ? (double)(x - 50) : x;
+ }
+ }
+
+ public record R09(String x) {
+ public String x() {
+ return (x.length() > 1) ? x.substring(0, 1) : x;
+ }
+ }
+
+ @DataProvider(name = "recordData")
+ public Object[][] recordTypeAndExpectedValue() {
+ return new Object[][] {
+ new Object[] { R01.class, boolean.class, new Object[]{true, false} },
+ new Object[] { R02.class, byte.class, new Object[]{(byte)0, (byte)1, (byte)2, (byte)3, (byte)4, (byte)5,
+ (byte)50, (byte)51, (byte)52, (byte)53, (byte)54, (byte)55} },
+ new Object[] { R03.class, short.class, new Object[]{(short)0, (short)1, (short)2, (short)3, (short)4, (short)5,
+ (short)50, (short)51, (short)52, (short)53, (short)54, (short)55} },
+ new Object[] { R04.class, char.class, new Object[]{(char)0, (char)1, (char)2, (char)3, (char)4, (char)5,
+ (char)50, (char)51, (char)52, (char)53, (char)54, (char)55} },
+ new Object[] { R05.class, int.class, new Object[]{0, 1, 2, 3, 4, 5, 50, 51, 52, 53, 54, 55} },
+ new Object[] { R06.class, long.class, new Object[]{0L, 1L, 2L, 3L, 4L, 5L, 50L, 51L, 52L, 53L, 54L, 55L} },
+ new Object[] { R07.class, float.class, new Object[]{(float)0, (float)1, (float)2, (float)3, (float)4, (float)5,
+ (float)50, (float)51, (float)52, (float)53, (float)54, (float)55} },
+ new Object[] { R08.class, double.class, new Object[]{(double)0, (double)1, (double)2, (double)3, (double)4, (double)5,
+ (double)50, (double)51, (double)52, (double)53, (double)54, (double)55} },
+ new Object[] { R09.class, String.class, new Object[]{"1", "2", "3", "4", "5",
+ "1_", "2_", "3_", "4_", "5_"} },
+ };
+ }
+
+ @Test(dataProvider = "recordData")
+ public void testEqualsDoesntUseAccessors(Class<?> clazz, Class<?> componentClass, Object[] expectedXValues) throws Exception {
+ Constructor<?> ctor;
+ Method getter, equalsMethod;
+ ctor = clazz.getConstructor(componentClass);
+ equalsMethod = clazz.getMethod("equals", Object.class);
+ getter = clazz.getMethod("x");
+ for (int i = 0; i < expectedXValues.length / 2; i++) {
+ Object rec1 = ctor.newInstance(expectedXValues[i]);
+ Object rec2 = ctor.newInstance(expectedXValues[i + expectedXValues.length / 2]);
+ System.out.println(rec1.toString());
+ System.out.println(rec2.toString());
+ assertFalse((boolean) equalsMethod.invoke(rec1, rec2));
+ assertNotEquals(expectedXValues[i], expectedXValues[i + expectedXValues.length / 2]);
+ assertEquals(getter.invoke(rec1), getter.invoke(rec2));
+ }
+ }
+}
diff --git a/ojluni/src/test/java/lang/reflect/records/RecordReflectionTest.java b/ojluni/src/test/java/lang/reflect/records/RecordReflectionTest.java
new file mode 100644
index 0000000..38debf3
--- /dev/null
+++ b/ojluni/src/test/java/lang/reflect/records/RecordReflectionTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8235369 8235550 8247444
+ * @summary reflection test for records
+ * @compile RecordReflectionTest.java
+ * @run testng/othervm RecordReflectionTest
+ * @run testng/othervm/java.security.policy=allPermissions.policy RecordReflectionTest
+ */
+package test.java.lang.reflect.records;
+
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.List;
+import org.testng.annotations.*;
+import static org.testng.Assert.*;
+
+@Test
+public class RecordReflectionTest {
+
+ class NoRecord {}
+
+ record R1() {}
+
+ record R2(int i, int j) {}
+
+ record R3(List<String> ls) {}
+
+ record R4(R1 r1, R2 r2, R3 r3) {}
+
+ record R5(String... args) {}
+
+ record R6(long l, String... args) implements java.io.Serializable {}
+
+ record R7(String s1, String s2, String... args) {}
+
+ record R8<A, B>(A a, B b) implements java.io.Serializable { }
+
+ @DataProvider(name = "recordClasses")
+ public Object[][] recordClassData() {
+ return List.of(R1.class,
+ R2.class,
+ R3.class,
+ R4.class,
+ R5.class,
+ R6.class,
+ R7.class,
+ R8.class)
+ .stream().map(c -> new Object[] {c}).toArray(Object[][]::new);
+ }
+
+ @Test(dataProvider = "recordClasses")
+ public void testIsRecord(Class<?> cls) {
+ String message = cls.toGenericString();
+ assertTrue(cls.isRecord());
+ assertTrue(cls.getSuperclass() == java.lang.Record.class);
+ assertTrue(cls.getRecordComponents() != null);
+ assertTrue(message.contains("record"), message);
+ }
+
+ @DataProvider(name = "notRecordClasses")
+ public Object[][] notRecordClasses() {
+ return List.of(NoRecord.class,
+ NoRecord[].class,
+ Record.class, // java.lang.Record is not itself a record class
+ Record[].class,
+ byte.class,
+ byte[].class,
+ int.class,
+ int[].class,
+ long.class,
+ long[].class)
+ .stream().map(c -> new Object[] {c}).toArray(Object[][]::new);
+ }
+
+ @Test(dataProvider = "notRecordClasses")
+ public void testNotARecordClass(Class<?> cls) {
+ assertFalse(cls.isRecord());
+ assertFalse(cls.getSuperclass() == java.lang.Record.class);
+ assertTrue(cls.getRecordComponents() == null);
+ }
+
+ @DataProvider(name = "reflectionData")
+ public Object[][] reflectionData() {
+ return new Object[][] {
+ new Object[] { new R1(),
+ 0,
+ null,
+ null,
+ null },
+ new Object[] { new R2(1, 2),
+ 2,
+ new Object[]{ 1, 2 },
+ new String[]{ "i", "j" },
+ new String[]{ "int", "int"} },
+ new Object[] { new R3(List.of("1")),
+ 1,
+ new Object[]{ List.of("1") },
+ new String[]{ "ls" },
+ new String[]{ "java.util.List<java.lang.String>"} },
+ new Object[] { new R4(new R1(), new R2(6, 7), new R3(List.of("s"))),
+ 3,
+ new Object[]{ new R1(), new R2(6, 7), new R3(List.of("s")) },
+ new String[]{ "r1", "r2", "r3" },
+ new String[]{ R1.class.toString(), R2.class.toString(), R3.class.toString()} },
+ };
+ }
+
+ @Test(dataProvider = "reflectionData")
+ public void testRecordReflection(Object recordOb,
+ int numberOfComponents,
+ Object[] values,
+ String[] names,
+ String[] signatures)
+ throws ReflectiveOperationException
+ {
+ Class<?> recordClass = recordOb.getClass();
+ assertTrue(recordClass.isRecord());
+ RecordComponent[] recordComponents = recordClass.getRecordComponents();
+ assertEquals(recordComponents.length, numberOfComponents);
+ int i = 0;
+ for (RecordComponent rc : recordComponents) {
+ assertEquals(rc.getName(), names[i]);
+ assertEquals(rc.getType(), rc.getAccessor().getReturnType());
+ assertEquals(rc.getAccessor().invoke(recordOb), values[i]);
+ assertEquals(rc.getAccessor().getGenericReturnType().toString(), signatures[i],
+ String.format("signature of method \"%s\" different from expected signature \"%s\"",
+ rc.getAccessor().getGenericReturnType(), signatures[i]));
+ i++;
+ }
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ ElementType.RECORD_COMPONENT, ElementType.FIELD })
+ @interface RCA {}
+
+ record AnnotatedRec(@RCA int i) {}
+
+ public void testDeclAnnotationsInRecordComp() throws Throwable {
+ Class<?> recordClass = AnnotatedRec.class;
+ RecordComponent rc = recordClass.getRecordComponents()[0];
+ Annotation[] annos = rc.getAnnotations();
+ assertEquals(annos.length, 1);
+ assertEquals(annos[0].toString(), "@test.java.lang.reflect.records.RecordReflectionTest$RCA()");
+
+ Field f = recordClass.getDeclaredField("i");
+ assertEquals(f.getAnnotations().length, 1);
+ assertEquals(f.getAnnotations()[0].toString(), annos[0].toString());
+ }
+
+ // BEGIN Android-removed: ART doesn't support the Annotated Type APIs.
+ /*
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.TYPE_USE})
+ @interface TYPE_USE {}
+
+ record TypeAnnotatedRec(@TYPE_USE int i) {}
+
+ public void testTypeAnnotationsInRecordComp() throws Throwable {
+ Class<?> recordClass = TypeAnnotatedRec.class;
+ RecordComponent rc = recordClass.getRecordComponents()[0];
+ AnnotatedType at = rc.getAnnotatedType();
+ Annotation[] annos = at.getAnnotations();
+ assertEquals(annos.length, 1);
+ assertEquals(annos[0].toString(), "@RecordReflectionTest$TYPE_USE()");
+
+ Field f = recordClass.getDeclaredField("i");
+ assertEquals(f.getAnnotatedType().getAnnotations().length, 1);
+ assertEquals(f.getAnnotatedType().getAnnotations()[0].toString(), annos[0].toString());
+ }
+ */
+ // END Android-removed: ART doesn't support the Annotated Type APIs.
+
+ // Android-changed: ART doesn't prevent writes to record field yet.
+ @Test(enabled = false)
+ public void testReadOnlyFieldInRecord() throws Throwable {
+ R2 o = new R2(1, 2);
+ Class<?> recordClass = R2.class;
+ String fieldName = "i";
+ Field f = recordClass.getDeclaredField(fieldName);
+ // Android-changed: libcore doesn't have the trySetAccessible method yet.
+ // assertTrue(f.trySetAccessible());
+ f.setAccessible(true);
+ assertTrue(f.get(o) != null);
+ try {
+ f.set(o, null);
+ assertTrue(false, "should fail to set " + fieldName);
+ } catch (IllegalAccessException e) {
+ }
+ }
+
+}
diff --git a/ojluni/src/test/java/nio/Buffer/EqualsCompareTest.java b/ojluni/src/test/java/nio/Buffer/EqualsCompareTest.java
new file mode 100644
index 0000000..cae95e1
--- /dev/null
+++ b/ojluni/src/test/java/nio/Buffer/EqualsCompareTest.java
@@ -0,0 +1,714 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.nio.Buffer;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.LongBuffer;
+import java.nio.ShortBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.LongFunction;
+import java.util.stream.IntStream;
+
+/*
+ * @test
+ * @bug 8193085 8199773
+ * @summary tests for buffer equals and compare
+ * @run testng EqualsCompareTest
+ */
+
+public class EqualsCompareTest {
+
+ // Maximum width in bits
+ static final int MAX_WIDTH = 512;
+
+ static final Map<Class, Integer> typeToWidth;
+
+ static {
+ typeToWidth = new HashMap<>();
+ typeToWidth.put(byte.class, Byte.SIZE);
+ typeToWidth.put(short.class, Short.SIZE);
+ typeToWidth.put(char.class, Character.SIZE);
+ typeToWidth.put(int.class, Integer.SIZE);
+ typeToWidth.put(long.class, Long.SIZE);
+ typeToWidth.put(float.class, Float.SIZE);
+ typeToWidth.put(double.class, Double.SIZE);
+ }
+
+ static int arraySizeFor(Class<?> type) {
+ assert type.isPrimitive();
+ return 4 * MAX_WIDTH / typeToWidth.get(type);
+ }
+
+ enum BufferKind {
+ HEAP,
+ HEAP_VIEW,
+ DIRECT;
+ }
+
+ static abstract class BufferType<T extends Buffer, E> {
+ final BufferKind k;
+ final Class<?> bufferType;
+ final Class<?> elementType;
+
+ final MethodHandle eq;
+ final MethodHandle cmp;
+ final MethodHandle mismtch;
+
+ final MethodHandle getter;
+ final MethodHandle setter;
+
+ BufferType(BufferKind k, Class<T> bufferType, Class<?> elementType) {
+ this.k = k;
+ this.bufferType = bufferType;
+ this.elementType = elementType;
+
+ var lookup = MethodHandles.lookup();
+ try {
+ eq = lookup.findVirtual(bufferType, "equals", MethodType.methodType(boolean.class, Object.class));
+ cmp = lookup.findVirtual(bufferType, "compareTo", MethodType.methodType(int.class, bufferType));
+ mismtch = lookup.findVirtual(bufferType, "mismatch", MethodType.methodType(int.class, bufferType));
+
+ getter = lookup.findVirtual(bufferType, "get", MethodType.methodType(elementType, int.class));
+ setter = lookup.findVirtual(bufferType, "put", MethodType.methodType(bufferType, int.class, elementType));
+ }
+ catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return bufferType.getName() + " " + k;
+ }
+
+ T construct(int length) {
+ return construct(length, ByteOrder.BIG_ENDIAN);
+ }
+
+ abstract T construct(int length, ByteOrder bo);
+
+ @SuppressWarnings("unchecked")
+ T slice(T a, int from, int to, boolean dupOtherwiseSlice) {
+ a = (T) a.position(from).limit(to);
+ return (T) (dupOtherwiseSlice ? a.duplicate() : a.slice());
+ }
+
+ @SuppressWarnings("unchecked")
+ E get(T a, int i) {
+ try {
+ return (E) getter.invoke(a, i);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ void set(T a, int i, Object v) {
+ try {
+ setter.invoke(a, i, convert(v));
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ abstract Object convert(Object o);
+
+ boolean equals(T a, T b) {
+ try {
+ return (boolean) eq.invoke(a, b);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ int compare(T a, T b) {
+ try {
+ return (int) cmp.invoke(a, b);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ boolean pairWiseEquals(T a, T b) {
+ if (a.remaining() != b.remaining())
+ return false;
+ int p = a.position();
+ for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--)
+ if (!get(a, i).equals(get(b, j)))
+ return false;
+ return true;
+ }
+
+ int mismatch(T a, T b) {
+ try {
+ return (int) mismtch.invoke(a, b);
+ }
+ catch (RuntimeException | Error e) {
+ throw e;
+ }
+ catch (Throwable t) {
+ throw new Error(t);
+ }
+ }
+
+ static class Bytes extends BufferType<ByteBuffer, Byte> {
+ Bytes(BufferKind k) {
+ super(k, ByteBuffer.class, byte.class);
+ }
+
+ @Override
+ ByteBuffer construct(int length, ByteOrder bo) {
+ switch (k) {
+ case DIRECT:
+ return ByteBuffer.allocateDirect(length).order(bo);
+ default:
+ case HEAP_VIEW:
+ case HEAP:
+ return ByteBuffer.allocate(length).order(bo);
+ }
+ }
+
+ @Override
+ Object convert(Object o) {
+ return o instanceof Integer
+ ? ((Integer) o).byteValue()
+ : o;
+ }
+ }
+
+ static class Chars extends BufferType<CharBuffer, Character> {
+ Chars(BufferKind k) {
+ super(k, CharBuffer.class, char.class);
+ }
+
+ @Override
+ CharBuffer construct(int length, ByteOrder bo) {
+ switch (k) {
+ case DIRECT:
+ return ByteBuffer.allocateDirect(length * Character.BYTES).
+ order(bo).
+ asCharBuffer();
+ case HEAP_VIEW:
+ return ByteBuffer.allocate(length * Character.BYTES).
+ order(bo).
+ asCharBuffer();
+ default:
+ case HEAP:
+ return CharBuffer.allocate(length);
+ }
+ }
+
+ @Override
+ Object convert(Object o) {
+ return o instanceof Integer
+ ? (char) ((Integer) o).intValue()
+ : o;
+ }
+
+ CharBuffer transformToStringBuffer(CharBuffer c) {
+ char[] chars = new char[c.remaining()];
+ c.get(chars);
+ return CharBuffer.wrap(new String(chars));
+ }
+ }
+
+ static class Shorts extends BufferType<ShortBuffer, Short> {
+ Shorts(BufferKind k) {
+ super(k, ShortBuffer.class, short.class);
+ }
+
+ @Override
+ ShortBuffer construct(int length, ByteOrder bo) {
+ switch (k) {
+ case DIRECT:
+ return ByteBuffer.allocateDirect(length * Short.BYTES).
+ order(bo).
+ asShortBuffer();
+ case HEAP_VIEW:
+ return ByteBuffer.allocate(length * Short.BYTES).
+ order(bo).
+ asShortBuffer();
+ default:
+ case HEAP:
+ return ShortBuffer.allocate(length);
+ }
+ }
+
+ @Override
+ Object convert(Object o) {
+ return o instanceof Integer
+ ? ((Integer) o).shortValue()
+ : o;
+ }
+ }
+
+ static class Ints extends BufferType<IntBuffer, Integer> {
+ Ints(BufferKind k) {
+ super(k, IntBuffer.class, int.class);
+ }
+
+ @Override
+ IntBuffer construct(int length, ByteOrder bo) {
+ switch (k) {
+ case DIRECT:
+ return ByteBuffer.allocateDirect(length * Integer.BYTES).
+ order(bo).
+ asIntBuffer();
+ case HEAP_VIEW:
+ return ByteBuffer.allocate(length * Integer.BYTES).
+ order(bo).
+ asIntBuffer();
+ default:
+ case HEAP:
+ return IntBuffer.allocate(length);
+ }
+ }
+
+ Object convert(Object o) {
+ return o;
+ }
+ }
+
+ static class Floats extends BufferType<FloatBuffer, Float> {
+ Floats(BufferKind k) {
+ super(k, FloatBuffer.class, float.class);
+ }
+
+ @Override
+ FloatBuffer construct(int length, ByteOrder bo) {
+ switch (k) {
+ case DIRECT:
+ return ByteBuffer.allocateDirect(length * Float.BYTES).
+ order(bo).
+ asFloatBuffer();
+ case HEAP_VIEW:
+ return ByteBuffer.allocate(length * Float.BYTES).
+ order(bo).
+ asFloatBuffer();
+ default:
+ case HEAP:
+ return FloatBuffer.allocate(length);
+ }
+ }
+
+ @Override
+ Object convert(Object o) {
+ return o instanceof Integer
+ ? ((Integer) o).floatValue()
+ : o;
+ }
+
+ @Override
+ boolean pairWiseEquals(FloatBuffer a, FloatBuffer b) {
+ if (a.remaining() != b.remaining())
+ return false;
+ int p = a.position();
+ for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--) {
+ float av = a.get(i);
+ float bv = b.get(j);
+ if (av != bv && (!Float.isNaN(av) || !Float.isNaN(bv)))
+ return false;
+ }
+ return true;
+ }
+ }
+
+ static class Longs extends BufferType<LongBuffer, Long> {
+ Longs(BufferKind k) {
+ super(k, LongBuffer.class, long.class);
+ }
+
+ @Override
+ LongBuffer construct(int length, ByteOrder bo) {
+ switch (k) {
+ case DIRECT:
+ return ByteBuffer.allocateDirect(length * Long.BYTES).
+ order(bo).
+ asLongBuffer();
+ case HEAP_VIEW:
+ return ByteBuffer.allocate(length * Long.BYTES).
+ order(bo).
+ asLongBuffer();
+ default:
+ case HEAP:
+ return LongBuffer.allocate(length);
+ }
+ }
+
+ @Override
+ Object convert(Object o) {
+ return o instanceof Integer
+ ? ((Integer) o).longValue()
+ : o;
+ }
+ }
+
+ static class Doubles extends BufferType<DoubleBuffer, Double> {
+ Doubles(BufferKind k) {
+ super(k, DoubleBuffer.class, double.class);
+ }
+
+ @Override
+ DoubleBuffer construct(int length, ByteOrder bo) {
+ switch (k) {
+ case DIRECT:
+ return ByteBuffer.allocateDirect(length * Double.BYTES).
+ order(bo).
+ asDoubleBuffer();
+ case HEAP_VIEW:
+ return ByteBuffer.allocate(length * Double.BYTES).
+ order(bo).
+ asDoubleBuffer();
+ default:
+ case HEAP:
+ return DoubleBuffer.allocate(length);
+ }
+ }
+
+ @Override
+ Object convert(Object o) {
+ return o instanceof Integer
+ ? ((Integer) o).doubleValue()
+ : o;
+ }
+
+ @Override
+ boolean pairWiseEquals(DoubleBuffer a, DoubleBuffer b) {
+ if (a.remaining() != b.remaining())
+ return false;
+ int p = a.position();
+ for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--) {
+ double av = a.get(i);
+ double bv = b.get(j);
+ if (av != bv && (!Double.isNaN(av) || !Double.isNaN(bv)))
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+
+ static Object[][] bufferTypes;
+
+ @DataProvider
+ public static Object[][] bufferTypesProvider() {
+ if (bufferTypes == null) {
+ bufferTypes = new Object[][]{
+ {new BufferType.Bytes(BufferKind.HEAP)},
+ {new BufferType.Bytes(BufferKind.DIRECT)},
+ {new BufferType.Chars(BufferKind.HEAP)},
+ {new BufferType.Chars(BufferKind.HEAP_VIEW)},
+ {new BufferType.Chars(BufferKind.DIRECT)},
+ {new BufferType.Shorts(BufferKind.HEAP)},
+ {new BufferType.Shorts(BufferKind.HEAP_VIEW)},
+ {new BufferType.Shorts(BufferKind.DIRECT)},
+ {new BufferType.Ints(BufferKind.HEAP)},
+ {new BufferType.Ints(BufferKind.HEAP_VIEW)},
+ {new BufferType.Ints(BufferKind.DIRECT)},
+ {new BufferType.Floats(BufferKind.HEAP)},
+ {new BufferType.Floats(BufferKind.HEAP_VIEW)},
+ {new BufferType.Floats(BufferKind.DIRECT)},
+ {new BufferType.Longs(BufferKind.HEAP)},
+ {new BufferType.Longs(BufferKind.HEAP_VIEW)},
+ {new BufferType.Longs(BufferKind.DIRECT)},
+ {new BufferType.Doubles(BufferKind.HEAP)},
+ {new BufferType.Doubles(BufferKind.HEAP_VIEW)},
+ {new BufferType.Doubles(BufferKind.DIRECT)},
+ };
+ }
+ return bufferTypes;
+ }
+
+
+ static Object[][] floatbufferTypes;
+
+ @DataProvider
+ public static Object[][] floatBufferTypesProvider() {
+ if (floatbufferTypes == null) {
+ LongFunction<Object> bTof = rb -> Float.intBitsToFloat((int) rb);
+ LongFunction<Object> bToD = Double::longBitsToDouble;
+
+ floatbufferTypes = new Object[][]{
+ // canonical and non-canonical NaNs
+ // If conversion is a signalling NaN it may be subject to conversion to a
+ // quiet NaN on some processors, even if a copy is performed
+ // The tests assume that if conversion occurs it does not convert to the
+ // canonical NaN
+ new Object[]{new BufferType.Floats(BufferKind.HEAP), 0x7fc00000L, 0x7f800001L, bTof},
+ new Object[]{new BufferType.Floats(BufferKind.HEAP_VIEW), 0x7fc00000L, 0x7f800001L, bTof},
+ new Object[]{new BufferType.Floats(BufferKind.DIRECT), 0x7fc00000L, 0x7f800001L, bTof},
+ new Object[]{new BufferType.Doubles(BufferKind.HEAP), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},
+ new Object[]{new BufferType.Doubles(BufferKind.HEAP_VIEW), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},
+ new Object[]{new BufferType.Doubles(BufferKind.DIRECT), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},
+
+ // +0.0 and -0.0
+ new Object[]{new BufferType.Floats(BufferKind.HEAP), 0x0L, 0x80000000L, bTof},
+ new Object[]{new BufferType.Floats(BufferKind.HEAP_VIEW), 0x0L, 0x80000000L, bTof},
+ new Object[]{new BufferType.Floats(BufferKind.DIRECT), 0x0L, 0x80000000L, bTof},
+ new Object[]{new BufferType.Doubles(BufferKind.HEAP), 0x0L, 0x8000000000000000L, bToD},
+ new Object[]{new BufferType.Doubles(BufferKind.HEAP_VIEW), 0x0L, 0x8000000000000000L, bToD},
+ new Object[]{new BufferType.Doubles(BufferKind.DIRECT), 0x0L, 0x8000000000000000L, bToD},
+ };
+ }
+ return floatbufferTypes;
+ }
+
+
+ static Object[][] charBufferTypes;
+
+ @DataProvider
+ public static Object[][] charBufferTypesProvider() {
+ if (charBufferTypes == null) {
+ charBufferTypes = new Object[][]{
+ {new BufferType.Chars(BufferKind.HEAP)},
+ {new BufferType.Chars(BufferKind.HEAP_VIEW)},
+ {new BufferType.Chars(BufferKind.DIRECT)},
+ };
+ }
+ return charBufferTypes;
+ }
+
+
+ // Tests all primitive buffers
+ @Test(dataProvider = "bufferTypesProvider")
+ public void testBuffers(BufferType<Buffer, Buffer> bufferType) {
+ // Test with buffers of the same byte order (BE)
+ BiFunction<BufferType<Buffer, Buffer>, Integer, Buffer> constructor = (at, s) -> {
+ Buffer a = at.construct(s);
+ for (int x = 0; x < s; x++) {
+ at.set(a, x, x % 8);
+ }
+ return a;
+ };
+
+ // Test with buffers of different byte order
+ if (bufferType.elementType != byte.class &&
+ (bufferType.k == BufferKind.HEAP_VIEW ||
+ bufferType.k == BufferKind.DIRECT)) {
+
+ BiFunction<BufferType<Buffer, Buffer>, Integer, Buffer> leConstructor = (at, s) -> {
+ Buffer a = at.construct(s, ByteOrder.LITTLE_ENDIAN);
+ for (int x = 0; x < s; x++) {
+ at.set(a, x, x % 8);
+ }
+ return a;
+ };
+ testBufferType(bufferType, constructor, leConstructor);
+ }
+ }
+
+ // Tests float and double buffers with edge-case values (NaN, -0.0, +0.0)
+ @Test(dataProvider = "floatBufferTypesProvider")
+ public void testFloatBuffers(
+ BufferType<Buffer, Float> bufferType,
+ long rawBitsA, long rawBitsB,
+ LongFunction<Object> bitsToFloat) {
+ Object av = bitsToFloat.apply(rawBitsA);
+ Object bv = bitsToFloat.apply(rawBitsB);
+
+ BiFunction<BufferType<Buffer, Float>, Integer, Buffer> allAs = (at, s) -> {
+ Buffer b = at.construct(s);
+ for (int x = 0; x < s; x++) {
+ at.set(b, x, av);
+ }
+ return b;
+ };
+
+ BiFunction<BufferType<Buffer, Float>, Integer, Buffer> allBs = (at, s) -> {
+ Buffer b = at.construct(s);
+ for (int x = 0; x < s; x++) {
+ at.set(b, x, bv);
+ }
+ return b;
+ };
+
+ BiFunction<BufferType<Buffer, Float>, Integer, Buffer> halfBs = (at, s) -> {
+ Buffer b = at.construct(s);
+ for (int x = 0; x < s / 2; x++) {
+ at.set(b, x, bv);
+ }
+ for (int x = s / 2; x < s; x++) {
+ at.set(b, x, 1);
+ }
+ return b;
+ };
+
+ // Validation check
+ int size = arraySizeFor(bufferType.elementType);
+ Assert.assertTrue(bufferType.pairWiseEquals(allAs.apply(bufferType, size),
+ allBs.apply(bufferType, size)));
+ Assert.assertTrue(bufferType.equals(allAs.apply(bufferType, size),
+ allBs.apply(bufferType, size)));
+
+ testBufferType(bufferType, allAs, allBs);
+ testBufferType(bufferType, allAs, halfBs);
+ }
+
+ // Tests CharBuffer for region sources and CharSequence sources
+ @Test(dataProvider = "charBufferTypesProvider")
+ public void testCharBuffers(BufferType.Chars charBufferType) {
+
+ BiFunction<BufferType.Chars, Integer, CharBuffer> constructor = (at, s) -> {
+ CharBuffer a = at.construct(s);
+ for (int x = 0; x < s; x++) {
+ at.set(a, x, x % 8);
+ }
+ return a;
+ };
+
+ BiFunction<BufferType.Chars, Integer, CharBuffer> constructorX = constructor.
+ andThen(charBufferType::transformToStringBuffer);
+
+ testBufferType(charBufferType, constructor, constructorX);
+ }
+
+
+ <B extends Buffer, E, BT extends BufferType<B, E>>
+ void testBufferType(BT bt,
+ BiFunction<BT, Integer, B> aConstructor,
+ BiFunction<BT, Integer, B> bConstructor) {
+ int n = arraySizeFor(bt.elementType);
+
+ for (boolean dupOtherwiseSlice : new boolean[]{ false, true }) {
+ for (int s : ranges(0, n)) {
+ B a = aConstructor.apply(bt, s);
+ B b = bConstructor.apply(bt, s);
+
+ for (int aFrom : ranges(0, s)) {
+ for (int aTo : ranges(aFrom, s)) {
+ int aLength = aTo - aFrom;
+
+ B as = aLength != s
+ ? bt.slice(a, aFrom, aTo, dupOtherwiseSlice)
+ : a;
+
+ for (int bFrom : ranges(0, s)) {
+ for (int bTo : ranges(bFrom, s)) {
+ int bLength = bTo - bFrom;
+
+ B bs = bLength != s
+ ? bt.slice(b, bFrom, bTo, dupOtherwiseSlice)
+ : b;
+
+ boolean eq = bt.pairWiseEquals(as, bs);
+ Assert.assertEquals(bt.equals(as, bs), eq);
+ Assert.assertEquals(bt.equals(bs, as), eq);
+ if (eq) {
+ Assert.assertEquals(bt.compare(as, bs), 0);
+ Assert.assertEquals(bt.compare(bs, as), 0);
+
+ // If buffers are equal, there shall be no mismatch
+ Assert.assertEquals(bt.mismatch(as, bs), -1);
+ Assert.assertEquals(bt.mismatch(bs, as), -1);
+ }
+ else {
+ int aCb = bt.compare(as, bs);
+ int bCa = bt.compare(bs, as);
+ int v = Integer.signum(aCb) * Integer.signum(bCa);
+ Assert.assertTrue(v == -1);
+
+ int aMs = bt.mismatch(as, bs);
+ int bMs = bt.mismatch(bs, as);
+ Assert.assertNotEquals(aMs, -1);
+ Assert.assertEquals(aMs, bMs);
+ }
+ }
+ }
+ // TODO(b/271236407): fix this
+// if (aLength > 0 && !a.isReadOnly()) {
+// for (int i = aFrom; i < aTo; i++) {
+// B c = aConstructor.apply(bt, a.capacity());
+// B cs = aLength != s
+// ? bt.slice(c, aFrom, aTo, dupOtherwiseSlice)
+// : c;
+//
+// // Create common prefix with a length of i - aFrom
+// bt.set(c, i, -1);
+//
+// Assert.assertFalse(bt.equals(c, a));
+//
+// int cCa = bt.compare(cs, as);
+// int aCc = bt.compare(as, cs);
+// int v = Integer.signum(cCa) * Integer.signum(aCc);
+// Assert.assertTrue(v == -1);
+//
+// int cMa = bt.mismatch(cs, as);
+// int aMc = bt.mismatch(as, cs);
+// Assert.assertEquals(cMa, aMc);
+// Assert.assertEquals(cMa, i - aFrom);
+// }
+// }
+ }
+ }
+ }
+ }
+ }
+
+ static int[] ranges(int from, int to) {
+ int width = to - from;
+ switch (width) {
+ case 0:
+ return new int[]{};
+ case 1:
+ return new int[]{from, to};
+ case 2:
+ return new int[]{from, from + 1, to};
+ case 3:
+ return new int[]{from, from + 1, from + 2, to};
+ default:
+ return IntStream.of(from, from + 1, from + 2, to / 2 - 1, to / 2, to / 2 + 1, to - 2, to - 1, to)
+ .filter(i -> i >= from && i <= to)
+ .distinct().toArray();
+ }
+ }
+}
diff --git a/ojluni/src/tools/gensrc_android.sh b/ojluni/src/tools/gensrc_android.sh
index 732cec0..0410741 100755
--- a/ojluni/src/tools/gensrc_android.sh
+++ b/ojluni/src/tools/gensrc_android.sh
@@ -27,7 +27,7 @@
OJLUNI_JAVA_ROOT=${ANDROID_BUILD_TOP}/libcore/ojluni/src/main/java
-NAWK=awk SCRIPTS=${ANDROID_BUILD_TOP}/libcore/ojluni/src/tools/scripts/ \
+AWK=awk SCRIPTS=${ANDROID_BUILD_TOP}/libcore/ojluni/src/tools/scripts/ \
${ANDROID_BUILD_TOP}/libcore/ojluni/src/tools/scripts/genExceptions.sh \
${OJLUNI_JAVA_ROOT}/java/nio/charset/exceptions \
${OJLUNI_JAVA_ROOT}/java/nio/charset
diff --git a/ojluni/src/tools/make/Makefile b/ojluni/src/tools/make/Makefile
index aec6826..ecfdbf2 100644
--- a/ojluni/src/tools/make/Makefile
+++ b/ojluni/src/tools/make/Makefile
@@ -32,7 +32,7 @@
# Define command line tools
MKDIR := mkdir
-RM := rm
+RM := rm -f # ignore if the file doesn't exist
MV := mv
JAVAC := javac
@@ -48,6 +48,9 @@
$(MKDIR) -p $(BUILD_TOOLS_JDK_DIR)
$(JAVAC) -d $(BUILD_TOOLS_JDK_DIR) $(SPP_SRC)
+ExecuteWithLog = $(2) | tee -a $(1)
+
+MakeTargetDir = mkdir -p $(dir $@)
# Define variables only needed for GensrcCharsetEncoder.gmk
GENSRC_CHARSETCODER_SRC := $(ANDROID_BUILD_TOP)/libcore/ojluni/src/main/java/java/nio
diff --git a/ojluni/src/tools/make/gensrc/GensrcCharsetCoder.gmk b/ojluni/src/tools/make/gensrc/GensrcCharsetCoder.gmk
index 3de6404..17fddda 100644
--- a/ojluni/src/tools/make/gensrc/GensrcCharsetCoder.gmk
+++ b/ojluni/src/tools/make/gensrc/GensrcCharsetCoder.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2020, 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
@@ -35,9 +35,10 @@
################################################################################
$(GENSRC_CHARSETCODER_DST)/CharsetDecoder.java: $(GENSRC_CHARSETCODER_TEMPLATE)
- $(MKDIR) -p $(@D)
- -$(RM) $@.tmp
- $(TOOL_SPP) < $< >$@.tmp \
+ $(call MakeTargetDir)
+ $(RM) $@.tmp
+ $(call ExecuteWithLog, $(SUPPORT_OUTPUTDIR)/gensrc/java.base/_charset_decoder, \
+ $(TOOL_SPP) -i$< -o$@.tmp \
-Kdecoder \
-DA='A' \
-Da='a' \
@@ -62,7 +63,7 @@
-DItypesPerOtype='CharsPerByte' \
-DnotLegal='not legal for this charset' \
-Dotypes-per-itype='chars-per-byte' \
- -DoutSequence='Unicode character'
+ -DoutSequence='Unicode character')
$(MV) $@.tmp $@
GENSRC_CHARSETCODER += $(GENSRC_CHARSETCODER_DST)/CharsetDecoder.java
@@ -70,9 +71,10 @@
################################################################################
$(GENSRC_CHARSETCODER_DST)/CharsetEncoder.java: $(GENSRC_CHARSETCODER_TEMPLATE)
- $(MKDIR) -p $(@D)
- -$(RM) $@.tmp
- $(TOOL_SPP) < $< >$@.tmp \
+ $(call MakeTargetDir)
+ $(RM) $@.tmp
+ $(call ExecuteWithLog, $(SUPPORT_OUTPUTDIR)/gensrc/java.base/_charset_encoder, \
+ $(TOOL_SPP) -i$< -o$@.tmp \
-Kencoder \
-DA='An' \
-Da='an' \
@@ -97,12 +99,13 @@
-DItypesPerOtype='BytesPerChar' \
-DnotLegal='not a legal sixteen-bit Unicode sequence' \
-Dotypes-per-itype='bytes-per-char' \
- -DoutSequence='byte sequence in the given charset'
+ -DoutSequence='byte sequence in the given charset')
$(MV) $@.tmp $@
GENSRC_CHARSETCODER += $(GENSRC_CHARSETCODER_DST)/CharsetEncoder.java
-GENSRC_JAVA_BASE += $(GENSRC_CHARSETCODER)
################################################################################
$(GENSRC_CHARSETCODER): $(BUILD_TOOLS_JDK)
+
+TARGETS += $(GENSRC_CHARSETCODER)
diff --git a/ojluni/src/tools/scripts/addNotices.sh b/ojluni/src/tools/scripts/addNotices.sh
index 6e0cdf9..d986481 100755
--- a/ojluni/src/tools/scripts/addNotices.sh
+++ b/ojluni/src/tools/scripts/addNotices.sh
@@ -1,6 +1,6 @@
#! /bin/sh
#
-# Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2007, 2020, 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
@@ -40,6 +40,6 @@
__END__
fi
-$NAWK ' /^#.*Copyright.*Oracle/ { next }
+$AWK ' /^#.*Copyright.*Oracle/ { next }
/^#([^!]|$)/ { sub(/^#/, " *"); print }
/^$/ { print " */"; exit } ' $0
diff --git a/ojluni/src/tools/scripts/genExceptions.sh b/ojluni/src/tools/scripts/genExceptions.sh
index 66ef805..4f6c0d9 100755
--- a/ojluni/src/tools/scripts/genExceptions.sh
+++ b/ojluni/src/tools/scripts/genExceptions.sh
@@ -1,6 +1,6 @@
#! /bin/sh
#
-# Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2000, 2021, 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
@@ -60,6 +60,7 @@
extends ${SUPER}
{
+ @java.io.Serial
private static final long serialVersionUID = $SVUID;
__END__
@@ -67,6 +68,9 @@
cat >>$out <<__END__
+ /**
+ * The $ARG_PHRASE.
+ */
private $ARG_TYPE $ARG_ID;
/**
diff --git a/openjdk_java_files.bp b/openjdk_java_files.bp
index 36d03b7..ab546c2 100644
--- a/openjdk_java_files.bp
+++ b/openjdk_java_files.bp
@@ -183,6 +183,7 @@
"ojluni/src/main/java/java/lang/ProcessImpl.java",
"ojluni/src/main/java/java/lang/Process.java",
"ojluni/src/main/java/java/lang/Readable.java",
+ "ojluni/src/main/java/java/lang/Record.java",
"ojluni/src/main/java/java/lang/package-info.java",
"ojluni/src/main/java/java/lang/reflect/AccessibleObject.java",
"ojluni/src/main/java/java/lang/reflect/AnnotatedElement.java",
@@ -204,6 +205,7 @@
"ojluni/src/main/java/java/lang/reflect/Parameter.java",
"ojluni/src/main/java/java/lang/reflect/ParameterizedType.java",
"ojluni/src/main/java/java/lang/reflect/Proxy.java",
+ "ojluni/src/main/java/java/lang/reflect/RecordComponent.java",
"ojluni/src/main/java/java/lang/reflect/ReflectPermission.java",
"ojluni/src/main/java/java/lang/reflect/Type.java",
"ojluni/src/main/java/java/lang/reflect/TypeVariable.java",
@@ -218,6 +220,8 @@
"ojluni/src/main/java/java/lang/ref/SoftReference.java",
"ojluni/src/main/java/java/lang/ref/WeakReference.java",
"ojluni/src/main/java/java/lang/ref/package-info.java",
+ "ojluni/src/main/java/java/lang/runtime/ObjectMethods.java",
+ "ojluni/src/main/java/java/lang/runtime/package-info.java",
"ojluni/src/main/java/java/lang/Runnable.java",
"ojluni/src/main/java/java/lang/RuntimeException.java",
"ojluni/src/main/java/java/lang/Runtime.java",
@@ -268,6 +272,7 @@
"ojluni/src/main/java/java/lang/invoke/MutableCallSite.java",
"ojluni/src/main/java/java/lang/invoke/Stable.java",
"ojluni/src/main/java/java/lang/invoke/Transformers.java",
+ "ojluni/src/main/java/java/lang/invoke/TypeDescriptor.java",
"ojluni/src/main/java/java/lang/invoke/VarHandle.java",
"ojluni/src/main/java/java/lang/invoke/VolatileCallSite.java",
"ojluni/src/main/java/java/lang/invoke/WrongMethodTypeException.java",
@@ -1462,17 +1467,42 @@
"ojluni/src/main/java/com/sun/nio/file/ExtendedWatchEventModifier.java",
"ojluni/src/main/java/com/sun/nio/file/SensitivityWatchEventModifier.java",
"ojluni/src/main/java/java/beans/ChangeListenerMap.java",
+ // Hide the java.lang.constant APIs until master switches away from Android UDC. b/270028670
+ "ojluni/src/main/java/java/lang/invoke/ConstantBootstraps.java",
+ "ojluni/src/main/java/java/lang/constant/AsTypeMethodHandleDesc.java",
+ "ojluni/src/main/java/java/lang/constant/ClassDesc.java",
+ "ojluni/src/main/java/java/lang/constant/Constable.java",
+ "ojluni/src/main/java/java/lang/constant/ConstantDesc.java",
+ "ojluni/src/main/java/java/lang/constant/ConstantDescs.java",
+ "ojluni/src/main/java/java/lang/constant/ConstantUtils.java",
+ "ojluni/src/main/java/java/lang/constant/DirectMethodHandleDesc.java",
+ "ojluni/src/main/java/java/lang/constant/DirectMethodHandleDescImpl.java",
+ "ojluni/src/main/java/java/lang/constant/DynamicCallSiteDesc.java",
+ "ojluni/src/main/java/java/lang/constant/DynamicConstantDesc.java",
+ "ojluni/src/main/java/java/lang/constant/MethodHandleDesc.java",
+ "ojluni/src/main/java/java/lang/constant/MethodTypeDesc.java",
+ "ojluni/src/main/java/java/lang/constant/MethodTypeDescImpl.java",
+ "ojluni/src/main/java/java/lang/constant/PrimitiveClassDescImpl.java",
+ "ojluni/src/main/java/java/lang/constant/ReferenceClassDescImpl.java",
+ "ojluni/src/main/java/java/lang/constant/package-info.java",
+ "ojluni/src/main/java/java/security/DrbgParameters.java",
+ "ojluni/src/main/java/java/security/SecureRandomParameters.java",
+ "ojluni/src/main/java/java/security/spec/DSAGenParameterSpec.java",
+ "ojluni/src/main/java/java/security/spec/EdDSAParameterSpec.java",
"ojluni/src/main/java/java/time/zone/IcuZoneRulesProvider.java",
"ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java",
"ojluni/src/main/java/java/util/ImmutableCollections.java",
"ojluni/src/main/java/java/util/LocaleISOData.java",
"ojluni/src/main/java/java/util/KeyValueHolder.java",
"ojluni/src/main/java/java/util/JapaneseImperialCalendar.java",
+ "ojluni/src/main/java/javax/crypto/spec/ChaCha20ParameterSpec.java",
+ "ojluni/src/main/java/javax/security/auth/x500/X500PrivateCredential.java",
"ojluni/src/main/java/jdk/net/ExtendedSocketOptions.java",
"ojluni/src/main/java/jdk/net/NetworkPermission.java",
"ojluni/src/main/java/jdk/net/SocketFlow.java",
"ojluni/src/main/java/jdk/net/Sockets.java",
"ojluni/src/main/java/jdk/internal/HotSpotIntrinsicCandidate.java",
+ "ojluni/src/main/java/jdk/internal/ValueBased.java",
"ojluni/src/main/java/jdk/internal/misc/InnocuousThread.java",
"ojluni/src/main/java/jdk/internal/misc/JavaIOFileDescriptorAccess.java",
"ojluni/src/main/java/jdk/internal/misc/JavaObjectInputStreamAccess.java",
diff --git a/tools/checkstyle/libcore-checkstyle.sh b/tools/checkstyle/libcore-checkstyle.sh
index e85bf67..78faf01 100755
--- a/tools/checkstyle/libcore-checkstyle.sh
+++ b/tools/checkstyle/libcore-checkstyle.sh
@@ -30,6 +30,7 @@
[luni/src/test/dex_src/libcore]=tools/checkstyle/aosp-copyright.xml
[luni/src/test/etc]=tools/checkstyle/aosp-copyright.xml
[luni/src/test/filesystems]=tools/checkstyle/aosp-copyright.xml
+ [luni/src/test/java/crossvmtest]=tools/checkstyle/aosp-copyright.xml
[luni/src/test/java/libcore/android]=tools/checkstyle/aosp-copyright.xml
[luni/src/test/java/libcore/build]=tools/checkstyle/aosp-copyright.xml
[luni/src/test/java/libcore/dalvik/system]=tools/checkstyle/aosp-copyright.xml
@@ -46,12 +47,14 @@
[luni/src/test/java/org/apache/harmony]=tools/checkstyle/not-gpl.xml
[luni/src/test/java/tests/com/android/org]=tools/checkstyle/aosp-copyright.xml
[luni/src/test/java/tests/java/lang]=tools/checkstyle/aosp-copyright.xml
+ [luni/src/test/java/tests/java/nio]=tools/checkstyle/aosp-copyright.xml
[luni/src/test/java/tests/java/security]=tools/checkstyle/asf-copyright.xml
[luni/src/test/java/tests/java/sql]=tools/checkstyle/aosp-copyright.xml
[luni/src/test/java/tests/org/w3c]=tools/checkstyle/w3c-copyright.xml
[luni/src/test/java/tests/security]=tools/checkstyle/not-gpl.xml
[luni/src/test/java/tests/support]=tools/checkstyle/aosp-copyright.xml
[luni/src/test/java/tests/targets]=tools/checkstyle/aosp-copyright.xml
+ [luni/src/test/java17language]=tools/checkstyle/aosp-copyright.xml
[luni/src/test/java11language]=tools/checkstyle/aosp-copyright.xml
[luni/src/test/java9compatibility]=tools/checkstyle/aosp-copyright.xml
[luni/src/test/java9language]=tools/checkstyle/aosp-copyright.xml
diff --git a/tools/checkstyle/ojluni-src-test-header.xml b/tools/checkstyle/ojluni-src-test-header.xml
index 9083b10..a63a013 100644
--- a/tools/checkstyle/ojluni-src-test-header.xml
+++ b/tools/checkstyle/ojluni-src-test-header.xml
@@ -40,6 +40,15 @@
<property name="fileNamePattern"
value="ojluni/src/test/java/security/Provider/ProvidersTest.java" />
</module>
+ <!--
+ puppycrawl fails to parse the Record type implementing Serializable, and the code valid in Java 17.
+ libcore/ojluni/src/test/java/lang/reflect/records/RecordReflectionTest.java:55:39: unexpected token: implements
+ libcore/ojluni/src/test/java/lang/reflect/records/RecordReflectionTest.java:63:12: unexpected token: void
+ -->
+ <module name="BeforeExecutionExclusionFileFilter">
+ <property name="fileNamePattern"
+ value="ojluni/src/test/java/lang/reflect/records/RecordReflectionTest.java" />
+ </module>
<module name="TreeWalker">
<module name="RegexpSinglelineJava">
diff --git a/tools/openjdk-analyzer/src/libcore/tools/analyzer/openjdk/unsupported_new_apis.txt b/tools/openjdk-analyzer/src/libcore/tools/analyzer/openjdk/unsupported_new_apis.txt
index 14eb9cf..a9eb97a 100644
--- a/tools/openjdk-analyzer/src/libcore/tools/analyzer/openjdk/unsupported_new_apis.txt
+++ b/tools/openjdk-analyzer/src/libcore/tools/analyzer/openjdk/unsupported_new_apis.txt
@@ -12,7 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# See UnsupportedNewApis.contains() for the API signature format
+# List of APIs not supported by libcore.
+# This list doesn't block anyone to add the APIs into libcore, but the APIs are not shown
+# during API analysis by libcore-openjdk-analyzer.
+# See UnsupportedNewApis.java for the API signature format
# Android doesn't support java.lang.Module system.
java/lang/LayerInstantiationException
@@ -29,14 +32,17 @@
java/lang/module/ResolvedModule
java/lang/Class#forName(Ljava/lang/Module;Ljava/lang/String;)Ljava/lang/Class;
java/lang/Class#getModule()Ljava/lang/Module;
+java/lang/ClassLoader#findClass(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;
+java/lang/ClassLoader#findResource(Ljava/lang/String;Ljava/lang/String;)Ljava/net/URL;
java/lang/ClassLoader#getUnnamedModule()Ljava/lang/Module;
+java/lang/StackTraceElement#<init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V
java/lang/StackTraceElement#getModuleName()Ljava/lang/String;
java/lang/StackTraceElement#getModuleVersion()Ljava/lang/String;
java/util/ResourceBundle#getBundle(Ljava/lang/String;Ljava/lang/Module;)Ljava/util/ResourceBundle;
java/util/ResourceBundle#getBundle(Ljava/lang/String;Ljava/util/Locale;Ljava/lang/Module;)Ljava/util/ResourceBundle;
java/util/ServiceLoader#load(Ljava/lang/ModuleLayer;Ljava/lang/Class;)Ljava/util/ServiceLoader;
-# Android doesn't support the following i18n SPI because the i18n stack is closely
+# libcore doesn't support the following i18n SPI because the i18n stack is closely
# integrated with ICU.
java/text/spi/BreakIteratorProvider
java/text/spi/CollatorProvider
@@ -50,3 +56,122 @@
java/util/spi/LocaleNameProvider
java/util/spi/LocaleServiceProvider
java/util/spi/TimeZoneNameProvider
+
+# libcore doesn't support Type annotation reflection APIs since Android O. http://b/30391692
+java/lang/reflect/AnnotatedArrayType
+java/lang/reflect/AnnotatedParameterizedType
+java/lang/reflect/AnnotatedType
+java/lang/reflect/AnnotatedTypeVariable
+java/lang/reflect/AnnotatedWildcardType
+java/lang/Class#getAnnotatedInterfaces()[Ljava/lang/reflect/AnnotatedType;
+java/lang/Class#getAnnotatedSuperclass()Ljava/lang/reflect/AnnotatedType;
+java/lang/reflect/Constructor#getAnnotatedReceiverType()Ljava/lang/reflect/AnnotatedType;
+java/lang/reflect/Constructor#getAnnotatedReturnType()Ljava/lang/reflect/AnnotatedType;
+java/lang/reflect/Executable#getAnnotatedExceptionTypes()[Ljava/lang/reflect/AnnotatedType;
+java/lang/reflect/Executable#getAnnotatedParameterTypes()[Ljava/lang/reflect/AnnotatedType;
+java/lang/reflect/Executable#getAnnotatedReceiverType()Ljava/lang/reflect/AnnotatedType;
+java/lang/reflect/Executable#getAnnotatedReturnType()Ljava/lang/reflect/AnnotatedType;
+java/lang/reflect/Field#getAnnotatedType()Ljava/lang/reflect/AnnotatedType;
+java/lang/reflect/Method#getAnnotatedReturnType()Ljava/lang/reflect/AnnotatedType;
+java/lang/reflect/Parameter#getAnnotatedType()Ljava/lang/reflect/AnnotatedType;
+java/lang/reflect/TypeVariable#getAnnotatedBounds()[Ljava/lang/reflect/AnnotatedType;
+
+# Please use android.icu.text.CompactDecimalFormat available since Android N. http://b/262705909
+# This CompactDecimalFormat uses the same LDML TR-35 spec. It's better using the ICU one
+# when the spec and implementation are written and maintained consistently.
+java/text/CompactNumberFormat
+java/text/NumberFormat#getCompactNumberInstance()Ljava/text/NumberFormat;
+java/text/NumberFormat#getCompactNumberInstance(Ljava/util/Locale;Ljava/text/NumberFormat$Style;)Ljava/text/NumberFormat;
+java/text/NumberFormat$Style#LONG:Ljava/text/NumberFormat$Style;
+java/text/NumberFormat$Style#SHORT:Ljava/text/NumberFormat$Style;
+java/text/NumberFormat$Style#valueOf(Ljava/lang/String;)Ljava/text/NumberFormat$Style;
+java/text/NumberFormat$Style#values()[Ljava/text/NumberFormat$Style;
+
+# Android doesn't support SecurityManager.
+java/io/FilePermission#equals(Ljava/lang/Object;)Z
+java/io/FilePermission#hashCode()I
+java/io/FilePermission#newPermissionCollection()Ljava/security/PermissionCollection;
+java/net/SocketPermission#equals(Ljava/lang/Object;)Z
+java/net/SocketPermission#hashCode()I
+java/net/SocketPermission#newPermissionCollection()Ljava/security/PermissionCollection;
+java/net/URLPermission
+java/security/AccessControlContext#equals(Ljava/lang/Object;)Z
+java/security/AccessControlContext#hashCode()I
+java/security/AccessController#doPrivileged(Ljava/security/PrivilegedExceptionAction;Ljava/security/AccessControlContext;[Ljava/security/Permission;)Ljava/lang/Object;
+java/security/AccessController#doPrivilegedWithCombiner(Ljava/security/PrivilegedAction;Ljava/security/AccessControlContext;[Ljava/security/Permission;)Ljava/lang/Object;
+java/security/AccessController#doPrivilegedWithCombiner(Ljava/security/PrivilegedExceptionAction;Ljava/security/AccessControlContext;[Ljava/security/Permission;)Ljava/lang/Object;
+java/security/AllPermission#equals(Ljava/lang/Object;)Z
+java/security/AllPermission#hashCode()I
+java/security/AllPermission#newPermissionCollection()Ljava/security/PermissionCollection;
+java/security/AuthProvider#<init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+java/security/BasicPermission#equals(Ljava/lang/Object;)Z
+java/security/BasicPermission#hashCode()I
+java/security/BasicPermission#newPermissionCollection()Ljava/security/PermissionCollection;
+java/security/CodeSource#equals(Ljava/lang/Object;)Z
+java/security/CodeSource#hashCode()I
+java/security/CodeSource#toString()Ljava/lang/String;
+java/security/Permission#equals(Ljava/lang/Object;)Z
+java/security/Permission#hashCode()I
+java/security/Permission#toString()Ljava/lang/String;
+java/security/PermissionCollection#elementsAsStream()Ljava/util/stream/Stream;
+java/security/PermissionCollection#toString()Ljava/lang/String;
+java/security/ProtectionDomain#staticPermissionsOnly()Z
+java/security/ProtectionDomain#toString()Ljava/lang/String;
+java/security/UnresolvedPermission#equals(Ljava/lang/Object;)Z
+java/security/UnresolvedPermission#hashCode()I
+java/security/UnresolvedPermission#newPermissionCollection()Ljava/security/PermissionCollection;
+java/security/UnresolvedPermission#toString()Ljava/lang/String;
+java/security/URIParameter
+java/util/PropertyPermission#equals(Ljava/lang/Object;)Z
+java/util/PropertyPermission#getActions()Ljava/lang/String;
+java/util/PropertyPermission#hashCode()I
+java/util/PropertyPermission#implies(Ljava/security/Permission;)Z
+java/util/PropertyPermission#newPermissionCollection()Ljava/security/PermissionCollection;
+
+# Only a limited set of javax.security.auth.login APIs are supported due to KeyStore.
+# The rest of APIs are not supported.
+javax/security/auth/RefreshFailedException
+javax/security/auth/Refreshable
+javax/security/auth/callback/ChoiceCallback
+javax/security/auth/callback/ConfirmationCallback
+javax/security/auth/callback/LanguageCallback
+javax/security/auth/callback/NameCallback
+javax/security/auth/callback/TextInputCallback
+javax/security/auth/callback/TextOutputCallback
+javax/security/auth/login/AccountException
+javax/security/auth/login/AccountExpiredException
+javax/security/auth/login/AccountLockedException
+javax/security/auth/login/AccountNotFoundException
+javax/security/auth/login/AppConfigurationEntry
+javax/security/auth/login/AppConfigurationEntry$LoginModuleControlFlag
+javax/security/auth/login/Configuration
+javax/security/auth/login/Configuration$Parameters
+javax/security/auth/login/ConfigurationSpi
+javax/security/auth/login/CredentialException
+javax/security/auth/login/CredentialExpiredException
+javax/security/auth/login/CredentialNotFoundException
+javax/security/auth/login/FailedLoginException
+javax/security/auth/login/LoginContext
+javax/security/auth/spi/LoginModule
+javax/security/auth/PrivateCredentialPermission#equals(Ljava/lang/Object;)Z
+javax/security/auth/PrivateCredentialPermission#hashCode()I
+javax/security/auth/PrivateCredentialPermission#newPermissionCollection()Ljava/security/PermissionCollection;
+
+# libcore doesn't intend to support loading resources not in classloader.
+java/util/spi/AbstractResourceBundleProvider
+java/util/spi/ResourceBundleControlProvider
+java/util/spi/ResourceBundleProvider
+
+# libcore doesn't need a provider of compiler / documentation tool on device.
+java/util/spi/ToolProvider
+
+# Neither Runtime$Version nor multi-release JARs are applicable to Android.
+java/lang/Runtime$Version
+java/lang/Runtime#version()Ljava/lang/Runtime$Version;
+java/util/jar/Attributes$Name#MULTI_RELEASE:Ljava/util/jar/Attributes$Name;
+java/util/jar/JarFile#<init>(Ljava/io/File;ZILjava/lang/Runtime$Version;)V
+java/util/jar/JarFile#baseVersion()Ljava/lang/Runtime$Version;
+java/util/jar/JarFile#getVersion()Ljava/lang/Runtime$Version;
+java/util/jar/JarFile#isMultiRelease()Z
+java/util/jar/JarFile#runtimeVersion()Ljava/lang/Runtime$Version;
+java/util/jar/JarFile#versionedStream()Ljava/util/stream/Stream;