Clarify how custom event types can be used

Actually you need them to be in a subpackage of
RemoteApplicationEvent.

Fixes gh-33
This commit is contained in:
Dave Syer
2016-04-25 11:55:54 +01:00
parent 548bb3c451
commit d0696be642
5 changed files with 115 additions and 10 deletions

View File

@@ -103,5 +103,9 @@ queries on the data. Or forward it to a specialized tracing service.
The Bus can carry any event of type `RemoteApplicationEvent`, but the
default transport is JSON and the deserializer needs to know which
types are going to be used ahead of time. To register a new type you
can use `@JsonTypeName` on your custom class.
types are going to be used ahead of time. To register a new type it
needs to be in a subpackage of `org.springframework.cloud.bus.event`.
You can use `@JsonTypeName` on your custom class or rely on the
default strategy which is to use the simple name of the class. Note
that both the producer and the consumer will need access to the class
definition.

View File

@@ -22,6 +22,7 @@ import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.util.ClassUtils;
import org.springframework.util.MimeTypeUtils;
@@ -39,7 +40,7 @@ import com.fasterxml.jackson.databind.SerializationFeature;
public class BusJacksonAutoConfiguration {
@Bean
public BusJacksonMessageConverter busJsonConverter() {
public MessageConverter busJsonConverter() {
return new BusJacksonMessageConverter();
}
@@ -68,8 +69,8 @@ class BusJacksonMessageConverter extends AbstractFromMessageConverter {
public BusJacksonMessageConverter() {
super(MimeTypeUtils.APPLICATION_JSON, MessageConverterUtils.X_JAVA_OBJECT);
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.registerModule(new SubtypeModule(findSubTypes()));
this.mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
this.mapper.registerModule(new SubtypeModule(findSubTypes()));
}
private Class<?>[] findSubTypes() {
@@ -125,14 +126,14 @@ class BusJacksonMessageConverter extends AbstractFromMessageConverter {
Object payload = message.getPayload();
if (payload instanceof byte[]) {
result = mapper.readValue((byte[]) payload, targetClass);
result = this.mapper.readValue((byte[]) payload, targetClass);
}
else if (payload instanceof String) {
result = mapper.readValue((String) payload, targetClass);
result = this.mapper.readValue((String) payload, targetClass);
}
}
catch (Exception e) {
logger.error(e.getMessage(), e);
this.logger.error(e.getMessage(), e);
return null;
}
return result;

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2015 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.cloud.bus.event.test;
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
@SuppressWarnings("serial")
public class TestRemoteApplicationEvent extends RemoteApplicationEvent {
@SuppressWarnings("unused")
private TestRemoteApplicationEvent() {
}
protected TestRemoteApplicationEvent(Object source, String originService,
String destinationService) {
super(source, originService, destinationService);
}
protected TestRemoteApplicationEvent(Object source, String originService) {
super(source, originService);
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2015 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.cloud.bus.event.test;
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
import com.fasterxml.jackson.annotation.JsonTypeName;
@SuppressWarnings("serial")
@JsonTypeName("typed")
public class TypedRemoteApplicationEvent extends RemoteApplicationEvent {
@SuppressWarnings("unused")
private TypedRemoteApplicationEvent() {
}
protected TypedRemoteApplicationEvent(Object source, String originService,
String destinationService) {
super(source, originService, destinationService);
}
protected TypedRemoteApplicationEvent(Object source, String originService) {
super(source, originService);
}
}

View File

@@ -5,6 +5,10 @@ import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
import org.springframework.cloud.bus.event.test.TestRemoteApplicationEvent;
import org.springframework.cloud.bus.event.test.TypedRemoteApplicationEvent;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.support.MessageBuilder;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -15,7 +19,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
public class SubtypeModuleTests {
@Test
public void testSubclass() throws Exception {
public void testDeserializeSubclass() throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new SubtypeModule(MyRemoteApplicationEvent.class));
@@ -27,12 +31,35 @@ public class SubtypeModuleTests {
assertEquals("originService was wrong", "myorigin", myEvent.getOriginService());
assertEquals("destinationService was wrong", "myservice",
myEvent.getDestinationService());
}
event = mapper.readValue("{\"type\":\"another\"}",
@Test
public void testDeserializeWhenTypeIsKnown() throws Exception {
ObjectMapper mapper = new ObjectMapper();
RemoteApplicationEvent event = mapper.readValue("{\"type\":\"another\"}",
AnotherRemoteApplicationEvent.class);
assertTrue("event is wrong type", event instanceof AnotherRemoteApplicationEvent);
}
@Test
public void testDeserializeWithMessageConverter() throws Exception {
MessageConverter converter = new BusJacksonAutoConfiguration().busJsonConverter();
Object event = converter.fromMessage(
MessageBuilder.withPayload("{\"type\":\"TestRemoteApplicationEvent\"}").build(),
RemoteApplicationEvent.class);
assertTrue("event is wrong type", event instanceof TestRemoteApplicationEvent);
}
@Test
public void testDeserializeJsonTypeWithMessageConverter() throws Exception {
MessageConverter converter = new BusJacksonAutoConfiguration().busJsonConverter();
Object event = converter.fromMessage(
MessageBuilder.withPayload("{\"type\":\"typed\"}").build(),
RemoteApplicationEvent.class);
assertTrue("event is wrong type", event instanceof TypedRemoteApplicationEvent);
}
@SuppressWarnings("serial")
@JsonTypeName("my")
public static class MyRemoteApplicationEvent extends RemoteApplicationEvent {