GH-8757: Add nullabilty to .support.converter
Fixes https://github.com/spring-projects/spring-integration/issues/8757 * Add ctor `ObjectStringMessageConverter(Charset)` * create tests for `ObjectStringMessageConverter` * fix codestyle issues * revise JavaDoc * `@NonNullApi` for `org.springframework.integration.support.converter` * revise `SimpleMessageConverter` * `inboundMessageMapper` and `outboundMessageMapper` are initialized to their default implementations Bboth are set in non-default ctors with final setters * remove `@Nullable` from `private BeanFactory beanFactory` * Handle empty `String... headerNames` * Some code clean up
This commit is contained in:
committed by
Artem Bilan
parent
6909fbe7ad
commit
29186e2b46
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
@@ -30,6 +30,7 @@ import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.serializer.DefaultDeserializer;
|
||||
import org.springframework.core.serializer.Deserializer;
|
||||
import org.springframework.core.serializer.support.SerializationFailedException;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
@@ -55,6 +56,7 @@ public class AllowListDeserializingConverter implements Converter<byte[], Object
|
||||
|
||||
private final Deserializer<Object> deserializer;
|
||||
|
||||
@Nullable
|
||||
private final ClassLoader defaultDeserializerClassLoader;
|
||||
|
||||
private final boolean usingDefaultDeserializer;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2023 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.
|
||||
@@ -22,6 +22,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.integration.support.utils.IntegrationUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.converter.MessageConverter;
|
||||
@@ -33,22 +34,21 @@ import org.springframework.util.Assert;
|
||||
* if present.
|
||||
*
|
||||
* @author Gary Russell
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
*/
|
||||
public class DefaultDatatypeChannelMessageConverter implements MessageConverter,
|
||||
BeanFactoryAware {
|
||||
public class DefaultDatatypeChannelMessageConverter implements MessageConverter, BeanFactoryAware {
|
||||
|
||||
private volatile ConversionService conversionService = DefaultConversionService.getSharedInstance();
|
||||
private ConversionService conversionService = DefaultConversionService.getSharedInstance();
|
||||
|
||||
private volatile boolean conversionServiceSet;
|
||||
private boolean conversionServiceSet;
|
||||
|
||||
/**
|
||||
* Specify the {@link ConversionService} to use when trying to convert to
|
||||
* requested type. If this property is not set explicitly but
|
||||
* the converter is managed within a context, it will attempt to locate a
|
||||
* bean named "integrationConversionService" defined within that context.
|
||||
*
|
||||
* @param conversionService The conversion service.
|
||||
*/
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
@@ -59,7 +59,7 @@ public class DefaultDatatypeChannelMessageConverter implements MessageConverter,
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
if (!this.conversionServiceSet && beanFactory != null) {
|
||||
if (!this.conversionServiceSet) {
|
||||
ConversionService integrationConversionService = IntegrationUtils.getConversionService(beanFactory);
|
||||
if (integrationConversionService != null) {
|
||||
this.conversionService = integrationConversionService;
|
||||
@@ -81,7 +81,7 @@ public class DefaultDatatypeChannelMessageConverter implements MessageConverter,
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message<?> toMessage(Object payload, MessageHeaders header) {
|
||||
public Message<?> toMessage(Object payload, @Nullable MessageHeaders header) {
|
||||
throw new UnsupportedOperationException("This converter does not support this method");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
@@ -31,6 +31,7 @@ import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.converter.MessageConverter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Converts to/from a Map with 2 keys ('headers' and 'payload').
|
||||
@@ -43,15 +44,15 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class MapMessageConverter implements MessageConverter, BeanFactoryAware {
|
||||
|
||||
private volatile String[] headerNames;
|
||||
private String[] headerNames = {};
|
||||
|
||||
private volatile boolean filterHeadersInToMessage;
|
||||
private boolean filterHeadersInToMessage;
|
||||
|
||||
private volatile BeanFactory beanFactory;
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private volatile MessageBuilderFactory messageBuilderFactory = new DefaultMessageBuilderFactory();
|
||||
private MessageBuilderFactory messageBuilderFactory = new DefaultMessageBuilderFactory();
|
||||
|
||||
private volatile boolean messageBuilderFactorySet;
|
||||
private boolean messageBuilderFactorySet;
|
||||
|
||||
|
||||
@Override
|
||||
@@ -77,16 +78,19 @@ public class MapMessageConverter implements MessageConverter, BeanFactoryAware {
|
||||
* @param headerNames The header names.
|
||||
*/
|
||||
public void setHeaderNames(String... headerNames) {
|
||||
Assert.notEmpty(headerNames, "at least one header name is required");
|
||||
this.headerNames = Arrays.copyOf(headerNames, headerNames.length);
|
||||
if (ObjectUtils.isEmpty(headerNames)) {
|
||||
this.headerNames = new String[] {};
|
||||
}
|
||||
else {
|
||||
this.headerNames = Arrays.copyOf(headerNames, headerNames.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* By default all headers on Map passed to {@link #toMessage(Object, MessageHeaders)}
|
||||
* By default, all headers on Map passed to {@link #toMessage(Object, MessageHeaders)}
|
||||
* will be mapped. Set this property
|
||||
* to 'true' if you wish to limit the inbound headers to those in
|
||||
* the #headerNames.
|
||||
*
|
||||
* to 'true' if you wish to limit the inbound headers to those
|
||||
* in the {@link #headerNames}.
|
||||
* @param filterHeadersInToMessage true if the headers should be filtered.
|
||||
*/
|
||||
public void setFilterHeadersInToMessage(boolean filterHeadersInToMessage) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2019 the original author or authors.
|
||||
* Copyright 2017-2023 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.
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.integration.support.converter;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.converter.StringMessageConverter;
|
||||
|
||||
@@ -24,16 +27,31 @@ import org.springframework.messaging.converter.StringMessageConverter;
|
||||
* <p>
|
||||
* Delegates to super when payload is {@code byte[]} or {@code String}.
|
||||
* Performs {@link Object#toString()} in other cases.
|
||||
* <p>
|
||||
* This class is intended to serve as a fallback converter for internal message deserialization purposes. Therefore, it
|
||||
* is recommended to exclusively use the
|
||||
* {@link org.springframework.messaging.converter.AbstractMessageConverter#fromMessage(Message, Class) fromMessage}
|
||||
* method with {@code String.class} as the {@code targetClass}.
|
||||
*
|
||||
* @author Marius Bogoevici
|
||||
* @author Artem Bilan
|
||||
* @author Falk Hanisch
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
public class ObjectStringMessageConverter extends StringMessageConverter {
|
||||
|
||||
public ObjectStringMessageConverter(Charset defaultCharset) {
|
||||
super(defaultCharset);
|
||||
}
|
||||
|
||||
public ObjectStringMessageConverter() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Object convertFromInternal(Message<?> message, Class<?> targetClass, Object conversionHint) {
|
||||
protected Object convertFromInternal(Message<?> message, Class<?> targetClass, @Nullable Object conversionHint) {
|
||||
Object payload = message.getPayload();
|
||||
if (payload instanceof String || payload instanceof byte[]) {
|
||||
return super.convertFromInternal(message, targetClass, conversionHint);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2019 the original author or authors.
|
||||
* Copyright 2015-2023 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.
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
package org.springframework.integration.support.converter;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.converter.MessageConverter;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The simple {@link MessageConverter} implementation which contract is to return
|
||||
@@ -31,6 +31,7 @@ import org.springframework.util.Assert;
|
||||
* operates only with {@link Message}s, e.g. Spring Integration Adapters.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
public class PassThruMessageConverter implements MessageConverter {
|
||||
@@ -41,9 +42,13 @@ public class PassThruMessageConverter implements MessageConverter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message<?> toMessage(Object payload, MessageHeaders headers) {
|
||||
Assert.isInstanceOf(byte[].class, payload, "'payload' must be of 'byte[]' type.");
|
||||
return MessageBuilder.createMessage(payload, headers);
|
||||
public Message<?> toMessage(Object payload, @Nullable MessageHeaders headers) {
|
||||
if (payload instanceof byte[]) {
|
||||
return MessageBuilder.withPayload(payload).copyHeaders(headers).build();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
@@ -42,51 +42,50 @@ import org.springframework.messaging.converter.MessageConverter;
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class SimpleMessageConverter implements MessageConverter, BeanFactoryAware {
|
||||
|
||||
private volatile InboundMessageMapper inboundMessageMapper;
|
||||
private InboundMessageMapper inboundMessageMapper = new DefaultInboundMessageMapper();
|
||||
|
||||
private volatile OutboundMessageMapper outboundMessageMapper;
|
||||
private OutboundMessageMapper outboundMessageMapper = new DefaultOutboundMessageMapper();
|
||||
|
||||
private volatile MessageBuilderFactory messageBuilderFactory = new DefaultMessageBuilderFactory();
|
||||
private MessageBuilderFactory messageBuilderFactory = new DefaultMessageBuilderFactory();
|
||||
|
||||
private volatile boolean messageBuilderFactorySet;
|
||||
private boolean messageBuilderFactorySet;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
public SimpleMessageConverter() {
|
||||
this(null, null);
|
||||
}
|
||||
public SimpleMessageConverter() { }
|
||||
|
||||
public SimpleMessageConverter(InboundMessageMapper<?> inboundMessageMapper) {
|
||||
this(inboundMessageMapper,
|
||||
(inboundMessageMapper instanceof OutboundMessageMapper
|
||||
? (OutboundMessageMapper<?>) inboundMessageMapper
|
||||
: null));
|
||||
setInboundMessageMapper(inboundMessageMapper);
|
||||
if (inboundMessageMapper instanceof OutboundMessageMapper<?> messageMapper) {
|
||||
setOutboundMessageMapper(messageMapper);
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleMessageConverter(OutboundMessageMapper<?> outboundMessageMapper) {
|
||||
this(outboundMessageMapper instanceof InboundMessageMapper
|
||||
? (InboundMessageMapper<?>) outboundMessageMapper
|
||||
: null,
|
||||
outboundMessageMapper);
|
||||
if (outboundMessageMapper instanceof InboundMessageMapper<?> messageMapper) {
|
||||
setInboundMessageMapper(messageMapper);
|
||||
}
|
||||
setOutboundMessageMapper(outboundMessageMapper);
|
||||
}
|
||||
|
||||
public SimpleMessageConverter(InboundMessageMapper<?> inboundMessageMapper,
|
||||
OutboundMessageMapper<?> outboundMessageMapper) {
|
||||
this.setInboundMessageMapper(inboundMessageMapper);
|
||||
this.setOutboundMessageMapper(outboundMessageMapper);
|
||||
|
||||
setInboundMessageMapper(inboundMessageMapper);
|
||||
setOutboundMessageMapper(outboundMessageMapper);
|
||||
}
|
||||
|
||||
|
||||
public final void setInboundMessageMapper(InboundMessageMapper<?> inboundMessageMapper) {
|
||||
this.inboundMessageMapper = (inboundMessageMapper != null)
|
||||
? inboundMessageMapper
|
||||
: new DefaultInboundMessageMapper();
|
||||
public final void setInboundMessageMapper(@Nullable InboundMessageMapper<?> inboundMessageMapper) {
|
||||
if (inboundMessageMapper != null) {
|
||||
this.inboundMessageMapper = inboundMessageMapper;
|
||||
}
|
||||
}
|
||||
|
||||
public final void setOutboundMessageMapper(OutboundMessageMapper<?> outboundMessageMapper) {
|
||||
this.outboundMessageMapper = (outboundMessageMapper != null
|
||||
? outboundMessageMapper
|
||||
: new DefaultOutboundMessageMapper());
|
||||
public final void setOutboundMessageMapper(@Nullable OutboundMessageMapper<?> outboundMessageMapper) {
|
||||
if (outboundMessageMapper != null) {
|
||||
this.outboundMessageMapper = outboundMessageMapper;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,8 +109,8 @@ public class SimpleMessageConverter implements MessageConverter, BeanFactoryAwar
|
||||
try {
|
||||
return this.inboundMessageMapper.toMessage(object, headers);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MessageConversionException("failed to convert object to Message", e);
|
||||
catch (Exception ex) {
|
||||
throw new MessageConversionException("failed to convert object to Message", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,8 +120,8 @@ public class SimpleMessageConverter implements MessageConverter, BeanFactoryAwar
|
||||
try {
|
||||
return this.outboundMessageMapper.fromMessage(message);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MessageConversionException(message, "failed to convert Message to object", e);
|
||||
catch (Exception ex) {
|
||||
throw new MessageConversionException(message, "failed to convert Message to object", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/**
|
||||
* Provides classes supporting message conversion.
|
||||
*/
|
||||
@org.springframework.lang.NonNullApi
|
||||
@org.springframework.lang.NonNullFields
|
||||
package org.springframework.integration.support.converter;
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2002-2023 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.integration.support.converter;
|
||||
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Falk Hanisch
|
||||
*
|
||||
* @since 6.2
|
||||
*/
|
||||
class ObjectStringMessageConverterTests {
|
||||
|
||||
private static final ArbitraryPayload PAYLOAD = new ArbitraryPayload(1234, "ÄÖÜ");
|
||||
|
||||
@Test
|
||||
void testFromMessage() {
|
||||
Message<ArbitraryPayload> message = MessageBuilder.withPayload(PAYLOAD).build();
|
||||
ObjectStringMessageConverter converter = new ObjectStringMessageConverter();
|
||||
Object result = converter.fromMessage(message, String.class);
|
||||
|
||||
assertThat(message.getPayload()).isEqualTo(PAYLOAD);
|
||||
assertThat(result).isEqualTo(PAYLOAD.toString());
|
||||
|
||||
result = converter.fromMessage(message, Object.class);
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testToMessage() {
|
||||
String text = PAYLOAD.text();
|
||||
ObjectStringMessageConverter converter = new ObjectStringMessageConverter(StandardCharsets.ISO_8859_1);
|
||||
Message<?> converted = converter.toMessage(text, null);
|
||||
|
||||
assertThat(converted).isNotNull();
|
||||
assertThat(converted.getPayload()).isEqualTo(text.getBytes(StandardCharsets.ISO_8859_1));
|
||||
|
||||
converter.setSerializedPayloadClass(String.class);
|
||||
converted = converter.toMessage(text, null);
|
||||
assertThat(converted).isNotNull();
|
||||
assertThat(converted.getPayload()).isEqualTo(text);
|
||||
|
||||
converted = converter.toMessage(PAYLOAD, null);
|
||||
assertThat(converted).isNull();
|
||||
}
|
||||
|
||||
private record ArbitraryPayload(Integer id, String text) {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user