View Javadoc

1   /*
2    * Copyright 2006 Outsource Cafe, Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the 'License')
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an 'AS IS' BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.javagen.revgen.mapping;
17  
18  import java.math.BigDecimal;
19  import java.math.BigInteger;
20  import java.sql.Timestamp;
21  import java.util.HashMap;
22  import java.util.Map;
23  
24  import org.javagen.agile.db.model.Column;
25  import org.javagen.agile.db.model.DbType;
26  import org.javagen.agile.db.model.Table;
27  import org.javagen.agile.oo.model.Class;
28  import org.javagen.revgen.context.Keys;
29  
30  /***
31   * Misc. static methods to support Java mapping.
32   * <p>
33   * @TODO This class could probably be eliminated or at least cleaned up.
34   * 
35   * @author Richard Easterling
36   */
37  public final class Db2JavaUtil {
38  
39      private static final Integer ONE = new Integer(1);
40      private static final Integer ZERO = new Integer(0);
41      
42      private Db2JavaUtil() {}
43  
44      /***
45       * Try to match best minimal Java numeric type needed to represent SQL type.
46       * 
47       * @param column
48       * @return minimal sufficient type or null if no match found
49       */
50      public static java.lang.Class<?> minimalJavaType(Column column) {
51          //DbType.NUMERIC defaults to java.math.BigDecimal.class
52          if (column.getDbType()!=null) {
53              switch (column.getDbType()) {
54              case NUMERIC: 
55                  if (zeroScale(column.getScale())) {
56                      return cardinalTypes(column.getColumnSize());
57                  } else { //try float or double
58                      return minimulNumericType(column.getColumnSize(), column.getScale());
59                  }
60              case DECIMAL: 
61                  if (zeroScale(column.getScale())) {
62                      return cardinalTypes(column.getColumnSize());
63                  } else { //try float or double
64                      //TODO are DB Numeric and Decimal equivalent? If not need minimulDecimalType method
65                      return minimulNumericType(column.getColumnSize(), column.getScale());
66                  }
67              }
68          }
69          return null;
70      }
71  
72      public static java.lang.Class<?> cardinalTypes(Integer precision) {
73          if (precision==null)
74              return BigInteger.class;
75          if (precision<3) //8bit long, 2^7 = 128 or 2 digits of precision
76              return Byte.class;              
77          if (precision<5) //16bit long, 2^15 = 32,768 or 4 digits of precision
78              return Short.class;             
79          if (precision<10) //32bit long, 2^31 = 2,147,483,648 or 9 digits of precision
80              return Integer.class;               
81          if (precision<19) //64bit long, 2^63 = 9,223,372,036,900,000,000 or 18 digits of precision 
82              return Long.class;              
83          return BigInteger.class;
84      }
85  
86      public static java.lang.Class<?> minimulNumericType(Integer precision, Integer scale) {
87          if (precision!=null && precision<8) {
88              //32bit Float 24bits for number 8bits for exponent or 2^24=16,777,216 or 7 digits of precision
89              return Float.class;
90          } else if (precision!=null && precision<17) {
91              //64bit Double 54bits for number 10bits for exponent or 2^54=18,014,398,509,000,000 or 16 digits of precision
92              return Double.class;
93          } else {
94              return BigDecimal.class;
95          }
96      }
97      
98      public static boolean zeroScale(Integer i) {
99          return i==null || i==0;
100     }
101     
102     /***
103      * Converts types to primitives if they are not keys and are not nullable.
104      */
105     public static java.lang.Class<?> primitiveMappingCanidate(java.lang.Class<?> wrapperClass, Column column) {
106         java.lang.Class<?> primitiveClass = Db2JavaUtil.primitiveClass(wrapperClass);
107         if (primitiveClass==null) {
108             return null;
109         } else {
110             if (notTrue(column.isKey()) && notTrue(column.isForeignKey()) && (column.getNotNull()!=null && column.getNotNull())) {
111                 return primitiveClass;
112             } else {
113                 return null;
114             }
115         }
116     }
117     
118     public static java.lang.Class<?> booleanTypeCanidate(Column column) {
119         if (ONE.equals(column.getColumnSize()) 
120                 && (column.getScale()==null || ZERO.equals(column.getScale())) 
121                 && (DbType.CHAR.equals(column.getDbType()) || DbType.VARCHAR.equals(column.getDbType()))
122                 && column.getDefaultValue()!=null
123            )
124         {
125             String defaultVal = column.getDefaultValue().toString();
126             return ("Y".equalsIgnoreCase(defaultVal) || "N".equalsIgnoreCase(defaultVal) ||
127                     "T".equalsIgnoreCase(defaultVal) || "F".equalsIgnoreCase(defaultVal))
128                    ? boolean.class
129                    : null;
130         } else {
131             return null;
132         }
133     }
134     
135    /***
136      * Lookup mapped Class instance held in Table context filtering out link-tables.
137      * This only works for 1-to-1 table to class mappings.
138      * @param table
139      * @return org.javagen.agile.java.model.Class instance
140      */
141 	public static Class getClassFromTable(Table table) {
142 		if ( Boolean.TRUE.equals(table.isLinkTable()) || table.getContext()==null) 
143 			return null;
144 		Class _class = (Class)table.get(Keys.ENTITY.toString());
145 		return _class;
146 	}
147 
148 	public static java.lang.Class<?> javaType(DbType dbType) {
149 		java.lang.Class<?> _class = java2DbMapping.get(dbType);
150 		return _class;
151 	}
152 	
153     public static java.lang.Class<?> javaType(String dbType) {
154         return javaType(DbType.valueOf(dbType));
155     }
156     
157     public static boolean notTrue(Boolean boolOrNull) {
158         return boolOrNull==null || Boolean.FALSE.equals(boolOrNull);
159     }
160     
161     /***
162      * @param wrapperClass - any Java class
163      * @return - primitive class if input is a wrapper class or null if the input in not a wrapper class
164      */
165     public static java.lang.Class<?> primitiveClass(java.lang.Class<?> wrapperClass) {
166         return wrapperToPrimitive.get(wrapperClass);
167     }
168     
169 	static Map<DbType, java.lang.Class<?>> java2DbMapping = null;
170     
171     static Map<java.lang.Class<?>, java.lang.Class<?>> wrapperToPrimitive;
172 	
173 	static {
174         //map wrapper classes to their primitives
175         wrapperToPrimitive = new HashMap<java.lang.Class<?>, java.lang.Class<?>>();
176         wrapperToPrimitive.put(Boolean.class, Boolean.TYPE);
177         wrapperToPrimitive.put(Character.class, Character.TYPE);
178         wrapperToPrimitive.put(Byte.class, Byte.TYPE);
179         wrapperToPrimitive.put(Short.class, Short.TYPE);
180         wrapperToPrimitive.put(Integer.class, Integer.TYPE);
181         wrapperToPrimitive.put(Long.class, Long.TYPE);
182         wrapperToPrimitive.put(Float.class, Float.TYPE);
183         wrapperToPrimitive.put(Double.class, Double.TYPE);
184         wrapperToPrimitive.put(Void.class, Void.TYPE);
185         
186 		//TODO default java mappings should are already specified somewhere?
187 		java2DbMapping = new HashMap<DbType, java.lang.Class<?>>();
188 		java2DbMapping.put(DbType.BIT, Boolean.class);
189 		java2DbMapping.put(DbType.TINYINT, Byte.class);
190 		java2DbMapping.put(DbType.SMALLINT, Short.class);
191 		java2DbMapping.put(DbType.INTEGER, Integer.class);
192 		java2DbMapping.put(DbType.BIGINT, Long.class);
193 		java2DbMapping.put(DbType.FLOAT, Float.class);
194 		java2DbMapping.put(DbType.REAL, Double.class);
195 		java2DbMapping.put(DbType.NUMERIC, java.math.BigDecimal.class);
196 		java2DbMapping.put(DbType.DECIMAL, Double.class);
197 		java2DbMapping.put(DbType.CHAR, Character.class);
198 		java2DbMapping.put(DbType.VARCHAR, String.class);
199 		java2DbMapping.put(DbType.LONGVARCHAR, String.class);
200 		java2DbMapping.put(DbType.DATE, java.util.Date.class);
201 		java2DbMapping.put(DbType.TIME, java.sql.Time.class);
202 		java2DbMapping.put(DbType.TIMESTAMP, Timestamp.class);
203 		java2DbMapping.put(DbType.BINARY, Byte[].class);
204 		java2DbMapping.put(DbType.VARBINARY, Byte[].class);
205 		java2DbMapping.put(DbType.LONGVARBINARY, Byte[].class);
206 		java2DbMapping.put(DbType.NULL, Void.class);
207 		java2DbMapping.put(DbType.OTHER, Object.class);
208 		java2DbMapping.put(DbType.JAVA_OBJECT, Object.class);
209 		java2DbMapping.put(DbType.DISTINCT, Boolean.class);
210 		java2DbMapping.put(DbType.STRUCT, Boolean.class);
211 		java2DbMapping.put(DbType.ARRAY, Boolean.class);
212 		java2DbMapping.put(DbType.BLOB, Byte[].class);
213 		java2DbMapping.put(DbType.CLOB, Character[].class);
214 		java2DbMapping.put(DbType.REF, Boolean.class);
215 		java2DbMapping.put(DbType.DOUBLE, Double.class);
216 		//Hibernate boolean types:
217 		//java2DbMapping.put(DbType.BOOLEANINT, Boolean.class);
218 		//java2DbMapping.put(DbType.BOOLEANCHAR, Boolean.class);
219 	}
220 }