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