Author: tchemit Date: 2010-02-21 19:16:09 +0100 (Sun, 21 Feb 2010) New Revision: 1764 Added: trunk/src/main/java/org/nuiton/util/beans/ trunk/src/main/java/org/nuiton/util/beans/Binder.java trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java trunk/src/main/java/org/nuiton/util/beans/BinderModel.java trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java trunk/src/main/java/org/nuiton/util/beans/package-info.java trunk/src/test/java/org/nuiton/util/beans/ trunk/src/test/java/org/nuiton/util/beans/BeanA.java trunk/src/test/java/org/nuiton/util/beans/BeanB.java trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java trunk/src/test/java/org/nuiton/util/beans/BinderProviderTest.java trunk/src/test/java/org/nuiton/util/beans/BinderTest.java Log: Evolution #309: BeanLoador Added: trunk/src/main/java/org/nuiton/util/beans/Binder.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/Binder.java (rev 0) +++ trunk/src/main/java/org/nuiton/util/beans/Binder.java 2010-02-21 18:16:09 UTC (rev 1764) @@ -0,0 +1,128 @@ +/* + * *##% Nuiton utilities library + * Copyright (C) 2004 - 2010 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +package org.nuiton.util.beans; + +import java.lang.reflect.InvocationTargetException; +import java.util.Map; +import java.util.TreeMap; + +/** + * A {@code binder} permits to copy some properties from an object to another + * one. + * <p/> + * It is based on a {@link BinderModel} which contains the mapping of properties + * to transfert from the source object to the destination object. + * <p/> + * Use the method {@link #copy(Object, Object)} to transfert properties. + * <p/> + * Use the method {@link #obtainProperties(Object)} to obtain + * + * @author tchemit < chemit@codelutin.com > + * @param <I> the source bean type + * @param <O> the destination bean type + * @since 1.1.5 + */ +public class Binder<I, O> implements java.io.Serializable { + + + private static final long serialVersionUID = 1L; + + /** + * the model of the binder + */ + protected BinderModel<I, O> model; + + /** + * Obtain from the given object all properties registred in the binder + * model. + * <p/> + * <b>Note:</b> If a property's value is null, it will not be injected in + * the result. + * + * @param from the bean to read + * @return the map of properties obtained indexed by their property name, + * or an empty map is the given {@code from} is {@code null}. + */ + public Map<String, Object> obtainProperties(I from) { + if (from == null) { + // special limit case + return java.util.Collections.emptyMap(); + } + Map<String, Object> result = new TreeMap<String, Object>(); + for (String srcProperty : model.getSourceDescriptors()) { + + try { + Object read; + read = model.getSourceReadMethod(srcProperty).invoke(from); + if (read != null) { + result.put(srcProperty, read); + } + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + return result; + } + + /** + * Copy properties from a source bean to a destination one according to + * the model of the binder. + * + * @param from the bean to read + * @param dst the bean to write + */ + public void copy(I from, O dst) { + + for (String srcProperty : model.getSourceDescriptors()) { + + String dstProperty = model.getTargetProperty(srcProperty); + + try { + Object read = + model.getSourceReadMethod(srcProperty).invoke(from); + model.getTargetWriteMethod(dstProperty).invoke(dst, read); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + } + + /** + * Get the model of the binder. + * + * @return the model of the binder + */ + protected BinderModel<I, O> getModel() { + return model; + } + + /** + * Set the model of the binder. + * + * @param model the model of the binder + */ + protected void setModel(BinderModel<?, ?> model) { + this.model = (BinderModel<I, O>) model; + } +} \ No newline at end of file Property changes on: trunk/src/main/java/org/nuiton/util/beans/Binder.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java (rev 0) +++ trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java 2010-02-21 18:16:09 UTC (rev 1764) @@ -0,0 +1,357 @@ +/* + * *##% Nuiton utilities library + * Copyright (C) 2004 - 2010 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package org.nuiton.util.beans; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Map; +import java.util.TreeMap; + +/** + * A builder of {@link BinderModel} and {@link Binder}. + * <p/> + * A {@code binder} permits to copy some properties from a bean to another one. + * + * @author tchemit < chemit@codelutin.com > + * @see BinderModel + * @see Binder + * @since 1.1.5 + */ +public class BinderBuilder { + + /** + * current model used to build the binder + */ + protected BinderModel<?, ?> model; + protected Map<String, PropertyDescriptor> sourceDescriptors; + protected Map<String, PropertyDescriptor> targetDescriptors; + + + /** + * Creates a new binder model for a mirrored binder (source type = target + * type). + * <p/> + * <b>Note:</b> If a previous model was created, but not released via the + * method {@link #createBinder(Class)}, the method will failed. + * + * @param type the type of source and target + * @return the instance of the builder + * @throws IllegalStateException if a previous builder model was created + * without been released + * @throws NullPointerException if a parameter is null + */ + public BinderBuilder createBinderModel(Class<?> type) + throws IllegalStateException, NullPointerException { + createBinderModel(type, type); + return this; + } + + /** + * Creates a new binder model. + * <p/> + * <b>Note:</b> If a previous model was created, but not released via the + * method {@link #createBinder(Class)}, the method will failed. + * + * @param sourceType the type of the source + * @param targetType the type of the target + * @return the instance of the builder + * @throws IllegalStateException if a previous builder model was created + * without been released + * @throws NullPointerException if a parameter is null + */ + public BinderBuilder createBinderModel(Class<?> sourceType, + Class<?> targetType) + throws IllegalStateException, NullPointerException { + if (sourceType == null) { + throw new NullPointerException("sourceType can not be null"); + } + if (targetType == null) { + throw new NullPointerException("targetType can not be null"); + } + + if (model != null) { + throw new IllegalStateException("there is already a binderModel in " + + "construction, release it with the method createBinder " + + "before using this method."); + } + + // init model + model = new BinderModel(sourceType, targetType); + + // obtain src descriptors + try { + sourceDescriptors = new TreeMap<String, PropertyDescriptor>(); + + BeanInfo beanInfo = Introspector.getBeanInfo(model.getSourceType()); + for (PropertyDescriptor descriptor : + beanInfo.getPropertyDescriptors()) { + sourceDescriptors.put(descriptor.getName(), descriptor); + } + } catch (IntrospectionException e) { + throw new RuntimeException("Could not obtain bean properties " + + "descriptors for source type " + sourceType, e); + } + // obtain dst descriptors + try { + targetDescriptors = new TreeMap<String, PropertyDescriptor>(); + + BeanInfo beanInfo = Introspector.getBeanInfo(model.getTargetType()); + for (PropertyDescriptor descriptor : + beanInfo.getPropertyDescriptors()) { + targetDescriptors.put(descriptor.getName(), descriptor); + } + } catch (IntrospectionException e) { + throw new RuntimeException("Could not obtain bean properties " + + "descriptors for target type " + targetType, e); + } + + return this; + } + + /** + * Creates a new binder given using the {@link Binder} type of binder + * from the internal binder model + * previously created via the method {@code createBinderModel<XXX>} and + * then filled with methods {@code addXXX(XXX)}. + * <p/> + * <b>Note:</b> If no model is present, the method will fail. + * + * @return the instance of the new buinder. + * @throws IllegalStateException if no model was previously created. + * @throws NullPointerException if the parameter is {@code null} + */ + public Binder<?, ?> createBinder() + throws NullPointerException, IllegalStateException { + + Binder binder = createBinder(Binder.class); + return binder; + } + + /** + * Creates a new binder given his type from the internal binder model + * previously created via the method {@code createBinderModel<XXX>} and + * then filled with methods {@code addXXX(XXX)}. + * <p/> + * <b>Note:</b> If no model is present, the method will fail. + * + * @param binderType the type of binder to instanciate + * @param <B> the type of binder to instanciate + * @return the instance of the new buinder. + * @throws IllegalStateException if no model was previously created. + * @throws NullPointerException if the parameter is {@code null} + */ + public <B extends Binder<?, ?>> B createBinder(Class<B> binderType) + throws NullPointerException, IllegalStateException { + checkModelExists(); + if (binderType == null) { + throw new NullPointerException("binderType can not be null"); + } + try { + B binder = binderType.newInstance(); + binder.setModel(model); + return binder; + } catch (Exception e) { + throw new IllegalStateException("could not instanciate binder " + + binderType, e); + } finally { + // release resources of the model + model = null; + sourceDescriptors.clear(); + sourceDescriptors = null; + targetDescriptors.clear(); + targetDescriptors = null; + } + } + + /** + * Add to the binder model some simple properties (says source property name + * = target property name). + * <p/> + * <b>Note:</b> If no model is present, the method will fail. + * + * @param properties the name of mirrored property + * @return the instance of the builder + * @throws IllegalStateException if no model was previously created + * @throws NullPointerException if a property is {@code null} + */ + public BinderBuilder addSimpleProperties(String... properties) + throws IllegalStateException, NullPointerException { + checkModelExists(); + for (String property : properties) { + if (property == null) { + throw new NullPointerException("parameter 'properties' can " + + "not contains a null value"); + } + addProperty0(property, property); + } + return this; + } + + /** + * Add to the binder model some simple properties (says source property name + * = target property name). + * <p/> + * <b>Note:</b> If no model is present, the method will fail. + * + * @param sourceProperty the name of the source property to bind + * @param targetProperty the name of the target property to bind + * @return the instance of the builder + * @throws IllegalStateException if no model was previously created + * @throws NullPointerException if a parameter is {@code null} + */ + + public BinderBuilder addProperty(String sourceProperty, + String targetProperty) + throws IllegalStateException, NullPointerException { + if (sourceProperty == null) { + throw new NullPointerException("parameter 'sourceProperty' " + + "can not be null"); + } + if (targetProperty == null) { + throw new NullPointerException("parameter 'targetProperty' " + + "can not be null"); + } + checkModelExists(); + addProperty0(sourceProperty, targetProperty); + return this; + } + + /** + * Add to the binder model some properties. + * <p/> + * Parameter {@code sourceAndTargetProperties} must be a array of couple + * of {@code sourceProperty}, {@code targetProperty}. + * <p/> + * Example : + * <pre> + * builder.addProperties("name","name2","text","text"); + * </pre> + * <p/> + * <b>Note:</b> If no model is present, the method will fail. + * + * @param sourceAndTargetProperties the couple of (sourceProperty - + * targetProperty) to bind + * @return the instance of the builder + * @throws IllegalStateException if no model was previously created + * @throws IllegalArgumentException if there is not the same number of + * source and target properties + * @throws NullPointerException if a parameter is {@code null} + */ + public BinderBuilder addProperties(String... sourceAndTargetProperties) + throws IllegalStateException, IllegalArgumentException, + NullPointerException { + checkModelExists(); + if (sourceAndTargetProperties.length % 2 != 0) { + throw new IllegalArgumentException("must have couple(s) of " + + "(sourceProperty,targetProperty) but had " + + Arrays.toString(sourceAndTargetProperties)); + } + for (int i = 0, max = sourceAndTargetProperties.length / 2; + i < max; i++) { + String sourceProperty = sourceAndTargetProperties[2 * i]; + String targetProperty = sourceAndTargetProperties[2 * i + 1]; + if (sourceProperty == null) { + throw new NullPointerException("parameter " + + "'sourceAndTargetProperties' can not contains " + + "a null value"); + } + if (targetProperty == null) { + throw new NullPointerException("parameter " + + "'sourceAndTargetProperties' can not contains " + + "a null value"); + } + addProperty0(sourceProperty, targetProperty); + } + return this; + } + + + protected void addProperty0(String sourceProperty, + String targetProperty) { + // check srcProperty does not exist + if (model.containsSourceProperty(sourceProperty)) { + throw new IllegalArgumentException("source property '" + + sourceProperty + "' " + " was already registred."); + } + // check dstProperty does not exist + if (model.containsTargetProperty(targetProperty)) { + throw new IllegalArgumentException("destination property '" + + targetProperty + "' " + " was already registred."); + } + + // obtain source descriptor + PropertyDescriptor sourceDescriptor = + sourceDescriptors.get(sourceProperty); + if (sourceDescriptor == null) { + throw new IllegalArgumentException("no property '" + + sourceProperty + "' " + "found on type " + + model.getSourceType()); + } + // check srcProperty is readable + Method readMethod = sourceDescriptor.getReadMethod(); + if (readMethod == null) { + throw new IllegalArgumentException("property '" + sourceProperty + + "' " + "is not readable on type " + model.getSourceType()); + } + + // obtain dst descriptor + PropertyDescriptor targetDescriptor = + targetDescriptors.get(targetProperty); + if (targetDescriptor == null) { + throw new IllegalArgumentException("no property '" + + targetProperty + "' " + "found on type " + + model.getTargetType()); + } + // check dstProperty is writable + Method writeMethod = sourceDescriptor.getWriteMethod(); + if (writeMethod == null) { + throw new IllegalArgumentException("property '" + targetProperty + + "' " + "is not writable on type " + model.getTargetType()); + } + + // check types are ok + Class<?> sourceType = sourceDescriptor.getPropertyType(); + Class<?> targetType = targetDescriptor.getPropertyType(); + //TODO-TC20100221 : should check if primitive and boxed it in such case + if (sourceType != targetType) { + throw new IllegalArgumentException("source property '" + + sourceProperty + "' and target property '" + + targetProperty + "' are not compatible ( sourceType : " + + sourceType + " vs targetType :" + targetType + ')'); + } + + // safe to add the binding + model.addBinding(sourceDescriptor, targetDescriptor); + } + + protected void checkModelExists() throws IllegalStateException { + if (model == null) { + throw new IllegalStateException("there is not model, must " + + "create one with createBinderModel method"); + } + } + + protected BinderModel<?, ?> getModel() { + return model; + } +} \ No newline at end of file Property changes on: trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: trunk/src/main/java/org/nuiton/util/beans/BinderModel.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/BinderModel.java (rev 0) +++ trunk/src/main/java/org/nuiton/util/beans/BinderModel.java 2010-02-21 18:16:09 UTC (rev 1764) @@ -0,0 +1,231 @@ +/* + * *##% Nuiton utilities library + * Copyright (C) 2004 - 2010 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package org.nuiton.util.beans; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + + +/** + * Model of a {@link Binder}. + * + * @author tchemit < chemit@codelutin.com > + * @param <S> the source type + * @param <T> the target type + * @since 1.1.5 + */ +public class BinderModel<S, T> implements java.io.Serializable { + + /** + * source type + */ + protected final Class<S> sourceType; + /** + * destination type + */ + protected final Class<T> targetType; + + /** + * source type descriptors (key are property names) + */ + protected final Map<String, PropertyDescriptor> sourceDescriptors; + /** + * destination descriptors (key are property names) + */ + protected final Map<String, PropertyDescriptor> targetDescriptors; + /** + * properties mapping (key are source properties, value are destination + * properties) + */ + protected final Map<String, String> propertiesMapping; + + private static final long serialVersionUID = 1L; + + public BinderModel(Class<S> sourceType, Class<T> targetType) { + this.sourceType = sourceType; + this.targetType = targetType; + this.sourceDescriptors = new TreeMap<String, PropertyDescriptor>(); + this.targetDescriptors = new TreeMap<String, PropertyDescriptor>(); + this.propertiesMapping = new TreeMap<String, String>(); + } + + /** + * Gets the type of the binder's source. + * + * @return the type of the source object in the binder + */ + public Class<S> getSourceType() { + return sourceType; + } + + /** + * Gets the type of the binder's destination + * + * @return the type of the destination object in the binder + */ + public Class<T> getTargetType() { + return targetType; + } + + /** + * Gets all registred property names of the binder's source type. + * + * @return the array of all source object properties names to bind + */ + public String[] getSourceDescriptors() { + Set<String> universe = sourceDescriptors.keySet(); + return universe.toArray(new String[sourceDescriptors.size()]); + } + + /** + * Gets all registred property names of the binder's destination type. + * + * @return the array of all source object properties names to bind + */ + public String[] getTargetDescriptors() { + Set<String> universe = targetDescriptors.keySet(); + return universe.toArray(new String[targetDescriptors.size()]); + } + + /** + * Gets the destination property name given the + * + * @param sourceProperty the name of the source property to bind + * @return the name of the destination object property to bind, or + * {@code null} if {@code propertySrc} is unknown in the model + */ + public String getTargetProperty(String sourceProperty) { + if (!containsSourceProperty(sourceProperty)) { + return null; + } + String dstProperty = propertiesMapping.get(sourceProperty); + return dstProperty; + } + + /** + * Gets the bean descriptor of the source type for the given + * destination property. + * + * @param sourceProperty name of the source type property name + * @return the descriptor or {@code null} if not found. + */ + public PropertyDescriptor getSourceDescriptor(String sourceProperty) { + // check src property is registred + if (!containsSourceProperty(sourceProperty)) { + return null; + } + PropertyDescriptor descriptor = sourceDescriptors.get(sourceProperty); + return descriptor; + } + + /** + * @param srcProperty the name of a property of the source object. + * @return the method to read in a source object for the given property. + */ + public Method getSourceReadMethod(String srcProperty) { + PropertyDescriptor descriptor = getSourceDescriptor(srcProperty); + Method readMethod = null; + if (descriptor != null) { + readMethod = descriptor.getReadMethod(); + } + return readMethod; + } + + /** + * @param sourceProperty the name of a property of the source object. + * @return the method to write in a source object for the given property. + */ + public Method getSourceWriteMethod(String sourceProperty) { + PropertyDescriptor descriptor = getSourceDescriptor(sourceProperty); + Method writeMethod = null; + if (descriptor != null) { + writeMethod = descriptor.getWriteMethod(); + } + return writeMethod; + } + + /** + * Gets the bean descriptor of the destination type for the given + * destination property. + * + * @param targetProperty name of the destination type property name + * @return the descriptor or {@code null} if not found. + */ + public PropertyDescriptor getTargetDescriptor(String targetProperty) { + // check dst property is registred + if (!containsTargetProperty(targetProperty)) { + return null; + } + PropertyDescriptor descriptor = targetDescriptors.get(targetProperty); + return descriptor; + } + + /** + * @param targetProperty the name of a property of the destination object. + * @return the method to read in a destination object for the given + * property. + */ + public Method getTargetReadMethod(String targetProperty) { + PropertyDescriptor descriptor = getTargetDescriptor(targetProperty); + Method readMethod = null; + if (descriptor != null) { + readMethod = descriptor.getReadMethod(); + } + return readMethod; + } + + /** + * @param targetProperty the name of a property of the destination object. + * @return the method to write in a destination object for the given + * property. + */ + public Method getTargetWriteMethod(String targetProperty) { + PropertyDescriptor descriptor = getTargetDescriptor(targetProperty); + Method writeMethod = null; + if (descriptor != null) { + writeMethod = descriptor.getWriteMethod(); + } + return writeMethod; + } + + protected boolean containsSourceProperty(String sourceProperty) { + return propertiesMapping.containsKey(sourceProperty); + } + + protected boolean containsTargetProperty(String targetProperty) { + return propertiesMapping.containsValue(targetProperty); + } + + protected void addBinding(PropertyDescriptor sourceDescriptor, + PropertyDescriptor targetDescriptor) { + + String sourceProperty = sourceDescriptor.getName(); + String targetProperty = targetDescriptor.getName(); + sourceDescriptors.put(sourceProperty, sourceDescriptor); + targetDescriptors.put(targetProperty, targetDescriptor); + propertiesMapping.put(sourceProperty, targetProperty); + } + + protected Map<String, String> getPropertiesMapping() { + return propertiesMapping; + } +} \ No newline at end of file Property changes on: trunk/src/main/java/org/nuiton/util/beans/BinderModel.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java (rev 0) +++ trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java 2010-02-21 18:16:09 UTC (rev 1764) @@ -0,0 +1,320 @@ +/* + * *##% Nuiton utilities library + * Copyright (C) 2004 - 2010 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ + +package org.nuiton.util.beans; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.HashMap; +import java.util.Map; + +/** + * Manage a cache of {@link Binder} objects. + * <p/> + * You must first register some binders via the {@code registerBinder} api. + * <pre> + * Binder<User,UserDTO> mybinder = ...; + * registerBinder(myNewBinder); + * </pre> + * To use several binders of the the same types, you can moreover specify + * a context name of your binder : + * <pre> + * Binder<User,UserDTO> mybinder = ...; + * registerBinder(myBinder, "One"); + * </pre> + * <p/> + * Then you can obtained them back via the api + * <pre> + * Binder<User,UserDTO> mybinder = getBinder(User.class,UserDTO); + * </pre> + * <p/> + * or with a context name : + * <pre> + * Binder<User,UserDTO> mybinder = getBinder(User.class,UserDTO.class, "One"); + * </pre> + * + * @author tchemit < chemit@codelutin.com > + * @see Binder + * @see BinderBuilder + * @since 1.1.5 + */ +public class BinderProvider { + + /** + * Logger + */ + private static final Log log = LogFactory.getLog(BinderProvider.class); + /** + * Cache of registred binders indexed by their unique entry + */ + protected static Map<BinderEntry, Binder> binders; + + /** + * Gets the registred mirror binder (source type = target type) with no + * context name specified. + * + * @param sourceType the type of source and target + * @param <S> the type of source and target + * @return the registred binder or {@code null} if not found. + */ + public static <S> Binder<S, S> getBinder(Class<S> sourceType) { + return getBinder(sourceType, sourceType, null); + } + + /** + * Gets the registred mirror binder (source type = target type) with the + * given context name. + * + * @param sourceType the type of source and target + * @param name the context's name of the searched binder + * @param <S> the type of source and target + * @return the registred binder or {@code null} if not found. + */ + public static <S> Binder<S, S> getBinder(Class<S> sourceType, + String name) { + return getBinder(sourceType, sourceType, name); + } + + + /** + * Gets the registred binder given his types with no context name. + * + * @param sourceType the type of source + * @param targetType the type of target + * @param <S> the type of source + * @param <T> the type of target + * @return the registred binder or {@code null} if not found. + */ + public static <S, T> Binder<S, T> getBinder(Class<S> sourceType, + Class<T> targetType) { + return getBinder(sourceType, targetType, null); + } + + /** + * Gets the registred binder given his types and his context's name. + * + * @param sourceType the type of source + * @param targetType the type of target + * @param name the context's name of the searched binder + * @param <S> the type of source + * @param <T> the type of target + * @return the registred binder or {@code null} if not found. + */ + public static <S, T> Binder<S, T> getBinder(Class<S> sourceType, + Class<T> targetType, + String name) { + BinderEntry entry = new BinderEntry(sourceType, targetType, name); + if (log.isDebugEnabled()) { + log.debug("for entry " + entry); + } + Binder<?, ?> result = getBinders().get(entry); + if (result == null) { + // binder not found + if (log.isWarnEnabled()) { + log.warn("Could not find binder " + entry); + } + } + return (Binder<S, T>) result; + } + + /** + * Register a binder with no context name. + * <p/> + * <b>Note: </b> If a previous binder with same definition exists, it will + * be overriden by the new binder. + * + * @param binder the binder to register. + */ + public static void registerBinder(Binder<?, ?> binder) { + registerBinder(binder, null); + } + + /** + * Register a binder with no context's name from a {@link BinderBuilder}. + * <p/> + * <b>Note: </b> If a previous binder with same definition exists, it will + * be overriden by the new binder. + * + * @param builder the builder which contains builder model to use + * @see BinderBuilder#createBinder(Class) + */ + public static <B extends Binder> void registerBinder(BinderBuilder builder) { + registerBinder(builder, Binder.class); + } + + /** + * Register a binder with no context's name from a {@link BinderBuilder}. + * <p/> + * <b>Note: </b> If a previous binder with same definition exists, it will + * be overriden by the new binder. + * + * @param builder the builder which contains builder model to use + * @param binderType the type of binder to instanciate and register. + * @see BinderBuilder#createBinder(Class) + */ + public static <B extends Binder> void registerBinder(BinderBuilder builder, + Class<B> binderType) { + + registerBinder(builder, binderType, null); + } + + /** + * Register a binder with a context's name from a {@link BinderBuilder}. + * <p/> + * <b>Note: </b> If a previous binder with same definition exists, it will + * be overriden by the new binder. + * + * @param builder the builder which contains builder model to use + * @param name the context's name + * @see BinderBuilder#createBinder(Class) + */ + public static <B extends Binder> void registerBinder(BinderBuilder builder, + String name) { + + registerBinder(builder, Binder.class, name); + } + + /** + * Register a binder with a context's name from a {@link BinderBuilder}. + * <p/> + * <b>Note: </b> If a previous binder with same definition exists, it will + * be overriden by the new binder. + * + * @param builder the builder which contains builder model to use + * @param binderType the type of binder to instanciate and register. + * @param name the context's name + * @see BinderBuilder#createBinder(Class) + */ + public static <B extends Binder> void registerBinder(BinderBuilder builder, + Class<B> binderType, + String name) { + // instanciate the binder + B binder = builder.createBinder(binderType); + // register it + registerBinder(binder, name); + } + + /** + * Register a binder with a context name. + * <p/> + * <b>Note: </b> If a previous binder with same definition exists, it will + * be overriden by the new binder. + * + * @param binder the binder to register. + * @param name the context's name + */ + public static void registerBinder(Binder<?, ?> binder, String name) { + BinderModel<?, ?> model = binder.getModel(); + BinderEntry entry = new BinderEntry( + model.getSourceType(), + model.getTargetType(), + name + ); + if (log.isDebugEnabled()) { + log.debug("binder to seek : " + entry); + } + Binder oldBinder = getBinders().get(entry); + if (oldBinder != null) { + // already a binder for this entry + if (log.isWarnEnabled()) { + log.warn("Binder already registred for " + entry + " : " + + oldBinder); + log.warn("Will be replace by the new binder " + binder); + } + } + // register the binder + if (log.isDebugEnabled()) { + log.debug("entry : " + entry + " : " + binder); + } + getBinders().put(entry, binder); + } + + protected static Map<BinderEntry, Binder> getBinders() { + if (binders == null) { + binders = new HashMap<BinderEntry, Binder>(); + } + return binders; + } + + /** + * Definition of an binder entry (source and target types + context name). + * <p/> + * <b>Note :</b>When no context is specified, we always use a + * {@code null} context name. + */ + public static class BinderEntry { + + protected final Class<?> sourceType; + protected final Class<?> targetType; + protected final String name; + + + public BinderEntry(Class<?> sourceType, + Class<?> targetType, + String name) { + this.sourceType = sourceType; + this.targetType = targetType; + this.name = name; + } + + public Class<?> getSourceType() { + return sourceType; + } + + public Class<?> getTargetType() { + return targetType; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + BinderEntry that = (BinderEntry) o; + + return name == null ? that.name == null : name.equals(that.name) && + sourceType.equals(that.sourceType) && + targetType.equals(that.targetType); + } + + @Override + public int hashCode() { + int result = sourceType.hashCode(); + result = 31 * result + targetType.hashCode(); + result = 31 * result + (name != null ? name.hashCode() : 0); + return result; + } + + @Override + public String toString() { + StringBuilder buffer = new StringBuilder("<"); + buffer.append(super.toString()); + buffer.append(", sourceType: ").append(getSourceType()).append(','); + buffer.append(" targetType: ").append(getTargetType()).append(','); + buffer.append(" name: ").append(getName()).append('>'); + + return buffer.toString(); + } + } +} Property changes on: trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: trunk/src/main/java/org/nuiton/util/beans/package-info.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/package-info.java (rev 0) +++ trunk/src/main/java/org/nuiton/util/beans/package-info.java 2010-02-21 18:16:09 UTC (rev 1764) @@ -0,0 +1,6 @@ +/** + * Packages for all stuff of bean transformations (binder, and others...). + * + * @since 1.1.5 + */ +package org.nuiton.util.beans; Property changes on: trunk/src/main/java/org/nuiton/util/beans/package-info.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: trunk/src/test/java/org/nuiton/util/beans/BeanA.java =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BeanA.java (rev 0) +++ trunk/src/test/java/org/nuiton/util/beans/BeanA.java 2010-02-21 18:16:09 UTC (rev 1764) @@ -0,0 +1,43 @@ +package org.nuiton.util.beans; + +public class BeanA { + + public static final String PROPERTY_A = "a"; + public static final String PROPERTY_B = "b"; + public static final String PROPERTY_C = "c"; + public static final String PROPERTY_D = "d"; + + String a,b,c,d; + + public String getA() { + return a; + } + + public void setA(String a) { + this.a = a; + } + + public String getB() { + return b; + } + + public void setB(String b) { + this.b = b; + } + + public String getC() { + return c; + } + + public void setC(String c) { + this.c = c; + } + + public String getD() { + return d; + } + + public void setD(String d) { + this.d = d; + } +} \ No newline at end of file Property changes on: trunk/src/test/java/org/nuiton/util/beans/BeanA.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: trunk/src/test/java/org/nuiton/util/beans/BeanB.java =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BeanB.java (rev 0) +++ trunk/src/test/java/org/nuiton/util/beans/BeanB.java 2010-02-21 18:16:09 UTC (rev 1764) @@ -0,0 +1,43 @@ +package org.nuiton.util.beans; + +public class BeanB extends BeanA { + + public static final String PROPERTY_A2 = "a2"; + public static final String PROPERTY_B2 = "b2"; + public static final String PROPERTY_C2 = "c2"; + public static final String PROPERTY_D2 = "d2"; + + String a2, b2, c2, d2; + + public String getA2() { + return a2; + } + + public void setA2(String a2) { + this.a2 = a2; + } + + public String getB2() { + return b2; + } + + public void setB2(String b2) { + this.b2 = b2; + } + + public String getC2() { + return c2; + } + + public void setC2(String c2) { + this.c2 = c2; + } + + public String getD2() { + return d2; + } + + public void setD2(String d2) { + this.d2 = d2; + } +} \ No newline at end of file Property changes on: trunk/src/test/java/org/nuiton/util/beans/BeanB.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java (rev 0) +++ trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java 2010-02-21 18:16:09 UTC (rev 1764) @@ -0,0 +1,297 @@ +package org.nuiton.util.beans; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.beans.PropertyDescriptor; +import java.util.Map; + +public class BinderBuilderTest { + + private BinderBuilder builder; + protected static final String PROPERTY_CLASS = "class"; + + @Before + public void setUp() { + + builder = new BinderBuilder(); + } + + @Test(expected = NullPointerException.class) + public void testCreateMirroredBinderModel_NPE() throws Exception { + builder.createBinderModel(null); + } + + @Test + public void testCreateMirroredBinderModel() throws Exception { + builder.createBinderModel(BeanA.class); + Assert.assertNotNull(builder.getModel()); + Map<String, PropertyDescriptor> sourceDescriptors; + Map<String, PropertyDescriptor> targetDescriptors; + + sourceDescriptors = builder.sourceDescriptors; + Assert.assertNotNull(sourceDescriptors); + Assert.assertEquals(5, sourceDescriptors.size()); + Assert.assertTrue(sourceDescriptors.containsKey(PROPERTY_CLASS)); + Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_A)); + Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_B)); + Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_C)); + Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_D)); + + + targetDescriptors = builder.targetDescriptors; + Assert.assertNotNull(targetDescriptors); + Assert.assertEquals(5, targetDescriptors.size()); + Assert.assertTrue(targetDescriptors.containsKey(PROPERTY_CLASS)); + Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_A)); + Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_B)); + Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_C)); + Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_D)); + + Assert.assertEquals(BeanA.class, builder.getModel().getSourceType()); + Assert.assertEquals(BeanA.class, builder.getModel().getTargetType()); + } + + @Test(expected = IllegalStateException.class) + public void testCreateMirroredBinderModel_Twice() throws Exception { + builder.createBinderModel(BeanA.class); + Assert.assertNotNull(builder.getModel()); + Assert.assertEquals(BeanA.class, builder.getModel().getSourceType()); + Assert.assertEquals(BeanA.class, builder.getModel().getTargetType()); + builder.createBinderModel(BeanA.class); + } + + @Test(expected = NullPointerException.class) + public void testCreateBinderModel_NPE() throws Exception { + builder.createBinderModel(null, null); + } + + @Test(expected = NullPointerException.class) + public void testCreateBinderModel_NPE2() throws Exception { + builder.createBinderModel(BeanA.class, null); + } + + @Test(expected = NullPointerException.class) + public void testCreateBinderModel_NPE3() throws Exception { + builder.createBinderModel(null, BeanA.class); + } + + @Test + public void testCreateBinderModel() throws Exception { + builder.createBinderModel(BeanA.class, BeanB.class); + Assert.assertNotNull(builder.getModel()); + Map<String, PropertyDescriptor> sourceDescriptors; + Map<String, PropertyDescriptor> targetDescriptors; + + sourceDescriptors = builder.sourceDescriptors; + Assert.assertNotNull(sourceDescriptors); + Assert.assertEquals(5, sourceDescriptors.size()); + Assert.assertTrue(sourceDescriptors.containsKey(PROPERTY_CLASS)); + Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_A)); + Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_B)); + Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_C)); + Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_D)); + + targetDescriptors = builder.targetDescriptors; + Assert.assertNotNull(targetDescriptors); + Assert.assertEquals(9, targetDescriptors.size()); + Assert.assertTrue(targetDescriptors.containsKey(PROPERTY_CLASS)); + Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_A)); + Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_B)); + Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_C)); + Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_D)); + Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_A2)); + Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_B2)); + Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_C2)); + Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_D2)); + + Assert.assertEquals(BeanA.class, builder.getModel().getSourceType()); + Assert.assertEquals(BeanB.class, builder.getModel().getTargetType()); + + } + + @Test(expected = IllegalStateException.class) + public void testCreateBinderModel_Twice() throws Exception { + builder.createBinderModel(BeanA.class, BeanB.class); + Assert.assertNotNull(builder.getModel()); + Assert.assertEquals(BeanA.class, builder.getModel().getSourceType()); + Assert.assertEquals(BeanB.class, builder.getModel().getTargetType()); + builder.createBinderModel(BeanA.class, BeanB.class); + } + + @Test(expected = IllegalStateException.class) + public void testCreateBinder_NO_Model() throws Exception { + builder.createBinder(Binder.class); + } + + @Test(expected = NullPointerException.class) + public void testCreateBinder_NPE() throws Exception { + builder.createBinderModel(BeanA.class, BeanB.class); + builder.createBinder(null); + } + + @Test + public void testAddSimpleProperties() throws Exception { + + builder.createBinderModel(BeanA.class); + BinderModel<?, ?> model = builder.getModel(); + + try { + builder.addSimpleProperties((String) null); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + builder.addSimpleProperties(BeanA.PROPERTY_A); + Assert.assertEquals(1, model.getSourceDescriptors().length); + Assert.assertEquals(1, model.getTargetDescriptors().length); + Map<String, String> map = model.getPropertiesMapping(); + Assert.assertEquals(1, map.size()); + Assert.assertTrue(map.containsKey(BeanA.PROPERTY_A)); + Assert.assertTrue(map.containsValue(BeanA.PROPERTY_A)); + Assert.assertEquals(BeanA.PROPERTY_A, map.get(BeanA.PROPERTY_A)); + + try { + builder.addSimpleProperties(BeanA.PROPERTY_A); + Assert.fail(); + } catch (IllegalArgumentException e) { + Assert.assertTrue(true); + } + + try { + builder.addSimpleProperties(BeanB.PROPERTY_A2); + Assert.fail(); + } catch (IllegalArgumentException e) { + Assert.assertTrue(true); + } + + builder.addSimpleProperties(BeanA.PROPERTY_B); + Assert.assertEquals(2, model.getSourceDescriptors().length); + Assert.assertEquals(2, model.getTargetDescriptors().length); + Assert.assertEquals(2, map.size()); + Assert.assertTrue(map.containsKey(BeanA.PROPERTY_B)); + Assert.assertTrue(map.containsValue(BeanA.PROPERTY_B)); + Assert.assertEquals(BeanA.PROPERTY_B, map.get(BeanA.PROPERTY_B)); + + } + + @Test + public void testAddProperty() throws Exception { + builder.createBinderModel(BeanA.class, BeanB.class); + BinderModel<?, ?> model = builder.getModel(); + + try { + builder.addProperty(null, null); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + try { + builder.addProperty(BeanA.PROPERTY_A, null); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + try { + builder.addProperty(null, BeanA.PROPERTY_A); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + builder.addProperty(BeanA.PROPERTY_A, BeanA.PROPERTY_A); + Assert.assertEquals(1, model.getSourceDescriptors().length); + Assert.assertEquals(1, model.getTargetDescriptors().length); + Map<String, String> map = model.getPropertiesMapping(); + Assert.assertEquals(1, map.size()); + Assert.assertTrue(map.containsKey(BeanA.PROPERTY_A)); + Assert.assertTrue(map.containsValue(BeanA.PROPERTY_A)); + Assert.assertEquals(BeanA.PROPERTY_A, map.get(BeanA.PROPERTY_A)); + + try { + builder.addProperty(BeanB.PROPERTY_A, BeanB.PROPERTY_A2); + Assert.fail(); + } catch (IllegalArgumentException e) { + Assert.assertTrue(true); + } + + try { + builder.addProperty(BeanB.PROPERTY_A2, BeanB.PROPERTY_A); + Assert.fail(); + } catch (IllegalArgumentException e) { + Assert.assertTrue(true); + } + + builder.addProperty(BeanA.PROPERTY_B, BeanB.PROPERTY_B2); + Assert.assertEquals(2, model.getSourceDescriptors().length); + Assert.assertEquals(2, model.getTargetDescriptors().length); + Assert.assertEquals(2, map.size()); + Assert.assertTrue(map.containsKey(BeanA.PROPERTY_B)); + Assert.assertTrue(map.containsValue(BeanB.PROPERTY_B2)); + Assert.assertEquals(BeanB.PROPERTY_B2, map.get(BeanB.PROPERTY_B)); + } + + @Test + public void testAddProperties() throws Exception { + builder.createBinderModel(BeanA.class, BeanB.class); + + try { + builder.addProperties(BeanB.PROPERTY_A, BeanB.PROPERTY_A2, + BeanB.PROPERTY_B); + Assert.fail(); + } catch (IllegalArgumentException e) { + Assert.assertTrue(true); + } + + try { + builder.addProperties(BeanB.PROPERTY_A, null, + BeanB.PROPERTY_B, BeanB.PROPERTY_B); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + + builder.addProperties(BeanB.PROPERTY_A, BeanB.PROPERTY_A, + BeanB.PROPERTY_B, BeanB.PROPERTY_B2); + + BinderModel<?, ?> model = builder.getModel(); + Assert.assertEquals(2, model.getSourceDescriptors().length); + Assert.assertEquals(2, model.getTargetDescriptors().length); + Map<String, String> map = model.getPropertiesMapping(); + Assert.assertEquals(2, map.size()); + Assert.assertTrue(map.containsKey(BeanA.PROPERTY_A)); + Assert.assertTrue(map.containsValue(BeanA.PROPERTY_A)); + Assert.assertEquals(BeanA.PROPERTY_A, map.get(BeanA.PROPERTY_A)); + + Assert.assertTrue(map.containsKey(BeanA.PROPERTY_B)); + Assert.assertTrue(map.containsValue(BeanB.PROPERTY_B2)); + Assert.assertEquals(BeanB.PROPERTY_B2, map.get(BeanB.PROPERTY_B)); + } + + @Test + public void testCreateBinder() throws Exception { + builder.createBinderModel(BeanA.class, BeanB.class); + builder.addProperties(BeanB.PROPERTY_A, BeanB.PROPERTY_A, + BeanB.PROPERTY_B, BeanB.PROPERTY_B2); + + Binder<BeanA, BeanB> binder = + (Binder<BeanA, BeanB>) builder.createBinder(); + + Assert.assertNull(builder.getModel()); + Assert.assertNull(builder.sourceDescriptors); + Assert.assertNull(builder.targetDescriptors); + + BeanA a = new BeanA(); + BeanB b = new BeanB(); + + a.setA("a"); + a.setB("b"); + b.setA("a2"); + b.setB2("b2"); + + binder.copy(a, b); + Assert.assertEquals("a", b.getA()); + Assert.assertEquals("b", b.getB2()); + Assert.assertNull(b.getB()); + } +} \ No newline at end of file Property changes on: trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: trunk/src/test/java/org/nuiton/util/beans/BinderProviderTest.java =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BinderProviderTest.java (rev 0) +++ trunk/src/test/java/org/nuiton/util/beans/BinderProviderTest.java 2010-02-21 18:16:09 UTC (rev 1764) @@ -0,0 +1,166 @@ +package org.nuiton.util.beans; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class BinderProviderTest { + + Binder<BeanA, BeanA> binderA; + Binder<BeanA, BeanB> binderB; + private static final String MY_BINDER_NAME = "myBinder"; + private static final String MY_BINDER2_NAME = "myBinder2"; + + @Before + public void setUp() { + + BinderProvider.binders = null; + + BinderBuilder builder = new BinderBuilder(); + binderA = (Binder<BeanA, BeanA>) + builder.createBinderModel(BeanA.class). + addSimpleProperties(BeanA.PROPERTY_A). + createBinder(); + binderB = (Binder<BeanA, BeanB>) + builder.createBinderModel(BeanA.class, BeanB.class). + addSimpleProperties(BeanA.PROPERTY_A, BeanA.PROPERTY_B). + addProperty(BeanA.PROPERTY_C, BeanB.PROPERTY_C2). + createBinder(); + + } + + @Test + public void testRegisterBinder() throws Exception { + + Assert.assertNull(BinderProvider.binders); + + try { + BinderProvider.registerBinder((Binder) null); + Assert.fail(); + } catch (NullPointerException e) { + + Assert.assertTrue(true); + } + try { + BinderProvider.registerBinder((BinderBuilder) null); + Assert.fail(); + } catch (NullPointerException e) { + + Assert.assertTrue(true); + } + + BinderProvider.registerBinder(binderA); + + Assert.assertNotNull(BinderProvider.binders); + Assert.assertEquals(1, BinderProvider.getBinders().size()); + Assert.assertTrue(BinderProvider.getBinders().containsValue(binderA)); + + } + + @Test + public void testRegisterBinderWithName() throws Exception { + Assert.assertNull(BinderProvider.binders); + + try { + BinderProvider.registerBinder((Binder) null, null); + Assert.fail(); + } catch (NullPointerException e) { + + Assert.assertTrue(true); + } + + try { + BinderProvider.registerBinder((Binder) null, MY_BINDER_NAME); + Assert.fail(); + } catch (NullPointerException e) { + + Assert.assertTrue(true); + } + try { + BinderProvider.registerBinder((BinderBuilder) null, (String) null); + Assert.fail(); + } catch (NullPointerException e) { + + Assert.assertTrue(true); + } + try { + BinderProvider.registerBinder((BinderBuilder) null, MY_BINDER_NAME); + Assert.fail(); + } catch (NullPointerException e) { + + Assert.assertTrue(true); + } + + BinderProvider.registerBinder(binderA, MY_BINDER_NAME); + + Assert.assertNotNull(BinderProvider.binders); + Assert.assertEquals(1, BinderProvider.getBinders().size()); + Assert.assertTrue(BinderProvider.getBinders().containsValue(binderA)); + } + + @Test + public void testGetMirroredBinder() throws Exception { + BinderProvider.registerBinder(binderA); + Binder<BeanA, BeanA> aBeanABinder = BinderProvider.getBinder(BeanA.class); + Assert.assertNotNull(aBeanABinder); + Assert.assertEquals(binderA, aBeanABinder); + Binder<BeanB, BeanB> beanBBinder = BinderProvider.getBinder(BeanB.class); + Assert.assertNull(beanBBinder); + + + } + + @Test + public void testGetMirroredBinderWithName() throws Exception { + BinderProvider.registerBinder(binderA, MY_BINDER_NAME); + Binder<BeanA, BeanA> beanABinder; + Binder<BeanB, BeanB> beanBBinder; + + beanABinder = BinderProvider.getBinder(BeanA.class); + Assert.assertNull(beanABinder); + beanABinder = BinderProvider.getBinder(BeanA.class, MY_BINDER_NAME); + Assert.assertNotNull(beanABinder); + Assert.assertEquals(binderA, beanABinder); + beanBBinder = BinderProvider.getBinder(BeanB.class); + + Assert.assertNull(beanBBinder); + beanBBinder = BinderProvider.getBinder(BeanB.class, MY_BINDER_NAME); + + Assert.assertNull(beanBBinder); + } + + @Test + public void testGetBinder() throws Exception { + + BinderProvider.registerBinder(binderB); + Binder<BeanA, BeanA> beanABinder; + Binder<BeanA, BeanB> beanBBinder; + + beanABinder = BinderProvider.getBinder(BeanA.class); + Assert.assertNull(beanABinder); + + beanBBinder = BinderProvider.getBinder(BeanA.class, BeanB.class); + Assert.assertNotNull(beanBBinder); + Assert.assertEquals(binderB, beanBBinder); + + } + + @Test + public void testGetBinderWithName() throws Exception { + BinderProvider.registerBinder(binderB, MY_BINDER2_NAME); + Binder<BeanA, BeanA> beanABinder; + Binder<BeanA, BeanB> beanBBinder; + + beanABinder = BinderProvider.getBinder(BeanA.class); + Assert.assertNull(beanABinder); + + beanBBinder = BinderProvider.getBinder(BeanA.class, BeanB.class); + Assert.assertNull(beanBBinder); + + beanBBinder = BinderProvider.getBinder(BeanA.class, BeanB.class, MY_BINDER2_NAME); + Assert.assertNotNull(beanBBinder); + Assert.assertEquals(binderB, beanBBinder); + + + } +} \ No newline at end of file Property changes on: trunk/src/test/java/org/nuiton/util/beans/BinderProviderTest.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Added: trunk/src/test/java/org/nuiton/util/beans/BinderTest.java =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BinderTest.java (rev 0) +++ trunk/src/test/java/org/nuiton/util/beans/BinderTest.java 2010-02-21 18:16:09 UTC (rev 1764) @@ -0,0 +1,113 @@ +package org.nuiton.util.beans; + +import org.junit.*; + +import java.util.Map; + +public class BinderTest { + + BeanA a; + BeanB b; + + Binder<BeanA, BeanA> binderA; + Binder<BeanA, BeanB> binderB; + private static final String VALUE_A = "a"; + private static final String VALUE_B = "b"; + private static final String VALUE_C = "c"; + + @BeforeClass + public static void beforeClass() { + + BinderProvider.binders = null; + + BinderBuilder builder = new BinderBuilder(); + BinderProvider.registerBinder(builder. + createBinderModel(BeanA.class). + addSimpleProperties(BeanA.PROPERTY_A)); + + + BinderProvider.registerBinder(builder. + createBinderModel(BeanA.class, BeanB.class). + addSimpleProperties(BeanA.PROPERTY_A, BeanA.PROPERTY_B). + addProperty(BeanA.PROPERTY_C, BeanB.PROPERTY_C2)); + + } + + @AfterClass + public static void tearDown() { + + BinderProvider.binders = null; + + } + + @Before + public void setUp() { + + binderA = BinderProvider.getBinder(BeanA.class); + binderB = BinderProvider.getBinder(BeanA.class, BeanB.class); + + a = new BeanA(); + b = new BeanB(); + } + + @Test + public void testObtainProperties() throws Exception { + Map<String, Object> map; + map = binderA.obtainProperties(a); + Assert.assertEquals(0, map.size()); + + map = binderB.obtainProperties(a); + Assert.assertEquals(0, map.size()); + + a.setA(VALUE_A); + map = binderA.obtainProperties(a); + Assert.assertEquals(1, map.size()); + Assert.assertTrue(map.containsKey(BeanA.PROPERTY_A)); + Assert.assertTrue(map.containsValue(VALUE_A)); + Assert.assertEquals(VALUE_A, map.get(BeanA.PROPERTY_A)); + + map = binderB.obtainProperties(a); + Assert.assertEquals(1, map.size()); + Assert.assertTrue(map.containsKey(BeanA.PROPERTY_A)); + Assert.assertTrue(map.containsValue(VALUE_A)); + Assert.assertEquals(VALUE_A, map.get(BeanA.PROPERTY_A)); + + a.setB(VALUE_B); + map = binderA.obtainProperties(a); + Assert.assertEquals(1, map.size()); + Assert.assertTrue(map.containsKey(BeanA.PROPERTY_A)); + Assert.assertFalse(map.containsKey(BeanA.PROPERTY_B)); + Assert.assertTrue(map.containsValue(VALUE_A)); + Assert.assertFalse(map.containsValue(VALUE_B)); + Assert.assertEquals(VALUE_A, map.get(BeanA.PROPERTY_A)); + + map = binderB.obtainProperties(a); + Assert.assertEquals(2, map.size()); + Assert.assertTrue(map.containsKey(BeanA.PROPERTY_A)); + Assert.assertTrue(map.containsKey(BeanA.PROPERTY_B)); + Assert.assertTrue(map.containsValue(VALUE_A)); + Assert.assertTrue(map.containsValue(VALUE_B)); + Assert.assertEquals(VALUE_A, map.get(BeanA.PROPERTY_A)); + Assert.assertEquals(VALUE_B, map.get(BeanA.PROPERTY_B)); + } + + @Test + public void testCopy() throws Exception { + + a.setA(VALUE_A); + a.setB(VALUE_B); + a.setC(VALUE_C); + + binderA.copy(a, b); + Assert.assertEquals(VALUE_A, b.getA()); + Assert.assertNull(b.getB()); + Assert.assertNull(b.getB2()); + Assert.assertNull(b.getC()); + + binderB.copy(a, b); + Assert.assertEquals(VALUE_A, b.getA()); + Assert.assertEquals(VALUE_B, b.getB()); + Assert.assertNull(b.getC()); + Assert.assertEquals(VALUE_C, b.getC2()); + } +} \ No newline at end of file Property changes on: trunk/src/test/java/org/nuiton/util/beans/BinderTest.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL