Java tutorial
/** * Copyright (c) 2009-2011 Zauber S.A. <http://www.zaubersoftware.com/> * * 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 ar.com.zauber.commons.mom; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.ParameterizedType; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.beanutils.BeanUtilsBean; import org.apache.commons.beanutils.ConvertUtilsBean; import org.apache.commons.beanutils.Converter; import org.apache.commons.beanutils.DynaProperty; import org.apache.commons.beanutils.LazyDynaMap; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.Transformer; import org.apache.commons.lang.UnhandledException; import org.apache.commons.lang.Validate; /** * {@link MapObjectMapper} * * @author flbulgarelli */ @SuppressWarnings({ "unchecked", "rawtypes" }) public class MapObjectMapper { private final Transformer toMap = new ToMapTransformer(); private final BeanUtilsBean beanUtils; private final MapToBeanConverter beanConverter = new MapToBeanConverter(); private final ListToBeanArrayConverter listConverter = new ListToBeanArrayConverter(); private final MappingPackage mappingPackage; private PropertyStyle propertyStyle = BeanStyle.STYLE; public MapObjectMapper(final String packageName) { this.mappingPackage = new MappingPackage(packageName); } { beanUtils = new BeanUtilsBean(new ConvertUtilsBean() { @Override public Converter lookup(final Class destinationType) { if (isMappeableArray(destinationType)) { return listConverter; } if (isMappeable(destinationType)) { return beanConverter; } return super.lookup(destinationType); } @Override public Object convert(Object value, Class targetType) { return super.convert(value, targetType); } }) { @Override protected Object convert(final Object value, final Class targetType) { if (!targetType.isPrimitive() && value == null) { return null; } return super.convert(value, targetType); } }; } public MapObjectMapper registerConverter(Converter converter, Class<?> clazz) { beanUtils.getConvertUtils().register(converter, clazz); return this; } public Map<String, Object> toMap(final Object object) { Validate.isTrue(mappingPackage.isMappeable(object.getClass())); return new AttributesMap(object, this); } public List<Map<String, Object>> toMap(final Object[] objects) { return (List<Map<String, Object>>) CollectionUtils.collect(Arrays.asList(objects), toMap); } public <T> T toObject(Class<T> targetType, Object input) { if (input == null) { return null; } if (targetType.isAssignableFrom(input.getClass())) return (T) input; return (T) beanUtils.getConvertUtils().convert(input, targetType); } public <T> T[] toArray(final Class<T> clazz, final List<Map<String, Object>> list) { return (T[]) beanUtils.getConvertUtils().convert(list, Array.newInstance(clazz, 0).getClass()); } public boolean isMappeableArray(final Class<?> clazz) { return mappingPackage.isMappeableArray(clazz); } public boolean isMappeable(final Class<?> clazz) { return mappingPackage.isMappeable(clazz); } private class ToMapTransformer implements Transformer { public Object transform(final Object input) { return toMap(input); } } /** * {@link Converter} that transforms a list of maps into an array of * mappeable objects */ private class ListToBeanArrayConverter implements Converter { public Object convert(final Class destinationType, final Object value) { try { List<Map<String, Object>> list = (List<Map<String, Object>>) value; Object[] array = (Object[]) Array.newInstance(destinationType.getComponentType(), list.size()); Iterator<Map<String, Object>> iter = list.iterator(); for (int i = 0; i < array.length; i++) { array[i] = toObject(destinationType.getComponentType(), iter.next()); } return array; } catch (Exception e) { throw soften(e); } } } private class MapToBeanConverter implements Converter { public Object convert(final Class type, final Object value) { if (type.isAssignableFrom(value.getClass())) return value; try { LazyDynaMap dynaMap = new LazyDynaMap((Map<String, Object>) value); Object bean = type.newInstance(); copyProperties(dynaMap, bean); return bean; } catch (Exception e) { throw soften(e); } } /** * @param source * @param destination * @throws IllegalAccessException * @throws InvocationTargetException */ public void copyProperties(LazyDynaMap source, Object destination) throws IllegalAccessException, InvocationTargetException { Validate.notNull(source); Validate.notNull(destination); DynaProperty[] origDescriptors = source.getDynaClass().getDynaProperties(); for (int i = 0; i < origDescriptors.length; i++) { String name = origDescriptors[i].getName(); copyProperty(source.get(name), destination, name); } } protected void copyProperty(Object property, Object destination, String name) { try { if (propertyStyle.isSeteable(beanUtils, property, destination, name)) { if (List.class .isAssignableFrom(beanUtils.getPropertyUtils().getPropertyType(destination, name))) { final Class<?> componentType = getComponentType(destination, name); property = CollectionUtils.collect(coalesceList((List) property), new Transformer() { public Object transform(Object input) { return toObject(componentType, input); } }); } propertyStyle.setValue(beanUtils, property, destination, name); } else if (!name.equals("class")) { throw new IllegalArgumentException( "There is no settable property named " + name + " in class " + destination.getClass()); } } catch (Exception e) { throw soften(e); } } protected List coalesceList(List list) { return list != null ? list : Collections.emptyList(); } } public MapObjectMapper setPropertyStyle(PropertyStyle property) { this.propertyStyle = property; return this; } public RuntimeException soften(Exception e) { if (e instanceof RuntimeException) { return (RuntimeException) e; } return new UnhandledException(e); } protected Class<?> getComponentType(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { return (Class<?>) ((ParameterizedType) PropertyUtils.getPropertyDescriptor(bean, name).getReadMethod() .getGenericReturnType()).getActualTypeArguments()[0]; } }