Hi Adam The only behavior change is with the debug output, right?
Is this a new pattern that internal optional fields should be defined as an Optional? And, when there is no provider the string form "from: " looks strange, I would rather make it "from nowhere". I would also move the space before "from" to where the method is called, say, " verification algorithm " + getProvidedByString(). Thanks Max > On Dec 13, 2016, at 4:05 AM, Adam Petcher <adam.petc...@oracle.com> wrote: > > Okay. I changed getProvider() to return this.provider.orElse(null), which > will allow this method to return null. For consistency, I allow all other > providers (in Instance and Service) to be null using Optional.ofNullable(). > Hopefully, I found and fixed all the whitespace issues, too. Here is the > corrected diff: > > diff --git a/src/java.base/share/classes/java/security/Signature.java > b/src/java.base/share/classes/java/security/Signature.java > --- a/src/java.base/share/classes/java/security/Signature.java > +++ b/src/java.base/share/classes/java/security/Signature.java > @@ -134,7 +134,7 @@ > private String algorithm; > > // The provider > - Provider provider; > + Optional<Provider> provider = Optional.empty(); > > /** > * Possible {@link #state} value, signifying that > @@ -266,7 +266,7 @@ > SignatureSpi spi = (SignatureSpi)instance.impl; > sig = new Delegate(spi, algorithm); > } > - sig.provider = instance.provider; > + sig.provider = Optional.ofNullable(instance.provider); > return sig; > } > > @@ -449,13 +449,17 @@ > */ > public final Provider getProvider() { > chooseFirstProvider(); > - return this.provider; > + return this.provider.orElse(null); > } > > void chooseFirstProvider() { > // empty, overridden in Delegate > } > > + private String getProvidedByString() { > + return provider.map(x -> " from: " + x.getName()).orElse(""); > + } > + > /** > * Initializes this object for verification. If this method is called > * again with a different argument, it negates the effect > @@ -473,7 +477,7 @@ > > if (!skipDebug && pdebug != null) { > pdebug.println("Signature." + algorithm + > - " verification algorithm from: " + this.provider.getName()); > + " verification algorithm" + getProvidedByString()); > } > } > > @@ -522,7 +526,7 @@ > > if (!skipDebug && pdebug != null) { > pdebug.println("Signature." + algorithm + > - " verification algorithm from: " + this.provider.getName()); > + " verification algorithm" + getProvidedByString()); > } > } > > @@ -543,7 +547,7 @@ > > if (!skipDebug && pdebug != null) { > pdebug.println("Signature." + algorithm + > - " signing algorithm from: " + this.provider.getName()); > + " signing algorithm" + getProvidedByString()); > } > } > > @@ -566,7 +570,7 @@ > > if (!skipDebug && pdebug != null) { > pdebug.println("Signature." + algorithm + > - " signing algorithm from: " + this.provider.getName()); > + " signing algorithm" + getProvidedByString()); > } > } > > @@ -1087,7 +1091,7 @@ > } > try { > sigSpi = newInstance(s); > - provider = s.getProvider(); > + provider = Optional.ofNullable(s.getProvider()); > // not needed any more > firstService = null; > serviceIterator = null; > @@ -1132,7 +1136,7 @@ > try { > SignatureSpi spi = newInstance(s); > init(spi, type, key, random); > - provider = s.getProvider(); > + provider = Optional.ofNullable(s.getProvider()); > sigSpi = spi; > firstService = null; > serviceIterator = null; > diff --git a/test/java/security/Signature/NoProvider.java > b/test/java/security/Signature/NoProvider.java > new file mode 100644 > --- /dev/null > +++ b/test/java/security/Signature/NoProvider.java > @@ -0,0 +1,99 @@ > +/* > + * 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. > + * > + * 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 8165751 > + * @summary Verify that that a subclass of Signature that does not contain a > + * provider can be used verify. > + * @run main/othervm -Djava.security.debug=provider NoProvider > + */ > + > +import java.security.*; > + > +public class NoProvider { > + > + private static class NoProviderPublicKey implements PublicKey { > + > + public String getAlgorithm() { > + return "NoProvider"; > + } > + public String getFormat() { > + return "none"; > + } > + public byte[] getEncoded() { > + return new byte[1]; > + } > + } > + > + private static class NoProviderSignature extends Signature { > + > + public NoProviderSignature() { > + super("NoProvider"); > + } > + > + protected void engineInitVerify(PublicKey publicKey) > + throws InvalidKeyException { > + // do nothing > + } > + > + protected void engineInitSign(PrivateKey privateKey) > + throws InvalidKeyException { > + // do nothing > + } > + > + protected void engineUpdate(byte b) throws SignatureException { > + // do nothing > + } > + > + protected void engineUpdate(byte[] b, int off, int len) > + throws SignatureException { > + // do nothing > + } > + > + protected byte[] engineSign() throws SignatureException { > + return new byte[1]; > + } > + > + protected boolean engineVerify(byte[] sigBytes) > + throws SignatureException { > + return false; > + } > + > + @Deprecated > + protected void engineSetParameter(String param, Object value) > + throws InvalidParameterException { > + // do nothing > + } > + > + @Deprecated > + protected Object engineGetParameter(String param) > + throws InvalidParameterException { > + return null; > + } > + } > + > + public static void main(String[] args) throws Exception { > + new NoProviderSignature().initVerify(new NoProviderPublicKey()); > + } > +} > > > On 12/12/2016 1:44 PM, Sean Mullan wrote: >> On 12/8/16 11:17 AM, Adam Petcher wrote: >>> >>> Subclasses of Signature may have a null provider. In this case, the >>> debug logging code will throw a NPE when attempting to call getName() on >>> it. Since this member may be null, I would like to change its type to >>> Optional to ensure that code checks whether it is present before using >>> it. I have assumed that getProvider() methods (in both Signature and >>> Service) always return non-null---if this assumption is incorrect, then >>> I'll need to change some of the uses of Optional in/around these methods. >> >> I think we would want to preserve the current behavior of getProvider >> returning null for one of these subclasses (even though it isn't specified >> that null is an acceptable return value). Better to be safe here, otherwise >> NoSuchElementException would be thrown which would be unexpected and not >> specified by getProvider. >> >> Other than that, just a minor style comment on a few lines of the test: >> >> > + private static class NoProviderPublicKey implements PublicKey{ >> >> space before "{" >> >> --Sean >> >>> Note that this issue of missing null checks for providers exists in >>> several classes (e.g. Cipher, MessageDigest). Once this patch is >>> reviewed and committed, I will apply the same solution to all other >>> affected classes. >>> >>> Bug: https://bugs.openjdk.java.net/browse/JDK-8165751 >>> >>> Diff: >>> >>> diff --git a/src/java.base/share/classes/java/security/Signature.java >>> b/src/java.base/share/classes/java/security/Signature.java >>> --- a/src/java.base/share/classes/java/security/Signature.java >>> +++ b/src/java.base/share/classes/java/security/Signature.java >>> @@ -134,7 +134,7 @@ >>> private String algorithm; >>> >>> // The provider >>> - Provider provider; >>> + Optional<Provider> provider = Optional.empty(); >>> >>> /** >>> * Possible {@link #state} value, signifying that >>> @@ -266,7 +266,7 @@ >>> SignatureSpi spi = (SignatureSpi)instance.impl; >>> sig = new Delegate(spi, algorithm); >>> } >>> - sig.provider = instance.provider; >>> + sig.provider = Optional.of(instance.provider); >>> return sig; >>> } >>> >>> @@ -449,13 +449,17 @@ >>> */ >>> public final Provider getProvider() { >>> chooseFirstProvider(); >>> - return this.provider; >>> + return this.provider.get(); >>> } >>> >>> void chooseFirstProvider() { >>> // empty, overridden in Delegate >>> } >>> >>> + private String getProvidedByString(){ >>> + return provider.map(x -> " from: " + x.getName()).orElse(""); >>> + } >>> + >>> /** >>> * Initializes this object for verification. If this method is called >>> * again with a different argument, it negates the effect >>> @@ -473,7 +477,7 @@ >>> >>> if (!skipDebug && pdebug != null) { >>> pdebug.println("Signature." + algorithm + >>> - " verification algorithm from: " + >>> this.provider.getName()); >>> + " verification algorithm" + getProvidedByString()); >>> } >>> } >>> >>> @@ -522,7 +526,7 @@ >>> >>> if (!skipDebug && pdebug != null) { >>> pdebug.println("Signature." + algorithm + >>> - " verification algorithm from: " + >>> this.provider.getName()); >>> + " verification algorithm" + getProvidedByString()); >>> } >>> } >>> >>> @@ -543,7 +547,7 @@ >>> >>> if (!skipDebug && pdebug != null) { >>> pdebug.println("Signature." + algorithm + >>> - " signing algorithm from: " + this.provider.getName()); >>> + " signing algorithm" + getProvidedByString()); >>> } >>> } >>> >>> @@ -566,7 +570,7 @@ >>> >>> if (!skipDebug && pdebug != null) { >>> pdebug.println("Signature." + algorithm + >>> - " signing algorithm from: " + this.provider.getName()); >>> + " signing algorithm" + getProvidedByString()); >>> } >>> } >>> >>> @@ -1087,7 +1091,7 @@ >>> } >>> try { >>> sigSpi = newInstance(s); >>> - provider = s.getProvider(); >>> + provider = Optional.of(s.getProvider()); >>> // not needed any more >>> firstService = null; >>> serviceIterator = null; >>> @@ -1132,7 +1136,7 @@ >>> try { >>> SignatureSpi spi = newInstance(s); >>> init(spi, type, key, random); >>> - provider = s.getProvider(); >>> + provider = Optional.of(s.getProvider()); >>> sigSpi = spi; >>> firstService = null; >>> serviceIterator = null; >>> diff --git a/test/java/security/Signature/NoProvider.java >>> b/test/java/security/Signature/NoProvider.java >>> new file mode 100644 >>> --- /dev/null >>> +++ b/test/java/security/Signature/NoProvider.java >>> @@ -0,0 +1,99 @@ >>> +/* >>> + * 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. >>> + * >>> + * 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 8165751 >>> + * @summary Verify that that a subclass of Signature that does not >>> contain a >>> + * provider can be used verify. >>> + * @run main/othervm -Djava.security.debug=provider NoProvider >>> + */ >>> + >>> +import java.security.*; >>> + >>> +public class NoProvider { >>> + >>> + private static class NoProviderPublicKey implements PublicKey{ >>> + public String getAlgorithm(){ >>> + return "NoProvider"; >>> + } >>> + public String getFormat(){ >>> + return "none"; >>> + } >>> + public byte[] getEncoded(){ >>> + return new byte[1]; >>> + } >>> + } >>> + >>> + private static class NoProviderSignature extends Signature{ >>> + >>> + public NoProviderSignature(){ >>> + super("NoProvider"); >>> + } >>> + >>> + protected void engineInitVerify(PublicKey publicKey) >>> + throws InvalidKeyException{ >>> + // do nothing >>> + } >>> + >>> + protected void engineInitSign(PrivateKey privateKey) >>> + throws InvalidKeyException{ >>> + // do nothing >>> + } >>> + >>> + protected void engineUpdate(byte b) throws SignatureException{ >>> + // do nothing >>> + } >>> + >>> + protected void engineUpdate(byte[] b, int off, int len) >>> + throws SignatureException{ >>> + // do nothing >>> + } >>> + >>> + protected byte[] engineSign() throws SignatureException{ >>> + return new byte[1]; >>> + } >>> + >>> + protected boolean engineVerify(byte[] sigBytes) >>> + throws SignatureException{ >>> + return false; >>> + } >>> + >>> + @Deprecated >>> + protected void engineSetParameter(String param, Object value) >>> + throws InvalidParameterException{ >>> + // do nothing >>> + } >>> + >>> + @Deprecated >>> + protected Object engineGetParameter(String param) >>> + throws InvalidParameterException{ >>> + return null; >>> + } >>> + >>> + } >>> + >>> + public static void main(String[] args) throws Exception { >>> + new NoProviderSignature().initVerify(new NoProviderPublicKey()); >>> + } >>> +} >