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
The following commit(s) were added to refs/heads/master by this push: new ef82a51 REST refactoring. ef82a51 is described below commit ef82a51b928963745c56e374e721fe946f4ce993 Author: JamesBognar <james.bog...@salesforce.com> AuthorDate: Sat Feb 20 10:52:32 2021 -0500 REST refactoring. --- .../juneau/http/header/BasicStringHeader.java | 13 + .../apache/juneau/http/pair/BasicNamedString.java | 13 + .../juneau/examples/rest/RequestEchoResource.java | 2 +- .../apache/juneau/rest/client/ResponseBody.java | 4 +- .../apache/juneau/rest/client/ResponseHeader.java | 17 +- .../org/apache/juneau/rest/RequestAttributes.java | 6 +- .../java/org/apache/juneau/rest/RequestBody.java | 8 +- .../java/org/apache/juneau/rest/RequestHeader.java | 105 +---- .../org/apache/juneau/rest/RequestHeaders.java | 255 ++++++++---- .../org/apache/juneau/rest/RequestQueryParam.java | 23 +- .../main/java/org/apache/juneau/rest/RestCall.java | 2 +- .../apache/juneau/rest/RestOperationContext.java | 7 +- .../java/org/apache/juneau/rest/RestRequest.java | 452 ++++++++++++++++----- .../java/org/apache/juneau/rest/RestResponse.java | 14 +- .../assertions/FluentProtocolVersionAssertion.java | 90 ++++ .../assertions/FluentRequestLineAssertion.java | 91 +++++ .../juneau/rest/logging/BasicRestLogger.java | 2 - .../apache/juneau/rest/vars/RequestHeaderVar.java | 2 +- .../apache/juneau/rest/vars/RequestQueryVar.java | 2 +- .../apache/juneau/rest/widget/MenuItemWidget.java | 6 +- .../juneau/http/SerializedHttpEntity_Test.java | 2 +- .../org/apache/juneau/http/remote/Remote_Test.java | 2 +- .../juneau/rest/Header_AcceptCharset_Test.java | 6 +- .../org/apache/juneau/rest/RestOp_Params_Test.java | 2 +- .../juneau/rest/annotation/RestHook_Test.java | 14 +- .../rest/client/RestClient_BasicCalls_Test.java | 2 +- .../client/RestClient_Config_BeanContext_Test.java | 2 +- .../client/RestClient_Config_OpenApi_Test.java | 2 +- .../client/RestClient_Config_RestClient_Test.java | 2 +- .../rest/client/RestClient_Headers_Test.java | 2 +- .../client/RestClient_Response_Headers_Test.java | 4 +- .../rest/client/RestClient_Response_Test.java | 2 +- 32 files changed, 851 insertions(+), 305 deletions(-) diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/BasicStringHeader.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/BasicStringHeader.java index bf03dd0..900b249 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/BasicStringHeader.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/BasicStringHeader.java @@ -131,6 +131,19 @@ public class BasicStringHeader extends BasicHeader { return Optional.ofNullable(getParsedValue()); } + /** + * Return the value if present, otherwise return other. + * + * <p> + * This is a shortened form for calling <c>asString().orElse(<jv>other</jv>)</c>. + * + * @param other The value to be returned if there is no value present, may be <jk>null</jk>. + * @return The value, if present, otherwise other. + */ + public String orElse(String other) { + return asString().orElse(other); + } + private String getParsedValue() { if (parsed != null) return parsed; diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/pair/BasicNamedString.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/pair/BasicNamedString.java index e9c0b48..bb4aacc 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/pair/BasicNamedString.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/pair/BasicNamedString.java @@ -111,6 +111,19 @@ public class BasicNamedString extends BasicNameValuePair { return Optional.ofNullable(getParsedValue()); } + /** + * Return the value if present, otherwise return other. + * + * <p> + * This is a shortened form for calling <c>asString().orElse(<jv>other</jv>)</c>. + * + * @param other The value to be returned if there is no value present, may be <jk>null</jk>. + * @return The value, if present, otherwise other. + */ + public String orElse(String other) { + return asString().orElse(other); + } + private String getParsedValue() { if (parsed != null) return parsed; diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java index ca36454..2f8bbed 100644 --- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java +++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java @@ -88,6 +88,6 @@ public class RequestEchoResource extends BasicRestObject { @RestOp(method="*", path="/*", converters={Traversable.class,Queryable.class}, summary="Serializes the incoming HttpServletRequest object.") public HttpServletRequest doGet(RestRequest req) { // Just echo the request back as the response. - return req; + return req.getHttpServletRequest(); } } diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseBody.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseBody.java index aedc868..c47eed2 100644 --- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseBody.java +++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseBody.java @@ -266,7 +266,7 @@ public class ResponseBody implements HttpEntity { // Figure out what the charset of the response is. String cs = null; - String ct = getContentType().asString().orElse(null); + String ct = getContentType().orElse(null); // First look for "charset=" in Content-Type header of response. if (ct != null) @@ -675,7 +675,7 @@ public class ResponseBody implements HttpEntity { return (T)r; } - String ct = firstNonEmpty(response.getResponseHeader("Content-Type").asString().orElse("text/plain")); + String ct = firstNonEmpty(response.getResponseHeader("Content-Type").orElse("text/plain")); if (parser == null) parser = client.getMatchingParser(ct); diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseHeader.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseHeader.java index 2afa920..679c55a 100644 --- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseHeader.java +++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseHeader.java @@ -135,6 +135,19 @@ public class ResponseHeader implements Header { } /** + * Return the value if present, otherwise return other. + * + * <p> + * This is a shortened form for calling <c>asString().orElse(<jv>other</jv>)</c>. + * + * @param other The value to be returned if there is no value present, may be <jk>null</jk>. + * @return The value, if present, otherwise other. + */ + public String orElse(String other) { + return asString().orElse(other); + } + + /** * Returns the value of this header as a string. * * @return The value of this header as a string, or {@link Optional#empty()} if the header was not present. @@ -307,7 +320,7 @@ public class ResponseHeader implements Header { * @return The response object (for method chaining). */ public RestResponse asString(Mutable<String> m) { - m.set(asString().orElse(null)); + m.set(orElse(null)); return response; } @@ -417,7 +430,7 @@ public class ResponseHeader implements Header { * @throws RestCallException If a connection error occurred. */ public Matcher asMatcher(Pattern pattern) throws RestCallException { - return pattern.matcher(asString().orElse("")); + return pattern.matcher(orElse("")); } /** diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestAttributes.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestAttributes.java index 2421b7e..59bd365 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestAttributes.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestAttributes.java @@ -16,6 +16,8 @@ import static org.apache.juneau.internal.CollectionUtils.*; import java.util.*; +import javax.servlet.http.*; + import org.apache.juneau.collections.*; import org.apache.juneau.http.*; import org.apache.juneau.internal.*; @@ -35,13 +37,13 @@ public class RequestAttributes extends OMap { private static final long serialVersionUID = 1L; - final RestRequest req; + final HttpServletRequest req; final OMap defaultEntries; final VarResolverSession vs; RequestAttributes(RestRequest req) { super(); - this.req = req; + this.req = req.getHttpServletRequest(); this.defaultEntries = new OMap(); this.vs = req.getVarResolverSession(); } diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java index 5927855..1b8257f 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java @@ -314,7 +314,7 @@ public class RequestBody { Reader r = getUnbufferedReader(); if (r instanceof BufferedReader) return (BufferedReader)r; - int len = req.getContentLength(); + int len = req.getHttpServletRequest().getContentLength(); int buffSize = len <= 0 ? 8192 : Math.max(len, 8192); return new BufferedReader(r, buffSize); } @@ -328,7 +328,7 @@ public class RequestBody { protected Reader getUnbufferedReader() throws IOException { if (body != null) return new CharSequenceReader(new String(body, UTF8)); - return new InputStreamReader(getInputStream(), req.getCharacterEncoding()); + return new InputStreamReader(getInputStream(), req.getCharset()); } /** @@ -491,14 +491,14 @@ public class RequestBody { private Encoder getEncoder() throws UnsupportedMediaType { if (encoder == null) { - String ce = req.getHeader("content-encoding"); + String ce = req.getStringHeader("content-encoding").orElse(null); if (isNotEmpty(ce)) { ce = ce.trim(); encoder = encoders.getEncoder(ce); if (encoder == null) throw new UnsupportedMediaType( "Unsupported encoding in request header ''Content-Encoding'': ''{0}''\n\tSupported codings: {1}", - req.getHeader("content-encoding"), encoders.getSupportedEncodings() + req.getStringHeader("content-encoding").orElse(null), encoders.getSupportedEncodings() ); } diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeader.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeader.java index ec1d72b..68309b4 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeader.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeader.java @@ -20,7 +20,6 @@ import java.util.regex.*; import org.apache.http.*; import org.apache.juneau.*; -import org.apache.juneau.assertions.*; import org.apache.juneau.http.*; import org.apache.juneau.http.exception.*; import org.apache.juneau.http.exception.HttpException; @@ -29,6 +28,7 @@ import org.apache.juneau.httppart.*; import org.apache.juneau.oapi.*; import org.apache.juneau.parser.ParseException; import org.apache.juneau.reflect.*; +import org.apache.juneau.rest.assertions.*; /** * Represents a single header on an HTTP request. @@ -103,6 +103,19 @@ public class RequestHeader implements Header { } /** + * Return the value if present, otherwise return other. + * + * <p> + * This is a shortened form for calling <c>asString().orElse(<jv>other</jv>)</c>. + * + * @param other The value to be returned if there is no value present, may be <jk>null</jk>. + * @return The value, if present, otherwise other. + */ + public String orElse(String other) { + return asString().orElse(other); + } + + /** * Returns the value of this header as a string. * * @return The value of this header as a string, or {@link Optional#empty()} if the header was not present. @@ -168,10 +181,10 @@ public class RequestHeader implements Header { ClassInfo ci = ClassInfo.of(c); ConstructorInfo cc = ci.getConstructor(Visibility.PUBLIC, String.class); if (cc != null) - return cc.invoke(asString()); + return cc.invoke(orElse(null)); cc = ci.getConstructor(Visibility.PUBLIC, String.class, String.class); if (cc != null) - return cc.invoke(getName(), asString()); + return cc.invoke(getName(), orElse(null)); } catch (Exception e) { throw new RuntimeException(e); } @@ -303,7 +316,7 @@ public class RequestHeader implements Header { */ public <T> Optional<T> asType(ClassMeta<T> type) throws HttpException { try { - return Optional.ofNullable(parser.parse(HEADER, schema, asString().orElse(null), type)); + return Optional.ofNullable(parser.parse(HEADER, schema, orElse(null), type)); } catch (ParseException e) { throw new BadRequest(e, "Could not parse header ''{0}''.", getName()); } @@ -328,7 +341,7 @@ public class RequestHeader implements Header { * @throws HttpException If a connection error occurred. */ public Matcher asMatcher(Pattern pattern) throws HttpException { - return pattern.matcher(asString().orElse("")); + return pattern.matcher(orElse("")); } /** @@ -386,88 +399,14 @@ public class RequestHeader implements Header { * <h5 class='section'>Examples:</h5> * <p class='bcode w800'> * <jv>request</jv> - * .getRequestHeader(<js>"Content-Type"</js>) - * .assertString().is(<js>"application/json"</js>); - * </p> - * - * <p> - * The assertion test returns the header object allowing you to chain multiple requests like so: - * <p class='bcode w800'> - * <jc>// Validates the header and then convert it to a bean.</jc> - * MediaType <jv>mediaType</jv> = <jv>request</jv> - * .getRequestHeader(<js>"Content-Type"</js>) - * .assertString().matches(<js>".*json.*"</js>) - * .as(MediaType.<jk>class</jk>).get(); - * </p> - * - * @return A new fluent assertion object. - */ - public FluentStringAssertion<RequestHeader> assertString() { - return new FluentStringAssertion<>(asString().orElse(null), this); - } - - /** - * Provides the ability to perform fluent-style assertions on an integer request header. - * - * <h5 class='section'>Examples:</h5> - * <p class='bcode w800'> - * <jv>request</jv> - * .getRequestHeader(<js>"Age"</js>) - * .assertInteger().isGreaterThan(1); - * </p> - * - * @return A new fluent assertion object. - */ - public FluentIntegerAssertion<RequestHeader> assertInteger() { - return new FluentIntegerAssertion<>(asIntegerHeader().asInteger().orElse(null), this); - } - - /** - * Provides the ability to perform fluent-style assertions on a long request header. - * - * <h5 class='section'>Examples:</h5> - * <p class='bcode w800'> - * <jv>request</jv> - * .getRequestHeader(<js>"Length"</js>) - * .assertLong().isLessThan(100000); - * </p> - * - * @return A new fluent assertion object. - */ - public FluentLongAssertion<RequestHeader> assertLong() { - return new FluentLongAssertion<>(asLongHeader().asLong().orElse(null), this); - } - - /** - * Provides the ability to perform fluent-style assertions on a date request header. - * - * <h5 class='section'>Examples:</h5> - * <p class='bcode w800'> - * <jv>request</jv> - * .getRequestHeader(<js>"Expires"</js>) - * .assertDate().isAfterNow(); - * </p> - * - * @return A new fluent assertion object. - */ - public FluentZonedDateTimeAssertion<RequestHeader> assertDate() { - return new FluentZonedDateTimeAssertion<>(asDateHeader().asZonedDateTime().orElse(null), this); - } - - /** - * Provides the ability to perform fluent-style assertions on comma-separated string headers. - * - * <h5 class='section'>Examples:</h5> - * <p class='bcode w800'> - * <jv>request</jv> - * .getRequestHeader(<js>"Allow"</js>) - * .assertCsvArray().contains(<js>"GET"</js>); + * .getHeader(<js>"Content-Type"</js>) + * .assertValue().is(<js>"application/json"</js>); * </p> * * @return A new fluent assertion object. */ - public FluentListAssertion<RequestHeader> assertCsvArray() { - return new FluentListAssertion<>(asCsvArrayHeader().asList().orElse(null), this); + public FluentRequestHeaderAssertion<RequestHeader> assertValue() { + return new FluentRequestHeaderAssertion<>(this, this); } //------------------------------------------------------------------------------------------------------------------ diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java index 2bdb107..d939a23 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java @@ -23,6 +23,7 @@ import java.util.*; import java.util.function.*; import org.apache.http.*; +import org.apache.http.message.*; import org.apache.juneau.httppart.*; import org.apache.juneau.internal.*; import org.apache.juneau.collections.*; @@ -53,11 +54,11 @@ public class RequestHeaders { this.req = req; this.caseSensitive = caseSensitive; - for (Enumeration<String> e = req.getHeaderNames(); e.hasMoreElements();) { + for (Enumeration<String> e = req.getHttpServletRequest().getHeaderNames(); e.hasMoreElements();) { String name = e.nextElement(); String key = key(name); List<RequestHeader> l = new ArrayList<>(); - for (Enumeration<String> ve = req.getHeaders(name); ve.hasMoreElements();) { + for (Enumeration<String> ve = req.getHttpServletRequest().getHeaders(name); ve.hasMoreElements();) { RequestHeader h = new RequestHeader(req, name, ve.nextElement()); list.add(h); l.add(h); @@ -99,18 +100,21 @@ public class RequestHeaders { return this; } + //----------------------------------------------------------------------------------------------------------------- + // Basic operations. + //----------------------------------------------------------------------------------------------------------------- + /** * Adds default entries to these headers. * * <p> - * Similar to {@link #put(String, Object)} but doesn't override existing values. + * Similar to {@link #set(String, Object)} but doesn't override existing values. * - * @param pairs - * The default entries. - * <br>Can be <jk>null</jk>. + * @param pairs The default entries. Must not be <jk>null</jk>. * @return This object (for method chaining). */ public RequestHeaders addDefault(List<Header> pairs) { + assertArgNotNull("pairs", pairs); for (Header p : pairs) { String name = p.getName(); String key = key(name); @@ -134,7 +138,7 @@ public class RequestHeaders { * Note that this method never returns <jk>null</jk> and that {@link RequestHeader#exists()} can be used * to test for the existence of the header. * - * @param name The header name. + * @param name The header name. Must not be <jk>null</jk>. * @return The header. Never <jk>null</jk>. */ public RequestHeader getFirst(String name) { @@ -150,7 +154,7 @@ public class RequestHeaders { * Note that this method never returns <jk>null</jk> and that {@link RequestHeader#exists()} can be used * to test for the existence of the header. * - * @param name The header name. + * @param name The header name. Must not be <jk>null</jk>. * @return The header. Never <jk>null</jk>. */ public RequestHeader getLast(String name) { @@ -162,7 +166,7 @@ public class RequestHeaders { /** * Returns all the headers with the specified name. * - * @param name The header name. + * @param name The header name. Must not be <jk>null</jk>. * @return The list of all headers with the specified name, or an empty list if none are found. */ public List<RequestHeader> getAll(String name) { @@ -181,6 +185,173 @@ public class RequestHeaders { } /** + * Returns <jk>true</jk> if the header with the specified name is present. + * + * @param name The header name. Must not be <jk>null</jk>. + * @return <jk>true</jk> if the header with the specified name is present. + */ + public boolean contains(String name) { + assertArgNotNull("name", name); + return map.containsKey(key(name)); + } + + /** + * Adds a request header value. + * + * <p> + * Header is added to the end of the headers. + * <br>Existing headers with the same name are not changed. + * + * @param name The header name. Must not be <jk>null</jk>. + * @param value The header value. Can be <jk>null</jk>. + * @return This object (for method chaining). + */ + public RequestHeaders add(String name, Object value) { + assertArgNotNull("name", name); + String key = key(name); + RequestHeader h = new RequestHeader(req, name, stringify(value)).parser(parser); + if (map.containsKey(key)) + map.get(key).add(h); + else + map.put(key, AList.of(h)); + list.add(h); + return this; + } + + /** + * Adds request header values. + * + * <p> + * Headers are added to the end of the headers. + * <br>Existing headers with the same name are not changed. + * + * @param header The header objects. Must not be <jk>null</jk>. + * @return This object (for method chaining). + */ + public RequestHeaders add(Header...header) { + assertArgNotNull("header", header); + for (Header h : header) { + assertArgNotNull("header entry", h); + add(h.getName(), h.getValue()); + } + return this; + } + + /** + * Sets a request header value. + * + * <p> + * Header is added to the end of the headers. + * <br>Any previous headers with the same name are removed. + * + * @param name The header name. Must not be <jk>null</jk>. + * @param value + * The header value. + * <br>Converted to a string using {@link Object#toString()}. + * <br>Can be <jk>null</jk>. + * @return This object (for method chaining). + */ + public RequestHeaders set(String name, Object value) { + assertArgNotNull("name", name); + String key = key(name); + remove(key); + RequestHeader h = new RequestHeader(req, name, stringify(value)).parser(parser); + map.put(key, AList.of(h)); + list.add(h); + return this; + } + + /** + * Sets request header values. + * + * <p> + * Headers are added to the end of the headers. + * <br>Any previous headers with the same name are removed. + * + * @param headers The header beans. Must not be <jk>null</jk> or contain <jk>null</jk>. + * @return This object (for method chaining). + */ + public RequestHeaders set(Header...headers) { + assertArgNotNull("headers", headers); + for (Header h : headers) + remove(h); + for (Header h : headers) + add(h); + return this; + } + + /** + * Remove headers. + * + * @param name The header names. Must not be <jk>null</jk>. + * @return This object (for method chaining). + */ + public RequestHeaders remove(String...name) { + assertArgNotNull("name", name); + for (String n : name) { + String key = key(n); + if (map.containsKey(key)) + list.removeAll(map.get(key)); + map.remove(key); + } + return this; + } + + /** + * Remove headers. + * + * @param headers The headers to remove. Must not be <jk>null</jk>. + * @return This object (for method chaining). + */ + public RequestHeaders remove(Header...headers) { + for (Header h : headers) + remove(h.getName()); + return this; + } + + /** + * Returns an iterator of all the headers. + * + * @return An iterator of all the headers. Never <jk>null</jk>. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public HeaderIterator iterator() { + return new BasicListHeaderIterator((List)list, null); + } + + /** + * Returns an iterator of all the headers with the specified name. + * + * @param name The header name. + * @return An iterator of all the headers with the specified name. Never <jk>null</jk>. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public HeaderIterator iterator(String name) { + return new BasicListHeaderIterator((List)map.get(key(name)), null); + } + + /** + * Returns a copy of this object but only with the specified header names copied. + * + * @param headers The list to include in the copy. + * @return A new list object. + */ + public RequestHeaders subset(String...headers) { + Map<String,List<RequestHeader>> m = Arrays + .asList(headers) + .stream() + .map(x -> key(x)) + .filter(map::containsKey) + .collect(toMap(Function.identity(),map::get)); + + return new RequestHeaders(req, m, parser, caseSensitive); + } + + //----------------------------------------------------------------------------------------------------------------- + // Convenience getters. + //----------------------------------------------------------------------------------------------------------------- + + /** * Returns the last header with the specified name as a string. * * <ul class='notes'> @@ -270,65 +441,9 @@ public class RequestHeaders { return getLast(name).asDate(); } - /** - * Sets a request header value. - * - * <p> - * This overwrites any previous value. - * - * @param name The header name. - * @param value The header value. - * @return This object (for method chaining). - */ - public RequestHeaders put(String name, Object value) { - assertArgNotNull("name", name); - String key = key(name); - RequestHeader h = new RequestHeader(req, name, stringify(value)).parser(parser); - if (map.containsKey(key)) - list.removeIf(x->caseSensitive?x.getName().equals(name):x.getName().equalsIgnoreCase(name)); - list.add(h); - map.put(key, AList.of(h)); - return this; - } - - /** - * Adds a request header value. - * - * <p> - * Header is added to the end of the headers. - * - * @param name The header name. - * @param value The header value. - * @return This object (for method chaining). - */ - public RequestHeaders add(String name, Object value) { - assertArgNotNull("name", name); - String key = key(name); - RequestHeader h = new RequestHeader(req, name, stringify(value)).parser(parser); - if (map.containsKey(key)) - map.get(key).add(h); - else - map.put(key, AList.of(h)); - list.add(h); - return this; - } - - /** - * Returns a copy of this object but only with the specified header names copied. - * - * @param headers The list to include in the copy. - * @return A new list object. - */ - public RequestHeaders subset(String...headers) { - Map<String,List<RequestHeader>> m = Arrays - .asList(headers) - .stream() - .map(x -> key(x)) - .filter(map::containsKey) - .collect(toMap(Function.identity(),map::get)); - - return new RequestHeaders(req, m, parser, caseSensitive); - } + //----------------------------------------------------------------------------------------------------------------- + // Standard headers. + //----------------------------------------------------------------------------------------------------------------- /** * Returns the <c>Accept</c> header on the request. @@ -828,6 +943,10 @@ public class RequestHeaders { return ofNullable(Warning.of(getString("Warning").orElse(null))); } + //----------------------------------------------------------------------------------------------------------------- + // Other methods. + //----------------------------------------------------------------------------------------------------------------- + /** * Converts the headers to a readable string. * diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQueryParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQueryParam.java index 6af47f7..568082c 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQueryParam.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQueryParam.java @@ -103,6 +103,19 @@ public class RequestQueryParam implements NameValuePair { } /** + * Return the value if present, otherwise return other. + * + * <p> + * This is a shortened form for calling <c>asString().orElse(<jv>other</jv>)</c>. + * + * @param other The value to be returned if there is no value present, may be <jk>null</jk>. + * @return The value, if present, otherwise other. + */ + public String orElse(String other) { + return asString().orElse(other); + } + + /** * Returns the value of this parameter as a string. * * @return The value of this parameter as a string, or {@link Optional#empty()} if the parameter was not present. @@ -168,10 +181,10 @@ public class RequestQueryParam implements NameValuePair { ClassInfo ci = ClassInfo.of(c); ConstructorInfo cc = ci.getConstructor(Visibility.PUBLIC, String.class); if (cc != null) - return cc.invoke(asString()); + return cc.invoke(orElse(null)); cc = ci.getConstructor(Visibility.PUBLIC, String.class, String.class); if (cc != null) - return cc.invoke(getName(), asString()); + return cc.invoke(getName(), orElse(null)); } catch (Exception e) { throw new RuntimeException(e); } @@ -276,7 +289,7 @@ public class RequestQueryParam implements NameValuePair { */ public <T> Optional<T> asType(ClassMeta<T> type) throws HttpException { try { - return Optional.ofNullable(parser.parse(HEADER, schema, asString().orElse(null), type)); + return Optional.ofNullable(parser.parse(HEADER, schema, orElse(null), type)); } catch (ParseException e) { throw new BadRequest(e, "Could not parse query parameter ''{0}''.", getName()); } @@ -302,7 +315,7 @@ public class RequestQueryParam implements NameValuePair { * @throws HttpException If a connection error occurred. */ public Matcher asMatcher(Pattern pattern) throws HttpException { - return pattern.matcher(asString().orElse("")); + return pattern.matcher(orElse("")); } /** @@ -378,7 +391,7 @@ public class RequestQueryParam implements NameValuePair { * @return A new fluent assertion object. */ public FluentStringAssertion<RequestQueryParam> assertString() { - return new FluentStringAssertion<>(asString().orElse(null), this); + return new FluentStringAssertion<>(orElse(null), this); } /** diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCall.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCall.java index 00d45d7..270bac7 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCall.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCall.java @@ -469,7 +469,7 @@ public class RestCall { /** * Returns the output that was set by calling {@link RestResponse#setOutput(Object)}. - * + * * <p> * If it's empty, then {@link RestResponse#setOutput(Object)} wasn't called. * <br>If it's not empty but contains an empty, then <c>response.setObject(<jk>null</jk>)</c> was called. diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOperationContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOperationContext.java index e089fcf..3fb6370 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOperationContext.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOperationContext.java @@ -24,6 +24,7 @@ import static java.util.Collections.*; import java.lang.annotation.*; import java.lang.reflect.Method; +import java.nio.charset.*; import java.util.*; import java.util.concurrent.*; import java.util.function.*; @@ -658,7 +659,7 @@ public class RestOperationContext extends BeanContext implements Comparable<Rest private final List<org.apache.http.Header> defaultRequestHeaders, defaultResponseHeaders; private final List<NameValuePair> defaultRequestQuery, defaultRequestFormData; private final List<NamedAttribute> defaultRequestAttributes; - private final String defaultCharset; + private final Charset defaultCharset; private final long maxInput; private final List<MediaType> supportedAcceptTypes, @@ -763,7 +764,7 @@ public class RestOperationContext extends BeanContext implements Comparable<Rest _httpMethod = "*"; httpMethod = _httpMethod.toUpperCase(Locale.ENGLISH); - defaultCharset = cp.getString(REST_defaultCharset).orElse("utf-8"); + defaultCharset = Charset.forName(cp.getString(REST_defaultCharset).orElse("utf-8")); maxInput = StringUtils.parseLongWithSuffix(cp.get(REST_maxInput, String.class).orElse("100M")); @@ -1734,7 +1735,7 @@ public class RestOperationContext extends BeanContext implements Comparable<Rest * * @return The default charset. Never <jk>null</jk>. */ - public String getDefaultCharset() { + public Charset getDefaultCharset() { return defaultCharset; } diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java index 45eb25c..c7674bc 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java @@ -39,6 +39,7 @@ import javax.servlet.http.*; import org.apache.http.*; import org.apache.http.message.*; +import org.apache.http.params.*; import org.apache.juneau.*; import org.apache.juneau.assertions.*; import org.apache.juneau.config.*; @@ -103,7 +104,7 @@ import org.apache.juneau.utils.*; * </ul> */ @SuppressWarnings({ "unchecked", "unused" }) -public final class RestRequest extends HttpServletRequestWrapper { +public final class RestRequest implements HttpRequest { // Constructor initialized. private HttpServletRequest inner; @@ -125,22 +126,23 @@ public final class RestRequest extends HttpServletRequestWrapper { private VarResolverSession varSession; private RequestFormData formData; private UriContext uriContext; - private String charset, authorityPath; + private String authorityPath; private Config config; private Swagger swagger; + private Charset charset; /** * Constructor. */ RestRequest(RestCall call) throws Exception { - super(call.getRequest()); - this.call = call; this.opContext = call.getRestOperationContext(); inner = call.getRequest(); context = call.getContext(); + attrs = new RequestAttributes(this); + queryParams = new RequestQueryParams(this, call.getQueryParams(), true); headers = new RequestHeaders(this, queryParams, false); @@ -150,7 +152,7 @@ public final class RestRequest extends HttpServletRequestWrapper { if (context.isAllowBodyParam()) { String b = queryParams.getString("body").orElse(null); if (b != null) { - headers.put("Content-Type", UonSerializer.DEFAULT.getResponseContentType()); + headers.set("Content-Type", UonSerializer.DEFAULT.getResponseContentType()); body.load(MediaType.UON, UonParser.DEFAULT, b.getBytes(UTF8)); } } @@ -193,26 +195,25 @@ public final class RestRequest extends HttpServletRequestWrapper { .addDefault(context.getDefaultRequestHeaders()) .parser(partParserSession); - attrs = new RequestAttributes(this); - attrs - .addDefault(opContext.getDefaultRequestAttributes()) - .addDefault(context.getDefaultRequestAttributes()); - body .encoders(opContext.getEncoders()) .parsers(opContext.getParsers()) .headers(headers) .maxInput(opContext.getMaxInput()); + attrs + .addDefault(opContext.getDefaultRequestAttributes()) + .addDefault(context.getDefaultRequestAttributes()); + if (isDebug()) inner = CachingHttpServletRequest.wrap(inner); } - /** - * Returns a string of the form <js>"HTTP method-name full-url"</js> - * - * @return A description string of the request. - */ + //----------------------------------------------------------------------------------------------------------------- + // Request line. + //----------------------------------------------------------------------------------------------------------------- + + @Override /* HttpRequest */ public RequestLine getRequestLine() { String x = inner.getProtocol(); int i = x.indexOf('/'); @@ -221,11 +222,32 @@ public final class RestRequest extends HttpServletRequestWrapper { return new BasicRequestLine(inner.getMethod(), inner.getRequestURI(), pv); } + @Override /* HttpRequest */ + public ProtocolVersion getProtocolVersion() { + return getRequestLine().getProtocolVersion(); + } + //----------------------------------------------------------------------------------------------------------------- // Assertions //----------------------------------------------------------------------------------------------------------------- /** + * Returns an assertion on the request line returned by {@link #getRequestLine()}. + * + * <h5 class='section'>Example:</h5> + * <p class='bcode w800'> + * <jc>// Validates the request body contains "foo".</jc> + * <jv>request</jv> + * .assertRequestLine().protocol().minor().is(1); + * </p> + * + * @return A new assertion object. + */ + public FluentRequestLineAssertion<RestRequest> assertRequestLine() { + return new FluentRequestLineAssertion<RestRequest>(getRequestLine(), this); + } + + /** * Returns a fluent assertion for the request body. * * <h5 class='section'>Example:</h5> @@ -248,14 +270,14 @@ public final class RestRequest extends HttpServletRequestWrapper { * <p class='bcode w800'> * <jc>// Validates the content type is JSON.</jc> * <jv>request</jv> - * .assertHeader(<js>"Content-Type"</js>).asString().is(<js>"application/json"</js>); + * .assertHeader(<js>"Content-Type"</js>).is(<js>"application/json"</js>); * </p> * * @param name The header name. * @return A new fluent assertion on the parameter, never <jk>null</jk>. */ public FluentRequestHeaderAssertion<RestRequest> assertHeader(String name) { - return new FluentRequestHeaderAssertion<RestRequest>(getRequestHeader(name), this); + return new FluentRequestHeaderAssertion<RestRequest>(getHeader(name), this); } /** @@ -297,7 +319,7 @@ public final class RestRequest extends HttpServletRequestWrapper { * <jv>headers</jv>.addDefault(<js>"ETag"</js>, <jsf>DEFAULT_UUID</jsf>); * * <jc>// Get a header value as a POJO.</jc> - * UUID etag = <jv>headers</jv>.get(<js>"ETag"</js>).as(UUID.<jk>class</jk>).orElse(<jk>null</jk>); + * UUID etag = <jv>headers</jv>.get(<js>"ETag"</js>).asType(UUID.<jk>class</jk>).orElse(<jk>null</jk>); * * <jc>// Get a standard header.</jc> * Optional<CacheControl> = <jv>headers</jv>.getCacheControl(); @@ -328,21 +350,150 @@ public final class RestRequest extends HttpServletRequestWrapper { } /** - * Returns the last header with the specified name. + * Returns the last header with a specified name of this message. + * + * <p> + * If there is more than one matching header in the message the last element of <c>getHeaders(String)</c> is returned. + * <br>If there is no matching header in the message, an empty request header object is returned. * - * Unlike {@link #getHeader(String)}, this method returns an empty - * {@link ResponseHeader} object instead of returning <jk>null</jk>. This allows it to be used more easily - * in fluent calls. + * <p> + * This method is identical to {@link #getLastHeader(String)}. * + * <h5 class='section'>Example:</h5> * <p class='bcode w800'> - * <jv>req</jv>.getRequestHeader("Foo").asInteger().orElse(-1); + * <jc>// Gets a header and throws a BadRequest if it doesn't exist.</jc> + * <jv>request</jv> + * .getHeader(<js>"Foo"</js>) + * .assertValue().exists() + * .asString().get(); * </p> * * @param name The header name. - * @return The header. Never <jk>null</jk>. + * @return The request header object, never <jk>null</jk>. */ - public RequestHeader getRequestHeader(String name) { - return headers.getLast(name).parser(getPartParserSession()); + public RequestHeader getHeader(String name) { + return getLastHeader(name); + } + + /** + * Returns the last header with a specified name as a string value. + * + * <p> + * This method is equivalent to calling <c>getLastHeader(<jv>name</jv>).asString()</c>. + * + * @param name The header name. + * @return The request header value as a string, never <jk>null</jk>. + */ + public Optional<String> getStringHeader(String name) { + return getLastHeader(name).asString(); + } + + /** + * Returns the first header with a specified name of this message. + * + * <p> + * If there is more than one matching header in the message the first element of <c>getHeaders(String)</c> is returned. + * <br>If there is no matching header in the message, an empty request header object is returned. + * + * <h5 class='section'>Example:</h5> + * <p class='bcode w800'> + * <jc>// Gets a header and throws a BadRequest if it doesn't exist.</jc> + * <jv>request</jv> + * .getFirstHeader(<js>"Foo"</js>) + * .assertValue().exists() + * .asString().get(); + * </p> + * + * @param name The header name. + * @return The request header object, never <jk>null</jk>. + */ + @Override /* HttpRequest */ + public RequestHeader getFirstHeader(String name) { + return headers.getFirst(name); + } + + /** + * Returns the last header with a specified name of this message. + * + * <p> + * If there is more than one matching header in the message the last element of <c>getHeaders(String)</c> is returned. + * <br>If there is no matching header in the message, an empty request header object is returned. + * + * <h5 class='section'>Example:</h5> + * <p class='bcode w800'> + * <jc>// Gets a header and throws a BadRequest if it doesn't exist.</jc> + * <jv>request</jv> + * .getLastHeader(<js>"Foo"</js>) + * .assertValue().exists() + * .asString().get(); + * </p> + * + * @param name The header name. + * @return The request header object, never <jk>null</jk>. + */ + @Override /* HttpRequest */ + public RequestHeader getLastHeader(String name) { + return headers.getLast(name); + } + + @Override /* HttpRequest */ + public RequestHeader[] getAllHeaders() { + return headers.getAll().toArray(new RequestHeader[0]); + } + + @Override /* HttpRequest */ + public void addHeader(org.apache.http.Header header) { + headers.add(header); + } + + @Override /* HttpRequest */ + public void addHeader(String name, String value) { + headers.add(name, value); + } + + @Override /* HttpRequest */ + public void setHeader(org.apache.http.Header header) { + headers.set(header); + } + + @Override /* HttpRequest */ + public void setHeader(String name, String value) { + headers.set(name, value); + } + + @Override /* HttpRequest */ + public void setHeaders(org.apache.http.Header[] headers) { + this.headers.set(headers); + } + + @Override /* HttpRequest */ + public void removeHeader(org.apache.http.Header header) { + headers.remove(header); + } + + @Override /* HttpRequest */ + public void removeHeaders(String name) { + headers.remove(name); + } + + @Override /* HttpRequest */ + public HeaderIterator headerIterator() { + return headers.iterator(); + } + + @Override /* HttpRequest */ + public HeaderIterator headerIterator(String name) { + return headers.iterator(name); + } + + @Override /* HttpRequest */ + public boolean containsHeader(String name) { + return headers.contains(name); + } + + @Override /* HttpRequest */ + public RequestHeader[] getHeaders(String name) { + return headers.getAll(name).toArray(new RequestHeader[0]); } /** @@ -359,65 +510,52 @@ public final class RestRequest extends HttpServletRequestWrapper { * @throws HttpException If REST call failed. */ public FluentStringAssertion<RestRequest> assertCharset() { - return new FluentStringAssertion<>(getCharacterEncoding(), this); - } - - @Override /* ServletRequest */ - public String getHeader(String name) { - return getRequestHeaders().getString(name).orElse(null); - } - - @Override /* ServletRequest */ - public Enumeration<String> getHeaders(String name) { - return inner.getHeaders(name); + return new FluentStringAssertion<>(getCharset().name(), this); } /** * Sets the charset to expect on the request body. + * + * @param value The new value to use for the request body. */ - @Override /* ServletRequest */ - public void setCharacterEncoding(String charset) { - this.charset = charset; + public void setCharset(Charset value) { + this.charset = value; } /** * Returns the charset specified on the <c>Content-Type</c> header, or <js>"UTF-8"</js> if not specified. + * + * @return The charset to use to decode the request body. */ - @Override /* ServletRequest */ - public String getCharacterEncoding() throws UnsupportedMediaType { + public Charset getCharset() { if (charset == null) { // Determine charset // NOTE: Don't use super.getCharacterEncoding() because the spec is implemented inconsistently. // Jetty returns the default charset instead of null if the character is not specified on the request. - String h = getHeader("Content-Type"); + String h = getLastHeader("Content-Type").orElse(null); if (h != null) { int i = h.indexOf(";charset="); if (i > 0) - charset = h.substring(i+9).trim(); + charset = Charset.forName(h.substring(i+9).trim()); } if (charset == null) charset = opContext.getDefaultCharset(); if (charset == null) - charset = "UTF-8"; - if (! Charset.isSupported(charset)) - throw new UnsupportedMediaType("Unsupported charset in header ''Content-Type'': ''{0}''", h); + charset = Charset.forName("UTF-8"); } return charset; } /** - * Wrapper around {@link #getCharacterEncoding()} that converts the value to a {@link Charset}. + * Returns the preferred Locale that the client will accept content in, based on the Accept-Language header. + * + * <p> + * If the client request doesn't provide an <c>Accept-Language</c> header, this method returns the default locale for the server. * - * @return The request character encoding converted to a {@link Charset}. + * @return The preferred Locale that the client will accept content in. Never <jk>null</jk>. */ - public Charset getCharset() { - String s = getCharacterEncoding(); - return s == null ? null : Charset.forName(s); - } - - @Override /* ServletRequest */ public Locale getLocale() { - Locale best = super.getLocale(); + Locale best = inner.getLocale(); String h = headers.getString("Accept-Language").orElse(null); if (h != null) { StringRanges sr = StringRanges.of(h); @@ -432,21 +570,6 @@ public final class RestRequest extends HttpServletRequestWrapper { return best; } - @Override /* ServletRequest */ - public Enumeration<Locale> getLocales() { - String h = headers.getString("Accept-Language").orElse(null); - if (h != null) { - StringRanges mr = StringRanges.of(h); - if (! mr.getRanges().isEmpty()) { - List<Locale> l = new ArrayList<>(mr.getRanges().size()); - for (StringRange r : mr.getRanges()) - if (r.getQValue() > 0) - l.add(toLocale(r.getName())); - return enumeration(l); - } - } - return super.getLocales(); - } //----------------------------------------------------------------------------------------------------------------- // Attributes @@ -494,6 +617,26 @@ public final class RestRequest extends HttpServletRequestWrapper { return attrs; } + /** + * Returns the request attribute with the specified name. + * + * @param name The attribute name. + * @return The attribute value, never <jk>null</jk>. + */ + public Optional<Object> getAttribute(String name) { + return Optional.ofNullable(attrs.get(name)); + } + + /** + * Sets a request attribute. + * + * @param name The attribute name. + * @param value The attribute value. + */ + public void setAttribute(String name, Object value) { + attrs.put(name, value); + } + //----------------------------------------------------------------------------------------------------------------- // Query parameters //----------------------------------------------------------------------------------------------------------------- @@ -505,7 +648,7 @@ public final class RestRequest extends HttpServletRequestWrapper { * Returns a {@link RequestQueryParams} object that encapsulates access to URL GET parameters. * * <p> - * Similar to {@link #getParameterMap()} but only looks for query parameters in the URL and not form posts. + * Similar to {@link HttpServletRequest#getParameterMap()} but only looks for query parameters in the URL and not form posts. * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> @@ -561,7 +704,7 @@ public final class RestRequest extends HttpServletRequestWrapper { * Returns a {@link RequestFormData} object that encapsulates access to form post parameters. * * <p> - * Similar to {@link #getParameterMap()}, but only looks for form data in the HTTP body. + * Similar to {@link HttpServletRequest#getParameterMap()}, but only looks for form data in the HTTP body. * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> @@ -604,7 +747,7 @@ public final class RestRequest extends HttpServletRequestWrapper { if (formData == null) { formData = new RequestFormData(this, partParserSession); if (! body.isLoaded()) { - formData.putAll(getParameterMap()); + formData.putAll(inner.getParameterMap()); } else { Map<String,String[]> m = RestUtils.parseQuery(body.getReader()); for (Map.Entry<String,String[]> e : m.entrySet()) { @@ -749,8 +892,13 @@ public final class RestRequest extends HttpServletRequestWrapper { * * <p> * Automatically handles GZipped input streams. + * + * <p> + * This method is equivalent to calling <c>getBody().getReader()</c>. + * + * @return The HTTP body content as a {@link Reader}. + * @throws IOException If body could not be read. */ - @Override /* ServletRequest */ public BufferedReader getReader() throws IOException { return getBody().getReader(); } @@ -761,10 +909,12 @@ public final class RestRequest extends HttpServletRequestWrapper { * <p> * Automatically handles GZipped input streams. * + * <p> + * This method is equivalent to calling <c>getBody().getInputStream()</c>. + * * @return The negotiated input stream. * @throws IOException If any error occurred while trying to get the input stream or wrap it in the GZIP wrapper. */ - @Override /* ServletRequest */ public ServletInputStream getInputStream() throws IOException { return getBody().getInputStream(); } @@ -773,10 +923,20 @@ public final class RestRequest extends HttpServletRequestWrapper { // URI-related methods //----------------------------------------------------------------------------------------------------------------- - @Override /* HttpServletRequest */ + /** + * Returns the portion of the request URI that indicates the context of the request. + * + * <p>The context path always comes first in a request URI. + * The path starts with a <js>"/"</js> character but does not end with a <js>"/"</js> character. + * For servlets in the default (root) context, this method returns <js>""</js>. + * The container does not decode this string. + * + * @return The context path, never <jk>null</jk>. + * @see HttpServletRequest#getContextPath() + */ public String getContextPath() { String cp = context.getUriContext(); - return cp == null ? super.getContextPath() : cp; + return cp == null ? inner.getContextPath() : cp; } /** @@ -788,9 +948,9 @@ public final class RestRequest extends HttpServletRequestWrapper { if (authorityPath == null) authorityPath = context.getUriAuthority(); if (authorityPath == null) { - String scheme = getScheme(); - int port = getServerPort(); - StringBuilder sb = new StringBuilder(getScheme()).append("://").append(getServerName()); + String scheme = inner.getScheme(); + int port = inner.getServerPort(); + StringBuilder sb = new StringBuilder(inner.getScheme()).append("://").append(inner.getServerName()); if (! (port == 80 && "http".equals(scheme) || port == 443 && "https".equals(scheme))) sb.append(':').append(port); authorityPath = sb.toString(); @@ -798,10 +958,19 @@ public final class RestRequest extends HttpServletRequestWrapper { return authorityPath; } - @Override /* HttpServletRequest */ + /** + * Returns the part of this request's URL that calls the servlet. + * + * <p> + * This path starts with a <js>"/"</js> character and includes either the servlet name or a path to the servlet, + * but does not include any extra path information or a query string. + * + * @return The servlet path, never <jk>null</jk>. + * @see HttpServletRequest#getServletPath() + */ public String getServletPath() { String cp = context.getUriContext(); - String sp = super.getServletPath(); + String sp = inner.getServletPath(); return cp == null || ! sp.startsWith(cp) ? sp : sp.substring(cp.length()); } @@ -816,7 +985,7 @@ public final class RestRequest extends HttpServletRequestWrapper { */ public UriContext getUriContext() { if (uriContext == null) - uriContext = UriContext.of(getAuthorityPath(), getContextPath(), getServletPath(), StringUtils.urlEncodePath(super.getPathInfo())); + uriContext = UriContext.of(getAuthorityPath(), getContextPath(), getServletPath(), StringUtils.urlEncodePath(inner.getPathInfo())); return uriContext; } @@ -854,7 +1023,7 @@ public final class RestRequest extends HttpServletRequestWrapper { * @return A new URI. */ public URI getUri(boolean includeQuery, Map<String,?> addQueryParams) { - String uri = getRequestURI(); + String uri = inner.getRequestURI(); if (includeQuery || addQueryParams != null) { StringBuilder sb = new StringBuilder(uri); RequestQueryParams rq = this.queryParams.copy(); @@ -873,6 +1042,58 @@ public final class RestRequest extends HttpServletRequestWrapper { } } + /** + * Returns any extra path information associated with the URL the client sent when it made this request. + * + * <p> + * The extra path information follows the servlet path but precedes the query string and will start with a <js>"/"</js> character. + * This method returns <jk>null</jk> if there was no extra path information. + * + * @return The extra path information. + * @see HttpServletRequest#getPathInfo() + */ + public String getPathInfo() { + return inner.getPathInfo(); + } + + /** + * Returns the part of this request's URL from the protocol name up to the query string in the first line of the HTTP request. + * + * The web container does not decode this String + * + * @return The request URI. + * @see HttpServletRequest#getRequestURI() + */ + public String getRequestURI() { + return inner.getRequestURI(); + } + + + /** + * Returns the query string that is contained in the request URL after the path. + * + * <p> + * This method returns <jk>null</jk> if the URL does not have a query string. + * + * @return The query string. + * @see HttpServletRequest#getQueryString() + */ + public String getQueryString() { + return inner.getQueryString(); + } + + /** + * Reconstructs the URL the client used to make the request. + * + * <p> + * The returned URL contains a protocol, server name, port number, and server path, but it does not include query string parameters. + * + * @return The request URL. + * @see HttpServletRequest#getRequestURL() + */ + public StringBuffer getRequestURL() { + return inner.getRequestURL(); + } //----------------------------------------------------------------------------------------------------------------- // Labels //----------------------------------------------------------------------------------------------------------------- @@ -946,22 +1167,18 @@ public final class RestRequest extends HttpServletRequestWrapper { } /** - * Returns the method of this request. + * Returns the HTTP method of this request. * * <p> * If <c>allowHeaderParams</c> init parameter is <jk>true</jk>, then first looks for * <c>&method=xxx</c> in the URL query string. + * + * @return The HTTP method of this request. */ - @Override /* ServletRequest */ public String getMethod() { return call.getMethod(); } - @Override /* ServletRequest */ - public int getContentLength() { - return getBody().getContentLength(); - } - /** * Returns <jk>true</jk> if <c>&plainText=true</c> was specified as a URL parameter. * @@ -1060,7 +1277,7 @@ public final class RestRequest extends HttpServletRequestWrapper { * @return <jk>true</jk> if debug mode is enabled. */ public boolean isDebug() { - Boolean b = ObjectUtils.castOrNull(getAttribute("Debug"), Boolean.class); + Boolean b = ObjectUtils.castOrNull(getAttribute("Debug").orElse(null), Boolean.class); return b == null ? false : b; } @@ -1323,7 +1540,7 @@ public final class RestRequest extends HttpServletRequestWrapper { if (pt == FORMDATA) return getFormData().get(pp, schema, name, type); if (pt == HEADER) - return getRequestHeaders().getLast(name).parser(pp).schema(schema).asType(type); + return getLastHeader(name).parser(pp).schema(schema).asType(type); if (pt == PATH) return getPathMatch().get(pp, schema, name, type); } @@ -1366,6 +1583,48 @@ public final class RestRequest extends HttpServletRequestWrapper { } /** + * Not implemented. + */ + @SuppressWarnings("deprecation") + @Override + public HttpParams getParams() { + return null; + } + + /** + * Not implemented. + */ + @SuppressWarnings("deprecation") + @Override + public void setParams(HttpParams params) { + } + + /** + * Returns the current session associated with this request, or if the request does not have a session, creates one. + * + * @return The current request session. + * @see HttpServletRequest#getSession() + */ + public HttpSession getSession() { + return inner.getSession(); + } + + /** + * Returns a boolean indicating whether the authenticated user is included in the specified logical "role". + * + * <p> + * Roles and role membership can be defined using deployment descriptors. + * If the user has not been authenticated, the method returns false. + * + * @param role The role name. + * @return <jk>true</jk> if the user holds the specified role. + * @see HttpServletRequest#isUserInRole(String) + */ + public boolean isUserInRole(String role) { + return inner.isUserInRole(role); + } + + /** * Returns the wrapped servlet request. * * @return The wrapped servlet request. @@ -1378,9 +1637,8 @@ public final class RestRequest extends HttpServletRequestWrapper { public String toString() { StringBuilder sb = new StringBuilder("\n").append(getRequestLine()).append("\n"); sb.append("---Headers---\n"); - for (Enumeration<String> e = getHeaderNames(); e.hasMoreElements();) { - String h = e.nextElement(); - sb.append("\t").append(h).append(": ").append(getHeader(h)).append("\n"); + for (RequestHeader h : getAllHeaders()) { + sb.append("\t").append(h).append("\n"); } String m = getMethod(); if (m.equals("PUT") || m.equals("POST")) { diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java index aa2dad3..fc66df3 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java @@ -84,7 +84,7 @@ public final class RestResponse extends HttpServletResponseWrapper { RestContext context = call.getContext(); try { - String passThroughHeaders = request.getHeader("x-response-headers"); + String passThroughHeaders = request.getHeader("x-response-headers").orElse(null); if (passThroughHeaders != null) { HttpPartParser p = context.getPartParser(); OMap m = p.createPartSession(request.getParserSessionArgs()).parse(HEADER, null, passThroughHeaders, context.getClassMeta(OMap.class)); @@ -96,8 +96,8 @@ public final class RestResponse extends HttpServletResponseWrapper { } // Find acceptable charset - String h = request.getHeader("accept-charset"); - String charset = null; + String h = request.getHeader("accept-charset").orElse(null); + Charset charset = null; if (h == null) charset = opContext.getDefaultCharset(); else for (StringRange r : StringRanges.of(h).getRanges()) { @@ -105,7 +105,7 @@ public final class RestResponse extends HttpServletResponseWrapper { if (r.getName().equals("*")) charset = opContext.getDefaultCharset(); else if (Charset.isSupported(r.getName())) - charset = r.getName(); + charset = Charset.forName(r.getName()); if (charset != null) break; } @@ -117,8 +117,8 @@ public final class RestResponse extends HttpServletResponseWrapper { setHeaderSafe(e.getName(), stringify(e.getValue())); if (charset == null) - throw new NotAcceptable("No supported charsets in header ''Accept-Charset'': ''{0}''", request.getHeader("Accept-Charset")); - super.setCharacterEncoding(charset); + throw new NotAcceptable("No supported charsets in header ''Accept-Charset'': ''{0}''", request.getStringHeader("Accept-Charset").orElse(null)); + inner.setCharacterEncoding(charset.name()); } @@ -259,7 +259,7 @@ public final class RestResponse extends HttpServletResponseWrapper { Encoder encoder = null; EncoderGroup encoders = request.getOpContext().getEncoders(); - String ae = request.getHeader("Accept-Encoding"); + String ae = request.getHeader("Accept-Encoding").orElse(null); if (! (ae == null || ae.isEmpty())) { EncoderMatch match = encoders.getEncoderMatch(ae); if (match == null) { diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/assertions/FluentProtocolVersionAssertion.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/assertions/FluentProtocolVersionAssertion.java new file mode 100644 index 0000000..1a8aaad --- /dev/null +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/assertions/FluentProtocolVersionAssertion.java @@ -0,0 +1,90 @@ +// *************************************************************************************************************************** +// * 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.assertions; + +import org.apache.http.*; +import org.apache.juneau.assertions.*; +import org.apache.juneau.http.exception.*; +import org.apache.juneau.internal.*; + +/** + * Used for fluent assertion calls against {@link ProtocolVersion} objects. + * + * @param <R> The return type. + */ +@FluentSetters(returns="FluentProtocolVersionAssertion<R>") +public class FluentProtocolVersionAssertion<R> extends FluentAssertion<R> { + + private final ProtocolVersion value; + + /** + * Constructor. + * + * @param value The object being tested. + * @param returns The object to return after the test. + */ + public FluentProtocolVersionAssertion(ProtocolVersion value, R returns) { + super(null, returns); + this.value = value; + throwable(BadRequest.class); + } + + /** + * Returns the protocol string as a new assertion. + * + * @return A new assertion. + */ + public FluentStringAssertion<R> protocol() { + return new FluentStringAssertion<>(value.getProtocol(), returns()); + } + + /** + * Returns the protocol major version as a new assertion. + * + * @return A new assertion. + */ + public FluentIntegerAssertion<R> major() { + return new FluentIntegerAssertion<>(value.getMajor(), returns()); + } + + /** + * Returns the protocol minor version as a new assertion. + * + * @return A new assertion. + */ + public FluentIntegerAssertion<R> minor() { + return new FluentIntegerAssertion<>(value.getMinor(), returns()); + } + + // <FluentSetters> + + @Override /* GENERATED - Assertion */ + public FluentProtocolVersionAssertion<R> msg(String msg, Object...args) { + super.msg(msg, args); + return this; + } + + @Override /* GENERATED - Assertion */ + public FluentProtocolVersionAssertion<R> stderr() { + super.stderr(); + return this; + } + + @Override /* GENERATED - Assertion */ + public FluentProtocolVersionAssertion<R> stdout() { + super.stdout(); + return this; + } + + // </FluentSetters> +} diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/assertions/FluentRequestLineAssertion.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/assertions/FluentRequestLineAssertion.java new file mode 100644 index 0000000..cc73691 --- /dev/null +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/assertions/FluentRequestLineAssertion.java @@ -0,0 +1,91 @@ +// *************************************************************************************************************************** +// * 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.assertions; + +import org.apache.http.*; +import org.apache.juneau.assertions.*; +import org.apache.juneau.http.exception.*; +import org.apache.juneau.internal.*; + +/** + * Used for fluent assertion calls against {@link RequestLine} objects. + * + * @param <R> The return type. + */ +@FluentSetters(returns="FluentRequestLineAssertion<R>") +public class FluentRequestLineAssertion<R> extends FluentAssertion<R> { + + private final RequestLine value; + + /** + * Constructor. + * + * @param value The object being tested. + * @param returns The object to return after the test. + */ + public FluentRequestLineAssertion(RequestLine value, R returns) { + super(null, returns); + this.value = value; + throwable(BadRequest.class); + } + + /** + * Returns the request line method string as a new assertion. + * + * @return A new assertion. + */ + public FluentStringAssertion<R> method() { + return new FluentStringAssertion<>(value.getMethod(), returns()); + } + + /** + * Returns the request line uri string as a new assertion. + * + * @return A new assertion. + */ + public FluentStringAssertion<R> uri() { + return new FluentStringAssertion<>(value.getUri(), returns()); + } + + /** + * Returns the request line protocol version as a new assertion. + * + * @return A new assertion. + */ + public FluentProtocolVersionAssertion<R> protocolVersion() { + return new FluentProtocolVersionAssertion<>(value.getProtocolVersion(), returns()); + } + + // <FluentSetters> + + @Override /* GENERATED - Assertion */ + public FluentRequestLineAssertion<R> msg(String msg, Object...args) { + super.msg(msg, args); + return this; + } + + @Override /* GENERATED - Assertion */ + public FluentRequestLineAssertion<R> stderr() { + super.stderr(); + return this; + } + + @Override /* GENERATED - Assertion */ + public FluentRequestLineAssertion<R> stdout() { + super.stdout(); + return this; + } + + + // </FluentSetters> +} diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicRestLogger.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicRestLogger.java index 3a72bfd..2af886a 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicRestLogger.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicRestLogger.java @@ -335,8 +335,6 @@ public class BasicRestLogger implements RestLogger { } private byte[] getRequestBody(HttpServletRequest req) { - if (req instanceof RestRequest) - req = ((RestRequest)req).getHttpServletRequest(); if (req instanceof CachingHttpServletRequest) return ((CachingHttpServletRequest)req).getBody(); return castOrNull(req.getAttribute("RequestBody"), byte[].class); diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestHeaderVar.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestHeaderVar.java index 49bf226..0a34d85 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestHeaderVar.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestHeaderVar.java @@ -67,7 +67,7 @@ public class RequestHeaderVar extends MultipartResolvingVar { @Override /* Var */ public String resolve(VarResolverSession session, String key) { - return session.getBean(RestRequest.class).orElseThrow(InternalServerError::new).getHeader(key); + return session.getBean(RestRequest.class).orElseThrow(InternalServerError::new).getHeader(key).orElse(null); } @Override /* Var */ diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestQueryVar.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestQueryVar.java index c2a166a..613ed50 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestQueryVar.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestQueryVar.java @@ -68,7 +68,7 @@ public class RequestQueryVar extends MultipartResolvingVar { @Override /* Var */ public String resolve(VarResolverSession session, String key) { - return session.getBean(RestRequest.class).orElseThrow(InternalServerError::new).getRequestQueryParam(key).asString().orElse(null); + return session.getBean(RestRequest.class).orElseThrow(InternalServerError::new).getRequestQueryParam(key).orElse(null); } @Override /* Var */ diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java index c2d8fd5..aa7063e 100644 --- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java +++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java @@ -172,11 +172,7 @@ public abstract class MenuItemWidget extends Widget { } private Integer getId(RestRequest req) { - Integer id = (Integer)req.getAttribute("LastMenuItemId"); - if (id == null) - id = 1; - else - id = id + 1; + Integer id = (Integer)req.getAttribute("LastMenuItemId").orElse(0) + 1; req.setAttribute("LastMenuItemId", id); return id; } diff --git a/juneau-utest/src/test/java/org/apache/juneau/http/SerializedHttpEntity_Test.java b/juneau-utest/src/test/java/org/apache/juneau/http/SerializedHttpEntity_Test.java index 1f26306..fd97286 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/http/SerializedHttpEntity_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/http/SerializedHttpEntity_Test.java @@ -41,7 +41,7 @@ public class SerializedHttpEntity_Test { public static class A extends BasicRestObject { @RestPost public String[] checkHeader(org.apache.juneau.rest.RestRequest req) { - return req.getRequestHeaders().getAll(req.getHeader("Check")).stream().map(x -> x.getValue()).toArray(String[]::new); + return req.getRequestHeaders().getAll(req.getStringHeader("Check").get()).stream().map(x -> x.getValue()).toArray(String[]::new); } @RestPost public Reader checkBody(org.apache.juneau.rest.RestRequest req) throws IOException { diff --git a/juneau-utest/src/test/java/org/apache/juneau/http/remote/Remote_Test.java b/juneau-utest/src/test/java/org/apache/juneau/http/remote/Remote_Test.java index 4a8e628..b00359a 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/http/remote/Remote_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/http/remote/Remote_Test.java @@ -567,7 +567,7 @@ public class Remote_Test { public static class F extends BasicRestObject { @RestGet public String[] headers(org.apache.juneau.rest.RestRequest req) { - return req.getRequestHeaders().getAll(req.getHeader("Check")).stream().map(x -> x.getValue()).toArray(String[]::new); + return req.getRequestHeaders().getAll(req.getHeader("Check").orElse(null)).stream().map(x -> x.getValue()).toArray(String[]::new); } } diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/Header_AcceptCharset_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/Header_AcceptCharset_Test.java index 6f992d7..31ed25a 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/rest/Header_AcceptCharset_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/rest/Header_AcceptCharset_Test.java @@ -45,15 +45,15 @@ public class Header_AcceptCharset_Test { public void a01_qValues() throws Exception { RestClient a = MockRestClient.build(A.class); a.get("/a").accept("text/plain").acceptCharset("utf-8").run().assertCharset().is("utf-8"); - a.get("/a").accept("text/plain").acceptCharset("iso-8859-1").run().assertCharset().is("iso-8859-1"); + a.get("/a").accept("text/plain").acceptCharset("iso-8859-1").run().assertCharset().is("ISO-8859-1"); a.get("/a").accept("text/plain").acceptCharset("bad,utf-8").run().assertCharset().is("utf-8"); a.get("/a").accept("text/plain").acceptCharset("utf-8,bad").run().assertCharset().is("utf-8"); a.get("/a").accept("text/plain").acceptCharset("bad;q=0.9,utf-8;q=0.1").run().assertCharset().is("utf-8"); a.get("/a").accept("text/plain").acceptCharset("bad;q=0.1,utf-8;q=0.9").run().assertCharset().is("utf-8"); a.get("/a").accept("text/plain").acceptCharset("utf-8;q=0.9,iso-8859-1;q=0.1").run().assertCharset().is("utf-8"); - a.get("/a").accept("text/plain").acceptCharset("utf-8;q=0.1,iso-8859-1;q=0.9").run().assertCharset().is("iso-8859-1"); + a.get("/a").accept("text/plain").acceptCharset("utf-8;q=0.1,iso-8859-1;q=0.9").run().assertCharset().is("ISO-8859-1"); a.get("/a").accept("text/plain").acceptCharset("*").run().assertCharset().is("utf-8"); - a.get("/a").accept("text/plain").acceptCharset("bad,iso-8859-1;q=0.5,*;q=0.1").run().assertCharset().is("iso-8859-1"); + a.get("/a").accept("text/plain").acceptCharset("bad,iso-8859-1;q=0.5,*;q=0.1").run().assertCharset().is("ISO-8859-1"); a.get("/a").accept("text/plain").acceptCharset("bad,iso-8859-1;q=0.1,*;q=0.5").run().assertCharset().is("utf-8"); } diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/RestOp_Params_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/RestOp_Params_Test.java index f711850..dcf6af9 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/rest/RestOp_Params_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/rest/RestOp_Params_Test.java @@ -386,7 +386,7 @@ public class RestOp_Params_Test { @Override public Object resolve(RestCall call) throws Exception { - return new B2b(call.getRestRequest().getHeader("Custom")); + return new B2b(call.getRestRequest().getStringHeader("Custom").orElse(null)); } } diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/RestHook_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/RestHook_Test.java index 30cb8e3..053153e 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/RestHook_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/RestHook_Test.java @@ -58,9 +58,9 @@ public class RestHook_Test { attrs.put("p2", "xp2"); attrs.put("p4", "xp4"); attrs.put("p5", "xp5"); // New property - String overrideContentType = req.getHeader("Override-Content-Type"); + String overrideContentType = req.getStringHeader("Override-Content-Type").orElse(null); if (overrideContentType != null) - req.getRequestHeaders().put("Content-Type", overrideContentType); + req.getRequestHeaders().set("Content-Type", overrideContentType); } @RestPut( @@ -128,10 +128,10 @@ public class RestHook_Test { attrs.put("p2", "xp2"); attrs.put("p4", "xp4"); attrs.put("p5", "xp5"); // New property - String overrideAccept = req.getHeader("Override-Accept"); + String overrideAccept = req.getStringHeader("Override-Accept").orElse(null); if (overrideAccept != null) - req.getRequestHeaders().put("Accept", overrideAccept); - String overrideContentType = req.getHeader("Override-Content-Type"); + req.getRequestHeaders().set("Accept", overrideAccept); + String overrideContentType = req.getStringHeader("Override-Content-Type").orElse(null); if (overrideContentType != null) attrs.put("Override-Content-Type", overrideContentType); } @@ -151,9 +151,9 @@ public class RestHook_Test { public String b(RestRequest req, RequestAttributes attrs) throws Exception { attrs.put("p3", "pp3"); attrs.put("p4", "pp4"); - String accept = req.getHeader("Accept"); + String accept = req.getStringHeader("Accept").orElse(null); if (accept == null || accept.isEmpty()) - req.getRequestHeaders().put("Accept", "text/s2"); + req.getRequestHeaders().set("Accept", "text/s2"); return null; } } diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_BasicCalls_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_BasicCalls_Test.java index 0df76cc..4e8c688 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_BasicCalls_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_BasicCalls_Test.java @@ -83,7 +83,7 @@ public class RestClient_BasicCalls_Test { } @RestOp(path="/checkHeader") public String[] postHeader(org.apache.juneau.rest.RestRequest req) { - return req.getRequestHeaders().getAll(req.getHeader("Check")).stream().map(x -> x.getValue()).toArray(String[]::new); + return req.getRequestHeaders().getAll(req.getStringHeader("Check").orElse(null)).stream().map(x -> x.getValue()).toArray(String[]::new); } @RestOp(path="/",method="*") public Reader echoMethod(@Method String method) { diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Config_BeanContext_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Config_BeanContext_Test.java index 8ba94d1..092cbb0 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Config_BeanContext_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Config_BeanContext_Test.java @@ -41,7 +41,7 @@ public class RestClient_Config_BeanContext_Test { } @RestGet public String[] checkHeader(org.apache.juneau.rest.RestRequest req) { - return req.getRequestHeaders().getAll(req.getHeader("Check")).stream().map(x -> x.getValue()).toArray(String[]::new); + return req.getRequestHeaders().getAll(req.getStringHeader("Check").orElse(null)).stream().map(x -> x.getValue()).toArray(String[]::new); } @RestGet public Reader checkQuery(org.apache.juneau.rest.RestRequest req) { diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Config_OpenApi_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Config_OpenApi_Test.java index 455ea2a..3050f5a 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Config_OpenApi_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Config_OpenApi_Test.java @@ -36,7 +36,7 @@ public class RestClient_Config_OpenApi_Test { } @RestGet public String[] checkHeader(org.apache.juneau.rest.RestRequest req) { - return req.getRequestHeaders().getAll(req.getHeader("Check")).stream().map(x -> x.getValue()).toArray(String[]::new); + return req.getRequestHeaders().getAll(req.getStringHeader("Check").orElse(null)).stream().map(x -> x.getValue()).toArray(String[]::new); } @RestGet public Reader checkQuery(org.apache.juneau.rest.RestRequest req) { diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Config_RestClient_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Config_RestClient_Test.java index 86db999..92653e3 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Config_RestClient_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Config_RestClient_Test.java @@ -86,7 +86,7 @@ public class RestClient_Config_RestClient_Test { } @RestOp(path="/checkHeader") public String[] getHeader(org.apache.juneau.rest.RestRequest req) { - return req.getRequestHeaders().getAll(req.getHeader("Check")).stream().map(x -> x.getValue()).toArray(String[]::new); + return req.getRequestHeaders().getAll(req.getStringHeader("Check").orElse(null)).stream().map(x -> x.getValue()).toArray(String[]::new); } } diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Headers_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Headers_Test.java index f29355d..08b3fc8 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Headers_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Headers_Test.java @@ -58,7 +58,7 @@ public class RestClient_Headers_Test { public static class A extends BasicRestObject { @RestGet public String[] headers(org.apache.juneau.rest.RestRequest req) { - return req.getRequestHeaders().getAll(req.getHeader("Check")).stream().map(x -> x.getValue()).toArray(String[]::new); + return req.getRequestHeaders().getAll(req.getStringHeader("Check").get()).stream().map(x -> x.getValue()).toArray(String[]::new); } } diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Response_Headers_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Response_Headers_Test.java index bac5c35..57892dc 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Response_Headers_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Response_Headers_Test.java @@ -36,8 +36,8 @@ public class RestClient_Response_Headers_Test { public static class A extends BasicRestObject { @RestGet public String echo(org.apache.juneau.rest.RestRequest req, org.apache.juneau.rest.RestResponse res) { - String c = req.getHeader("Check"); - String[] h = req.getRequestHeaders().getAll(req.getHeader("Check")).stream().map(x -> x.getValue()).toArray(String[]::new); + String c = req.getStringHeader("Check").get(); + String[] h = req.getRequestHeaders().getAll(c).stream().map(x -> x.getValue()).toArray(String[]::new); if (h != null) for (String hh : h) res.addHeader(c, hh); diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Response_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Response_Test.java index 14ab963..3b43a3c 100644 --- a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Response_Test.java +++ b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Response_Test.java @@ -149,7 +149,7 @@ public class RestClient_Response_Test { public static class C extends BasicRestObject { @RestGet(path="/") public String getHeader(org.apache.juneau.rest.RestRequest req, org.apache.juneau.rest.RestResponse res) { - String n = req.getHeader("Check"); + String n = req.getStringHeader("Check").get(); String v = req.getRequestHeaders().getString(n).orElse(null); res.setHeader(n,v); return v;