View Javadoc
1   package org.andromda.utils;
2   
3   import java.text.MessageFormat;
4   import java.util.ArrayList;
5   import java.util.Arrays;
6   import java.util.List;
7   
8   import org.apache.commons.lang.StringUtils;
9   
10  /**
11   * A utility object used by the code generator when it needs to convert an object
12   * from one data type to another.
13   *
14   * @author Joel Kozikowski
15   * @author Bob Fields
16   */
17  public class JavaTypeConverter
18  {
19      private List<String> javaTypeConversionIgnoreList = new ArrayList<String>();
20  
21      /**
22       * Specifies a list of one or more fully qualified java types that should be ignored
23       * whenever a type conversion is done.  See Spring namespace property "javaTypeConversionIgnoreList"
24       * @param commaSeparatedIgnoreList comma separated list of types to be ignored
25       */
26      public void setJavaTypeConversionIgnoreList(String commaSeparatedIgnoreList)
27      {
28          javaTypeConversionIgnoreList = new ArrayList<String>();
29          if (commaSeparatedIgnoreList != null)
30          {
31              final String[] typeList = commaSeparatedIgnoreList.split("\\s*,\\s*");
32              javaTypeConversionIgnoreList.addAll(Arrays.asList(typeList));
33          }
34      }
35  
36      private static class ConversionEntry
37      {
38          // - not private to increase performance of
39          //   inner class access
40          final String sourceType;
41          final String targetType;
42          final String conversionPattern;
43  
44          public ConversionEntry(
45              final String sourceType,
46              final String targetType,
47              final String conversionPattern)
48          {
49              this.sourceType = sourceType;
50              this.targetType = targetType;
51              this.conversionPattern = conversionPattern;
52          }
53      }
54  
55      private static ConversionEntry[] conversionTable =
56          {
57              new ConversionEntry("int", "java.lang.Integer", "new java.lang.Integer({0})"),
58              new ConversionEntry("int", "java.lang.String", "java.lang.String.valueOf({0})"),
59              new ConversionEntry("int", "long", "(long){0}"),
60              new ConversionEntry("int", "double", "(double){0}"),
61              new ConversionEntry("int", "float", "(float){0}"),
62              new ConversionEntry("int", "boolean", "({0} != 0)"),
63              new ConversionEntry("java.lang.Integer", "int", "({0} == null ? 0 : {0}.intValue())"),
64              new ConversionEntry("java.lang.Integer", "java.lang.String", "({0} == null ? null : {0}.toString())"),
65              new ConversionEntry("java.lang.String", "int", "({0} == null ? 0 : Integer.valueOf({0}).intValue())"),
66              new ConversionEntry("java.lang.String", "java.lang.Integer", "({0} == null ? null : Integer.valueOf({0}))"),
67  
68              new ConversionEntry("long", "java.lang.Long", "new java.lang.Long({0})"),
69              new ConversionEntry("long", "java.lang.String", "java.lang.String.valueOf({0})"),
70              new ConversionEntry("long", "int", "(int){0}"),
71              new ConversionEntry("long", "double", "(double){0}"),
72              new ConversionEntry("long", "float", "(float){0}"),
73              new ConversionEntry("long", "boolean", "({0} != 0)"),
74              new ConversionEntry("java.lang.Long", "long", "({0} == null ? 0 : {0}.longValue())"),
75              new ConversionEntry("java.lang.Long", "java.lang.String", "({0} == null ? null : {0}.toString())"),
76              new ConversionEntry("java.lang.String", "long", "({0} == null ? 0 : Long.valueOf({0}).longValue())"),
77              new ConversionEntry("java.lang.String", "java.lang.Long", "({0} == null ? null : Long.valueOf({0}))"),
78  
79              new ConversionEntry("double", "java.lang.Double", "new java.lang.Double({0})"),
80              new ConversionEntry("double", "java.lang.String", "java.lang.String.valueOf({0})"),
81              new ConversionEntry("double", "int", "(int){0}"),
82              new ConversionEntry("double", "long", "(long){0}"),
83              new ConversionEntry("double", "float", "(float){0}"),
84              new ConversionEntry("double", "boolean", "({0} != 0.0)"),
85              new ConversionEntry("java.lang.Double", "double", "({0} == null ? 0.0 : {0}.doubleValue())"),
86              new ConversionEntry("java.lang.Double", "java.lang.String", "({0} == null ? null : {0}.toString())"),
87              new ConversionEntry("java.lang.String", "double", "({0} == null ? 0.0 : Double.valueOf({0}).doubleValue())"),
88              new ConversionEntry("java.lang.String", "java.lang.Double", "({0} == null ? null : Double.valueOf({0}))"),
89  
90              new ConversionEntry("float", "java.lang.Float", "new java.lang.Float({0})"),
91              new ConversionEntry("float", "java.lang.String", "java.lang.String.valueOf({0})"),
92              new ConversionEntry("float", "int", "(int){0}"),
93              new ConversionEntry("float", "long", "(long){0}"),
94              new ConversionEntry("float", "double", "(double){0}"),
95              new ConversionEntry("float", "boolean", "({0} != 0.0f)"),
96              new ConversionEntry("java.lang.Float", "float", "({0} == null ? 0.0f : {0}.floatValue())"),
97              new ConversionEntry("java.lang.Float", "java.lang.String", "({0} == null ? null : {0}.toString())"),
98              new ConversionEntry("java.lang.String", "float", "({0} == null ? 0.0f : Float.valueOf({0}).floatValue())"),
99              new ConversionEntry("java.lang.String", "java.lang.Float", "({0} == null ? null : Float.valueOf({0}))"),
100 
101             new ConversionEntry("int", "java.math.BigInteger", "java.math.BigInteger.valueOf((long){0})"),
102             new ConversionEntry("java.math.BigInteger", "int", "({0} == null ? 0 : {0}.intValue())"),
103             new ConversionEntry("long", "java.math.BigInteger", "java.math.BigInteger.valueOf({0})"),
104             new ConversionEntry("java.math.BigInteger", "long", "({0} == null ? 0 : {0}.longValue())"),
105             new ConversionEntry("java.math.BigInteger", "float", "({0} == null ? 0.0f : {0}.floatValue())"),
106             new ConversionEntry("float", "java.math.BigInteger", "new java.math.BigDecimal((double){0}).toBigInteger()"),
107             new ConversionEntry("java.math.BigInteger", "double", "({0} == null ? 0.0 : {0}.doubleValue())"),
108             new ConversionEntry("double", "java.math.BigInteger", "new java.math.BigDecimal({0}).toBigInteger()"),
109             new ConversionEntry("java.lang.String", "java.math.BigInteger", "new java.math.BigInteger({0})"),
110             new ConversionEntry("java.math.BigInteger", "java.lang.String", "({0} == null ? null : {0}.toString())"),
111             new ConversionEntry("java.math.BigDecimal", "java.math.BigInteger", "({0} == null ? null : {0}.toBigInteger())"),
112             new ConversionEntry("java.lang.Integer", "java.math.BigInteger", "({0} == null ? null : java.math.BigInteger.valueOf((long){0}.intValue()))"),
113             new ConversionEntry("java.math.BigInteger", "java.lang.Integer", "({0} == null ? null : new java.lang.Integer({0}.intValue()))"),
114             new ConversionEntry("java.lang.Long", "java.math.BigInteger", "({0} == null ? null : java.math.BigInteger.valueOf({0}.longValue()))"),
115             new ConversionEntry("java.math.BigInteger", "java.lang.Long", "({0} == null ? null : new java.lang.Long({0}.longValue()))"),
116             new ConversionEntry("java.lang.Float", "java.math.BigInteger", "({0} == null ? null : new java.math.BigDecimal((double){0}.floatValue()).toBigInteger())"),
117             new ConversionEntry("java.lang.Double", "java.math.BigInteger", "({0} == null ? null : new java.math.BigDecimal({0}.doubleValue()).toBigInteger())"),
118 
119             new ConversionEntry("int", "java.math.BigDecimal", "java.math.BigDecimal.valueOf((long){0})"),
120             new ConversionEntry("java.math.BigDecimal", "int", "({0} == null ? 0 : {0}.intValue())"),
121             new ConversionEntry("long", "java.math.BigDecimal", "java.math.BigDecimal.valueOf({0})"),
122             new ConversionEntry("java.math.BigDecimal", "long", "({0} == null ? 0 : {0}.longValue())"),
123             new ConversionEntry("java.math.BigDecimal", "float", "({0} == null ? 0.0f : {0}.floatValue())"),
124             new ConversionEntry("float", "java.math.BigDecimal", "new java.math.BigDecimal((double){0})"),
125             new ConversionEntry("java.math.BigDecimal", "double", "({0} == null ? 0.0 : {0}.doubleValue())"),
126             new ConversionEntry("double", "java.math.BigDecimal", "new java.math.BigDecimal({0})"),
127             new ConversionEntry("java.lang.String", "java.math.BigDecimal", "new java.math.BigDecimal({0})"),
128             new ConversionEntry("java.math.BigDecimal", "java.lang.String", "({0} == null ? null : {0}.toString())"),
129             new ConversionEntry("java.math.BigInteger", "java.math.BigDecimal", "new java.math.BigDecimal({0})"),
130             new ConversionEntry("java.lang.Integer", "java.math.BigDecimal", "({0} == null ? null : java.math.BigDecimal.valueOf((long){0}.intValue()))"),
131             new ConversionEntry("java.math.BigDecimal", "java.lang.Integer", "({0} == null ? null : new java.lang.Integer({0}.intValue()))"),
132             new ConversionEntry("java.lang.Long", "java.math.BigDecimal", "({0} == null ? null : java.math.BigDecimal.valueOf({0}.longValue()))"),
133             new ConversionEntry("java.math.BigDecimal", "java.lang.Long", "({0} == null ? null : new java.lang.Long({0}.longValue()))"),
134             new ConversionEntry("java.lang.Float", "java.math.BigDecimal", "({0} == null ? null : new java.math.BigDecimal((double){0}.floatValue()))"),
135             new ConversionEntry("java.lang.Double", "java.math.BigDecimal", "({0} == null ? null : new java.math.BigDecimal({0}.doubleValue()))"),
136 
137             new ConversionEntry("boolean", "java.lang.Boolean", "new java.lang.Boolean({0})"),
138             new ConversionEntry("boolean", "java.lang.String", "java.lang.String.valueOf({0})"),
139             new ConversionEntry("boolean", "int", "({0} ? 1 : 0)"),
140             new ConversionEntry("boolean", "long", "({0} ? 1 : 0)"),
141             new ConversionEntry("boolean", "double", "({0} ? 1.0 : 0.0)"),
142             new ConversionEntry("boolean", "float", "({0} ? 1.0f : 0.0f)"),
143             new ConversionEntry("java.lang.Boolean", "boolean", "({0} == null ? false : {0}.booleanValue())"),
144             new ConversionEntry("java.lang.Boolean", "java.lang.String", "({0} == null ? null : {0}.toString())"),
145             new ConversionEntry("java.lang.String", "boolean", "({0} == null ? false : Boolean.valueOf({0}).booleanValue())"),
146             new ConversionEntry("java.lang.String", "java.lang.Boolean", "({0} == null ? null : Boolean.valueOf({0}))"),
147 
148             new ConversionEntry("string", "java.lang.String", "{0}"),
149             new ConversionEntry("java.lang.String", "string", "{0}"),
150 
151             new ConversionEntry("java.util.Date", "java.lang.String",
152                 "({0} == null ? null : new java.text.SimpleDateFormat(\"yyyy-MM-dd HH:mm:ssZ\").format({0}))"),
153             new ConversionEntry("java.sql.Timestamp", "java.lang.String",
154                 "({0} == null ? null : new java.text.SimpleDateFormat(\"yyyy-MM-dd HH:mm:ssZ\").format({0}))"),
155             new ConversionEntry("java.sql.Time", "java.lang.String",
156                     "({0} == null ? null : new java.text.SimpleDateFormat(\"HH:mm:ssZ\").format({0}))"),
157             new ConversionEntry("java.sql.Date", "java.lang.String",
158                 "({0} == null ? null : new java.text.SimpleDateFormat(\"yyyy-MM-dd\").format({0}))"),
159             new ConversionEntry("java.lang.String", "java.util.Date",
160                 "({0} == null ? null : new java.text.SimpleDateFormat(\"yyyy-MM-dd HH:mm:ssZ\").parse({0}))"),
161             new ConversionEntry("java.lang.String", "java.sql.Timestamp",
162                 "({0} == null ? null : new java.sql.Timestamp(new java.text.SimpleDateFormat(\"yyyy-MM-dd HH:mm:ssZ\").parse({0}).getTime()))"),
163             new ConversionEntry("java.lang.String", "java.sql.Time",
164                 "({0} == null ? null : new java.sql.Time(new java.text.SimpleDateFormat(\"HH:mm:ssZ\").parse({0}).getTime()))"),
165             new ConversionEntry("java.lang.String", "java.sql.Date",
166                 "({0} == null ? null : new java.sql.Date(new java.text.SimpleDateFormat(\"yyyy-MM-dd\").parse({0}).getTime()))"),
167             new ConversionEntry("java.sql.Timestamp", "java.util.Date", "{0}"),
168             new ConversionEntry("java.sql.Timestamp", "java.sql.Time", "({0} == null ? null : new java.sql.Time({0}.getTime()))"),
169             new ConversionEntry("java.sql.Timestamp", "java.sql.Date", "({0} == null ? null : new java.sql.Date({0}.getTime()))"),
170             new ConversionEntry("java.sql.Time", "java.util.Date", "{0}"),
171             new ConversionEntry("java.sql.Time", "java.sql.Timestamp", "({0} == null ? null : new java.sql.Timestamp({0}.getTime()))"),
172             new ConversionEntry("java.sql.Date", "java.util.Date", "{0}"),
173             new ConversionEntry("java.sql.Date", "java.sql.Timestamp", "({0} == null ? null : new java.sql.Timestamp({0}.getTime()))"),
174             new ConversionEntry("java.util.Date", "java.sql.Timestamp", "({0} == null ? null : new java.sql.Timestamp({0}.getTime()))"),
175             new ConversionEntry("java.util.Date", "java.sql.Time", "({0} == null ? null : new java.sql.Time({0}.getTime()))"),
176             new ConversionEntry("java.util.Date", "java.sql.Date", "({0} == null ? null : new java.sql.Date({0}.getTime()))"),
177             new ConversionEntry("java.util.Date", "long", "({0} == null ? 0 : {0}.getTime())"),
178             new ConversionEntry("java.sql.Timestamp", "long", "({0} == null ? 0 : {0}.getTime())"),
179             new ConversionEntry("java.sql.Time", "long", "({0} == null ? 0 : {0}.getTime())"),
180             new ConversionEntry("java.sql.Date", "long", "({0} == null ? 0 : {0}.getTime())"),
181             new ConversionEntry("long", "java.sql.Date", "new java.sql.Date({0})"),
182             new ConversionEntry("long", "java.sql.Time", "new java.sql.Time({0})"),
183             new ConversionEntry("long", "java.sql.Timestamp", "new java.sql.Timestamp({0})"),
184             new ConversionEntry("long", "java.util.Date", "new java.util.Date({0})"),
185 
186             new ConversionEntry("java.lang.Character", "java.lang.String", "({0} == null ? null : {0}.toString())"),
187             new ConversionEntry("java.lang.String", "java.lang.Character", "({0} == null || {0}.length() == 0 ? null : java.lang.Character.valueOf({0}.charAt(0)))"),
188 
189             new ConversionEntry("java.lang.Object", "java.lang.String", "{0} == null ? null : {0}.toString()"),
190             new ConversionEntry("java.lang.Object", "java.lang.Integer", "{0} == null ? null : {0}.toString()"),
191             new ConversionEntry("java.lang.Object", "java.lang.Long", "{0} == null ? null : {0}.toString()"),
192             new ConversionEntry("java.lang.Object", "java.lang.Float", "{0} == null ? null : {0}.toString()"),
193             new ConversionEntry("java.lang.Object", "java.lang.Double", "{0} == null ? null : {0}.toString()"),
194             new ConversionEntry("java.lang.Object", "java.lang.Character", "({0} == null || {0}.toString().length() == 0 ? null : java.lang.Character.valueOf({0}.toString().charAr(0)))"),
195             new ConversionEntry("java.lang.String", "java.lang.Object", "{0}"),
196             new ConversionEntry("java.lang.Integer", "java.lang.Object", "{0}"),
197             new ConversionEntry("java.lang.Long", "java.lang.Object", "{0}"),
198             new ConversionEntry("java.lang.Float", "java.lang.Object", "{0}"),
199             new ConversionEntry("java.lang.Double", "java.lang.Object", "{0}"),
200             new ConversionEntry("java.lang.Character", "java.lang.Object", "{0}"),
201             new ConversionEntry("java.lang.Character", "char", "({0} == null ? 0 : {0}.charValue())"),
202             new ConversionEntry("char", "java.lang.Character", "java.lang.Character.valueOf({0})"),
203         };
204 
205     /**
206      * Attempts to code a type conversion from the specified source value to the target
207      * type that can be used on the right hand side of an assignment. If such a conversion
208      * exists, the Java code fragment to do that will be returned. If no such conversion exists,
209      * null is returned.
210      * @param sourceType The fully qualified data type of the source value
211      * @param sourceValue The actual source value (usually a variable name)
212      * @param targetType The fully qualified data type of the target value
213      * @return The converted value, or null if no conversion can be done.
214      */
215     public String typeConvert(
216         final String sourceType,
217         final String sourceValue,
218         final String targetType)
219     {
220         String convertedValue;
221 
222         if (StringUtils.isBlank(sourceType) || StringUtils.isBlank(targetType) ||
223             javaTypeConversionIgnoreList.contains(sourceType) || javaTypeConversionIgnoreList.contains(targetType))
224         {
225             convertedValue = null;
226         }
227         else if (sourceType.equals(targetType))
228         {
229             convertedValue = sourceValue;
230         }
231         else
232         {
233             convertedValue = null;
234 
235             for (int i = 0; i < conversionTable.length && convertedValue == null; i++)
236             {
237                 if (conversionTable[i].sourceType.equals(sourceType) &&
238                     conversionTable[i].targetType.equals(targetType))
239                 {
240                     convertedValue =
241                         MessageFormat.format(
242                             conversionTable[i].conversionPattern,
243                                 sourceValue);
244                 } // if
245             } // for
246 
247             if (convertedValue == null && sourceType.startsWith("java.lang.") && !sourceType.endsWith("[]"))
248             {
249                 // If source is a primitive wrapper, try to convert
250                 // to the base primitive first...
251                 String primitiveSource = sourceType.substring(10).toLowerCase();
252                 if ("integer".equals(primitiveSource))
253                 {
254                     primitiveSource = "int";
255                 }
256                 else if ("character".equals(primitiveSource)) {
257                     primitiveSource = "char";
258                 }
259 
260                 String interimValue = typeConvert(
261                         sourceType,
262                         sourceValue,
263                         primitiveSource);
264 
265                 if (interimValue != null)
266                 {
267                     convertedValue = typeConvert(
268                             primitiveSource,
269                             interimValue,
270                             targetType);
271                 }
272             }
273 
274             if (convertedValue == null && targetType.startsWith("java.lang.") && !targetType.endsWith("[]"))
275             {
276                 // One last try - if target is a primitive wrapper, try to convert
277                 // to the base primitive first...
278                 String primitiveTarget = targetType.substring(10).toLowerCase();
279                 if ("integer".equals(primitiveTarget))
280                 {
281                     primitiveTarget = "int";
282                 }
283                 else if ("character".equals(primitiveTarget))
284                 {
285                     primitiveTarget = "char";
286                 }
287 
288                 String interimValue = typeConvert(
289                         sourceType,
290                         sourceValue,
291                         primitiveTarget);
292                 if (interimValue != null)
293                 {
294                     convertedValue = typeConvert(
295                             primitiveTarget,
296                             interimValue,
297                             targetType);
298                 }
299             }
300         }
301 
302         return convertedValue;
303     }
304 
305     private static final List<String> javaLangList = new ArrayList<String>();
306     /**
307      * Creates a java.lang. fully qualified name from the given <code>name</code>,
308      * inserting 'java.lang.' in front if needed. Many EJB3 and Hibernate configuration files
309      * require java.lang. in the type name, where Java code does not (gives compiler warning).
310      * This allows UML Primitive types to be modeled and mapped without java.lang. implementation.
311      *
312      * @param name the name of the model element.
313      * @return the java.lang. fully qualified name, if needed.
314      */
315     public static String getJavaLangTypeName(String name)
316     {
317         if (StringUtils.isBlank(name))
318         {
319             return name;
320         }
321         synchronized (javaLangList)
322         {
323             if (javaLangList.isEmpty())
324             {
325                 javaLangList.add("String");
326                 javaLangList.add("Boolean");
327                 javaLangList.add("Integer");
328                 javaLangList.add("Long");
329                 javaLangList.add("Double");
330                 javaLangList.add("Object");
331                 javaLangList.add("Short");
332                 javaLangList.add("Character");
333                 javaLangList.add("Byte");
334                 javaLangList.add("Float");
335                 javaLangList.add("Number");
336                 javaLangList.add("Math");
337                 javaLangList.add("Class");
338                 javaLangList.add("Exception");
339                 javaLangList.add("Enum");
340             }
341         }
342         // If type has no package and is not the same as lowercase (i.e. primitive type)...
343         if (!(name.indexOf('.')>-1) && !(name.equals(name.toLowerCase())))
344         {
345             if (javaLangList.contains(name)
346                 || (name.endsWith("[]") && javaLangList.contains(name.substring(0, name.length()-2))))
347             {
348                 name = "java.lang." + name;
349             }
350         }
351         return name;
352     }
353 }