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 com.mybatisflex.annotation.EnumValue; 019 020import java.lang.reflect.Field; 021import java.lang.reflect.Method; 022import java.lang.reflect.Modifier; 023import java.math.BigDecimal; 024import java.math.BigInteger; 025import java.time.LocalDate; 026import java.time.LocalDateTime; 027import java.time.LocalTime; 028import java.time.temporal.Temporal; 029import java.util.Date; 030import java.util.List; 031import java.util.Objects; 032 033public class ConvertUtil { 034 035 036 public static Object convert(Object value, Class targetClass) { 037 if (value == null && targetClass.isPrimitive()) { 038 return getPrimitiveDefaultValue(targetClass); 039 } 040 if (value == null || (targetClass != String.class && value.getClass() == String.class 041 && StringUtil.isBlank((String) value))) { 042 return null; 043 } 044 if (value.getClass().isAssignableFrom(targetClass)) { 045 return value; 046 } 047 if (targetClass == String.class) { 048 return value.toString(); 049 } else if (targetClass == Integer.class || targetClass == int.class) { 050 if (value instanceof Number) { 051 return ((Number) value).intValue(); 052 } 053 return Integer.parseInt(value.toString()); 054 } else if (targetClass == Long.class || targetClass == long.class) { 055 if (value instanceof Number) { 056 return ((Number) value).longValue(); 057 } 058 return Long.parseLong(value.toString()); 059 } else if (targetClass == Double.class || targetClass == double.class) { 060 if (value instanceof Number) { 061 return ((Number) value).doubleValue(); 062 } 063 return Double.parseDouble(value.toString()); 064 } else if (targetClass == Float.class || targetClass == float.class) { 065 if (value instanceof Number) { 066 return ((Number) value).floatValue(); 067 } 068 return Float.parseFloat(value.toString()); 069 } else if (targetClass == Boolean.class || targetClass == boolean.class) { 070 String v = value.toString().toLowerCase(); 071 if ("1".equals(v) || "true".equalsIgnoreCase(v)) { 072 return Boolean.TRUE; 073 } else if ("0".equals(v) || "false".equalsIgnoreCase(v)) { 074 return Boolean.FALSE; 075 } else { 076 throw new RuntimeException("Can not parse to boolean type of value: \"" + value + "\""); 077 } 078 } else if (targetClass == java.math.BigDecimal.class) { 079 return new java.math.BigDecimal(value.toString()); 080 } else if (targetClass == java.math.BigInteger.class) { 081 return new java.math.BigInteger(value.toString()); 082 } else if (targetClass == byte[].class) { 083 return value.toString().getBytes(); 084 } else if (targetClass == Date.class) { 085 return DateUtil.parseDate(value); 086 } else if (targetClass == LocalDateTime.class) { 087 return toLocalDateTime(value); 088 } else if (targetClass == LocalDate.class) { 089 return DateUtil.toLocalDate(DateUtil.parseDate(value)); 090 } else if (targetClass == LocalTime.class) { 091 return DateUtil.toLocalTime(DateUtil.parseDate(value)); 092 } else if (targetClass == Short.class || targetClass == short.class) { 093 if (value instanceof Number) { 094 return ((Number) value).shortValue(); 095 } 096 return Short.parseShort(value.toString()); 097 } else if (targetClass.isEnum()) { 098 Object[] enumConstants = targetClass.getEnumConstants(); 099 List<Field> allFields = ClassUtil.getAllFields(targetClass, field -> field.getAnnotation(EnumValue.class) != null); 100 if (allFields.size() == 1) { 101 Field field = allFields.get(0); 102 103 String fieldGetterName = "get" + StringUtil.firstCharToUpperCase(field.getName()); 104 List<Method> allMethods = ClassUtil.getAllMethods(targetClass, method -> { 105 String methodName = method.getName(); 106 return methodName.equals(fieldGetterName); 107 }); 108 109 //getter 110 if (allMethods.size() == 1) { 111 Method getter = allMethods.get(0); 112 for (Object enumConstant : enumConstants) { 113 try { 114 Object enumValue = getter.invoke(enumConstant); 115 if (Objects.equals(enumValue, value)) { 116 return enumConstant; 117 } 118 } catch (Exception e) { 119 throw new RuntimeException(e); 120 } 121 } 122 } 123 124 //public field 125 else if (Modifier.isPublic(field.getModifiers())) { 126 for (Object enumConstant : enumConstants) { 127 if (Objects.equals(readPublicField(field, enumConstant), value)) { 128 return enumConstant; 129 } 130 } 131 } 132 } else if (value instanceof String) { 133 return Enum.valueOf(targetClass, value.toString()); 134 } 135 } 136 137 138 throw new IllegalArgumentException("\"" + targetClass.getName() + "\" can not be parsed."); 139 } 140 141 142 private static Object readPublicField(Field field, Object target) { 143 try { 144 return field.get(target); 145 } catch (IllegalAccessException e) { 146 throw new RuntimeException(e); 147 } 148 } 149 150 151 //Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE 152 public static Object getPrimitiveDefaultValue(Class<?> paraClass) { 153 if (paraClass == int.class || paraClass == long.class || paraClass == float.class || paraClass == double.class) { 154 return 0; 155 } else if (paraClass == boolean.class) { 156 return Boolean.FALSE; 157 } else if (paraClass == short.class) { 158 return (short) 0; 159 } else if (paraClass == byte.class) { 160 return (byte) 0; 161 } else if (paraClass == char.class) { 162 return '\u0000'; 163 } else { 164 throw new IllegalArgumentException("Can not get primitive default value for type: " + paraClass); 165 } 166 } 167 168 169 public static Integer toInt(Object i) { 170 if (i instanceof Integer) { 171 return (Integer) i; 172 } else if (i instanceof Number) { 173 return ((Number) i).intValue(); 174 } 175 return i != null ? Integer.parseInt(i.toString()) : null; 176 } 177 178 public static Long toLong(Object l) { 179 if (l instanceof Long) { 180 return (Long) l; 181 } else if (l instanceof Number) { 182 return ((Number) l).longValue(); 183 } 184 return l != null ? Long.parseLong(l.toString()) : null; 185 } 186 187 public static Double toDouble(Object d) { 188 if (d instanceof Double) { 189 return (Double) d; 190 } else if (d instanceof Number) { 191 return ((Number) d).doubleValue(); 192 } 193 194 return d != null ? Double.parseDouble(d.toString()) : null; 195 } 196 197 public static BigDecimal toBigDecimal(Object b) { 198 if (b instanceof BigDecimal) { 199 return (BigDecimal) b; 200 } else if (b != null) { 201 return new BigDecimal(b.toString()); 202 } else { 203 return null; 204 } 205 } 206 207 public static BigInteger toBigInteger(Object b) { 208 if (b instanceof BigInteger) { 209 return (BigInteger) b; 210 } 211 // 数据类型 id(19 number)在 Oracle Jdbc 下对应的是 BigDecimal, 212 // 但是在 MySql 下对应的是 BigInteger,这会导致在 MySql 下生成的代码无法在 Oracle 数据库中使用 213 if (b instanceof BigDecimal) { 214 return ((BigDecimal) b).toBigInteger(); 215 } else if (b instanceof Number) { 216 return BigInteger.valueOf(((Number) b).longValue()); 217 } else if (b instanceof String) { 218 return new BigInteger((String) b); 219 } 220 221 return (BigInteger) b; 222 } 223 224 public static Float toFloat(Object f) { 225 if (f instanceof Float) { 226 return (Float) f; 227 } else if (f instanceof Number) { 228 return ((Number) f).floatValue(); 229 } 230 return f != null ? Float.parseFloat(f.toString()) : null; 231 } 232 233 234 public static Short toShort(Object s) { 235 if (s instanceof Short) { 236 return (Short) s; 237 } else if (s instanceof Number) { 238 return ((Number) s).shortValue(); 239 } 240 return s != null ? Short.parseShort(s.toString()) : null; 241 } 242 243 244 public static Byte toByte(Object b) { 245 if (b instanceof Byte) { 246 return (Byte) b; 247 } else if (b instanceof Number) { 248 return ((Number) b).byteValue(); 249 } 250 return b != null ? Byte.parseByte(b.toString()) : null; 251 } 252 253 public static Boolean toBoolean(Object b) { 254 if (b instanceof Boolean) { 255 return (Boolean) b; 256 } else if (b == null) { 257 return null; 258 } 259 260 // 支持 Number 之下的整数类型 261 if (b instanceof Number) { 262 int n = ((Number) b).intValue(); 263 if (n == 1) { 264 return Boolean.TRUE; 265 } else if (n == 0) { 266 return Boolean.FALSE; 267 } 268 throw new IllegalArgumentException("Can not support convert: \"" + b + "\" to boolean."); 269 } 270 271 // 支持 String 272 if (b instanceof String) { 273 String s = b.toString(); 274 if ("true".equalsIgnoreCase(s) || "1".equals(s)) { 275 return Boolean.TRUE; 276 } else if ("false".equalsIgnoreCase(s) || "0".equals(s)) { 277 return Boolean.FALSE; 278 } 279 } 280 281 return (Boolean) b; 282 } 283 284 public static Number toNumber(Object o) { 285 if (o instanceof Number) { 286 return (Number) o; 287 } else if (o == null) { 288 return null; 289 } 290 String s = o.toString(); 291 return s.indexOf('.') != -1 ? Double.parseDouble(s) : Long.parseLong(s); 292 } 293 294 295 public static Date toDate(Object o) { 296 if (o instanceof Date) { 297 return (Date) o; 298 } 299 300 if (o instanceof Temporal) { 301 if (o instanceof LocalDateTime) { 302 return DateUtil.toDate((LocalDateTime) o); 303 } 304 if (o instanceof LocalDate) { 305 return DateUtil.toDate((LocalDate) o); 306 } 307 if (o instanceof LocalTime) { 308 return DateUtil.toDate((LocalTime) o); 309 } 310 } 311 312 if (o instanceof String) { 313 String s = (String) o; 314 return DateUtil.parseDate(s); 315 } 316 317 return (java.util.Date) o; 318 } 319 320 321 public static LocalDateTime toLocalDateTime(Object o) { 322 if (o instanceof LocalDateTime) { 323 return (LocalDateTime) o; 324 } 325 if (o instanceof java.util.Date) { 326 return DateUtil.toLocalDateTime((java.util.Date) o); 327 } 328 if (o instanceof LocalDate) { 329 return ((LocalDate) o).atStartOfDay(); 330 } 331 if (o instanceof LocalTime) { 332 return LocalDateTime.of(LocalDate.now(), (LocalTime) o); 333 } 334 335 if (o instanceof String) { 336 String s = (String) o; 337 return DateUtil.parseLocalDateTime(s); 338 } 339 340 return (LocalDateTime) o; 341 } 342}