AMQP-432: Properly convert BasicProperties values to and from
MessageProperties JIRA: https://jira.spring.io/browse/AMQP-432 Previously `DefaultMessagePropertiesConverter` converted just `LongString`, but BasicProperties may contain List and Map values with nested LongStrings. Values unsupported by AMQP which are contained in Lists or Maps are also not converted from `MessageProperties` to `BasicProperties`. Add logic to properly convert from LongString values nested in Lists/Maps. Add logic to properly convert unsupported values nested in Lists/Maps to Strings. **Cherry-pick to 1.3.x** Code style polishing
This commit is contained in:
committed by
Artem Bilan
parent
1b14c5f0fd
commit
d144db36d7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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
|
||||
@@ -15,6 +15,7 @@ package org.springframework.amqp.rabbit.support;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
@@ -35,6 +36,7 @@ import com.rabbitmq.client.LongString;
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Gary Russell
|
||||
* @author Soeren Unruh
|
||||
* @since 1.0
|
||||
*/
|
||||
public class DefaultMessagePropertiesConverter implements MessagePropertiesConverter {
|
||||
@@ -45,11 +47,7 @@ public class DefaultMessagePropertiesConverter implements MessagePropertiesConve
|
||||
Map<String, Object> headers = source.getHeaders();
|
||||
if (!CollectionUtils.isEmpty(headers)) {
|
||||
for (Map.Entry<String, Object> entry : headers.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof LongString) {
|
||||
value = this.convertLongString((LongString) value, charset);
|
||||
}
|
||||
target.setHeader(entry.getKey(), value);
|
||||
target.setHeader(entry.getKey(), convertLongStringIfNecessary(entry.getValue(), charset));
|
||||
}
|
||||
}
|
||||
target.setTimestamp(source.getTimestamp());
|
||||
@@ -130,6 +128,11 @@ public class DefaultMessagePropertiesConverter implements MessagePropertiesConve
|
||||
return writableHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a header value to a String if the value type is unsupported by AMQP, also handling values
|
||||
* nested inside Lists or Maps.
|
||||
* <p> {@code null} values are passed through, although Rabbit client will throw an IllegalArgumentException.
|
||||
*/
|
||||
private Object convertHeaderValueIfNecessary(Object value) {
|
||||
boolean valid = (value instanceof String) || (value instanceof byte[]) || (value instanceof Boolean)
|
||||
|| (value instanceof LongString) || (value instanceof Integer) || (value instanceof Long)
|
||||
@@ -139,6 +142,22 @@ public class DefaultMessagePropertiesConverter implements MessagePropertiesConve
|
||||
if (!valid && value != null) {
|
||||
value = value.toString();
|
||||
}
|
||||
else if (value instanceof List<?>) {
|
||||
List<Object> writableList = new ArrayList<Object>(((List<?>) value).size());
|
||||
for (Object listValue : (List<?>) value) {
|
||||
writableList.add(convertHeaderValueIfNecessary(listValue));
|
||||
}
|
||||
value = writableList;
|
||||
}
|
||||
else if (value instanceof Map<?, ?>) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> originalMap = (Map<String, Object>) value;
|
||||
Map<String, Object> writableMap = new HashMap<String, Object>(originalMap.size());
|
||||
for (Map.Entry<String, Object> entry : originalMap.entrySet()) {
|
||||
writableMap.put(entry.getKey(), this.convertHeaderValueIfNecessary(entry.getValue()));
|
||||
}
|
||||
value = writableMap;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -158,4 +177,31 @@ public class DefaultMessagePropertiesConverter implements MessagePropertiesConve
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a LongString value using {@link #convertLongString(LongString, String)}, also handling values
|
||||
* nested in Lists or Maps.
|
||||
*/
|
||||
private Object convertLongStringIfNecessary(Object value, String charset) {
|
||||
if (value instanceof LongString) {
|
||||
value = convertLongString((LongString) value, charset);
|
||||
}
|
||||
else if (value instanceof List<?>) {
|
||||
List<Object> convertedList = new ArrayList<Object>(((List<?>) value).size());
|
||||
for (Object listValue : (List<?>) value) {
|
||||
convertedList.add(this.convertLongStringIfNecessary(listValue, charset));
|
||||
}
|
||||
value = convertedList;
|
||||
}
|
||||
else if (value instanceof Map<?, ?>) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> originalMap = (Map<String, Object>) value;
|
||||
Map<String, Object> convertedMap = new HashMap<String, Object>();
|
||||
for (Map.Entry<String, Object> entry : originalMap.entrySet()) {
|
||||
convertedMap.put(entry.getKey(), this.convertLongStringIfNecessary(entry.getValue(), charset));
|
||||
}
|
||||
value = convertedMap;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2014 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.amqp.rabbit.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.amqp.core.MessageProperties;
|
||||
|
||||
import com.rabbitmq.client.AMQP.BasicProperties;
|
||||
import com.rabbitmq.client.Envelope;
|
||||
import com.rabbitmq.client.LongString;
|
||||
import com.rabbitmq.client.impl.LongStringHelper;
|
||||
|
||||
/**
|
||||
* @author Soeren Unruh
|
||||
* @since 1.3
|
||||
*/
|
||||
public class DefaultMessagePropertiesConverterTests {
|
||||
|
||||
private final MessagePropertiesConverter messagePropertiesConverter = new DefaultMessagePropertiesConverter();
|
||||
|
||||
private final Envelope envelope = new Envelope(0, false, null, null);
|
||||
|
||||
private final LongString longString = LongStringHelper.asLongString("longString");
|
||||
|
||||
private String longStringString;
|
||||
|
||||
@Before
|
||||
public void init() throws UnsupportedEncodingException {
|
||||
longStringString = new String(longString.getBytes(), "UTF-8");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToMessagePropertiesLongString() {
|
||||
Map<String, Object> headers = new HashMap<String, Object>();
|
||||
headers.put("longString", longString);
|
||||
BasicProperties source = new BasicProperties.Builder()
|
||||
.headers(headers)
|
||||
.build();
|
||||
MessageProperties messageProperties = messagePropertiesConverter.toMessageProperties(source, envelope, "UTF-8");
|
||||
assertEquals("LongString not converted to String",
|
||||
longStringString, messageProperties.getHeaders().get("longString"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToMessagePropertiesLongStringInList() {
|
||||
Map<String, Object> headers = new HashMap<String, Object>();
|
||||
headers.put("list", Arrays.asList(longString));
|
||||
BasicProperties source = new BasicProperties.Builder()
|
||||
.headers(headers)
|
||||
.build();
|
||||
MessageProperties messageProperties = messagePropertiesConverter.toMessageProperties(source, envelope, "UTF-8");
|
||||
assertEquals("LongString nested in List not converted to String",
|
||||
longStringString, ((List<?>) messageProperties.getHeaders().get("list")).get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testToMessagePropertiesLongStringDeepInList() {
|
||||
Map<String, Object> headers = new HashMap<String, Object>();
|
||||
headers.put("list", Arrays.asList(Arrays.asList(longString)));
|
||||
BasicProperties source = new BasicProperties.Builder()
|
||||
.headers(headers)
|
||||
.build();
|
||||
MessageProperties messageProperties = messagePropertiesConverter.toMessageProperties(source, envelope, "UTF-8");
|
||||
assertEquals("LongString deeply nested in List not converted to String",
|
||||
longStringString, ((List<?>) ((List<?>) messageProperties.getHeaders().get("list")).get(0)).get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testToMessagePropertiesLongStringInMap() {
|
||||
Map<String, Object> mapWithLongString = new HashMap<String, Object>();
|
||||
mapWithLongString.put("longString", longString);
|
||||
Map<String, Object> headers = new HashMap<String, Object>();
|
||||
headers.put("map", mapWithLongString);
|
||||
BasicProperties source = new BasicProperties.Builder()
|
||||
.headers(headers)
|
||||
.build();
|
||||
MessageProperties messageProperties = messagePropertiesConverter.toMessageProperties(source, envelope, "UTF-8");
|
||||
assertEquals("LongString nested in Map not converted to String",
|
||||
longStringString, ((Map<String, Object>) messageProperties.getHeaders().get("map")).get("longString"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromUnsupportedValue() {
|
||||
MessageProperties messageProperties = new MessageProperties();
|
||||
messageProperties.setHeader("unsupported", new Object());
|
||||
BasicProperties basicProps = messagePropertiesConverter.fromMessageProperties(messageProperties, "UTF-8");
|
||||
assertTrue("Unsupported value not converted to String",
|
||||
basicProps.getHeaders().get("unsupported") instanceof String);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromUnsupportedValueInList() {
|
||||
MessageProperties messageProperties = new MessageProperties();
|
||||
List<Object> listWithUnsupportedValue = Arrays.asList(new Object());
|
||||
messageProperties.setHeader("list", listWithUnsupportedValue);
|
||||
BasicProperties basicProps = messagePropertiesConverter.fromMessageProperties(messageProperties, "UTF-8");
|
||||
assertTrue("Unsupported value nested in List not converted to String",
|
||||
((List<?>) basicProps.getHeaders().get("list")).get(0) instanceof String);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testFromUnsupportedValueDeepInList() {
|
||||
MessageProperties messageProperties = new MessageProperties();
|
||||
List<List<Object>> listWithUnsupportedValue = Arrays.asList(Arrays.asList(new Object()));
|
||||
messageProperties.setHeader("list", listWithUnsupportedValue);
|
||||
BasicProperties basicProps = messagePropertiesConverter.fromMessageProperties(messageProperties, "UTF-8");
|
||||
assertTrue("Unsupported value deeply nested in List not converted to String",
|
||||
((List<Object>) ((List<?>) basicProps.getHeaders().get("list")).get(0)).get(0) instanceof String);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testFromUnsupportedValueInMap() {
|
||||
MessageProperties messageProperties = new MessageProperties();
|
||||
Map<String, Object> mapWithUnsupportedValue = new HashMap<String, Object>();
|
||||
mapWithUnsupportedValue.put("unsupported", new Object());
|
||||
messageProperties.setHeader("map", mapWithUnsupportedValue);
|
||||
BasicProperties basicProps = messagePropertiesConverter.fromMessageProperties(messageProperties, "UTF-8");
|
||||
assertTrue("Unsupported value nested in Map not converted to String",
|
||||
((Map<String, Object>) basicProps.getHeaders().get("map")).get("unsupported") instanceof String);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user