Compatibility for independent bus clients (#76)

independent bus clients may not have all events implemented or the location of the event classes could be in a different package.
This PR fixes issues in such an environment (e.g. Microservices). Therefore the event type in the AckRemoteApplicationEvent will be set via a special setter, so the availability of the type can be checked.
In addition the UnknownRemoteApplicationEvent is fixed to not cause a NullPointerException when raised.

Fixes #74
This commit is contained in:
Patrick Mentz
2017-08-04 21:51:24 +02:00
committed by Spencer Gibb
parent 00af9e26b0
commit 812100aa04
4 changed files with 65 additions and 2 deletions

View File

@@ -17,6 +17,8 @@
package org.springframework.cloud.bus.event;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* An event that signals an ack of a specific {@link RemoteApplicationEvent}. These events
* can be monitored by any applications that want to audit the responses to bus events.
@@ -31,7 +33,7 @@ public class AckRemoteApplicationEvent extends RemoteApplicationEvent {
private final String ackId;
private final String ackDestinationService;
private final Class<? extends RemoteApplicationEvent> event;
private Class<? extends RemoteApplicationEvent> event;
@SuppressWarnings("unused")
private AckRemoteApplicationEvent() {
@@ -62,6 +64,21 @@ public class AckRemoteApplicationEvent extends RemoteApplicationEvent {
return event;
}
/**
* Used by Jackson to set the remote class name of the event implementation. If the implementing class is unknown to
* this app, set the event to {@link UnknownRemoteApplicationEvent}.
*
* @param eventName the fq class name of the event implementation, not null
*/
@JsonProperty("event")
public void setEventName(String eventName) {
try {
event = (Class<? extends RemoteApplicationEvent>) Class.forName(eventName);
} catch (ClassNotFoundException e) {
event = UnknownRemoteApplicationEvent.class;
}
}
@Override
public int hashCode() {
final int prime = 31;

View File

@@ -34,7 +34,8 @@ public class UnknownRemoteApplicationEvent extends RemoteApplicationEvent {
}
public UnknownRemoteApplicationEvent(Object source, String typeInfo, byte[] payload) {
super(source, null, null);
// Initialize originService with an empty String, to avoid NullPointer in AntPathMatcher.
super(source, "", null);
this.typeInfo = typeInfo;
this.payload = payload;
}

View File

@@ -35,6 +35,7 @@ import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfigurati
import org.springframework.cloud.bus.event.AckRemoteApplicationEvent;
import org.springframework.cloud.bus.event.RefreshRemoteApplicationEvent;
import org.springframework.cloud.bus.event.SentApplicationEvent;
import org.springframework.cloud.bus.event.UnknownRemoteApplicationEvent;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.cloud.stream.test.binder.TestSupportBinderAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
@@ -206,6 +207,19 @@ public class BusAutoConfigurationTests {
this.context.getBean(InboundMessageHandlerConfiguration.class).refresh);
}
/**
* see https://github.com/spring-cloud/spring-cloud-bus/issues/74
*/
@Test
public void inboundNotFromSelfUnknown() {
this.context = SpringApplication.run(InboundMessageHandlerConfiguration.class);
this.context.setId("bar");
this.context.getBean(SpringCloudBusClient.INPUT, MessageChannel.class)
.send(new GenericMessage<>(
new UnknownRemoteApplicationEvent(this, "UnknownEvent", "yada".getBytes())));
// No Exception expected
}
@Configuration
@Import({ MessageConsumer.class, BusAutoConfiguration.class,
TestSupportBinderAutoConfiguration.class,

View File

@@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.springframework.cloud.bus.event.AckRemoteApplicationEvent;
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
import org.springframework.cloud.bus.event.UnknownRemoteApplicationEvent;
import org.springframework.cloud.bus.event.test.TestRemoteApplicationEvent;
@@ -92,6 +93,36 @@ public class SubtypeModuleTests {
assertTrue("event is wrong type", event instanceof TypedRemoteApplicationEvent);
}
/**
* see https://github.com/spring-cloud/spring-cloud-bus/issues/74
*/
@Test
public void testDeserializeAckRemoteApplicationEventWithKnownType() throws Exception {
BusJacksonMessageConverter converter = new BusJacksonAutoConfiguration().busJsonConverter();
converter.afterPropertiesSet();
Object event = converter.fromMessage(MessageBuilder.withPayload(
"{\"type\":\"AckRemoteApplicationEvent\", \"event\":\"org.springframework.cloud.bus.event.test.TestRemoteApplicationEvent\"}")
.build(), RemoteApplicationEvent.class);
assertTrue("event is no ack", event instanceof AckRemoteApplicationEvent);
AckRemoteApplicationEvent ackEvent = AckRemoteApplicationEvent.class.cast(event);
assertEquals("inner ack event has wrong type", TestRemoteApplicationEvent.class, ackEvent.getEvent());
}
/**
* see https://github.com/spring-cloud/spring-cloud-bus/issues/74
*/
@Test
public void testDeserializeAckRemoteApplicationEventWithUnknownType() throws Exception {
BusJacksonMessageConverter converter = new BusJacksonAutoConfiguration().busJsonConverter();
converter.afterPropertiesSet();
Object event = converter.fromMessage(MessageBuilder.withPayload(
"{\"type\":\"AckRemoteApplicationEvent\", \"event\":\"foo.bar.TestRemoteApplicationEvent\"}").build(),
RemoteApplicationEvent.class);
assertTrue("event is no ack", event instanceof AckRemoteApplicationEvent);
AckRemoteApplicationEvent ackEvent = AckRemoteApplicationEvent.class.cast(event);
assertEquals("inner ack event has wrong type", UnknownRemoteApplicationEvent.class, ackEvent.getEvent());
}
@SuppressWarnings("serial")
@JsonTypeName("my")
public static class MyRemoteApplicationEvent extends RemoteApplicationEvent {