Nuiton-utils-commits
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
February 2010
- 4 participants
- 18 discussions
Author: echatellier
Date: 2010-02-23 14:15:12 +0100 (Tue, 23 Feb 2010)
New Revision: 1769
Modified:
trunk/src/main/java/org/nuiton/util/ApplicationConfig.java
Log:
Reorder javadoc tags
Modified: trunk/src/main/java/org/nuiton/util/ApplicationConfig.java
===================================================================
--- trunk/src/main/java/org/nuiton/util/ApplicationConfig.java 2010-02-23 13:14:05 UTC (rev 1768)
+++ trunk/src/main/java/org/nuiton/util/ApplicationConfig.java 2010-02-23 13:15:12 UTC (rev 1769)
@@ -244,10 +244,9 @@
* </pre>
* <tt>getOption("fullname")</tt> retournera <tt>"John Doe"</tt>.
*
+ * @since 0.30
* @author poussin
* @version $Revision$
- * @since 0.30
- *
* <p/>
* Last update $Date$ by $Author$
*/
1
0
Author: echatellier
Date: 2010-02-23 14:14:05 +0100 (Tue, 23 Feb 2010)
New Revision: 1768
Modified:
trunk/src/main/java/org/nuiton/util/ApplicationConfig.java
Log:
Add link on types
Modified: trunk/src/main/java/org/nuiton/util/ApplicationConfig.java
===================================================================
--- trunk/src/main/java/org/nuiton/util/ApplicationConfig.java 2010-02-23 10:38:40 UTC (rev 1767)
+++ trunk/src/main/java/org/nuiton/util/ApplicationConfig.java 2010-02-23 13:14:05 UTC (rev 1768)
@@ -218,15 +218,15 @@
* sont:
* <ul>
* <li> les primitif (byte, short, int, long, float, double, char, boolean)
- * <li> String
- * <li> File
- * <li> URL
- * <li> Class
- * <li> SqlDate
- * <li> SqlTime
- * <li> SqlTimestamps
- * <li> les tableaux d'un type primitif ou String. Chaque element doit etre
- * separe par une virgule
+ * <li> {@link String}
+ * <li> {@link File}
+ * <li> {@link URL}
+ * <li> {@link Class}
+ * <li> Sql{@link Date}
+ * <li> Sql{@link Time}
+ * <li> Sql{@link Timestamp}
+ * <li> les tableaux d'un type primitif ou {@link String}. Chaque element doit
+ * etre separe par une virgule.
* </ul>
*
* Pour suporter d'autre type, il vous suffit d'enregistrer de nouveau
1
0
Author: echatellier
Date: 2010-02-23 11:38:40 +0100 (Tue, 23 Feb 2010)
New Revision: 1767
Modified:
trunk/src/main/java/org/nuiton/util/ApplicationConfig.java
trunk/src/main/java/org/nuiton/util/ArgumentsParserException.java
Log:
Update ApplicationConfig javadoc
Modified: trunk/src/main/java/org/nuiton/util/ApplicationConfig.java
===================================================================
--- trunk/src/main/java/org/nuiton/util/ApplicationConfig.java 2010-02-21 19:37:40 UTC (rev 1766)
+++ trunk/src/main/java/org/nuiton/util/ApplicationConfig.java 2010-02-23 10:38:40 UTC (rev 1767)
@@ -50,68 +50,64 @@
import java.beans.PropertyChangeListener;
/**
- * <h1>To do</h1>
- * <p/>
+ * Application configuration.
+ *
+ * <h3>TODO</h3>
* <ul>
- * <li> ajout d'annotations sur les methodes
- * pour precisser plus de chose pour les options (pattern, min/max, alias,
+ * <li>Ajout d'annotations sur les methodes
+ * pour preciser plus de chose pour les options (pattern, min/max, alias,
* description, ...)
- * <li> trouver un moyen de document les options et actions pour automatiquement
+ * <li>Trouver un moyen de document les options et actions pour automatiquement
* generer l'aide en ligne. Pour eviter de devoir maintenir une methode
* dans lequel est ecrit l'aide en plus des options.
- * <li> prise en compte du flag {@link #useOnlyAliases}
- * <li> vu qu'en java on ne peut pas pointer une methode mais seulement une classe
+ * <li>Prise en compte du flag {@link #useOnlyAliases}
+ * <li>Vu qu'en java on ne peut pas pointer une methode mais seulement une classe
* il y a un bout des actions qui sont des chaines (nom de la methode). Il faudrait
* faire un plugin maven qui check que l'action existe bien durant la compilation.
* Il est simple de le faire a l'execution mais c trop tard :(
* </ul>
- * <p/>
- * <h1>Usage</h1>
- * <li> create subclass of ApplicationConfig, where in constructor you call
- * addAliases, setConfigFileName, setDefaultActionPackage, setDefaultActionClass, setDefaultActionMethod
+ *
+ * <h3>Usage</h3>
+ * Create subclass of {@link ApplicationConfig}, where in constructor you call
+ * {@link #addAlias(String, String[])}, {@link #setConfigFileName(String)}
* to have properly value.
- * <p/>
- * <li> conf = new MonAppConfig();
- * <li> conf.parse(args);
- * <li> here you can used conf.getOption(key);
- * <li> conf.doAction(0);
- * <li> ...
- * <li> conf.doAction(n);
- * <p/>
- * <h1>Lecture des fichiers de configuration</h1>
- * <p/>
- * <p/>
+ * <pre>
+ * conf = new MonAppConfig();
+ * conf.parse(args);
+ * here you can used conf.getOption(key);
+ * conf.doAction(0);
+ * ...
+ * conf.doAction(n);
+ * </pre>
+ *
+ * <h3>Lecture des fichiers de configuration</h3>
+ *
* La lecture des fichiers de configuration se fait durant l'appel de la methode
* {@link #parse} en utilisant la valeur de {@link #getConfigFileName} pour
* trouver les fichiers (voir Les options de configuration pour l'ordre de
* chargement des fichiers)
- * <p/>
- * <h1>La sauvegarde</h1>
- * <p/>
- * <p/>
- * La sauvegarde des options se fait via une des trois methodes disponible
- * <p/>
+ *
+ * <h3>La sauvegarde</h3>
+ * La sauvegarde des options se fait via une des trois methodes disponibles :
* <ul>
* <li> {@link #save(File, boolean,String[])} sauve les données dans le fichier demandé
* <li> {@link #saveForSystem} sauvegarde les donnees dans /etc
* <li> {@link #saveForUser} sauvegarde les donnees dans $HOME
* </ul>
- * <p/>
- * Lors de l'utilisation de la methode {@link #saveForSystem(String[])} ou
- * {@link #saveForUser(String[])} seul les options lu dans un fichier ou modifier par
- * programmation ({@link #setOption} seront sauvegardees. Par exemple les
+ *
+ * Lors de l'utilisation de la methode {@link #saveForSystem} ou
+ * {@link #saveForUser} seules les options lues dans un fichier ou modifiées par
+ * programmation ({@link #setOption} seront sauvegardées. Par exemple les
* options passees sur la ligne de commande ne seront pas sauvees.
- * <p/>
- * <h1>Les options de configuration</h1>
- * <p/>
- * <p/>
+ *
+ * <h3>Les options de configuration</h3>
+ *
* Cette classe permet de lire les fichiers de configuration, utiliser les
* variable d'environnement et de parser la ligne de commande. L'ordre de prise
- * en compte des informations trouvées est la suivante (le premier le plus
- * important).
- * <p/>
+ * en compte des informations trouvées est le suivant (le premier le plus
+ * important) :
* <ul>
- * <li>options ajoutees par programmation: {@link #setOption}(key, value)</li>
+ * <li>options ajoutees par programmation: {@link #setOption(String, String)}</li>
* <li>ligne de commande</li>
* <li>variable d'environnement de la JVM: java -Dkey=value</li>
* <li>variable d'environnement; export key=value</li>
@@ -121,14 +117,14 @@
* <li>fichier de configuration trouve dans le classpath: $CLASSPATH/filename</li>
* <li>options ajoutees par programmation: {@link #defaults}.put(key, value)</li>
* </ul>
- * <p/>
- * <p/>
+ *
+ *
* Les options sur la ligne de commande sont de la forme:
* <pre>
* --option key value
* --monOption key value1 value2
* </pre>
- * <p/>
+ *
* <ul>
* <li>--option key value: est la syntaxe par defaut
* <li>--monOption key value1 value2: est la syntaxe si vous avez ajouter une
@@ -137,16 +133,15 @@
* arguments que vous souhaitez du moment qu'ils soient convertibles de la
* representation String vers le type que vous avez mis.
* </ul>
- * <p/>
- * <h1>Les actions</h1>
- * <p/>
- * Les actions ne peuvent etre que sur la ligne de commande. Ils sont de la
+ *
+ * <h3>Les actions</h3>
+ *
+ * Les actions ne peuvent etre que sur la ligne de commande. Elles sont de la
* forme:
* <pre>
* --le.package.LaClass#laMethode arg1 arg2 arg3 ... argN
* </pre>
- * <p/>
- * <p/>
+ *
* Une action est donc defini par le chemin complet vers la methode qui traitera
* l'action. Cette methode peut-etre une methode static ou non. Si la methode
* n'est pas static lors de l'instanciation de l'objet on essaie de passer en
@@ -158,40 +153,32 @@
* parties d'un meme objet utiliseront la meme instance de cette objet lors
* de leur execution.
* <p/>
- * <p/>
* Si la methode utilise les arguments variants alors tous les arguments
* jusqu'au prochain -- ou la fin de la ligne de commande sont utilises. Sinon
* Le nombre exact d'argument necessaire a la methode sont utilises.
* <p/>
- * <p/>
* Les arguments sont automatiquement converti dans le bon type reclame par la
* methode.
* <p/>
- * <p/>
* Si l'on veut des arguments optionnels le seul moyen actuellement est
* d'utiliser une methode avec des arguments variants
* <p/>
- * <p> Les actions ne sont pas execute mais seulement parsees. Pour les executer
- * il faut utiilser la methode {@link #doAction} qui prend en argument un numero
+ * Les actions ne sont pas execute mais seulement parsees. Pour les executer
+ * il faut utiliser la méthode {@link #doAction} qui prend en argument un numero
* de 'step'. Par defaut toutes les actions sont de niveau 0 et sont executee
* dans l'ordre d'apparition sur la ligne de commande. Si l'on souhaite
* distinguer les actions il est possible d'utiliser l'annotation
* {@link ApplicationConfig.Action.Step} sur la methode qui fera l'action en
* precisant une autre valeur que 0.
- * <p/>
* <pre>
* doAction(0);
* ... do something ...
* doAction(1);
* </pre>
- * <p/>
- * <p/>
* dans cette exemple on fait un traitement entre l'execution des actions
* de niveau 0 et les actions de niveau 1.
- * <p/>
- * <h1>Les arguments non parses</h1>
- * <p/>
- * <p/>
+ *
+ * <h3>Les arguments non parsées</h3>
* Tout ce qui n'est pas option ou action est considere comme non parse et peut
* etre recupere par la methode {@link #getUnparsed}. Si l'on souhaite forcer
* la fin du parsing de la ligne de commande il est possible de mettre --.
@@ -199,45 +186,36 @@
* <pre>
* monProg "mon arg" --option k1 v1 -- --option k2 v2 -- autre
* </pre>
- * <p/>
- * <p/>
* Dans cet exemple seule la premiere option sera considere comme une option.
- * On retrouvera dans unparsed: "mon arg", "--option", "k2", "v2", "--", "autre"
- * <p/>
- * <h1>Les alias</h1>
- * <p/>
+ * On retrouvera dans {@code unparsed}: "mon arg", "--option", "k2", "v2", "--",
+ * "autre"
+ *
+ * <h3>Les alias</h3>
* On voit qu'aussi bien pour les actions que pour les options, le nom de la
* methode doit etre utilise. Pour eviter ceci il est possible de definir
* des alias ce qui permet de creer des options courtes par exemple. Pour cela,
* on utilise la methode {@link #addAlias}.
- * <p/>
* <pre>
* addAlias("-v", "--option", "verbose", "true");
* addAlias("-o", "--option", "outputfile");
* addAlias("-i", "--mon.package.MaClass#MaMethode", "import");
* </pre>
- * <p/>
- * <p/>
* En faite avant le parsing de la ligne de commande tous les alias trouves sont
* automatiquement remplacer par leur correspondance. Il est donc possible
* d'utiliser ce mecanisme pour autre chose par exemple:
- * <p/>
* <pre>
* addAlias("cl", "Code Lutin");
* addAlias("bp", "Benjamin POUSSIN);
* </pre>
- * <p/>
- * <p/>
* Dans le premier exemple on simplifie une option de flags l'option -v n'attend
* donc plus d'argument. Dans le second exemple on simplifie une option qui
* attend encore un argment de type File. Enfin dans le troisieme exemple
* on simplifie la syntaxe d'une action et on force le premier argument de
* l'action a etre "import".
- * <p/>
- * <h1>Conversion de type</h1>
- * Pour la conversion de type nous utilisons common-beans. Les types supporte
+ *
+ * <h3>Conversion de type</h3>
+ * Pour la conversion de type nous utilisons common-beans. Les types supportes
* sont:
- * <p/>
* <ul>
* <li> les primitif (byte, short, int, long, float, double, char, boolean)
* <li> String
@@ -250,29 +228,44 @@
* <li> les tableaux d'un type primitif ou String. Chaque element doit etre
* separe par une virgule
* </ul>
+ *
+ * Pour suporter d'autre type, il vous suffit d'enregistrer de nouveau
+ * converter dans commons-beans.
+ *
+ * <h3>Les substitutions de variable</h3>
+ * {@link ApplicationConfig} supporte les substition de variables de la forme
+ * <tt>${xxx}</tt> où {@code xxx} est une autre variable de la configuration.
* <p/>
- * Pour suporter d'autre type, il vous suffit d'enregistrer de nouveau
- * converter dans commons-beans
- *
+ * Exemple (dans un fichier de configuration):
+ * <pre>
+ * firstname = John
+ * lastname = Doe
+ * fullname = ${firstname} ${lastname}
+ * </pre>
+ * <tt>getOption("fullname")</tt> retournera <tt>"John Doe"</tt>.
+ *
* @author poussin
* @version $Revision$
* @since 0.30
- * <p/>
- * Last update $Date$
- * by $Author$
+ *
+ * <p/>
+ * Last update $Date$ by $Author$
*/
public class ApplicationConfig {
/** to use log facility, just put in your code: log.info(\"...\"); */
static private Log log = LogFactory.getLog(ApplicationConfig.class);
- /**
- * used to know what is separator between la class et la method sur la
- * ligne de commande
- */
+
+ /** Used to know what is separator between class and method on command line. */
static final private String CLASS_METHOD_SEPARATOR = "#";
+
+ /** Configuration file key option. */
static final public String CONFIG_FILE_NAME = "config.file";
+
protected boolean useOnlyAliases = false;
+
protected Map<String, List<String>> aliases = new HashMap<String, List<String>>();
+
/** file /etc/[filename] */
String systemPath = File.separator + "etc" + File.separator;
/** file $user.home/.[filename] */
@@ -280,8 +273,10 @@
String userPath = getUserHome() + File.separator + ".";
/** file $user.home/.local/[filename] */
//String userPath2 = getUserHome() + File.separator + ".config" + File.separator;
- /** vrai si on est en train de parser les options de la ligne de commande */
+
+ /** vrai si on est en train de parser les options de la ligne de commande. */
protected boolean inParseOptionPhase = false;
+
protected Properties defaults = new Properties();
protected Properties classpath = new Properties(defaults);
protected Properties etcfile = new Properties(classpath);
@@ -296,7 +291,8 @@
/** contient apres l'appel de parse, la liste des arguments non utilises */
protected List<String> unparsed = new ArrayList<String>();
protected Map<Integer, List<Action>> actions = new HashMap<Integer, List<Action>>();
- /** suport of config modification */
+
+ /** suport of config modification. */
protected PropertyChangeSupport pcs = new PropertyChangeSupport(this);
/**
@@ -384,17 +380,31 @@
}
}
+ /**
+ * Init ApplicationConfig with current simple class name as config file.
+ *
+ * Also init converters.
+ * @see ConverterUtil#initConverters()
+ */
public ApplicationConfig() {
setConfigFileName(this.getClass().getSimpleName());
// init extra-converters
ConverterUtil.initConverters();
}
+ /**
+ * Get user home directory (system property {@code user.home}).
+ * @return user home directory
+ */
static public String getUserHome() {
String result = System.getProperty("user.home");
return result;
}
+ /**
+ * Get user name (system property {@code user.name}).
+ * @return user name
+ */
public String getUsername() {
String result = getOption("user.name");
return result;
@@ -412,7 +422,7 @@
}
/**
- * Save configuration, in specified file
+ * Save configuration, in specified file.
*
* @param file file where config will be writen
* @param forceAll if true save all config option
@@ -515,6 +525,18 @@
}
}
+ /**
+ * Do action in specified step.
+ *
+ * @param step do action only defined in this step
+ *
+ * @throws IllegalAccessException
+ * @throws IllegalArgumentException
+ * @throws InvocationTargetException
+ * @throws InstantiationException
+ *
+ * @see Action.Step
+ */
public void doAction(int step) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
List<Action> list = actions.get(step);
if (list != null) {
@@ -533,7 +555,7 @@
}
/**
- * All argument in aliases as key is substitued by target
+ * All argument in aliases as key is substitued by target.
*
* @param alias alias string as '-v'
* @param target substitution as '--option verbose true'
@@ -564,13 +586,17 @@
setDefaultOption(CONFIG_FILE_NAME, name);
}
+ /**
+ * Get name of file where options are read (in /etc, $HOME, $CURDIR).
+ * @return name of file
+ */
public String getConfigFileName() {
String result = getOption(CONFIG_FILE_NAME);
return result;
}
/**
- * Set option value
+ * Set option value.
*
* @param key property key
* @param value property value
@@ -584,7 +610,9 @@
}
/**
- * get option value as string
+ * get option value as string.
+ *
+ * Replace inner ${xxx} value.
*
* @param key the option's key
* @return String representation value
@@ -643,7 +671,7 @@
/**
* Permet de recuperer l'ensemble des options commencant par une certaine
- * chaine
+ * chaine.
*
* @param prefix debut de cle a recuperer
* @return la liste des options filtrées
@@ -661,7 +689,7 @@
}
/**
- * get option value from a option definition
+ * Get option value from a option definition.
*
* @param key the definition of the option
* @return the value for the given option
@@ -672,14 +700,13 @@
}
/**
- * get option value as typed value
+ * Get option value as typed value.
*
* @param <T> type of the object wanted as return type
* @param clazz type of object wanted as return type
* @param key the option's key
* @return typed value
*/
- @SuppressWarnings("unchecked")
public <T> T getOption(Class<T> clazz, String key) {
T result = null;
String cacheKey = key + "-" + clazz.getName();
@@ -695,7 +722,7 @@
if (cacheItem == null || cacheItem.hash != hash) {
// prefer use our convertert method (auto-register more converters)
result = ConverterUtil.convert(clazz, value);
-// result = (T) ConvertUtils.convert(value, clazz);
+ // result = (T) ConvertUtils.convert(value, clazz);
cacheItem = new CacheItem<T>(result, hash);
cacheOption.put(cacheKey, cacheItem);
} else {
@@ -706,10 +733,10 @@
}
/**
- * get option value as typed value
+ * Get option value as {@link File}.
*
* @param key the option's key
- * @return typed value
+ * @return value as file
*/
public File getOptionAsFile(String key) {
File result = getOption(File.class, key);
@@ -718,10 +745,10 @@
}
/**
- * get option value as typed value
+ * Get option value as {@link URL}.
*
* @param key the option's key
- * @return typed value
+ * @return value as URL
*/
public URL getOptionAsURL(String key) {
URL result = getOption(URL.class, key);
@@ -729,10 +756,10 @@
}
/**
- * get option value as typed value
+ * Get option value as {@link Class}.
*
* @param key the option's key
- * @return typed value
+ * @return value as Class
*/
public Class<?> getOptionAsClass(String key) {
Class<?> result = getOption(Class.class, key);
@@ -740,10 +767,10 @@
}
/**
- * get option value as typed value
+ * Get option value as {@link Date}.
*
* @param key the option's key
- * @return typed value
+ * @return value as Date
*/
public Date getOptionAsDate(String key) {
Date result = getOption(Date.class, key);
@@ -751,10 +778,10 @@
}
/**
- * get option value as typed value
+ * Get option value as {@link Time}.
*
* @param key the option's key
- * @return typed value
+ * @return value as Time
*/
public Time getOptionAsTime(String key) {
Time result = getOption(Time.class, key);
@@ -762,10 +789,10 @@
}
/**
- * get option value as typed value
+ * Get option value as {@link Timestamp}.
*
* @param key the option's key
- * @return typed value
+ * @return value as Timestamp
*/
public Timestamp getOptionAsTimestamp(String key) {
Timestamp result = getOption(Timestamp.class, key);
@@ -773,10 +800,10 @@
}
/**
- * get option value as typed value
+ * Get option value as {@code int}.
*
* @param key the option's key
- * @return typed value
+ * @return value as {@code int}
*/
public int getOptionAsInt(String key) {
Integer result = getOption(Integer.class, key);
@@ -784,10 +811,10 @@
}
/**
- * get option value as typed value
+ * Get option value as {@code double}.
*
* @param key the option's key
- * @return typed value
+ * @return value as {@code double}
*/
public double getOptionAsDouble(String key) {
Double result = getOption(Double.class, key);
@@ -795,10 +822,10 @@
}
/**
- * get option value as typed value
+ * Get option value as {@code boolean}.
*
* @param key the option's key
- * @return typed value
+ * @return value as {@code boolean}.
*/
public boolean getOptionAsBoolean(String key) {
Boolean result = getOption(Boolean.class, key);
@@ -816,7 +843,7 @@
/**
* Set manually options when you don't want to use parse method to check
- * properties file configured by setConfigFileName.
+ * properties file configured by {@link #setConfigFileName}.
*
* @param options Properties which contains all options to set
*/
@@ -825,7 +852,7 @@
}
/**
- * Get all set method on this object or super object
+ * Get all set method on this object or super object.
*
* @return map with method name without set and in lower case as key, and
* method as value
@@ -962,7 +989,6 @@
*
* @param args argument as main(String[] args)
* @throws ArgumentsParserException
- *
*/
public void parse(String[] args) throws ArgumentsParserException {
try {
Property changes on: trunk/src/main/java/org/nuiton/util/ApplicationConfig.java
___________________________________________________________________
Deleted: svn:mergeinfo
-
Added: svn:keywords
+ Author Date Id Revision HeadURL
Modified: trunk/src/main/java/org/nuiton/util/ArgumentsParserException.java
===================================================================
--- trunk/src/main/java/org/nuiton/util/ArgumentsParserException.java 2010-02-21 19:37:40 UTC (rev 1766)
+++ trunk/src/main/java/org/nuiton/util/ArgumentsParserException.java 2010-02-23 10:38:40 UTC (rev 1767)
@@ -18,7 +18,7 @@
package org.nuiton.util;
/**
- * Argument parsing exception
+ * Argument parsing exception.
*
* @author Benjamin Poussin <poussin(a)codelutin.com>
* Copyright Code Lutin
@@ -32,10 +32,21 @@
/** serialVersionUID. */
private static final long serialVersionUID = 8265924907001359910L;
+ /**
+ * Constructs a new exception with the specified detail message.
+ *
+ * @param msg message
+ */
public ArgumentsParserException(String msg) {
super(msg);
}
+ /**
+ * Constructs a new exception with the specified detail message and cause.
+ *
+ * @param msg message
+ * @param eee cause
+ */
public ArgumentsParserException(String msg, Throwable eee) {
super(msg, eee);
}
Property changes on: trunk/src/main/java/org/nuiton/util/ArgumentsParserException.java
___________________________________________________________________
Deleted: svn:mergeinfo
-
Deleted: svn:eol-style
- native
1
0
r1766 - in trunk/src: main/java/org/nuiton/util/beans test/java/org/nuiton/util/beans
by tchemit@users.nuiton.org 21 Feb '10
by tchemit@users.nuiton.org 21 Feb '10
21 Feb '10
Author: tchemit
Date: 2010-02-21 20:37:40 +0100 (Sun, 21 Feb 2010)
New Revision: 1766
Modified:
trunk/src/main/java/org/nuiton/util/beans/Binder.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/BinderTest.java
Log:
- Binder : if copy from a null source, just reset target properties
- Binder : treate primitive type case nullity
Modified: trunk/src/main/java/org/nuiton/util/beans/Binder.java
===================================================================
--- trunk/src/main/java/org/nuiton/util/beans/Binder.java 2010-02-21 19:36:18 UTC (rev 1765)
+++ trunk/src/main/java/org/nuiton/util/beans/Binder.java 2010-02-21 19:37:40 UTC (rev 1766)
@@ -19,7 +19,12 @@
package org.nuiton.util.beans;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.nuiton.util.ObjectUtil;
+
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.Map;
import java.util.TreeMap;
@@ -41,6 +46,10 @@
*/
public class Binder<I, O> implements java.io.Serializable {
+ /**
+ * Logger
+ */
+ private static final Log log = LogFactory.getLog(Binder.class);
private static final long serialVersionUID = 1L;
@@ -56,23 +65,34 @@
* <b>Note:</b> If a property's value is null, it will not be injected in
* the result.
*
- * @param from the bean to read
+ * @param source the bean to read
* @return the map of properties obtained indexed by their property name,
* or an empty map is the given {@code from} is {@code null}.
*/
- public Map<String, Object> obtainProperties(I from) {
- if (from == null) {
+ public Map<String, Object> obtainProperties(I source) {
+ if (source == null) {
// special limit case
return java.util.Collections.emptyMap();
}
Map<String, Object> result = new TreeMap<String, Object>();
- for (String srcProperty : model.getSourceDescriptors()) {
+ for (String sourceProperty : model.getSourceDescriptors()) {
try {
Object read;
- read = model.getSourceReadMethod(srcProperty).invoke(from);
+ Method readMethod = model.getSourceReadMethod(sourceProperty);
+ read = readMethod.invoke(source);
+ if (log.isDebugEnabled()) {
+ log.debug("property " + sourceProperty + ", type : " +
+ readMethod.getReturnType() + ", value = " + read);
+ }
+ if (readMethod.getReturnType().isPrimitive() &&
+ ObjectUtil.getNullValue(
+ readMethod.getReturnType()).equals(read)) {
+ // for primitive type case, force nullity
+ read = null;
+ }
if (read != null) {
- result.put(srcProperty, read);
+ result.put(sourceProperty, read);
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
@@ -86,20 +106,39 @@
/**
* Copy properties from a source bean to a destination one according to
* the model of the binder.
+ * <p/>
+ * <b>Note:</b> If {@code from} object is null, then {@code null} values
+ * will be set to mapped properties into {@code dst}
*
- * @param from the bean to read
- * @param dst the bean to write
+ * @param source the bean to read
+ * @param target the bean to write
+ * @throws NullPointerException if target parameter is {@code null}
*/
- public void copy(I from, O dst) {
+ public void copy(I source, O target) throws NullPointerException {
+ if (target == null) {
+ throw new NullPointerException("parameter 'target' can no be null");
+ }
+ for (String sourceProperty : model.getSourceDescriptors()) {
- for (String srcProperty : model.getSourceDescriptors()) {
+ String targetProperty = model.getTargetProperty(sourceProperty);
- String dstProperty = model.getTargetProperty(srcProperty);
-
try {
- Object read =
- model.getSourceReadMethod(srcProperty).invoke(from);
- model.getTargetWriteMethod(dstProperty).invoke(dst, read);
+ Object read = null;
+ Method readMethod = model.getSourceReadMethod(sourceProperty);
+ if (source != null) {
+ // obtain value from source
+ read = readMethod.invoke(source);
+ }
+ // obtain acceptable null value (for primitive types, use
+ // default values).
+ if (read == null) {
+ read = ObjectUtil.getNullValue(readMethod.getReturnType());
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("property " + sourceProperty + ", type : " +
+ readMethod.getReturnType() + ", value = " + read);
+ }
+ model.getTargetWriteMethod(targetProperty).invoke(target, read);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
Modified: trunk/src/test/java/org/nuiton/util/beans/BeanA.java
===================================================================
--- trunk/src/test/java/org/nuiton/util/beans/BeanA.java 2010-02-21 19:36:18 UTC (rev 1765)
+++ trunk/src/test/java/org/nuiton/util/beans/BeanA.java 2010-02-21 19:37:40 UTC (rev 1766)
@@ -6,9 +6,14 @@
public static final String PROPERTY_B = "b";
public static final String PROPERTY_C = "c";
public static final String PROPERTY_D = "d";
+ public static final String PROPERTY_E = "e";
+ public static final String PROPERTY_F = "f";
- String a,b,c,d;
+ String a, b, c, d;
+
+ int e, f;
+
public String getA() {
return a;
}
@@ -40,4 +45,20 @@
public void setD(String d) {
this.d = d;
}
+
+ public int getE() {
+ return e;
+ }
+
+ public void setE(int e) {
+ this.e = e;
+ }
+
+ public int getF() {
+ return f;
+ }
+
+ public void setF(int f) {
+ this.f = f;
+ }
}
\ No newline at end of file
Modified: trunk/src/test/java/org/nuiton/util/beans/BeanB.java
===================================================================
--- trunk/src/test/java/org/nuiton/util/beans/BeanB.java 2010-02-21 19:36:18 UTC (rev 1765)
+++ trunk/src/test/java/org/nuiton/util/beans/BeanB.java 2010-02-21 19:37:40 UTC (rev 1766)
@@ -6,9 +6,12 @@
public static final String PROPERTY_B2 = "b2";
public static final String PROPERTY_C2 = "c2";
public static final String PROPERTY_D2 = "d2";
-
+ public static final String PROPERTY_E2 = "e2";
+ public static final String PROPERTY_F2 = "f2";
String a2, b2, c2, d2;
+ int e2,f2;
+
public String getA2() {
return a2;
}
@@ -40,4 +43,20 @@
public void setD2(String d2) {
this.d2 = d2;
}
+
+ public int getE2() {
+ return e2;
+ }
+
+ public void setE2(int e2) {
+ this.e2 = e2;
+ }
+
+ public int getF2() {
+ return f2;
+ }
+
+ public void setF2(int f2) {
+ this.f2 = f2;
+ }
}
\ No newline at end of file
Modified: trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java
===================================================================
--- trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java 2010-02-21 19:36:18 UTC (rev 1765)
+++ trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java 2010-02-21 19:37:40 UTC (rev 1766)
@@ -32,22 +32,26 @@
sourceDescriptors = builder.sourceDescriptors;
Assert.assertNotNull(sourceDescriptors);
- Assert.assertEquals(5, sourceDescriptors.size());
+ Assert.assertEquals(7, sourceDescriptors.size());
Assert.assertTrue(sourceDescriptors.containsKey(PROPERTY_CLASS));
Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_A));
Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_B));
Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_C));
Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_D));
+ Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_E));
+ Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_F));
targetDescriptors = builder.targetDescriptors;
Assert.assertNotNull(targetDescriptors);
- Assert.assertEquals(5, targetDescriptors.size());
+ Assert.assertEquals(7, targetDescriptors.size());
Assert.assertTrue(targetDescriptors.containsKey(PROPERTY_CLASS));
Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_A));
Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_B));
Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_C));
Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_D));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_F));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_F));
Assert.assertEquals(BeanA.class, builder.getModel().getSourceType());
Assert.assertEquals(BeanA.class, builder.getModel().getTargetType());
@@ -86,25 +90,31 @@
sourceDescriptors = builder.sourceDescriptors;
Assert.assertNotNull(sourceDescriptors);
- Assert.assertEquals(5, sourceDescriptors.size());
+ Assert.assertEquals(7, sourceDescriptors.size());
Assert.assertTrue(sourceDescriptors.containsKey(PROPERTY_CLASS));
Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_A));
Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_B));
Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_C));
Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_D));
+ Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_E));
+ Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_F));
targetDescriptors = builder.targetDescriptors;
Assert.assertNotNull(targetDescriptors);
- Assert.assertEquals(9, targetDescriptors.size());
+ Assert.assertEquals(13, targetDescriptors.size());
Assert.assertTrue(targetDescriptors.containsKey(PROPERTY_CLASS));
Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_A));
Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_B));
Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_C));
Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_D));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_E));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_F));
Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_A2));
Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_B2));
Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_C2));
Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_D2));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_E2));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_F2));
Assert.assertEquals(BeanA.class, builder.getModel().getSourceType());
Assert.assertEquals(BeanB.class, builder.getModel().getTargetType());
Modified: trunk/src/test/java/org/nuiton/util/beans/BinderTest.java
===================================================================
--- trunk/src/test/java/org/nuiton/util/beans/BinderTest.java 2010-02-21 19:36:18 UTC (rev 1765)
+++ trunk/src/test/java/org/nuiton/util/beans/BinderTest.java 2010-02-21 19:37:40 UTC (rev 1766)
@@ -14,6 +14,7 @@
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() {
@@ -29,7 +30,9 @@
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_C, BeanB.PROPERTY_C2).
+ addProperty(BeanA.PROPERTY_E, BeanB.PROPERTY_E2)
+ );
}
@@ -97,17 +100,27 @@
a.setA(VALUE_A);
a.setB(VALUE_B);
a.setC(VALUE_C);
+ a.setE(VALUE_E);
binderA.copy(a, b);
Assert.assertEquals(VALUE_A, b.getA());
Assert.assertNull(b.getB());
Assert.assertNull(b.getB2());
Assert.assertNull(b.getC());
+ Assert.assertEquals(0,b.getE2());
binderB.copy(a, b);
Assert.assertEquals(VALUE_A, b.getA());
Assert.assertEquals(VALUE_B, b.getB());
Assert.assertNull(b.getC());
Assert.assertEquals(VALUE_C, b.getC2());
+ Assert.assertEquals(VALUE_E, b.getE2());
+
+ binderB.copy(null, b);
+ Assert.assertNull(b.getA());
+ Assert.assertNull(b.getB());
+ Assert.assertNull(b.getC2());
+ Assert.assertEquals(0,b.getE2());
+
}
}
\ No newline at end of file
1
0
r1765 - in trunk/src: main/java/org/nuiton/util test/java/org/nuiton/util
by tchemit@users.nuiton.org 21 Feb '10
by tchemit@users.nuiton.org 21 Feb '10
21 Feb '10
Author: tchemit
Date: 2010-02-21 20:36:18 +0100 (Sun, 21 Feb 2010)
New Revision: 1765
Modified:
trunk/src/main/java/org/nuiton/util/ObjectUtil.java
trunk/src/test/java/org/nuiton/util/ObjectUtilTest.java
Log:
add GetNullValue and isNullValue methods in Objectutil to deal thim primitive types nullity (as their default value)
Modified: trunk/src/main/java/org/nuiton/util/ObjectUtil.java
===================================================================
--- trunk/src/main/java/org/nuiton/util/ObjectUtil.java 2010-02-21 18:16:09 UTC (rev 1764)
+++ trunk/src/main/java/org/nuiton/util/ObjectUtil.java 2010-02-21 19:36:18 UTC (rev 1765)
@@ -33,6 +33,7 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
+import org.apache.commons.beanutils.MethodUtils;
import static org.nuiton.i18n.I18n._;
import org.apache.commons.logging.Log;
@@ -50,6 +51,13 @@
/** to use log facility, just put in your code: log.info(\"...\"); */
static private Log log = LogFactory.getLog(ObjectUtil.class);
+ protected static final Integer ZERO = 0;
+ protected static final Character ZEROC = (char)0;
+ protected static final Float ZEROF = 0f;
+ protected static final Long ZEROL = 0l;
+ protected static final Double ZEROD = 0.;
+ protected static final Byte ZEROB = 0;
+
/**
* ObjectUtil constructor
* private because of this class is a static class : nobody
@@ -398,5 +406,111 @@
return b?Boolean.TRUE:Boolean.FALSE;
}
+ /**
+ * Obtains the null value for the given type (works too with primitive
+ * types).
+ *
+ * @param type the type to test
+ * @return the {@code null} value or default value for primitive types
+ * @since 1.1.5
+ */
+ public static Object getNullValue(Class<?> type) {
+ if (type == null) {
+ throw new NullPointerException("parameter 'type' can not be null");
+ }
+ if (type.isPrimitive()) {
+ type = MethodUtils.getPrimitiveWrapper(type);
+ if (Boolean.class.isAssignableFrom(type)) {
+ return Boolean.FALSE;
+ }
+ if (Integer.class.isAssignableFrom(type)) {
+ return ZERO;
+ }
+ if (Character.class.isAssignableFrom(type)) {
+ return ZEROC;
+ }
+ if (Float.class.isAssignableFrom(type)) {
+ return ZEROF;
+ }
+ if (Long.class.isAssignableFrom(type)) {
+ return ZEROL;
+ }
+ if (Double.class.isAssignableFrom(type)) {
+ return ZEROD;
+ }
+ if (Byte.class.isAssignableFrom(type)) {
+ return ZEROB;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Tests if the given value is null according to default value for
+ * primitive types if nedded.
+ *
+ * @param value the value to test
+ * @return {@code true} if value is null or default value on a primitive
+ * @since 1.1.5
+ */
+ public static boolean isNullValue(Object value) {
+ if (value == null) {
+ return true;
+ }
+ Class<?> type = value.getClass();
+
+ //FIXME-TC20100212 : this case can not be, due to auto-boxing mecanism
+ if (type.isPrimitive()) {
+ type = MethodUtils.getPrimitiveWrapper(type);
+
+ if (Boolean.class.isAssignableFrom(type)) {
+ return Boolean.FALSE.equals(value);
+ }
+ if (Integer.class.isAssignableFrom(type)) {
+ return ZERO.equals(value);
+ }
+ if (Character.class.isAssignableFrom(type)) {
+ return ZEROC.equals(value);
+ }
+ if (Float.class.isAssignableFrom(type)) {
+ return ZEROF.equals(value);
+ }
+ if (Long.class.isAssignableFrom(type)) {
+ return ZEROL.equals(value);
+ }
+ if (Double.class.isAssignableFrom(type)) {
+ return ZEROD.equals(value);
+ }
+ if (Byte.class.isAssignableFrom(type)) {
+ return ZEROB.equals(value);
+ }
+ }
+ return false;
+ }
+
+ public static boolean isNullValue(boolean value) {
+ return Boolean.FALSE.equals(value);
+ }
+
+ public static boolean isNullValue(byte value) {
+ return value == ZEROB;
+ }
+
+ public static boolean isNullValue(int value) {
+ return value == ZEROB;
+ }
+
+ public static boolean isNullValue(char value) {
+ return value == ZEROC;
+ }
+
+ public static boolean isNullValue(float value) {
+ return value == ZEROF;
+ }
+
+ public static boolean isNullValue(double value) {
+ return value == ZEROD;
+ }
+
} // ObjectUtil
Modified: trunk/src/test/java/org/nuiton/util/ObjectUtilTest.java
===================================================================
--- trunk/src/test/java/org/nuiton/util/ObjectUtilTest.java 2010-02-21 18:16:09 UTC (rev 1764)
+++ trunk/src/test/java/org/nuiton/util/ObjectUtilTest.java 2010-02-21 19:36:18 UTC (rev 1765)
@@ -35,16 +35,18 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import junit.framework.TestCase;
+import org.junit.Assert;
+import org.junit.Test;
/**
* @author poussin
*
*/
-public class ObjectUtilTest extends TestCase {
+public class ObjectUtilTest extends Assert {
- public void testCall() throws Exception {
+ @Test
+ public void testCall() throws Exception {
Dummy dummy = new Dummy();
List<Method> methods = ObjectUtil.getMethod(Dummy.class, "setfile", true);
@@ -65,7 +67,8 @@
Arrays.asList(dummy.getAllFile()));
}
- public void testCreate() throws Exception {
+@Test
+ public void testCreate() throws Exception {
Object o = ObjectUtil.create("java.lang.StringBuffer");
assertTrue(o != null);
assertTrue(o instanceof StringBuffer);
@@ -78,7 +81,51 @@
assertEquals(new File("/tmp/fileTest"), dummy.getFile());
}
+ @Test
+ public void testGetNullValue() throws Exception {
+ try {
+ assertNull(ObjectUtil.getNullValue(null));
+ fail();
+ } catch (Exception e) {
+ assertTrue(true);
+ }
+
+ assertEquals(false, ObjectUtil.getNullValue(boolean.class));
+ assertEquals(0, ObjectUtil.getNullValue(int.class));
+ assertEquals((char)0, ObjectUtil.getNullValue(char.class));
+ assertEquals(0f, ObjectUtil.getNullValue(float.class));
+ assertEquals(0d, ObjectUtil.getNullValue(double.class));
+ assertEquals((byte)0, ObjectUtil.getNullValue(byte.class));
+
+ assertNull(ObjectUtil.getNullValue(Boolean.class));
+ assertNull(ObjectUtil.getNullValue(Integer.class));
+ assertNull(ObjectUtil.getNullValue(Character.class));
+ assertNull(ObjectUtil.getNullValue(Float.class));
+ assertNull(ObjectUtil.getNullValue(Double.class));
+ assertNull(ObjectUtil.getNullValue(Byte.class));
+ }
+
+ @Test
+ public void testIsNullValue() throws Exception {
+
+ assertTrue(ObjectUtil.isNullValue(null));
+
+ assertTrue(ObjectUtil.isNullValue(false));
+ assertTrue(ObjectUtil.isNullValue(0));
+ assertTrue(ObjectUtil.isNullValue((char) 0));
+ assertTrue(ObjectUtil.isNullValue(0f));
+ assertTrue(ObjectUtil.isNullValue(0d));
+ assertTrue(ObjectUtil.isNullValue((byte)0));
+
+ assertFalse(ObjectUtil.isNullValue(Boolean.FALSE));
+ assertFalse(ObjectUtil.isNullValue(Integer.valueOf(0)));
+ assertFalse(ObjectUtil.isNullValue(Character.valueOf((char) 0)));
+ assertFalse(ObjectUtil.isNullValue(Float.valueOf(0)));
+ assertFalse(ObjectUtil.isNullValue(Double.valueOf(0)));
+ assertFalse(ObjectUtil.isNullValue(Byte.valueOf((byte)0)));
+ }
+
static public class Dummy {
String name;
1
0
r1764 - in trunk/src: main/java/org/nuiton/util main/java/org/nuiton/util/beans test/java/org/nuiton/util test/java/org/nuiton/util/beans
by tchemit@users.nuiton.org 21 Feb '10
by tchemit@users.nuiton.org 21 Feb '10
21 Feb '10
Author: tchemit
Date: 2010-02-21 19:16:09 +0100 (Sun, 21 Feb 2010)
New Revision: 1764
Added:
trunk/src/main/java/org/nuiton/util/beans/
trunk/src/main/java/org/nuiton/util/beans/Binder.java
trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java
trunk/src/main/java/org/nuiton/util/beans/BinderModel.java
trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java
trunk/src/main/java/org/nuiton/util/beans/package-info.java
trunk/src/test/java/org/nuiton/util/beans/
trunk/src/test/java/org/nuiton/util/beans/BeanA.java
trunk/src/test/java/org/nuiton/util/beans/BeanB.java
trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java
trunk/src/test/java/org/nuiton/util/beans/BinderProviderTest.java
trunk/src/test/java/org/nuiton/util/beans/BinderTest.java
Log:
Evolution #309: BeanLoador
Added: trunk/src/main/java/org/nuiton/util/beans/Binder.java
===================================================================
--- trunk/src/main/java/org/nuiton/util/beans/Binder.java (rev 0)
+++ trunk/src/main/java/org/nuiton/util/beans/Binder.java 2010-02-21 18:16:09 UTC (rev 1764)
@@ -0,0 +1,128 @@
+/*
+ * *##% Nuiton utilities library
+ * Copyright (C) 2004 - 2010 CodeLutin
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%*
+ */
+
+package org.nuiton.util.beans;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * A {@code binder} permits to copy some properties from an object to another
+ * one.
+ * <p/>
+ * It is based on a {@link BinderModel} which contains the mapping of properties
+ * to transfert from the source object to the destination object.
+ * <p/>
+ * Use the method {@link #copy(Object, Object)} to transfert properties.
+ * <p/>
+ * Use the method {@link #obtainProperties(Object)} to obtain
+ *
+ * @author tchemit < chemit(a)codelutin.com >
+ * @param <I> the source bean type
+ * @param <O> the destination bean type
+ * @since 1.1.5
+ */
+public class Binder<I, O> implements java.io.Serializable {
+
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * the model of the binder
+ */
+ protected BinderModel<I, O> model;
+
+ /**
+ * Obtain from the given object all properties registred in the binder
+ * model.
+ * <p/>
+ * <b>Note:</b> If a property's value is null, it will not be injected in
+ * the result.
+ *
+ * @param from the bean to read
+ * @return the map of properties obtained indexed by their property name,
+ * or an empty map is the given {@code from} is {@code null}.
+ */
+ public Map<String, Object> obtainProperties(I from) {
+ if (from == null) {
+ // special limit case
+ return java.util.Collections.emptyMap();
+ }
+ Map<String, Object> result = new TreeMap<String, Object>();
+ for (String srcProperty : model.getSourceDescriptors()) {
+
+ try {
+ Object read;
+ read = model.getSourceReadMethod(srcProperty).invoke(from);
+ if (read != null) {
+ result.put(srcProperty, read);
+ }
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Copy properties from a source bean to a destination one according to
+ * the model of the binder.
+ *
+ * @param from the bean to read
+ * @param dst the bean to write
+ */
+ public void copy(I from, O dst) {
+
+ for (String srcProperty : model.getSourceDescriptors()) {
+
+ String dstProperty = model.getTargetProperty(srcProperty);
+
+ try {
+ Object read =
+ model.getSourceReadMethod(srcProperty).invoke(from);
+ model.getTargetWriteMethod(dstProperty).invoke(dst, read);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Get the model of the binder.
+ *
+ * @return the model of the binder
+ */
+ protected BinderModel<I, O> getModel() {
+ return model;
+ }
+
+ /**
+ * Set the model of the binder.
+ *
+ * @param model the model of the binder
+ */
+ protected void setModel(BinderModel<?, ?> model) {
+ this.model = (BinderModel<I, O>) model;
+ }
+}
\ No newline at end of file
Property changes on: trunk/src/main/java/org/nuiton/util/beans/Binder.java
___________________________________________________________________
Added: svn:keywords
+ "Author Date Id Revision HeadURL
Added: trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java
===================================================================
--- trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java (rev 0)
+++ trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java 2010-02-21 18:16:09 UTC (rev 1764)
@@ -0,0 +1,357 @@
+/*
+ * *##% Nuiton utilities library
+ * Copyright (C) 2004 - 2010 CodeLutin
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%*
+ */
+package org.nuiton.util.beans;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * A builder of {@link BinderModel} and {@link Binder}.
+ * <p/>
+ * A {@code binder} permits to copy some properties from a bean to another one.
+ *
+ * @author tchemit < chemit(a)codelutin.com >
+ * @see BinderModel
+ * @see Binder
+ * @since 1.1.5
+ */
+public class BinderBuilder {
+
+ /**
+ * current model used to build the binder
+ */
+ protected BinderModel<?, ?> model;
+ protected Map<String, PropertyDescriptor> sourceDescriptors;
+ protected Map<String, PropertyDescriptor> targetDescriptors;
+
+
+ /**
+ * Creates a new binder model for a mirrored binder (source type = target
+ * type).
+ * <p/>
+ * <b>Note:</b> If a previous model was created, but not released via the
+ * method {@link #createBinder(Class)}, the method will failed.
+ *
+ * @param type the type of source and target
+ * @return the instance of the builder
+ * @throws IllegalStateException if a previous builder model was created
+ * without been released
+ * @throws NullPointerException if a parameter is null
+ */
+ public BinderBuilder createBinderModel(Class<?> type)
+ throws IllegalStateException, NullPointerException {
+ createBinderModel(type, type);
+ return this;
+ }
+
+ /**
+ * Creates a new binder model.
+ * <p/>
+ * <b>Note:</b> If a previous model was created, but not released via the
+ * method {@link #createBinder(Class)}, the method will failed.
+ *
+ * @param sourceType the type of the source
+ * @param targetType the type of the target
+ * @return the instance of the builder
+ * @throws IllegalStateException if a previous builder model was created
+ * without been released
+ * @throws NullPointerException if a parameter is null
+ */
+ public BinderBuilder createBinderModel(Class<?> sourceType,
+ Class<?> targetType)
+ throws IllegalStateException, NullPointerException {
+ if (sourceType == null) {
+ throw new NullPointerException("sourceType can not be null");
+ }
+ if (targetType == null) {
+ throw new NullPointerException("targetType can not be null");
+ }
+
+ if (model != null) {
+ throw new IllegalStateException("there is already a binderModel in " +
+ "construction, release it with the method createBinder " +
+ "before using this method.");
+ }
+
+ // init model
+ model = new BinderModel(sourceType, targetType);
+
+ // obtain src descriptors
+ try {
+ sourceDescriptors = new TreeMap<String, PropertyDescriptor>();
+
+ BeanInfo beanInfo = Introspector.getBeanInfo(model.getSourceType());
+ for (PropertyDescriptor descriptor :
+ beanInfo.getPropertyDescriptors()) {
+ sourceDescriptors.put(descriptor.getName(), descriptor);
+ }
+ } catch (IntrospectionException e) {
+ throw new RuntimeException("Could not obtain bean properties " +
+ "descriptors for source type " + sourceType, e);
+ }
+ // obtain dst descriptors
+ try {
+ targetDescriptors = new TreeMap<String, PropertyDescriptor>();
+
+ BeanInfo beanInfo = Introspector.getBeanInfo(model.getTargetType());
+ for (PropertyDescriptor descriptor :
+ beanInfo.getPropertyDescriptors()) {
+ targetDescriptors.put(descriptor.getName(), descriptor);
+ }
+ } catch (IntrospectionException e) {
+ throw new RuntimeException("Could not obtain bean properties " +
+ "descriptors for target type " + targetType, e);
+ }
+
+ return this;
+ }
+
+ /**
+ * Creates a new binder given using the {@link Binder} type of binder
+ * from the internal binder model
+ * previously created via the method {@code createBinderModel<XXX>} and
+ * then filled with methods {@code addXXX(XXX)}.
+ * <p/>
+ * <b>Note:</b> If no model is present, the method will fail.
+ *
+ * @return the instance of the new buinder.
+ * @throws IllegalStateException if no model was previously created.
+ * @throws NullPointerException if the parameter is {@code null}
+ */
+ public Binder<?, ?> createBinder()
+ throws NullPointerException, IllegalStateException {
+
+ Binder binder = createBinder(Binder.class);
+ return binder;
+ }
+
+ /**
+ * Creates a new binder given his type from the internal binder model
+ * previously created via the method {@code createBinderModel<XXX>} and
+ * then filled with methods {@code addXXX(XXX)}.
+ * <p/>
+ * <b>Note:</b> If no model is present, the method will fail.
+ *
+ * @param binderType the type of binder to instanciate
+ * @param <B> the type of binder to instanciate
+ * @return the instance of the new buinder.
+ * @throws IllegalStateException if no model was previously created.
+ * @throws NullPointerException if the parameter is {@code null}
+ */
+ public <B extends Binder<?, ?>> B createBinder(Class<B> binderType)
+ throws NullPointerException, IllegalStateException {
+ checkModelExists();
+ if (binderType == null) {
+ throw new NullPointerException("binderType can not be null");
+ }
+ try {
+ B binder = binderType.newInstance();
+ binder.setModel(model);
+ return binder;
+ } catch (Exception e) {
+ throw new IllegalStateException("could not instanciate binder " +
+ binderType, e);
+ } finally {
+ // release resources of the model
+ model = null;
+ sourceDescriptors.clear();
+ sourceDescriptors = null;
+ targetDescriptors.clear();
+ targetDescriptors = null;
+ }
+ }
+
+ /**
+ * Add to the binder model some simple properties (says source property name
+ * = target property name).
+ * <p/>
+ * <b>Note:</b> If no model is present, the method will fail.
+ *
+ * @param properties the name of mirrored property
+ * @return the instance of the builder
+ * @throws IllegalStateException if no model was previously created
+ * @throws NullPointerException if a property is {@code null}
+ */
+ public BinderBuilder addSimpleProperties(String... properties)
+ throws IllegalStateException, NullPointerException {
+ checkModelExists();
+ for (String property : properties) {
+ if (property == null) {
+ throw new NullPointerException("parameter 'properties' can " +
+ "not contains a null value");
+ }
+ addProperty0(property, property);
+ }
+ return this;
+ }
+
+ /**
+ * Add to the binder model some simple properties (says source property name
+ * = target property name).
+ * <p/>
+ * <b>Note:</b> If no model is present, the method will fail.
+ *
+ * @param sourceProperty the name of the source property to bind
+ * @param targetProperty the name of the target property to bind
+ * @return the instance of the builder
+ * @throws IllegalStateException if no model was previously created
+ * @throws NullPointerException if a parameter is {@code null}
+ */
+
+ public BinderBuilder addProperty(String sourceProperty,
+ String targetProperty)
+ throws IllegalStateException, NullPointerException {
+ if (sourceProperty == null) {
+ throw new NullPointerException("parameter 'sourceProperty' " +
+ "can not be null");
+ }
+ if (targetProperty == null) {
+ throw new NullPointerException("parameter 'targetProperty' " +
+ "can not be null");
+ }
+ checkModelExists();
+ addProperty0(sourceProperty, targetProperty);
+ return this;
+ }
+
+ /**
+ * Add to the binder model some properties.
+ * <p/>
+ * Parameter {@code sourceAndTargetProperties} must be a array of couple
+ * of {@code sourceProperty}, {@code targetProperty}.
+ * <p/>
+ * Example :
+ * <pre>
+ * builder.addProperties("name","name2","text","text");
+ * </pre>
+ * <p/>
+ * <b>Note:</b> If no model is present, the method will fail.
+ *
+ * @param sourceAndTargetProperties the couple of (sourceProperty -
+ * targetProperty) to bind
+ * @return the instance of the builder
+ * @throws IllegalStateException if no model was previously created
+ * @throws IllegalArgumentException if there is not the same number of
+ * source and target properties
+ * @throws NullPointerException if a parameter is {@code null}
+ */
+ public BinderBuilder addProperties(String... sourceAndTargetProperties)
+ throws IllegalStateException, IllegalArgumentException,
+ NullPointerException {
+ checkModelExists();
+ if (sourceAndTargetProperties.length % 2 != 0) {
+ throw new IllegalArgumentException("must have couple(s) of " +
+ "(sourceProperty,targetProperty) but had " +
+ Arrays.toString(sourceAndTargetProperties));
+ }
+ for (int i = 0, max = sourceAndTargetProperties.length / 2;
+ i < max; i++) {
+ String sourceProperty = sourceAndTargetProperties[2 * i];
+ String targetProperty = sourceAndTargetProperties[2 * i + 1];
+ if (sourceProperty == null) {
+ throw new NullPointerException("parameter " +
+ "'sourceAndTargetProperties' can not contains " +
+ "a null value");
+ }
+ if (targetProperty == null) {
+ throw new NullPointerException("parameter " +
+ "'sourceAndTargetProperties' can not contains " +
+ "a null value");
+ }
+ addProperty0(sourceProperty, targetProperty);
+ }
+ return this;
+ }
+
+
+ protected void addProperty0(String sourceProperty,
+ String targetProperty) {
+ // check srcProperty does not exist
+ if (model.containsSourceProperty(sourceProperty)) {
+ throw new IllegalArgumentException("source property '" +
+ sourceProperty + "' " + " was already registred.");
+ }
+ // check dstProperty does not exist
+ if (model.containsTargetProperty(targetProperty)) {
+ throw new IllegalArgumentException("destination property '" +
+ targetProperty + "' " + " was already registred.");
+ }
+
+ // obtain source descriptor
+ PropertyDescriptor sourceDescriptor =
+ sourceDescriptors.get(sourceProperty);
+ if (sourceDescriptor == null) {
+ throw new IllegalArgumentException("no property '" +
+ sourceProperty + "' " + "found on type " +
+ model.getSourceType());
+ }
+ // check srcProperty is readable
+ Method readMethod = sourceDescriptor.getReadMethod();
+ if (readMethod == null) {
+ throw new IllegalArgumentException("property '" + sourceProperty +
+ "' " + "is not readable on type " + model.getSourceType());
+ }
+
+ // obtain dst descriptor
+ PropertyDescriptor targetDescriptor =
+ targetDescriptors.get(targetProperty);
+ if (targetDescriptor == null) {
+ throw new IllegalArgumentException("no property '" +
+ targetProperty + "' " + "found on type " +
+ model.getTargetType());
+ }
+ // check dstProperty is writable
+ Method writeMethod = sourceDescriptor.getWriteMethod();
+ if (writeMethod == null) {
+ throw new IllegalArgumentException("property '" + targetProperty +
+ "' " + "is not writable on type " + model.getTargetType());
+ }
+
+ // check types are ok
+ Class<?> sourceType = sourceDescriptor.getPropertyType();
+ Class<?> targetType = targetDescriptor.getPropertyType();
+ //TODO-TC20100221 : should check if primitive and boxed it in such case
+ if (sourceType != targetType) {
+ throw new IllegalArgumentException("source property '" +
+ sourceProperty + "' and target property '" +
+ targetProperty + "' are not compatible ( sourceType : " +
+ sourceType + " vs targetType :" + targetType + ')');
+ }
+
+ // safe to add the binding
+ model.addBinding(sourceDescriptor, targetDescriptor);
+ }
+
+ protected void checkModelExists() throws IllegalStateException {
+ if (model == null) {
+ throw new IllegalStateException("there is not model, must " +
+ "create one with createBinderModel method");
+ }
+ }
+
+ protected BinderModel<?, ?> getModel() {
+ return model;
+ }
+}
\ No newline at end of file
Property changes on: trunk/src/main/java/org/nuiton/util/beans/BinderBuilder.java
___________________________________________________________________
Added: svn:keywords
+ "Author Date Id Revision HeadURL
Added: trunk/src/main/java/org/nuiton/util/beans/BinderModel.java
===================================================================
--- trunk/src/main/java/org/nuiton/util/beans/BinderModel.java (rev 0)
+++ trunk/src/main/java/org/nuiton/util/beans/BinderModel.java 2010-02-21 18:16:09 UTC (rev 1764)
@@ -0,0 +1,231 @@
+/*
+ * *##% Nuiton utilities library
+ * Copyright (C) 2004 - 2010 CodeLutin
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%*
+ */
+package org.nuiton.util.beans;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+
+/**
+ * Model of a {@link Binder}.
+ *
+ * @author tchemit < chemit(a)codelutin.com >
+ * @param <S> the source type
+ * @param <T> the target type
+ * @since 1.1.5
+ */
+public class BinderModel<S, T> implements java.io.Serializable {
+
+ /**
+ * source type
+ */
+ protected final Class<S> sourceType;
+ /**
+ * destination type
+ */
+ protected final Class<T> targetType;
+
+ /**
+ * source type descriptors (key are property names)
+ */
+ protected final Map<String, PropertyDescriptor> sourceDescriptors;
+ /**
+ * destination descriptors (key are property names)
+ */
+ protected final Map<String, PropertyDescriptor> targetDescriptors;
+ /**
+ * properties mapping (key are source properties, value are destination
+ * properties)
+ */
+ protected final Map<String, String> propertiesMapping;
+
+ private static final long serialVersionUID = 1L;
+
+ public BinderModel(Class<S> sourceType, Class<T> targetType) {
+ this.sourceType = sourceType;
+ this.targetType = targetType;
+ this.sourceDescriptors = new TreeMap<String, PropertyDescriptor>();
+ this.targetDescriptors = new TreeMap<String, PropertyDescriptor>();
+ this.propertiesMapping = new TreeMap<String, String>();
+ }
+
+ /**
+ * Gets the type of the binder's source.
+ *
+ * @return the type of the source object in the binder
+ */
+ public Class<S> getSourceType() {
+ return sourceType;
+ }
+
+ /**
+ * Gets the type of the binder's destination
+ *
+ * @return the type of the destination object in the binder
+ */
+ public Class<T> getTargetType() {
+ return targetType;
+ }
+
+ /**
+ * Gets all registred property names of the binder's source type.
+ *
+ * @return the array of all source object properties names to bind
+ */
+ public String[] getSourceDescriptors() {
+ Set<String> universe = sourceDescriptors.keySet();
+ return universe.toArray(new String[sourceDescriptors.size()]);
+ }
+
+ /**
+ * Gets all registred property names of the binder's destination type.
+ *
+ * @return the array of all source object properties names to bind
+ */
+ public String[] getTargetDescriptors() {
+ Set<String> universe = targetDescriptors.keySet();
+ return universe.toArray(new String[targetDescriptors.size()]);
+ }
+
+ /**
+ * Gets the destination property name given the
+ *
+ * @param sourceProperty the name of the source property to bind
+ * @return the name of the destination object property to bind, or
+ * {@code null} if {@code propertySrc} is unknown in the model
+ */
+ public String getTargetProperty(String sourceProperty) {
+ if (!containsSourceProperty(sourceProperty)) {
+ return null;
+ }
+ String dstProperty = propertiesMapping.get(sourceProperty);
+ return dstProperty;
+ }
+
+ /**
+ * Gets the bean descriptor of the source type for the given
+ * destination property.
+ *
+ * @param sourceProperty name of the source type property name
+ * @return the descriptor or {@code null} if not found.
+ */
+ public PropertyDescriptor getSourceDescriptor(String sourceProperty) {
+ // check src property is registred
+ if (!containsSourceProperty(sourceProperty)) {
+ return null;
+ }
+ PropertyDescriptor descriptor = sourceDescriptors.get(sourceProperty);
+ return descriptor;
+ }
+
+ /**
+ * @param srcProperty the name of a property of the source object.
+ * @return the method to read in a source object for the given property.
+ */
+ public Method getSourceReadMethod(String srcProperty) {
+ PropertyDescriptor descriptor = getSourceDescriptor(srcProperty);
+ Method readMethod = null;
+ if (descriptor != null) {
+ readMethod = descriptor.getReadMethod();
+ }
+ return readMethod;
+ }
+
+ /**
+ * @param sourceProperty the name of a property of the source object.
+ * @return the method to write in a source object for the given property.
+ */
+ public Method getSourceWriteMethod(String sourceProperty) {
+ PropertyDescriptor descriptor = getSourceDescriptor(sourceProperty);
+ Method writeMethod = null;
+ if (descriptor != null) {
+ writeMethod = descriptor.getWriteMethod();
+ }
+ return writeMethod;
+ }
+
+ /**
+ * Gets the bean descriptor of the destination type for the given
+ * destination property.
+ *
+ * @param targetProperty name of the destination type property name
+ * @return the descriptor or {@code null} if not found.
+ */
+ public PropertyDescriptor getTargetDescriptor(String targetProperty) {
+ // check dst property is registred
+ if (!containsTargetProperty(targetProperty)) {
+ return null;
+ }
+ PropertyDescriptor descriptor = targetDescriptors.get(targetProperty);
+ return descriptor;
+ }
+
+ /**
+ * @param targetProperty the name of a property of the destination object.
+ * @return the method to read in a destination object for the given
+ * property.
+ */
+ public Method getTargetReadMethod(String targetProperty) {
+ PropertyDescriptor descriptor = getTargetDescriptor(targetProperty);
+ Method readMethod = null;
+ if (descriptor != null) {
+ readMethod = descriptor.getReadMethod();
+ }
+ return readMethod;
+ }
+
+ /**
+ * @param targetProperty the name of a property of the destination object.
+ * @return the method to write in a destination object for the given
+ * property.
+ */
+ public Method getTargetWriteMethod(String targetProperty) {
+ PropertyDescriptor descriptor = getTargetDescriptor(targetProperty);
+ Method writeMethod = null;
+ if (descriptor != null) {
+ writeMethod = descriptor.getWriteMethod();
+ }
+ return writeMethod;
+ }
+
+ protected boolean containsSourceProperty(String sourceProperty) {
+ return propertiesMapping.containsKey(sourceProperty);
+ }
+
+ protected boolean containsTargetProperty(String targetProperty) {
+ return propertiesMapping.containsValue(targetProperty);
+ }
+
+ protected void addBinding(PropertyDescriptor sourceDescriptor,
+ PropertyDescriptor targetDescriptor) {
+
+ String sourceProperty = sourceDescriptor.getName();
+ String targetProperty = targetDescriptor.getName();
+ sourceDescriptors.put(sourceProperty, sourceDescriptor);
+ targetDescriptors.put(targetProperty, targetDescriptor);
+ propertiesMapping.put(sourceProperty, targetProperty);
+ }
+
+ protected Map<String, String> getPropertiesMapping() {
+ return propertiesMapping;
+ }
+}
\ No newline at end of file
Property changes on: trunk/src/main/java/org/nuiton/util/beans/BinderModel.java
___________________________________________________________________
Added: svn:keywords
+ "Author Date Id Revision HeadURL
Added: trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java
===================================================================
--- trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java (rev 0)
+++ trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java 2010-02-21 18:16:09 UTC (rev 1764)
@@ -0,0 +1,320 @@
+/*
+ * *##% Nuiton utilities library
+ * Copyright (C) 2004 - 2010 CodeLutin
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%*
+ */
+
+package org.nuiton.util.beans;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Manage a cache of {@link Binder} objects.
+ * <p/>
+ * You must first register some binders via the {@code registerBinder} api.
+ * <pre>
+ * Binder<User,UserDTO> mybinder = ...;
+ * registerBinder(myNewBinder);
+ * </pre>
+ * To use several binders of the the same types, you can moreover specify
+ * a context name of your binder :
+ * <pre>
+ * Binder<User,UserDTO> mybinder = ...;
+ * registerBinder(myBinder, "One");
+ * </pre>
+ * <p/>
+ * Then you can obtained them back via the api
+ * <pre>
+ * Binder<User,UserDTO> mybinder = getBinder(User.class,UserDTO);
+ * </pre>
+ * <p/>
+ * or with a context name :
+ * <pre>
+ * Binder<User,UserDTO> mybinder = getBinder(User.class,UserDTO.class, "One");
+ * </pre>
+ *
+ * @author tchemit < chemit(a)codelutin.com >
+ * @see Binder
+ * @see BinderBuilder
+ * @since 1.1.5
+ */
+public class BinderProvider {
+
+ /**
+ * Logger
+ */
+ private static final Log log = LogFactory.getLog(BinderProvider.class);
+ /**
+ * Cache of registred binders indexed by their unique entry
+ */
+ protected static Map<BinderEntry, Binder> binders;
+
+ /**
+ * Gets the registred mirror binder (source type = target type) with no
+ * context name specified.
+ *
+ * @param sourceType the type of source and target
+ * @param <S> the type of source and target
+ * @return the registred binder or {@code null} if not found.
+ */
+ public static <S> Binder<S, S> getBinder(Class<S> sourceType) {
+ return getBinder(sourceType, sourceType, null);
+ }
+
+ /**
+ * Gets the registred mirror binder (source type = target type) with the
+ * given context name.
+ *
+ * @param sourceType the type of source and target
+ * @param name the context's name of the searched binder
+ * @param <S> the type of source and target
+ * @return the registred binder or {@code null} if not found.
+ */
+ public static <S> Binder<S, S> getBinder(Class<S> sourceType,
+ String name) {
+ return getBinder(sourceType, sourceType, name);
+ }
+
+
+ /**
+ * Gets the registred binder given his types with no context name.
+ *
+ * @param sourceType the type of source
+ * @param targetType the type of target
+ * @param <S> the type of source
+ * @param <T> the type of target
+ * @return the registred binder or {@code null} if not found.
+ */
+ public static <S, T> Binder<S, T> getBinder(Class<S> sourceType,
+ Class<T> targetType) {
+ return getBinder(sourceType, targetType, null);
+ }
+
+ /**
+ * Gets the registred binder given his types and his context's name.
+ *
+ * @param sourceType the type of source
+ * @param targetType the type of target
+ * @param name the context's name of the searched binder
+ * @param <S> the type of source
+ * @param <T> the type of target
+ * @return the registred binder or {@code null} if not found.
+ */
+ public static <S, T> Binder<S, T> getBinder(Class<S> sourceType,
+ Class<T> targetType,
+ String name) {
+ BinderEntry entry = new BinderEntry(sourceType, targetType, name);
+ if (log.isDebugEnabled()) {
+ log.debug("for entry " + entry);
+ }
+ Binder<?, ?> result = getBinders().get(entry);
+ if (result == null) {
+ // binder not found
+ if (log.isWarnEnabled()) {
+ log.warn("Could not find binder " + entry);
+ }
+ }
+ return (Binder<S, T>) result;
+ }
+
+ /**
+ * Register a binder with no context name.
+ * <p/>
+ * <b>Note: </b> If a previous binder with same definition exists, it will
+ * be overriden by the new binder.
+ *
+ * @param binder the binder to register.
+ */
+ public static void registerBinder(Binder<?, ?> binder) {
+ registerBinder(binder, null);
+ }
+
+ /**
+ * Register a binder with no context's name from a {@link BinderBuilder}.
+ * <p/>
+ * <b>Note: </b> If a previous binder with same definition exists, it will
+ * be overriden by the new binder.
+ *
+ * @param builder the builder which contains builder model to use
+ * @see BinderBuilder#createBinder(Class)
+ */
+ public static <B extends Binder> void registerBinder(BinderBuilder builder) {
+ registerBinder(builder, Binder.class);
+ }
+
+ /**
+ * Register a binder with no context's name from a {@link BinderBuilder}.
+ * <p/>
+ * <b>Note: </b> If a previous binder with same definition exists, it will
+ * be overriden by the new binder.
+ *
+ * @param builder the builder which contains builder model to use
+ * @param binderType the type of binder to instanciate and register.
+ * @see BinderBuilder#createBinder(Class)
+ */
+ public static <B extends Binder> void registerBinder(BinderBuilder builder,
+ Class<B> binderType) {
+
+ registerBinder(builder, binderType, null);
+ }
+
+ /**
+ * Register a binder with a context's name from a {@link BinderBuilder}.
+ * <p/>
+ * <b>Note: </b> If a previous binder with same definition exists, it will
+ * be overriden by the new binder.
+ *
+ * @param builder the builder which contains builder model to use
+ * @param name the context's name
+ * @see BinderBuilder#createBinder(Class)
+ */
+ public static <B extends Binder> void registerBinder(BinderBuilder builder,
+ String name) {
+
+ registerBinder(builder, Binder.class, name);
+ }
+
+ /**
+ * Register a binder with a context's name from a {@link BinderBuilder}.
+ * <p/>
+ * <b>Note: </b> If a previous binder with same definition exists, it will
+ * be overriden by the new binder.
+ *
+ * @param builder the builder which contains builder model to use
+ * @param binderType the type of binder to instanciate and register.
+ * @param name the context's name
+ * @see BinderBuilder#createBinder(Class)
+ */
+ public static <B extends Binder> void registerBinder(BinderBuilder builder,
+ Class<B> binderType,
+ String name) {
+ // instanciate the binder
+ B binder = builder.createBinder(binderType);
+ // register it
+ registerBinder(binder, name);
+ }
+
+ /**
+ * Register a binder with a context name.
+ * <p/>
+ * <b>Note: </b> If a previous binder with same definition exists, it will
+ * be overriden by the new binder.
+ *
+ * @param binder the binder to register.
+ * @param name the context's name
+ */
+ public static void registerBinder(Binder<?, ?> binder, String name) {
+ BinderModel<?, ?> model = binder.getModel();
+ BinderEntry entry = new BinderEntry(
+ model.getSourceType(),
+ model.getTargetType(),
+ name
+ );
+ if (log.isDebugEnabled()) {
+ log.debug("binder to seek : " + entry);
+ }
+ Binder oldBinder = getBinders().get(entry);
+ if (oldBinder != null) {
+ // already a binder for this entry
+ if (log.isWarnEnabled()) {
+ log.warn("Binder already registred for " + entry + " : " +
+ oldBinder);
+ log.warn("Will be replace by the new binder " + binder);
+ }
+ }
+ // register the binder
+ if (log.isDebugEnabled()) {
+ log.debug("entry : " + entry + " : " + binder);
+ }
+ getBinders().put(entry, binder);
+ }
+
+ protected static Map<BinderEntry, Binder> getBinders() {
+ if (binders == null) {
+ binders = new HashMap<BinderEntry, Binder>();
+ }
+ return binders;
+ }
+
+ /**
+ * Definition of an binder entry (source and target types + context name).
+ * <p/>
+ * <b>Note :</b>When no context is specified, we always use a
+ * {@code null} context name.
+ */
+ public static class BinderEntry {
+
+ protected final Class<?> sourceType;
+ protected final Class<?> targetType;
+ protected final String name;
+
+
+ public BinderEntry(Class<?> sourceType,
+ Class<?> targetType,
+ String name) {
+ this.sourceType = sourceType;
+ this.targetType = targetType;
+ this.name = name;
+ }
+
+ public Class<?> getSourceType() {
+ return sourceType;
+ }
+
+ public Class<?> getTargetType() {
+ return targetType;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ BinderEntry that = (BinderEntry) o;
+
+ return name == null ? that.name == null : name.equals(that.name) &&
+ sourceType.equals(that.sourceType) &&
+ targetType.equals(that.targetType);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = sourceType.hashCode();
+ result = 31 * result + targetType.hashCode();
+ result = 31 * result + (name != null ? name.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buffer = new StringBuilder("<");
+ buffer.append(super.toString());
+ buffer.append(", sourceType: ").append(getSourceType()).append(',');
+ buffer.append(" targetType: ").append(getTargetType()).append(',');
+ buffer.append(" name: ").append(getName()).append('>');
+
+ return buffer.toString();
+ }
+ }
+}
Property changes on: trunk/src/main/java/org/nuiton/util/beans/BinderProvider.java
___________________________________________________________________
Added: svn:keywords
+ "Author Date Id Revision HeadURL
Added: trunk/src/main/java/org/nuiton/util/beans/package-info.java
===================================================================
--- trunk/src/main/java/org/nuiton/util/beans/package-info.java (rev 0)
+++ trunk/src/main/java/org/nuiton/util/beans/package-info.java 2010-02-21 18:16:09 UTC (rev 1764)
@@ -0,0 +1,6 @@
+/**
+ * Packages for all stuff of bean transformations (binder, and others...).
+ *
+ * @since 1.1.5
+ */
+package org.nuiton.util.beans;
Property changes on: trunk/src/main/java/org/nuiton/util/beans/package-info.java
___________________________________________________________________
Added: svn:keywords
+ "Author Date Id Revision HeadURL
Added: trunk/src/test/java/org/nuiton/util/beans/BeanA.java
===================================================================
--- trunk/src/test/java/org/nuiton/util/beans/BeanA.java (rev 0)
+++ trunk/src/test/java/org/nuiton/util/beans/BeanA.java 2010-02-21 18:16:09 UTC (rev 1764)
@@ -0,0 +1,43 @@
+package org.nuiton.util.beans;
+
+public class BeanA {
+
+ public static final String PROPERTY_A = "a";
+ public static final String PROPERTY_B = "b";
+ public static final String PROPERTY_C = "c";
+ public static final String PROPERTY_D = "d";
+
+ String a,b,c,d;
+
+ public String getA() {
+ return a;
+ }
+
+ public void setA(String a) {
+ this.a = a;
+ }
+
+ public String getB() {
+ return b;
+ }
+
+ public void setB(String b) {
+ this.b = b;
+ }
+
+ public String getC() {
+ return c;
+ }
+
+ public void setC(String c) {
+ this.c = c;
+ }
+
+ public String getD() {
+ return d;
+ }
+
+ public void setD(String d) {
+ this.d = d;
+ }
+}
\ No newline at end of file
Property changes on: trunk/src/test/java/org/nuiton/util/beans/BeanA.java
___________________________________________________________________
Added: svn:keywords
+ "Author Date Id Revision HeadURL
Added: trunk/src/test/java/org/nuiton/util/beans/BeanB.java
===================================================================
--- trunk/src/test/java/org/nuiton/util/beans/BeanB.java (rev 0)
+++ trunk/src/test/java/org/nuiton/util/beans/BeanB.java 2010-02-21 18:16:09 UTC (rev 1764)
@@ -0,0 +1,43 @@
+package org.nuiton.util.beans;
+
+public class BeanB extends BeanA {
+
+ public static final String PROPERTY_A2 = "a2";
+ public static final String PROPERTY_B2 = "b2";
+ public static final String PROPERTY_C2 = "c2";
+ public static final String PROPERTY_D2 = "d2";
+
+ String a2, b2, c2, d2;
+
+ public String getA2() {
+ return a2;
+ }
+
+ public void setA2(String a2) {
+ this.a2 = a2;
+ }
+
+ public String getB2() {
+ return b2;
+ }
+
+ public void setB2(String b2) {
+ this.b2 = b2;
+ }
+
+ public String getC2() {
+ return c2;
+ }
+
+ public void setC2(String c2) {
+ this.c2 = c2;
+ }
+
+ public String getD2() {
+ return d2;
+ }
+
+ public void setD2(String d2) {
+ this.d2 = d2;
+ }
+}
\ No newline at end of file
Property changes on: trunk/src/test/java/org/nuiton/util/beans/BeanB.java
___________________________________________________________________
Added: svn:keywords
+ "Author Date Id Revision HeadURL
Added: trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java
===================================================================
--- trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java (rev 0)
+++ trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java 2010-02-21 18:16:09 UTC (rev 1764)
@@ -0,0 +1,297 @@
+package org.nuiton.util.beans;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.beans.PropertyDescriptor;
+import java.util.Map;
+
+public class BinderBuilderTest {
+
+ private BinderBuilder builder;
+ protected static final String PROPERTY_CLASS = "class";
+
+ @Before
+ public void setUp() {
+
+ builder = new BinderBuilder();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testCreateMirroredBinderModel_NPE() throws Exception {
+ builder.createBinderModel(null);
+ }
+
+ @Test
+ public void testCreateMirroredBinderModel() throws Exception {
+ builder.createBinderModel(BeanA.class);
+ Assert.assertNotNull(builder.getModel());
+ Map<String, PropertyDescriptor> sourceDescriptors;
+ Map<String, PropertyDescriptor> targetDescriptors;
+
+ sourceDescriptors = builder.sourceDescriptors;
+ Assert.assertNotNull(sourceDescriptors);
+ Assert.assertEquals(5, sourceDescriptors.size());
+ Assert.assertTrue(sourceDescriptors.containsKey(PROPERTY_CLASS));
+ Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_A));
+ Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_B));
+ Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_C));
+ Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_D));
+
+
+ targetDescriptors = builder.targetDescriptors;
+ Assert.assertNotNull(targetDescriptors);
+ Assert.assertEquals(5, targetDescriptors.size());
+ Assert.assertTrue(targetDescriptors.containsKey(PROPERTY_CLASS));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_A));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_B));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_C));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_D));
+
+ Assert.assertEquals(BeanA.class, builder.getModel().getSourceType());
+ Assert.assertEquals(BeanA.class, builder.getModel().getTargetType());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testCreateMirroredBinderModel_Twice() throws Exception {
+ builder.createBinderModel(BeanA.class);
+ Assert.assertNotNull(builder.getModel());
+ Assert.assertEquals(BeanA.class, builder.getModel().getSourceType());
+ Assert.assertEquals(BeanA.class, builder.getModel().getTargetType());
+ builder.createBinderModel(BeanA.class);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testCreateBinderModel_NPE() throws Exception {
+ builder.createBinderModel(null, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testCreateBinderModel_NPE2() throws Exception {
+ builder.createBinderModel(BeanA.class, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testCreateBinderModel_NPE3() throws Exception {
+ builder.createBinderModel(null, BeanA.class);
+ }
+
+ @Test
+ public void testCreateBinderModel() throws Exception {
+ builder.createBinderModel(BeanA.class, BeanB.class);
+ Assert.assertNotNull(builder.getModel());
+ Map<String, PropertyDescriptor> sourceDescriptors;
+ Map<String, PropertyDescriptor> targetDescriptors;
+
+ sourceDescriptors = builder.sourceDescriptors;
+ Assert.assertNotNull(sourceDescriptors);
+ Assert.assertEquals(5, sourceDescriptors.size());
+ Assert.assertTrue(sourceDescriptors.containsKey(PROPERTY_CLASS));
+ Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_A));
+ Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_B));
+ Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_C));
+ Assert.assertTrue(sourceDescriptors.containsKey(BeanA.PROPERTY_D));
+
+ targetDescriptors = builder.targetDescriptors;
+ Assert.assertNotNull(targetDescriptors);
+ Assert.assertEquals(9, targetDescriptors.size());
+ Assert.assertTrue(targetDescriptors.containsKey(PROPERTY_CLASS));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_A));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_B));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_C));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanA.PROPERTY_D));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_A2));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_B2));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_C2));
+ Assert.assertTrue(targetDescriptors.containsKey(BeanB.PROPERTY_D2));
+
+ Assert.assertEquals(BeanA.class, builder.getModel().getSourceType());
+ Assert.assertEquals(BeanB.class, builder.getModel().getTargetType());
+
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testCreateBinderModel_Twice() throws Exception {
+ builder.createBinderModel(BeanA.class, BeanB.class);
+ Assert.assertNotNull(builder.getModel());
+ Assert.assertEquals(BeanA.class, builder.getModel().getSourceType());
+ Assert.assertEquals(BeanB.class, builder.getModel().getTargetType());
+ builder.createBinderModel(BeanA.class, BeanB.class);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testCreateBinder_NO_Model() throws Exception {
+ builder.createBinder(Binder.class);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testCreateBinder_NPE() throws Exception {
+ builder.createBinderModel(BeanA.class, BeanB.class);
+ builder.createBinder(null);
+ }
+
+ @Test
+ public void testAddSimpleProperties() throws Exception {
+
+ builder.createBinderModel(BeanA.class);
+ BinderModel<?, ?> model = builder.getModel();
+
+ try {
+ builder.addSimpleProperties((String) null);
+ Assert.fail();
+ } catch (NullPointerException e) {
+ Assert.assertTrue(true);
+ }
+ builder.addSimpleProperties(BeanA.PROPERTY_A);
+ Assert.assertEquals(1, model.getSourceDescriptors().length);
+ Assert.assertEquals(1, model.getTargetDescriptors().length);
+ Map<String, String> map = model.getPropertiesMapping();
+ Assert.assertEquals(1, map.size());
+ Assert.assertTrue(map.containsKey(BeanA.PROPERTY_A));
+ Assert.assertTrue(map.containsValue(BeanA.PROPERTY_A));
+ Assert.assertEquals(BeanA.PROPERTY_A, map.get(BeanA.PROPERTY_A));
+
+ try {
+ builder.addSimpleProperties(BeanA.PROPERTY_A);
+ Assert.fail();
+ } catch (IllegalArgumentException e) {
+ Assert.assertTrue(true);
+ }
+
+ try {
+ builder.addSimpleProperties(BeanB.PROPERTY_A2);
+ Assert.fail();
+ } catch (IllegalArgumentException e) {
+ Assert.assertTrue(true);
+ }
+
+ builder.addSimpleProperties(BeanA.PROPERTY_B);
+ Assert.assertEquals(2, model.getSourceDescriptors().length);
+ Assert.assertEquals(2, model.getTargetDescriptors().length);
+ Assert.assertEquals(2, map.size());
+ Assert.assertTrue(map.containsKey(BeanA.PROPERTY_B));
+ Assert.assertTrue(map.containsValue(BeanA.PROPERTY_B));
+ Assert.assertEquals(BeanA.PROPERTY_B, map.get(BeanA.PROPERTY_B));
+
+ }
+
+ @Test
+ public void testAddProperty() throws Exception {
+ builder.createBinderModel(BeanA.class, BeanB.class);
+ BinderModel<?, ?> model = builder.getModel();
+
+ try {
+ builder.addProperty(null, null);
+ Assert.fail();
+ } catch (NullPointerException e) {
+ Assert.assertTrue(true);
+ }
+ try {
+ builder.addProperty(BeanA.PROPERTY_A, null);
+ Assert.fail();
+ } catch (NullPointerException e) {
+ Assert.assertTrue(true);
+ }
+ try {
+ builder.addProperty(null, BeanA.PROPERTY_A);
+ Assert.fail();
+ } catch (NullPointerException e) {
+ Assert.assertTrue(true);
+ }
+ builder.addProperty(BeanA.PROPERTY_A, BeanA.PROPERTY_A);
+ Assert.assertEquals(1, model.getSourceDescriptors().length);
+ Assert.assertEquals(1, model.getTargetDescriptors().length);
+ Map<String, String> map = model.getPropertiesMapping();
+ Assert.assertEquals(1, map.size());
+ Assert.assertTrue(map.containsKey(BeanA.PROPERTY_A));
+ Assert.assertTrue(map.containsValue(BeanA.PROPERTY_A));
+ Assert.assertEquals(BeanA.PROPERTY_A, map.get(BeanA.PROPERTY_A));
+
+ try {
+ builder.addProperty(BeanB.PROPERTY_A, BeanB.PROPERTY_A2);
+ Assert.fail();
+ } catch (IllegalArgumentException e) {
+ Assert.assertTrue(true);
+ }
+
+ try {
+ builder.addProperty(BeanB.PROPERTY_A2, BeanB.PROPERTY_A);
+ Assert.fail();
+ } catch (IllegalArgumentException e) {
+ Assert.assertTrue(true);
+ }
+
+ builder.addProperty(BeanA.PROPERTY_B, BeanB.PROPERTY_B2);
+ Assert.assertEquals(2, model.getSourceDescriptors().length);
+ Assert.assertEquals(2, model.getTargetDescriptors().length);
+ Assert.assertEquals(2, map.size());
+ Assert.assertTrue(map.containsKey(BeanA.PROPERTY_B));
+ Assert.assertTrue(map.containsValue(BeanB.PROPERTY_B2));
+ Assert.assertEquals(BeanB.PROPERTY_B2, map.get(BeanB.PROPERTY_B));
+ }
+
+ @Test
+ public void testAddProperties() throws Exception {
+ builder.createBinderModel(BeanA.class, BeanB.class);
+
+ try {
+ builder.addProperties(BeanB.PROPERTY_A, BeanB.PROPERTY_A2,
+ BeanB.PROPERTY_B);
+ Assert.fail();
+ } catch (IllegalArgumentException e) {
+ Assert.assertTrue(true);
+ }
+
+ try {
+ builder.addProperties(BeanB.PROPERTY_A, null,
+ BeanB.PROPERTY_B, BeanB.PROPERTY_B);
+ Assert.fail();
+ } catch (NullPointerException e) {
+ Assert.assertTrue(true);
+ }
+
+ builder.addProperties(BeanB.PROPERTY_A, BeanB.PROPERTY_A,
+ BeanB.PROPERTY_B, BeanB.PROPERTY_B2);
+
+ BinderModel<?, ?> model = builder.getModel();
+ Assert.assertEquals(2, model.getSourceDescriptors().length);
+ Assert.assertEquals(2, model.getTargetDescriptors().length);
+ Map<String, String> map = model.getPropertiesMapping();
+ Assert.assertEquals(2, map.size());
+ Assert.assertTrue(map.containsKey(BeanA.PROPERTY_A));
+ Assert.assertTrue(map.containsValue(BeanA.PROPERTY_A));
+ Assert.assertEquals(BeanA.PROPERTY_A, map.get(BeanA.PROPERTY_A));
+
+ Assert.assertTrue(map.containsKey(BeanA.PROPERTY_B));
+ Assert.assertTrue(map.containsValue(BeanB.PROPERTY_B2));
+ Assert.assertEquals(BeanB.PROPERTY_B2, map.get(BeanB.PROPERTY_B));
+ }
+
+ @Test
+ public void testCreateBinder() throws Exception {
+ builder.createBinderModel(BeanA.class, BeanB.class);
+ builder.addProperties(BeanB.PROPERTY_A, BeanB.PROPERTY_A,
+ BeanB.PROPERTY_B, BeanB.PROPERTY_B2);
+
+ Binder<BeanA, BeanB> binder =
+ (Binder<BeanA, BeanB>) builder.createBinder();
+
+ Assert.assertNull(builder.getModel());
+ Assert.assertNull(builder.sourceDescriptors);
+ Assert.assertNull(builder.targetDescriptors);
+
+ BeanA a = new BeanA();
+ BeanB b = new BeanB();
+
+ a.setA("a");
+ a.setB("b");
+ b.setA("a2");
+ b.setB2("b2");
+
+ binder.copy(a, b);
+ Assert.assertEquals("a", b.getA());
+ Assert.assertEquals("b", b.getB2());
+ Assert.assertNull(b.getB());
+ }
+}
\ No newline at end of file
Property changes on: trunk/src/test/java/org/nuiton/util/beans/BinderBuilderTest.java
___________________________________________________________________
Added: svn:keywords
+ "Author Date Id Revision HeadURL
Added: trunk/src/test/java/org/nuiton/util/beans/BinderProviderTest.java
===================================================================
--- trunk/src/test/java/org/nuiton/util/beans/BinderProviderTest.java (rev 0)
+++ trunk/src/test/java/org/nuiton/util/beans/BinderProviderTest.java 2010-02-21 18:16:09 UTC (rev 1764)
@@ -0,0 +1,166 @@
+package org.nuiton.util.beans;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class BinderProviderTest {
+
+ Binder<BeanA, BeanA> binderA;
+ Binder<BeanA, BeanB> binderB;
+ private static final String MY_BINDER_NAME = "myBinder";
+ private static final String MY_BINDER2_NAME = "myBinder2";
+
+ @Before
+ public void setUp() {
+
+ BinderProvider.binders = null;
+
+ BinderBuilder builder = new BinderBuilder();
+ binderA = (Binder<BeanA, BeanA>)
+ builder.createBinderModel(BeanA.class).
+ addSimpleProperties(BeanA.PROPERTY_A).
+ createBinder();
+ binderB = (Binder<BeanA, BeanB>)
+ builder.createBinderModel(BeanA.class, BeanB.class).
+ addSimpleProperties(BeanA.PROPERTY_A, BeanA.PROPERTY_B).
+ addProperty(BeanA.PROPERTY_C, BeanB.PROPERTY_C2).
+ createBinder();
+
+ }
+
+ @Test
+ public void testRegisterBinder() throws Exception {
+
+ Assert.assertNull(BinderProvider.binders);
+
+ try {
+ BinderProvider.registerBinder((Binder) null);
+ Assert.fail();
+ } catch (NullPointerException e) {
+
+ Assert.assertTrue(true);
+ }
+ try {
+ BinderProvider.registerBinder((BinderBuilder) null);
+ Assert.fail();
+ } catch (NullPointerException e) {
+
+ Assert.assertTrue(true);
+ }
+
+ BinderProvider.registerBinder(binderA);
+
+ Assert.assertNotNull(BinderProvider.binders);
+ Assert.assertEquals(1, BinderProvider.getBinders().size());
+ Assert.assertTrue(BinderProvider.getBinders().containsValue(binderA));
+
+ }
+
+ @Test
+ public void testRegisterBinderWithName() throws Exception {
+ Assert.assertNull(BinderProvider.binders);
+
+ try {
+ BinderProvider.registerBinder((Binder) null, null);
+ Assert.fail();
+ } catch (NullPointerException e) {
+
+ Assert.assertTrue(true);
+ }
+
+ try {
+ BinderProvider.registerBinder((Binder) null, MY_BINDER_NAME);
+ Assert.fail();
+ } catch (NullPointerException e) {
+
+ Assert.assertTrue(true);
+ }
+ try {
+ BinderProvider.registerBinder((BinderBuilder) null, (String) null);
+ Assert.fail();
+ } catch (NullPointerException e) {
+
+ Assert.assertTrue(true);
+ }
+ try {
+ BinderProvider.registerBinder((BinderBuilder) null, MY_BINDER_NAME);
+ Assert.fail();
+ } catch (NullPointerException e) {
+
+ Assert.assertTrue(true);
+ }
+
+ BinderProvider.registerBinder(binderA, MY_BINDER_NAME);
+
+ Assert.assertNotNull(BinderProvider.binders);
+ Assert.assertEquals(1, BinderProvider.getBinders().size());
+ Assert.assertTrue(BinderProvider.getBinders().containsValue(binderA));
+ }
+
+ @Test
+ public void testGetMirroredBinder() throws Exception {
+ BinderProvider.registerBinder(binderA);
+ Binder<BeanA, BeanA> aBeanABinder = BinderProvider.getBinder(BeanA.class);
+ Assert.assertNotNull(aBeanABinder);
+ Assert.assertEquals(binderA, aBeanABinder);
+ Binder<BeanB, BeanB> beanBBinder = BinderProvider.getBinder(BeanB.class);
+ Assert.assertNull(beanBBinder);
+
+
+ }
+
+ @Test
+ public void testGetMirroredBinderWithName() throws Exception {
+ BinderProvider.registerBinder(binderA, MY_BINDER_NAME);
+ Binder<BeanA, BeanA> beanABinder;
+ Binder<BeanB, BeanB> beanBBinder;
+
+ beanABinder = BinderProvider.getBinder(BeanA.class);
+ Assert.assertNull(beanABinder);
+ beanABinder = BinderProvider.getBinder(BeanA.class, MY_BINDER_NAME);
+ Assert.assertNotNull(beanABinder);
+ Assert.assertEquals(binderA, beanABinder);
+ beanBBinder = BinderProvider.getBinder(BeanB.class);
+
+ Assert.assertNull(beanBBinder);
+ beanBBinder = BinderProvider.getBinder(BeanB.class, MY_BINDER_NAME);
+
+ Assert.assertNull(beanBBinder);
+ }
+
+ @Test
+ public void testGetBinder() throws Exception {
+
+ BinderProvider.registerBinder(binderB);
+ Binder<BeanA, BeanA> beanABinder;
+ Binder<BeanA, BeanB> beanBBinder;
+
+ beanABinder = BinderProvider.getBinder(BeanA.class);
+ Assert.assertNull(beanABinder);
+
+ beanBBinder = BinderProvider.getBinder(BeanA.class, BeanB.class);
+ Assert.assertNotNull(beanBBinder);
+ Assert.assertEquals(binderB, beanBBinder);
+
+ }
+
+ @Test
+ public void testGetBinderWithName() throws Exception {
+ BinderProvider.registerBinder(binderB, MY_BINDER2_NAME);
+ Binder<BeanA, BeanA> beanABinder;
+ Binder<BeanA, BeanB> beanBBinder;
+
+ beanABinder = BinderProvider.getBinder(BeanA.class);
+ Assert.assertNull(beanABinder);
+
+ beanBBinder = BinderProvider.getBinder(BeanA.class, BeanB.class);
+ Assert.assertNull(beanBBinder);
+
+ beanBBinder = BinderProvider.getBinder(BeanA.class, BeanB.class, MY_BINDER2_NAME);
+ Assert.assertNotNull(beanBBinder);
+ Assert.assertEquals(binderB, beanBBinder);
+
+
+ }
+}
\ No newline at end of file
Property changes on: trunk/src/test/java/org/nuiton/util/beans/BinderProviderTest.java
___________________________________________________________________
Added: svn:keywords
+ "Author Date Id Revision HeadURL
Added: trunk/src/test/java/org/nuiton/util/beans/BinderTest.java
===================================================================
--- trunk/src/test/java/org/nuiton/util/beans/BinderTest.java (rev 0)
+++ trunk/src/test/java/org/nuiton/util/beans/BinderTest.java 2010-02-21 18:16:09 UTC (rev 1764)
@@ -0,0 +1,113 @@
+package org.nuiton.util.beans;
+
+import org.junit.*;
+
+import java.util.Map;
+
+public class BinderTest {
+
+ BeanA a;
+ BeanB b;
+
+ Binder<BeanA, BeanA> binderA;
+ Binder<BeanA, BeanB> binderB;
+ private static final String VALUE_A = "a";
+ private static final String VALUE_B = "b";
+ private static final String VALUE_C = "c";
+
+ @BeforeClass
+ public static void beforeClass() {
+
+ BinderProvider.binders = null;
+
+ BinderBuilder builder = new BinderBuilder();
+ BinderProvider.registerBinder(builder.
+ createBinderModel(BeanA.class).
+ addSimpleProperties(BeanA.PROPERTY_A));
+
+
+ BinderProvider.registerBinder(builder.
+ createBinderModel(BeanA.class, BeanB.class).
+ addSimpleProperties(BeanA.PROPERTY_A, BeanA.PROPERTY_B).
+ addProperty(BeanA.PROPERTY_C, BeanB.PROPERTY_C2));
+
+ }
+
+ @AfterClass
+ public static void tearDown() {
+
+ BinderProvider.binders = null;
+
+ }
+
+ @Before
+ public void setUp() {
+
+ binderA = BinderProvider.getBinder(BeanA.class);
+ binderB = BinderProvider.getBinder(BeanA.class, BeanB.class);
+
+ a = new BeanA();
+ b = new BeanB();
+ }
+
+ @Test
+ public void testObtainProperties() throws Exception {
+ Map<String, Object> map;
+ map = binderA.obtainProperties(a);
+ Assert.assertEquals(0, map.size());
+
+ map = binderB.obtainProperties(a);
+ Assert.assertEquals(0, map.size());
+
+ a.setA(VALUE_A);
+ map = binderA.obtainProperties(a);
+ Assert.assertEquals(1, map.size());
+ Assert.assertTrue(map.containsKey(BeanA.PROPERTY_A));
+ Assert.assertTrue(map.containsValue(VALUE_A));
+ Assert.assertEquals(VALUE_A, map.get(BeanA.PROPERTY_A));
+
+ map = binderB.obtainProperties(a);
+ Assert.assertEquals(1, map.size());
+ Assert.assertTrue(map.containsKey(BeanA.PROPERTY_A));
+ Assert.assertTrue(map.containsValue(VALUE_A));
+ Assert.assertEquals(VALUE_A, map.get(BeanA.PROPERTY_A));
+
+ a.setB(VALUE_B);
+ map = binderA.obtainProperties(a);
+ Assert.assertEquals(1, map.size());
+ Assert.assertTrue(map.containsKey(BeanA.PROPERTY_A));
+ Assert.assertFalse(map.containsKey(BeanA.PROPERTY_B));
+ Assert.assertTrue(map.containsValue(VALUE_A));
+ Assert.assertFalse(map.containsValue(VALUE_B));
+ Assert.assertEquals(VALUE_A, map.get(BeanA.PROPERTY_A));
+
+ map = binderB.obtainProperties(a);
+ Assert.assertEquals(2, map.size());
+ Assert.assertTrue(map.containsKey(BeanA.PROPERTY_A));
+ Assert.assertTrue(map.containsKey(BeanA.PROPERTY_B));
+ Assert.assertTrue(map.containsValue(VALUE_A));
+ Assert.assertTrue(map.containsValue(VALUE_B));
+ Assert.assertEquals(VALUE_A, map.get(BeanA.PROPERTY_A));
+ Assert.assertEquals(VALUE_B, map.get(BeanA.PROPERTY_B));
+ }
+
+ @Test
+ public void testCopy() throws Exception {
+
+ a.setA(VALUE_A);
+ a.setB(VALUE_B);
+ a.setC(VALUE_C);
+
+ binderA.copy(a, b);
+ Assert.assertEquals(VALUE_A, b.getA());
+ Assert.assertNull(b.getB());
+ Assert.assertNull(b.getB2());
+ Assert.assertNull(b.getC());
+
+ binderB.copy(a, b);
+ Assert.assertEquals(VALUE_A, b.getA());
+ Assert.assertEquals(VALUE_B, b.getB());
+ Assert.assertNull(b.getC());
+ Assert.assertEquals(VALUE_C, b.getC2());
+ }
+}
\ No newline at end of file
Property changes on: trunk/src/test/java/org/nuiton/util/beans/BinderTest.java
___________________________________________________________________
Added: svn:keywords
+ "Author Date Id Revision HeadURL
1
0
Author: tchemit
Date: 2010-02-21 11:27:26 +0100 (Sun, 21 Feb 2010)
New Revision: 1763
Modified:
trunk/pom.xml
Log:
Utilisation de mavenpom4redmine 2.0.5
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2010-02-09 17:00:40 UTC (rev 1762)
+++ trunk/pom.xml 2010-02-21 10:27:26 UTC (rev 1763)
@@ -10,7 +10,7 @@
<parent>
<groupId>org.nuiton</groupId>
<artifactId>mavenpom4redmine</artifactId>
- <version>2.0.4</version>
+ <version>2.0.5</version>
</parent>
<artifactId>nuiton-utils</artifactId>
1
0
Author: echatellier
Date: 2010-02-09 18:00:40 +0100 (Tue, 09 Feb 2010)
New Revision: 1762
Modified:
trunk/src/main/java/org/nuiton/i18n/I18n.java
Log:
Add a quick fix when key to translate is null.
Modified: trunk/src/main/java/org/nuiton/i18n/I18n.java
===================================================================
--- trunk/src/main/java/org/nuiton/i18n/I18n.java 2010-01-28 10:25:42 UTC (rev 1761)
+++ trunk/src/main/java/org/nuiton/i18n/I18n.java 2010-02-09 17:00:40 UTC (rev 1762)
@@ -131,6 +131,12 @@
* sinon.
*/
public static String _(String message) {
+
+ // if the key to translate is null, just return null
+ if (message == null) {
+ return null;
+ }
+
if (loader == null || loader.getLanguage() == null) {
return applyFilter(message);
}
@@ -146,6 +152,12 @@
* sinon.
*/
public static String _(String message, Object... args) {
+
+ // if the key to translate is null, just return null
+ if (message == null) {
+ return null;
+ }
+
String result = message;
Language language = loader == null ? null : loader.getLanguage();
if (language != null) {
1
0