From db48b546ac2b95b74cf99197cfd2092d7f63b230 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 25 Sep 2020 12:20:37 +0200 Subject: [PATCH] Polishing --- .../org/springframework/util/MimeType.java | 7 ++-- .../MappingJackson2MessageConverter.java | 6 +-- .../converter/AbstractMessageConverter.java | 42 ++++++++++--------- .../MappingJackson2MessageConverter.java | 8 ++-- .../MarshallingMessageConverter.java | 7 +++- .../MappingJackson2MessageConverterTests.java | 18 ++++---- .../codec/json/AbstractJackson2Decoder.java | 2 +- .../http/codec/json/Jackson2CodecSupport.java | 4 +- .../http/converter/HttpMessageConverter.java | 6 +-- .../AbstractJackson2HttpMessageConverter.java | 4 +- .../web/client/RestTemplate.java | 12 +++--- .../web/util/UriComponentsBuilder.java | 17 +++----- 12 files changed, 63 insertions(+), 70 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/MimeType.java b/spring-core/src/main/java/org/springframework/util/MimeType.java index cad9b5f5b77..6aaf4925add 100644 --- a/spring-core/src/main/java/org/springframework/util/MimeType.java +++ b/spring-core/src/main/java/org/springframework/util/MimeType.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -194,7 +194,7 @@ public class MimeType implements Comparable, Serializable { * @see HTTP 1.1, section 2.2 */ private void checkToken(String token) { - for (int i = 0; i < token.length(); i++ ) { + for (int i = 0; i < token.length(); i++) { char ch = token.charAt(i); if (!TOKEN.get(ch)) { throw new IllegalArgumentException("Invalid token character '" + ch + "' in token \"" + token + "\""); @@ -207,8 +207,7 @@ public class MimeType implements Comparable, Serializable { Assert.hasLength(value, "'value' must not be empty"); checkToken(attribute); if (PARAM_CHARSET.equals(attribute)) { - value = unquote(value); - Charset.forName(value); + Charset.forName(unquote(value)); } else if (!isQuotedString(value)) { checkToken(value); diff --git a/spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJackson2MessageConverter.java b/spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJackson2MessageConverter.java index 279382e1392..f4a8cf31f1a 100644 --- a/spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJackson2MessageConverter.java +++ b/spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJackson2MessageConverter.java @@ -123,7 +123,7 @@ public class MappingJackson2MessageConverter implements SmartMessageConverter, B /** * Specify the encoding to use when converting to and from text-based * message body content. The default encoding will be "UTF-8". - *

When reading from a a text-based message, an encoding may have been + *

When reading from a text-based message, an encoding may have been * suggested through a special JMS property which will then be preferred * over the encoding set on this MessageConverter instance. * @see #setEncodingPropertyName @@ -457,11 +457,11 @@ public class MappingJackson2MessageConverter implements SmartMessageConverter, B } Class mappedClass = this.idClassMappings.get(typeId); if (mappedClass != null) { - return this.objectMapper.getTypeFactory().constructType(mappedClass); + return this.objectMapper.constructType(mappedClass); } try { Class typeClass = ClassUtils.forName(typeId, this.beanClassLoader); - return this.objectMapper.getTypeFactory().constructType(typeClass); + return this.objectMapper.constructType(typeClass); } catch (Throwable ex) { throw new MessageConversionException("Failed to resolve type id [" + typeId + "]", ex); diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java index 6ac679d39ef..cb81b02b6f4 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/AbstractMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -151,21 +151,6 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter } - /** - * Returns the default content type for the payload. Called when - * {@link #toMessage(Object, MessageHeaders)} is invoked without message headers or - * without a content type header. - *

By default, this returns the first element of the {@link #getSupportedMimeTypes() - * supportedMimeTypes}, if any. Can be overridden in sub-classes. - * @param payload the payload being converted to message - * @return the content type, or {@code null} if not known - */ - @Nullable - protected MimeType getDefaultContentType(Object payload) { - List mimeTypes = getSupportedMimeTypes(); - return (!mimeTypes.isEmpty() ? mimeTypes.get(0) : null); - } - @Override @Nullable public final Object fromMessage(Message message, Class targetClass) { @@ -181,10 +166,6 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter return convertFromInternal(message, targetClass, conversionHint); } - protected boolean canConvertFrom(Message message, Class targetClass) { - return (supports(targetClass) && supportsMimeType(message.getHeaders())); - } - @Override @Nullable public final Message toMessage(Object payload, @Nullable MessageHeaders headers) { @@ -224,6 +205,11 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter return builder.build(); } + + protected boolean canConvertFrom(Message message, Class targetClass) { + return (supports(targetClass) && supportsMimeType(message.getHeaders())); + } + protected boolean canConvertTo(Object payload, @Nullable MessageHeaders headers) { return (supports(payload.getClass()) && supportsMimeType(headers)); } @@ -249,6 +235,22 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter return (headers != null && this.contentTypeResolver != null ? this.contentTypeResolver.resolve(headers) : null); } + /** + * Return the default content type for the payload. Called when + * {@link #toMessage(Object, MessageHeaders)} is invoked without + * message headers or without a content type header. + *

By default, this returns the first element of the + * {@link #getSupportedMimeTypes() supportedMimeTypes}, if any. + * Can be overridden in subclasses. + * @param payload the payload being converted to a message + * @return the content type, or {@code null} if not known + */ + @Nullable + protected MimeType getDefaultContentType(Object payload) { + List mimeTypes = getSupportedMimeTypes(); + return (!mimeTypes.isEmpty() ? mimeTypes.get(0) : null); + } + /** * Whether the given class is supported by this converter. diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java index c38eb5f302d..acd16c5b319 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java @@ -43,6 +43,7 @@ import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.MimeType; /** @@ -141,6 +142,7 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter { } } + @Override protected boolean canConvertFrom(Message message, @Nullable Class targetClass) { if (targetClass == null || !supportsMimeType(message.getHeaders())) { @@ -212,7 +214,7 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter { Object payload = message.getPayload(); Class view = getSerializationView(conversionHint); try { - if (targetClass.isInstance(payload)) { + if (ClassUtils.isAssignableValue(targetClass, payload)) { return payload; } else if (payload instanceof byte[]) { @@ -248,7 +250,7 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter { Type genericParameterType = param.getNestedGenericParameterType(); Class contextClass = param.getContainingClass(); Type type = GenericTypeResolver.resolveType(genericParameterType, contextClass); - return this.objectMapper.getTypeFactory().constructType(type); + return this.objectMapper.constructType(type); } return this.objectMapper.constructType(targetClass); } @@ -333,7 +335,7 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter { * @return the JSON encoding to use (never {@code null}) */ protected JsonEncoding getJsonEncoding(@Nullable MimeType contentType) { - if (contentType != null && (contentType.getCharset() != null)) { + if (contentType != null && contentType.getCharset() != null) { Charset charset = contentType.getCharset(); for (JsonEncoding encoding : JsonEncoding.values()) { if (charset.name().equals(encoding.getJavaName())) { diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/MarshallingMessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/MarshallingMessageConverter.java index daef525b189..4310e2f2f2b 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/MarshallingMessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/MarshallingMessageConverter.java @@ -47,6 +47,8 @@ import org.springframework.util.MimeType; * * @author Arjen Poutsma * @since 4.2 + * @see Marshaller + * @see Unmarshaller */ public class MarshallingMessageConverter extends AbstractMessageConverter { @@ -62,7 +64,8 @@ public class MarshallingMessageConverter extends AbstractMessageConverter { * {@link #setUnmarshaller(Unmarshaller)} to be invoked separately. */ public MarshallingMessageConverter() { - this(new MimeType("application", "xml"), new MimeType("text", "xml"), new MimeType("application", "*+xml")); + this(new MimeType("application", "xml"), new MimeType("text", "xml"), + new MimeType("application", "*+xml")); } /** @@ -161,7 +164,7 @@ public class MarshallingMessageConverter extends AbstractMessageConverter { return new StreamSource(new ByteArrayInputStream((byte[]) payload)); } else { - return new StreamSource(new StringReader((String) payload)); + return new StreamSource(new StringReader(payload.toString())); } } diff --git a/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java b/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java index 652dc0108fe..d6dadc7527d 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -75,13 +75,8 @@ public class MappingJackson2MessageConverterTests { @Test public void fromMessage() { MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); - String payload = "{" + - "\"bytes\":\"AQI=\"," + - "\"array\":[\"Foo\",\"Bar\"]," + - "\"number\":42," + - "\"string\":\"Foo\"," + - "\"bool\":true," + - "\"fraction\":42.0}"; + String payload = "{\"bytes\":\"AQI=\",\"array\":[\"Foo\",\"Bar\"]," + + "\"number\":42,\"string\":\"Foo\",\"bool\":true,\"fraction\":42.0}"; Message message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build(); MyBean actual = (MyBean) converter.fromMessage(message, MyBean.class); @@ -245,9 +240,12 @@ public class MappingJackson2MessageConverterTests { public void jsonViewPayload(@JsonView(MyJacksonView2.class) JacksonViewBean payload) { } - void handleList(List payload) {} + void handleList(List payload) { + } + + void handleMessage(Message message) { + } - void handleMessage(Message message) {} public static class MyBean { diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java index c77e49263b1..f5086a121df 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Decoder.java @@ -105,7 +105,7 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple @Override public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) { - JavaType javaType = getObjectMapper().getTypeFactory().constructType(elementType.getType()); + JavaType javaType = getObjectMapper().constructType(elementType.getType()); // Skip String: CharSequenceDecoder + "*/*" comes after return (!CharSequence.class.isAssignableFrom(elementType.toClass()) && getObjectMapper().canDeserialize(javaType) && supportsMimeType(mimeType)); diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java index 363fd54cbe2..4d7d2771ffc 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java @@ -27,7 +27,6 @@ import java.util.Map; import com.fasterxml.jackson.annotation.JsonView; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.type.TypeFactory; import org.apache.commons.logging.Log; import org.springframework.core.GenericTypeResolver; @@ -100,8 +99,7 @@ public abstract class Jackson2CodecSupport { } protected JavaType getJavaType(Type type, @Nullable Class contextClass) { - TypeFactory typeFactory = this.objectMapper.getTypeFactory(); - return typeFactory.constructType(GenericTypeResolver.resolveType(type, contextClass)); + return this.objectMapper.constructType(GenericTypeResolver.resolveType(type, contextClass)); } protected Map getHints(ResolvableType resolvableType) { diff --git a/spring-web/src/main/java/org/springframework/http/converter/HttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/HttpMessageConverter.java index 45fc0b0141c..a0583b9c6d5 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/HttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/HttpMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ import org.springframework.http.MediaType; import org.springframework.lang.Nullable; /** - * Strategy interface that specifies a converter that can convert from and to HTTP requests and responses. + * Strategy interface for converting from and to HTTP requests and responses. * * @author Arjen Poutsma * @author Juergen Hoeller @@ -54,7 +54,7 @@ public interface HttpMessageConverter { /** * Return the list of {@link MediaType} objects supported by this converter. - * @return the list of supported media types + * @return the list of supported media types, potentially an immutable copy */ List getSupportedMediaTypes(); diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java index 3464ac4e94a..465db9e4161 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java @@ -43,7 +43,6 @@ import com.fasterxml.jackson.databind.SerializationConfig; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; import com.fasterxml.jackson.databind.ser.FilterProvider; -import com.fasterxml.jackson.databind.type.TypeFactory; import org.springframework.core.GenericTypeResolver; import org.springframework.http.HttpInputMessage; @@ -376,8 +375,7 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener * @return the Jackson JavaType */ protected JavaType getJavaType(Type type, @Nullable Class contextClass) { - TypeFactory typeFactory = this.objectMapper.getTypeFactory(); - return typeFactory.constructType(GenericTypeResolver.resolveType(type, contextClass)); + return this.objectMapper.constructType(GenericTypeResolver.resolveType(type, contextClass)); } /** diff --git a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java index 321dcca570f..6cb0194ca43 100644 --- a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java +++ b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java @@ -21,7 +21,6 @@ import java.lang.reflect.Type; import java.net.URI; import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -109,9 +108,8 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat ClassLoader classLoader = RestTemplate.class.getClassLoader(); romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader); jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader); - jackson2Present = - ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) && - ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader); + jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) && + ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader); jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader); jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader); jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader); @@ -912,7 +910,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat HttpHeaders httpHeaders = httpRequest.getHeaders(); HttpHeaders requestHeaders = this.requestEntity.getHeaders(); if (!requestHeaders.isEmpty()) { - requestHeaders.forEach((key, values) -> httpHeaders.put(key, new LinkedList<>(values))); + requestHeaders.forEach((key, values) -> httpHeaders.put(key, new ArrayList<>(values))); } if (httpHeaders.getContentLength() < 0) { httpHeaders.setContentLength(0L); @@ -931,7 +929,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat (GenericHttpMessageConverter) messageConverter; if (genericConverter.canWrite(requestBodyType, requestBodyClass, requestContentType)) { if (!requestHeaders.isEmpty()) { - requestHeaders.forEach((key, values) -> httpHeaders.put(key, new LinkedList<>(values))); + requestHeaders.forEach((key, values) -> httpHeaders.put(key, new ArrayList<>(values))); } logBody(requestBody, requestContentType, genericConverter); genericConverter.write(requestBody, requestBodyType, requestContentType, httpRequest); @@ -940,7 +938,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat } else if (messageConverter.canWrite(requestBodyClass, requestContentType)) { if (!requestHeaders.isEmpty()) { - requestHeaders.forEach((key, values) -> httpHeaders.put(key, new LinkedList<>(values))); + requestHeaders.forEach((key, values) -> httpHeaders.put(key, new ArrayList<>(values))); } logBody(requestBody, requestContentType, messageConverter); ((HttpMessageConverter) messageConverter).write( diff --git a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java index 8384be15cf3..9b20bfd15fe 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java @@ -233,7 +233,7 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { } builder.scheme(scheme); if (opaque) { - String ssp = uri.substring(scheme.length()).substring(1); + String ssp = uri.substring(scheme.length() + 1); if (StringUtils.hasLength(fragment)) { ssp = ssp.substring(0, ssp.length() - (fragment.length() + 1)); } @@ -394,9 +394,8 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { * characters that should have been encoded. */ public UriComponents build(boolean encoded) { - return buildInternal(encoded ? - EncodingHint.FULLY_ENCODED : - this.encodeTemplate ? EncodingHint.ENCODE_TEMPLATE : EncodingHint.NONE); + return buildInternal(encoded ? EncodingHint.FULLY_ENCODED : + (this.encodeTemplate ? EncodingHint.ENCODE_TEMPLATE : EncodingHint.NONE)); } private UriComponents buildInternal(EncodingHint hint) { @@ -408,8 +407,7 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { HierarchicalUriComponents uric = new HierarchicalUriComponents(this.scheme, this.fragment, this.userInfo, this.host, this.port, this.pathBuilder.build(), this.queryParams, hint == EncodingHint.FULLY_ENCODED); - - result = hint == EncodingHint.ENCODE_TEMPLATE ? uric.encodeTemplate(this.charset) : uric; + result = (hint == EncodingHint.ENCODE_TEMPLATE ? uric.encodeTemplate(this.charset) : uric); } if (!this.uriVariables.isEmpty()) { result = result.expand(name -> this.uriVariables.getOrDefault(name, UriTemplateVariables.SKIP_VALUE)); @@ -466,9 +464,8 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { * @see UriComponents#toUriString() */ public String toUriString() { - return this.uriVariables.isEmpty() ? - build().encode().toUriString() : - buildInternal(EncodingHint.ENCODE_TEMPLATE).toUriString(); + return (this.uriVariables.isEmpty() ? build().encode().toUriString() : + buildInternal(EncodingHint.ENCODE_TEMPLATE).toUriString()); } @@ -849,12 +846,10 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { scheme("https"); port(null); } - String hostHeader = headers.getFirst("X-Forwarded-Host"); if (StringUtils.hasText(hostHeader)) { adaptForwardedHost(StringUtils.tokenizeToStringArray(hostHeader, ",")[0]); } - String portHeader = headers.getFirst("X-Forwarded-Port"); if (StringUtils.hasText(portHeader)) { port(Integer.parseInt(StringUtils.tokenizeToStringArray(portHeader, ",")[0]));