From edeff55ababc7ea01dd58ac42f01cf33a024a2d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Fri, 7 Apr 2023 17:27:39 +0800 Subject: [PATCH] optimize Row.java --- .../core/datasource/DataSourceBuilder.java | 2 +- .../core/dialect/CommonsDialectImpl.java | 3 +- .../core/keygen/RowKeyGenerator.java | 5 +- .../core/provider/RowSqlProvider.java | 16 +- .../java/com/mybatisflex/core/row/Row.java | 163 +++++++++- .../java/com/mybatisflex/core/row/RowCPI.java | 49 +++ .../mybatisflex/core/table/ConvertUtil.java | 113 ------- .../com/mybatisflex/core/table/TableInfo.java | 11 +- .../mybatisflex/core/util/ConvertUtil.java | 287 ++++++++++++++++++ .../com/mybatisflex/core/util/DateUtil.java | 60 +++- 10 files changed, 555 insertions(+), 154 deletions(-) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowCPI.java delete mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/table/ConvertUtil.java create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ConvertUtil.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/datasource/DataSourceBuilder.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/datasource/DataSourceBuilder.java index 06136708..a58cd2ec 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/datasource/DataSourceBuilder.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/datasource/DataSourceBuilder.java @@ -15,7 +15,7 @@ */ package com.mybatisflex.core.datasource; -import com.mybatisflex.core.table.ConvertUtil; +import com.mybatisflex.core.util.ConvertUtil; import com.mybatisflex.core.util.StringUtil; import org.apache.ibatis.reflection.Reflector; import org.apache.ibatis.reflection.invoker.Invoker; diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/CommonsDialectImpl.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/CommonsDialectImpl.java index 31a07fff..0384ca77 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/CommonsDialectImpl.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/CommonsDialectImpl.java @@ -19,6 +19,7 @@ import com.mybatisflex.core.FlexConsts; import com.mybatisflex.core.exception.FlexExceptions; import com.mybatisflex.core.query.*; import com.mybatisflex.core.row.Row; +import com.mybatisflex.core.row.RowCPI; import com.mybatisflex.core.table.TableInfo; import com.mybatisflex.core.util.ArrayUtil; import com.mybatisflex.core.util.CollectionUtil; @@ -169,7 +170,7 @@ public class CommonsDialectImpl implements IDialect { StringBuilder sql = new StringBuilder(); Set modifyAttrs = row.obtainModifyAttrs(); - String[] primaryKeys = row.obtainsPrimaryKeyStrings(); + String[] primaryKeys = RowCPI.obtainsPrimaryKeyStrings(row); sql.append("UPDATE ").append(wrap(tableName)).append(" SET "); int index = 0; diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/keygen/RowKeyGenerator.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/keygen/RowKeyGenerator.java index ab0fc4c8..28d11a9d 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/keygen/RowKeyGenerator.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/keygen/RowKeyGenerator.java @@ -15,9 +15,10 @@ */ package com.mybatisflex.core.keygen; -import com.mybatisflex.core.FlexConsts; import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.core.FlexConsts; import com.mybatisflex.core.row.Row; +import com.mybatisflex.core.row.RowCPI; import com.mybatisflex.core.row.RowKey; import com.mybatisflex.core.util.ArrayUtil; import com.mybatisflex.core.util.CollectionUtil; @@ -52,7 +53,7 @@ public class RowKeyGenerator implements KeyGenerator, IMultiKeyGenerator { @Override public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) { Row row = (Row) ((Map) parameter).get(FlexConsts.ROW); - keyGenerators = buildRowKeyGenerators(row.obtainsPrimaryKeys()); + keyGenerators = buildRowKeyGenerators(RowCPI.obtainsPrimaryKeys(row)); for (KeyGenerator keyGenerator : keyGenerators) { keyGenerator.processBefore(executor, ms, stmt, parameter); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/RowSqlProvider.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/RowSqlProvider.java index a78c59bc..91b9b793 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/RowSqlProvider.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/RowSqlProvider.java @@ -20,6 +20,7 @@ import com.mybatisflex.core.exception.FlexExceptions; import com.mybatisflex.core.query.CPI; import com.mybatisflex.core.query.QueryWrapper; import com.mybatisflex.core.row.Row; +import com.mybatisflex.core.row.RowCPI; import com.mybatisflex.core.row.RowMapper; import com.mybatisflex.core.util.ArrayUtil; import com.mybatisflex.core.util.CollectionUtil; @@ -61,7 +62,7 @@ public class RowSqlProvider { public static String insert(Map params) { String tableName = ProviderUtil.getTableName(params); Row row = ProviderUtil.getRow(params); - ProviderUtil.setSqlArgs(params, row.obtainModifyValues()); + ProviderUtil.setSqlArgs(params, RowCPI.obtainModifyValues(row)); return DialectFactory.getDialect().forInsertRow(tableName, row); } @@ -82,16 +83,15 @@ public class RowSqlProvider { //让所有 row 的列顺序和值的数量与第条数据保持一致 //这个必须 new 一个 LinkedHashSet,因为 keepModifyAttrs 会清除 row 所有的 modifyAttrs Set modifyAttrs = new LinkedHashSet<>(rows.get(0).obtainModifyAttrs()); - rows.forEach(row -> row.keepModifyAttrs(modifyAttrs)); + rows.forEach(row -> RowCPI.keepModifyAttrs(row, modifyAttrs)); Object[] values = new Object[]{}; for (Row row : rows) { - values = ArrayUtil.concat(values, row.obtainModifyValues()); + values = ArrayUtil.concat(values, RowCPI.obtainModifyValues(row)); } ProviderUtil.setSqlArgs(params, values); - //sql: INSERT INTO `tb_table`(`name`, `sex`) VALUES (?, ?),(?, ?),(?, ?) return DialectFactory.getDialect().forInsertBatchWithFirstRowColumns(tableName, rows); } @@ -144,7 +144,7 @@ public class RowSqlProvider { public static String deleteByQuery(Map params) { String tableName = ProviderUtil.getTableName(params); QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); - CPI.setFromIfNecessary(queryWrapper,tableName); + CPI.setFromIfNecessary(queryWrapper, tableName); Object[] valueArray = CPI.getValueArray(queryWrapper); ProviderUtil.setSqlArgs(params, valueArray); @@ -162,7 +162,7 @@ public class RowSqlProvider { public static String updateById(Map params) { String tableName = ProviderUtil.getTableName(params); Row row = ProviderUtil.getRow(params); - ProviderUtil.setSqlArgs(params, row.obtainAllModifyValues()); + ProviderUtil.setSqlArgs(params, RowCPI.obtainAllModifyValues(row)); return DialectFactory.getDialect().forUpdateById(tableName, row); } @@ -181,7 +181,7 @@ public class RowSqlProvider { QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); CPI.setFromIfNecessary(queryWrapper, tableName); - Object[] modifyValues = data.obtainModifyValues(); + Object[] modifyValues = RowCPI.obtainModifyValues(data); Object[] valueArray = CPI.getValueArray(queryWrapper); ProviderUtil.setSqlArgs(params, ArrayUtil.concat(modifyValues, valueArray)); @@ -207,7 +207,7 @@ public class RowSqlProvider { Object[] values = new Object[0]; for (Row row : rows) { - values = ArrayUtil.concat(values, row.obtainAllModifyValues()); + values = ArrayUtil.concat(values, RowCPI.obtainAllModifyValues(row)); } ProviderUtil.setSqlArgs(params, values); return DialectFactory.getDialect().forUpdateBatchById(tableName, rows); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java index 2ec0966f..0dd63414 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java @@ -20,12 +20,19 @@ import com.mybatisflex.core.query.QueryColumn; import com.mybatisflex.core.table.TableInfo; import com.mybatisflex.core.table.TableInfoFactory; import com.mybatisflex.core.util.ArrayUtil; +import com.mybatisflex.core.util.ConvertUtil; import com.mybatisflex.core.util.SqlUtil; import com.mybatisflex.core.util.StringUtil; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Time; +import java.sql.Timestamp; +import java.time.LocalDateTime; import java.util.*; public class Row extends HashMap implements ModifyAttrsRecord { + private static final Object[] NULL_ARGS = new Object[0]; //主键,多个主键用英文逗号隔开 @@ -125,25 +132,156 @@ public class Row extends HashMap implements ModifyAttrsRecord { } - public Object get(Object key, Object defaultValue) { + public Object get(String key, Object defaultValue) { Object result = super.get(key); return result != null ? result : defaultValue; } + public String getString(String key) { + Object s = super.get(key); + return s != null ? s.toString() : null; + } + + + public String getString(String key, String defaultValue) { + Object s = super.get(key); + if (s == null) { + return defaultValue; + } + String r = s.toString(); + return r.trim().length() == 0 ? defaultValue : r; + } + + public Integer getInt(String key) { + return ConvertUtil.toInt(super.get(key)); + } + + public Integer getInt(String key, Integer defaultValue) { + Integer r = ConvertUtil.toInt(super.get(key)); + return r != null ? r : defaultValue; + } + + public Long getLong(String key) { + return ConvertUtil.toLong(super.get(key)); + } + + public Long getLong(String key, Long defaultValue) { + Long r = ConvertUtil.toLong(super.get(key)); + return r != null ? r : defaultValue; + } + + public Double getDouble(String key) { + return ConvertUtil.toDouble(super.get(key)); + } + + public Double getDouble(String key, Double defaultValue) { + Double r = ConvertUtil.toDouble(super.get(key)); + return r != null ? r : defaultValue; + } + + + public Float getFloat(String key, Float defaultValue) { + Float r = ConvertUtil.toFloat(super.get(key)); + return r != null ? r : defaultValue; + } + + public Float getFloat(String key) { + return ConvertUtil.toFloat(super.get(key)); + } + + + public Short getShort(String key, Short defaultValue) { + Short r = ConvertUtil.toShort(super.get(key)); + return r != null ? r : defaultValue; + } + + public Short getShort(String key) { + return ConvertUtil.toShort(super.get(key)); + } + + public BigInteger getBigInteger(String key) { + return ConvertUtil.toBigInteger(super.get(key)); + } + + public BigInteger getBigInteger(String key, BigInteger defaultValue) { + BigInteger r = ConvertUtil.toBigInteger(super.get(key)); + return r != null ? r : defaultValue; + } + + public BigDecimal getBigDecimal(String key) { + return ConvertUtil.toBigDecimal(super.get(key)); + } + + public BigDecimal getBigDecimal(String key, BigDecimal defaultValue) { + BigDecimal r = ConvertUtil.toBigDecimal(super.get(key)); + return r != null ? r : defaultValue; + } + + public Boolean getBoolean(String key) { + return ConvertUtil.toBoolean(super.get(key)); + } + + public Boolean getBoolean(String key, Boolean defaultValue) { + Boolean r = ConvertUtil.toBoolean(super.get(key)); + return r != null ? r : defaultValue; + } + + public Date getDate(String key) { + return ConvertUtil.toDate(super.get(key)); + } + + public Date getDate(String key, Date defaultValue) { + Date r = ConvertUtil.toDate(super.get(key)); + return r != null ? r : defaultValue; + } + + public LocalDateTime getLocalDateTime(String key) { + return ConvertUtil.toLocalDateTime(super.get(key)); + } + + public LocalDateTime getLocalDateTime(String key, LocalDateTime defaultValue) { + LocalDateTime r = ConvertUtil.toLocalDateTime(super.get(key)); + return r != null ? r : defaultValue; + } + + public Time getTime(String key) { + return (Time) super.get(key); + } + + public Time getTime(String key, Time defaultValue) { + Time r = (Time) super.get(key); + return r != null ? r : defaultValue; + } + + public Timestamp getTimestamp(String key) { + return (Timestamp) super.get(key); + } + + public Timestamp getTimestamp(String key, Timestamp defaultValue) { + Timestamp r = (Timestamp) super.get(key); + return r != null ? r : defaultValue; + } + + public Byte getByte(String key) { + return ConvertUtil.toByte(super.get(key)); + } + + public byte[] getBytes(String key) { + return (byte[]) super.get(key); + } + @Override public Object remove(Object key) { removeModifyAttr(key.toString()); return super.remove(key); } - public T toEntity(Class entityClass) { TableInfo tableInfo = TableInfoFactory.ofEntityClass(entityClass); return tableInfo.newInstanceByRow(this); } - public Map toCamelKeysMap() { Map ret = new HashMap<>(); for (String key : keySet()) { @@ -152,7 +290,6 @@ public class Row extends HashMap implements ModifyAttrsRecord { return ret; } - public Map toUnderlineKeysMap() { Map ret = new HashMap<>(); for (String key : keySet()) { @@ -162,22 +299,18 @@ public class Row extends HashMap implements ModifyAttrsRecord { } - public void keepModifyAttrs(Collection attrs) { + void keepModifyAttrs(Collection attrs) { if (attrs == null) { throw new NullPointerException("attrs is null."); } - clearModifyFlag(); modifyAttrs.addAll(attrs); } /** - * 获取修改的值,值需要保持顺序 - * 返回的内容不包含主键的值 - * - * @return values 数组 + * 获取修改的值,值需要保持顺序,返回的内容不包含主键的值 */ - public Object[] obtainModifyValues() { + Object[] obtainModifyValues() { Object[] values = new Object[modifyAttrs.size()]; int index = 0; for (String modifyAttr : modifyAttrs) { @@ -187,7 +320,7 @@ public class Row extends HashMap implements ModifyAttrsRecord { } - public String[] obtainsPrimaryKeyStrings() { + String[] obtainsPrimaryKeyStrings() { String[] returnKeys = new String[primaryKeys.length]; for (int i = 0; i < primaryKeys.length; i++) { returnKeys[i] = primaryKeys[i].keyColumn; @@ -196,12 +329,12 @@ public class Row extends HashMap implements ModifyAttrsRecord { } - public RowKey[] obtainsPrimaryKeys() { + RowKey[] obtainsPrimaryKeys() { return this.primaryKeys; } - public Object[] obtainsPrimaryValues() { + Object[] obtainsPrimaryValues() { if (ArrayUtil.isEmpty(primaryKeys)) { return NULL_ARGS; } @@ -213,7 +346,7 @@ public class Row extends HashMap implements ModifyAttrsRecord { } - public Object[] obtainAllModifyValues() { + Object[] obtainAllModifyValues() { return ArrayUtil.concat(obtainModifyValues(), obtainsPrimaryValues()); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowCPI.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowCPI.java new file mode 100644 index 00000000..5001747c --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowCPI.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.core.row; + +import java.util.Collection; + +/** + * cross package invoker + */ +public class RowCPI { + + public static void keepModifyAttrs(Row row, Collection attrs) { + row.keepModifyAttrs(attrs); + } + + public static Object[] obtainModifyValues(Row row) { + return row.obtainModifyValues(); + } + + public static String[] obtainsPrimaryKeyStrings(Row row) { + return row.obtainsPrimaryKeyStrings(); + } + + public static RowKey[] obtainsPrimaryKeys(Row row) { + return row.obtainsPrimaryKeys(); + } + + public static Object[] obtainsPrimaryValues(Row row) { + return row.obtainsPrimaryValues(); + } + + public static Object[] obtainAllModifyValues(Row row) { + return row.obtainAllModifyValues(); + } + +} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/ConvertUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/ConvertUtil.java deleted file mode 100644 index a3df77c3..00000000 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/ConvertUtil.java +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.mybatisflex.core.table; - -import com.mybatisflex.core.util.DateUtil; -import com.mybatisflex.core.util.StringUtil; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.util.Date; - -public class ConvertUtil { - - - public static Object convert(Object value, Class targetClass) { - if (value == null && targetClass.isPrimitive()){ - return getPrimitiveDefaultValue(targetClass); - } - if (value == null || (targetClass != String.class && value.getClass() == String.class - && StringUtil.isBlank((String) value))) { - return null; - } - if (value.getClass().isAssignableFrom(targetClass)) { - return value; - } - if (targetClass == String.class) { - return value.toString(); - } else if (targetClass == Integer.class || targetClass == int.class) { - if (value instanceof Number) { - return ((Number) value).intValue(); - } - return Integer.parseInt(value.toString()); - } else if (targetClass == Long.class || targetClass == long.class) { - if (value instanceof Number) { - return ((Number) value).longValue(); - } - return Long.parseLong(value.toString()); - } else if (targetClass == Double.class || targetClass == double.class) { - if (value instanceof Number) { - return ((Number) value).doubleValue(); - } - return Double.parseDouble(value.toString()); - } else if (targetClass == Float.class || targetClass == float.class) { - if (value instanceof Number) { - return ((Number) value).floatValue(); - } - return Float.parseFloat(value.toString()); - } else if (targetClass == Boolean.class || targetClass == boolean.class) { - String v = value.toString().toLowerCase(); - if ("1".equals(v) || "true".equalsIgnoreCase(v)) { - return Boolean.TRUE; - } else if ("0".equals(v) || "false".equalsIgnoreCase(v)) { - return Boolean.FALSE; - } else { - throw new RuntimeException("Can not parse to boolean type of value: \"" + value + "\""); - } - } else if (targetClass == java.math.BigDecimal.class) { - return new java.math.BigDecimal(value.toString()); - } else if (targetClass == java.math.BigInteger.class) { - return new java.math.BigInteger(value.toString()); - } else if (targetClass == byte[].class) { - return value.toString().getBytes(); - } else if (targetClass == Date.class) { - return DateUtil.parseDate(value); - } else if (targetClass == LocalDateTime.class) { - return DateUtil.toLocalDateTime(DateUtil.parseDate(value)); - } else if (targetClass == LocalDate.class) { - return DateUtil.toLocalDate(DateUtil.parseDate(value)); - } else if (targetClass == LocalTime.class) { - return DateUtil.toLocalTime(DateUtil.parseDate(value)); - } else if (targetClass == Short.class || targetClass == short.class) { - if (value instanceof Number) { - return ((Number) value).shortValue(); - } - return Short.parseShort(value.toString()); - } - - throw new IllegalArgumentException("\"" + targetClass.getName() + "\" can not be parsed."); - } - - - //Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE - public static Object getPrimitiveDefaultValue(Class paraClass) { - if (paraClass == int.class || paraClass == long.class || paraClass == float.class || paraClass == double.class) { - return 0; - } else if (paraClass == boolean.class) { - return Boolean.FALSE; - } else if (paraClass == short.class) { - return (short) 0; - } else if (paraClass == byte.class) { - return (byte) 0; - } else if (paraClass == char.class) { - return '\u0000'; - } else { - //不存在这种类型 - return null; - } - } -} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfo.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfo.java index 2d0d9e05..ba46848c 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfo.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfo.java @@ -23,10 +23,7 @@ import com.mybatisflex.annotation.KeyType; import com.mybatisflex.core.javassist.ModifyAttrsRecord; import com.mybatisflex.core.mybatis.TypeHandlerObject; import com.mybatisflex.core.row.Row; -import com.mybatisflex.core.util.ArrayUtil; -import com.mybatisflex.core.util.ClassUtil; -import com.mybatisflex.core.util.CollectionUtil; -import com.mybatisflex.core.util.StringUtil; +import com.mybatisflex.core.util.*; import org.apache.ibatis.mapping.ResultFlag; import org.apache.ibatis.mapping.ResultMap; import org.apache.ibatis.mapping.ResultMapping; @@ -406,9 +403,9 @@ public class TableInfo { // ModifyAttrsRecord 忽略 ignoreNulls 的设置, // 当使用 ModifyAttrsRecord 时,可以理解为要对字段进行 null 值进行更新,否则没必要使用 ModifyAttrsRecord - // if (ignoreNulls && value == null) { - // continue; - // } + // if (ignoreNulls && value == null) { + // continue; + // } values.add(value); } } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ConvertUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ConvertUtil.java new file mode 100644 index 00000000..157ffeb7 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ConvertUtil.java @@ -0,0 +1,287 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.core.util; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.temporal.Temporal; +import java.util.Date; + +public class ConvertUtil { + + + public static Object convert(Object value, Class targetClass) { + if (value == null && targetClass.isPrimitive()) { + return getPrimitiveDefaultValue(targetClass); + } + if (value == null || (targetClass != String.class && value.getClass() == String.class + && StringUtil.isBlank((String) value))) { + return null; + } + if (value.getClass().isAssignableFrom(targetClass)) { + return value; + } + if (targetClass == String.class) { + return value.toString(); + } else if (targetClass == Integer.class || targetClass == int.class) { + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return Integer.parseInt(value.toString()); + } else if (targetClass == Long.class || targetClass == long.class) { + if (value instanceof Number) { + return ((Number) value).longValue(); + } + return Long.parseLong(value.toString()); + } else if (targetClass == Double.class || targetClass == double.class) { + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } else if (targetClass == Float.class || targetClass == float.class) { + if (value instanceof Number) { + return ((Number) value).floatValue(); + } + return Float.parseFloat(value.toString()); + } else if (targetClass == Boolean.class || targetClass == boolean.class) { + String v = value.toString().toLowerCase(); + if ("1".equals(v) || "true".equalsIgnoreCase(v)) { + return Boolean.TRUE; + } else if ("0".equals(v) || "false".equalsIgnoreCase(v)) { + return Boolean.FALSE; + } else { + throw new RuntimeException("Can not parse to boolean type of value: \"" + value + "\""); + } + } else if (targetClass == java.math.BigDecimal.class) { + return new java.math.BigDecimal(value.toString()); + } else if (targetClass == java.math.BigInteger.class) { + return new java.math.BigInteger(value.toString()); + } else if (targetClass == byte[].class) { + return value.toString().getBytes(); + } else if (targetClass == Date.class) { + return DateUtil.parseDate(value); + } else if (targetClass == LocalDateTime.class) { + return toLocalDateTime(value); + } else if (targetClass == LocalDate.class) { + return DateUtil.toLocalDate(DateUtil.parseDate(value)); + } else if (targetClass == LocalTime.class) { + return DateUtil.toLocalTime(DateUtil.parseDate(value)); + } else if (targetClass == Short.class || targetClass == short.class) { + if (value instanceof Number) { + return ((Number) value).shortValue(); + } + return Short.parseShort(value.toString()); + } + + throw new IllegalArgumentException("\"" + targetClass.getName() + "\" can not be parsed."); + } + + + //Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE + public static Object getPrimitiveDefaultValue(Class paraClass) { + if (paraClass == int.class || paraClass == long.class || paraClass == float.class || paraClass == double.class) { + return 0; + } else if (paraClass == boolean.class) { + return Boolean.FALSE; + } else if (paraClass == short.class) { + return (short) 0; + } else if (paraClass == byte.class) { + return (byte) 0; + } else if (paraClass == char.class) { + return '\u0000'; + } else { + throw new IllegalArgumentException("Can not get primitive default value for type: " + paraClass); + } + } + + + public static Integer toInt(Object i) { + if (i instanceof Integer) { + return (Integer) i; + } else if (i instanceof Number) { + return ((Number) i).intValue(); + } + return i != null ? Integer.parseInt(i.toString()) : null; + } + + public static Long toLong(Object l) { + if (l instanceof Long) { + return (Long) l; + } else if (l instanceof Number) { + return ((Number) l).longValue(); + } + return l != null ? Long.parseLong(l.toString()) : null; + } + + public static Double toDouble(Object d) { + if (d instanceof Double) { + return (Double) d; + } else if (d instanceof Number) { + return ((Number) d).doubleValue(); + } + + return d != null ? Double.parseDouble(d.toString()) : null; + } + + public static BigDecimal toBigDecimal(Object b) { + if (b instanceof BigDecimal) { + return (BigDecimal) b; + } else if (b != null) { + return new BigDecimal(b.toString()); + } else { + return null; + } + } + + public static BigInteger toBigInteger(Object b) { + if (b instanceof BigInteger) { + return (BigInteger)b; + } + // 数据类型 id(19 number)在 Oracle Jdbc 下对应的是 BigDecimal, + // 但是在 MySql 下对应的是 BigInteger,这会导致在 MySql 下生成的代码无法在 Oracle 数据库中使用 + if (b instanceof BigDecimal) { + return ((BigDecimal)b).toBigInteger(); + } else if (b instanceof Number) { + return BigInteger.valueOf(((Number)b).longValue()); + } else if (b instanceof String) { + return new BigInteger((String)b); + } + + return (BigInteger)b; + } + + public static Float toFloat(Object f) { + if (f instanceof Float) { + return (Float) f; + } else if (f instanceof Number) { + return ((Number) f).floatValue(); + } + return f != null ? Float.parseFloat(f.toString()) : null; + } + + + public static Short toShort(Object s) { + if (s instanceof Short) { + return (Short) s; + } else if (s instanceof Number) { + return ((Number) s).shortValue(); + } + return s != null ? Short.parseShort(s.toString()) : null; + } + + + public static Byte toByte(Object b) { + if (b instanceof Byte) { + return (Byte) b; + } else if (b instanceof Number) { + return ((Number) b).byteValue(); + } + return b != null ? Byte.parseByte(b.toString()) : null; + } + + public static Boolean toBoolean(Object b) { + if (b instanceof Boolean) { + return (Boolean) b; + } else if (b == null) { + return null; + } + + // 支持 Number 之下的整数类型 + if (b instanceof Number) { + int n = ((Number) b).intValue(); + if (n == 1) { + return Boolean.TRUE; + } else if (n == 0) { + return Boolean.FALSE; + } + throw new IllegalArgumentException("Can not support convert: \"" + b + "\" to boolean."); + } + + // 支持 String + if (b instanceof String) { + String s = b.toString(); + if ("true".equalsIgnoreCase(s) || "1".equals(s)) { + return Boolean.TRUE; + } else if ("false".equalsIgnoreCase(s) || "0".equals(s)) { + return Boolean.FALSE; + } + } + + return (Boolean) b; + } + + public static Number toNumber(Object o) { + if (o instanceof Number) { + return (Number) o; + } else if (o == null) { + return null; + } + String s = o.toString(); + return s.indexOf('.') != -1 ? Double.parseDouble(s) : Long.parseLong(s); + } + + + public static Date toDate(Object o) { + if (o instanceof Date) { + return (Date) o; + } + + if (o instanceof Temporal) { + if (o instanceof LocalDateTime) { + return DateUtil.toDate((LocalDateTime) o); + } + if (o instanceof LocalDate) { + return DateUtil.toDate((LocalDate) o); + } + if (o instanceof LocalTime) { + return DateUtil.toDate((LocalTime) o); + } + } + + if (o instanceof String) { + String s = (String) o; + return DateUtil.parseDate(s); + } + + return (java.util.Date) o; + } + + + public static LocalDateTime toLocalDateTime(Object o) { + if (o instanceof LocalDateTime) { + return (LocalDateTime) o; + } + if (o instanceof java.util.Date) { + return DateUtil.toLocalDateTime((java.util.Date) o); + } + if (o instanceof LocalDate) { + return ((LocalDate) o).atStartOfDay(); + } + if (o instanceof LocalTime) { + return LocalDateTime.of(LocalDate.now(), (LocalTime) o); + } + + if (o instanceof String) { + String s = (String) o; + return DateUtil.parseLocalDateTime(s); + } + + return (LocalDateTime) o; + } +} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/DateUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/DateUtil.java index 5c50432d..1aca1cb8 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/DateUtil.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/DateUtil.java @@ -20,13 +20,14 @@ import java.sql.Timestamp; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.*; +import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.HashMap; import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + -/** - * @author michael yang (fuhai999@gmail.com) - */ public class DateUtil { public static String datePatternWithoutDividing = "yyyyMMdd"; @@ -39,6 +40,16 @@ public class DateUtil { private static final ThreadLocal> TL = ThreadLocal.withInitial(() -> new HashMap<>()); + private static final Map dateTimeFormatters = new ConcurrentHashMap<>(); + + public static DateTimeFormatter getDateTimeFormatter(String pattern) { + DateTimeFormatter ret = dateTimeFormatters.get(pattern); + if (ret == null) { + ret = DateTimeFormatter.ofPattern(pattern); + dateTimeFormatters.put(pattern, ret); + } + return ret; + } public static SimpleDateFormat getSimpleDateFormat(String pattern) { SimpleDateFormat ret = TL.get().get(pattern); @@ -54,8 +65,6 @@ public class DateUtil { } - - public static Date parseDate(Object value) { if (value instanceof Number) { return new Date(((Number) value).longValue()); @@ -122,6 +131,45 @@ public class DateUtil { } + + public static LocalDateTime parseLocalDateTime(String dateString) { + if (StringUtil.isBlank(dateString)) { + return null; + } + dateString = dateString.trim(); + DateTimeFormatter dateTimeFormatter = getDateTimeFormatter(getPattern(dateString)); + try { + return LocalDateTime.parse(dateString, dateTimeFormatter); + } catch (Exception ex) { + //2022-10-23 00:00:00.0 + int lastIndexOf = dateString.lastIndexOf("."); + if (lastIndexOf == 19) { + return parseLocalDateTime(dateString.substring(0, lastIndexOf)); + } + + //2022-10-23 00:00:00,0 + lastIndexOf = dateString.lastIndexOf(","); + if (lastIndexOf == 19) { + return parseLocalDateTime(dateString.substring(0, lastIndexOf)); + } + + //2022-10-23 00:00:00 000123 + lastIndexOf = dateString.lastIndexOf(" "); + if (lastIndexOf == 19) { + return parseLocalDateTime(dateString.substring(0, lastIndexOf)); + } + + if (dateString.contains(".") || dateString.contains("/")) { + dateString = dateString.replace(".", "-").replace("/", "-"); + dateTimeFormatter = getDateTimeFormatter(getPattern(dateString)); + return LocalDateTime.parse(dateString, dateTimeFormatter); + } else { + throw ex; + } + } + } + + private static String getPattern(String dateString) { int length = dateString.length(); if (length == datetimePattern.length()) { @@ -145,7 +193,6 @@ public class DateUtil { } - public static LocalDateTime toLocalDateTime(Date date) { if (date == null) { return null; @@ -177,7 +224,6 @@ public class DateUtil { } - public static LocalTime toLocalTime(Date date) { if (date == null) { return null;