Skip to content

Commit 4464d4d

Browse files
garyrussellartembilan
authored andcommitted
AMQP-798: Master to 2.1.x; Fix Tangles
JIRA: https://jira.spring.io/browse/AMQP-798 Also update amqp-client to 5.2.0 Don't use `MessageConverter` in `Message.toString()` (cycle) Fix cycle between template and admin (via containers) Fix outbound reference from support to connection Fix cycle between connection and listener via RabbitUtils Fix cycle between listener and core via ChannelAwareMessageListener and admin Fix cycle between listener.adapter and listener via RabbitListenerErrorHandler Fix cycle between amqp.support and amqp.core via Correlation Fix cycle between listener and transaction via ListenerFailedRuleBasedTransactionAttribute Fix Tests Polishing - PR Comments; rename schema Test polishing - travis failures Polishing according PR comments * Update Copyright for all affected classes * Optimize `DirectMessageListenerContainer.checkMissingQueues()` to cache `amqpAdmin` from the locally created * `RabbitUtils.DEFAULT_PORT` as not-used and deprecated in `2.0.x` * Remove commented test in the `LogAppenderUtils` * Deprecate `AbstractAdaptableMessageListener#setRabbitAdmin()` in favor of newly introduced `setAmqpAdmin()`
1 parent 1d38c14 commit 4464d4d

File tree

56 files changed

+714
-370
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+714
-370
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ subprojects { subproject ->
9494
log4jVersion = '2.8.2'
9595
logbackVersion = '1.2.3'
9696
mockitoVersion = '2.11.0'
97-
rabbitmqVersion = project.hasProperty('rabbitmqVersion') ? project.rabbitmqVersion : '5.1.2'
97+
rabbitmqVersion = project.hasProperty('rabbitmqVersion') ? project.rabbitmqVersion : '5.2.0'
9898
rabbitmqHttpClientVersion = '2.0.1.RELEASE'
9999

100100
springVersion = project.hasProperty('springVersion') ? project.springVersion : '5.0.4.RELEASE'

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
version=2.0.3.BUILD-SNAPSHOT
1+
version=2.1.0.BUILD-SNAPSHOT
22
org.gradle.daemon=true

spring-amqp/src/main/java/org/springframework/amqp/core/AmqpAdmin.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -105,4 +105,12 @@ public interface AmqpAdmin {
105105
*/
106106
Properties getQueueProperties(String queueName);
107107

108+
/**
109+
* Initialize the admin.
110+
* @since 2.1
111+
*/
112+
default void initialize() {
113+
// no op
114+
}
115+
108116
}

spring-amqp/src/main/java/org/springframework/amqp/support/Correlation.java renamed to spring-amqp/src/main/java/org/springframework/amqp/core/Correlation.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017 the original author or authors.
2+
* Copyright 2017-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.amqp.support;
17+
package org.springframework.amqp.core;
1818

1919
/**
2020
* A marker interface for data used to correlate information about sent messages.

spring-amqp/src/main/java/org/springframework/amqp/core/Message.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,11 +16,15 @@
1616

1717
package org.springframework.amqp.core;
1818

19+
import java.io.ByteArrayInputStream;
1920
import java.io.Serializable;
2021
import java.nio.charset.Charset;
2122
import java.util.Arrays;
23+
import java.util.LinkedHashSet;
24+
import java.util.Set;
2225

23-
import org.springframework.amqp.support.converter.SerializerMessageConverter;
26+
import org.springframework.amqp.utils.SerializationUtils;
27+
import org.springframework.util.Assert;
2428

2529
/**
2630
* The 0-8 and 0-9-1 AMQP specifications do not define an Message class or interface. Instead, when performing an
@@ -42,11 +46,8 @@ public class Message implements Serializable {
4246

4347
private static final String ENCODING = Charset.defaultCharset().name();
4448

45-
private static final SerializerMessageConverter SERIALIZER_MESSAGE_CONVERTER = new SerializerMessageConverter();
46-
47-
static {
48-
SERIALIZER_MESSAGE_CONVERTER.setWhiteListPatterns(Arrays.asList("java.util.*", "java.lang.*"));
49-
}
49+
private static final Set<String> whiteListPatterns = new LinkedHashSet<String>(
50+
Arrays.asList("java.util.*", "java.lang.*"));
5051

5152
private final MessageProperties messageProperties;
5253

@@ -70,7 +71,8 @@ public Message(byte[] body, MessageProperties messageProperties) { //NOSONAR
7071
* @since 1.5.7
7172
*/
7273
public static void addWhiteListPatterns(String... patterns) {
73-
SERIALIZER_MESSAGE_CONVERTER.addWhiteListPatterns(patterns);
74+
Assert.notNull(patterns, "'patterns' cannot be null");
75+
whiteListPatterns.addAll(Arrays.asList(patterns));
7476
}
7577

7678
public byte[] getBody() {
@@ -100,7 +102,8 @@ private String getBodyContentAsString() {
100102
try {
101103
String contentType = (this.messageProperties != null) ? this.messageProperties.getContentType() : null;
102104
if (MessageProperties.CONTENT_TYPE_SERIALIZED_OBJECT.equals(contentType)) {
103-
return SERIALIZER_MESSAGE_CONVERTER.fromMessage(this).toString();
105+
return SerializationUtils.deserialize(new ByteArrayInputStream(this.body), whiteListPatterns,
106+
getClass().getClassLoader()).toString();
104107
}
105108
if (MessageProperties.CONTENT_TYPE_TEXT_PLAIN.equals(contentType)
106109
|| MessageProperties.CONTENT_TYPE_JSON.equals(contentType)

spring-amqp/src/main/java/org/springframework/amqp/core/MessagePostProcessor.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.springframework.amqp.core;
1818

1919
import org.springframework.amqp.AmqpException;
20-
import org.springframework.amqp.support.Correlation;
2120

2221
/**
2322
* Used in several places in the framework, such as

spring-amqp/src/main/java/org/springframework/amqp/support/converter/WhiteListDeserializingMessageConverter.java

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016 the original author or authors.
2+
* Copyright 2016-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
2222
import java.util.List;
2323
import java.util.Set;
2424

25-
import org.springframework.util.PatternMatchUtils;
25+
import org.springframework.amqp.utils.SerializationUtils;
2626

2727
/**
2828
* MessageConverters that potentially use Java deserialization.
@@ -59,20 +59,7 @@ public void addWhiteListPatterns(String... patterns) {
5959
}
6060

6161
protected void checkWhiteList(Class<?> clazz) throws IOException {
62-
if (this.whiteListPatterns.isEmpty()) {
63-
return;
64-
}
65-
if (clazz.isArray() || clazz.isPrimitive() || clazz.equals(String.class)
66-
|| Number.class.isAssignableFrom(clazz)) {
67-
return;
68-
}
69-
String className = clazz.getName();
70-
for (String pattern : this.whiteListPatterns) {
71-
if (PatternMatchUtils.simpleMatch(pattern, className)) {
72-
return;
73-
}
74-
}
75-
throw new SecurityException("Attempt to deserialize unauthorized " + clazz);
62+
SerializationUtils.checkWhiteList(clazz, this.whiteListPatterns);
7663
}
7764

7865
}

spring-amqp/src/main/java/org/springframework/amqp/utils/SerializationUtils.java

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2017 the original author or authors.
2+
* Copyright 2006-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,8 +19,16 @@
1919
import java.io.ByteArrayInputStream;
2020
import java.io.ByteArrayOutputStream;
2121
import java.io.IOException;
22+
import java.io.InputStream;
2223
import java.io.ObjectInputStream;
2324
import java.io.ObjectOutputStream;
25+
import java.io.ObjectStreamClass;
26+
import java.util.Set;
27+
28+
import org.springframework.core.ConfigurableObjectInputStream;
29+
import org.springframework.core.NestedIOException;
30+
import org.springframework.util.ObjectUtils;
31+
import org.springframework.util.PatternMatchUtils;
2432

2533
/**
2634
* Static utility to help with serialization.
@@ -91,4 +99,59 @@ public static Object deserialize(ObjectInputStream stream) {
9199
}
92100
}
93101

102+
/**
103+
* Deserialize the stream.
104+
* @param inputStream the stream.
105+
* @param whiteListPatterns allowed classes.
106+
* @param classLoader the class loader.
107+
* @return the result.
108+
* @throws IOException IO Exception.
109+
* @since 2.1
110+
*/
111+
public static Object deserialize(InputStream inputStream, Set<String> whiteListPatterns, ClassLoader classLoader)
112+
throws IOException {
113+
114+
try (
115+
ObjectInputStream objectInputStream = new ConfigurableObjectInputStream(inputStream, classLoader) {
116+
117+
@Override
118+
protected Class<?> resolveClass(ObjectStreamClass classDesc)
119+
throws IOException, ClassNotFoundException {
120+
Class<?> clazz = super.resolveClass(classDesc);
121+
checkWhiteList(clazz, whiteListPatterns);
122+
return clazz;
123+
}
124+
125+
}) {
126+
127+
return objectInputStream.readObject();
128+
}
129+
catch (ClassNotFoundException ex) {
130+
throw new NestedIOException("Failed to deserialize object type", ex);
131+
}
132+
}
133+
134+
/**
135+
* Verify that the class is in the white list.
136+
* @param clazz the class.
137+
* @param whiteListPatterns the patterns.
138+
* @since 2.1
139+
*/
140+
public static void checkWhiteList(Class<?> clazz, Set<String> whiteListPatterns) {
141+
if (ObjectUtils.isEmpty(whiteListPatterns)) {
142+
return;
143+
}
144+
if (clazz.isArray() || clazz.isPrimitive() || clazz.equals(String.class)
145+
|| Number.class.isAssignableFrom(clazz)) {
146+
return;
147+
}
148+
String className = clazz.getName();
149+
for (String pattern : whiteListPatterns) {
150+
if (PatternMatchUtils.simpleMatch(pattern, className)) {
151+
return;
152+
}
153+
}
154+
throw new SecurityException("Attempt to deserialize unauthorized " + clazz);
155+
}
156+
94157
}

spring-rabbit-test/src/main/java/org/springframework/amqp/rabbit/test/TestRabbitTemplate.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017 the original author or authors.
2+
* Copyright 2017-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@
2222
import static org.mockito.BDDMockito.willAnswer;
2323
import static org.mockito.Mockito.mock;
2424

25-
import java.io.IOException;
2625
import java.util.ArrayList;
2726
import java.util.HashMap;
2827
import java.util.Iterator;
@@ -34,11 +33,11 @@
3433
import org.springframework.amqp.core.MessageBuilder;
3534
import org.springframework.amqp.core.MessageListener;
3635
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
37-
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
3836
import org.springframework.amqp.rabbit.core.RabbitTemplate;
3937
import org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer;
4038
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry;
4139
import org.springframework.amqp.rabbit.listener.adapter.AbstractAdaptableMessageListener;
40+
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
4241
import org.springframework.amqp.rabbit.support.CorrelationData;
4342
import org.springframework.amqp.rabbit.support.RabbitExceptionTranslator;
4443
import org.springframework.beans.BeansException;
@@ -57,6 +56,7 @@
5756
* It does not currently support publisher confirms/returns.
5857
*
5958
* @author Gary Russell
59+
*
6060
* @since 2.0
6161
*
6262
*/
@@ -111,7 +111,8 @@ protected boolean useDirectReplyTo() {
111111

112112
@Override
113113
protected void sendToRabbit(Channel channel, String exchange, String routingKey, boolean mandatory,
114-
Message message) throws IOException {
114+
Message message) {
115+
115116
Listeners listeners = this.listeners.get(routingKey);
116117
if (listeners == null) {
117118
throw new IllegalArgumentException("No listener for " + routingKey);
@@ -193,6 +194,7 @@ private synchronized Object next() {
193194
}
194195
return this.iterator.next();
195196
}
197+
196198
}
197199

198200
}

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/AsyncRabbitTemplate.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2017 the original author or authors.
2+
* Copyright 2016-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,21 +31,21 @@
3131
import org.springframework.amqp.core.AmqpMessageReturnedException;
3232
import org.springframework.amqp.core.AmqpReplyTimeoutException;
3333
import org.springframework.amqp.core.AsyncAmqpTemplate;
34+
import org.springframework.amqp.core.Correlation;
3435
import org.springframework.amqp.core.Message;
3536
import org.springframework.amqp.core.MessagePostProcessor;
3637
import org.springframework.amqp.core.MessageProperties;
3738
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
38-
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
3939
import org.springframework.amqp.rabbit.core.RabbitTemplate;
4040
import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback;
4141
import org.springframework.amqp.rabbit.core.RabbitTemplate.ReturnCallback;
4242
import org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer;
4343
import org.springframework.amqp.rabbit.listener.DirectReplyToMessageListenerContainer;
4444
import org.springframework.amqp.rabbit.listener.DirectReplyToMessageListenerContainer.ChannelHolder;
4545
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
46+
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
4647
import org.springframework.amqp.rabbit.support.CorrelationData;
4748
import org.springframework.amqp.rabbit.support.PublisherCallbackChannel;
48-
import org.springframework.amqp.support.Correlation;
4949
import org.springframework.amqp.support.converter.MessageConverter;
5050
import org.springframework.amqp.support.converter.SmartMessageConverter;
5151
import org.springframework.beans.factory.BeanNameAware;
@@ -833,6 +833,7 @@ private static class AsyncCorrelationData<C> extends CorrelationData {
833833

834834
AsyncCorrelationData(MessagePostProcessor userPostProcessor, ParameterizedTypeReference<C> returnType,
835835
boolean enableConfirms) {
836+
836837
this.userPostProcessor = userPostProcessor;
837838
this.returnType = returnType;
838839
this.enableConfirms = enableConfirms;

0 commit comments

Comments
 (0)