Project Report: fawkez

Packagesummary org.jcoderz.phoenix.cmpgen2

org.jcoderz.phoenix.cmpgen2.TypeMapping

LineHitsNoteSource
1  /*
2   * $Id: TypeMapping.java 1011 2008-06-16 17:57:36Z amandel $
3   *
4   * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5   *
6   * Redistribution and use in source and binary forms, with or without
7   * modification, are permitted provided that the following conditions are
8   * met:
9   *
10   *    * Redistributions of source code must retain the above copyright
11   *      notice, this list of conditions and the following disclaimer.
12   *    * Redistributions in binary form must reproduce the above
13   *      copyright notice, this list of conditions and the following
14   *      disclaimer in the documentation and/or other materials
15   *      provided with the distribution.
16   *    * Neither the name of the jCoderZ.org Project nor the names of
17   *      its contributors may be used to endorse or promote products
18   *      derived from this software without specific prior written
19   *      permission.
20   *
21   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32   */
33  package org.jcoderz.phoenix.cmpgen2;
34  
35  import java.math.BigDecimal;
36  import java.sql.Date;
37  import java.sql.Timestamp;
38  import java.util.Arrays;
39  import java.util.HashSet;
40  import java.util.List;
41  import java.util.Set;
42  
43  import org.jcoderz.commons.util.Constants;
44  import org.jcoderz.phoenix.sqlparser.ColumnSpec;
45  import org.jcoderz.phoenix.sqlparser.NumericAttribute;
46  
47  
48  /**
49   * @author Albrecht Messner
50   */
51  public final class TypeMapping
52  {
530    private static final String[] JAVA_PRIMITIVE_TYPES = {
54        Byte.TYPE.getName(),
55        Short.TYPE.getName(),
56        Integer.TYPE.getName(),
57        Long.TYPE.getName(),
58        Float.TYPE.getName(),
59        Double.TYPE.getName(),
60        Character.TYPE.getName(),
61        Boolean.TYPE.getName(),
62        "byte[]"
63     };
64     
650    private static final String[] PRIMITIVE_TYPE_WRAPPERS = {
66        Byte.class.getName(),
67        Short.class.getName(),
68        Integer.class.getName(),
69        Long.class.getName(),
70        Float.class.getName(),
71        Double.class.getName(),
72        Character.class.getName(),
73        Boolean.class.getName(),
74        "byte[]"
75     };
76     
77     // these get mapped to java.lang.String
780    private static final String[] STRING_TYPES = {
79        "CHAR",
80        "CHAR2",
81        "NCHAR",
82        "NCHAR2",
83        "VARCHAR",
84        "VARCHAR2",
85        "NVARCHAR",
86        "NVARCHAR2"
87        };
88  
890    private static final String[] TIMESTAMP_TYPES = {
90        "TIMESTAMP"
91        };
92     
930    private static final String[] DATE_TYPES = {
94        "DATE"
95        };
96     
97     // these get mapped to numeric types
980    private static final String[] NUMERIC_TYPES = {
99        "NUMBER",
100        "NUMERIC",
101        "DECIMAL",
102        "INTEGER",
103        "INT",
104        "FLOAT",
105        "REAL"
106        };
107        
1080    private static final String[] FLOAT_TYPES = {
109        "FLOAT",
110        "REAL"
111     };
112     
113     private static final int INTEGER_PRECISION_LIMIT = 10;
114     private static final int LONG_PRECISION_LIMIT = 19;
115  
116  
117     // put all arrays into hash sets for faster lookup
1180    private static final Set STRING_TYPE_SET = new HashSet();
1190    private static final Set NUMERIC_TYPE_SET = new HashSet();
1200    private static final Set TIMESTAMP_TYPE_SET = new HashSet();
1210    private static final Set DATE_TYPE_SET = new HashSet();
1220    private static final Set FLOAT_TYPE_SET = new HashSet();
1230    private static final Set JAVA_PRIMITIVE_TYPE_SET = new HashSet();
124  
125     static
126     {
1270       STRING_TYPE_SET.addAll(Arrays.asList(STRING_TYPES));
1280       NUMERIC_TYPE_SET.addAll(Arrays.asList(NUMERIC_TYPES));
1290       TIMESTAMP_TYPE_SET.addAll(Arrays.asList(TIMESTAMP_TYPES));
1300       DATE_TYPE_SET.addAll(Arrays.asList(DATE_TYPES));
1310       FLOAT_TYPE_SET.addAll(Arrays.asList(FLOAT_TYPES));
1320       JAVA_PRIMITIVE_TYPE_SET.addAll(Arrays.asList(JAVA_PRIMITIVE_TYPES));
1330    }
134     
135     /**
136      * private constructor to avoid instantiation
137      */
138     private TypeMapping ()
1390    {
1400    }
141     
142     /**
143      * Finds the appropriate type mapping from a given column spec.
144      * 
145      * Note that the type returned here is the "simple" type as it is stored
146      * in the database, not the "complex" type.
147      * 
148      * @param column the column specification
149      * @param fullyQualified whether the type should contain the package
150      *        name or not
151      * @return the simple java type used to store the column in the db
152      * @throws CmpGeneratorException if no type mapping can be found
153      */
154 (1)   public static String getJavaType (
155           ColumnSpec column,
156           boolean fullyQualified)
157           throws CmpGeneratorException
158     {
1590       String javaType = column.getJavaType();
1600       if (javaType == null)
161        {
162           // this gets a mapping for character data types
1630          javaType = getTypeMapping(column.getColumnType());
164           
165           // no character type, try to find a numeric type
1660          if (javaType == null)
167           {
1680             final List sqlTypeAttributes = column.getDatatypeAttributes();
1690             int att1 = 0, att2 = 0;
1700(2)            if (sqlTypeAttributes.size() > 0)
171              {
1720                att1 = ((NumericAttribute) sqlTypeAttributes.get(0)).getNumber();
1730(3)               if (sqlTypeAttributes.size() > 1)
174                 {
1750                   att2 = ((NumericAttribute) sqlTypeAttributes.get(1))
176                        .getNumber();
177                 }
178              }
1790             javaType =
180                 getNumberTypeMapping(
181                    column.getColumnType(),
182                    att1,
183                    att2);
1840          }
185        }
186        else
187        {
188           // a java type has been specified
1890          final String loadMethod = column.getLoadMethod();
1900          if (loadMethod != null)
191           {
192              // hey! it's a complex type
193              // the "simple" java type can be found in the signature of the
194              // load method
1950             final int openParen = loadMethod.indexOf('(');
1960             final int closeParen = loadMethod.indexOf(')');
1970             if (openParen == -1
198                 || closeParen == -1
199                 || closeParen <= openParen)
200              {
2010                throw new CmpGeneratorException(
202                    loadMethod + " is an invalid load method signature");
203              }
2040             javaType = loadMethod.substring(openParen + 1, closeParen).trim();
2050             if (javaType.length() <= 0)
206              {
2070                throw new CmpGeneratorException(
208                    loadMethod + " is an invalid load method signature");
209              }
210           }
211        }
212        
2130       if (javaType == null)
214        {
2150          throw new CmpGeneratorException("No type mapping found for column "
216              + column);
217        }
218  
219        // ok, now we've got a java type. if it is a primitive type
220        // and the column is nullable, then we must use the wrapper object
221        // instead
2220       if (isPrimitiveType(javaType) && !column.isNotNull())
223        {
2240          javaType = primitiveToObject(javaType);
225        }
226  
227        // check if we should return the type fully qualified
2280       if (!fullyQualified)
229        {
2300          javaType = unqualifyType(javaType);
231        }
232  
2330       return javaType;
234     }
235  
236     /**
237      * Returns everything after the last dot in a type name.
238      * @param typeName a java type name
239      * @return the unqualified type name, or the argument if
240      *         it was not a qualified java type name
241      */
242     public static String unqualifyType (String typeName)
243     {
2440       final int dotIndex = typeName.lastIndexOf('.');
2450       return typeName.substring(dotIndex + 1);
246     }
247  
248     /**
249      * Returns the fully qualified java type to which an SQL type is mapped.
250      * 
251      * @param sqlType the name of the sql type
252      * @return the FQ type name of the java type, or null if this method can not
253      *         find a type mapping
254      */
255     public static String getTypeMapping (String sqlType)
256     {
257        String javaType;
258        
2590       final String s = sqlType.toUpperCase(Constants.SYSTEM_LOCALE);
2600       if (STRING_TYPE_SET.contains(s))
261        {
2620          javaType = String.class.getName();
263        }
2640       else if (TIMESTAMP_TYPE_SET.contains(s))
265        {
2660          javaType = Timestamp.class.getName();
267        }
2680       else if (DATE_TYPE_SET.contains(s))
269        {
2700          javaType = Date.class.getName();
271        }
2720       else if (NUMERIC_TYPE_SET.contains(s))
273        {
2740          javaType = null;
275        }
276        else
277        {
2780          javaType = Object.class.getName();
279        }
280        
2810       return javaType;
282     }
283     
284     /**
285      * Returns a type mapping for numeric types.
286      * 
287      * @param sqlType the name of the sql type
288      * @param precision the precision of the sql type
289      * @param scale the scale of the sql type, or 0 if no scale given
290      * @return the name of the appropriate java type
291      */
292 (4)   public static String getNumberTypeMapping (
293        String sqlType,
294        int precision,
295        int scale)
296     {
297        String javaType;
2980       final String s = sqlType.toUpperCase(Constants.SYSTEM_LOCALE);
299  
3000       if (precision < 0 || scale < 0)
301        {
3020(5)         throw new IllegalArgumentException(
303                   "Scale and precision must be non-negative");
304        }
305  
3060       if (NUMERIC_TYPE_SET.contains(s))
307        {
3080          if (scale > 0 || FLOAT_TYPE_SET.contains(s))
309           {
3100             return BigDecimal.class.getName();
311           }
312           else
313           {
3140             if (precision < INTEGER_PRECISION_LIMIT)
315              {
3160                javaType = Integer.TYPE.getName();
317              }
3180             else if (precision < LONG_PRECISION_LIMIT)
319              {
3200                javaType = Long.TYPE.getName();
321              }
322              else
323              {
3240                javaType = BigDecimal.class.getName();
325              }
326           }
327        }
328        else
329        {
3300          throw new IllegalArgumentException(s + " is not a numeric SQL type");
331        }
332        
3330       return javaType;
334     }
335     
336     /**
337      * Determines whether a given type is primitive.
338      * 
339      * @param type the name of a java type
340      * @return true if the type is primitive, false otherwise
341      */
342     public static boolean isPrimitiveType (String type)
343     {
3440       boolean result = false;
3450       if (JAVA_PRIMITIVE_TYPE_SET.contains(type))
346        {
3470          result = true;
348        }
3490       return result;
350     }
351  
352     /**
353      * Maps a java primitive type to its corresponding wrapper object.
354      * @param primitiveType the name of a primitive type
355      * @return the corresponding wrapper object
356      * @throws IllegalArgumentException if primitiveType is not a primitive type
357      */
358     public static String primitiveToObject (String primitiveType)
359     {
3600       if (!isPrimitiveType(primitiveType))
361        {
3620          throw new IllegalArgumentException(
363                 "Can't map "
364                 + primitiveType
365                 + " to its Object wrapper because it is not a primitive type");
366        }
3670       String objectWrapperName = null;
3680       for (int i = 0; i < JAVA_PRIMITIVE_TYPES.length; i++)
369        {
3700          if (JAVA_PRIMITIVE_TYPES[i].equals(primitiveType))
371           {
3720             objectWrapperName = PRIMITIVE_TYPE_WRAPPERS[i];
3730             break;
374           }
375        }
3760       return objectWrapperName;
377     }
378  
379  }

Findings in this File

c (1) 154 : 4 Cyclomatic Complexity is 14 (max allowed is 12).
d (2) 170 : 17 Substitute calls to size() == 0 (or size() != 0) with calls to isEmpty()
c (3) 173 : 16 Nested if-else depth is 3 (max allowed is 2).
c (4) 292 : 4 Return count is 2 (max allowed is 1).
i (5) 302 : 0 method org.jcoderz.phoenix.cmpgen2.TypeMapping.getNumberTypeMapping(String, int, int) throws exception with static message string