Nullability fine-tuning and related polishing
Issue: SPR-17250
This commit is contained in:
parent
5f2d47a17e
commit
58b3af9475
|
|
@ -31,7 +31,7 @@ import org.springframework.util.MultiValueMap;
|
|||
* {@code HttpHeaders} object that can only be read, not written to.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 5.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class ReadOnlyHttpHeaders extends HttpHeaders {
|
||||
|
||||
|
|
@ -59,10 +59,7 @@ class ReadOnlyHttpHeaders extends HttpHeaders {
|
|||
@Override
|
||||
public List<String> get(Object key) {
|
||||
List<String> values = this.headers.get(key);
|
||||
if (values != null) {
|
||||
return Collections.unmodifiableList(values);
|
||||
}
|
||||
return values;
|
||||
return (values != null ? Collections.unmodifiableList(values) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -36,16 +36,18 @@ import org.springframework.util.MultiValueMap;
|
|||
* {@code MultiValueMap} implementation for wrapping Jetty HTTP headers.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 5.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
||||
|
||||
private final HttpFields headers;
|
||||
|
||||
|
||||
JettyHeadersAdapter(HttpFields headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getFirst(String key) {
|
||||
return this.headers.get(key);
|
||||
|
|
@ -95,24 +97,18 @@ class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
|||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.headers.size() == 0;
|
||||
return (this.headers.size() == 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
if (key instanceof String) {
|
||||
return this.headers.containsKey((String) key);
|
||||
}
|
||||
return false;
|
||||
return (key instanceof String && this.headers.containsKey((String) key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
if (value instanceof String) {
|
||||
return this.headers.stream()
|
||||
.anyMatch(field -> field.contains((String) value));
|
||||
}
|
||||
return false;
|
||||
return (value instanceof String &&
|
||||
this.headers.stream().anyMatch(field -> field.contains((String) value)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
@ -144,8 +140,8 @@ class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends List<String>> m) {
|
||||
m.forEach(this::put);
|
||||
public void putAll(Map<? extends String, ? extends List<String>> map) {
|
||||
map.forEach(this::put);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -179,6 +175,7 @@ class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
private class EntryIterator implements Iterator<Entry<String, List<String>>> {
|
||||
|
||||
private Enumeration<String> names = headers.getFieldNames();
|
||||
|
|
@ -194,6 +191,7 @@ class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private class HeaderEntry implements Entry<String, List<String>> {
|
||||
|
||||
private final String key;
|
||||
|
|
@ -204,7 +202,7 @@ class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
|||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return this.key.toString();
|
||||
return this.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -219,4 +217,5 @@ class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
|||
return previousValues;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,12 +34,14 @@ import org.springframework.core.io.buffer.DataBuffer;
|
|||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ServletHttpHandlerAdapter} extension that uses Jetty APIs for writing
|
||||
* to the response with {@link ByteBuffer}.
|
||||
*
|
||||
* @author Violeta Georgieva
|
||||
* @author Brian Clozel
|
||||
* @since 5.0
|
||||
* @see org.springframework.web.server.adapter.AbstractReactiveWebInitializer
|
||||
*/
|
||||
|
|
@ -53,6 +55,8 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
|||
@Override
|
||||
protected ServletServerHttpRequest createRequest(HttpServletRequest request, AsyncContext context)
|
||||
throws IOException, URISyntaxException {
|
||||
|
||||
Assert.notNull(getServletPath(), "Servlet path is not initialized");
|
||||
return new JettyServerHttpRequest(request, context, getServletPath(), getDataBufferFactory(), getBufferSize());
|
||||
}
|
||||
|
||||
|
|
@ -64,6 +68,7 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
|||
response, context, getDataBufferFactory(), getBufferSize(), request);
|
||||
}
|
||||
|
||||
|
||||
private static final class JettyServerHttpRequest extends ServletServerHttpRequest {
|
||||
|
||||
JettyServerHttpRequest(HttpServletRequest request, AsyncContext asyncContext,
|
||||
|
|
|
|||
|
|
@ -34,16 +34,18 @@ import org.springframework.util.MultiValueMap;
|
|||
* {@code MultiValueMap} implementation for wrapping Netty HTTP headers.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 5.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class NettyHeadersAdapter implements MultiValueMap<String, String> {
|
||||
|
||||
private final HttpHeaders headers;
|
||||
|
||||
|
||||
NettyHeadersAdapter(HttpHeaders headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getFirst(String key) {
|
||||
|
|
@ -99,14 +101,14 @@ class NettyHeadersAdapter implements MultiValueMap<String, String> {
|
|||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return (key instanceof String) && this.headers.contains((String) key);
|
||||
return (key instanceof String && this.headers.contains((String) key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return (value instanceof String) &&
|
||||
return (value instanceof String &&
|
||||
this.headers.entries().stream()
|
||||
.anyMatch(entry -> value != null && value.equals(entry.getValue()));
|
||||
.anyMatch(entry -> value.equals(entry.getValue())));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -138,8 +140,8 @@ class NettyHeadersAdapter implements MultiValueMap<String, String> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends List<String>> m) {
|
||||
m.forEach(this.headers::add);
|
||||
public void putAll(Map<? extends String, ? extends List<String>> map) {
|
||||
map.forEach(this.headers::add);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -173,6 +175,7 @@ class NettyHeadersAdapter implements MultiValueMap<String, String> {
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
private class EntryIterator implements Iterator<Entry<String, List<String>>> {
|
||||
|
||||
private Iterator<String> names = headers.names().iterator();
|
||||
|
|
@ -188,6 +191,7 @@ class NettyHeadersAdapter implements MultiValueMap<String, String> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private class HeaderEntry implements Entry<String, List<String>> {
|
||||
|
||||
private final String key;
|
||||
|
|
|
|||
|
|
@ -38,23 +38,25 @@ import org.springframework.util.MultiValueMap;
|
|||
* {@code MultiValueMap} implementation for wrapping Tomcat HTTP headers.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 5.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class TomcatHeadersAdapter implements MultiValueMap<String, String> {
|
||||
|
||||
private final MimeHeaders headers;
|
||||
|
||||
|
||||
TomcatHeadersAdapter(MimeHeaders headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getFirst(String key) {
|
||||
return this.headers.getHeader(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(String key, String value) {
|
||||
public void add(String key, @Nullable String value) {
|
||||
this.headers.addValue(key).setString(value);
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +71,7 @@ class TomcatHeadersAdapter implements MultiValueMap<String, String> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void set(String key, String value) {
|
||||
public void set(String key, @Nullable String value) {
|
||||
this.headers.setValue(key).setString(value);
|
||||
}
|
||||
|
||||
|
|
@ -98,13 +100,13 @@ class TomcatHeadersAdapter implements MultiValueMap<String, String> {
|
|||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.headers.size() == 0;
|
||||
return (this.headers.size() == 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
if (key instanceof String) {
|
||||
return this.headers.findHeader((String) key, 0) != -1;
|
||||
return (this.headers.findHeader((String) key, 0) != -1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -152,8 +154,8 @@ class TomcatHeadersAdapter implements MultiValueMap<String, String> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends List<String>> m) {
|
||||
m.forEach(this::put);
|
||||
public void putAll(Map<? extends String, ? extends List<String>> map) {
|
||||
map.forEach(this::put);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -191,6 +193,7 @@ class TomcatHeadersAdapter implements MultiValueMap<String, String> {
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
private class EntryIterator implements Iterator<Entry<String, List<String>>> {
|
||||
|
||||
private Enumeration<String> names = headers.names();
|
||||
|
|
@ -206,11 +209,12 @@ class TomcatHeadersAdapter implements MultiValueMap<String, String> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private final class HeaderEntry implements Entry<String, List<String>> {
|
||||
|
||||
private final String key;
|
||||
|
||||
private HeaderEntry(String key) {
|
||||
HeaderEntry(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
|
|
@ -234,4 +238,5 @@ class TomcatHeadersAdapter implements MultiValueMap<String, String> {
|
|||
return previous;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ import org.springframework.util.ReflectionUtils;
|
|||
*
|
||||
* @author Violeta Georgieva
|
||||
* @author Brian Clozel
|
||||
* @author Brian Clozel
|
||||
* @since 5.0
|
||||
* @see org.springframework.web.server.adapter.AbstractReactiveWebInitializer
|
||||
*/
|
||||
|
|
@ -64,7 +63,7 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
|||
protected ServletServerHttpRequest createRequest(HttpServletRequest request, AsyncContext asyncContext)
|
||||
throws IOException, URISyntaxException {
|
||||
|
||||
Assert.notNull(getServletPath(), "servletPath is not initialized.");
|
||||
Assert.notNull(getServletPath(), "Servlet path is not initialized");
|
||||
return new TomcatServerHttpRequest(
|
||||
request, asyncContext, getServletPath(), getDataBufferFactory(), getBufferSize());
|
||||
}
|
||||
|
|
@ -77,16 +76,20 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
|||
response, asyncContext, getDataBufferFactory(), getBufferSize(), request);
|
||||
}
|
||||
|
||||
|
||||
private static final class TomcatServerHttpRequest extends ServletServerHttpRequest {
|
||||
|
||||
private static final Field COYOTE_REQUEST_FIELD = ReflectionUtils.findField(RequestFacade.class, "request");
|
||||
private static final Field COYOTE_REQUEST_FIELD;
|
||||
|
||||
private final int bufferSize;
|
||||
|
||||
private final DataBufferFactory factory;
|
||||
|
||||
static {
|
||||
ReflectionUtils.makeAccessible(COYOTE_REQUEST_FIELD);
|
||||
Field field = ReflectionUtils.findField(RequestFacade.class, "request");
|
||||
Assert.state(field != null, "Incompatible Tomcat implementation");
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
COYOTE_REQUEST_FIELD = field;
|
||||
}
|
||||
|
||||
TomcatServerHttpRequest(HttpServletRequest request, AsyncContext context,
|
||||
|
|
@ -99,8 +102,10 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
|||
}
|
||||
|
||||
private static HttpHeaders createTomcatHttpHeaders(HttpServletRequest request) {
|
||||
Request tomcatRequest = ((org.apache.catalina.connector.Request) ReflectionUtils
|
||||
.getField(COYOTE_REQUEST_FIELD, request)).getCoyoteRequest();
|
||||
org.apache.catalina.connector.Request connectorRequest = (org.apache.catalina.connector.Request)
|
||||
ReflectionUtils.getField(COYOTE_REQUEST_FIELD, request);
|
||||
Assert.state(connectorRequest != null, "No Tomcat connector request");
|
||||
Request tomcatRequest = connectorRequest.getCoyoteRequest();
|
||||
TomcatHeadersAdapter headers = new TomcatHeadersAdapter(tomcatRequest.getMimeHeaders());
|
||||
return new HttpHeaders(headers);
|
||||
}
|
||||
|
|
@ -112,11 +117,9 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
|||
DataBuffer dataBuffer = this.factory.allocateBuffer(capacity);
|
||||
try {
|
||||
ByteBuffer byteBuffer = dataBuffer.asByteBuffer(0, capacity);
|
||||
|
||||
ServletRequest request = getNativeRequest();
|
||||
int read = ((CoyoteInputStream) request.getInputStream()).read(byteBuffer);
|
||||
logBytesRead(read);
|
||||
|
||||
if (read > 0) {
|
||||
dataBuffer.writePosition(read);
|
||||
release = false;
|
||||
|
|
@ -140,10 +143,13 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
|||
|
||||
private static final class TomcatServerHttpResponse extends ServletServerHttpResponse {
|
||||
|
||||
private static final Field COYOTE_RESPONSE_FIELD = ReflectionUtils.findField(ResponseFacade.class, "response");
|
||||
private static final Field COYOTE_RESPONSE_FIELD;
|
||||
|
||||
static {
|
||||
ReflectionUtils.makeAccessible(COYOTE_RESPONSE_FIELD);
|
||||
Field field = ReflectionUtils.findField(ResponseFacade.class, "response");
|
||||
Assert.state(field != null, "Incompatible Tomcat implementation");
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
COYOTE_RESPONSE_FIELD = field;
|
||||
}
|
||||
|
||||
TomcatServerHttpResponse(HttpServletResponse response, AsyncContext context,
|
||||
|
|
@ -153,8 +159,10 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
|||
}
|
||||
|
||||
private static HttpHeaders createTomcatHttpHeaders(HttpServletResponse response) {
|
||||
Response tomcatResponse = ((org.apache.catalina.connector.Response) ReflectionUtils
|
||||
.getField(COYOTE_RESPONSE_FIELD, response)).getCoyoteResponse();
|
||||
org.apache.catalina.connector.Response connectorResponse = (org.apache.catalina.connector.Response)
|
||||
ReflectionUtils.getField(COYOTE_RESPONSE_FIELD, response);
|
||||
Assert.state(connectorResponse != null, "No Tomcat connector response");
|
||||
Response tomcatResponse = connectorResponse.getCoyoteResponse();
|
||||
TomcatHeadersAdapter headers = new TomcatHeadersAdapter(tomcatResponse.getMimeHeaders());
|
||||
return new HttpHeaders(headers);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,16 +36,18 @@ import org.springframework.util.MultiValueMap;
|
|||
* {@code MultiValueMap} implementation for wrapping Undertow HTTP headers.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 5.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class UndertowHeadersAdapter implements MultiValueMap<String, String> {
|
||||
|
||||
private final HeaderMap headers;
|
||||
|
||||
|
||||
UndertowHeadersAdapter(HeaderMap headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getFirst(String key) {
|
||||
return this.headers.getFirst(key);
|
||||
|
|
@ -92,25 +94,20 @@ class UndertowHeadersAdapter implements MultiValueMap<String, String> {
|
|||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.headers.size() == 0;
|
||||
return (this.headers.size() == 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
if (key instanceof String) {
|
||||
return this.headers.contains((String) key);
|
||||
}
|
||||
return false;
|
||||
return (key instanceof String && this.headers.contains((String) key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
if (value instanceof String) {
|
||||
return this.headers.getHeaderNames().stream()
|
||||
.map(this.headers::get)
|
||||
.anyMatch(values -> values.contains(value));
|
||||
}
|
||||
return false;
|
||||
return (value instanceof String &&
|
||||
this.headers.getHeaderNames().stream()
|
||||
.map(this.headers::get)
|
||||
.anyMatch(values -> values.contains(value)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -140,8 +137,8 @@ class UndertowHeadersAdapter implements MultiValueMap<String, String> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends List<String>> m) {
|
||||
m.forEach((key, values) ->
|
||||
public void putAll(Map<? extends String, ? extends List<String>> map) {
|
||||
map.forEach((key, values) ->
|
||||
this.headers.putAll(HttpString.tryFromString(key), values));
|
||||
}
|
||||
|
||||
|
|
@ -179,6 +176,7 @@ class UndertowHeadersAdapter implements MultiValueMap<String, String> {
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
private class EntryIterator implements Iterator<Entry<String, List<String>>> {
|
||||
|
||||
private Iterator<HttpString> names = headers.getHeaderNames().iterator();
|
||||
|
|
@ -194,6 +192,7 @@ class UndertowHeadersAdapter implements MultiValueMap<String, String> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private class HeaderEntry implements Entry<String, List<String>> {
|
||||
|
||||
private final HttpString key;
|
||||
|
|
@ -219,4 +218,5 @@ class UndertowHeadersAdapter implements MultiValueMap<String, String> {
|
|||
return previousValues;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue