Provide Gson/JSON-B MessageConverter for spring-messaging (aligned with spring-web)
Closes gh-21496
This commit is contained in:
parent
ad5072a43c
commit
214bc407b4
|
|
@ -12,6 +12,8 @@ dependencies {
|
||||||
optional("io.rsocket:rsocket-core")
|
optional("io.rsocket:rsocket-core")
|
||||||
optional("io.rsocket:rsocket-transport-netty")
|
optional("io.rsocket:rsocket-transport-netty")
|
||||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
optional("com.fasterxml.jackson.core:jackson-databind")
|
||||||
|
optional("com.google.code.gson:gson")
|
||||||
|
optional("javax.json.bind:javax.json.bind-api")
|
||||||
optional("javax.xml.bind:jaxb-api")
|
optional("javax.xml.bind:jaxb-api")
|
||||||
optional("com.google.protobuf:protobuf-java-util")
|
optional("com.google.protobuf:protobuf-java-util")
|
||||||
optional("org.jetbrains.kotlinx:kotlinx-coroutines-core")
|
optional("org.jetbrains.kotlinx:kotlinx-coroutines-core")
|
||||||
|
|
@ -31,8 +33,10 @@ dependencies {
|
||||||
testCompile("org.jetbrains.kotlin:kotlin-stdlib")
|
testCompile("org.jetbrains.kotlin:kotlin-stdlib")
|
||||||
testCompile("org.xmlunit:xmlunit-assertj")
|
testCompile("org.xmlunit:xmlunit-assertj")
|
||||||
testCompile("org.xmlunit:xmlunit-matchers")
|
testCompile("org.xmlunit:xmlunit-matchers")
|
||||||
|
testRuntime("com.sun.activation:javax.activation")
|
||||||
testRuntime("com.sun.xml.bind:jaxb-core")
|
testRuntime("com.sun.xml.bind:jaxb-core")
|
||||||
testRuntime("com.sun.xml.bind:jaxb-impl")
|
testRuntime("com.sun.xml.bind:jaxb-impl")
|
||||||
testRuntime("com.sun.activation:javax.activation")
|
testRuntime("javax.json:javax.json-api")
|
||||||
|
testRuntime("org.apache.johnzon:johnzon-jsonb")
|
||||||
testRuntime(project(":spring-context"))
|
testRuntime(project(":spring-context"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://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.messaging.converter;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.messaging.Message;
|
||||||
|
import org.springframework.messaging.MessageHeaders;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.MimeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common base class for plain JSON converters, e.g. Gson and JSON-B.
|
||||||
|
*
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 5.3
|
||||||
|
* @see GsonMessageConverter
|
||||||
|
* @see JsonbMessageConverter
|
||||||
|
* @see #fromJson(Reader, Type)
|
||||||
|
* @see #fromJson(String, Type)
|
||||||
|
* @see #toJson(Object, Type)
|
||||||
|
* @see #toJson(Object, Type, Writer)
|
||||||
|
*/
|
||||||
|
public abstract class AbstractJsonMessageConverter extends AbstractMessageConverter {
|
||||||
|
|
||||||
|
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
||||||
|
|
||||||
|
|
||||||
|
protected AbstractJsonMessageConverter() {
|
||||||
|
super(new MimeType("application", "json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean supports(Class<?> clazz) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected Object convertFromInternal(Message<?> message, Class<?> targetClass, @Nullable Object conversionHint) {
|
||||||
|
try {
|
||||||
|
Type resolvedType = getResolvedType(targetClass, conversionHint);
|
||||||
|
Object payload = message.getPayload();
|
||||||
|
if (ClassUtils.isAssignableValue(targetClass, payload)) {
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
else if (payload instanceof byte[]) {
|
||||||
|
return fromJson(getReader((byte[]) payload, message.getHeaders()), resolvedType);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Assuming a text-based source payload
|
||||||
|
return fromJson(payload.toString(), resolvedType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new MessageConversionException(message, "Could not read JSON: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected Object convertToInternal(Object payload, @Nullable MessageHeaders headers, @Nullable Object conversionHint) {
|
||||||
|
try {
|
||||||
|
Type resolvedType = getResolvedType(payload.getClass(), conversionHint);
|
||||||
|
if (byte[].class == getSerializedPayloadClass()) {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
|
||||||
|
Writer writer = getWriter(out, headers);
|
||||||
|
toJson(payload, resolvedType, writer);
|
||||||
|
writer.flush();
|
||||||
|
return out.toByteArray();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Assuming a text-based target payload
|
||||||
|
return toJson(payload, resolvedType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new MessageConversionException("Could not write JSON: " + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Reader getReader(byte[] payload, @Nullable MessageHeaders headers) {
|
||||||
|
InputStream in = new ByteArrayInputStream(payload);
|
||||||
|
return new InputStreamReader(in, getCharsetToUse(headers));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Writer getWriter(ByteArrayOutputStream out, @Nullable MessageHeaders headers) {
|
||||||
|
return new OutputStreamWriter(out, getCharsetToUse(headers));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Charset getCharsetToUse(@Nullable MessageHeaders headers) {
|
||||||
|
MimeType mimeType = getMimeType(headers);
|
||||||
|
return (mimeType != null && mimeType.getCharset() != null ? mimeType.getCharset() : DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected abstract Object fromJson(Reader reader, Type resolvedType);
|
||||||
|
|
||||||
|
protected abstract Object fromJson(String payload, Type resolvedType);
|
||||||
|
|
||||||
|
protected abstract void toJson(Object payload, Type resolvedType, Writer writer);
|
||||||
|
|
||||||
|
protected abstract String toJson(Object payload, Type resolvedType);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.messaging.converter;
|
package org.springframework.messaging.converter;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
@ -25,6 +26,8 @@ import java.util.List;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.springframework.core.GenericTypeResolver;
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
import org.springframework.messaging.MessageHeaders;
|
import org.springframework.messaging.MessageHeaders;
|
||||||
|
|
@ -92,7 +95,7 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows sub-classes to add more supported mime types.
|
* Allows subclasses to add more supported mime types.
|
||||||
* @since 5.2.2
|
* @since 5.2.2
|
||||||
*/
|
*/
|
||||||
protected void addSupportedMimeTypes(MimeType... supportedMimeTypes) {
|
protected void addSupportedMimeTypes(MimeType... supportedMimeTypes) {
|
||||||
|
|
@ -167,21 +170,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.
|
|
||||||
* <p>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<MimeType> mimeTypes = getSupportedMimeTypes();
|
|
||||||
return (!mimeTypes.isEmpty() ? mimeTypes.get(0) : null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public final Object fromMessage(Message<?> message, Class<?> targetClass) {
|
public final Object fromMessage(Message<?> message, Class<?> targetClass) {
|
||||||
|
|
@ -197,10 +185,6 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter
|
||||||
return convertFromInternal(message, targetClass, conversionHint);
|
return convertFromInternal(message, targetClass, conversionHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean canConvertFrom(Message<?> message, Class<?> targetClass) {
|
|
||||||
return (supports(targetClass) && supportsMimeType(message.getHeaders()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public final Message<?> toMessage(Object payload, @Nullable MessageHeaders headers) {
|
public final Message<?> toMessage(Object payload, @Nullable MessageHeaders headers) {
|
||||||
|
|
@ -240,6 +224,11 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected boolean canConvertFrom(Message<?> message, Class<?> targetClass) {
|
||||||
|
return (supports(targetClass) && supportsMimeType(message.getHeaders()));
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean canConvertTo(Object payload, @Nullable MessageHeaders headers) {
|
protected boolean canConvertTo(Object payload, @Nullable MessageHeaders headers) {
|
||||||
return (supports(payload.getClass()) && supportsMimeType(headers));
|
return (supports(payload.getClass()) && supportsMimeType(headers));
|
||||||
}
|
}
|
||||||
|
|
@ -265,6 +254,22 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter
|
||||||
return (headers != null && this.contentTypeResolver != null ? this.contentTypeResolver.resolve(headers) : null);
|
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.
|
||||||
|
* <p>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<MimeType> mimeTypes = getSupportedMimeTypes();
|
||||||
|
return (!mimeTypes.isEmpty() ? mimeTypes.get(0) : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the given class is supported by this converter.
|
* Whether the given class is supported by this converter.
|
||||||
|
|
@ -307,4 +312,19 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Type getResolvedType(Class<?> targetClass, @Nullable Object conversionHint) {
|
||||||
|
if (conversionHint instanceof MethodParameter) {
|
||||||
|
MethodParameter param = (MethodParameter) conversionHint;
|
||||||
|
param = param.nestedIfOptional();
|
||||||
|
if (Message.class.isAssignableFrom(param.getParameterType())) {
|
||||||
|
param = param.nested();
|
||||||
|
}
|
||||||
|
Type genericParameterType = param.getNestedGenericParameterType();
|
||||||
|
Class<?> contextClass = param.getContainingClass();
|
||||||
|
return GenericTypeResolver.resolveType(genericParameterType, contextClass);
|
||||||
|
}
|
||||||
|
return targetClass;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://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.messaging.converter;
|
||||||
|
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of {@link MessageConverter} that can read and write JSON
|
||||||
|
* using <a href="https://code.google.com/p/google-gson/">Google Gson</a>.
|
||||||
|
*
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 5.3
|
||||||
|
* @see com.google.gson.Gson
|
||||||
|
* @see com.google.gson.GsonBuilder
|
||||||
|
* @see #setGson
|
||||||
|
*/
|
||||||
|
public class GsonMessageConverter extends AbstractJsonMessageConverter {
|
||||||
|
|
||||||
|
private Gson gson;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new {@code GsonMessageConverter} with default configuration.
|
||||||
|
*/
|
||||||
|
public GsonMessageConverter() {
|
||||||
|
this.gson = new Gson();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new {@code GsonMessageConverter} with the given delegate.
|
||||||
|
* @param gson the Gson instance to use
|
||||||
|
*/
|
||||||
|
public GsonMessageConverter(Gson gson) {
|
||||||
|
Assert.notNull(gson, "A Gson instance is required");
|
||||||
|
this.gson = gson;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@code Gson} instance to use.
|
||||||
|
* If not set, a default {@link Gson#Gson() Gson} instance will be used.
|
||||||
|
* <p>Setting a custom-configured {@code Gson} is one way to take further
|
||||||
|
* control of the JSON serialization process.
|
||||||
|
* @see #GsonMessageConverter(Gson)
|
||||||
|
*/
|
||||||
|
public void setGson(Gson gson) {
|
||||||
|
Assert.notNull(gson, "A Gson instance is required");
|
||||||
|
this.gson = gson;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the configured {@code Gson} instance for this converter.
|
||||||
|
*/
|
||||||
|
public Gson getGson() {
|
||||||
|
return this.gson;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object fromJson(Reader reader, Type resolvedType) {
|
||||||
|
return getGson().fromJson(reader, resolvedType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object fromJson(String payload, Type resolvedType) {
|
||||||
|
return getGson().fromJson(payload, resolvedType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void toJson(Object payload, Type resolvedType, Writer writer) {
|
||||||
|
if (resolvedType instanceof ParameterizedType) {
|
||||||
|
getGson().toJson(payload, resolvedType, writer);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
getGson().toJson(payload, writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String toJson(Object payload, Type resolvedType) {
|
||||||
|
if (resolvedType instanceof ParameterizedType) {
|
||||||
|
return getGson().toJson(payload, resolvedType);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return getGson().toJson(payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://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.messaging.converter;
|
||||||
|
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
import javax.json.bind.Jsonb;
|
||||||
|
import javax.json.bind.JsonbBuilder;
|
||||||
|
import javax.json.bind.JsonbConfig;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of {@link MessageConverter} that can read and write JSON
|
||||||
|
* using the <a href="http://json-b.net/">JSON Binding API</a>.
|
||||||
|
*
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 5.3
|
||||||
|
* @see javax.json.bind.Jsonb
|
||||||
|
* @see javax.json.bind.JsonbBuilder
|
||||||
|
* @see #setJsonb
|
||||||
|
*/
|
||||||
|
public class JsonbMessageConverter extends AbstractJsonMessageConverter {
|
||||||
|
|
||||||
|
private Jsonb jsonb;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new {@code JsonbMessageConverter} with default configuration.
|
||||||
|
*/
|
||||||
|
public JsonbMessageConverter() {
|
||||||
|
this.jsonb = JsonbBuilder.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new {@code JsonbMessageConverter} with the given configuration.
|
||||||
|
* @param config the {@code JsonbConfig} for the underlying delegate
|
||||||
|
*/
|
||||||
|
public JsonbMessageConverter(JsonbConfig config) {
|
||||||
|
this.jsonb = JsonbBuilder.create(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new {@code JsonbMessageConverter} with the given delegate.
|
||||||
|
* @param jsonb the Jsonb instance to use
|
||||||
|
*/
|
||||||
|
public JsonbMessageConverter(Jsonb jsonb) {
|
||||||
|
Assert.notNull(jsonb, "A Jsonb instance is required");
|
||||||
|
this.jsonb = jsonb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@code Jsonb} instance to use.
|
||||||
|
* If not set, a default {@code Jsonb} instance will be created.
|
||||||
|
* <p>Setting a custom-configured {@code Jsonb} is one way to take further
|
||||||
|
* control of the JSON serialization process.
|
||||||
|
* @see #JsonbMessageConverter(Jsonb)
|
||||||
|
* @see #JsonbMessageConverter(JsonbConfig)
|
||||||
|
* @see JsonbBuilder
|
||||||
|
*/
|
||||||
|
public void setJsonb(Jsonb jsonb) {
|
||||||
|
Assert.notNull(jsonb, "A Jsonb instance is required");
|
||||||
|
this.jsonb = jsonb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the configured {@code Jsonb} instance for this converter.
|
||||||
|
*/
|
||||||
|
public Jsonb getJsonb() {
|
||||||
|
return this.jsonb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object fromJson(Reader reader, Type resolvedType) {
|
||||||
|
return getJsonb().fromJson(reader, resolvedType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object fromJson(String payload, Type resolvedType) {
|
||||||
|
return getJsonb().fromJson(payload, resolvedType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void toJson(Object payload, Type resolvedType, Writer writer) {
|
||||||
|
if (resolvedType instanceof ParameterizedType) {
|
||||||
|
getJsonb().toJson(payload, resolvedType, writer);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
getJsonb().toJson(payload, writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String toJson(Object payload, Type resolvedType) {
|
||||||
|
if (resolvedType instanceof ParameterizedType) {
|
||||||
|
return getJsonb().toJson(payload, resolvedType);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return getJsonb().toJson(payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -35,12 +35,12 @@ import com.fasterxml.jackson.databind.MapperFeature;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
|
||||||
import org.springframework.core.GenericTypeResolver;
|
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
import org.springframework.messaging.MessageHeaders;
|
import org.springframework.messaging.MessageHeaders;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.MimeType;
|
import org.springframework.util.MimeType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,6 +139,7 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canConvertFrom(Message<?> message, @Nullable Class<?> targetClass) {
|
protected boolean canConvertFrom(Message<?> message, @Nullable Class<?> targetClass) {
|
||||||
if (targetClass == null || !supportsMimeType(message.getHeaders())) {
|
if (targetClass == null || !supportsMimeType(message.getHeaders())) {
|
||||||
|
|
@ -206,11 +207,11 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter {
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
protected Object convertFromInternal(Message<?> message, Class<?> targetClass, @Nullable Object conversionHint) {
|
protected Object convertFromInternal(Message<?> message, Class<?> targetClass, @Nullable Object conversionHint) {
|
||||||
JavaType javaType = getJavaType(targetClass, conversionHint);
|
JavaType javaType = this.objectMapper.constructType(getResolvedType(targetClass, conversionHint));
|
||||||
Object payload = message.getPayload();
|
Object payload = message.getPayload();
|
||||||
Class<?> view = getSerializationView(conversionHint);
|
Class<?> view = getSerializationView(conversionHint);
|
||||||
try {
|
try {
|
||||||
if (targetClass.isInstance(payload)) {
|
if (ClassUtils.isAssignableValue(targetClass, payload)) {
|
||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
else if (payload instanceof byte[]) {
|
else if (payload instanceof byte[]) {
|
||||||
|
|
@ -236,21 +237,6 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JavaType getJavaType(Class<?> targetClass, @Nullable Object conversionHint) {
|
|
||||||
if (conversionHint instanceof MethodParameter) {
|
|
||||||
MethodParameter param = (MethodParameter) conversionHint;
|
|
||||||
param = param.nestedIfOptional();
|
|
||||||
if (Message.class.isAssignableFrom(param.getParameterType())) {
|
|
||||||
param = param.nested();
|
|
||||||
}
|
|
||||||
Type genericParameterType = param.getNestedGenericParameterType();
|
|
||||||
Class<?> contextClass = param.getContainingClass();
|
|
||||||
Type type = GenericTypeResolver.resolveType(genericParameterType, contextClass);
|
|
||||||
return this.objectMapper.getTypeFactory().constructType(type);
|
|
||||||
}
|
|
||||||
return this.objectMapper.constructType(targetClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
protected Object convertToInternal(Object payload, @Nullable MessageHeaders headers,
|
protected Object convertToInternal(Object payload, @Nullable MessageHeaders headers,
|
||||||
|
|
@ -331,7 +317,7 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter {
|
||||||
* @return the JSON encoding to use (never {@code null})
|
* @return the JSON encoding to use (never {@code null})
|
||||||
*/
|
*/
|
||||||
protected JsonEncoding getJsonEncoding(@Nullable MimeType contentType) {
|
protected JsonEncoding getJsonEncoding(@Nullable MimeType contentType) {
|
||||||
if (contentType != null && (contentType.getCharset() != null)) {
|
if (contentType != null && contentType.getCharset() != null) {
|
||||||
Charset charset = contentType.getCharset();
|
Charset charset = contentType.getCharset();
|
||||||
for (JsonEncoding encoding : JsonEncoding.values()) {
|
for (JsonEncoding encoding : JsonEncoding.values()) {
|
||||||
if (charset.name().equals(encoding.getJavaName())) {
|
if (charset.name().equals(encoding.getJavaName())) {
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -34,6 +34,8 @@ import org.springframework.messaging.MessageHandler;
|
||||||
import org.springframework.messaging.converter.ByteArrayMessageConverter;
|
import org.springframework.messaging.converter.ByteArrayMessageConverter;
|
||||||
import org.springframework.messaging.converter.CompositeMessageConverter;
|
import org.springframework.messaging.converter.CompositeMessageConverter;
|
||||||
import org.springframework.messaging.converter.DefaultContentTypeResolver;
|
import org.springframework.messaging.converter.DefaultContentTypeResolver;
|
||||||
|
import org.springframework.messaging.converter.GsonMessageConverter;
|
||||||
|
import org.springframework.messaging.converter.JsonbMessageConverter;
|
||||||
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
|
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
|
||||||
import org.springframework.messaging.converter.MessageConverter;
|
import org.springframework.messaging.converter.MessageConverter;
|
||||||
import org.springframework.messaging.converter.StringMessageConverter;
|
import org.springframework.messaging.converter.StringMessageConverter;
|
||||||
|
|
@ -93,8 +95,20 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
|
||||||
|
|
||||||
private static final String MVC_VALIDATOR_NAME = "mvcValidator";
|
private static final String MVC_VALIDATOR_NAME = "mvcValidator";
|
||||||
|
|
||||||
private static final boolean jackson2Present = ClassUtils.isPresent(
|
private static final boolean jackson2Present;
|
||||||
"com.fasterxml.jackson.databind.ObjectMapper", AbstractMessageBrokerConfiguration.class.getClassLoader());
|
|
||||||
|
private static final boolean gsonPresent;
|
||||||
|
|
||||||
|
private static final boolean jsonbPresent;
|
||||||
|
|
||||||
|
|
||||||
|
static {
|
||||||
|
ClassLoader classLoader = AbstractMessageBrokerConfiguration.class.getClassLoader();
|
||||||
|
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
|
||||||
|
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
|
||||||
|
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
|
||||||
|
jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
@ -391,6 +405,12 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
|
||||||
if (jackson2Present) {
|
if (jackson2Present) {
|
||||||
converters.add(createJacksonConverter());
|
converters.add(createJacksonConverter());
|
||||||
}
|
}
|
||||||
|
else if (gsonPresent) {
|
||||||
|
converters.add(new GsonMessageConverter());
|
||||||
|
}
|
||||||
|
else if (jsonbPresent) {
|
||||||
|
converters.add(new JsonbMessageConverter());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new CompositeMessageConverter(converters);
|
return new CompositeMessageConverter(converters);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,249 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://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.messaging.converter;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.messaging.Message;
|
||||||
|
import org.springframework.messaging.MessageHeaders;
|
||||||
|
import org.springframework.messaging.support.MessageBuilder;
|
||||||
|
import org.springframework.util.MimeType;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
import static org.assertj.core.api.Assertions.within;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test fixture for {@link GsonMessageConverter}.
|
||||||
|
*
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
|
* @author Sebastien Deleuze
|
||||||
|
*/
|
||||||
|
public class GsonMessageConverterTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultConstructor() {
|
||||||
|
GsonMessageConverter converter = new GsonMessageConverter();
|
||||||
|
assertThat(converter.getSupportedMimeTypes()).contains(new MimeType("application", "json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessage() {
|
||||||
|
GsonMessageConverter converter = new GsonMessageConverter();
|
||||||
|
String payload = "{\"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);
|
||||||
|
|
||||||
|
assertThat(actual.getString()).isEqualTo("Foo");
|
||||||
|
assertThat(actual.getNumber()).isEqualTo(42);
|
||||||
|
assertThat(actual.getFraction()).isCloseTo(42F, within(0F));
|
||||||
|
assertThat(actual.getArray()).isEqualTo(new String[]{"Foo", "Bar"});
|
||||||
|
assertThat(actual.isBool()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessageUntyped() {
|
||||||
|
GsonMessageConverter converter = new GsonMessageConverter();
|
||||||
|
String payload = "{\"array\":[\"Foo\",\"Bar\"]," +
|
||||||
|
"\"number\":42,\"string\":\"Foo\",\"bool\":true,\"fraction\":42.0}";
|
||||||
|
Message<?> message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build();
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
HashMap<String, Object> actual = (HashMap<String, Object>) converter.fromMessage(message, HashMap.class);
|
||||||
|
|
||||||
|
assertThat(actual.get("string")).isEqualTo("Foo");
|
||||||
|
assertThat(actual.get("number")).isEqualTo(42.0);
|
||||||
|
assertThat((Double) actual.get("fraction")).isCloseTo(42D, within(0D));
|
||||||
|
assertThat(actual.get("array")).isEqualTo(Arrays.asList("Foo", "Bar"));
|
||||||
|
assertThat(actual.get("bool")).isEqualTo(Boolean.TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessageMatchingInstance() {
|
||||||
|
MyBean myBean = new MyBean();
|
||||||
|
GsonMessageConverter converter = new GsonMessageConverter();
|
||||||
|
Message<?> message = MessageBuilder.withPayload(myBean).build();
|
||||||
|
assertThat(converter.fromMessage(message, MyBean.class)).isSameAs(myBean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessageInvalidJson() {
|
||||||
|
GsonMessageConverter converter = new GsonMessageConverter();
|
||||||
|
String payload = "FooBar";
|
||||||
|
Message<?> message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build();
|
||||||
|
assertThatExceptionOfType(MessageConversionException.class).isThrownBy(() ->
|
||||||
|
converter.fromMessage(message, MyBean.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessageValidJsonWithUnknownProperty() {
|
||||||
|
GsonMessageConverter converter = new GsonMessageConverter();
|
||||||
|
String payload = "{\"string\":\"string\",\"unknownProperty\":\"value\"}";
|
||||||
|
Message<?> message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build();
|
||||||
|
MyBean myBean = (MyBean)converter.fromMessage(message, MyBean.class);
|
||||||
|
assertThat(myBean.getString()).isEqualTo("string");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessageToList() throws Exception {
|
||||||
|
GsonMessageConverter converter = new GsonMessageConverter();
|
||||||
|
String payload = "[1, 2, 3, 4, 5, 6, 7, 8, 9]";
|
||||||
|
Message<?> message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build();
|
||||||
|
|
||||||
|
Method method = getClass().getDeclaredMethod("handleList", List.class);
|
||||||
|
MethodParameter param = new MethodParameter(method, 0);
|
||||||
|
Object actual = converter.fromMessage(message, List.class, param);
|
||||||
|
|
||||||
|
assertThat(actual).isNotNull();
|
||||||
|
assertThat(actual).isEqualTo(Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessageToMessageWithPojo() throws Exception {
|
||||||
|
GsonMessageConverter converter = new GsonMessageConverter();
|
||||||
|
String payload = "{\"string\":\"foo\"}";
|
||||||
|
Message<?> message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build();
|
||||||
|
|
||||||
|
Method method = getClass().getDeclaredMethod("handleMessage", Message.class);
|
||||||
|
MethodParameter param = new MethodParameter(method, 0);
|
||||||
|
Object actual = converter.fromMessage(message, MyBean.class, param);
|
||||||
|
|
||||||
|
assertThat(actual instanceof MyBean).isTrue();
|
||||||
|
assertThat(((MyBean) actual).getString()).isEqualTo("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toMessage() {
|
||||||
|
GsonMessageConverter converter = new GsonMessageConverter();
|
||||||
|
MyBean payload = new MyBean();
|
||||||
|
payload.setString("Foo");
|
||||||
|
payload.setNumber(42);
|
||||||
|
payload.setFraction(42F);
|
||||||
|
payload.setArray(new String[]{"Foo", "Bar"});
|
||||||
|
payload.setBool(true);
|
||||||
|
|
||||||
|
Message<?> message = converter.toMessage(payload, null);
|
||||||
|
String actual = new String((byte[]) message.getPayload(), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
assertThat(actual.contains("\"string\":\"Foo\"")).isTrue();
|
||||||
|
assertThat(actual.contains("\"number\":42")).isTrue();
|
||||||
|
assertThat(actual.contains("fraction\":42.0")).isTrue();
|
||||||
|
assertThat(actual.contains("\"array\":[\"Foo\",\"Bar\"]")).isTrue();
|
||||||
|
assertThat(actual.contains("\"bool\":true")).isTrue();
|
||||||
|
assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class)).as("Invalid content-type").isEqualTo(new MimeType("application", "json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toMessageUtf16() {
|
||||||
|
GsonMessageConverter converter = new GsonMessageConverter();
|
||||||
|
MimeType contentType = new MimeType("application", "json", StandardCharsets.UTF_16BE);
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
map.put(MessageHeaders.CONTENT_TYPE, contentType);
|
||||||
|
MessageHeaders headers = new MessageHeaders(map);
|
||||||
|
String payload = "H\u00e9llo W\u00f6rld";
|
||||||
|
Message<?> message = converter.toMessage(payload, headers);
|
||||||
|
|
||||||
|
assertThat(new String((byte[]) message.getPayload(), StandardCharsets.UTF_16BE)).isEqualTo("\"" + payload + "\"");
|
||||||
|
assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)).isEqualTo(contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toMessageUtf16String() {
|
||||||
|
GsonMessageConverter converter = new GsonMessageConverter();
|
||||||
|
converter.setSerializedPayloadClass(String.class);
|
||||||
|
|
||||||
|
MimeType contentType = new MimeType("application", "json", StandardCharsets.UTF_16BE);
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
map.put(MessageHeaders.CONTENT_TYPE, contentType);
|
||||||
|
MessageHeaders headers = new MessageHeaders(map);
|
||||||
|
String payload = "H\u00e9llo W\u00f6rld";
|
||||||
|
Message<?> message = converter.toMessage(payload, headers);
|
||||||
|
|
||||||
|
assertThat(message.getPayload()).isEqualTo("\"" + payload + "\"");
|
||||||
|
assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)).isEqualTo(contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void handleList(List<Long> payload) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleMessage(Message<MyBean> message) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class MyBean {
|
||||||
|
|
||||||
|
private String string;
|
||||||
|
|
||||||
|
private int number;
|
||||||
|
|
||||||
|
private float fraction;
|
||||||
|
|
||||||
|
private String[] array;
|
||||||
|
|
||||||
|
private boolean bool;
|
||||||
|
|
||||||
|
public boolean isBool() {
|
||||||
|
return bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBool(boolean bool) {
|
||||||
|
this.bool = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString() {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setString(String string) {
|
||||||
|
this.string = string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumber() {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumber(int number) {
|
||||||
|
this.number = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getFraction() {
|
||||||
|
return fraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFraction(float fraction) {
|
||||||
|
this.fraction = fraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getArray() {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setArray(String[] array) {
|
||||||
|
this.array = array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,249 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://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.messaging.converter;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.messaging.Message;
|
||||||
|
import org.springframework.messaging.MessageHeaders;
|
||||||
|
import org.springframework.messaging.support.MessageBuilder;
|
||||||
|
import org.springframework.util.MimeType;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
import static org.assertj.core.api.Assertions.within;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test fixture for {@link JsonbMessageConverter}.
|
||||||
|
*
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
|
* @author Sebastien Deleuze
|
||||||
|
*/
|
||||||
|
public class JsonbMessageConverterTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultConstructor() {
|
||||||
|
JsonbMessageConverter converter = new JsonbMessageConverter();
|
||||||
|
assertThat(converter.getSupportedMimeTypes()).contains(new MimeType("application", "json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessage() {
|
||||||
|
JsonbMessageConverter converter = new JsonbMessageConverter();
|
||||||
|
String payload = "{\"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);
|
||||||
|
|
||||||
|
assertThat(actual.getString()).isEqualTo("Foo");
|
||||||
|
assertThat(actual.getNumber()).isEqualTo(42);
|
||||||
|
assertThat(actual.getFraction()).isCloseTo(42F, within(0F));
|
||||||
|
assertThat(actual.getArray()).isEqualTo(new String[]{"Foo", "Bar"});
|
||||||
|
assertThat(actual.isBool()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessageUntyped() {
|
||||||
|
JsonbMessageConverter converter = new JsonbMessageConverter();
|
||||||
|
String payload = "{\"array\":[\"Foo\",\"Bar\"]," +
|
||||||
|
"\"number\":42,\"string\":\"Foo\",\"bool\":true,\"fraction\":42.0}";
|
||||||
|
Message<?> message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build();
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
HashMap<String, Object> actual = (HashMap<String, Object>) converter.fromMessage(message, HashMap.class);
|
||||||
|
|
||||||
|
assertThat(actual.get("string")).isEqualTo("Foo");
|
||||||
|
assertThat(actual.get("number")).isEqualTo(42);
|
||||||
|
assertThat((Double) actual.get("fraction")).isCloseTo(42D, within(0D));
|
||||||
|
assertThat(actual.get("array")).isEqualTo(Arrays.asList("Foo", "Bar"));
|
||||||
|
assertThat(actual.get("bool")).isEqualTo(Boolean.TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessageMatchingInstance() {
|
||||||
|
MyBean myBean = new MyBean();
|
||||||
|
JsonbMessageConverter converter = new JsonbMessageConverter();
|
||||||
|
Message<?> message = MessageBuilder.withPayload(myBean).build();
|
||||||
|
assertThat(converter.fromMessage(message, MyBean.class)).isSameAs(myBean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessageInvalidJson() {
|
||||||
|
JsonbMessageConverter converter = new JsonbMessageConverter();
|
||||||
|
String payload = "FooBar";
|
||||||
|
Message<?> message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build();
|
||||||
|
assertThatExceptionOfType(MessageConversionException.class).isThrownBy(() ->
|
||||||
|
converter.fromMessage(message, MyBean.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessageValidJsonWithUnknownProperty() {
|
||||||
|
JsonbMessageConverter converter = new JsonbMessageConverter();
|
||||||
|
String payload = "{\"string\":\"string\",\"unknownProperty\":\"value\"}";
|
||||||
|
Message<?> message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build();
|
||||||
|
MyBean myBean = (MyBean)converter.fromMessage(message, MyBean.class);
|
||||||
|
assertThat(myBean.getString()).isEqualTo("string");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessageToList() throws Exception {
|
||||||
|
JsonbMessageConverter converter = new JsonbMessageConverter();
|
||||||
|
String payload = "[1, 2, 3, 4, 5, 6, 7, 8, 9]";
|
||||||
|
Message<?> message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build();
|
||||||
|
|
||||||
|
Method method = getClass().getDeclaredMethod("handleList", List.class);
|
||||||
|
MethodParameter param = new MethodParameter(method, 0);
|
||||||
|
Object actual = converter.fromMessage(message, List.class, param);
|
||||||
|
|
||||||
|
assertThat(actual).isNotNull();
|
||||||
|
assertThat(actual).isEqualTo(Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromMessageToMessageWithPojo() throws Exception {
|
||||||
|
JsonbMessageConverter converter = new JsonbMessageConverter();
|
||||||
|
String payload = "{\"string\":\"foo\"}";
|
||||||
|
Message<?> message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build();
|
||||||
|
|
||||||
|
Method method = getClass().getDeclaredMethod("handleMessage", Message.class);
|
||||||
|
MethodParameter param = new MethodParameter(method, 0);
|
||||||
|
Object actual = converter.fromMessage(message, MyBean.class, param);
|
||||||
|
|
||||||
|
assertThat(actual instanceof MyBean).isTrue();
|
||||||
|
assertThat(((MyBean) actual).getString()).isEqualTo("foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toMessage() {
|
||||||
|
JsonbMessageConverter converter = new JsonbMessageConverter();
|
||||||
|
MyBean payload = new MyBean();
|
||||||
|
payload.setString("Foo");
|
||||||
|
payload.setNumber(42);
|
||||||
|
payload.setFraction(42F);
|
||||||
|
payload.setArray(new String[]{"Foo", "Bar"});
|
||||||
|
payload.setBool(true);
|
||||||
|
|
||||||
|
Message<?> message = converter.toMessage(payload, null);
|
||||||
|
String actual = new String((byte[]) message.getPayload(), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
assertThat(actual.contains("\"string\":\"Foo\"")).isTrue();
|
||||||
|
assertThat(actual.contains("\"number\":42")).isTrue();
|
||||||
|
assertThat(actual.contains("fraction\":42.0")).isTrue();
|
||||||
|
assertThat(actual.contains("\"array\":[\"Foo\",\"Bar\"]")).isTrue();
|
||||||
|
assertThat(actual.contains("\"bool\":true")).isTrue();
|
||||||
|
assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MimeType.class)).as("Invalid content-type").isEqualTo(new MimeType("application", "json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toMessageUtf16() {
|
||||||
|
JsonbMessageConverter converter = new JsonbMessageConverter();
|
||||||
|
MimeType contentType = new MimeType("application", "json", StandardCharsets.UTF_16BE);
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
map.put(MessageHeaders.CONTENT_TYPE, contentType);
|
||||||
|
MessageHeaders headers = new MessageHeaders(map);
|
||||||
|
String payload = "H\u00e9llo W\u00f6rld";
|
||||||
|
Message<?> message = converter.toMessage(payload, headers);
|
||||||
|
|
||||||
|
assertThat(new String((byte[]) message.getPayload(), StandardCharsets.UTF_16BE)).isEqualTo(payload);
|
||||||
|
assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)).isEqualTo(contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toMessageUtf16String() {
|
||||||
|
JsonbMessageConverter converter = new JsonbMessageConverter();
|
||||||
|
converter.setSerializedPayloadClass(String.class);
|
||||||
|
|
||||||
|
MimeType contentType = new MimeType("application", "json", StandardCharsets.UTF_16BE);
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
map.put(MessageHeaders.CONTENT_TYPE, contentType);
|
||||||
|
MessageHeaders headers = new MessageHeaders(map);
|
||||||
|
String payload = "H\u00e9llo W\u00f6rld";
|
||||||
|
Message<?> message = converter.toMessage(payload, headers);
|
||||||
|
|
||||||
|
assertThat(message.getPayload()).isEqualTo(payload);
|
||||||
|
assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)).isEqualTo(contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void handleList(List<Long> payload) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleMessage(Message<MyBean> message) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class MyBean {
|
||||||
|
|
||||||
|
private String string;
|
||||||
|
|
||||||
|
private int number;
|
||||||
|
|
||||||
|
private float fraction;
|
||||||
|
|
||||||
|
private String[] array;
|
||||||
|
|
||||||
|
private boolean bool;
|
||||||
|
|
||||||
|
public boolean isBool() {
|
||||||
|
return bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBool(boolean bool) {
|
||||||
|
this.bool = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString() {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setString(String string) {
|
||||||
|
this.string = string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumber() {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumber(int number) {
|
||||||
|
this.number = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getFraction() {
|
||||||
|
return fraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFraction(float fraction) {
|
||||||
|
this.fraction = fraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getArray() {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setArray(String[] array) {
|
||||||
|
this.array = array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -48,10 +48,9 @@ public class MappingJackson2MessageConverterTests {
|
||||||
@Test
|
@Test
|
||||||
public void defaultConstructor() {
|
public void defaultConstructor() {
|
||||||
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
||||||
assertThat(converter.getSupportedMimeTypes())
|
assertThat(converter.getSupportedMimeTypes()).contains(new MimeType("application", "json"));
|
||||||
.contains(new MimeType("application", "json"));
|
|
||||||
assertThat(converter.getObjectMapper().getDeserializationConfig()
|
assertThat(converter.getObjectMapper().getDeserializationConfig()
|
||||||
.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)).isFalse();
|
.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-12724
|
@Test // SPR-12724
|
||||||
|
|
@ -60,7 +59,7 @@ public class MappingJackson2MessageConverterTests {
|
||||||
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(mimetype);
|
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(mimetype);
|
||||||
assertThat(converter.getSupportedMimeTypes()).contains(mimetype);
|
assertThat(converter.getSupportedMimeTypes()).contains(mimetype);
|
||||||
assertThat(converter.getObjectMapper().getDeserializationConfig()
|
assertThat(converter.getObjectMapper().getDeserializationConfig()
|
||||||
.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)).isFalse();
|
.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-12724
|
@Test // SPR-12724
|
||||||
|
|
@ -70,19 +69,14 @@ public class MappingJackson2MessageConverterTests {
|
||||||
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(jsonMimetype, xmlMimetype);
|
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(jsonMimetype, xmlMimetype);
|
||||||
assertThat(converter.getSupportedMimeTypes()).contains(jsonMimetype, xmlMimetype);
|
assertThat(converter.getSupportedMimeTypes()).contains(jsonMimetype, xmlMimetype);
|
||||||
assertThat(converter.getObjectMapper().getDeserializationConfig()
|
assertThat(converter.getObjectMapper().getDeserializationConfig()
|
||||||
.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)).isFalse();
|
.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void fromMessage() {
|
public void fromMessage() {
|
||||||
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
||||||
String payload = "{" +
|
String payload = "{\"bytes\":\"AQI=\",\"array\":[\"Foo\",\"Bar\"]," +
|
||||||
"\"bytes\":\"AQI=\"," +
|
"\"number\":42,\"string\":\"Foo\",\"bool\":true,\"fraction\":42.0}";
|
||||||
"\"array\":[\"Foo\",\"Bar\"]," +
|
|
||||||
"\"number\":42," +
|
|
||||||
"\"string\":\"Foo\"," +
|
|
||||||
"\"bool\":true," +
|
|
||||||
"\"fraction\":42.0}";
|
|
||||||
Message<?> message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build();
|
Message<?> message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build();
|
||||||
MyBean actual = (MyBean) converter.fromMessage(message, MyBean.class);
|
MyBean actual = (MyBean) converter.fromMessage(message, MyBean.class);
|
||||||
|
|
||||||
|
|
@ -97,8 +91,8 @@ public class MappingJackson2MessageConverterTests {
|
||||||
@Test
|
@Test
|
||||||
public void fromMessageUntyped() {
|
public void fromMessageUntyped() {
|
||||||
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
||||||
String payload = "{\"bytes\":\"AQI=\",\"array\":[\"Foo\",\"Bar\"],"
|
String payload = "{\"bytes\":\"AQI=\",\"array\":[\"Foo\",\"Bar\"]," +
|
||||||
+ "\"number\":42,\"string\":\"Foo\",\"bool\":true,\"fraction\":42.0}";
|
"\"number\":42,\"string\":\"Foo\",\"bool\":true,\"fraction\":42.0}";
|
||||||
Message<?> message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build();
|
Message<?> message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build();
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
HashMap<String, Object> actual = (HashMap<String, Object>) converter.fromMessage(message, HashMap.class);
|
HashMap<String, Object> actual = (HashMap<String, Object>) converter.fromMessage(message, HashMap.class);
|
||||||
|
|
@ -111,7 +105,7 @@ public class MappingJackson2MessageConverterTests {
|
||||||
assertThat(actual.get("bytes")).isEqualTo("AQI=");
|
assertThat(actual.get("bytes")).isEqualTo("AQI=");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // gh-22386
|
@Test // gh-22386
|
||||||
public void fromMessageMatchingInstance() {
|
public void fromMessageMatchingInstance() {
|
||||||
MyBean myBean = new MyBean();
|
MyBean myBean = new MyBean();
|
||||||
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
||||||
|
|
@ -137,7 +131,7 @@ public class MappingJackson2MessageConverterTests {
|
||||||
assertThat(myBean.getString()).isEqualTo("string");
|
assertThat(myBean.getString()).isEqualTo("string");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-16252
|
@Test // SPR-16252
|
||||||
public void fromMessageToList() throws Exception {
|
public void fromMessageToList() throws Exception {
|
||||||
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
||||||
String payload = "[1, 2, 3, 4, 5, 6, 7, 8, 9]";
|
String payload = "[1, 2, 3, 4, 5, 6, 7, 8, 9]";
|
||||||
|
|
@ -151,7 +145,7 @@ public class MappingJackson2MessageConverterTests {
|
||||||
assertThat(actual).isEqualTo(Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L));
|
assertThat(actual).isEqualTo(Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-16486
|
@Test // SPR-16486
|
||||||
public void fromMessageToMessageWithPojo() throws Exception {
|
public void fromMessageToMessageWithPojo() throws Exception {
|
||||||
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
||||||
String payload = "{\"string\":\"foo\"}";
|
String payload = "{\"string\":\"foo\"}";
|
||||||
|
|
@ -198,7 +192,7 @@ public class MappingJackson2MessageConverterTests {
|
||||||
String payload = "H\u00e9llo W\u00f6rld";
|
String payload = "H\u00e9llo W\u00f6rld";
|
||||||
Message<?> message = converter.toMessage(payload, headers);
|
Message<?> message = converter.toMessage(payload, headers);
|
||||||
|
|
||||||
assertThat(new String((byte[]) message.getPayload(), StandardCharsets.UTF_16BE)).isEqualTo(("\"" + payload + "\""));
|
assertThat(new String((byte[]) message.getPayload(), StandardCharsets.UTF_16BE)).isEqualTo("\"" + payload + "\"");
|
||||||
assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)).isEqualTo(contentType);
|
assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)).isEqualTo(contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,7 +208,7 @@ public class MappingJackson2MessageConverterTests {
|
||||||
String payload = "H\u00e9llo W\u00f6rld";
|
String payload = "H\u00e9llo W\u00f6rld";
|
||||||
Message<?> message = converter.toMessage(payload, headers);
|
Message<?> message = converter.toMessage(payload, headers);
|
||||||
|
|
||||||
assertThat(message.getPayload()).isEqualTo(("\"" + payload + "\""));
|
assertThat(message.getPayload()).isEqualTo("\"" + payload + "\"");
|
||||||
assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)).isEqualTo(contentType);
|
assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)).isEqualTo(contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -254,9 +248,12 @@ public class MappingJackson2MessageConverterTests {
|
||||||
public void jsonViewPayload(@JsonView(MyJacksonView2.class) JacksonViewBean payload) {
|
public void jsonViewPayload(@JsonView(MyJacksonView2.class) JacksonViewBean payload) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleList(List<Long> payload) {}
|
void handleList(List<Long> payload) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleMessage(Message<MyBean> message) {
|
||||||
|
}
|
||||||
|
|
||||||
void handleMessage(Message<MyBean> message) {}
|
|
||||||
|
|
||||||
public static class MyBean {
|
public static class MyBean {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -42,6 +42,8 @@ import org.springframework.lang.Nullable;
|
||||||
import org.springframework.messaging.converter.ByteArrayMessageConverter;
|
import org.springframework.messaging.converter.ByteArrayMessageConverter;
|
||||||
import org.springframework.messaging.converter.CompositeMessageConverter;
|
import org.springframework.messaging.converter.CompositeMessageConverter;
|
||||||
import org.springframework.messaging.converter.DefaultContentTypeResolver;
|
import org.springframework.messaging.converter.DefaultContentTypeResolver;
|
||||||
|
import org.springframework.messaging.converter.GsonMessageConverter;
|
||||||
|
import org.springframework.messaging.converter.JsonbMessageConverter;
|
||||||
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
|
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
|
||||||
import org.springframework.messaging.converter.StringMessageConverter;
|
import org.springframework.messaging.converter.StringMessageConverter;
|
||||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||||
|
|
@ -113,11 +115,18 @@ class MessageBrokerBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
|
|
||||||
private static final boolean jackson2Present;
|
private static final boolean jackson2Present;
|
||||||
|
|
||||||
|
private static final boolean gsonPresent;
|
||||||
|
|
||||||
|
private static final boolean jsonbPresent;
|
||||||
|
|
||||||
private static final boolean javaxValidationPresent;
|
private static final boolean javaxValidationPresent;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ClassLoader classLoader = MessageBrokerBeanDefinitionParser.class.getClassLoader();
|
ClassLoader classLoader = MessageBrokerBeanDefinitionParser.class.getClassLoader();
|
||||||
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader);
|
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
|
||||||
|
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
|
||||||
|
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
|
||||||
|
jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
|
||||||
javaxValidationPresent = ClassUtils.isPresent("javax.validation.Validator", classLoader);
|
javaxValidationPresent = ClassUtils.isPresent("javax.validation.Validator", classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -502,6 +511,12 @@ class MessageBrokerBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
jacksonConverterDef.getPropertyValues().add("objectMapper", jacksonFactoryDef);
|
jacksonConverterDef.getPropertyValues().add("objectMapper", jacksonFactoryDef);
|
||||||
converters.add(jacksonConverterDef);
|
converters.add(jacksonConverterDef);
|
||||||
}
|
}
|
||||||
|
else if (gsonPresent) {
|
||||||
|
converters.add(new RootBeanDefinition(GsonMessageConverter.class));
|
||||||
|
}
|
||||||
|
else if (jsonbPresent) {
|
||||||
|
converters.add(new RootBeanDefinition(JsonbMessageConverter.class));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ConstructorArgumentValues cargs = new ConstructorArgumentValues();
|
ConstructorArgumentValues cargs = new ConstructorArgumentValues();
|
||||||
cargs.addIndexedArgumentValue(0, converters);
|
cargs.addIndexedArgumentValue(0, converters);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue