Merge pull request #51 from olegz/INT-1968
ObjectToMapTransformer now handles BigDecimal
This commit is contained in:
@@ -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