r1990 - in trunk/src: main/java/org/nuiton/util/beans test/java/org/nuiton/util/beans
Author: tchemit Date: 2010-12-29 16:30:39 +0100 (Wed, 29 Dec 2010) New Revision: 1990 Url: http://nuiton.org/repositories/revision/nuiton-utils/1990 Log: Evolution #1179: Improve Binder api Removed: trunk/src/main/java/org/nuiton/util/beans/BinderModel.java Modified: 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/BinderFactory.java trunk/src/main/java/org/nuiton/util/beans/BinderModelBuilder.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/BinderBuilderTest.java trunk/src/test/java/org/nuiton/util/beans/BinderFactoryTest.java trunk/src/test/java/org/nuiton/util/beans/BinderModelBuilderTest.java trunk/src/test/java/org/nuiton/util/beans/BinderTest.java Modified: trunk/src/main/java/org/nuiton/util/beans/Binder.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/Binder.java 2010-12-28 16:52:49 UTC (rev 1989) +++ trunk/src/main/java/org/nuiton/util/beans/Binder.java 2010-12-29 15:30:39 UTC (rev 1990) @@ -29,6 +29,7 @@ import org.apache.commons.logging.LogFactory; import org.nuiton.util.ObjectUtil; +import java.beans.PropertyDescriptor; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -49,18 +50,24 @@ * 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,String...)} to transfert properties. + * Use the method {@link #copy(Object, Object, String...)} to transfert properties. * <p/> - * Use the method {@link #obtainProperties(Object,String...)} to obtain + * Use the method {@link #obtainProperties(Object, String...)} to obtain some + * properties from a given object. + * <p/> + * For more informations about how to obtain a binder, see the + * {@link BinderFactory} or the package info javadoc or unit tests... * - * @author tchemit <chemit@codelutin.com> * @param <I> the source bean type * @param <O> the destination bean type + * @author tchemit <chemit@codelutin.com> + * @see BinderFactory + * @see BinderModelBuilder * @since 1.1.5 */ public class Binder<I, O> implements Serializable { - /** Logger */ + /** Logger. */ private static final Log log = LogFactory.getLog(Binder.class); private static final long serialVersionUID = 1L; @@ -83,7 +90,7 @@ /** To duplicate the collection */ duplicate { - + @SuppressWarnings({"unchecked"}) @Override public Object copy(Object readValue) { if (readValue instanceof Set<?>) { @@ -243,10 +250,11 @@ * specifed, will use all the properties defined in * binder) * @throws NullPointerException if target parameter is {@code null} + * @throws RuntimeException if a property can not be copied to the target object */ protected void copy(I source, O target, boolean excludeProperties, String... propertyNames) - throws NullPointerException { + throws RuntimeException { if (target == null) { throw new NullPointerException("parameter 'target' can no be null"); } @@ -289,12 +297,13 @@ read = getCollectionValue(sourceProperty, read); } model.getTargetWriteMethod(targetProperty).invoke(target, read); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } catch (InstantiationException e) { - throw new RuntimeException(e); + } catch (Exception e) { + throw new RuntimeException( + "Could not bind property [" + + source.getClass().getName() + ":" + + sourceProperty + "] to [" + + target.getClass().getName() + ":" + + targetProperty + "]", e); } } } @@ -371,40 +380,300 @@ } protected Object bindProperty(String sourceProperty, Object read) throws IllegalAccessException, InstantiationException { - Binder<?,?> binder = model.getBinder(sourceProperty); + Binder<?, ?> binder = model.getBinder(sourceProperty); Object result = bind(binder, read); return result; } - + @SuppressWarnings({"unchecked"}) protected Object bindCollection(String sourceProperty, Object read) throws IllegalAccessException, InstantiationException { if (read == null) { return null; } - Binder<?,?> binder = model.getBinder(sourceProperty); + Binder<?, ?> binder = model.getBinder(sourceProperty); - Collection result = null; + Collection result; if (read instanceof Set<?>) { result = new HashSet(); - } - // in any other cases, let says this is a ArrayList - if (read instanceof Collection<?>) { + } else { + + // in any other cases, let says this is a ArrayList result = new ArrayList(); } - - for (Object o : (Collection<?>) read) { + Collection<?> collection = (Collection<?>) read; + for (Object o : collection) { Object r = bind(binder, o); result.add(r); } return result; } + @SuppressWarnings({"unchecked"}) protected Object bind(Binder binder, Object read) throws IllegalAccessException, InstantiationException { Object result = read.getClass().newInstance(); binder.copy(read, result); return result; } + + /** + * Model of a {@link Binder}. + * <p/> + * TODO tchemit 20100225 should have special cases for collections treatment. + * + * @param <S> the source type + * @param <T> the target type + * @author tchemit <chemit@codelutin.com> + * @since 1.1.5 + */ + public static class BinderModel<S, T> implements 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; + + /** mapping of collection properties strategies */ + protected Map<String, CollectionStrategy> collectionStrategies; + + /** mapping of extra binders to use to copy properties */ + protected Map<String, Binder<?, ?>> binders; + + private static final long serialVersionUID = 2L; + + public BinderModel(Class<S> sourceType, Class<T> targetType) { + this.sourceType = sourceType; + this.targetType = targetType; + sourceDescriptors = new TreeMap<String, PropertyDescriptor>(); + targetDescriptors = new TreeMap<String, PropertyDescriptor>(); + propertiesMapping = new TreeMap<String, String>(); + collectionStrategies = new TreeMap<String, CollectionStrategy>(); + binders = new TreeMap<String, Binder<?, ?>>(); + } + + /** + * 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()]); + } + + public CollectionStrategy getCollectionStrategy(String property) { + return collectionStrategies.get(property); + } + + /** + * 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; + } + + public Class<?> getCollectionType(String sourceProperty) { + Method method = getSourceReadMethod(sourceProperty); + Class<?> type = method.getReturnType(); + if (Collection.class.isAssignableFrom(type)) { + return type; + } + return null; + } + + public void addCollectionStrategy(String propertyName, + CollectionStrategy strategy) { + collectionStrategies.put(propertyName, strategy); + } + + public void addBinder(String propertyName, Binder<?, ?> binder) { + binders.put(propertyName, binder); + } + + protected boolean containsSourceProperty(String sourceProperty) { + return propertiesMapping.containsKey(sourceProperty); + } + + protected boolean containsTargetProperty(String targetProperty) { + return propertiesMapping.containsValue(targetProperty); + } + + protected boolean containsCollectionProperty(String propertyName) { + return collectionStrategies.containsKey(propertyName); + } + + protected boolean containsBinderProperty(String propertyName) { + return binders.containsKey(propertyName); + } + + 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 void removeBinding(String source) { + String target = propertiesMapping.get(source); + + sourceDescriptors.remove(source); + targetDescriptors.remove(target); + propertiesMapping.remove(source); + + if (containsBinderProperty(source)) { + binders.remove(source); + } + if (containsCollectionProperty(source)) { + collectionStrategies.remove(source); + } + } + + protected Map<String, String> getPropertiesMapping() { + return propertiesMapping; + } + + public Binder<?, ?> getBinder(String sourceProperty) { + return binders.get(sourceProperty); + } + } } Modified: trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java 2010-12-28 16:52:49 UTC (rev 1989) +++ trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java 2010-12-29 15:30:39 UTC (rev 1990) @@ -36,19 +36,21 @@ import java.util.TreeMap; /** - * A builder of {@link BinderModel} and {@link Binder}. + * A builder of {@link Binder.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.BinderModel * @see Binder * @since 1.1.5 + * @deprecated since 1.5.3, prefer use the {@link BinderModelBuilder} instead, will be removed in version 2.0 */ +@Deprecated public class BinderBuilder { /** current model used to build the binder */ - protected BinderModel<?, ?> model; + protected Binder.BinderModel<?, ?> model; /** source properties descriptors */ protected Map<String, PropertyDescriptor> sourceDescriptors; @@ -135,7 +137,7 @@ } // init model - model = new BinderModel(sourceType, targetType); + model = new Binder.BinderModel(sourceType, targetType); // obtain source descriptors sourceDescriptors = new TreeMap<String, PropertyDescriptor>(); @@ -425,7 +427,7 @@ } } - protected BinderModel<?, ?> getModel() { + protected Binder.BinderModel<?, ?> getModel() { return model; } Modified: trunk/src/main/java/org/nuiton/util/beans/BinderFactory.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/BinderFactory.java 2010-12-28 16:52:49 UTC (rev 1989) +++ trunk/src/main/java/org/nuiton/util/beans/BinderFactory.java 2010-12-29 15:30:39 UTC (rev 1990) @@ -11,6 +11,7 @@ /** * Factory of {@link Binder}. * <p/> + * <h1>Obtain a new binder</h1> * To obtain a new binder you can use the {@code newBinder(XXX)} methods. * <p/> * For example to obtain a mirrored binder (same source and target type) which @@ -18,7 +19,23 @@ * <pre> * Binder<BeanA, BeanA> binder = BinderFactory.newBinder(BeanA.class); * </pre> + * <h1>Usage of contextale binder</h1> + * It is possible to use different binder for same source and target type, using a + * extra context name parameter, like this : + * <pre> + * Binder<BeanA, BeanA> binder = BinderFactory.newBinder(BeanA.class, "mycontext"); + * </pre> * + * This is usefull when you register your own binder model in the factory (see + * next section) to bind different things from the same type of objects... + * + * <h1>Register a new binder model</h1> + * To register a new binder's model use one of the method {@code registerBinderModel(XXX)}. + * <p/> + * + * More documentation will come soon, yu can see the package info javadoc or + * unit tests... + * * @author tchemit <chemit@codelutin.com> * @since 1.5.3 */ @@ -106,41 +123,41 @@ return binder; } - public static <S, T> BinderModel<S, T> registerBinderModel(BinderModelBuilder<S, T> binderModelBuilder) throws IllegalArgumentException { - BinderModel<S, T> model = registerBinderModel(binderModelBuilder, null); + public static <S, T> Binder.BinderModel<S, T> registerBinderModel(BinderModelBuilder<S, T> binderModelBuilder) throws IllegalArgumentException { + Binder.BinderModel<S, T> model = registerBinderModel(binderModelBuilder, null); return model; } - public static <S, T> BinderModel<S, T> registerBinderModel(Binder<S, T> binder) throws IllegalArgumentException { - BinderModel<S, T> model = registerBinderModel(binder, null); + public static <S, T> Binder.BinderModel<S, T> registerBinderModel(Binder<S, T> binder) throws IllegalArgumentException { + Binder.BinderModel<S, T> model = registerBinderModel(binder, null); return model; } - public static <S, T> BinderModel<S, T> registerBinderModel(BinderModel<S, T> model) throws IllegalArgumentException { + public static <S, T> Binder.BinderModel<S, T> registerBinderModel(Binder.BinderModel<S, T> model) throws IllegalArgumentException { registerBinderModel(model, null); return model; } - public static <S, T> BinderModel<S, T> registerBinderModel(BinderModelBuilder<S, T> binderModelBuilder, - String contextName) throws IllegalArgumentException { - BinderModel<S, T> model = binderModelBuilder.getModel(); + public static <S, T> Binder.BinderModel<S, T> registerBinderModel(BinderModelBuilder<S, T> binderModelBuilder, + String contextName) throws IllegalArgumentException { + Binder.BinderModel<S, T> model = binderModelBuilder.getModel(); registerBinderModel(model, contextName); return model; } - public static <S, T> BinderModel<S, T> registerBinderModel(Binder<S, T> binder, - String contextName) throws IllegalArgumentException { - BinderModel<S, T> model = binder.getModel(); + public static <S, T> Binder.BinderModel<S, T> registerBinderModel(Binder<S, T> binder, + String contextName) throws IllegalArgumentException { + Binder.BinderModel<S, T> model = binder.getModel(); registerBinderModel(model, contextName); return model; } - public static <S, T> BinderModel<S, T> registerBinderModel(BinderModel<S, T> model, - String contextName) throws IllegalArgumentException { + public static <S, T> Binder.BinderModel<S, T> registerBinderModel(Binder.BinderModel<S, T> model, + String contextName) throws IllegalArgumentException { // check if the given model is not already registred for the given context - BinderModel<S, T> registredModel = + Binder.BinderModel<S, T> registredModel = getBinderModels().get(model, contextName); // let's add this model into cache of models @@ -181,7 +198,7 @@ return binderModels; } - protected static String toString(BinderModel<?, ?> model, String contextName) { + protected static String toString(Binder.BinderModel<?, ?> model, String contextName) { return toString(model.getSourceType(), model.getTargetType(), contextName); } @@ -206,7 +223,7 @@ Class<B> binderType) { // obtain the cached model - BinderModel<S, T> model = + Binder.BinderModel<S, T> model = getBinderModels().get(sourceType, targetType, contextName); if (model == null) { @@ -237,18 +254,18 @@ return binder; } - public static class BindelModelEntryMap implements Map<BinderModelEntry, BinderModel<?, ?>> { + public static class BindelModelEntryMap implements Map<BinderModelEntry, Binder.BinderModel<?, ?>> { - protected Map<BinderModelEntry, BinderModel<?, ?>> delegate; + protected Map<BinderModelEntry, Binder.BinderModel<?, ?>> delegate; public BindelModelEntryMap() { - delegate = new HashMap<BinderModelEntry, BinderModel<?, ?>>(); + delegate = new HashMap<BinderModelEntry, Binder.BinderModel<?, ?>>(); } - public <S, T> BinderModel<S, T> get(Class<S> source, - Class<T> target, - String contextName) { - BinderModel<S, T> result = null; + public <S, T> Binder.BinderModel<S, T> get(Class<S> source, + Class<T> target, + String contextName) { + Binder.BinderModel<S, T> result = null; for (BinderModelEntry key : binderModels.keySet()) { if (!key.getSourceType().equals(source)) { @@ -268,18 +285,18 @@ } } - result = (BinderModel<S, T>) binderModels.get(key); + result = (Binder.BinderModel<S, T>) binderModels.get(key); break; } return result; } - public <S, T> BinderModel<S, T> get(BinderModel<S, T> model, - String contextName) { + public <S, T> Binder.BinderModel<S, T> get(Binder.BinderModel<S, T> model, + String contextName) { Class<S> source = model.getSourceType(); Class<T> target = model.getTargetType(); - BinderModel<S, T> result = get(source, target, contextName); + Binder.BinderModel<S, T> result = get(source, target, contextName); return result; } @@ -304,20 +321,20 @@ } @Override - public BinderModel<?, ?> get(Object key) { + public Binder.BinderModel<?, ?> get(Object key) { return delegate.get(key); } - public BinderModel<?, ?> put(BinderModelEntry key, BinderModel<?, ?> value) { + public Binder.BinderModel<?, ?> put(BinderModelEntry key, Binder.BinderModel<?, ?> value) { return delegate.put(key, value); } @Override - public BinderModel<?, ?> remove(Object key) { + public Binder.BinderModel<?, ?> remove(Object key) { return delegate.remove(key); } - public void putAll(Map<? extends BinderModelEntry, ? extends BinderModel<?, ?>> m) { + public void putAll(Map<? extends BinderModelEntry, ? extends Binder.BinderModel<?, ?>> m) { delegate.putAll(m); } @@ -332,12 +349,12 @@ } @Override - public Collection<BinderModel<?, ?>> values() { + public Collection<Binder.BinderModel<?, ?>> values() { return delegate.values(); } @Override - public Set<Entry<BinderModelEntry, BinderModel<?, ?>>> entrySet() { + public Set<Entry<BinderModelEntry, Binder.BinderModel<?, ?>>> entrySet() { return delegate.entrySet(); } @@ -365,7 +382,7 @@ this.name = name; } - public BinderModelEntry(BinderModel<?, ?> model, String contextName) { + public BinderModelEntry(Binder.BinderModel<?, ?> model, String contextName) { this(model.getSourceType(), model.getTargetType(), contextName); } Deleted: trunk/src/main/java/org/nuiton/util/beans/BinderModel.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/BinderModel.java 2010-12-28 16:52:49 UTC (rev 1989) +++ trunk/src/main/java/org/nuiton/util/beans/BinderModel.java 2010-12-29 15:30:39 UTC (rev 1990) @@ -1,294 +0,0 @@ -/* - * #%L - * Nuiton Utils - * - * $Id$ - * $HeadURL$ - * %% - * 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>. - * #L% - */ - -package org.nuiton.util.beans; - -import java.beans.PropertyDescriptor; -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - - -/** - * Model of a {@link Binder}. - * <p/> - * TODO-TC20100225 should have special cases for collections treatment. - * - * @param <S> the source type - * @param <T> the target type - * @author tchemit <chemit@codelutin.com> - * @since 1.1.5 - */ -public class BinderModel<S, T> implements 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; - - /** mapping of collection properties strategies */ - protected Map<String, Binder.CollectionStrategy> collectionStrategies; - - /** mapping of extra binders to use to copy properties */ - protected Map<String, Binder<?, ?>> binders; - - private static final long serialVersionUID = 2L; - - public BinderModel(Class<S> sourceType, Class<T> targetType) { - this.sourceType = sourceType; - this.targetType = targetType; - sourceDescriptors = new TreeMap<String, PropertyDescriptor>(); - targetDescriptors = new TreeMap<String, PropertyDescriptor>(); - propertiesMapping = new TreeMap<String, String>(); - collectionStrategies = new TreeMap<String, Binder.CollectionStrategy>(); - binders = new TreeMap<String, Binder<?, ?>>(); - } - - /** - * 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()]); - } - - public Binder.CollectionStrategy getCollectionStrategy(String property) { - return collectionStrategies.get(property); - } - - /** - * 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; - } - - public Class<?> getCollectionType(String sourceProperty) { - Method method = getSourceReadMethod(sourceProperty); - Class<?> type = method.getReturnType(); - if (Collection.class.isAssignableFrom(type)) { - return type; - } - return null; - } - - public void addCollectionStrategy(String propertyName, - Binder.CollectionStrategy strategy) { - collectionStrategies.put(propertyName, strategy); - } - - public void addBinder(String propertyName, Binder<?, ?> binder) { - binders.put(propertyName, binder); - } - - protected boolean containsSourceProperty(String sourceProperty) { - return propertiesMapping.containsKey(sourceProperty); - } - - protected boolean containsTargetProperty(String targetProperty) { - return propertiesMapping.containsValue(targetProperty); - } - - protected boolean containsCollectionProperty(String propertyName) { - return collectionStrategies.containsKey(propertyName); - } - - protected boolean containsBinderProperty(String propertyName) { - return binders.containsKey(propertyName); - } - - 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 void removeBinding(String source) { - String target = propertiesMapping.get(source); - - sourceDescriptors.remove(source); - targetDescriptors.remove(target); - propertiesMapping.remove(source); - - if (containsBinderProperty(source)) { - binders.remove(source); - } - if (containsCollectionProperty(source)) { - collectionStrategies.remove(source); - } - } - - protected Map<String, String> getPropertiesMapping() { - return propertiesMapping; - } - - public Binder<?, ?> getBinder(String sourceProperty) { - return binders.get(sourceProperty); - } -} Modified: trunk/src/main/java/org/nuiton/util/beans/BinderModelBuilder.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/BinderModelBuilder.java 2010-12-28 16:52:49 UTC (rev 1989) +++ trunk/src/main/java/org/nuiton/util/beans/BinderModelBuilder.java 2010-12-29 15:30:39 UTC (rev 1990) @@ -38,7 +38,7 @@ import java.util.TreeMap; /** - * Class to create a new {@link BinderModel}. + * Class to create a new {@link Binder.BinderModel}. * <p/> * <p/> * A such object is designed to build only one model of binder and can not be @@ -99,14 +99,14 @@ * </pre> * * @author tchemit <chemit@codelutin.com> - * @see BinderModel + * @see Binder.BinderModel * @see Binder * @since 1.5.3 */ public class BinderModelBuilder<S, T> { /** current model used to build the binder */ - protected BinderModel<S, T> model; + protected Binder.BinderModel<S, T> model; /** source properties descriptors */ protected Map<String, PropertyDescriptor> sourceDescriptors; @@ -371,7 +371,7 @@ } // init model - model = new BinderModel<S, T>(sourceType, targetType); + model = new Binder.BinderModel<S, T>(sourceType, targetType); // obtain source descriptors sourceDescriptors = new TreeMap<String, PropertyDescriptor>(); @@ -447,7 +447,7 @@ } - protected BinderModel<S, T> getModel() { + protected Binder.BinderModel<S, T> getModel() { return model; } Modified: trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java 2010-12-28 16:52:49 UTC (rev 1989) +++ trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java 2010-12-29 15:30:39 UTC (rev 1990) @@ -225,7 +225,7 @@ * @param name the context's name */ public static void registerBinder(Binder<?, ?> binder, String name) { - BinderModel<?, ?> model = binder.getModel(); + Binder.BinderModel<?, ?> model = binder.getModel(); BinderEntry entry = new BinderEntry( model.getSourceType(), model.getTargetType(), Modified: trunk/src/main/java/org/nuiton/util/beans/package-info.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/package-info.java 2010-12-28 16:52:49 UTC (rev 1989) +++ trunk/src/main/java/org/nuiton/util/beans/package-info.java 2010-12-29 15:30:39 UTC (rev 1990) @@ -25,6 +25,76 @@ /** * Packages for all stuff of bean transformations (binder, and others...). * + * This package contains two api : + * <ul> + * <li> the Binder api to copy objects</li> + * <li> Some javabeans compiliant api</li> + * </ul> + * + * <h1>The <b>Binder</b> api</h1> + * <p> + * This api permits to some object properties from an object to another one. + * </p> + * <h2>Obtain a binder</h2> + * A {@link Binder} contains a safe model named {@link Binder.BinderModel} which knows + * all properties that can be copied. + * <br/> + * To use this api, you have only to get a {@link Binder} object from the + * {@link BinderFactory} like this : + * <pre> + * Binder<A, A> binder = BinderFactory.newBinder(A.class); + * </pre> + * + * It is also possible to build a more sofisticated binder which will only copy + * some properties, using the {@link BinderModelBuilder}. + * + * <h2>Use a binder</h2> + * Once you have a binder, you use the {@link Binder} api : + * <p/> + * To copy all properties from an object to another one : + * <pre> + * binder.copy(source, target); + * </pre> + * + * To copy just some properties from an object to another one : + * <pre> + * binder.copy(source, target, "propertyOne", "propertyTwo"); + * </pre> + * + * To copy all properties except some : + * <pre> + * binder.copyExcluding(source, target, "propertyToExeclude"); + * </pre> + * + * To obtain some properties from an object, use the following code : + * <pre> + * Map<String, Object> properties = binder.obtainProperties(source, "propertyOne", "propertyTwo"); + * </pre> + * + * <h2>Building a new BinderModel</h2> + * <p> + * In two words, you have to use the {@link BinderModelBuilder} object to do this. + * then register your binder model into the {@link BinderFactory} using + * one of the method {@code BinderFactory#registerBinderModel(XXX)}. + * </p> + * More explainations will come soon... + * <br/> + * You can go and look on the unit tests which describe it pretty well :) : + * <pre> + * org.nuiton.util.beans.BinderModelBuilderTest + * </pre> + * + * <h1> JavaBeans api</h1> + * + * <h2>{@link BeanMonitor} class</h2> + * This object permits to listen javaBeans and keep modifications made on a bean. + * + * More exalanations will come soon, meanwhile you can see the test class : + * <pre> + * org.nuiton.util.beans.BeanMonitorTest + * </pre> + * + * * @since 1.1.5 */ package org.nuiton.util.beans; Modified: trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java 2010-12-28 16:52:49 UTC (rev 1989) +++ trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java 2010-12-29 15:30:39 UTC (rev 1990) @@ -182,7 +182,7 @@ public void testAddSimpleProperties() throws Exception { builder.createBinderModel(BeanA.class); - BinderModel<?, ?> model = builder.getModel(); + Binder.BinderModel<?, ?> model = builder.getModel(); try { builder.addSimpleProperties((String) null); @@ -226,7 +226,7 @@ @Test public void testAddProperty() throws Exception { builder.createBinderModel(BeanA.class, BeanB.class); - BinderModel<?, ?> model = builder.getModel(); + Binder.BinderModel<?, ?> model = builder.getModel(); try { builder.addProperty(null, null); @@ -301,7 +301,7 @@ builder.addProperties(BeanB.PROPERTY_A, BeanB.PROPERTY_A, BeanB.PROPERTY_B, BeanB.PROPERTY_B2); - BinderModel<?, ?> model = builder.getModel(); + Binder.BinderModel<?, ?> model = builder.getModel(); Assert.assertEquals(2, model.getSourceDescriptors().length); Assert.assertEquals(2, model.getTargetDescriptors().length); Map<String, String> map = model.getPropertiesMapping(); Modified: trunk/src/test/java/org/nuiton/util/beans/BinderFactoryTest.java =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BinderFactoryTest.java 2010-12-28 16:52:49 UTC (rev 1989) +++ trunk/src/test/java/org/nuiton/util/beans/BinderFactoryTest.java 2010-12-29 15:30:39 UTC (rev 1990) @@ -66,7 +66,7 @@ Assert.assertNull(BinderFactory.binderModels); - BinderModel<BeanA, BeanA> model = + Binder.BinderModel<BeanA, BeanA> model = BinderFactory.registerBinderModel(BinderModelBuilder.newDefaultBuilder(BeanA.class)); Assert.assertNotNull(BinderFactory.binderModels); @@ -74,7 +74,7 @@ Assert.assertEquals(model, BinderFactory.newBinder(BeanA.class).getModel()); - BinderModel<BeanA, BeanA> model1 = + Binder.BinderModel<BeanA, BeanA> model1 = BinderFactory.registerBinderModel(BinderModelBuilder.newDefaultBuilder(BeanA.class)); Assert.assertNotNull(BinderFactory.binderModels); Modified: trunk/src/test/java/org/nuiton/util/beans/BinderModelBuilderTest.java =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BinderModelBuilderTest.java 2010-12-28 16:52:49 UTC (rev 1989) +++ trunk/src/test/java/org/nuiton/util/beans/BinderModelBuilderTest.java 2010-12-29 15:30:39 UTC (rev 1990) @@ -393,7 +393,7 @@ builderAA = BinderModelBuilder.newEmptyBuilder(BeanA.class); - BinderModel<BeanA, BeanA> model = builderAA.getModel(); + Binder.BinderModel<BeanA, BeanA> model = builderAA.getModel(); // limit case try { @@ -437,7 +437,7 @@ builderAB = BinderModelBuilder.newEmptyBuilder(BeanA.class, BeanB.class); - BinderModel<BeanA, BeanB> model = builderAB.getModel(); + Binder.BinderModel<BeanA, BeanB> model = builderAB.getModel(); // limit cases @@ -512,7 +512,7 @@ builderAB.addProperties(BeanB.PROPERTY_A, BeanB.PROPERTY_A, BeanB.PROPERTY_B, BeanB.PROPERTY_B2); - BinderModel<?, ?> model = builderAB.getModel(); + Binder.BinderModel<?, ?> model = builderAB.getModel(); Assert.assertEquals(2, model.getSourceDescriptors().length); Assert.assertEquals(2, model.getTargetDescriptors().length); Modified: trunk/src/test/java/org/nuiton/util/beans/BinderTest.java =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BinderTest.java 2010-12-28 16:52:49 UTC (rev 1989) +++ trunk/src/test/java/org/nuiton/util/beans/BinderTest.java 2010-12-29 15:30:39 UTC (rev 1990) @@ -25,55 +25,77 @@ package org.nuiton.util.beans; -import org.junit.*; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; 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"; + private static final int VALUE_E = 10; @BeforeClass public static void beforeClass() { - BinderProvider.binders = null; + // remove all previous models from the factory + BinderFactory.clear(); - BinderBuilder builder = new BinderBuilder(); - BinderProvider.registerBinder(builder. - createBinderModel(BeanA.class). - addSimpleProperties(BeanA.PROPERTY_A)); + // creates a mirrored binder model from A -> A with only one property + BinderModelBuilder<BeanA, BeanA> builder = + BinderModelBuilder.newEmptyBuilder(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). - addProperty(BeanA.PROPERTY_E, BeanB.PROPERTY_E2) - ); + // register the model into factory + BinderFactory.registerBinderModel(builder); + // creates a binder model from A -> B with more properties + + BinderModelBuilder<BeanA, BeanB> builder1 = + BinderModelBuilder.newEmptyBuilder(BeanA.class, BeanB.class). + addSimpleProperties(BeanA.PROPERTY_A, BeanA.PROPERTY_B). + addProperty(BeanA.PROPERTY_C, BeanB.PROPERTY_C2). + addProperty(BeanA.PROPERTY_E, BeanB.PROPERTY_E2); + + // register the model into factory + BinderFactory.registerBinderModel(builder1); + } @AfterClass public static void tearDown() { - BinderProvider.binders = null; + // remove all models from the factory + BinderFactory.clear(); } @Before public void setUp() { - binderA = BinderProvider.getBinder(BeanA.class); - binderB = BinderProvider.getBinder(BeanA.class, BeanB.class); + // get the binder A -> A + binderA = BinderFactory.newBinder(BeanA.class); + // get the binder A -> B + binderB = BinderFactory.newBinder(BeanA.class, BeanB.class); + a = new BeanA(); b = new BeanB(); } @@ -132,7 +154,7 @@ Assert.assertNull(b.getB()); Assert.assertNull(b.getB2()); Assert.assertNull(b.getC()); - Assert.assertEquals(0,b.getE2()); + Assert.assertEquals(0, b.getE2()); binderB.copy(a, b); Assert.assertEquals(VALUE_A, b.getA()); @@ -145,11 +167,28 @@ Assert.assertNull(b.getA()); Assert.assertNull(b.getB()); Assert.assertNull(b.getC2()); - Assert.assertEquals(0,b.getE2()); + Assert.assertEquals(0, b.getE2()); } - + @Test + public void testCopyIncluding() throws Exception { + + a.setA(VALUE_A); + a.setB(VALUE_B); + a.setC(VALUE_C); + a.setE(VALUE_E); + + // copy only the property A + binderA.copy(a, b, BeanA.PROPERTY_A); + Assert.assertEquals(VALUE_A, b.getA()); + Assert.assertNull(b.getB()); + Assert.assertNull(b.getB2()); + Assert.assertNull(b.getC()); + Assert.assertEquals(0, b.getE2()); + } + + @Test public void testCopyExcluding() throws Exception { a.setA(VALUE_A);
participants (1)
-
tchemit@users.nuiton.org