001/* 002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.util; 017 018import java.io.Serializable; 019import java.math.BigDecimal; 020import java.math.BigInteger; 021import java.time.LocalDate; 022import java.time.LocalDateTime; 023import java.time.LocalTime; 024import java.time.temporal.Temporal; 025import java.util.Date; 026 027public class ConvertUtil { 028 029 private ConvertUtil() { 030 } 031 032 @SuppressWarnings("rawtypes") 033 public static Object convert(Object value, Class targetClass) { 034 return convert(value, targetClass, false); 035 } 036 037 @SuppressWarnings({"unchecked", "rawtypes"}) 038 public static Object convert(Object value, Class targetClass, boolean ignoreConvertError) { 039 if (value == null && targetClass.isPrimitive()) { 040 return getPrimitiveDefaultValue(targetClass); 041 } 042 if (value == null || (targetClass != String.class && value.getClass() == String.class 043 && StringUtil.isBlank((String) value))) { 044 return null; 045 } 046 if (value.getClass().isAssignableFrom(targetClass)) { 047 return value; 048 } 049 if (targetClass == Serializable.class && value instanceof Serializable) { 050 return value; 051 } 052 if (targetClass == String.class) { 053 return value.toString(); 054 } else if (targetClass == Integer.class || targetClass == int.class) { 055 if (value instanceof Number) { 056 return ((Number) value).intValue(); 057 } 058 return Integer.parseInt(value.toString()); 059 } else if (targetClass == Long.class || targetClass == long.class) { 060 if (value instanceof Number) { 061 return ((Number) value).longValue(); 062 } 063 return Long.parseLong(value.toString()); 064 } else if (targetClass == Double.class || targetClass == double.class) { 065 if (value instanceof Number) { 066 return ((Number) value).doubleValue(); 067 } 068 return Double.parseDouble(value.toString()); 069 } else if (targetClass == Float.class || targetClass == float.class) { 070 if (value instanceof Number) { 071 return ((Number) value).floatValue(); 072 } 073 return Float.parseFloat(value.toString()); 074 } else if (targetClass == Boolean.class || targetClass == boolean.class) { 075 String v = value.toString().toLowerCase(); 076 if ("1".equals(v) || "true".equalsIgnoreCase(v)) { 077 return Boolean.TRUE; 078 } else if ("0".equals(v) || "false".equalsIgnoreCase(v)) { 079 return Boolean.FALSE; 080 } else { 081 throw new RuntimeException("Can not parse to boolean type of value: \"" + value + "\""); 082 } 083 } else if (targetClass == java.math.BigDecimal.class) { 084 return new java.math.BigDecimal(value.toString()); 085 } else if (targetClass == java.math.BigInteger.class) { 086 return new java.math.BigInteger(value.toString()); 087 } else if (targetClass == byte[].class) { 088 return value.toString().getBytes(); 089 } else if (targetClass == Date.class) { 090 return DateUtil.parseDate(value); 091 } else if (targetClass == LocalDateTime.class) { 092 return toLocalDateTime(value); 093 } else if (targetClass == LocalDate.class) { 094 return DateUtil.toLocalDate(DateUtil.parseDate(value)); 095 } else if (targetClass == LocalTime.class) { 096 return DateUtil.toLocalTime(DateUtil.parseDate(value)); 097 } else if (targetClass == Short.class || targetClass == short.class) { 098 if (value instanceof Number) { 099 return ((Number) value).shortValue(); 100 } 101 return Short.parseShort(value.toString()); 102 } else if (targetClass.isEnum()) { 103 EnumWrapper<?> enumWrapper = EnumWrapper.of(targetClass); 104 if (enumWrapper.hasEnumValueAnnotation()) { 105 return enumWrapper.getEnum(value); 106 } else if (value instanceof String) { 107 return Enum.valueOf(targetClass, value.toString()); 108 } 109 } 110 if (ignoreConvertError) { 111 return null; 112 } else { 113 throw new IllegalArgumentException("Can not convert \"" + value + "\" to type\"" + targetClass.getName() + "\"."); 114 } 115 } 116 117 118 //Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE 119 public static Object getPrimitiveDefaultValue(Class<?> paraClass) { 120 if (paraClass == int.class || paraClass == long.class || paraClass == float.class || paraClass == double.class) { 121 return 0; 122 } else if (paraClass == boolean.class) { 123 return Boolean.FALSE; 124 } else if (paraClass == short.class) { 125 return (short) 0; 126 } else if (paraClass == byte.class) { 127 return (byte) 0; 128 } else if (paraClass == char.class) { 129 return '\u0000'; 130 } else { 131 throw new IllegalArgumentException("Can not get primitive default value for type: " + paraClass); 132 } 133 } 134 135 public static Class<?> primitiveToBoxed(Class<?> paraClass) { 136 if (paraClass == Integer.TYPE) { 137 return Integer.class; 138 } else if (paraClass == Long.TYPE) { 139 return Long.class; 140 } else if (paraClass == Double.TYPE) { 141 return Double.class; 142 } else if (paraClass == Float.TYPE) { 143 return Float.class; 144 } else if (paraClass == Boolean.TYPE) { 145 return Boolean.class; 146 } else if (paraClass == Short.TYPE) { 147 return Short.class; 148 } else if (paraClass == Byte.TYPE) { 149 return Byte.class; 150 } else if (paraClass == Character.TYPE) { 151 return Character.class; 152 } else { 153 throw new IllegalArgumentException("Can not convert primitive class for type: " + paraClass); 154 } 155 } 156 157 158 public static Integer toInt(Object i) { 159 if (i instanceof Integer) { 160 return (Integer) i; 161 } else if (i instanceof Number) { 162 return ((Number) i).intValue(); 163 } 164 return i != null ? Integer.parseInt(i.toString()) : null; 165 } 166 167 public static Long toLong(Object l) { 168 if (l instanceof Long) { 169 return (Long) l; 170 } else if (l instanceof Number) { 171 return ((Number) l).longValue(); 172 } 173 return l != null ? Long.parseLong(l.toString()) : null; 174 } 175 176 public static Double toDouble(Object d) { 177 if (d instanceof Double) { 178 return (Double) d; 179 } else if (d instanceof Number) { 180 return ((Number) d).doubleValue(); 181 } 182 183 return d != null ? Double.parseDouble(d.toString()) : null; 184 } 185 186 public static BigDecimal toBigDecimal(Object b) { 187 if (b instanceof BigDecimal) { 188 return (BigDecimal) b; 189 } else if (b != null) { 190 return new BigDecimal(b.toString()); 191 } else { 192 return null; 193 } 194 } 195 196 public static BigInteger toBigInteger(Object b) { 197 if (b instanceof BigInteger) { 198 return (BigInteger) b; 199 } 200 // 数据类型 id(19 number)在 Oracle Jdbc 下对应的是 BigDecimal, 201 // 但是在 MySql 下对应的是 BigInteger,这会导致在 MySql 下生成的代码无法在 Oracle 数据库中使用 202 if (b instanceof BigDecimal) { 203 return ((BigDecimal) b).toBigInteger(); 204 } else if (b instanceof Number) { 205 return BigInteger.valueOf(((Number) b).longValue()); 206 } else if (b instanceof String) { 207 return new BigInteger((String) b); 208 } 209 210 return (BigInteger) b; 211 } 212 213 public static Float toFloat(Object f) { 214 if (f instanceof Float) { 215 return (Float) f; 216 } else if (f instanceof Number) { 217 return ((Number) f).floatValue(); 218 } 219 return f != null ? Float.parseFloat(f.toString()) : null; 220 } 221 222 223 public static Short toShort(Object s) { 224 if (s instanceof Short) { 225 return (Short) s; 226 } else if (s instanceof Number) { 227 return ((Number) s).shortValue(); 228 } 229 return s != null ? Short.parseShort(s.toString()) : null; 230 } 231 232 233 public static Byte toByte(Object b) { 234 if (b instanceof Byte) { 235 return (Byte) b; 236 } else if (b instanceof Number) { 237 return ((Number) b).byteValue(); 238 } 239 return b != null ? Byte.parseByte(b.toString()) : null; 240 } 241 242 public static Boolean toBoolean(Object b) { 243 if (b instanceof Boolean) { 244 return (Boolean) b; 245 } else if (b == null) { 246 return null; 247 } 248 249 // 支持 Number 之下的整数类型 250 if (b instanceof Number) { 251 int n = ((Number) b).intValue(); 252 if (n == 1) { 253 return Boolean.TRUE; 254 } else if (n == 0) { 255 return Boolean.FALSE; 256 } 257 throw new IllegalArgumentException("Can not support convert: \"" + b + "\" to boolean."); 258 } 259 260 // 支持 String 261 if (b instanceof String) { 262 String s = b.toString(); 263 if ("true".equalsIgnoreCase(s) || "1".equals(s)) { 264 return Boolean.TRUE; 265 } else if ("false".equalsIgnoreCase(s) || "0".equals(s)) { 266 return Boolean.FALSE; 267 } 268 } 269 270 return (Boolean) b; 271 } 272 273 274 public static Date toDate(Object o) { 275 if (o instanceof Date) { 276 return (Date) o; 277 } 278 279 if (o instanceof Temporal) { 280 if (o instanceof LocalDateTime) { 281 return DateUtil.toDate((LocalDateTime) o); 282 } 283 if (o instanceof LocalDate) { 284 return DateUtil.toDate((LocalDate) o); 285 } 286 if (o instanceof LocalTime) { 287 return DateUtil.toDate((LocalTime) o); 288 } 289 } 290 291 if (o instanceof String) { 292 String s = (String) o; 293 return DateUtil.parseDate(s); 294 } 295 296 return (java.util.Date) o; 297 } 298 299 300 public static LocalDateTime toLocalDateTime(Object o) { 301 if (o instanceof LocalDateTime) { 302 return (LocalDateTime) o; 303 } 304 if (o instanceof java.util.Date) { 305 return DateUtil.toLocalDateTime((java.util.Date) o); 306 } 307 if (o instanceof LocalDate) { 308 return ((LocalDate) o).atStartOfDay(); 309 } 310 if (o instanceof LocalTime) { 311 return LocalDateTime.of(LocalDate.now(), (LocalTime) o); 312 } 313 314 if (o instanceof String) { 315 String s = (String) o; 316 return DateUtil.parseLocalDateTime(s); 317 } 318 319 return (LocalDateTime) o; 320 } 321 322}