r1989 - in trunk/src: main/java/org/nuiton/util/beans test/java/org/nuiton/util/beans
Author: tchemit Date: 2010-12-28 17:52:49 +0100 (Tue, 28 Dec 2010) New Revision: 1989 Url: http://nuiton.org/repositories/revision/nuiton-utils/1989 Log: Improve binder api (need more docs) Added: trunk/src/main/java/org/nuiton/util/beans/BinderFactory.java trunk/src/main/java/org/nuiton/util/beans/BinderModelBuilder.java trunk/src/test/java/org/nuiton/util/beans/BinderFactoryTest.java trunk/src/test/java/org/nuiton/util/beans/BinderModelBuilderTest.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/BinderModel.java trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java 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 Modified: trunk/src/main/java/org/nuiton/util/beans/Binder.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/Binder.java 2010-12-27 15:58:28 UTC (rev 1988) +++ trunk/src/main/java/org/nuiton/util/beans/Binder.java 2010-12-28 16:52:49 UTC (rev 1989) @@ -313,8 +313,8 @@ * * @param model the model of the binder */ - protected void setModel(BinderModel<?, ?> model) { - this.model = (BinderModel<I, O>) model; + protected void setModel(BinderModel<I, O> model) { + this.model = model; } /** @@ -371,7 +371,7 @@ } 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; } @@ -383,7 +383,7 @@ return null; } - Binder binder = model.getBinder(sourceProperty); + Binder<?,?> binder = model.getBinder(sourceProperty); Collection result = null; Modified: trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java 2010-12-27 15:58:28 UTC (rev 1988) +++ trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java 2010-12-28 16:52:49 UTC (rev 1989) @@ -187,9 +187,9 @@ throw new NullPointerException("binderType can not be null"); } try { - B binder = binderType.newInstance(); + Binder binder = binderType.newInstance(); binder.setModel(model); - return binder; + return (B)binder; } catch (Exception e) { throw new IllegalStateException( "could not instanciate binder " + binderType, e); Added: trunk/src/main/java/org/nuiton/util/beans/BinderFactory.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/BinderFactory.java (rev 0) +++ trunk/src/main/java/org/nuiton/util/beans/BinderFactory.java 2010-12-28 16:52:49 UTC (rev 1989) @@ -0,0 +1,419 @@ +package org.nuiton.util.beans; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Factory of {@link Binder}. + * <p/> + * 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 + * will be able to copy all accepting properties, use this code : + * <pre> + * Binder<BeanA, BeanA> binder = BinderFactory.newBinder(BeanA.class); + * </pre> + * + * @author tchemit <chemit@codelutin.com> + * @since 1.5.3 + */ +public class BinderFactory { + + /** Logger. */ + private static final Log log = LogFactory.getLog(BinderFactory.class); + + /** Cache of registred binders indexed by their unique entry */ + protected static BindelModelEntryMap binderModels; + + /** + * 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> newBinder(Class<S> sourceType) { + return newBinder0(sourceType, sourceType, null, Binder.class); + } + + /** + * Gets the registred mirror binder (source type = target type) with the + * given context name. + * + * @param sourceType the type of source and target + * @param contextName 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> newBinder(Class<S> sourceType, + String contextName) { + return newBinder0(sourceType, sourceType, contextName, Binder.class); + } + + /** + * 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> newBinder(Class<S> sourceType, + Class<T> targetType) { + return newBinder0(sourceType, targetType, null, Binder.class); + } + + + /** + * Gets the registred binder given his types with no context name. + * + * @param sourceType the type of source + * @param targetType the type of target + * @param contextName 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> newBinder(Class<S> sourceType, + Class<T> targetType, + String contextName) { + return newBinder0(sourceType, targetType, contextName, Binder.class); + } + + /** + * 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 contextName the context's name of the searched binder + * @param binderType type of binder required + * @param <S> the type of source + * @param <T> the type of target + * @return the new instanciated binder. + */ + public static <S, T, B extends Binder<S, T>> B newBinder(Class<S> sourceType, + Class<T> targetType, + String contextName, + Class<B> binderType) { + B binder = (B) newBinder0(sourceType, targetType, contextName, binderType); + return binder; + } + + public static <S, T> BinderModel<S, T> registerBinderModel(BinderModelBuilder<S, T> binderModelBuilder) throws IllegalArgumentException { + 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); + return model; + } + + public static <S, T> BinderModel<S, T> registerBinderModel(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(); + 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(); + registerBinderModel(model, contextName); + return model; + } + + public static <S, T> BinderModel<S, T> registerBinderModel(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 = + getBinderModels().get(model, contextName); + + // let's add this model into cache of models + BinderModelEntry key = new BinderModelEntry(model, contextName); + + if (registredModel != null) { + + // this model is already registred, remove it from cache + if (log.isWarnEnabled()) { + log.warn("Remove existing binder model from cache : " + + toString(registredModel, contextName)); + } + } + + // add new model into cache + getBinderModels().put(key, model); + return model; + } + + /** + * Clear the cache of registred binder models. + * <p/> + * <b>Note :<b> This is a convienient method for test purposes and should + * be used in a normal usage of this provider. + */ + public static void clear() { + if (binderModels != null) { + binderModels.clear(); + binderModels = null; + } + } + + + protected static BindelModelEntryMap getBinderModels() { + if (binderModels == null) { + binderModels = new BindelModelEntryMap(); + } + return binderModels; + } + + protected static String toString(BinderModel<?, ?> model, String contextName) { + return toString(model.getSourceType(), model.getTargetType(), contextName); + } + + protected static String toString(Class<?> sourceType, Class<?> targetType, String contextName) { + return "<" + sourceType.getName() + " - " + targetType.getName() + " > [" + contextName + "] "; + } + + /** + * 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 contextName the context's name of the searched binder + * @param binderType type of binder required + * @param <S> the type of source + * @param <T> the type of target + * @return the registred binder or {@code null} if not found. + */ + protected static <S, T, B extends Binder<S, T>> Binder<S, T> newBinder0(Class<S> sourceType, + Class<T> targetType, + String contextName, + Class<B> binderType) { + + // obtain the cached model + BinderModel<S, T> model = + getBinderModels().get(sourceType, targetType, contextName); + + if (model == null) { + + // model not yet registred, let's create it + + if (log.isInfoEnabled()) { + log.info("No binder model found for " + + toString(sourceType, targetType, contextName) + + ", will create a new default one."); + } + + BinderModelBuilder<S, T> builder = + BinderModelBuilder.newDefaultBuilder(sourceType, targetType); + + // register the new binder model + model = registerBinderModel(builder, contextName); + } + + B binder; + try { + binder = binderType.newInstance(); + } catch (Exception e) { + throw new IllegalStateException("Could not instanciate binder of type " + binderType, e); + } + + binder.setModel(model); + return binder; + } + + public static class BindelModelEntryMap implements Map<BinderModelEntry, BinderModel<?, ?>> { + + protected Map<BinderModelEntry, BinderModel<?, ?>> delegate; + + public BindelModelEntryMap() { + delegate = new HashMap<BinderModelEntry, BinderModel<?, ?>>(); + } + + public <S, T> BinderModel<S, T> get(Class<S> source, + Class<T> target, + String contextName) { + BinderModel<S, T> result = null; + + for (BinderModelEntry key : binderModels.keySet()) { + if (!key.getSourceType().equals(source)) { + continue; + } + if (!key.getTargetType().equals(target)) { + continue; + } + + if (key.getName() == null) { + if (contextName != null) { + continue; + } + } else { + if (!key.getName().equals(contextName)) { + continue; + } + } + + result = (BinderModel<S, T>) binderModels.get(key); + break; + } + return result; + } + + public <S, T> BinderModel<S, T> get(BinderModel<S, T> model, + String contextName) { + + Class<S> source = model.getSourceType(); + Class<T> target = model.getTargetType(); + BinderModel<S, T> result = get(source, target, contextName); + return result; + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return delegate.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return delegate.containsValue(value); + } + + @Override + public BinderModel<?, ?> get(Object key) { + return delegate.get(key); + } + + public BinderModel<?, ?> put(BinderModelEntry key, BinderModel<?, ?> value) { + return delegate.put(key, value); + } + + @Override + public BinderModel<?, ?> remove(Object key) { + return delegate.remove(key); + } + + public void putAll(Map<? extends BinderModelEntry, ? extends BinderModel<?, ?>> m) { + delegate.putAll(m); + } + + @Override + public void clear() { + delegate.clear(); + } + + @Override + public Set<BinderModelEntry> keySet() { + return delegate.keySet(); + } + + @Override + public Collection<BinderModel<?, ?>> values() { + return delegate.values(); + } + + @Override + public Set<Entry<BinderModelEntry, BinderModel<?, ?>>> entrySet() { + return delegate.entrySet(); + } + + } + + /** + * Definition of an binder model 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 BinderModelEntry { + + protected final Class<?> sourceType; + + protected final Class<?> targetType; + + protected final String name; + + public BinderModelEntry(Class<?> sourceType, + Class<?> targetType, + String name) { + this.sourceType = sourceType; + this.targetType = targetType; + this.name = name; + } + + public BinderModelEntry(BinderModel<?, ?> model, String contextName) { + this(model.getSourceType(), model.getTargetType(), contextName); + } + + 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; + } + + BinderModelEntry that = (BinderModelEntry) 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/BinderFactory.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Modified: trunk/src/main/java/org/nuiton/util/beans/BinderModel.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/BinderModel.java 2010-12-27 15:58:28 UTC (rev 1988) +++ trunk/src/main/java/org/nuiton/util/beans/BinderModel.java 2010-12-28 16:52:49 UTC (rev 1989) @@ -39,9 +39,9 @@ * <p/> * TODO-TC20100225 should have special cases for collections treatment. * - * @author tchemit <chemit@codelutin.com> * @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 { @@ -269,6 +269,21 @@ 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; } Copied: trunk/src/main/java/org/nuiton/util/beans/BinderModelBuilder.java (from rev 1988, trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java) =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/BinderModelBuilder.java (rev 0) +++ trunk/src/main/java/org/nuiton/util/beans/BinderModelBuilder.java 2010-12-28 16:52:49 UTC (rev 1989) @@ -0,0 +1,485 @@ +/* + * #%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.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * Class to create a new {@link BinderModel}. + * <p/> + * <p/> + * A such object is designed to build only one model of binder and can not be + * used directly to create a new binder, it prepares only the model of a new + * binder, which after must be registred in the {@link BinderFactory} to obtain + * a real {@link Binder}. + * <p/> + * If you want to create more than one binder model, use each time a new + * binder builder. + * <p/> + * To obtain a new instance of a build please use one of the factories method : + * <ul> + * <li>{@link #newEmptyBuilder(Class)}} to create a binder model with same + * source and target type</li> + * <li>{@link #newEmptyBuilder(Class, Class)} to create a binder model with a + * possible different source and target type</li> + * <li>{@link #newDefaultBuilder(Class)} to create a binder model with same + * source and target type and then fill the model with all matching properties.</li> + * <li>{@link #newDefaultBuilder(Class, Class)} to create a binder model + * with a possible different source and target type and then fill the model + * with all matching properties.</li> + * </ul> + * Then you can use folowing methods to specify what to put in the copy model : + * <ul> + * <li>{@link #addSimpleProperties(String...)} to add in the binder model simple + * properties (a simple property is a property present in both source and target type)</li> + * <li>{@link #addProperty(String, String)} to add in the binder model a single + * property (from source type) to be copied to another property (in target type)</li> + * <li>{@link #addProperties(String...)} to add in the binder model properties + * (says here you specify some couple of properties (sourcePropertyName, + * targetPropertyName) to be added in the binder model)</li> + * <li>{@link #addBinder(String, Binder)} to add in the binder model + * another binder to be used to copy the given simple property (same name in + * source and target type)</li> + * <li>{@link #addCollectionStrategy(Binder.CollectionStrategy, String...)} to + * specify the strategy to be used to bind some collection some source type to + * target type</li> + * </ul> + * <b>Note :</b> You can chain thoses methods since all of them always return + * the current instance of the builder : + * <pre> + * builder.addSimpleProperties(...).addProperty(...).addBinder(...) + * </pre> + * <p/> + * Here is an example of how to use the {@link BinderModelBuilder} : + * <pre> + * BinderModelBuilder<Bean, Bean> builder = new BinderModelBuilder(Bean.class); + * builder.addSimpleProperties("name", "surname"); + * BinderFactory.registerBinderModel(builder); + * Binder<Bean, Bean> binder = BinderFactory.getBinder(BeanA.class); + * <p/> + * </pre> + * <p/> + * Once the binder is registred into the {@link BinderFactory}, you can get it + * each time you need it : + * <pre> + * Binder<Bean, Bean> binder = BinderFactory.getBinder(Bean.class); + * </pre> + * + * @author tchemit <chemit@codelutin.com> + * @see BinderModel + * @see Binder + * @since 1.5.3 + */ +public class BinderModelBuilder<S, T> { + + /** current model used to build the binder */ + protected BinderModel<S, T> model; + + /** source properties descriptors */ + protected Map<String, PropertyDescriptor> sourceDescriptors; + + /** target properties descriptors */ + protected Map<String, PropertyDescriptor> targetDescriptors; + + /** + * Creates a new mirrored and empty model binder for the given {@code type}. + * + * @param type the type of mirrored binder + * @return the new instanciated builder + */ + public static <S> BinderModelBuilder<S, S> newEmptyBuilder(Class<S> type) { + return new BinderModelBuilder<S, S>(type, type); + } + + /** + * Creates a new empty model binder for the given types. + * + * @param sourceType type of the source of the binder + * @param targetType type of the target of the binder + * @return the new instanciated builder + */ + public static <S, T> BinderModelBuilder<S, T> newEmptyBuilder(Class<S> sourceType, + Class<T> targetType) { + return new BinderModelBuilder<S, T>(sourceType, targetType); + } + + /** + * Creates a new mirrored model builder and fill the model with all matching + * and available property from the given type. + * + * @param sourceType the mirrored type of the binder model to create + * @param <S> the mirrored type of the binder model to create + * @return the new instanciated model builder fully filled + */ + public static <S> BinderModelBuilder<S, S> newDefaultBuilder(Class<S> sourceType) { + return newDefaultBuilder(sourceType, sourceType); + + } + + /** + * Creates a new model builder and fill the model with all matching + * and available properties from the source type to the target type. + * + * @param sourceType the source type of the model to create + * @param targetType the target type of the model to create + * @param <S> the source type of the binder model to create + * @param <T> the target type of the binder model to create + * @return the new instanciated model builder fully filled + */ + public static <S, T> BinderModelBuilder<S, T> newDefaultBuilder(Class<S> sourceType, + Class<T> targetType) { + BinderModelBuilder<S, T> builder = + newEmptyBuilder(sourceType, targetType); + Map<String, PropertyDescriptor> source = builder.sourceDescriptors; + Map<String, PropertyDescriptor> target = builder.targetDescriptors; + List<String> properties = new ArrayList<String>(); + for (String propertyName : source.keySet()) { + if (!target.containsKey(propertyName)) { + + // not exactly match for this property, do not use this property + continue; + } + PropertyDescriptor sourceDescriptor = source.get(propertyName); + if (sourceDescriptor.getReadMethod() == null) { + + // no getter on source, do not use this property + continue; + } + PropertyDescriptor targetDescriptor = target.get(propertyName); + if (targetDescriptor.getWriteMethod() == null) { + + // no setter on target, do not use this property + continue; + } + + // can safely use this property + properties.add(propertyName); + } + + // add all detected properties + builder.addSimpleProperties( + properties.toArray(new String[properties.size()])); + return builder; + } + + + /** + * 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 BinderModelBuilder<S, T> addSimpleProperties(String... properties) + throws IllegalStateException, NullPointerException { + 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 BinderModelBuilder<S, T> 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"); + } + 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 BinderModelBuilder<S, T> addProperties(String... sourceAndTargetProperties) + throws IllegalStateException, IllegalArgumentException, + NullPointerException { + 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; + } + + public BinderModelBuilder<S, T> addBinder(String propertyName, Binder<?, ?> binder) { + + // check property is registred + if (!model.containsSourceProperty(propertyName)) { + throw new IllegalArgumentException( + "source property '" + propertyName + "' " + + " is NOT registred."); + } + + // check property is the same type of given binder + PropertyDescriptor descriptor = sourceDescriptors.get(propertyName); + Class<?> type = descriptor.getPropertyType(); + + if (!Collection.class.isAssignableFrom(type) && + !binder.model.getSourceType().isAssignableFrom(type)) { + throw new IllegalStateException( + "source property '" + propertyName + + "' has not the same type [" + type + + "] of the binder [" + binder.model.getSourceType() + "]."); + } + + // can safely add the strategy + model.addBinder(propertyName, binder); + + return this; + } + + public BinderModelBuilder<S, T> addCollectionStrategy(Binder.CollectionStrategy strategy, + String... propertyNames) { + + for (String propertyName : propertyNames) { + + // check property is registred + if (!model.containsSourceProperty(propertyName)) { + throw new IllegalArgumentException( + "source property '" + propertyName + "' " + + " is NOT registred."); + } + + // check property is collection type + PropertyDescriptor descriptor = sourceDescriptors.get(propertyName); + Class<?> type = descriptor.getPropertyType(); + if (!Collection.class.isAssignableFrom(type)) { + throw new IllegalStateException( + "source property '" + propertyName + + "' is not a collection type [" + type + "]"); + } + + // can safely add the strategy + model.addCollectionStrategy(propertyName, strategy); + } + return this; + } + + /** + * Creates a binder for the given types. + * + * @param sourceType type of the source of the binder + * @param targetType type of the target of the binder + */ + protected BinderModelBuilder(Class<S> sourceType, Class<T> targetType) { + 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<S, T>(sourceType, targetType); + + // obtain source descriptors + sourceDescriptors = new TreeMap<String, PropertyDescriptor>(); + loadDescriptors(model.getSourceType(), sourceDescriptors); + + // obtain target descriptors + targetDescriptors = new TreeMap<String, PropertyDescriptor>(); + loadDescriptors(model.getTargetType(), targetDescriptors); + + } + + protected void addProperty0(String sourceProperty, + String targetProperty) { + + // 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.equals(targetType)) { + throw new IllegalArgumentException("source property '" + + sourceProperty + "' and target property '" + + targetProperty + "' are not compatible ( sourceType : " + + sourceType + " vs targetType :" + targetType + ')'); + } + + // check srcProperty does not exist + if (model.containsSourceProperty(sourceProperty)) { + + // just remove the old property mapping + model.removeBinding(sourceProperty); + + } + + // check dstProperty does not exist + // here we can not deal with it since we should remove the source + // property for the entry and this is a bit unatural + if (model.containsTargetProperty(targetProperty)) { + throw new IllegalArgumentException("destination property '" + + targetProperty + "' " + " was already registred."); + } + // safe to add the binding + model.addBinding(sourceDescriptor, targetDescriptor); + } + + + protected BinderModel<S, T> getModel() { + return model; + } + + protected void clear() { + sourceDescriptors = null; + targetDescriptors = null; + model = null; + } + + protected static void loadDescriptors( + Class<?> type, + Map<String, PropertyDescriptor> descriptors) { + try { + + BeanInfo beanInfo = Introspector.getBeanInfo(type); + for (PropertyDescriptor descriptor : + beanInfo.getPropertyDescriptors()) { + if (!descriptors.containsKey(descriptor.getName())) { + descriptors.put(descriptor.getName(), descriptor); + } + } + } catch (IntrospectionException e) { + throw new RuntimeException("Could not obtain bean properties " + + "descriptors for source type " + type, e); + } + Class<?>[] interfaces = type.getInterfaces(); + for (Class<?> i : interfaces) { + loadDescriptors(i, descriptors); + } + Class<?> superClass = type.getSuperclass(); + if (superClass != null && !Object.class.equals(superClass)) { + loadDescriptors(superClass, descriptors); + } + } +} Modified: trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java =================================================================== --- trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java 2010-12-27 15:58:28 UTC (rev 1988) +++ trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java 2010-12-28 16:52:49 UTC (rev 1989) @@ -60,7 +60,9 @@ * @see Binder * @see BinderBuilder * @since 1.1.5 + * @deprecated since 1.5.3, use now the {@link BinderFactory} instead, will be remove in version {@code 1.6}. */ +@Deprecated public class BinderProvider { /** Logger */ Modified: trunk/src/test/java/org/nuiton/util/beans/BeanA.java =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BeanA.java 2010-12-27 15:58:28 UTC (rev 1988) +++ trunk/src/test/java/org/nuiton/util/beans/BeanA.java 2010-12-28 16:52:49 UTC (rev 1989) @@ -30,6 +30,7 @@ public class BeanA { + public static final String PROPERTY_AA = "aa"; public static final String PROPERTY_A = "a"; public static final String PROPERTY_B = "b"; @@ -42,12 +43,16 @@ public static final String PROPERTY_F = "f"; - protected String a, b, c, d; + protected String aa, a, b, c, d; protected int e, f; protected PropertyChangeSupport pcs = new PropertyChangeSupport(this); + public void setAa(String aa) { + this.aa = aa; + } + public String getA() { return a; } Modified: trunk/src/test/java/org/nuiton/util/beans/BeanB.java =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BeanB.java 2010-12-27 15:58:28 UTC (rev 1988) +++ trunk/src/test/java/org/nuiton/util/beans/BeanB.java 2010-12-28 16:52:49 UTC (rev 1989) @@ -27,6 +27,8 @@ public class BeanB extends BeanA { + public static final String PROPERTY_BB = "bb"; + public static final String PROPERTY_A2 = "a2"; public static final String PROPERTY_B2 = "b2"; @@ -39,10 +41,16 @@ public static final String PROPERTY_F2 = "f2"; + String bb; + String a2, b2, c2, d2; int e2, f2; + public String getBb() { + return bb; + } + public String getA2() { return a2; } Modified: trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java 2010-12-27 15:58:28 UTC (rev 1988) +++ trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java 2010-12-28 16:52:49 UTC (rev 1989) @@ -29,12 +29,19 @@ import org.junit.Before; import org.junit.Test; +import javax.xml.ws.BindingProvider; import java.beans.PropertyDescriptor; import java.util.Map; +/** + * @author tchemit <chemit@codelutin.com> + * @deprecated since 1.5.3, will be removed when {@link BindingProvider} will be removed. + */ +@Deprecated public class BinderBuilderTest { private BinderBuilder builder; + protected static final String PROPERTY_CLASS = "class"; @Before @@ -57,8 +64,9 @@ sourceDescriptors = builder.sourceDescriptors; Assert.assertNotNull(sourceDescriptors); - Assert.assertEquals(7, sourceDescriptors.size()); + Assert.assertEquals(8, sourceDescriptors.size()); Assert.assertTrue(sourceDescriptors.containsKey(PROPERTY_CLASS)); + Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_AA)); Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_A)); Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_B)); Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_C)); @@ -69,8 +77,9 @@ targetDescriptors = builder.targetDescriptors; Assert.assertNotNull(targetDescriptors); - Assert.assertEquals(7, targetDescriptors.size()); + Assert.assertEquals(8, targetDescriptors.size()); Assert.assertTrue(targetDescriptors.containsKey(PROPERTY_CLASS)); + Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_AA)); Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_A)); Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_B)); Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_C)); @@ -115,8 +124,9 @@ sourceDescriptors = builder.sourceDescriptors; Assert.assertNotNull(sourceDescriptors); - Assert.assertEquals(7, sourceDescriptors.size()); + Assert.assertEquals(8, sourceDescriptors.size()); Assert.assertTrue(sourceDescriptors.containsKey(PROPERTY_CLASS)); + Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_AA)); Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_A)); Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_B)); Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_C)); @@ -124,16 +134,19 @@ Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_E)); Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_F)); + targetDescriptors = builder.targetDescriptors; Assert.assertNotNull(targetDescriptors); - Assert.assertEquals(13, targetDescriptors.size()); + Assert.assertEquals(15, targetDescriptors.size()); Assert.assertTrue(targetDescriptors.containsKey(PROPERTY_CLASS)); + Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_AA)); 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(BeanA.PROPERTY_E)); Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_F)); + Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_BB)); Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_A2)); Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_B2)); Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_C2)); @@ -143,7 +156,6 @@ Assert.assertEquals(BeanA.class, builder.getModel().getSourceType()); Assert.assertEquals(BeanB.class, builder.getModel().getTargetType()); - } @Test(expected = IllegalStateException.class) @@ -272,7 +284,7 @@ try { builder.addProperties(BeanB.PROPERTY_A, BeanB.PROPERTY_A2, - BeanB.PROPERTY_B); + BeanB.PROPERTY_B); Assert.fail(); } catch (IllegalArgumentException e) { Assert.assertTrue(true); @@ -280,14 +292,14 @@ try { builder.addProperties(BeanB.PROPERTY_A, null, - BeanB.PROPERTY_B, BeanB.PROPERTY_B); + 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); + BeanB.PROPERTY_B, BeanB.PROPERTY_B2); BinderModel<?, ?> model = builder.getModel(); Assert.assertEquals(2, model.getSourceDescriptors().length); @@ -307,7 +319,7 @@ 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); + BeanB.PROPERTY_B, BeanB.PROPERTY_B2); Binder<BeanA, BeanB> binder = (Binder<BeanA, BeanB>) builder.createBinder(); Added: trunk/src/test/java/org/nuiton/util/beans/BinderFactoryTest.java =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BinderFactoryTest.java (rev 0) +++ trunk/src/test/java/org/nuiton/util/beans/BinderFactoryTest.java 2010-12-28 16:52:49 UTC (rev 1989) @@ -0,0 +1,119 @@ +package org.nuiton.util.beans; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests the {@link BinderFactory}. + * + * @author tchemit <chemit@codelutin.com> + * @since 1.5.3 + */ + +public class BinderFactoryTest { + + @Before + public void setUp() throws Exception { + BinderFactory.clear(); + } + + @Test + public void testNewBinder() throws Exception { + + // Limit cases + try { + BinderFactory.newBinder(null); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + + try { + BinderFactory.newBinder(null, (Class<?>) null); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + + try { + BinderFactory.newBinder(BeanA.class, (Class<?>) null); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + + try { + BinderFactory.newBinder(null, BeanA.class); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + + Assert.assertTrue(BinderFactory.binderModels.isEmpty()); + + Binder<BeanA, BeanA> binderAA = BinderFactory.newBinder(BeanA.class); + + Assert.assertNotNull(binderAA); + Assert.assertNotNull(BinderFactory.binderModels); + Assert.assertEquals(1, BinderFactory.binderModels.size()); + + } + + + @Test + public void testRegisterBinderModel() throws Exception { + + Assert.assertNull(BinderFactory.binderModels); + + BinderModel<BeanA, BeanA> model = + BinderFactory.registerBinderModel(BinderModelBuilder.newDefaultBuilder(BeanA.class)); + + Assert.assertNotNull(BinderFactory.binderModels); + Assert.assertEquals(1, BinderFactory.binderModels.size()); + Assert.assertEquals(model, + BinderFactory.newBinder(BeanA.class).getModel()); + + BinderModel<BeanA, BeanA> model1 = + BinderFactory.registerBinderModel(BinderModelBuilder.newDefaultBuilder(BeanA.class)); + + Assert.assertNotNull(BinderFactory.binderModels); + Assert.assertEquals(1, BinderFactory.binderModels.size()); + Assert.assertNotSame(model, model1); + Assert.assertEquals(model1, + BinderFactory.newBinder(BeanA.class).getModel()); + + BinderFactory.registerBinderModel(model1, "context"); + + Assert.assertNotNull(BinderFactory.binderModels); + Assert.assertEquals(2, BinderFactory.binderModels.size()); + Assert.assertEquals( + model1, + BinderFactory.newBinder(BeanA.class, "context").getModel()); + + + BinderFactory.registerBinderModel(model, "context"); + + + Assert.assertNotNull(BinderFactory.binderModels); + Assert.assertEquals(2, BinderFactory.binderModels.size()); + Assert.assertEquals( + model, + BinderFactory.newBinder(BeanA.class, "context").getModel()); + + } + + + @Test + public void testClear() throws Exception { + Assert.assertNull(BinderFactory.binderModels); + BinderFactory.newBinder(BeanA.class); + Assert.assertNotNull(BinderFactory.binderModels); + Assert.assertEquals(1, BinderFactory.binderModels.size()); + + BinderFactory.clear(); + + Assert.assertNull(BinderFactory.binderModels); + + } +} Property changes on: trunk/src/test/java/org/nuiton/util/beans/BinderFactoryTest.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Copied: trunk/src/test/java/org/nuiton/util/beans/BinderModelBuilderTest.java (from rev 1988, trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java) =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BinderModelBuilderTest.java (rev 0) +++ trunk/src/test/java/org/nuiton/util/beans/BinderModelBuilderTest.java 2010-12-28 16:52:49 UTC (rev 1989) @@ -0,0 +1,543 @@ +/* + * #%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 org.junit.Assert; +import org.junit.Test; + +import java.util.Map; + +/** + * Tests the {@link BinderModelBuilder}. + * + * @author tchemit <chemit@codelutin.com> + * @since 1.5.3 + */ +public class BinderModelBuilderTest { + + protected static final String PROPERTY_CLASS = "class"; + + BinderModelBuilder<BeanA, BeanA> builderAA; + + BinderModelBuilder<BeanA, BeanB> builderAB; + + BinderModelBuilder<BeanB, BeanB> builderBB; + + BinderModelBuilder<BeanB, BeanA> builderBA; + + @Test + public void newEmptyBuilder() throws Exception { + + // Limit cases + + try { + BinderModelBuilder.newEmptyBuilder(null); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + try { + BinderModelBuilder.newEmptyBuilder(null, null); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + try { + BinderModelBuilder.newEmptyBuilder(BeanA.class, null); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + try { + BinderModelBuilder.newEmptyBuilder(null, BeanA.class); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + + // A --> A + + builderAA = BinderModelBuilder.newEmptyBuilder(BeanA.class); + assertBuilder(builderAA, BeanA.class, BeanA.class); + + assertDescriptor(builderAA.sourceDescriptors, + PROPERTY_CLASS, + BeanA.PROPERTY_AA, + BeanA.PROPERTY_A, + BeanA.PROPERTY_B, + BeanA.PROPERTY_C, + BeanA.PROPERTY_D, + BeanA.PROPERTY_E, + BeanA.PROPERTY_F + ); + + assertDescriptor(builderAA.targetDescriptors, + PROPERTY_CLASS, + BeanA.PROPERTY_AA, + BeanA.PROPERTY_A, + BeanA.PROPERTY_B, + BeanA.PROPERTY_C, + BeanA.PROPERTY_D, + BeanA.PROPERTY_E, + BeanA.PROPERTY_F + ); + + builderAA = BinderModelBuilder.newEmptyBuilder(BeanA.class, BeanA.class); + assertBuilder(builderAA, BeanA.class, BeanA.class); + + assertDescriptor(builderAA.sourceDescriptors, + PROPERTY_CLASS, + BeanA.PROPERTY_AA, + BeanA.PROPERTY_A, + BeanA.PROPERTY_B, + BeanA.PROPERTY_C, + BeanA.PROPERTY_D, + BeanA.PROPERTY_E, + BeanA.PROPERTY_F + ); + + assertDescriptor(builderAA.targetDescriptors, + PROPERTY_CLASS, + BeanA.PROPERTY_AA, + BeanA.PROPERTY_A, + BeanA.PROPERTY_B, + BeanA.PROPERTY_C, + BeanA.PROPERTY_D, + BeanA.PROPERTY_E, + BeanA.PROPERTY_F + ); + + // A --> B + + builderAB = BinderModelBuilder.newEmptyBuilder(BeanA.class, BeanB.class); + assertBuilder(builderAB, BeanA.class, BeanB.class); + + assertDescriptor(builderAB.sourceDescriptors, + PROPERTY_CLASS, + BeanA.PROPERTY_AA, + BeanA.PROPERTY_A, + BeanA.PROPERTY_B, + BeanA.PROPERTY_C, + BeanA.PROPERTY_D, + BeanA.PROPERTY_E, + BeanA.PROPERTY_F + ); + + assertDescriptor(builderAB.targetDescriptors, + PROPERTY_CLASS, + BeanA.PROPERTY_AA, + BeanB.PROPERTY_A, + BeanB.PROPERTY_B, + BeanB.PROPERTY_C, + BeanB.PROPERTY_D, + BeanB.PROPERTY_E, + BeanB.PROPERTY_F, + BeanB.PROPERTY_BB, + BeanB.PROPERTY_A2, + BeanB.PROPERTY_B2, + BeanB.PROPERTY_C2, + BeanB.PROPERTY_D2, + BeanB.PROPERTY_E2, + BeanB.PROPERTY_F2 + ); + + // B --> B + + builderBB = BinderModelBuilder.newEmptyBuilder(BeanB.class); + assertBuilder(builderBB, BeanB.class, BeanB.class); + + assertDescriptor(builderBB.sourceDescriptors, + PROPERTY_CLASS, + BeanA.PROPERTY_AA, + BeanB.PROPERTY_A, + BeanB.PROPERTY_B, + BeanB.PROPERTY_C, + BeanB.PROPERTY_D, + BeanB.PROPERTY_E, + BeanB.PROPERTY_F, + BeanB.PROPERTY_BB, + BeanB.PROPERTY_A2, + BeanB.PROPERTY_B2, + BeanB.PROPERTY_C2, + BeanB.PROPERTY_D2, + BeanB.PROPERTY_E2, + BeanB.PROPERTY_F2 + ); + assertDescriptor(builderBB.targetDescriptors, + PROPERTY_CLASS, + BeanA.PROPERTY_AA, + BeanB.PROPERTY_A, + BeanB.PROPERTY_B, + BeanB.PROPERTY_C, + BeanB.PROPERTY_D, + BeanB.PROPERTY_E, + BeanB.PROPERTY_F, + BeanB.PROPERTY_BB, + BeanB.PROPERTY_A2, + BeanB.PROPERTY_B2, + BeanB.PROPERTY_C2, + BeanB.PROPERTY_D2, + BeanB.PROPERTY_E2, + BeanB.PROPERTY_F2 + ); + + builderBB = BinderModelBuilder.newEmptyBuilder(BeanB.class, BeanB.class); + assertBuilder(builderBB, BeanB.class, BeanB.class); + + assertDescriptor(builderBB.sourceDescriptors, + PROPERTY_CLASS, + BeanA.PROPERTY_AA, + BeanB.PROPERTY_A, + BeanB.PROPERTY_B, + BeanB.PROPERTY_C, + BeanB.PROPERTY_D, + BeanB.PROPERTY_E, + BeanB.PROPERTY_F, + BeanB.PROPERTY_BB, + BeanB.PROPERTY_A2, + BeanB.PROPERTY_B2, + BeanB.PROPERTY_C2, + BeanB.PROPERTY_D2, + BeanB.PROPERTY_E2, + BeanB.PROPERTY_F2 + ); + assertDescriptor(builderBB.targetDescriptors, + PROPERTY_CLASS, + BeanA.PROPERTY_AA, + BeanB.PROPERTY_A, + BeanB.PROPERTY_B, + BeanB.PROPERTY_C, + BeanB.PROPERTY_D, + BeanB.PROPERTY_E, + BeanB.PROPERTY_F, + BeanB.PROPERTY_BB, + BeanB.PROPERTY_A2, + BeanB.PROPERTY_B2, + BeanB.PROPERTY_C2, + BeanB.PROPERTY_D2, + BeanB.PROPERTY_E2, + BeanB.PROPERTY_F2 + ); + + // B --> A + + builderBA = BinderModelBuilder.newEmptyBuilder(BeanB.class, BeanA.class); + assertBuilder(builderBA, BeanB.class, BeanA.class); + + assertDescriptor(builderBA.sourceDescriptors, + PROPERTY_CLASS, + BeanA.PROPERTY_AA, + BeanB.PROPERTY_A, + BeanB.PROPERTY_B, + BeanB.PROPERTY_C, + BeanB.PROPERTY_D, + BeanB.PROPERTY_E, + BeanB.PROPERTY_F, + BeanB.PROPERTY_BB, + BeanB.PROPERTY_A2, + BeanB.PROPERTY_B2, + BeanB.PROPERTY_C2, + BeanB.PROPERTY_D2, + BeanB.PROPERTY_E2, + BeanB.PROPERTY_F2 + ); + assertDescriptor(builderBA.targetDescriptors, + PROPERTY_CLASS, + BeanA.PROPERTY_AA, + BeanB.PROPERTY_A, + BeanB.PROPERTY_B, + BeanB.PROPERTY_C, + BeanB.PROPERTY_D, + BeanB.PROPERTY_E, + BeanB.PROPERTY_F + ); + } + + + @Test + public void newDefaultBuilder() throws Exception { + + // Limit cases + + try { + BinderModelBuilder.newDefaultBuilder(null); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + try { + BinderModelBuilder.newDefaultBuilder(null, null); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + try { + BinderModelBuilder.newDefaultBuilder(BeanA.class, null); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + try { + BinderModelBuilder.newDefaultBuilder(null, BeanA.class); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + + // A --> A + + builderAA = BinderModelBuilder.newDefaultBuilder(BeanA.class); + assertBuilder(builderAA, BeanA.class, BeanA.class); + assertDescriptor(builderAA.getModel().propertiesMapping, + BeanA.PROPERTY_A, + BeanA.PROPERTY_B, + BeanA.PROPERTY_C, + BeanA.PROPERTY_D, + BeanA.PROPERTY_E, + BeanA.PROPERTY_F + ); + + builderAA = BinderModelBuilder.newDefaultBuilder(BeanA.class, BeanA.class); + assertBuilder(builderAA, BeanA.class, BeanA.class); + assertDescriptor(builderAA.getModel().propertiesMapping, + BeanA.PROPERTY_A, + BeanA.PROPERTY_B, + BeanA.PROPERTY_C, + BeanA.PROPERTY_D, + BeanA.PROPERTY_E, + BeanA.PROPERTY_F + ); + + // A --> B + + builderAB = BinderModelBuilder.newDefaultBuilder(BeanA.class, BeanB.class); + assertBuilder(builderAB, BeanA.class, BeanB.class); + assertDescriptor(builderAB.getModel().propertiesMapping, + BeanA.PROPERTY_A, + BeanA.PROPERTY_B, + BeanA.PROPERTY_C, + BeanA.PROPERTY_D, + BeanA.PROPERTY_E, + BeanA.PROPERTY_F + ); + + // B --> B + + builderBB = BinderModelBuilder.newDefaultBuilder(BeanB.class); + assertBuilder(builderBB, BeanB.class, BeanB.class); + + assertDescriptor(builderBB.getModel().propertiesMapping, + BeanB.PROPERTY_A, + BeanB.PROPERTY_B, + BeanB.PROPERTY_C, + BeanB.PROPERTY_D, + BeanB.PROPERTY_E, + BeanB.PROPERTY_F, + BeanB.PROPERTY_A2, + BeanB.PROPERTY_B2, + BeanB.PROPERTY_C2, + BeanB.PROPERTY_D2, + BeanB.PROPERTY_E2, + BeanB.PROPERTY_F2 + ); + + builderBB = BinderModelBuilder.newDefaultBuilder(BeanB.class, BeanB.class); + assertBuilder(builderBB, BeanB.class, BeanB.class); + assertDescriptor(builderBB.getModel().propertiesMapping, + BeanB.PROPERTY_A, + BeanB.PROPERTY_B, + BeanB.PROPERTY_C, + BeanB.PROPERTY_D, + BeanB.PROPERTY_E, + BeanB.PROPERTY_F, + BeanB.PROPERTY_A2, + BeanB.PROPERTY_B2, + BeanB.PROPERTY_C2, + BeanB.PROPERTY_D2, + BeanB.PROPERTY_E2, + BeanB.PROPERTY_F2 + ); + + // B --> A + + builderBA = BinderModelBuilder.newDefaultBuilder(BeanB.class, BeanA.class); + assertBuilder(builderBA, BeanB.class, BeanA.class); + assertDescriptor(builderBA.getModel().propertiesMapping, + BeanB.PROPERTY_A, + BeanB.PROPERTY_B, + BeanB.PROPERTY_C, + BeanB.PROPERTY_D, + BeanB.PROPERTY_E, + BeanB.PROPERTY_F + ); + + } + + @Test + public void testAddSimpleProperties() throws Exception { + + builderAA = BinderModelBuilder.newEmptyBuilder(BeanA.class); + + BinderModel<BeanA, BeanA> model = builderAA.getModel(); + + // limit case + try { + builderAA.addSimpleProperties((String) null); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + + // not existing source property + try { + builderAA.addSimpleProperties(BeanB.PROPERTY_A2); + Assert.fail(); + } catch (IllegalArgumentException e) { + Assert.assertTrue(true); + } + + builderAA.addSimpleProperties(BeanA.PROPERTY_A); + Assert.assertEquals(1, model.getSourceDescriptors().length); + Assert.assertEquals(1, model.getTargetDescriptors().length); + Map<String, String> map = model.getPropertiesMapping(); + assertDescriptor(map, BeanB.PROPERTY_A); + Assert.assertEquals(BeanA.PROPERTY_A, map.get(BeanA.PROPERTY_A)); + + builderAA.addSimpleProperties(BeanA.PROPERTY_A); + Assert.assertEquals(1, model.getSourceDescriptors().length); + Assert.assertEquals(1, model.getTargetDescriptors().length); + assertDescriptor(map, BeanB.PROPERTY_A); + Assert.assertEquals(BeanA.PROPERTY_A, map.get(BeanA.PROPERTY_A)); + + builderAA.addSimpleProperties(BeanA.PROPERTY_B); + Assert.assertEquals(2, model.getSourceDescriptors().length); + Assert.assertEquals(2, model.getTargetDescriptors().length); + assertDescriptor(map, BeanB.PROPERTY_A, BeanB.PROPERTY_B); + Assert.assertEquals(BeanA.PROPERTY_B, map.get(BeanA.PROPERTY_B)); + + } + + @Test + public void testAddProperty() throws Exception { + builderAB = + BinderModelBuilder.newEmptyBuilder(BeanA.class, BeanB.class); + + BinderModel<BeanA, BeanB> model = builderAB.getModel(); + + // limit cases + + try { + builderAB.addProperty(null, null); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + try { + builderAB.addProperty(BeanA.PROPERTY_A, null); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + try { + builderAB.addProperty(null, BeanA.PROPERTY_A); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + + // not existing source property + try { + builderAB.addProperty(BeanB.PROPERTY_A2, BeanB.PROPERTY_A); + Assert.fail(); + } catch (IllegalArgumentException e) { + Assert.assertTrue(true); + } + + builderAB.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(); + assertDescriptor(map, BeanB.PROPERTY_A); + Assert.assertEquals(BeanA.PROPERTY_A, map.get(BeanA.PROPERTY_A)); + + builderAB.addProperty(BeanB.PROPERTY_A, BeanB.PROPERTY_A2); + Assert.assertEquals(1, model.getSourceDescriptors().length); + Assert.assertEquals(1, model.getTargetDescriptors().length); + assertDescriptor(map, BeanB.PROPERTY_A); + Assert.assertEquals(BeanB.PROPERTY_A2, map.get(BeanA.PROPERTY_A)); + + builderAB.addProperty(BeanA.PROPERTY_B, BeanB.PROPERTY_B2); + Assert.assertEquals(2, model.getSourceDescriptors().length); + Assert.assertEquals(2, model.getTargetDescriptors().length); + assertDescriptor(map, BeanB.PROPERTY_A, BeanB.PROPERTY_B); + Assert.assertEquals(BeanB.PROPERTY_B2, map.get(BeanB.PROPERTY_B)); + } + + @Test + public void testAddProperties() throws Exception { + builderAB = + BinderModelBuilder.newEmptyBuilder(BeanA.class, BeanB.class); + + try { + builderAB.addProperties(BeanB.PROPERTY_A, BeanB.PROPERTY_A2, + BeanB.PROPERTY_B); + Assert.fail(); + } catch (IllegalArgumentException e) { + Assert.assertTrue(true); + } + + try { + builderAB.addProperties(BeanB.PROPERTY_A, null, + BeanB.PROPERTY_B, BeanB.PROPERTY_B); + Assert.fail(); + } catch (NullPointerException e) { + Assert.assertTrue(true); + } + + builderAB.addProperties(BeanB.PROPERTY_A, BeanB.PROPERTY_A, + BeanB.PROPERTY_B, BeanB.PROPERTY_B2); + + BinderModel<?, ?> model = builderAB.getModel(); + + Assert.assertEquals(2, model.getSourceDescriptors().length); + Assert.assertEquals(2, model.getTargetDescriptors().length); + Map<String, String> map = model.getPropertiesMapping(); + assertDescriptor(map, BeanB.PROPERTY_A, BeanB.PROPERTY_B); + Assert.assertEquals(BeanA.PROPERTY_A, map.get(BeanA.PROPERTY_A)); + Assert.assertEquals(BeanB.PROPERTY_B2, map.get(BeanA.PROPERTY_B)); + } + + protected void assertDescriptor(Map<String, ?> descriptors, + String... propertyNames) { + Assert.assertNotNull(descriptors); + Assert.assertEquals(propertyNames.length, descriptors.size()); + for (String propertyName : propertyNames) { + Assert.assertTrue(descriptors.containsKey(propertyName)); + } + } + + protected <S, T> void assertBuilder(BinderModelBuilder<S, T> builder, + Class<S> sourceType, + Class<T> targetType) { + Assert.assertNotNull(builder); + Assert.assertNotNull(builder.getModel()); + Assert.assertEquals(sourceType, builder.getModel().getSourceType()); + Assert.assertEquals(targetType, builder.getModel().getTargetType()); + } + +} Modified: trunk/src/test/java/org/nuiton/util/beans/BinderProviderTest.java =================================================================== --- trunk/src/test/java/org/nuiton/util/beans/BinderProviderTest.java 2010-12-27 15:58:28 UTC (rev 1988) +++ trunk/src/test/java/org/nuiton/util/beans/BinderProviderTest.java 2010-12-28 16:52:49 UTC (rev 1989) @@ -29,6 +29,13 @@ import org.junit.Before; import org.junit.Test; +import javax.xml.ws.BindingProvider; + +/** + * @author tchemit <chemit@codelutin.com> + * @deprecated since 1.5.3, will be removed when {@link BindingProvider} will be removed. + */ +@Deprecated public class BinderProviderTest { Binder<BeanA, BeanA> binderA; @@ -86,6 +93,7 @@ public void testRegisterBinderWithName() throws Exception { Assert.assertNull(BinderProvider.binders); + String yo = "yo"; try { BinderProvider.registerBinder((Binder<?,?>) null, null); Assert.fail();
participants (1)
-
tchemit@users.nuiton.org