/*******************************************************************************
* Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package de.gebit.integrity.parameter.conversion.conversions.java.other;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import de.gebit.integrity.operations.UnexecutableException;
import de.gebit.integrity.parameter.conversion.Conversion;
import de.gebit.integrity.parameter.conversion.ConversionContext;
import de.gebit.integrity.parameter.conversion.ConversionFailedException;
import de.gebit.integrity.utils.ParameterUtil.UnresolvableVariableException;
/**
* A default Integrity conversion.
*
* @author Rene Schneider - initial API and implementation
*
*/
@SuppressWarnings("rawtypes")
@de.gebit.integrity.parameter.conversion.Conversion.Priority(0)
public class ObjectToMap extends Conversion<Object, Map> {
@Override
public Map convert(Object aSource, Class<? extends Map> aTargetType, ConversionContext aConversionContext)
throws ConversionFailedException {
// Using a Tree Map here for values ordered by key
Map<String, Object> tempKeyValueMap = new TreeMap<String, Object>();
try {
for (PropertyDescriptor tempDescriptor : Introspector.getBeanInfo(aSource.getClass(), Object.class)
.getPropertyDescriptors()) {
if (Boolean.TRUE.equals(tempDescriptor.getValue("transient"))) {
// Skip transient properties, as those are often used as "fake" properties in order to implement a
// getter for them which does some sort of magic. Calling unknown magical stuff in a generic fashion
// when running over Java Beans is not such a good idea and quickly leads to problems, which is the
// reason why transient properties are skipped here. See also issue #109.
continue;
}
Method tempReadMethod = tempDescriptor.getReadMethod();
if (tempReadMethod != null) {
Object tempValue = tempReadMethod.invoke(aSource);
if (tempValue instanceof Collection) {
Collection tempCollectionValue = (Collection) tempValue;
List<Object> tempList = new ArrayList<Object>();
Iterator<?> tempIterator = tempCollectionValue.iterator();
while (tempIterator.hasNext()) {
Object tempConvertedValue = convertValueRecursive(null, null, tempIterator.next(),
aConversionContext);
tempList.add(tempConvertedValue);
}
// In the Integrity language, there is no difference between an array of nested objects with
// just one object and a single nested object. The array just comes into existence by specifying
// more than one object, separated by commas. Therefore, when converting bean objects to maps
// (for comparison with nested object structures specified in the test script), we have to omit
// the array object when converting collections with just one entry: the single entry must be
// inserted directly into the map and not be wrapped into an array of size 1. Fixes issue #125.
if (tempList.size() == 1) {
tempKeyValueMap.put(tempDescriptor.getName(), tempList.get(0));
} else {
tempKeyValueMap.put(tempDescriptor.getName(), tempList.toArray());
}
} else {
Object tempConvertedValue = convertValueRecursive(null, null, tempValue, aConversionContext);
tempKeyValueMap.put(tempDescriptor.getName(), tempConvertedValue);
}
}
}
} catch (IntrospectionException exc) {
throw new ConversionFailedException(aSource.getClass(), aTargetType, null, exc);
} catch (IllegalArgumentException exc) {
throw new ConversionFailedException(aSource.getClass(), aTargetType, null, exc);
} catch (IllegalAccessException exc) {
throw new ConversionFailedException(aSource.getClass(), aTargetType, null, exc);
} catch (InvocationTargetException exc) {
throw new ConversionFailedException(aSource.getClass(), aTargetType, null, exc);
} catch (UnresolvableVariableException exc) {
throw new ConversionFailedException(aSource.getClass(), aTargetType, null, exc);
} catch (ClassNotFoundException exc) {
throw new ConversionFailedException(aSource.getClass(), aTargetType, null, exc);
} catch (UnexecutableException exc) {
throw new ConversionFailedException(aSource.getClass(), aTargetType, null, exc);
} catch (InstantiationException exc) {
throw new ConversionFailedException(aSource.getClass(), aTargetType, null, exc);
}
return tempKeyValueMap;
}
// protected boolean isTransient(String aFieldName, Class<?> aClass) {
// Class<?> tempClassInFocus = aClass;
// while(tempClassInFocus != null) {
// try {
// Field tempField = tempClassInFocus.getDeclaredField(aFieldName);
//
// if(tempField != null) {
// return tempField.getModifiers() & Modifier
// }
// } catch (NoSuchFieldException | SecurityException exc) {
// // ignore
// }
// }
// }
}