INT-4316 Add ObjectToMapTransformer.mapper option

JIRA: https://jira.spring.io/browse/INT-4316

To allow to customize a JSON representation of the Object, provide a
`JsonObjectMapper`-based ctor for the `ObjectToMapTransformer`
This commit is contained in:
Artem Bilan
2017-07-25 11:57:03 -04:00
parent 784d891fa5
commit 74b59ef8d3
12 changed files with 246 additions and 41 deletions

View File

@@ -118,6 +118,10 @@
<logging-channel-adapter id="loggingChannelAdapterWithinChain" level="WARN"/>
</chain>
<beans:bean id="jsonObjectMapper" class="org.mockito.Mockito" factory-method="mock">
<beans:constructor-arg value="org.springframework.integration.support.json.JsonObjectMapper"/>
</beans:bean>
<chain id="subComponentsIdSupport1" input-channel="subComponentsIdSupport1Channel">
<splitter id="splitterWithinChain"/>
<resequencer id="resequencerWithinChain"/>
@@ -130,7 +134,9 @@
<gateway id="gatewayWithinChain" request-channel="strings" reply-channel="numbers"
request-timeout="1000" reply-timeout="100"/>
<object-to-string-transformer id="objectToStringTransformerWithinChain"/>
<object-to-map-transformer id="objectToMapTransformerWithinChain"/>
<object-to-map-transformer id="objectToMapTransformerWithinChain"
flatten="false"
object-mapper="jsonObjectMapper"/>
<map-to-object-transformer id="mapToObjectTransformerWithinChain"
type="org.springframework.integration.config.ChainParserTests$FooPojo"/>
<object-to-json-transformer id="objectToJsonTransformerWithinChain"/>
@@ -147,7 +153,7 @@
</chain>
<chain id="recipientListRouterChain" input-channel="subComponentsIdSupport3Channel">
<recipient-list-router id="recipientListRouterWithinChain">
<recipient-list-router id="recipientListRouterWithinChain">
<recipient channel="strings"/>
<recipient channel="numbers"/>
</recipient-list-router>

View File

@@ -16,6 +16,7 @@
package org.springframework.integration.config;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -59,8 +60,10 @@ import org.springframework.integration.handler.ReplyRequiredException;
import org.springframework.integration.handler.ServiceActivatingHandler;
import org.springframework.integration.message.MessageMatcher;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.support.json.JsonObjectMapper;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.integration.transformer.MessageTransformingHandler;
import org.springframework.integration.transformer.ObjectToMapTransformer;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
@@ -129,7 +132,8 @@ public class ChainParserTests {
@Autowired
private MessageChannel loggingChannelAdapterChannel;
@Autowired @Qualifier("logChain.handler")
@Autowired
@Qualifier("logChain.handler")
private MessageHandlerChain logChain;
@Autowired
@@ -321,7 +325,7 @@ public class ChainParserTests {
DirectFieldAccessor dfa = new DirectFieldAccessor(handler);
dfa.setPropertyValue("messageLogger", logger);
this.loggingChannelAdapterChannel.send(MessageBuilder.withPayload(new byte[] {116, 101, 115, 116}).build());
this.loggingChannelAdapterChannel.send(MessageBuilder.withPayload(new byte[] { 116, 101, 115, 116 }).build());
assertNotNull(log.get());
assertEquals("TEST", log.get());
}
@@ -392,13 +396,23 @@ public class ChainParserTests {
GatewayProxyFactoryBean.class);
assertEquals("strings", TestUtils.getPropertyValue(gatewayProxyFactoryBean, "defaultRequestChannelName"));
assertEquals("numbers", TestUtils.getPropertyValue(gatewayProxyFactoryBean, "defaultReplyChannelName"));
assertEquals(new Long(1000), TestUtils
assertEquals(1000L, TestUtils
.getPropertyValue(gatewayProxyFactoryBean, "defaultRequestTimeout", Expression.class).getValue());
assertEquals(new Long(100), TestUtils
assertEquals(100L, TestUtils
.getPropertyValue(gatewayProxyFactoryBean, "defaultReplyTimeout", Expression.class).getValue());
assertTrue(this.beanFactory.containsBean("subComponentsIdSupport1$child.objectToStringTransformerWithinChain.handler"));
assertTrue(this.beanFactory.containsBean("subComponentsIdSupport1$child.objectToMapTransformerWithinChain.handler"));
Object transformerHandler = this.beanFactory.getBean("subComponentsIdSupport1$child.objectToMapTransformerWithinChain.handler");
Object transformer = TestUtils.getPropertyValue(transformerHandler, "transformer");
assertThat(transformer, instanceOf(ObjectToMapTransformer.class));
assertFalse(TestUtils.getPropertyValue(transformer, "shouldFlattenKeys", Boolean.class));
assertSame(this.beanFactory.getBean(JsonObjectMapper.class),
TestUtils.getPropertyValue(transformer, "jsonObjectMapper"));
assertTrue(this.beanFactory.containsBean("subComponentsIdSupport1$child.mapToObjectTransformerWithinChain.handler"));
assertTrue(this.beanFactory.containsBean("subComponentsIdSupport1$child.controlBusWithinChain.handler"));
assertTrue(this.beanFactory.containsBean("subComponentsIdSupport1$child.routerWithinChain.handler"));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@@ -16,17 +16,21 @@
package org.springframework.integration.transformer;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.junit.Test;
@@ -36,12 +40,19 @@ import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.support.json.Jackson2JsonObjectMapper;
import org.springframework.messaging.Message;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
/**
*
* @author Oleg Zhurakousky
* @author Gunnar Hillert
* @author Vikas Prasad
* @author Artem Bilan
*
* @since 2.0
*/
public class ObjectToMapTransformerTests {
@@ -154,6 +165,41 @@ public class ObjectToMapTransformerTests {
transformer.transform(message);
}
@Test
public void testJacksonJSR310Support_PassInstantField_ReturnsMapWithOnlyOneEntryForInstantField() throws Exception {
Person person = new Person();
person.deathDate = Instant.now();
Employee employee = new Employee();
employee.setPerson(person);
Map<String, Object> transformedMap = new ObjectToMapTransformer().transformPayload(employee);
// If JSR310 support is enabled by calling findAndRegisterModules() on the Jackson mapper,
// Instant field should not be broken. Thus the count should exactly be 1 here.
assertEquals(1L, transformedMap.values().stream().filter(Objects::nonNull).count());
}
@Test
public void testCustomMapperSupport_DisableTimestampFlag_SerializesDateAsString() throws Exception {
Employee employee = buildEmployee();
ObjectMapper customMapper = new ObjectMapper();
customMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
Map<String, Object> transformedMap =
new ObjectToMapTransformer(new Jackson2JsonObjectMapper(customMapper))
.transformPayload(employee);
assertThat(transformedMap.get("listOfDates[0][0]"), instanceOf(String.class));
assertThat(transformedMap.get("listOfDates[0][1]"), instanceOf(String.class));
assertThat(transformedMap.get("listOfDates[1][0]"), instanceOf(String.class));
assertThat(transformedMap.get("listOfDates[1][1]"), instanceOf(String.class));
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public Employee buildEmployee() {
Address companyAddress = new Address();
@@ -162,8 +208,8 @@ public class ObjectToMapTransformerTests {
companyAddress.setZip("12345");
Map<String, Long[]> coordinates = new HashMap<String, Long[]>();
coordinates.put("latitude", new Long[]{(long) 1, (long) 5, (long) 13});
coordinates.put("longitude", new Long[]{(long) 156});
coordinates.put("latitude", new Long[] { (long) 1, (long) 5, (long) 13 });
coordinates.put("longitude", new Long[] { (long) 156 });
companyAddress.setCoordinates(coordinates);
List<Date> datesA = new ArrayList<Date>();
@@ -231,58 +277,90 @@ public class ObjectToMapTransformerTests {
}
public static class Employee {
private List<String> departments;
private List<List<Date>> listOfDates;
private String companyName;
private Person person;
private Address companyAddress;
private Map<String, Map<String, Object>> testMapInMapData;
public List<List<Date>> getListOfDates() {
return listOfDates;
}
public void setListOfDates(List<List<Date>> listOfDates) {
this.listOfDates = listOfDates;
}
public Map<String, Map<String, Object>> getTestMapInMapData() {
return testMapInMapData;
}
public void setTestMapInMapData(
Map<String, Map<String, Object>> testMapInMapData) {
this.testMapInMapData = testMapInMapData;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public Address getCompanyAddress() {
return companyAddress;
}
public void setCompanyAddress(Address companyAddress) {
this.companyAddress = companyAddress;
}
public List<String> getDepartments() {
return departments;
}
public void setDepartments(List<String> departments) {
this.departments = departments;
}
}
public static class Person {
private String fname;
private String lname;
private String[] akaNames;
private List<Map<String, Object>> remarks;
private Child child;
private BigDecimal age;
private Date birthDate;
public Instant deathDate;
private Address address;
public BigDecimal getAge() {
return age;
}
@@ -299,85 +377,112 @@ public class ObjectToMapTransformerTests {
this.birthDate = birthDate;
}
private Date birthDate;
public Child getChild() {
return child;
}
public void setChild(Child child) {
this.child = child;
}
public List<Map<String, Object>> getRemarks() {
return remarks;
}
public void setRemarks(List<Map<String, Object>> remarks) {
this.remarks = remarks;
}
private Address address;
public String[] getAkaNames() {
return akaNames;
}
public void setAkaNames(String... akaNames) {
this.akaNames = akaNames;
}
public String getFname() {
return fname;
}
public void setFname(String fname) {
this.fname = fname;
}
public String getLname() {
return lname;
}
public void setLname(String lname) {
this.lname = lname;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
public static class Address {
private String street;
private String city;
private String zip;
private Map<String, List<String>> mapWithListData;
private Map<String, Long[]> coordinates;
public Map<String, List<String>> getMapWithListData() {
return mapWithListData;
}
public void setMapWithListData(Map<String, List<String>> mapWithListData) {
this.mapWithListData = mapWithListData;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getZip() {
return zip;
}
public void setZip(String zip) {
this.zip = zip;
}
public Map<String, Long[]> getCoordinates() {
return coordinates;
}
public void setCoordinates(Map<String, Long[]> coordinates) {
this.coordinates = coordinates;
}
}
public static class Child {
private Person parent;
public Person getParent() {
@@ -387,5 +492,7 @@ public class ObjectToMapTransformerTests {
public void setParent(Person parent) {
this.parent = parent;
}
}
}