diff --git a/spring-cloud-bus-tests/src/test/java/org/springframework/cloud/bus/jackson/BusJacksonIntegrationTests.java b/spring-cloud-bus-tests/src/test/java/org/springframework/cloud/bus/jackson/BusJacksonIntegrationTests.java new file mode 100644 index 0000000..8663183 --- /dev/null +++ b/spring-cloud-bus-tests/src/test/java/org/springframework/cloud/bus/jackson/BusJacksonIntegrationTests.java @@ -0,0 +1,105 @@ +package org.springframework.cloud.bus.jackson; + +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.cloud.bus.ServiceMatcher; +import org.springframework.cloud.bus.event.RemoteApplicationEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.event.EventListener; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RestController; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT) +public class BusJacksonIntegrationTests { + + @LocalServerPort + private int port; + + @Autowired + private TestRestTemplate rest; + + @Autowired + private BusJacksonMessageConverter converter; + + @Test + public void testCustomEventSerializes() { + assertThat(converter.isMapperCreated()).isFalse(); + + rest.put("http://localhost:"+port+"/names"+"/foo", null); + rest.put("http://localhost:"+port+"/names"+"/bar", null); + + ResponseEntity response = rest.getForEntity("http://localhost:" + port + "/names", List.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).contains("foo", "bar"); + } + + public static class NameEvent extends RemoteApplicationEvent { + + private String name; + + protected NameEvent() {} + + public NameEvent(Object source, String originService, String name) { + super(source, originService); + this.name = name; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + } + + @RestController + @EnableAutoConfiguration + @SpringBootConfiguration + @RemoteApplicationEventScan + protected static class Config { + final private Set names = ConcurrentHashMap.newKeySet(); + @Autowired + private ServiceMatcher busServiceMatcher; + @Autowired + private ApplicationEventPublisher publisher; + + @GetMapping("/names") + public Collection names() { + return this.names; + } + + @PutMapping("/names/{name}") + public void sayName(@PathVariable String name) { + this.names.add(name); + publisher.publishEvent(new NameEvent(this, busServiceMatcher.getServiceId(), name)); + } + + @EventListener + public void handleNameSaid(NameEvent event) { + this.names.add(event.getName()); + } + + } +} diff --git a/spring-cloud-bus/src/main/java/org/springframework/cloud/bus/jackson/BusJacksonAutoConfiguration.java b/spring-cloud-bus/src/main/java/org/springframework/cloud/bus/jackson/BusJacksonAutoConfiguration.java index 6676fcf..65e2d29 100644 --- a/spring-cloud-bus/src/main/java/org/springframework/cloud/bus/jackson/BusJacksonAutoConfiguration.java +++ b/spring-cloud-bus/src/main/java/org/springframework/cloud/bus/jackson/BusJacksonAutoConfiguration.java @@ -22,21 +22,23 @@ import java.util.Arrays; import java.util.List; import java.util.Set; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.cloud.bus.BusAutoConfiguration; import org.springframework.cloud.bus.ConditionalOnBusEnabled; import org.springframework.cloud.bus.endpoint.RefreshBusEndpoint; import org.springframework.cloud.bus.event.RemoteApplicationEvent; import org.springframework.cloud.bus.event.UnknownRemoteApplicationEvent; -import org.springframework.cloud.stream.annotation.StreamMessageConverter; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.context.annotation.Configuration; import org.springframework.core.type.filter.AssignableTypeFilter; @@ -45,10 +47,6 @@ import org.springframework.messaging.converter.AbstractMessageConverter; import org.springframework.util.ClassUtils; import org.springframework.util.MimeTypeUtils; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; - /** * @author Spencer Gibb * @author Dave Syer @@ -58,16 +56,9 @@ import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; @Configuration @ConditionalOnBusEnabled @ConditionalOnClass({ RefreshBusEndpoint.class, ObjectMapper.class }) -@AutoConfigureBefore(BusAutoConfiguration.class) +@AutoConfigureBefore({ BusAutoConfiguration.class, JacksonAutoConfiguration.class}) public class BusJacksonAutoConfiguration { - @Bean - @ConditionalOnMissingBean(name = "busJsonConverter") - @StreamMessageConverter - public AbstractMessageConverter busJsonConverter(@Autowired(required = false) ObjectMapper objectMapper) { - return new BusJacksonMessageConverter(objectMapper); - } - } class BusJacksonMessageConverter extends AbstractMessageConverter @@ -79,6 +70,7 @@ class BusJacksonMessageConverter extends AbstractMessageConverter .getPackageName(RemoteApplicationEvent.class); private final ObjectMapper mapper; + private final boolean mapperCreated; private String[] packagesToScan = new String[] { DEFAULT_PACKAGE }; @@ -86,16 +78,23 @@ class BusJacksonMessageConverter extends AbstractMessageConverter this(null); } + @Autowired(required = false) public BusJacksonMessageConverter(ObjectMapper objectMapper) { super(MimeTypeUtils.APPLICATION_JSON); if (objectMapper != null) { this.mapper = objectMapper; + this.mapperCreated = false; } else { this.mapper = new ObjectMapper(); + this.mapperCreated = true; } } + public boolean isMapperCreated() { + return mapperCreated; + } + public void setPackagesToScan(String[] packagesToScan) { List packages = new ArrayList<>(Arrays.asList(packagesToScan)); if (!packages.contains(DEFAULT_PACKAGE)) {