View Javadoc
1   /*
2    *    Copyright 2006-2023 the original author or authors.
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    *       https://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.mybatis.generator.internal.types;
17  
18  import java.math.BigDecimal;
19  import java.sql.Types;
20  import java.util.Date;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Properties;
25  
26  import org.mybatis.generator.api.IntrospectedColumn;
27  import org.mybatis.generator.api.JavaTypeResolver;
28  import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
29  import org.mybatis.generator.config.Context;
30  import org.mybatis.generator.config.PropertyRegistry;
31  import org.mybatis.generator.internal.util.StringUtility;
32  
33  public class JavaTypeResolverDefaultImpl implements JavaTypeResolver {
34  
35      protected List<String> warnings;
36  
37      protected final Properties properties;
38  
39      protected Context context;
40  
41      protected boolean forceBigDecimals;
42      protected boolean useJSR310Types;
43  
44      protected final Map<Integer, JdbcTypeInformation> typeMap;
45  
46      public JavaTypeResolverDefaultImpl() {
47          super();
48          properties = new Properties();
49          typeMap = new HashMap<>();
50  
51          typeMap.put(Types.ARRAY, new JdbcTypeInformation("ARRAY", //$NON-NLS-1$
52                  new FullyQualifiedJavaType(Object.class.getName())));
53          typeMap.put(Types.BIGINT, new JdbcTypeInformation("BIGINT", //$NON-NLS-1$
54                  new FullyQualifiedJavaType(Long.class.getName())));
55          typeMap.put(Types.BINARY, new JdbcTypeInformation("BINARY", //$NON-NLS-1$
56                  new FullyQualifiedJavaType("byte[]"))); //$NON-NLS-1$
57          typeMap.put(Types.BIT, new JdbcTypeInformation("BIT", //$NON-NLS-1$
58                  new FullyQualifiedJavaType(Boolean.class.getName())));
59          typeMap.put(Types.BLOB, new JdbcTypeInformation("BLOB", //$NON-NLS-1$
60                  new FullyQualifiedJavaType("byte[]"))); //$NON-NLS-1$
61          typeMap.put(Types.BOOLEAN, new JdbcTypeInformation("BOOLEAN", //$NON-NLS-1$
62                  new FullyQualifiedJavaType(Boolean.class.getName())));
63          typeMap.put(Types.CHAR, new JdbcTypeInformation("CHAR", //$NON-NLS-1$
64                  new FullyQualifiedJavaType(String.class.getName())));
65          typeMap.put(Types.CLOB, new JdbcTypeInformation("CLOB", //$NON-NLS-1$
66                  new FullyQualifiedJavaType(String.class.getName())));
67          typeMap.put(Types.DATALINK, new JdbcTypeInformation("DATALINK", //$NON-NLS-1$
68                  new FullyQualifiedJavaType(Object.class.getName())));
69          typeMap.put(Types.DATE, new JdbcTypeInformation("DATE", //$NON-NLS-1$
70                  new FullyQualifiedJavaType(Date.class.getName())));
71          typeMap.put(Types.DECIMAL, new JdbcTypeInformation("DECIMAL", //$NON-NLS-1$
72                  new FullyQualifiedJavaType(BigDecimal.class.getName())));
73          typeMap.put(Types.DISTINCT, new JdbcTypeInformation("DISTINCT", //$NON-NLS-1$
74                  new FullyQualifiedJavaType(Object.class.getName())));
75          typeMap.put(Types.DOUBLE, new JdbcTypeInformation("DOUBLE", //$NON-NLS-1$
76                  new FullyQualifiedJavaType(Double.class.getName())));
77          typeMap.put(Types.FLOAT, new JdbcTypeInformation("FLOAT", //$NON-NLS-1$
78                  new FullyQualifiedJavaType(Double.class.getName())));
79          typeMap.put(Types.INTEGER, new JdbcTypeInformation("INTEGER", //$NON-NLS-1$
80                  new FullyQualifiedJavaType(Integer.class.getName())));
81          typeMap.put(Types.JAVA_OBJECT, new JdbcTypeInformation("JAVA_OBJECT", //$NON-NLS-1$
82                  new FullyQualifiedJavaType(Object.class.getName())));
83          typeMap.put(Types.LONGNVARCHAR, new JdbcTypeInformation("LONGNVARCHAR", //$NON-NLS-1$
84                  new FullyQualifiedJavaType(String.class.getName())));
85          typeMap.put(Types.LONGVARBINARY, new JdbcTypeInformation(
86                  "LONGVARBINARY", //$NON-NLS-1$
87                  new FullyQualifiedJavaType("byte[]"))); //$NON-NLS-1$
88          typeMap.put(Types.LONGVARCHAR, new JdbcTypeInformation("LONGVARCHAR", //$NON-NLS-1$
89                  new FullyQualifiedJavaType(String.class.getName())));
90          typeMap.put(Types.NCHAR, new JdbcTypeInformation("NCHAR", //$NON-NLS-1$
91                  new FullyQualifiedJavaType(String.class.getName())));
92          typeMap.put(Types.NCLOB, new JdbcTypeInformation("NCLOB", //$NON-NLS-1$
93                  new FullyQualifiedJavaType(String.class.getName())));
94          typeMap.put(Types.NVARCHAR, new JdbcTypeInformation("NVARCHAR", //$NON-NLS-1$
95                  new FullyQualifiedJavaType(String.class.getName())));
96          typeMap.put(Types.NULL, new JdbcTypeInformation("NULL", //$NON-NLS-1$
97                  new FullyQualifiedJavaType(Object.class.getName())));
98          typeMap.put(Types.NUMERIC, new JdbcTypeInformation("NUMERIC", //$NON-NLS-1$
99                  new FullyQualifiedJavaType(BigDecimal.class.getName())));
100         typeMap.put(Types.OTHER, new JdbcTypeInformation("OTHER", //$NON-NLS-1$
101                 new FullyQualifiedJavaType(Object.class.getName())));
102         typeMap.put(Types.REAL, new JdbcTypeInformation("REAL", //$NON-NLS-1$
103                 new FullyQualifiedJavaType(Float.class.getName())));
104         typeMap.put(Types.REF, new JdbcTypeInformation("REF", //$NON-NLS-1$
105                 new FullyQualifiedJavaType(Object.class.getName())));
106         typeMap.put(Types.SMALLINT, new JdbcTypeInformation("SMALLINT", //$NON-NLS-1$
107                 new FullyQualifiedJavaType(Short.class.getName())));
108         typeMap.put(Types.STRUCT, new JdbcTypeInformation("STRUCT", //$NON-NLS-1$
109                 new FullyQualifiedJavaType(Object.class.getName())));
110         typeMap.put(Types.TIME, new JdbcTypeInformation("TIME", //$NON-NLS-1$
111                 new FullyQualifiedJavaType(Date.class.getName())));
112         typeMap.put(Types.TIMESTAMP, new JdbcTypeInformation("TIMESTAMP", //$NON-NLS-1$
113                 new FullyQualifiedJavaType(Date.class.getName())));
114         typeMap.put(Types.TINYINT, new JdbcTypeInformation("TINYINT", //$NON-NLS-1$
115                 new FullyQualifiedJavaType(Byte.class.getName())));
116         typeMap.put(Types.VARBINARY, new JdbcTypeInformation("VARBINARY", //$NON-NLS-1$
117                 new FullyQualifiedJavaType("byte[]"))); //$NON-NLS-1$
118         typeMap.put(Types.VARCHAR, new JdbcTypeInformation("VARCHAR", //$NON-NLS-1$
119                 new FullyQualifiedJavaType(String.class.getName())));
120         // JDK 1.8 types
121         typeMap.put(Types.TIME_WITH_TIMEZONE, new JdbcTypeInformation("TIME_WITH_TIMEZONE", //$NON-NLS-1$
122                 new FullyQualifiedJavaType("java.time.OffsetTime"))); //$NON-NLS-1$
123         typeMap.put(Types.TIMESTAMP_WITH_TIMEZONE, new JdbcTypeInformation("TIMESTAMP_WITH_TIMEZONE", //$NON-NLS-1$
124                 new FullyQualifiedJavaType("java.time.OffsetDateTime"))); //$NON-NLS-1$
125     }
126 
127     @Override
128     public void addConfigurationProperties(Properties properties) {
129         this.properties.putAll(properties);
130         forceBigDecimals = StringUtility
131                 .isTrue(properties
132                         .getProperty(PropertyRegistry.TYPE_RESOLVER_FORCE_BIG_DECIMALS));
133         useJSR310Types = StringUtility
134                 .isTrue(properties
135                         .getProperty(PropertyRegistry.TYPE_RESOLVER_USE_JSR310_TYPES));
136     }
137 
138     @Override
139     public FullyQualifiedJavaType calculateJavaType(
140             IntrospectedColumn introspectedColumn) {
141         FullyQualifiedJavaType answer = null;
142         JdbcTypeInformation jdbcTypeInformation = typeMap
143                 .get(introspectedColumn.getJdbcType());
144 
145         if (jdbcTypeInformation != null) {
146             answer = jdbcTypeInformation.getFullyQualifiedJavaType();
147             answer = overrideDefaultType(introspectedColumn, answer);
148         }
149 
150         return answer;
151     }
152 
153     protected FullyQualifiedJavaType overrideDefaultType(IntrospectedColumn column,
154             FullyQualifiedJavaType defaultType) {
155         FullyQualifiedJavaType answer = defaultType;
156 
157         switch (column.getJdbcType()) {
158         case Types.BIT:
159             answer = calculateBitReplacement(column, defaultType);
160             break;
161         case Types.DATE:
162             answer = calculateDateType(column, defaultType);
163             break;
164         case Types.DECIMAL:
165         case Types.NUMERIC:
166             answer = calculateBigDecimalReplacement(column, defaultType);
167             break;
168         case Types.TIME:
169             answer = calculateTimeType(column, defaultType);
170             break;
171         case Types.TIMESTAMP:
172             answer = calculateTimestampType(column, defaultType);
173             break;
174         default:
175             break;
176         }
177 
178         return answer;
179     }
180 
181     protected FullyQualifiedJavaType calculateDateType(IntrospectedColumn column, FullyQualifiedJavaType defaultType) {
182         FullyQualifiedJavaType answer;
183 
184         if (useJSR310Types) {
185             answer = new FullyQualifiedJavaType("java.time.LocalDate"); //$NON-NLS-1$
186         } else {
187             answer = defaultType;
188         }
189 
190         return answer;
191     }
192 
193     protected FullyQualifiedJavaType calculateTimeType(IntrospectedColumn column, FullyQualifiedJavaType defaultType) {
194         FullyQualifiedJavaType answer;
195 
196         if (useJSR310Types) {
197             answer = new FullyQualifiedJavaType("java.time.LocalTime"); //$NON-NLS-1$
198         } else {
199             answer = defaultType;
200         }
201 
202         return answer;
203     }
204 
205     protected FullyQualifiedJavaType calculateTimestampType(IntrospectedColumn column,
206             FullyQualifiedJavaType defaultType) {
207         FullyQualifiedJavaType answer;
208 
209         if (useJSR310Types) {
210             answer = new FullyQualifiedJavaType("java.time.LocalDateTime"); //$NON-NLS-1$
211         } else {
212             answer = defaultType;
213         }
214 
215         return answer;
216     }
217 
218     protected FullyQualifiedJavaType calculateBitReplacement(IntrospectedColumn column,
219             FullyQualifiedJavaType defaultType) {
220         FullyQualifiedJavaType answer;
221 
222         if (column.getLength() > 1) {
223             answer = new FullyQualifiedJavaType("byte[]"); //$NON-NLS-1$
224         } else {
225             answer = defaultType;
226         }
227 
228         return answer;
229     }
230 
231     protected FullyQualifiedJavaType calculateBigDecimalReplacement(IntrospectedColumn column,
232             FullyQualifiedJavaType defaultType) {
233         FullyQualifiedJavaType answer;
234 
235         if (column.getScale() > 0 || column.getLength() > 18 || forceBigDecimals) {
236             answer = defaultType;
237         } else if (column.getLength() > 9) {
238             answer = new FullyQualifiedJavaType(Long.class.getName());
239         } else if (column.getLength() > 4) {
240             answer = new FullyQualifiedJavaType(Integer.class.getName());
241         } else {
242             answer = new FullyQualifiedJavaType(Short.class.getName());
243         }
244 
245         return answer;
246     }
247 
248     @Override
249     public String calculateJdbcTypeName(IntrospectedColumn introspectedColumn) {
250         String answer = null;
251         JdbcTypeInformation jdbcTypeInformation = typeMap
252                 .get(introspectedColumn.getJdbcType());
253 
254         if (jdbcTypeInformation != null) {
255             answer = jdbcTypeInformation.getJdbcTypeName();
256         }
257 
258         return answer;
259     }
260 
261     @Override
262     public void setWarnings(List<String> warnings) {
263         this.warnings = warnings;
264     }
265 
266     @Override
267     public void setContext(Context context) {
268         this.context = context;
269     }
270 
271     public static class JdbcTypeInformation {
272         private final String jdbcTypeName;
273 
274         private final FullyQualifiedJavaType fullyQualifiedJavaType;
275 
276         public JdbcTypeInformation(String jdbcTypeName,
277                 FullyQualifiedJavaType fullyQualifiedJavaType) {
278             this.jdbcTypeName = jdbcTypeName;
279             this.fullyQualifiedJavaType = fullyQualifiedJavaType;
280         }
281 
282         public String getJdbcTypeName() {
283             return jdbcTypeName;
284         }
285 
286         public FullyQualifiedJavaType getFullyQualifiedJavaType() {
287             return fullyQualifiedJavaType;
288         }
289     }
290 }