diff --git a/spring-web/src/main/java/org/springframework/http/codec/ClientCodecConfigurer.java b/spring-web/src/main/java/org/springframework/http/codec/ClientCodecConfigurer.java index 84923fdc27f..2866b2386d4 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ClientCodecConfigurer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ClientCodecConfigurer.java @@ -35,17 +35,15 @@ import org.springframework.core.codec.Encoder; */ public interface ClientCodecConfigurer extends CodecConfigurer { - @Override ClientDefaultCodecs defaultCodecs(); /** - * Creates a new instance of the {@code ClientCodecConfigurer}. - * @return the created instance + * Create a new instance of the {@code ClientCodecConfigurer}. */ static ClientCodecConfigurer create() { - return new DefaultClientCodecConfigurer(); + return CodecConfigurerFactory.create(ClientCodecConfigurer.class); } @@ -71,6 +69,7 @@ public interface ClientCodecConfigurer extends CodecConfigurer { void serverSentEventDecoder(Decoder decoder); } + /** * Registry and container for multipart HTTP message writers. */ diff --git a/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurer.java b/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurer.java index ae8afecbc61..e555569e62f 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurer.java @@ -20,8 +20,6 @@ import java.util.List; import org.springframework.core.codec.Decoder; import org.springframework.core.codec.Encoder; -import org.springframework.http.codec.json.Jackson2JsonDecoder; -import org.springframework.http.codec.json.Jackson2JsonEncoder; /** * Defines a common interface for configuring either client or server HTTP @@ -73,15 +71,16 @@ public interface CodecConfigurer { /** * Override the default Jackson JSON {@code Decoder}. * @param decoder the decoder instance to use + * @see org.springframework.http.codec.json.Jackson2JsonDecoder */ - void jackson2JsonDecoder(Jackson2JsonDecoder decoder); + void jackson2JsonDecoder(Decoder decoder); /** * Override the default Jackson JSON {@code Encoder}. * @param encoder the encoder instance to use + * @see org.springframework.http.codec.json.Jackson2JsonEncoder */ - void jackson2JsonEncoder(Jackson2JsonEncoder encoder); - + void jackson2JsonEncoder(Encoder encoder); } @@ -119,6 +118,6 @@ public interface CodecConfigurer { * @param writer the writer to add */ void writer(HttpMessageWriter writer); - } + } diff --git a/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurerFactory.java b/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurerFactory.java new file mode 100644 index 00000000000..a9f1a1f4b68 --- /dev/null +++ b/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurerFactory.java @@ -0,0 +1,71 @@ +/* + * Copyright 2002-2017 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. + * 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.springframework.http.codec; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.springframework.beans.BeanUtils; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.support.PropertiesLoaderUtils; +import org.springframework.util.ClassUtils; + +/** + * Internal delegate for loading the default codec configurer class names. + * Models a loose relationship with the default implementations in the support + * package, literally only needing to know the default class name to use. + * + * @author Juergen Hoeller + * @since 5.0.1 + * @see ClientCodecConfigurer#create() + * @see ServerCodecConfigurer#create() + */ +class CodecConfigurerFactory { + + private static final String DEFAULT_CONFIGURERS_PATH = "CodecConfigurer.properties"; + + private static final Map, Class> defaultCodecConfigurers = new HashMap<>(4); + + static { + try { + Properties props = PropertiesLoaderUtils.loadProperties( + new ClassPathResource(DEFAULT_CONFIGURERS_PATH, CodecConfigurerFactory.class)); + for (String ifcName : props.stringPropertyNames()) { + String implName = props.getProperty(ifcName); + Class ifc = ClassUtils.forName(ifcName, CodecConfigurerFactory.class.getClassLoader()); + Class impl = ClassUtils.forName(implName, CodecConfigurerFactory.class.getClassLoader()); + defaultCodecConfigurers.put(ifc, impl); + } + } + catch (IOException | ClassNotFoundException ex) { + throw new IllegalStateException(ex); + } + } + + + @SuppressWarnings("unchecked") + public static T create(Class ifc) { + Class impl = defaultCodecConfigurers.get(ifc); + if (impl == null) { + throw new IllegalStateException("No default codec configurer found for " + ifc); + } + return (T) BeanUtils.instantiateClass(impl); + } + +} diff --git a/spring-web/src/main/java/org/springframework/http/codec/ServerCodecConfigurer.java b/spring-web/src/main/java/org/springframework/http/codec/ServerCodecConfigurer.java index a840f8840b7..cb2412e4a61 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ServerCodecConfigurer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ServerCodecConfigurer.java @@ -39,11 +39,10 @@ public interface ServerCodecConfigurer extends CodecConfigurer { /** - * Creates a new instance of the {@code ServerCodecConfigurer}. - * @return the created instance + * Create a new instance of the {@code ServerCodecConfigurer}. */ static ServerCodecConfigurer create() { - return new DefaultServerCodecConfigurer(); + return CodecConfigurerFactory.create(ServerCodecConfigurer.class); } diff --git a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEvent.java b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEvent.java index 542ee60f564..fd7de7fe768 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEvent.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEvent.java @@ -18,7 +18,6 @@ package org.springframework.http.codec; import java.time.Duration; -import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.lang.Nullable; /** @@ -167,10 +166,10 @@ public class ServerSentEvent { Builder comment(String comment); /** - * Set the value of the {@code data} field. If the {@code data} argument is a - * multi-line {@code String}, it will be turned into multiple {@code data} field lines - * as defined in the Server-Sent Events W3C recommendation. If {@code data} is not a - * String, it will be {@linkplain Jackson2JsonEncoder encoded} into JSON. + * Set the value of the {@code data} field. If the {@code data} argument is a multi-line + * {@code String}, it will be turned into multiple {@code data} field lines as defined + * in the Server-Sent Events W3C recommendation. If {@code data} is not a String, it will + * be {@linkplain org.springframework.http.codec.json.Jackson2JsonEncoder encoded} into JSON. * @param data the value of the data field * @return {@code this} builder */ @@ -181,9 +180,9 @@ public class ServerSentEvent { * @return the built event */ ServerSentEvent build(); - } + private static class BuilderImpl implements Builder { @Nullable 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 3849d5abdb7..113266e5c68 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 @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.http.codec.json; import java.io.IOException; @@ -54,7 +55,6 @@ import org.springframework.util.MimeType; */ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport implements HttpMessageDecoder { - /** * Constructor with a Jackson {@link ObjectMapper} to use. */ @@ -144,4 +144,5 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple protected A getAnnotation(MethodParameter parameter, Class annotType) { return parameter.getParameterAnnotation(annotType); } + } diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java index d98856d58d3..1cc34f93af7 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.http.codec.json; import java.io.IOException; @@ -57,6 +58,7 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple protected final List streamingMediaTypes = new ArrayList<>(1); + /** * Constructor with a Jackson {@link ObjectMapper} to use. */ @@ -64,6 +66,7 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple super(mapper, mimeTypes); } + /** * Configure "streaming" media types for which flushing should be performed * automatically vs at the end of the stream. @@ -76,6 +79,7 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple this.streamingMediaTypes.addAll(mediaTypes); } + @Override public boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType) { Class clazz = elementType.resolve(Object.class); @@ -143,6 +147,7 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple protected ObjectWriter customizeWriter(ObjectWriter writer, @Nullable MimeType mimeType, ResolvableType elementType, @Nullable Map hints) { + return writer; } 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 035b5a9bf49..d732b9e1855 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 @@ -83,7 +83,7 @@ public abstract class Jackson2CodecSupport { } /** - * Sub-classes should expose this as "decodable" or "encodable" mime types. + * Subclasses should expose this as "decodable" or "encodable" mime types. */ protected List getMimeTypes() { return this.mimeTypes; diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonDecoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonDecoder.java index e108c134f10..02aef7f52cb 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonDecoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonDecoder.java @@ -19,6 +19,7 @@ package org.springframework.http.codec.json; import java.util.List; import com.fasterxml.jackson.databind.ObjectMapper; + import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.util.MimeType; @@ -40,8 +41,10 @@ public class Jackson2JsonDecoder extends AbstractJackson2Decoder { super(mapper, mimeTypes); } + @Override public List getDecodableMimeTypes() { return getMimeTypes(); } + } diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java index 3ceeac10814..df462ef2cfa 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java @@ -63,16 +63,20 @@ public class Jackson2JsonEncoder extends AbstractJackson2Encoder { return printer; } + @Override protected ObjectWriter customizeWriter(ObjectWriter writer, @Nullable MimeType mimeType, ResolvableType elementType, @Nullable Map hints) { - return (this.ssePrettyPrinter != null && MediaType.TEXT_EVENT_STREAM.isCompatibleWith(mimeType) && - writer.getConfig().isEnabled(SerializationFeature.INDENT_OUTPUT) ? writer.with(this.ssePrettyPrinter) : writer); + return (this.ssePrettyPrinter != null && + MediaType.TEXT_EVENT_STREAM.isCompatibleWith(mimeType) && + writer.getConfig().isEnabled(SerializationFeature.INDENT_OUTPUT) ? + writer.with(this.ssePrettyPrinter) : writer); } @Override public List getEncodableMimeTypes() { return getMimeTypes(); } + } diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2SmileDecoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2SmileDecoder.java index 0e15943552a..7f561a0a93a 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2SmileDecoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2SmileDecoder.java @@ -16,7 +16,7 @@ package org.springframework.http.codec.json; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import com.fasterxml.jackson.databind.ObjectMapper; @@ -51,6 +51,7 @@ public class Jackson2SmileDecoder extends AbstractJackson2Decoder { @Override public List getDecodableMimeTypes() { - return Arrays.asList(SMILE_MIME_TYPE); + return Collections.singletonList(SMILE_MIME_TYPE); } + } diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2SmileEncoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2SmileEncoder.java index 4614aa43642..d52bfaf8ef7 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2SmileEncoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2SmileEncoder.java @@ -16,7 +16,7 @@ package org.springframework.http.codec.json; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import com.fasterxml.jackson.databind.ObjectMapper; @@ -49,8 +49,10 @@ public class Jackson2SmileEncoder extends AbstractJackson2Encoder { this.streamingMediaTypes.add(new MediaType("application", "stream+x-jackson-smile")); } + @Override public List getEncodableMimeTypes() { - return Arrays.asList(SMILE_MIME_TYPE); + return Collections.singletonList(SMILE_MIME_TYPE); } + } diff --git a/spring-web/src/main/java/org/springframework/http/codec/AbstractCodecConfigurer.java b/spring-web/src/main/java/org/springframework/http/codec/support/AbstractCodecConfigurer.java similarity index 79% rename from spring-web/src/main/java/org/springframework/http/codec/AbstractCodecConfigurer.java rename to spring-web/src/main/java/org/springframework/http/codec/support/AbstractCodecConfigurer.java index ce24fef95bc..459d530b054 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/AbstractCodecConfigurer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/support/AbstractCodecConfigurer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.http.codec; +package org.springframework.http.codec.support; import java.util.ArrayList; import java.util.Collections; @@ -32,6 +32,12 @@ import org.springframework.core.codec.Decoder; import org.springframework.core.codec.Encoder; import org.springframework.core.codec.ResourceDecoder; import org.springframework.core.codec.StringDecoder; +import org.springframework.http.codec.CodecConfigurer; +import org.springframework.http.codec.DecoderHttpMessageReader; +import org.springframework.http.codec.EncoderHttpMessageWriter; +import org.springframework.http.codec.HttpMessageReader; +import org.springframework.http.codec.HttpMessageWriter; +import org.springframework.http.codec.ResourceHttpMessageWriter; import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.http.codec.json.Jackson2SmileDecoder; @@ -50,7 +56,7 @@ import org.springframework.util.ClassUtils; */ abstract class AbstractCodecConfigurer implements CodecConfigurer { - protected static final boolean jackson2Present = + static final boolean jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", AbstractCodecConfigurer.class.getClassLoader()) && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", @@ -60,8 +66,8 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", AbstractCodecConfigurer.class.getClassLoader()); - protected static final boolean jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", - AbstractCodecConfigurer.class.getClassLoader()); + private static final boolean jaxb2Present = + ClassUtils.isPresent("javax.xml.bind.Binder", AbstractCodecConfigurer.class.getClassLoader()); private final AbstractDefaultCodecs defaultCodecs; @@ -69,7 +75,7 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { private final DefaultCustomCodecs customCodecs = new DefaultCustomCodecs(); - protected AbstractCodecConfigurer(AbstractDefaultCodecs defaultCodecs) { + AbstractCodecConfigurer(AbstractDefaultCodecs defaultCodecs) { Assert.notNull(defaultCodecs, "'defaultCodecs' is required"); this.defaultCodecs = defaultCodecs; this.defaultCodecs.setCustomCodecs(this.customCodecs); @@ -83,7 +89,7 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { @Override public void registerDefaults(boolean shouldRegister) { - this.defaultCodecs.setRegisterDefaults(shouldRegister); + this.defaultCodecs.registerDefaults(shouldRegister); } @Override @@ -120,60 +126,60 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { } - abstract protected static class AbstractDefaultCodecs implements DefaultCodecs { + abstract static class AbstractDefaultCodecs implements DefaultCodecs { private boolean registerDefaults = true; @Nullable - private Jackson2JsonDecoder jackson2JsonDecoder; + private Decoder jackson2JsonDecoder; @Nullable - private Jackson2JsonEncoder jackson2JsonEncoder; + private Encoder jackson2JsonEncoder; @Nullable private DefaultCustomCodecs customCodecs; - public void setRegisterDefaults(boolean registerDefaults) { + void registerDefaults(boolean registerDefaults) { this.registerDefaults = registerDefaults; } - public boolean shouldRegisterDefaults() { + boolean shouldRegisterDefaults() { return this.registerDefaults; } /** - * Access to custom codecs for sub-classes, e.g. for multipart writers. + * Access to custom codecs for subclasses, e.g. for multipart writers. */ - public void setCustomCodecs(@Nullable DefaultCustomCodecs customCodecs) { + void setCustomCodecs(@Nullable DefaultCustomCodecs customCodecs) { this.customCodecs = customCodecs; } @Nullable - public DefaultCustomCodecs getCustomCodecs() { + DefaultCustomCodecs getCustomCodecs() { return this.customCodecs; } @Override - public void jackson2JsonDecoder(Jackson2JsonDecoder decoder) { + public void jackson2JsonDecoder(Decoder decoder) { this.jackson2JsonDecoder = decoder; } - protected Jackson2JsonDecoder jackson2JsonDecoder() { + Decoder getJackson2JsonDecoder() { return (this.jackson2JsonDecoder != null ? this.jackson2JsonDecoder : new Jackson2JsonDecoder()); } @Override - public void jackson2JsonEncoder(Jackson2JsonEncoder encoder) { + public void jackson2JsonEncoder(Encoder encoder) { this.jackson2JsonEncoder = encoder; } - protected Jackson2JsonEncoder jackson2JsonEncoder() { + Encoder getJackson2JsonEncoder() { return (this.jackson2JsonEncoder != null ? this.jackson2JsonEncoder : new Jackson2JsonEncoder()); } // Readers... - public List> getTypedReaders() { + List> getTypedReaders() { if (!this.registerDefaults) { return Collections.emptyList(); } @@ -186,26 +192,26 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { return result; } - protected abstract boolean splitTextOnNewLine(); + abstract boolean splitTextOnNewLine(); - public List> getObjectReaders() { + List> getObjectReaders() { if (!this.registerDefaults) { return Collections.emptyList(); } List> result = new ArrayList<>(); - if (jaxb2Present) { - result.add(new DecoderHttpMessageReader<>(new Jaxb2XmlDecoder())); - } if (jackson2Present) { - result.add(new DecoderHttpMessageReader<>(jackson2JsonDecoder())); + result.add(new DecoderHttpMessageReader<>(getJackson2JsonDecoder())); } if (jackson2SmilePresent) { result.add(new DecoderHttpMessageReader<>(new Jackson2SmileDecoder())); } + if (jaxb2Present) { + result.add(new DecoderHttpMessageReader<>(new Jaxb2XmlDecoder())); + } return result; } - public List> getCatchAllReaders() { + List> getCatchAllReaders() { if (!this.registerDefaults) { return Collections.emptyList(); } @@ -216,7 +222,7 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { // Writers... - public List> getTypedWriters() { + List> getTypedWriters() { if (!this.registerDefaults) { return Collections.emptyList(); } @@ -229,24 +235,24 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { return result; } - public List> getObjectWriters() { + List> getObjectWriters() { if (!this.registerDefaults) { return Collections.emptyList(); } List> result = new ArrayList<>(); - if (jaxb2Present) { - result.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder())); - } if (jackson2Present) { - result.add(new EncoderHttpMessageWriter<>(jackson2JsonEncoder())); + result.add(new EncoderHttpMessageWriter<>(getJackson2JsonEncoder())); } if (jackson2SmilePresent) { result.add(new EncoderHttpMessageWriter<>(new Jackson2SmileEncoder())); } + if (jaxb2Present) { + result.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder())); + } return result; } - public List> getCatchAllWriters() { + List> getCatchAllWriters() { if (!this.registerDefaults) { return Collections.emptyList(); } @@ -257,7 +263,7 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { } - protected static class DefaultCustomCodecs implements CustomCodecs { + static class DefaultCustomCodecs implements CustomCodecs { private final List> typedReaders = new ArrayList<>(); @@ -289,19 +295,19 @@ abstract class AbstractCodecConfigurer implements CodecConfigurer { (canWriteObject ? this.objectWriters : this.typedWriters).add(writer); } - public List> getTypedReaders() { + List> getTypedReaders() { return this.typedReaders; } - public List> getTypedWriters() { + List> getTypedWriters() { return this.typedWriters; } - public List> getObjectReaders() { + List> getObjectReaders() { return this.objectReaders; } - public List> getObjectWriters() { + List> getObjectWriters() { return this.objectWriters; } } diff --git a/spring-web/src/main/java/org/springframework/http/codec/DefaultClientCodecConfigurer.java b/spring-web/src/main/java/org/springframework/http/codec/support/DefaultClientCodecConfigurer.java similarity index 81% rename from spring-web/src/main/java/org/springframework/http/codec/DefaultClientCodecConfigurer.java rename to spring-web/src/main/java/org/springframework/http/codec/support/DefaultClientCodecConfigurer.java index 67988a271c2..6abe9a2a2b4 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/DefaultClientCodecConfigurer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/support/DefaultClientCodecConfigurer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.http.codec; +package org.springframework.http.codec.support; import java.util.ArrayList; import java.util.Collections; @@ -22,6 +22,12 @@ import java.util.List; import org.springframework.core.codec.Decoder; import org.springframework.core.codec.Encoder; +import org.springframework.http.codec.ClientCodecConfigurer; +import org.springframework.http.codec.EncoderHttpMessageWriter; +import org.springframework.http.codec.FormHttpMessageWriter; +import org.springframework.http.codec.HttpMessageReader; +import org.springframework.http.codec.HttpMessageWriter; +import org.springframework.http.codec.ServerSentEventHttpMessageReader; import org.springframework.http.codec.multipart.MultipartHttpMessageWriter; import org.springframework.lang.Nullable; @@ -31,7 +37,7 @@ import org.springframework.lang.Nullable; * @author Rossen Stoyanchev * @since 5.0 */ -class DefaultClientCodecConfigurer extends AbstractCodecConfigurer implements ClientCodecConfigurer { +public class DefaultClientCodecConfigurer extends AbstractCodecConfigurer implements ClientCodecConfigurer { public DefaultClientCodecConfigurer() { super(new ClientDefaultCodecsImpl()); @@ -65,12 +71,12 @@ class DefaultClientCodecConfigurer extends AbstractCodecConfigurer implements Cl } @Override - protected boolean splitTextOnNewLine() { + boolean splitTextOnNewLine() { return false; } @Override - public List> getObjectReaders() { + List> getObjectReaders() { if (!shouldRegisterDefaults()) { return Collections.emptyList(); } @@ -84,12 +90,12 @@ class DefaultClientCodecConfigurer extends AbstractCodecConfigurer implements Cl if (this.sseDecoder != null) { return this.sseDecoder; } - return (jackson2Present ? jackson2JsonDecoder() : null); + return (jackson2Present ? getJackson2JsonDecoder() : null); } @Override - public List> getTypedWriters() { - if (!this.shouldRegisterDefaults()) { + List> getTypedWriters() { + if (!shouldRegisterDefaults()) { return Collections.emptyList(); } List> result = super.getTypedWriters(); @@ -137,7 +143,7 @@ class DefaultClientCodecConfigurer extends AbstractCodecConfigurer implements Cl return this; } - public List> getWriters() { + List> getWriters() { return this.writers; } } diff --git a/spring-web/src/main/java/org/springframework/http/codec/DefaultServerCodecConfigurer.java b/spring-web/src/main/java/org/springframework/http/codec/support/DefaultServerCodecConfigurer.java similarity index 74% rename from spring-web/src/main/java/org/springframework/http/codec/DefaultServerCodecConfigurer.java rename to spring-web/src/main/java/org/springframework/http/codec/support/DefaultServerCodecConfigurer.java index 5313c4b5d81..6c0420c3983 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/DefaultServerCodecConfigurer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/support/DefaultServerCodecConfigurer.java @@ -14,12 +14,17 @@ * limitations under the License. */ -package org.springframework.http.codec; +package org.springframework.http.codec.support; import java.util.Collections; import java.util.List; import org.springframework.core.codec.Encoder; +import org.springframework.http.codec.FormHttpMessageReader; +import org.springframework.http.codec.HttpMessageReader; +import org.springframework.http.codec.HttpMessageWriter; +import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.http.codec.ServerSentEventHttpMessageWriter; import org.springframework.http.codec.multipart.MultipartHttpMessageReader; import org.springframework.http.codec.multipart.SynchronossPartHttpMessageReader; import org.springframework.lang.Nullable; @@ -31,11 +36,11 @@ import org.springframework.util.ClassUtils; * @author Rossen Stoyanchev * @since 5.0 */ -class DefaultServerCodecConfigurer extends AbstractCodecConfigurer implements ServerCodecConfigurer { +public class DefaultServerCodecConfigurer extends AbstractCodecConfigurer implements ServerCodecConfigurer { - static final boolean synchronossMultipartPresent = ClassUtils.isPresent( - "org.synchronoss.cloud.nio.multipart.NioMultipartParser", - DefaultServerCodecConfigurer.class.getClassLoader()); + static final boolean synchronossMultipartPresent = + ClassUtils.isPresent("org.synchronoss.cloud.nio.multipart.NioMultipartParser", + DefaultServerCodecConfigurer.class.getClassLoader()); public DefaultServerCodecConfigurer() { @@ -62,12 +67,12 @@ class DefaultServerCodecConfigurer extends AbstractCodecConfigurer implements Se } @Override - protected boolean splitTextOnNewLine() { + boolean splitTextOnNewLine() { return true; } @Override - public List> getTypedReaders() { + List> getTypedReaders() { if (!shouldRegisterDefaults()) { return Collections.emptyList(); } @@ -82,7 +87,7 @@ class DefaultServerCodecConfigurer extends AbstractCodecConfigurer implements Se } @Override - public List> getObjectWriters() { + List> getObjectWriters() { if (!shouldRegisterDefaults()) { return Collections.emptyList(); } @@ -96,7 +101,7 @@ class DefaultServerCodecConfigurer extends AbstractCodecConfigurer implements Se if (this.sseEncoder != null) { return this.sseEncoder; } - return jackson2Present ? jackson2JsonEncoder() : null; + return jackson2Present ? getJackson2JsonEncoder() : null; } } diff --git a/spring-web/src/main/java/org/springframework/http/codec/support/package-info.java b/spring-web/src/main/java/org/springframework/http/codec/support/package-info.java new file mode 100644 index 00000000000..d2658887ebe --- /dev/null +++ b/spring-web/src/main/java/org/springframework/http/codec/support/package-info.java @@ -0,0 +1,11 @@ +/** + * Provides implementations of {@link org.springframework.http.codec.ClientCodecConfigurer} + * and {@link org.springframework.http.codec.ServerCodecConfigurer} based on the converter + * implementations from {@code org.springframework.http.codec.json} and co. + */ +@NonNullApi +@NonNullFields +package org.springframework.http.codec.support; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-web/src/main/resources/org/springframework/http/codec/CodecConfigurer.properties b/spring-web/src/main/resources/org/springframework/http/codec/CodecConfigurer.properties new file mode 100644 index 00000000000..dedf3138c1d --- /dev/null +++ b/spring-web/src/main/resources/org/springframework/http/codec/CodecConfigurer.properties @@ -0,0 +1,5 @@ +# Default CodecConfigurer implementation classes for static Client/ServerCodecConfigurer.create() calls. +# Not meant to be customized by application developers; simply instantiate custom impl classes instead. + +org.springframework.http.codec.ClientCodecConfigurer=org.springframework.http.codec.support.DefaultClientCodecConfigurer +org.springframework.http.codec.ServerCodecConfigurer=org.springframework.http.codec.support.DefaultServerCodecConfigurer diff --git a/spring-web/src/test/java/org/springframework/http/codec/ClientCodecConfigurerTests.java b/spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java similarity index 90% rename from spring-web/src/test/java/org/springframework/http/codec/ClientCodecConfigurerTests.java rename to spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java index a1493cbd060..98393d309c2 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/ClientCodecConfigurerTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.http.codec; + +package org.springframework.http.codec.support; import java.nio.charset.StandardCharsets; import java.time.Duration; @@ -38,6 +39,14 @@ import org.springframework.core.codec.ResourceDecoder; import org.springframework.core.codec.StringDecoder; import org.springframework.core.io.buffer.DefaultDataBufferFactory; import org.springframework.http.MediaType; +import org.springframework.http.codec.ClientCodecConfigurer; +import org.springframework.http.codec.DecoderHttpMessageReader; +import org.springframework.http.codec.EncoderHttpMessageWriter; +import org.springframework.http.codec.FormHttpMessageWriter; +import org.springframework.http.codec.HttpMessageReader; +import org.springframework.http.codec.HttpMessageWriter; +import org.springframework.http.codec.ResourceHttpMessageWriter; +import org.springframework.http.codec.ServerSentEventHttpMessageReader; import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.http.codec.json.Jackson2SmileDecoder; @@ -48,10 +57,11 @@ import org.springframework.http.codec.xml.Jaxb2XmlEncoder; import org.springframework.util.MimeTypeUtils; import static org.junit.Assert.*; -import static org.springframework.core.ResolvableType.forClass; +import static org.springframework.core.ResolvableType.*; /** * Unit tests for {@link ClientCodecConfigurer}. + * * @author Rossen Stoyanchev */ public class ClientCodecConfigurerTests { @@ -62,7 +72,7 @@ public class ClientCodecConfigurerTests { @Test - public void defaultReaders() throws Exception { + public void defaultReaders() { List> readers = this.configurer.getReaders(); assertEquals(10, readers.size()); assertEquals(ByteArrayDecoder.class, getNextDecoder(readers).getClass()); @@ -70,15 +80,15 @@ public class ClientCodecConfigurerTests { assertEquals(DataBufferDecoder.class, getNextDecoder(readers).getClass()); assertEquals(ResourceDecoder.class, getNextDecoder(readers).getClass()); assertStringDecoder(getNextDecoder(readers), true); - assertEquals(Jaxb2XmlDecoder.class, getNextDecoder(readers).getClass()); assertEquals(Jackson2JsonDecoder.class, getNextDecoder(readers).getClass()); assertEquals(Jackson2SmileDecoder.class, getNextDecoder(readers).getClass()); + assertEquals(Jaxb2XmlDecoder.class, getNextDecoder(readers).getClass()); assertSseReader(readers); assertStringDecoder(getNextDecoder(readers), false); } @Test - public void defaultWriters() throws Exception { + public void defaultWriters() { List> writers = this.configurer.getWriters(); assertEquals(11, writers.size()); assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass()); @@ -88,15 +98,14 @@ public class ClientCodecConfigurerTests { assertStringEncoder(getNextEncoder(writers), true); assertEquals(FormHttpMessageWriter.class, writers.get(this.index.getAndIncrement()).getClass()); assertEquals(MultipartHttpMessageWriter.class, writers.get(this.index.getAndIncrement()).getClass()); - assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass()); assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass()); assertEquals(Jackson2SmileEncoder.class, getNextEncoder(writers).getClass()); + assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass()); assertStringEncoder(getNextEncoder(writers), false); } @Test - public void jackson2EncoderOverride() throws Exception { - + public void jackson2EncoderOverride() { Jackson2JsonDecoder decoder = new Jackson2JsonDecoder(); this.configurer.defaultCodecs().jackson2JsonDecoder(decoder); diff --git a/spring-web/src/test/java/org/springframework/http/codec/CodecConfigurerTests.java b/spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java similarity index 93% rename from spring-web/src/test/java/org/springframework/http/codec/CodecConfigurerTests.java rename to spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java index 5afc47b4073..7e623c1dccd 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/CodecConfigurerTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.http.codec; + +package org.springframework.http.codec.support; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -33,6 +34,12 @@ import org.springframework.core.codec.Encoder; import org.springframework.core.codec.ResourceDecoder; import org.springframework.core.codec.StringDecoder; import org.springframework.http.MediaType; +import org.springframework.http.codec.CodecConfigurer; +import org.springframework.http.codec.DecoderHttpMessageReader; +import org.springframework.http.codec.EncoderHttpMessageWriter; +import org.springframework.http.codec.HttpMessageReader; +import org.springframework.http.codec.HttpMessageWriter; +import org.springframework.http.codec.ResourceHttpMessageWriter; import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.http.codec.json.Jackson2SmileDecoder; @@ -41,12 +48,9 @@ import org.springframework.http.codec.xml.Jaxb2XmlDecoder; import org.springframework.http.codec.xml.Jaxb2XmlEncoder; import org.springframework.util.MimeTypeUtils; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.springframework.core.ResolvableType.forClass; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; +import static org.springframework.core.ResolvableType.*; /** * Unit tests for {@link AbstractCodecConfigurer.AbstractDefaultCodecs}. @@ -60,7 +64,7 @@ public class CodecConfigurerTests { @Test - public void defaultReaders() throws Exception { + public void defaultReaders() { List> readers = this.configurer.getReaders(); assertEquals(9, readers.size()); assertEquals(ByteArrayDecoder.class, getNextDecoder(readers).getClass()); @@ -68,14 +72,14 @@ public class CodecConfigurerTests { assertEquals(DataBufferDecoder.class, getNextDecoder(readers).getClass()); assertEquals(ResourceDecoder.class, getNextDecoder(readers).getClass()); assertStringDecoder(getNextDecoder(readers), true); - assertEquals(Jaxb2XmlDecoder.class, getNextDecoder(readers).getClass()); assertEquals(Jackson2JsonDecoder.class, getNextDecoder(readers).getClass()); assertEquals(Jackson2SmileDecoder.class, getNextDecoder(readers).getClass()); + assertEquals(Jaxb2XmlDecoder.class, getNextDecoder(readers).getClass()); assertStringDecoder(getNextDecoder(readers), false); } @Test - public void defaultWriters() throws Exception { + public void defaultWriters() { List> writers = this.configurer.getWriters(); assertEquals(9, writers.size()); assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass()); @@ -83,15 +87,14 @@ public class CodecConfigurerTests { assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass()); assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass()); assertStringEncoder(getNextEncoder(writers), true); - assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass()); assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass()); assertEquals(Jackson2SmileEncoder.class, getNextEncoder(writers).getClass()); + assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass()); assertStringEncoder(getNextEncoder(writers), false); } @Test - public void defaultAndCustomReaders() throws Exception { - + public void defaultAndCustomReaders() { Decoder customDecoder1 = mock(Decoder.class); Decoder customDecoder2 = mock(Decoder.class); @@ -120,17 +123,16 @@ public class CodecConfigurerTests { assertEquals(StringDecoder.class, getNextDecoder(readers).getClass()); assertSame(customDecoder1, getNextDecoder(readers)); assertSame(customReader1, readers.get(this.index.getAndIncrement())); - assertEquals(Jaxb2XmlDecoder.class, getNextDecoder(readers).getClass()); assertEquals(Jackson2JsonDecoder.class, getNextDecoder(readers).getClass()); assertEquals(Jackson2SmileDecoder.class, getNextDecoder(readers).getClass()); + assertEquals(Jaxb2XmlDecoder.class, getNextDecoder(readers).getClass()); assertSame(customDecoder2, getNextDecoder(readers)); assertSame(customReader2, readers.get(this.index.getAndIncrement())); assertEquals(StringDecoder.class, getNextDecoder(readers).getClass()); } @Test - public void defaultAndCustomWriters() throws Exception { - + public void defaultAndCustomWriters() { Encoder customEncoder1 = mock(Encoder.class); Encoder customEncoder2 = mock(Encoder.class); @@ -159,17 +161,16 @@ public class CodecConfigurerTests { assertEquals(CharSequenceEncoder.class, getNextEncoder(writers).getClass()); assertSame(customEncoder1, getNextEncoder(writers)); assertSame(customWriter1, writers.get(this.index.getAndIncrement())); - assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass()); assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass()); assertEquals(Jackson2SmileEncoder.class, getNextEncoder(writers).getClass()); + assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass()); assertSame(customEncoder2, getNextEncoder(writers)); assertSame(customWriter2, writers.get(this.index.getAndIncrement())); assertEquals(CharSequenceEncoder.class, getNextEncoder(writers).getClass()); } @Test - public void defaultsOffCustomReaders() throws Exception { - + public void defaultsOffCustomReaders() { Decoder customDecoder1 = mock(Decoder.class); Decoder customDecoder2 = mock(Decoder.class); @@ -200,8 +201,7 @@ public class CodecConfigurerTests { } @Test - public void defaultsOffWithCustomWriters() throws Exception { - + public void defaultsOffWithCustomWriters() { Encoder customEncoder1 = mock(Encoder.class); Encoder customEncoder2 = mock(Encoder.class); @@ -232,8 +232,7 @@ public class CodecConfigurerTests { } @Test - public void jackson2DecoderOverride() throws Exception { - + public void jackson2DecoderOverride() { Jackson2JsonDecoder decoder = new Jackson2JsonDecoder(); this.configurer.defaultCodecs().jackson2JsonDecoder(decoder); @@ -246,8 +245,7 @@ public class CodecConfigurerTests { } @Test - public void jackson2EncoderOverride() throws Exception { - + public void jackson2EncoderOverride() { Jackson2JsonEncoder encoder = new Jackson2JsonEncoder(); this.configurer.defaultCodecs().jackson2JsonEncoder(encoder); @@ -295,7 +293,7 @@ public class CodecConfigurerTests { private static class TestDefaultCodecs extends AbstractDefaultCodecs { @Override - protected boolean splitTextOnNewLine() { + boolean splitTextOnNewLine() { return true; } } diff --git a/spring-web/src/test/java/org/springframework/http/codec/ServerCodecConfigurerTests.java b/spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java similarity index 90% rename from spring-web/src/test/java/org/springframework/http/codec/ServerCodecConfigurerTests.java rename to spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java index 6551d516431..15a8639de1b 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/ServerCodecConfigurerTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.http.codec; + +package org.springframework.http.codec.support; import java.nio.charset.StandardCharsets; import java.time.Duration; @@ -39,6 +40,14 @@ import org.springframework.core.codec.ResourceDecoder; import org.springframework.core.codec.StringDecoder; import org.springframework.core.io.buffer.DefaultDataBufferFactory; import org.springframework.http.MediaType; +import org.springframework.http.codec.DecoderHttpMessageReader; +import org.springframework.http.codec.EncoderHttpMessageWriter; +import org.springframework.http.codec.FormHttpMessageReader; +import org.springframework.http.codec.HttpMessageReader; +import org.springframework.http.codec.HttpMessageWriter; +import org.springframework.http.codec.ResourceHttpMessageWriter; +import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.http.codec.ServerSentEventHttpMessageWriter; import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.http.codec.json.Jackson2SmileDecoder; @@ -50,10 +59,11 @@ import org.springframework.http.codec.xml.Jaxb2XmlEncoder; import org.springframework.util.MimeTypeUtils; import static org.junit.Assert.*; -import static org.springframework.core.ResolvableType.forClass; +import static org.springframework.core.ResolvableType.*; /** * Unit tests for {@link ServerCodecConfigurer}. + * * @author Rossen Stoyanchev */ public class ServerCodecConfigurerTests { @@ -64,7 +74,7 @@ public class ServerCodecConfigurerTests { @Test - public void defaultReaders() throws Exception { + public void defaultReaders() { List> readers = this.configurer.getReaders(); assertEquals(12, readers.size()); assertEquals(ByteArrayDecoder.class, getNextDecoder(readers).getClass()); @@ -75,14 +85,14 @@ public class ServerCodecConfigurerTests { assertEquals(FormHttpMessageReader.class, readers.get(this.index.getAndIncrement()).getClass()); assertEquals(SynchronossPartHttpMessageReader.class, readers.get(this.index.getAndIncrement()).getClass()); assertEquals(MultipartHttpMessageReader.class, readers.get(this.index.getAndIncrement()).getClass()); - assertEquals(Jaxb2XmlDecoder.class, getNextDecoder(readers).getClass()); assertEquals(Jackson2JsonDecoder.class, getNextDecoder(readers).getClass()); assertEquals(Jackson2SmileDecoder.class, getNextDecoder(readers).getClass()); + assertEquals(Jaxb2XmlDecoder.class, getNextDecoder(readers).getClass()); assertStringDecoder(getNextDecoder(readers), false); } @Test - public void defaultWriters() throws Exception { + public void defaultWriters() { List> writers = this.configurer.getWriters(); assertEquals(10, writers.size()); assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass()); @@ -90,16 +100,15 @@ public class ServerCodecConfigurerTests { assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass()); assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass()); assertStringEncoder(getNextEncoder(writers), true); - assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass()); assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass()); assertEquals(Jackson2SmileEncoder.class, getNextEncoder(writers).getClass()); + assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass()); assertSseWriter(writers); assertStringEncoder(getNextEncoder(writers), false); } @Test - public void jackson2EncoderOverride() throws Exception { - + public void jackson2EncoderOverride() { Jackson2JsonEncoder encoder = new Jackson2JsonEncoder(); this.configurer.defaultCodecs().jackson2JsonEncoder(encoder);