This is an automated email from the ASF dual-hosted git repository. jamesbognar pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/juneau.git
commit e32f1a586793de88bcfd82b6085f18228c886065 Author: James Bognar <[email protected]> AuthorDate: Thu Jul 23 09:13:08 2026 -0400 TODO-286: resolve null-effect doc/impl contradictions + enrich ambiguous sites Triage of 36 flagged sites from the TODO-265 null-effect sweep: - DOC-FIX (behavior-preserving) where the Javadoc contradicted traced reality: BidiMap null-handling, BasicMediaTypeHeader "never null", and must-not-be-null NPE docs on IfRange.isEtag, UrlPathMatch, MethodExecStats. - CODE-FIX (10.0.0 behavior change): make the fluent request/response header/param/form assertions null-tolerant so asserting on an absent value no longer NPEs; adds null-value test coverage. - Enrich the genuinely implementation-dependent Group 2 sites with the TODO-265 convention pointing at the relevant {@link} target; setContent() reuses the existing leaf-type-dependent clause. - JsonSchemaMap left unchanged (contradiction refuted: ConcurrentHashMap rejects null keys regardless). Co-authored-by: Cursor <[email protected]> --- .../juneau/commons/bean/BeanMetaInitializer.java | 6 +-- .../apache/juneau/commons/collections/BidiMap.java | 9 ++-- .../org/apache/juneau/marshall/UriResolver.java | 8 ++-- .../marshall/httppart/BaseHttpPartParser.java | 6 +-- .../marshall/httppart/BaseHttpPartSerializer.java | 2 +- .../marshall/serializer/SerializerWriter.java | 2 +- .../apache/juneau/marshall/yaml/YamlWriter.java | 2 +- .../assertion/FluentResponseHeaderAssertion.java | 18 ++++---- .../FluentResponseHeaderAssertion_Test.java | 51 +++++++++++++++++++++ .../http/classic/entity/BasicHttpEntity.java | 2 +- .../http/classic/header/BasicMediaTypeHeader.java | 2 +- .../apache/juneau/http/classic/header/IfRange.java | 2 +- .../http/classic/header/SerializedHeader.java | 8 ++-- .../juneau/http/classic/part/PartBeanMeta.java | 4 +- .../juneau/http/classic/part/SerializedPart.java | 4 +- .../http/classic/resource/BasicResource.java | 2 +- .../http/classic/response/BasicHttpException.java | 2 +- .../http/classic/response/BasicHttpResponse.java | 2 +- .../FluentRequestFormParamAssertion.java | 18 ++++---- .../assertions/FluentRequestHeaderAssertion.java | 18 ++++---- .../FluentRequestQueryParamAssertion.java | 18 ++++---- .../juneau/rest/server/stats/MethodExecStats.java | 2 +- .../juneau/rest/server/util/UrlPathMatch.java | 2 +- .../FluentRequestFormParamAssertion_Test.java | 52 ++++++++++++++++++++++ .../FluentRequestHeaderAssertion_Test.java | 22 +++++++++ .../FluentRequestQueryParamAssertion_Test.java | 52 ++++++++++++++++++++++ 26 files changed, 247 insertions(+), 69 deletions(-) diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMetaInitializer.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMetaInitializer.java index efcb65256d..c411c95e6e 100644 --- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMetaInitializer.java +++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/bean/BeanMetaInitializer.java @@ -130,8 +130,8 @@ public interface BeanMetaInitializer { * Builds the bean-level {@link BeanRegistryLookup} for the supplied class. Returns <jk>null</jk> on the * commons-side path (no marshalling context). * - * @param marshallingContext The marshalling-side context (as an opaque {@link Object}). Can be <jk>null</jk>. - * @param beanFilter The bean filter applied to this bean meta. Can be <jk>null</jk>. + * @param marshallingContext The marshalling-side context (as an opaque {@link Object}). Can be <jk>null</jk>. The effect is implementation-dependent — see {@link org.apache.juneau.marshall.MarshalledBeanMetaInitializer}, the sole concrete implementer of this SPI. + * @param beanFilter The bean filter applied to this bean meta. Can be <jk>null</jk>. The effect is implementation-dependent — see {@link org.apache.juneau.marshall.MarshalledBeanMetaInitializer}. * @param classInfo The class info of the bean. Must not be <jk>null</jk>. * @param config The bean-modeling configuration. Must not be <jk>null</jk>. * @return The bean-level registry, or <jk>null</jk>. @@ -152,7 +152,7 @@ public interface BeanMetaInitializer { * Walks the parent classes/interfaces of {@code classInfo} and returns the first dictionary-name mapping for * {@code rawClass} found in any parent's registry, or <jk>null</jk> if none. * - * @param marshallingContext The marshalling-side context. Can be <jk>null</jk>. + * @param marshallingContext The marshalling-side context. Can be <jk>null</jk>. The effect is implementation-dependent — see {@link org.apache.juneau.marshall.MarshalledBeanMetaInitializer}. * @param classInfo The bean's class info. * @param rawClass The raw class to look up. * @return The dictionary name found in a parent's registry, or <jk>null</jk>. diff --git a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/BidiMap.java b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/BidiMap.java index 2f833b5988..9d2e4ab13d 100644 --- a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/BidiMap.java +++ b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/BidiMap.java @@ -36,7 +36,7 @@ import java.util.*; * <li>Implements the standard {@link Map} interface for forward key→value lookups * <li>Provides {@link #getKey(Object)} method for reverse value→key lookups * <li>Maintains insertion order using {@link LinkedHashMap} internally - * <li>Automatically filters out null keys and values + * <li>Filters out null keys and values when built via the {@link Builder} * <li>Supports both mutable and unmodifiable instances via the builder * <li>Thread-safety: Not thread-safe by default; external synchronization required if accessed by multiple threads * </ul> @@ -59,9 +59,10 @@ import java.util.*; * * <h5 class='section'>Null Handling:</h5> * <p> - * This map automatically filters out entries with null keys or values during construction. - * Attempting to add null keys or values via {@link #put(Object, Object)} or {@link #putAll(Map)} - * after construction will result in them being stored in the forward map but not the reverse map. + * The {@link Builder#add(Object, Object)}/{@link Builder#build()} construction path filters out entries with + * null keys or values. + * {@link #put(Object, Object)} and {@link #putAll(Map)} perform <b>no</b> null filtering after construction — + * null keys and values are stored in both the forward and reverse maps unconditionally. * * <h5 class='section'>Unmodifiable Instances:</h5> * <p class='bjava'> diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/UriResolver.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/UriResolver.java index aaaa342e61..73561797c6 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/UriResolver.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/UriResolver.java @@ -130,7 +130,7 @@ public class UriResolver { * Same as {@link #resolve(Object)} except appends result to the specified appendable. * * @param a The appendable to append the URL to. Must not be <jk>null</jk>. - * @param o The URI to convert to absolute form. Can be <jk>null</jk>. + * @param o The URI to convert to absolute form. Can be <jk>null</jk>. The effect is implementation-dependent, varying with the configured {@link UriResolution} and {@link UriRelativity}. * @return The same appendable passed in. */ @SuppressWarnings({ @@ -282,8 +282,8 @@ public class UriResolver { * String <jv>relativeUri</jv> = <jv>resolver</jv>.relativize(<js>"servlet:/"</js>, <js>"/context/servlet/path/foo"</js>); * </p> * - * @param relativeTo The URI to relativize against. Can be <jk>null</jk>. - * @param uri The URI to relativize. Can be <jk>null</jk>. + * @param relativeTo The URI to relativize against. Can be <jk>null</jk>. The effect is implementation-dependent, varying with the configured {@link UriResolution} and {@link UriRelativity}. + * @param uri The URI to relativize. Can be <jk>null</jk>. The effect is implementation-dependent, varying with the configured {@link UriResolution} and {@link UriRelativity}. * @return The relativized URI. */ public String relativize(Object relativeTo, Object uri) { @@ -297,7 +297,7 @@ public class UriResolver { * * @param uri * The URI to convert to absolute form. - * Can be <jk>null</jk>. + * Can be <jk>null</jk>. The effect is implementation-dependent, varying with the configured {@link UriResolution} and {@link UriRelativity}. * Can be any of the following: * <ul> * <li>{@link URI} diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/httppart/BaseHttpPartParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/httppart/BaseHttpPartParser.java index 4006de8088..4b70a5ba4f 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/httppart/BaseHttpPartParser.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/httppart/BaseHttpPartParser.java @@ -96,7 +96,7 @@ public abstract class BaseHttpPartParser extends MarshallingContextable implemen * <br>Can be <jk>null</jk> (will default to {@link HttpPartType#OTHER}). * @param schema * Schema information about the part. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>. The effect is implementation-dependent — see {@link HttpPartParserSession}. * <br>Not all part parsers use the schema information. * @param in The input being parsed. * <br>Can be <jk>null</jk> (will return <jk>null</jk> or use schema default if available). @@ -118,7 +118,7 @@ public abstract class BaseHttpPartParser extends MarshallingContextable implemen * <br>Can be <jk>null</jk> (will default to {@link HttpPartType#OTHER}). * @param schema * Schema information about the part. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>. The effect is implementation-dependent — see {@link HttpPartParserSession}. * <br>Not all part parsers use the schema information. * @param in The input being parsed. * <br>Can be <jk>null</jk> (will return <jk>null</jk> or use schema default if available). @@ -140,7 +140,7 @@ public abstract class BaseHttpPartParser extends MarshallingContextable implemen * <br>Can be <jk>null</jk> (will default to {@link HttpPartType#OTHER}). * @param schema * Schema information about the part. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>. The effect is implementation-dependent — see {@link HttpPartParserSession}. * <br>Not all part parsers use the schema information. * @param in The input being parsed. * <br>Can be <jk>null</jk> (will return <jk>null</jk> or use schema default if available). diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/httppart/BaseHttpPartSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/httppart/BaseHttpPartSerializer.java index bd6e738abc..58dd097cf8 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/httppart/BaseHttpPartSerializer.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/httppart/BaseHttpPartSerializer.java @@ -84,7 +84,7 @@ public abstract class BaseHttpPartSerializer extends MarshallingContextable impl * <br>Can be <jk>null</jk> (will default to {@link HttpPartType#OTHER}). * @param schema * Schema information about the part. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>. The effect is implementation-dependent — see {@link HttpPartSerializerSession}. * <br>Not all part serializers use the schema information. * @param value The value being serialized. * <br>Can be <jk>null</jk> (will return <jk>null</jk>). diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerWriter.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerWriter.java index 6ffbd1d453..07f93a019a 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerWriter.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/serializer/SerializerWriter.java @@ -235,7 +235,7 @@ public abstract class SerializerWriter<SELF extends SerializerWriter<SELF>> exte * session. * * @param value The URI to serialize. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>. The effect is implementation-dependent — see {@link UriResolver#append(Appendable, Object)}. * @return This object. */ public SELF appendUri(Object value) { diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/yaml/YamlWriter.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/yaml/YamlWriter.java index b677be3c36..668a3efa4a 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/yaml/YamlWriter.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/yaml/YamlWriter.java @@ -149,7 +149,7 @@ public class YamlWriter extends SerializerWriter<YamlWriter> { * Resolves the URI and writes it as a double-quoted YAML string. * * @param uri The URI to append to the output. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>. The effect is implementation-dependent — see {@link UriResolver#resolve(Object)}. * @return This object. */ public YamlWriter uriValue(Object uri) { diff --git a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/assertion/FluentResponseHeaderAssertion.java b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/assertion/FluentResponseHeaderAssertion.java index 7f766eec56..be3f2a0beb 100644 --- a/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/assertion/FluentResponseHeaderAssertion.java +++ b/juneau-rest/juneau-rest-client-classic/src/main/java/org/apache/juneau/rest/client/classic/assertion/FluentResponseHeaderAssertion.java @@ -138,14 +138,14 @@ public class FluentResponseHeaderAssertion<R> extends FluentStringAssertion<R> { * <br>Should be <jk>null</jk> if this is the top-level assertion. * @param value * The object being tested. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>, in which case this assertion behaves as if testing a header with no value (e.g. {@link #isNull()} passes, transform methods yield <jk>null</jk>-valued assertions). * @param returns * The object to return after a test method is called. * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be * used on the same assertion. */ public FluentResponseHeaderAssertion(Assertion creator, ResponseHeader value, R returns) { - super(creator, value.asString().orElse(null), returns); + super(creator, value == null ? null : value.asString().orElse(null), returns); this.value = value; setThrowable(BadRequest.class); } @@ -155,7 +155,7 @@ public class FluentResponseHeaderAssertion<R> extends FluentStringAssertion<R> { * * @param value * The object being tested. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>, in which case this assertion behaves as if testing a header with no value (e.g. {@link #isNull()} passes, transform methods yield <jk>null</jk>-valued assertions). * @param returns * The object to return after a test method is called. * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be @@ -174,7 +174,7 @@ public class FluentResponseHeaderAssertion<R> extends FluentStringAssertion<R> { * @throws RestCallException If value could not be parsed. */ public <T> FluentAnyAssertion<T,R> as(Class<T> type) throws RestCallException { - return new FluentAnyAssertion<>(value.as(type).orElse(null), returns()); + return new FluentAnyAssertion<>(value == null ? null : value.as(type).orElse(null), returns()); } /** @@ -189,7 +189,7 @@ public class FluentResponseHeaderAssertion<R> extends FluentStringAssertion<R> { * @throws RestCallException If value could not be parsed. */ public FluentAnyAssertion<Object,R> as(Type type, Type...args) throws RestCallException { - return new FluentAnyAssertion<>(value.as(type, args).orElse(null), returns()); + return new FluentAnyAssertion<>(value == null ? null : value.as(type, args).orElse(null), returns()); } /** @@ -199,7 +199,7 @@ public class FluentResponseHeaderAssertion<R> extends FluentStringAssertion<R> { * @throws AssertionError If object is not a boolean. */ public FluentBooleanAssertion<R> asBoolean() { - return new FluentBooleanAssertion<>(this, value.asBoolean().orElse(null), returns()); + return new FluentBooleanAssertion<>(this, value == null ? null : value.asBoolean().orElse(null), returns()); } /** @@ -209,7 +209,7 @@ public class FluentResponseHeaderAssertion<R> extends FluentStringAssertion<R> { * @throws AssertionError If object is not an integer. */ public FluentIntegerAssertion<R> asInteger() { - return new FluentIntegerAssertion<>(this, value.asInteger().orElse(null), returns()); + return new FluentIntegerAssertion<>(this, value == null ? null : value.asInteger().orElse(null), returns()); } @Override /* Overridden from FluentStringAssertion */ @@ -225,7 +225,7 @@ public class FluentResponseHeaderAssertion<R> extends FluentStringAssertion<R> { * @throws AssertionError If object is not a long. */ public FluentLongAssertion<R> asLong() { - return new FluentLongAssertion<>(this, value.asLong().orElse(null), returns()); + return new FluentLongAssertion<>(this, value == null ? null : value.asLong().orElse(null), returns()); } /** @@ -235,7 +235,7 @@ public class FluentResponseHeaderAssertion<R> extends FluentStringAssertion<R> { * @throws AssertionError If object is not a zoned-datetime. */ public FluentZonedDateTimeAssertion<R> asZonedDateTime() { - return new FluentZonedDateTimeAssertion<>(this, value.asDateHeader().asZonedDateTime().orElse(null), returns()); + return new FluentZonedDateTimeAssertion<>(this, value == null ? null : value.asDateHeader().asZonedDateTime().orElse(null), returns()); } @Override /* Overridden from Assertion */ diff --git a/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/assertion/FluentResponseHeaderAssertion_Test.java b/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/assertion/FluentResponseHeaderAssertion_Test.java new file mode 100644 index 0000000000..a136f73846 --- /dev/null +++ b/juneau-rest/juneau-rest-client-classic/src/test/java/org/apache/juneau/rest/client/classic/assertion/FluentResponseHeaderAssertion_Test.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.juneau.rest.client.classic.assertion; + +import static org.junit.jupiter.api.Assertions.*; + +import org.apache.juneau.rest.client.classic.*; +import org.junit.jupiter.api.*; + +/** + * Validates {@link FluentResponseHeaderAssertion} tolerates a null {@code value} (TODO-286 #9/#10 null-tolerance fix). + * + * <p> + * A null {@link ResponseHeader} used to NPE in both constructors ({@code value.asString()}) and in every transform + * method ({@code value.asBoolean()}, etc.). + */ +class FluentResponseHeaderAssertion_Test { + + @Test void a01_nullValue_chainedConstructor_doesNotThrow() { + var a = new FluentResponseHeaderAssertion<>(null, (ResponseHeader)null, null); + assertDoesNotThrow(a::isNull); + } + + @Test void a02_nullValue_directConstructor_doesNotThrow() { + var a = new FluentResponseHeaderAssertion<>((ResponseHeader)null, null); + assertDoesNotThrow(a::isNull); + } + + @Test void a03_nullValue_transformMethodsDoNotThrowAndYieldNull() { + var a = new FluentResponseHeaderAssertion<>((ResponseHeader)null, null); + assertDoesNotThrow(() -> a.asBoolean().isNull()); + assertDoesNotThrow(() -> a.asInteger().isNull()); + assertDoesNotThrow(() -> a.asLong().isNull()); + assertDoesNotThrow(() -> a.asZonedDateTime().isNull()); + assertDoesNotThrow(() -> a.as(String.class).isNull()); + } +} diff --git a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/entity/BasicHttpEntity.java b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/entity/BasicHttpEntity.java index 4c6043417d..f6eea6e254 100644 --- a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/entity/BasicHttpEntity.java +++ b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/entity/BasicHttpEntity.java @@ -293,7 +293,7 @@ public abstract class BasicHttpEntity<SELF extends BasicHttpEntity<SELF>> implem /** * Sets the content on this entity bean. * - * @param value The entity content, can be <jk>null</jk>. + * @param value The entity content. Can be <jk>null</jk> (the effect depends on the concrete leaf type: e.g. treated as empty for {@link StringEntity}/{@link ByteArrayEntity}, or a {@link NullPointerException} on read for {@link StreamEntity}/{@link ReaderEntity}/{@link FileEntity}). * @return This object. */ public SELF setContent(Object value) { diff --git a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/header/BasicMediaTypeHeader.java b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/header/BasicMediaTypeHeader.java index 490ffcf113..9fa0a42daf 100644 --- a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/header/BasicMediaTypeHeader.java +++ b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/header/BasicMediaTypeHeader.java @@ -177,7 +177,7 @@ public class BasicMediaTypeHeader extends BasicStringHeader { * For example, the media type <js>"text/foo+bar"</js> will return a list of * <code>[<js>'foo'</js>,<js>'bar'</js>]</code> * - * @return An unmodifiable list of subtype fragments. Can be <jk>null</jk>. + * @return An unmodifiable list of subtype fragments. Never <jk>null</jk>. */ public final List<String> getSubTypes() { return orElse(MediaType.EMPTY).getSubTypes(); } diff --git a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/header/IfRange.java b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/header/IfRange.java index 60fa6cc2c2..71a4678fc9 100644 --- a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/header/IfRange.java +++ b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/header/IfRange.java @@ -161,7 +161,7 @@ public class IfRange extends BasicDateHeader { * @param value * The header value. * <br>Must be an RFC-1123 formated string (e.g. <js>"Sat, 29 Oct 1994 19:43:31 GMT"</js>). - * <br>Can be <jk>null</jk>. + * <br>Must not be <jk>null</jk> (a <jk>null</jk> argument throws {@link NullPointerException}). */ public IfRange(String value) { super(NAME, isEtag(value) ? null : value); diff --git a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/header/SerializedHeader.java b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/header/SerializedHeader.java index ffa27d5797..3058832343 100644 --- a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/header/SerializedHeader.java +++ b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/header/SerializedHeader.java @@ -44,7 +44,7 @@ public class SerializedHeader extends BasicHeader { * @param name The header name. * @param value * The POJO to serialize as the header value. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>. The effect is implementation-dependent — see {@link HttpPartSerializerSession} and {@link HttpPartSchema}. * @return A new header bean. Never <jk>null</jk>. * @throws IllegalArgumentException If name is <jk>null</jk> or empty. */ @@ -84,7 +84,7 @@ public class SerializedHeader extends BasicHeader { * @param name The header name. * @param value * The supplier of the POJO to serialize as the header value. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>. The effect is implementation-dependent — see {@link HttpPartSerializerSession} and {@link HttpPartSchema}. * @return A new header bean. Never <jk>null</jk>. * @throws IllegalArgumentException If name is <jk>null</jk> or empty. */ @@ -128,7 +128,7 @@ public class SerializedHeader extends BasicHeader { * Constructor. * * @param name The HTTP header name name. - * @param value The POJO to serialize to the parameter value. Can be <jk>null</jk>. + * @param value The POJO to serialize to the parameter value. Can be <jk>null</jk>. The effect is implementation-dependent — see {@link HttpPartSerializerSession} and {@link HttpPartSchema}. * @param serializer * The serializer to use for serializing the value to a string value. * <br>Can be <jk>null</jk>, in which case the value is converted directly to a string instead of being serialized. @@ -160,7 +160,7 @@ public class SerializedHeader extends BasicHeader { * Header value is re-evaluated on each call to {@link #getValue()}. * * @param name The HTTP header name name. - * @param value The supplier of the POJO to serialize to the parameter value. Can be <jk>null</jk>. + * @param value The supplier of the POJO to serialize to the parameter value. Can be <jk>null</jk>. The effect is implementation-dependent — see {@link HttpPartSerializerSession} and {@link HttpPartSchema}. * @param serializer * The serializer to use for serializing the value to a string value. * <br>Can be <jk>null</jk>, in which case the value is converted directly to a string instead of being serialized. diff --git a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/part/PartBeanMeta.java b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/part/PartBeanMeta.java index cb76b21c2d..358ed034f1 100644 --- a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/part/PartBeanMeta.java +++ b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/part/PartBeanMeta.java @@ -121,7 +121,7 @@ public class PartBeanMeta<T> { * * @param value * The part value. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>. The effect is implementation-dependent, depending on the target bean type's constructor shape — see {@link #construct(String, Object)}. * @return A newly constructed bean. * @throws UnsupportedOperationException If bean could not be constructed (e.g. couldn't find a constructor). */ @@ -138,7 +138,7 @@ public class PartBeanMeta<T> { * {@link Header#value() @Header(value)} annotations. * @param value * The part value. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>. The effect is implementation-dependent, depending on the target bean type's constructor shape (e.g. coerced to <c>String</c> for a single-<c>String</c>-arg constructor, passed through unchanged otherwise). * @return A newly constructed bean. * @throws UnsupportedOperationException If bean could not be constructed (e.g. couldn't find a constructor). */ diff --git a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/part/SerializedPart.java b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/part/SerializedPart.java index 390e3c3252..f9ca83d98b 100644 --- a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/part/SerializedPart.java +++ b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/part/SerializedPart.java @@ -89,7 +89,7 @@ public class SerializedPart extends BasicPart { * * @param name The part name. * @param value The POJO to serialize to The part value. - * @param type The HTTP part type. Can be <jk>null</jk>. + * @param type The HTTP part type. Can be <jk>null</jk>. The effect is implementation-dependent — see {@link HttpPartSerializerSession#write}. * @param serializer * The serializer to use for serializing the value to a string value. * <br>Can be <jk>null</jk>, in which case the value is converted using a simple string conversion instead of being serialized. @@ -232,7 +232,7 @@ public class SerializedPart extends BasicPart { /** * Sets the HTTP part type. * - * @param value The new value for this property. Can be <jk>null</jk>. + * @param value The new value for this property. Can be <jk>null</jk>. The effect is implementation-dependent — see {@link HttpPartSerializerSession#write}. * @return This object. */ public SerializedPart type(HttpPartType value) { diff --git a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/resource/BasicResource.java b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/resource/BasicResource.java index 7512fa1997..d1dc9ade40 100644 --- a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/resource/BasicResource.java +++ b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/resource/BasicResource.java @@ -304,7 +304,7 @@ public abstract class BasicResource<SELF extends BasicResource<SELF>> implements /** * Sets the content on this entity bean. * - * @param value The entity content, can be <jk>null</jk>. + * @param value The entity content. Can be <jk>null</jk> (the effect depends on the concrete leaf type: e.g. treated as empty for {@link StringEntity}/{@link ByteArrayEntity}, or a {@link NullPointerException} on read for {@link StreamEntity}/{@link ReaderEntity}/{@link FileEntity}). * @return This object. */ public SELF setContent(Object value) { diff --git a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/response/BasicHttpException.java b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/response/BasicHttpException.java index 6021f6b846..6eb78b4b17 100644 --- a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/response/BasicHttpException.java +++ b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/response/BasicHttpException.java @@ -448,7 +448,7 @@ public class BasicHttpException extends BasicRuntimeException implements HttpRes * <p> * If not specified, uses {@link Locale#getDefault()}. * - * @param value The new value. Can be <jk>null</jk>. + * @param value The new value. Can be <jk>null</jk>. The effect is implementation-dependent, depending on the configured {@link ReasonPhraseCatalog} (e.g. ignored by {@link EnglishReasonPhraseCatalog}). * @return This object. */ public BasicHttpException setLocale2(Locale value) { diff --git a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/response/BasicHttpResponse.java b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/response/BasicHttpResponse.java index 47b9b5cf80..60aaab7f5a 100644 --- a/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/response/BasicHttpResponse.java +++ b/juneau-rest/juneau-rest-common-classic/src/main/java/org/apache/juneau/http/classic/response/BasicHttpResponse.java @@ -302,7 +302,7 @@ public abstract class BasicHttpResponse<SELF extends BasicHttpResponse<SELF>> im * <p> * If not specified, uses {@link Locale#getDefault()}. * - * @param value The new value. Can be <jk>null</jk>. + * @param value The new value. Can be <jk>null</jk>. The effect is implementation-dependent, depending on the configured {@link ReasonPhraseCatalog} (e.g. ignored by {@link EnglishReasonPhraseCatalog}). * @return This object. */ public SELF setLocale2(Locale value) { diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/assertions/FluentRequestFormParamAssertion.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/assertions/FluentRequestFormParamAssertion.java index e09dce7844..d0e7e8d30b 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/assertions/FluentRequestFormParamAssertion.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/assertions/FluentRequestFormParamAssertion.java @@ -137,14 +137,14 @@ public class FluentRequestFormParamAssertion<R> extends FluentStringAssertion<R> * <br>Should be <jk>null</jk> if this is the top-level assertion. * @param value * The object being tested. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>, in which case this assertion behaves as if testing a part with no value (e.g. {@link #isNull()} passes, transform methods yield <jk>null</jk>-valued assertions). * @param returns * The object to return after a test method is called. * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be * used on the same assertion. */ public FluentRequestFormParamAssertion(Assertion creator, RequestFormParam value, R returns) { - super(creator, value.asString().orElse(null), returns); + super(creator, value == null ? null : value.asString().orElse(null), returns); this.value = value; setThrowable(BadRequest.class); } @@ -154,7 +154,7 @@ public class FluentRequestFormParamAssertion<R> extends FluentStringAssertion<R> * * @param value * The object being tested. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>, in which case this assertion behaves as if testing a part with no value (e.g. {@link #isNull()} passes, transform methods yield <jk>null</jk>-valued assertions). * @param returns * The object to return after a test method is called. * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be @@ -172,7 +172,7 @@ public class FluentRequestFormParamAssertion<R> extends FluentStringAssertion<R> * @return A new fluent assertion object. */ public <T> FluentAnyAssertion<T,R> as(Class<T> type) { - return new FluentAnyAssertion<>(value.as(type).orElse(null), returns()); + return new FluentAnyAssertion<>(value == null ? null : value.as(type).orElse(null), returns()); } /** @@ -186,7 +186,7 @@ public class FluentRequestFormParamAssertion<R> extends FluentStringAssertion<R> * @return A new fluent assertion object. */ public FluentAnyAssertion<Object,R> as(Type type, Type...args) { - return new FluentAnyAssertion<>(value.as(type, args).orElse(null), returns()); + return new FluentAnyAssertion<>(value == null ? null : value.as(type, args).orElse(null), returns()); } /** @@ -196,7 +196,7 @@ public class FluentRequestFormParamAssertion<R> extends FluentStringAssertion<R> * @throws AssertionError If object is not a boolean. */ public FluentBooleanAssertion<R> asBoolean() { - return new FluentBooleanAssertion<>(this, value.asBoolean().orElse(null), returns()); + return new FluentBooleanAssertion<>(this, value == null ? null : value.asBoolean().orElse(null), returns()); } /** @@ -206,7 +206,7 @@ public class FluentRequestFormParamAssertion<R> extends FluentStringAssertion<R> * @throws AssertionError If object is not an integer. */ public FluentIntegerAssertion<R> asInteger() { - return new FluentIntegerAssertion<>(this, value.asInteger().orElse(null), returns()); + return new FluentIntegerAssertion<>(this, value == null ? null : value.asInteger().orElse(null), returns()); } @Override /* Overridden from FluentStringAssertion */ @@ -222,7 +222,7 @@ public class FluentRequestFormParamAssertion<R> extends FluentStringAssertion<R> * @throws AssertionError If object is not a long. */ public FluentLongAssertion<R> asLong() { - return new FluentLongAssertion<>(this, value.asLong().orElse(null), returns()); + return new FluentLongAssertion<>(this, value == null ? null : value.asLong().orElse(null), returns()); } /** @@ -232,7 +232,7 @@ public class FluentRequestFormParamAssertion<R> extends FluentStringAssertion<R> * @throws AssertionError If object is not a zoned-datetime. */ public FluentZonedDateTimeAssertion<R> asZonedDateTime() { - return new FluentZonedDateTimeAssertion<>(this, value.asDatePart().asZonedDateTime().orElse(null), returns()); + return new FluentZonedDateTimeAssertion<>(this, value == null ? null : value.asDatePart().asZonedDateTime().orElse(null), returns()); } @Override /* Overridden from Assertion */ diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/assertions/FluentRequestHeaderAssertion.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/assertions/FluentRequestHeaderAssertion.java index 8140424327..332a5474a0 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/assertions/FluentRequestHeaderAssertion.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/assertions/FluentRequestHeaderAssertion.java @@ -136,14 +136,14 @@ public class FluentRequestHeaderAssertion<R> extends FluentStringAssertion<R> { * <br>Should be <jk>null</jk> if this is the top-level assertion. * @param value * The object being tested. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>, in which case this assertion behaves as if testing a part with no value (e.g. {@link #isNull()} passes, transform methods yield <jk>null</jk>-valued assertions). * @param returns * The object to return after a test method is called. * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be * used on the same assertion. */ public FluentRequestHeaderAssertion(Assertion creator, RequestHeader value, R returns) { - super(creator, value.asString().orElse(null), returns); + super(creator, value == null ? null : value.asString().orElse(null), returns); this.value = value; setThrowable(BadRequest.class); } @@ -153,7 +153,7 @@ public class FluentRequestHeaderAssertion<R> extends FluentStringAssertion<R> { * * @param value * The object being tested. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>, in which case this assertion behaves as if testing a part with no value (e.g. {@link #isNull()} passes, transform methods yield <jk>null</jk>-valued assertions). * @param returns * The object to return after a test method is called. * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be @@ -171,7 +171,7 @@ public class FluentRequestHeaderAssertion<R> extends FluentStringAssertion<R> { * @return A new fluent assertion object. */ public <T> FluentAnyAssertion<T,R> as(Class<T> type) { - return new FluentAnyAssertion<>(value.as(type).orElse(null), returns()); + return new FluentAnyAssertion<>(value == null ? null : value.as(type).orElse(null), returns()); } /** @@ -185,7 +185,7 @@ public class FluentRequestHeaderAssertion<R> extends FluentStringAssertion<R> { * @return A new fluent assertion object. */ public FluentAnyAssertion<Object,R> as(Type type, Type...args) { - return new FluentAnyAssertion<>(value.as(type, args).orElse(null), returns()); + return new FluentAnyAssertion<>(value == null ? null : value.as(type, args).orElse(null), returns()); } /** @@ -195,7 +195,7 @@ public class FluentRequestHeaderAssertion<R> extends FluentStringAssertion<R> { * @throws AssertionError If object is not a boolean. */ public FluentBooleanAssertion<R> asBoolean() { - return new FluentBooleanAssertion<>(this, value.asBoolean().orElse(null), returns()); + return new FluentBooleanAssertion<>(this, value == null ? null : value.asBoolean().orElse(null), returns()); } /** @@ -205,7 +205,7 @@ public class FluentRequestHeaderAssertion<R> extends FluentStringAssertion<R> { * @throws AssertionError If object is not an integer. */ public FluentIntegerAssertion<R> asInteger() { - return new FluentIntegerAssertion<>(this, value.asInteger().orElse(null), returns()); + return new FluentIntegerAssertion<>(this, value == null ? null : value.asInteger().orElse(null), returns()); } @Override /* Overridden from FluentStringAssertion */ @@ -221,7 +221,7 @@ public class FluentRequestHeaderAssertion<R> extends FluentStringAssertion<R> { * @throws AssertionError If object is not a long. */ public FluentLongAssertion<R> asLong() { - return new FluentLongAssertion<>(this, value.asLong().orElse(null), returns()); + return new FluentLongAssertion<>(this, value == null ? null : value.asLong().orElse(null), returns()); } /** @@ -231,7 +231,7 @@ public class FluentRequestHeaderAssertion<R> extends FluentStringAssertion<R> { * @throws AssertionError If object is not a zoned-datetime. */ public FluentZonedDateTimeAssertion<R> asZonedDateTime() { - return new FluentZonedDateTimeAssertion<>(this, value.asDateHeader().asZonedDateTime().orElse(null), returns()); + return new FluentZonedDateTimeAssertion<>(this, value == null ? null : value.asDateHeader().asZonedDateTime().orElse(null), returns()); } @Override /* Overridden from Assertion */ diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/assertions/FluentRequestQueryParamAssertion.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/assertions/FluentRequestQueryParamAssertion.java index d9715e6355..cad335c245 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/assertions/FluentRequestQueryParamAssertion.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/assertions/FluentRequestQueryParamAssertion.java @@ -137,14 +137,14 @@ public class FluentRequestQueryParamAssertion<R> extends FluentStringAssertion<R * <br>Should be <jk>null</jk> if this is the top-level assertion. * @param value * The object being tested. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>, in which case this assertion behaves as if testing a part with no value (e.g. {@link #isNull()} passes, transform methods yield <jk>null</jk>-valued assertions). * @param returns * The object to return after a test method is called. * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be * used on the same assertion. */ public FluentRequestQueryParamAssertion(Assertion creator, RequestQueryParam value, R returns) { - super(creator, value.asString().orElse(null), returns); + super(creator, value == null ? null : value.asString().orElse(null), returns); this.value = value; setThrowable(BadRequest.class); } @@ -154,7 +154,7 @@ public class FluentRequestQueryParamAssertion<R> extends FluentStringAssertion<R * * @param value * The object being tested. - * <br>Can be <jk>null</jk>. + * <br>Can be <jk>null</jk>, in which case this assertion behaves as if testing a part with no value (e.g. {@link #isNull()} passes, transform methods yield <jk>null</jk>-valued assertions). * @param returns * The object to return after a test method is called. * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be @@ -172,7 +172,7 @@ public class FluentRequestQueryParamAssertion<R> extends FluentStringAssertion<R * @return A new fluent assertion object. */ public <T> FluentAnyAssertion<T,R> as(Class<T> type) { - return new FluentAnyAssertion<>(value.as(type).orElse(null), returns()); + return new FluentAnyAssertion<>(value == null ? null : value.as(type).orElse(null), returns()); } /** @@ -186,7 +186,7 @@ public class FluentRequestQueryParamAssertion<R> extends FluentStringAssertion<R * @return A new fluent assertion object. */ public FluentAnyAssertion<Object,R> as(Type type, Type...args) { - return new FluentAnyAssertion<>(value.as(type, args).orElse(null), returns()); + return new FluentAnyAssertion<>(value == null ? null : value.as(type, args).orElse(null), returns()); } /** @@ -196,7 +196,7 @@ public class FluentRequestQueryParamAssertion<R> extends FluentStringAssertion<R * @throws AssertionError If object is not a boolean. */ public FluentBooleanAssertion<R> asBoolean() { - return new FluentBooleanAssertion<>(this, value.asBoolean().orElse(null), returns()); + return new FluentBooleanAssertion<>(this, value == null ? null : value.asBoolean().orElse(null), returns()); } /** @@ -206,7 +206,7 @@ public class FluentRequestQueryParamAssertion<R> extends FluentStringAssertion<R * @throws AssertionError If object is not an integer. */ public FluentIntegerAssertion<R> asInteger() { - return new FluentIntegerAssertion<>(this, value.asInteger().orElse(null), returns()); + return new FluentIntegerAssertion<>(this, value == null ? null : value.asInteger().orElse(null), returns()); } @Override /* Overridden from FluentStringAssertion */ @@ -222,7 +222,7 @@ public class FluentRequestQueryParamAssertion<R> extends FluentStringAssertion<R * @throws AssertionError If object is not a long. */ public FluentLongAssertion<R> asLong() { - return new FluentLongAssertion<>(this, value.asLong().orElse(null), returns()); + return new FluentLongAssertion<>(this, value == null ? null : value.asLong().orElse(null), returns()); } /** @@ -232,7 +232,7 @@ public class FluentRequestQueryParamAssertion<R> extends FluentStringAssertion<R * @throws AssertionError If object is not a zoned-datetime. */ public FluentZonedDateTimeAssertion<R> asZonedDateTime() { - return new FluentZonedDateTimeAssertion<>(this, value.asDatePart().asZonedDateTime().orElse(null), returns()); + return new FluentZonedDateTimeAssertion<>(this, value == null ? null : value.asDatePart().asZonedDateTime().orElse(null), returns()); } @Override /* Overridden from Assertion */ diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/stats/MethodExecStats.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/stats/MethodExecStats.java index 2e603e2ceb..8c01d4ed2f 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/stats/MethodExecStats.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/stats/MethodExecStats.java @@ -184,7 +184,7 @@ public class MethodExecStats { /** * Call when an error occurs. * - * @param e The exception thrown. Can be <jk>null</jk>. + * @param e The exception thrown. Must not be <jk>null</jk> (a <jk>null</jk> argument throws {@link NullPointerException} via {@link ThrownStore#add(Throwable)}). * @return This object. */ public MethodExecStats error(Throwable e) { diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/util/UrlPathMatch.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/util/UrlPathMatch.java index b670f461fe..fe10b0b3de 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/util/UrlPathMatch.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/util/UrlPathMatch.java @@ -49,7 +49,7 @@ public class UrlPathMatch { /** * Constructor. * - * @param path The path being matched against. Can be <jk>null</jk>. + * @param path The path being matched against. Must not be <jk>null</jk> (a <jk>null</jk> argument causes {@link #getPrefix()}/{@link #getSuffix()} to throw {@link NullPointerException}). * @param matchedParts The number of parts that were matched against the path. * @param keys The variable keys. Can be <jk>null</jk> (no path variables are recorded; the variable map resolves to empty). * @param values The variable values. Can be <jk>null</jk> if <c>keys</c> is also <jk>null</jk>; otherwise must align positionally with <c>keys</c>. diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/server/assertions/FluentRequestFormParamAssertion_Test.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/server/assertions/FluentRequestFormParamAssertion_Test.java new file mode 100644 index 0000000000..e74480762d --- /dev/null +++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/server/assertions/FluentRequestFormParamAssertion_Test.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.juneau.rest.server.assertions; + +import static org.junit.jupiter.api.Assertions.*; + +import org.apache.juneau.*; +import org.apache.juneau.rest.server.httppart.*; +import org.junit.jupiter.api.*; + +/** + * Validates {@link FluentRequestFormParamAssertion} tolerates a null {@code value} (TODO-286 #6 null-tolerance fix). + * + * <p> + * A null {@link RequestFormParam} used to NPE in the constructor ({@code value.asString()}) and in every transform + * method ({@code value.asBoolean()}, etc.). + */ +class FluentRequestFormParamAssertion_Test extends TestBase { + + @Test void a01_nullValue_chainedConstructor_doesNotThrow() { + var a = new FluentRequestFormParamAssertion<>(null, (RequestFormParam)null, null); + assertDoesNotThrow(a::isNull); + } + + @Test void a02_nullValue_directConstructor_doesNotThrow() { + var a = new FluentRequestFormParamAssertion<>((RequestFormParam)null, null); + assertDoesNotThrow(a::isNull); + } + + @Test void a03_nullValue_transformMethodsDoNotThrowAndYieldNull() { + var a = new FluentRequestFormParamAssertion<>((RequestFormParam)null, null); + assertDoesNotThrow(() -> a.asBoolean().isNull()); + assertDoesNotThrow(() -> a.asInteger().isNull()); + assertDoesNotThrow(() -> a.asLong().isNull()); + assertDoesNotThrow(() -> a.asZonedDateTime().isNull()); + assertDoesNotThrow(() -> a.as(String.class).isNull()); + } +} diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/server/assertions/FluentRequestHeaderAssertion_Test.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/server/assertions/FluentRequestHeaderAssertion_Test.java index 0061b9395e..baa71235b2 100644 --- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/server/assertions/FluentRequestHeaderAssertion_Test.java +++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/server/assertions/FluentRequestHeaderAssertion_Test.java @@ -59,4 +59,26 @@ class FluentRequestHeaderAssertion_Test extends TestBase { var e = assertThrows(RuntimeException.class, () -> h.is("expected")); assertFalse(e.getMessage().startsWith("CUSTOM ")); } + + // TODO-286 #5: a null RequestHeader used to NPE in the constructor (value.asString()) and in every + // transform method (value.asBoolean(), etc.). Verify null is now tolerated end-to-end. + + @Test void a03_nullValue_chainedConstructor_doesNotThrow() { + var h = new FluentRequestHeaderAssertion<>(null, (RequestHeader)null, null); + assertDoesNotThrow(h::isNull); + } + + @Test void a04_nullValue_directConstructor_doesNotThrow() { + var h = new FluentRequestHeaderAssertion<>((RequestHeader)null, null); + assertDoesNotThrow(h::isNull); + } + + @Test void a05_nullValue_transformMethodsDoNotThrowAndYieldNull() { + var h = new FluentRequestHeaderAssertion<>((RequestHeader)null, null); + assertDoesNotThrow(() -> h.asBoolean().isNull()); + assertDoesNotThrow(() -> h.asInteger().isNull()); + assertDoesNotThrow(() -> h.asLong().isNull()); + assertDoesNotThrow(() -> h.asZonedDateTime().isNull()); + assertDoesNotThrow(() -> h.as(String.class).isNull()); + } } diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/server/assertions/FluentRequestQueryParamAssertion_Test.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/server/assertions/FluentRequestQueryParamAssertion_Test.java new file mode 100644 index 0000000000..10cefe827a --- /dev/null +++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/server/assertions/FluentRequestQueryParamAssertion_Test.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.juneau.rest.server.assertions; + +import static org.junit.jupiter.api.Assertions.*; + +import org.apache.juneau.*; +import org.apache.juneau.rest.server.httppart.*; +import org.junit.jupiter.api.*; + +/** + * Validates {@link FluentRequestQueryParamAssertion} tolerates a null {@code value} (TODO-286 #4 null-tolerance fix). + * + * <p> + * A null {@link RequestQueryParam} used to NPE in the constructor ({@code value.asString()}) and in every transform + * method ({@code value.asBoolean()}, etc.). + */ +class FluentRequestQueryParamAssertion_Test extends TestBase { + + @Test void a01_nullValue_chainedConstructor_doesNotThrow() { + var a = new FluentRequestQueryParamAssertion<>(null, (RequestQueryParam)null, null); + assertDoesNotThrow(a::isNull); + } + + @Test void a02_nullValue_directConstructor_doesNotThrow() { + var a = new FluentRequestQueryParamAssertion<>((RequestQueryParam)null, null); + assertDoesNotThrow(a::isNull); + } + + @Test void a03_nullValue_transformMethodsDoNotThrowAndYieldNull() { + var a = new FluentRequestQueryParamAssertion<>((RequestQueryParam)null, null); + assertDoesNotThrow(() -> a.asBoolean().isNull()); + assertDoesNotThrow(() -> a.asInteger().isNull()); + assertDoesNotThrow(() -> a.asLong().isNull()); + assertDoesNotThrow(() -> a.asZonedDateTime().isNull()); + assertDoesNotThrow(() -> a.as(String.class).isNull()); + } +}
