ObjectToMapTransformer now handles BigDecimal
refactored it to delegate to Jackson mapper (much simpler) deleted unused classes changed the name of the attribute to 'shouldFlattenKeys' added support and tests for Collection of Collections fixed method signature, polishing fixed javadoc polishing, fixed spelling error, updated javadocs
This commit is contained in:
committed by
Mark Fisher
parent
c38e585250
commit
1d9f0b24e5
@@ -1,160 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.integration.transformer;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 2.0
|
||||
*/
|
||||
class CycleDetector {
|
||||
private final ExpressionParser parser = new SpelExpressionParser();
|
||||
private final String[] defaultIgnorePakages = new String[]{
|
||||
"com.apple",
|
||||
"com.sun",
|
||||
"java.awt",
|
||||
"java",
|
||||
"javax",
|
||||
"org.jcp",
|
||||
"org.omg",
|
||||
"sun"
|
||||
};
|
||||
private boolean ignoreClassAttribute = true;
|
||||
private boolean ignoreDefaultPackages = true;
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @param ignorePakages
|
||||
*/
|
||||
public void detectCycle(Object target, String... ignorePakages){
|
||||
Map<Object, Set<Object>> objectReferenceMap = new HashMap<Object, Set<Object>>();
|
||||
this.doDetect(target, objectReferenceMap, ignorePakages);
|
||||
}
|
||||
/*
|
||||
*
|
||||
*/
|
||||
private void doDetect(Object target, Map<Object, Set<Object>> objectReferenceMap, String[] ignorePakages){
|
||||
if (propertyInIgnoredPackage(target, ignorePakages)){
|
||||
return;
|
||||
}
|
||||
if (collectionMapOrArray(target)){
|
||||
Iterable<?> iterable = null;
|
||||
if (target instanceof Collection<?>) {
|
||||
iterable = (Iterable<?>) target;
|
||||
} else if (target instanceof Map<?, ?>){
|
||||
iterable = ((Map<?, ?>) target).values();
|
||||
} else if (target.getClass().isArray()){
|
||||
iterable = CollectionUtils.arrayToList(target);
|
||||
}
|
||||
for (Object value : iterable) {
|
||||
this.doDetect(value, objectReferenceMap, ignorePakages);
|
||||
}
|
||||
} else {
|
||||
if (!objectReferenceMap.containsKey(target)){
|
||||
objectReferenceMap.put(target, new HashSet<Object>());
|
||||
}
|
||||
EvaluationContext context = new StandardEvaluationContext(target);
|
||||
BeanWrapperImpl bw = new BeanWrapperImpl(target);
|
||||
PropertyDescriptor[] descriptors = bw.getPropertyDescriptors();
|
||||
for (PropertyDescriptor propertyDescriptor : descriptors) {
|
||||
String propertyName = propertyDescriptor.getName();
|
||||
if (propertyName.equals("class") && ignoreClassAttribute){
|
||||
continue; // no need to process
|
||||
}
|
||||
Expression expression = parser.parseExpression(propertyName);
|
||||
Object propertyValue = null;
|
||||
try {
|
||||
propertyValue = expression.getValue(context);
|
||||
} catch (Exception e) {/*nothing to do, might only happen when 'ignoreClassAttribute' is set to false ('true' by default)*/}
|
||||
|
||||
if (propertyValue != null){
|
||||
if (!collectionMapOrArray(propertyValue)){
|
||||
Set<Object> references = objectReferenceMap.get(target);
|
||||
if (!references.contains(propertyValue)){
|
||||
references.add(propertyValue);
|
||||
}
|
||||
if (objectReferenceMap.containsKey(propertyValue)){
|
||||
references = objectReferenceMap.get(propertyValue);
|
||||
if (references.contains(target)){
|
||||
throw new MessageTransformationException("Cyclic reference detected between: " +
|
||||
propertyValue.getClass().getSimpleName() + " - " + target.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
}
|
||||
this.doDetect(propertyValue, objectReferenceMap, ignorePakages);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
*
|
||||
*/
|
||||
private boolean collectionMapOrArray(Object elementValue){
|
||||
return (elementValue instanceof Map<?,?> ||
|
||||
elementValue instanceof Collection<?> ||
|
||||
elementValue.getClass().isArray());
|
||||
}
|
||||
/*
|
||||
*
|
||||
*/
|
||||
private boolean propertyInIgnoredPackage(Object elementValue, String[] ignorePakagess){
|
||||
if (this.collectionMapOrArray(elementValue)){
|
||||
return false;
|
||||
}
|
||||
for (String packagePattern : ignorePakagess) {
|
||||
if (elementValue.getClass().getPackage().getName().startsWith(packagePattern)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (ignoreDefaultPackages){
|
||||
for (String packagePattern : defaultIgnorePakages) {
|
||||
if (elementValue.getClass().getPackage().getName().startsWith(packagePattern)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public boolean isIgnoreClassAttribute() {
|
||||
return ignoreClassAttribute;
|
||||
}
|
||||
|
||||
public void setIgnoreClassAttribute(boolean ignoreClassAttribute) {
|
||||
this.ignoreClassAttribute = ignoreClassAttribute;
|
||||
}
|
||||
|
||||
public boolean isIgnoreDefaultPackages() {
|
||||
return ignoreDefaultPackages;
|
||||
}
|
||||
|
||||
public void setIgnoreDefaultPackages(boolean ignoreDefaultPackages) {
|
||||
this.ignoreDefaultPackages = ignoreDefaultPackages;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -13,20 +13,25 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.transformer;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Will transform an object graph into a flat Map where keys are valid SpEL expressions
|
||||
* and values are of java.lang.* type. This means that this transformer will recursively navigate
|
||||
* through the Object graph until the value could be java.lang.*
|
||||
* It supports Collections, Maps and Arrays which means it will flatten Object's attributes that are defined as such:<br>
|
||||
* Will transform an object graph into a Map. It supports a conventional Map (map of maps) where complex attributes are
|
||||
* represented as Map values as well as a flat Map where keys document the path to the value. It supports Collections,
|
||||
* Maps and Arrays which means that for flat maps it will flatten an Object's properties as such:<br>
|
||||
*
|
||||
* private Map<String, Map<String, Object>> testMapInMapData;<br>
|
||||
* private List<String> departments;<br>
|
||||
* private String[] akaNames;<br>
|
||||
* private Map<String, List<String>> mapWithListData;<br>
|
||||
*
|
||||
* The resulting Map structure will look similar to this:<br>
|
||||
*
|
||||
@@ -34,20 +39,69 @@ import java.util.Map;
|
||||
* departments[0]=HR<br>
|
||||
* person.lname=Case
|
||||
*
|
||||
* By default it will transform to a flat Map. If you need to transform to a Map of Maps set the 'shouldFlattenKeys'
|
||||
* property to 'false' via the {@link ObjectToMapTransformer#setShouldFlattenKeys(boolean)} method.
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ObjectToMapTransformer extends AbstractPayloadTransformer<Object, Map<?,?>> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.integration.transformer.AbstractPayloadTransformer#transformPayload(java.lang.Object)
|
||||
*/
|
||||
private volatile boolean shouldFlattenKeys = true;
|
||||
|
||||
public void setShouldFlattenKeys(boolean shouldFlattenKeys) {
|
||||
this.shouldFlattenKeys = shouldFlattenKeys;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Map<String, Object> transformPayload(Object payload) throws Exception {
|
||||
CycleDetector cycleDetector = new CycleDetector();
|
||||
cycleDetector.detectCycle(payload);
|
||||
ObjectToSpelMapBuilder builder = new ObjectToSpelMapBuilder();
|
||||
return builder.buildSpelMap(payload);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Map<String,Object> result = new ObjectMapper().readValue(mapper.writeValueAsString(payload), Map.class);
|
||||
if (this.shouldFlattenKeys) {
|
||||
result = this.flattenMap(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, Object> flattenMap(Map<String,Object> result){
|
||||
Map<String,Object> resultMap = new HashMap<String, Object>();
|
||||
this.doFlatten("", result, resultMap);
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
private void doFlatten(String propertyPrefix, Map<String,Object> inputMap, Map<String,Object> resultMap){
|
||||
if (StringUtils.hasText(propertyPrefix)) {
|
||||
propertyPrefix = propertyPrefix + ".";
|
||||
}
|
||||
for (String key : inputMap.keySet()) {
|
||||
Object value = inputMap.get(key);
|
||||
this.doProcessElement(propertyPrefix + key, value, resultMap);
|
||||
}
|
||||
}
|
||||
|
||||
private void doProcessCollection(String propertyPrefix, Collection<?> list, Map<String, Object> resultMap) {
|
||||
int counter = 0;
|
||||
for (Object element : list) {
|
||||
this.doProcessElement(propertyPrefix + "[" + counter + "]", element, resultMap);
|
||||
counter ++;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void doProcessElement(String propertyPrefix, Object element, Map<String, Object> resultMap) {
|
||||
if (element instanceof Map) {
|
||||
this.doFlatten(propertyPrefix, (Map<String, Object>) element, resultMap);
|
||||
}
|
||||
else if (element instanceof Collection) {
|
||||
this.doProcessCollection(propertyPrefix, (Collection<?>) element, resultMap);
|
||||
}
|
||||
else if (element != null && element.getClass().isArray()) {
|
||||
Collection<?> collection = CollectionUtils.arrayToList(element);
|
||||
this.doProcessCollection(propertyPrefix, collection, resultMap);
|
||||
}
|
||||
else {
|
||||
resultMap.put(propertyPrefix, element);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.integration.transformer;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 2.0
|
||||
*/
|
||||
class ObjectToSpelMapBuilder {
|
||||
|
||||
private final ExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
private boolean serializeTypeName;
|
||||
|
||||
|
||||
public Map<String, Object> buildSpelMap(Object rootObject) {
|
||||
Map<String, Object> propertiesMap = new HashMap<String, Object>();
|
||||
EvaluationContext context = new StandardEvaluationContext(rootObject);
|
||||
this.buildProperties(context, "", propertiesMap, rootObject);
|
||||
return propertiesMap;
|
||||
}
|
||||
|
||||
private void buildProperties(EvaluationContext context, String parentPropertyPath, Map<String, Object> propertiesMap, Object object) {
|
||||
BeanWrapperImpl bw = new BeanWrapperImpl(object);
|
||||
PropertyDescriptor[] descriptors = bw.getPropertyDescriptors();
|
||||
for (PropertyDescriptor propertyDescriptor : descriptors) {
|
||||
Class<?> propertyType = propertyDescriptor.getPropertyType();
|
||||
String propertyName = propertyDescriptor.getName();
|
||||
String propertyPath = parentPropertyPath + propertyName;
|
||||
if (propertyType.isArray() || Collection.class.isAssignableFrom(propertyType)) {
|
||||
this.processArray(context, propertyPath, propertyName, propertyType, propertiesMap);
|
||||
}
|
||||
else if (propertyType.isAnonymousClass()) {
|
||||
throw new IllegalArgumentException("anonymous class property transformation is not supported");
|
||||
}
|
||||
else if (propertyType.isAssignableFrom(Map.class)) {
|
||||
Expression expression = parser.parseExpression(propertyPath);
|
||||
Map<?,?> map = (Map<?,?>) expression.getValue(context);
|
||||
if (map != null) {
|
||||
this.processMap(context, propertiesMap, map, parentPropertyPath, propertyName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Expression expression = parser.parseExpression(propertyPath);
|
||||
Object propertyValue = expression.getValue(context);
|
||||
if (propertyValue != null) {
|
||||
this.processElementValue(context, propertyValue, propertyName, propertyPath, propertiesMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processMap(EvaluationContext context, Map<String, Object> mappedProperties, Map<?,?> mapToTransform, String propertyPath, String propertyName) {
|
||||
Iterator<?> mapIter = mapToTransform.keySet().iterator();
|
||||
while (mapIter.hasNext()) {
|
||||
Object keyElement = mapIter.next();
|
||||
Object elementValue = mapToTransform.get(keyElement);
|
||||
String mapPropertyPath = propertyPath + propertyName + "['" + keyElement.toString() + "']";
|
||||
if (elementValue.getClass().isArray() || elementValue instanceof Collection<?>) {
|
||||
this.processArray(context, mapPropertyPath, "", elementValue.getClass(), mappedProperties);
|
||||
}
|
||||
else if (elementValue instanceof Map<?,?>) {
|
||||
this.processMap(context, mappedProperties, (Map<?, ?>) elementValue, mapPropertyPath, "");
|
||||
}
|
||||
else {
|
||||
this.processElementValue(context, elementValue, propertyName, mapPropertyPath, mappedProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processArray(EvaluationContext context, String propertyPath, String propertyName, Class<?> elementType, Map<String, Object> propertiesMap) {
|
||||
Expression arrayExp = parser.parseExpression(propertyPath);
|
||||
Object array = arrayExp.getValue(context);
|
||||
List<?> arrayElements = null;
|
||||
if (elementType.isArray()) {
|
||||
arrayElements = CollectionUtils.arrayToList(array);
|
||||
}
|
||||
else {
|
||||
arrayElements = (List<?>) array;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (Object arrayElement : arrayElements) {
|
||||
String arrayPropertyPath = propertyPath + "[" + i++ + "]";
|
||||
if (arrayElement instanceof Map<?, ?>) {
|
||||
// last argument is empty because it is not a named property, but an array element
|
||||
this.processMap(context, propertiesMap, (Map<?, ?>) arrayElement, arrayPropertyPath, "");
|
||||
}
|
||||
else if (arrayElement.getClass().isArray()){
|
||||
this.processArray(context, arrayPropertyPath, propertyName, elementType, propertiesMap);
|
||||
}
|
||||
else {
|
||||
this.processElementValue(context, arrayElement, propertyName, arrayPropertyPath, propertiesMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processElementValue(EvaluationContext context, Object elementValue, String propertyName, String propertyPath, Map<String, Object> propertiesMap) {
|
||||
// JDK packages considered shared, thus serializable
|
||||
if (elementValue.getClass().getPackage().getName().startsWith("java.lang")) {
|
||||
if (propertyName.equals("class") && !this.serializeTypeName) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
propertiesMap.put(propertyPath, elementValue);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.buildProperties(context, propertyPath + ".", propertiesMap, elementValue);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.integration.transformer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
*
|
||||
*/
|
||||
public class CycleDetectorTests {
|
||||
@Test
|
||||
public void testWithNoIgnoredPackages(){
|
||||
Parent parent = this.prepare(false);
|
||||
CycleDetector builder = new CycleDetector();
|
||||
builder.setIgnoreDefaultPackages(false);
|
||||
builder.detectCycle(parent);
|
||||
// should not throw an exception
|
||||
}
|
||||
@Test
|
||||
public void testWithNoIgnoredPackagesAndClassProperty(){
|
||||
Parent parent = this.prepare(false);
|
||||
CycleDetector builder = new CycleDetector();
|
||||
builder.setIgnoreDefaultPackages(false);
|
||||
builder.setIgnoreClassAttribute(false);
|
||||
builder.detectCycle(parent);
|
||||
// should not throw an exception
|
||||
}
|
||||
@Test
|
||||
public void testWithAditionalIgnoredPackages(){
|
||||
Parent parent = this.prepare(true);
|
||||
CycleDetector builder = new CycleDetector();
|
||||
builder.detectCycle(parent, "org.springframework.integration.transformer");
|
||||
// should not throw an exception, however if you remove additional package from
|
||||
// the above method there is a cycle in the domain core
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObjectReferenceMapWithoutCycle(){
|
||||
Parent parent = this.prepare(false);
|
||||
CycleDetector builder = new CycleDetector();
|
||||
builder.detectCycle(parent);
|
||||
// should not throw an exception
|
||||
}
|
||||
|
||||
@Test(expected=MessageTransformationException.class)
|
||||
public void testObjectReferenceMapWithCycle(){
|
||||
Parent parent = this.prepare(true);
|
||||
CycleDetector builder = new CycleDetector();
|
||||
builder.detectCycle(parent);
|
||||
}
|
||||
@Test
|
||||
public void testWithNoCyclesInArray(){
|
||||
Parent parent = this.prepare(false);
|
||||
Foo[] foos = new Foo[]{new Foo(), new Foo()};
|
||||
parent.getAddress().setFoos(foos);
|
||||
CycleDetector builder = new CycleDetector();
|
||||
builder.detectCycle(parent);
|
||||
}
|
||||
@Test(expected=MessageTransformationException.class)
|
||||
public void testWithCyclesInArray(){
|
||||
Parent parent = this.prepare(false);
|
||||
Foo foo = new Foo();
|
||||
Bar bar = new Bar();
|
||||
foo.setBar(bar);
|
||||
bar.setFoo(foo);
|
||||
Foo[] foos = new Foo[]{foo, new Foo()};
|
||||
parent.getAddress().setFoos(foos);
|
||||
CycleDetector builder = new CycleDetector();
|
||||
builder.detectCycle(parent);
|
||||
}
|
||||
@Test
|
||||
public void testWithNoCyclesInMapWithList(){
|
||||
Parent parent = this.prepare(false);
|
||||
Foo fooA = new Foo();
|
||||
Foo fooB = new Foo();
|
||||
Foo[] foos = new Foo[]{fooA, fooB};
|
||||
parent.getAddress().setFoos(foos);
|
||||
List<Foo> fooList = new ArrayList<Foo>();
|
||||
fooList.add(fooA);
|
||||
fooList.add(fooB);
|
||||
Map<Object, List<Foo>> mapOfFoos = new HashMap<Object, List<Foo>>();
|
||||
mapOfFoos.put("listOfFoos", fooList);
|
||||
parent.getChild().setMapOfFoos(mapOfFoos);
|
||||
CycleDetector builder = new CycleDetector();
|
||||
builder.detectCycle(parent);
|
||||
}
|
||||
@Test(expected=MessageTransformationException.class)
|
||||
public void testWithCyclesInMapWithList(){
|
||||
Parent parent = this.prepare(false);
|
||||
Foo fooA = new Foo();
|
||||
Bar bar = new Bar();
|
||||
bar.setFoo(fooA);
|
||||
fooA.setBar(bar);
|
||||
Foo fooB = new Foo();
|
||||
Foo[] foos = new Foo[]{new Foo(), new Foo()};
|
||||
parent.getAddress().setFoos(foos);
|
||||
List<Foo> fooList = new ArrayList<Foo>();
|
||||
fooList.add(fooA);
|
||||
fooList.add(fooB);
|
||||
Map<Object, List<Foo>> mapOfFoos = new HashMap<Object, List<Foo>>();
|
||||
mapOfFoos.put("listOfFoos", fooList);
|
||||
parent.getChild().setMapOfFoos(mapOfFoos);
|
||||
CycleDetector builder = new CycleDetector();
|
||||
builder.detectCycle(parent);
|
||||
}
|
||||
|
||||
//################# Test Classes ###################
|
||||
public Parent prepare(boolean cycle){
|
||||
Parent parent = new Parent();
|
||||
Child child = new Child();
|
||||
Address address = new Address();
|
||||
address.setStreet("123 Main st");
|
||||
child.setAddress(address);
|
||||
List<String> nickNames = new ArrayList<String>();
|
||||
nickNames.add("spanky");
|
||||
nickNames.add("goofy");
|
||||
child.setNickNames(nickNames);
|
||||
child.setName("Seva");
|
||||
if (cycle){
|
||||
child.setParent(parent);
|
||||
}
|
||||
|
||||
parent.setAddress(address);
|
||||
parent.setChild(child);
|
||||
parent.setName("Oleg");
|
||||
return parent;
|
||||
}
|
||||
/*
|
||||
*
|
||||
*/
|
||||
public static class Parent{
|
||||
private Address address;
|
||||
private Child child;
|
||||
private String name;
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
public void setAddress(Address address) {
|
||||
this.address = address;
|
||||
}
|
||||
public Child getChild() {
|
||||
return child;
|
||||
}
|
||||
public void setChild(Child child) {
|
||||
this.child = child;
|
||||
}
|
||||
}
|
||||
/*
|
||||
*
|
||||
*/
|
||||
public static class Child{
|
||||
private String name;
|
||||
private List<String> nickNames;
|
||||
private Map<Object, List<Foo>> mapOfFoos;
|
||||
private Address address;
|
||||
private Parent parent;
|
||||
public Parent getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(Parent parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public List<String> getNickNames() {
|
||||
return nickNames;
|
||||
}
|
||||
|
||||
public void setNickNames(List<String> nickNames) {
|
||||
this.nickNames = nickNames;
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(Address address) {
|
||||
this.address = address;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public Map<Object, List<Foo>> getMapOfFoos() {
|
||||
return mapOfFoos;
|
||||
}
|
||||
|
||||
public void setMapOfFoos(Map<Object, List<Foo>> mapOfFoos) {
|
||||
this.mapOfFoos = mapOfFoos;
|
||||
}
|
||||
}
|
||||
/*
|
||||
*
|
||||
*/
|
||||
public static class Address{
|
||||
private String street;
|
||||
private Foo[] foos;
|
||||
|
||||
public Foo[] getFoos() {
|
||||
return foos;
|
||||
}
|
||||
|
||||
public void setFoos(Foo[] foos) {
|
||||
this.foos = foos;
|
||||
}
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public void setStreet(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Foo{
|
||||
private Bar bar;
|
||||
|
||||
public Bar getBar() {
|
||||
return bar;
|
||||
}
|
||||
|
||||
public void setBar(Bar bar) {
|
||||
this.bar = bar;
|
||||
}
|
||||
}
|
||||
public static class Bar{
|
||||
private Foo foo;
|
||||
|
||||
public Foo getFoo() {
|
||||
return foo;
|
||||
}
|
||||
|
||||
public void setFoo(Foo foo) {
|
||||
this.foo = foo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -15,17 +15,19 @@
|
||||
*/
|
||||
package org.springframework.integration.transformer;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.codehaus.jackson.JsonGenerationException;
|
||||
import org.codehaus.jackson.JsonParseException;
|
||||
import org.codehaus.jackson.map.JsonMappingException;
|
||||
import org.junit.Test;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.context.expression.MapAccessor;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
@@ -33,6 +35,11 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
@@ -41,27 +48,101 @@ import org.springframework.integration.support.MessageBuilder;
|
||||
public class ObjectToMapTransformerTests {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testObjectToSpelMapTransformer(){
|
||||
public void testObjectToSpelMapTransformer() throws JsonParseException, JsonMappingException, JsonGenerationException, IOException{
|
||||
Employee employee = this.buildEmployee();
|
||||
EvaluationContext context = new StandardEvaluationContext(employee);
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
context.addPropertyAccessor(new MapAccessor());
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
ObjectToMapTransformer transformer = new ObjectToMapTransformer();
|
||||
Message<Employee> message = MessageBuilder.withPayload(employee).build();
|
||||
|
||||
Message<?> transformedMessage = transformer.transform(message);
|
||||
Map<String, Object> transformedMap = (Map<String, Object>) transformedMessage.getPayload();
|
||||
|
||||
System.out.println(transformedMap);
|
||||
assertNotNull(transformedMap);
|
||||
for (String key : transformedMap.keySet()) {
|
||||
Expression expression = parser.parseExpression(key);
|
||||
//System.out.println("Testing: " + key);
|
||||
Object valueFromTheMap = transformedMap.get(key);
|
||||
Object valueFromExpression = expression.getValue(context);
|
||||
String packageNameOfValueType = valueFromTheMap.getClass().getPackage().getName();
|
||||
assertTrue(packageNameOfValueType.startsWith("java.lang"));
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
}
|
||||
|
||||
Object valueFromTheMap = null;
|
||||
Object valueFromExpression = null;
|
||||
Expression expression = null;
|
||||
|
||||
expression = parser.parseExpression("departments[0]");
|
||||
valueFromTheMap = transformedMap.get("departments[0]");
|
||||
valueFromExpression = expression.getValue(context, employee, String.class);
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
|
||||
expression = parser.parseExpression("person.address.coordinates");
|
||||
valueFromTheMap = transformedMap.get("person.address.coordinates");
|
||||
valueFromExpression = expression.getValue(context, employee, Map.class);
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
|
||||
expression = parser.parseExpression("person.akaNames[0]");
|
||||
valueFromTheMap = transformedMap.get("person.akaNames[0]");
|
||||
valueFromExpression = expression.getValue(context, employee, String.class);
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
|
||||
expression = parser.parseExpression("testMapInMapData.internalMapA.bar");
|
||||
valueFromTheMap = transformedMap.get("testMapInMapData.internalMapA.bar");
|
||||
valueFromExpression = expression.getValue(context, employee, String.class);
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
|
||||
expression = parser.parseExpression("companyAddress.street");
|
||||
valueFromTheMap = transformedMap.get("companyAddress.street");
|
||||
valueFromExpression = expression.getValue(context, employee, String.class);
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
|
||||
expression = parser.parseExpression("person.lname");
|
||||
valueFromTheMap = transformedMap.get("person.lname");
|
||||
valueFromExpression = expression.getValue(context, employee, String.class);
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
|
||||
expression = parser.parseExpression("person.address.mapWithListData.mapWithListTestData[1]");
|
||||
valueFromTheMap = transformedMap.get("person.address.mapWithListData.mapWithListTestData[1]");
|
||||
valueFromExpression = expression.getValue(context, employee, String.class);
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
|
||||
expression = parser.parseExpression("companyAddress.city");
|
||||
valueFromTheMap = transformedMap.get("companyAddress.city");
|
||||
valueFromExpression = expression.getValue(context, employee, String.class);
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
|
||||
expression = parser.parseExpression("person.akaNames[2]");
|
||||
valueFromTheMap = transformedMap.get("person.akaNames[2]");
|
||||
valueFromExpression = expression.getValue(context, employee, String.class);
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
|
||||
expression = parser.parseExpression("person.child");
|
||||
valueFromTheMap = transformedMap.get("person.child");
|
||||
valueFromExpression = expression.getValue(context, employee, String.class);
|
||||
assertNull(valueFromTheMap);
|
||||
assertNull(valueFromExpression);
|
||||
|
||||
expression = parser.parseExpression("testMapInMapData.internalMapA.foo");
|
||||
valueFromTheMap = transformedMap.get("testMapInMapData.internalMapA.foo");
|
||||
valueFromExpression = expression.getValue(context, employee, String.class);
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
|
||||
expression = parser.parseExpression("person.address.city");
|
||||
valueFromTheMap = transformedMap.get("person.address.city");
|
||||
valueFromExpression = expression.getValue(context, employee, String.class);
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
|
||||
expression = parser.parseExpression("companyAddress.coordinates.latitude[0]");
|
||||
valueFromTheMap = transformedMap.get("companyAddress.coordinates.latitude[0]");
|
||||
valueFromExpression = expression.getValue(context, employee, Integer.class);
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
|
||||
expression = parser.parseExpression("person.remarks[1].baz");
|
||||
valueFromTheMap = transformedMap.get("person.remarks[1].baz");
|
||||
valueFromExpression = expression.getValue(context, employee, String.class);
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
|
||||
expression = parser.parseExpression("listOfDates[0][1]");
|
||||
valueFromTheMap = new Date((Long) transformedMap.get("listOfDates[0][1]"));
|
||||
valueFromExpression = expression.getValue(context, employee, Date.class);
|
||||
assertEquals(valueFromTheMap, valueFromExpression);
|
||||
}
|
||||
|
||||
@Test(expected=MessageTransformationException.class)
|
||||
public void testObjectToSpelMapTransformerWithCycle(){
|
||||
Employee employee = this.buildEmployee();
|
||||
@@ -86,9 +167,22 @@ public class ObjectToMapTransformerTests {
|
||||
coordinates.put("longitude", new Long[]{(long)156});
|
||||
companyAddress.setCoordinates(coordinates);
|
||||
|
||||
List<Date> datesA = new ArrayList<Date>();
|
||||
datesA.add(new Date(System.currentTimeMillis() + 10000));
|
||||
datesA.add(new Date(System.currentTimeMillis() + 20000));
|
||||
|
||||
List<Date> datesB = new ArrayList<Date>();
|
||||
datesB.add(new Date(System.currentTimeMillis() + 30000));
|
||||
datesB.add(new Date(System.currentTimeMillis() + 40000));
|
||||
|
||||
List<List<Date>> listOfDates = new ArrayList<List<Date>>();
|
||||
listOfDates.add(datesA);
|
||||
listOfDates.add(datesB);
|
||||
|
||||
Employee employee = new Employee();
|
||||
employee.setCompanyName("ABC Inc.");
|
||||
employee.setCompanyAddress(companyAddress);
|
||||
employee.setListOfDates(listOfDates);
|
||||
ArrayList departments = new ArrayList();
|
||||
departments.add("HR");
|
||||
departments.add("IT");
|
||||
@@ -98,6 +192,8 @@ public class ObjectToMapTransformerTests {
|
||||
person.setFname("Justin");
|
||||
person.setLname("Case");
|
||||
person.setAkaNames("Hard", "Use", "Beer");
|
||||
person.setBirthDate(new Date());
|
||||
person.setAge(new BigDecimal(10));
|
||||
Address personAddress = new Address();
|
||||
personAddress.setCity("Philly");
|
||||
personAddress.setStreet("123 Main");
|
||||
@@ -137,10 +233,17 @@ 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;
|
||||
}
|
||||
@@ -180,6 +283,24 @@ public class ObjectToMapTransformerTests {
|
||||
private String[] akaNames;
|
||||
private List<Map<String, Object>> remarks;
|
||||
private Child child;
|
||||
private BigDecimal age;
|
||||
public BigDecimal getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(BigDecimal age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public Date getBirthDate() {
|
||||
return birthDate;
|
||||
}
|
||||
|
||||
public void setBirthDate(Date birthDate) {
|
||||
this.birthDate = birthDate;
|
||||
}
|
||||
|
||||
private Date birthDate;
|
||||
public Child getChild() {
|
||||
return child;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user