From 32d8515bf445d2d942ec7256f312504bbb2ab2fb Mon Sep 17 00:00:00 2001 From: Redkale <8730487+redkale@users.noreply.github.com> Date: Wed, 28 Nov 2018 11:17:55 +0800 Subject: [PATCH] =?UTF-8?q?DataSource=E5=A2=9E=E5=8A=A0=E9=83=A8=E5=88=86J?= =?UTF-8?q?SON=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/org/redkale/source/DataJdbcSource.java | 57 ++++---- src/org/redkale/source/DataSources.java | 4 +- src/org/redkale/source/EntityInfo.java | 30 +++++ src/org/redkale/source/SourceConvert.java | 28 ++++ test/org/redkale/test/source/JsonRecord.java | 122 ++++++++++++++++++ test/org/redkale/test/util/UntilTestMain.java | 1 + 6 files changed, 210 insertions(+), 32 deletions(-) create mode 100644 src/org/redkale/source/SourceConvert.java create mode 100644 test/org/redkale/test/source/JsonRecord.java diff --git a/src/org/redkale/source/DataJdbcSource.java b/src/org/redkale/source/DataJdbcSource.java index 6a6080294..72b43c84b 100644 --- a/src/org/redkale/source/DataJdbcSource.java +++ b/src/org/redkale/source/DataJdbcSource.java @@ -167,27 +167,35 @@ public class DataJdbcSource extends DataSqlSource { final PreparedStatement prestmt = info.autoGenerated ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql); for (final T value : values) { - int i = 0; if (info.autouuid) info.createPrimaryValue(value); - for (Attribute attr : attrs) { - Serializable val = attr.get(value); - if (val instanceof byte[]) { - Blob blob = conn.createBlob(); - blob.setBytes(1, (byte[]) val); - prestmt.setObject(++i, blob); - } else if (val instanceof AtomicInteger) { - prestmt.setObject(++i, ((AtomicInteger) val).get()); - } else if (val instanceof AtomicLong) { - prestmt.setObject(++i, ((AtomicLong) val).get()); - } else { - prestmt.setObject(++i, val); - } - } + batchStatementParameters(conn, prestmt, info, attrs, value); prestmt.addBatch(); } return prestmt; } + protected int batchStatementParameters(Connection conn, PreparedStatement prestmt, EntityInfo info, Attribute[] attrs, T value) throws SQLException { + int i = 0; + for (Attribute attr : attrs) { + Serializable val = attr.get(value); + if (val instanceof byte[]) { + Blob blob = conn.createBlob(); + blob.setBytes(1, (byte[]) val); + prestmt.setObject(++i, blob); + } else if (val instanceof AtomicInteger) { + prestmt.setObject(++i, ((AtomicInteger) val).get()); + } else if (val instanceof AtomicLong) { + prestmt.setObject(++i, ((AtomicLong) val).get()); + } else if (val != null && !(val instanceof Number) && !(val instanceof CharSequence) && !(value instanceof java.util.Date) + && !val.getClass().getName().startsWith("java.sql.") && !val.getClass().getName().startsWith("java.time.")) { + prestmt.setObject(++i, info.jsonConvert.convertTo(attr.genericType(), val)); + } else { + prestmt.setObject(++i, val); + } + } + return i; + } + @Override protected CompletableFuture deleteDB(EntityInfo info, Flipper flipper, String sql) { Connection conn = null; @@ -224,21 +232,7 @@ public class DataJdbcSource extends DataSqlSource { char[] sqlchars = debugfinest ? updateSQL.toCharArray() : null; final Attribute primary = info.getPrimary(); for (final T value : values) { - int k = 0; - for (Attribute attr : attrs) { - Serializable val = attr.get(value); - if (val instanceof byte[]) { - Blob blob = conn.createBlob(); - blob.setBytes(1, (byte[]) val); - prestmt.setObject(++k, blob); - } else if (val instanceof AtomicInteger) { - prestmt.setObject(++k, ((AtomicInteger) val).get()); - } else if (val instanceof AtomicLong) { - prestmt.setObject(++k, ((AtomicLong) val).get()); - } else { - prestmt.setObject(++k, val); - } - } + int k = batchStatementParameters(conn, prestmt, info, attrs, value); prestmt.setObject(++k, primary.get(value)); prestmt.addBatch();//------------------------------------------------------------ if (debugfinest) { //打印调试信息 @@ -434,6 +428,9 @@ public class DataJdbcSource extends DataSqlSource { if (blob != null) val = blob.getBytes(1, (int) blob.length()); } else { val = (Serializable) set.getObject(1); + if (val != null && !CharSequence.class.isAssignableFrom(attr.type()) && (val instanceof CharSequence)) { + val = info.jsonConvert.convertFrom(attr.genericType(), val.toString()); + } } } set.close(); diff --git a/src/org/redkale/source/DataSources.java b/src/org/redkale/source/DataSources.java index 8b15065a4..201c55d9d 100644 --- a/src/org/redkale/source/DataSources.java +++ b/src/org/redkale/source/DataSources.java @@ -56,11 +56,11 @@ public final class DataSources { private DataSources() { } - public static DataSource createDataSource2(final String unitName, Properties prop) throws IOException { + public static DataSource createDataSource(final String unitName, Properties prop) throws IOException { return new DataJdbcSource(unitName, null, prop, prop); } - public static DataSource createDataSource2(final String unitName, Properties readprop, Properties writeprop) throws IOException { + public static DataSource createDataSource(final String unitName, Properties readprop, Properties writeprop) throws IOException { return new DataJdbcSource(unitName, null, readprop, writeprop); } diff --git a/src/org/redkale/source/EntityInfo.java b/src/org/redkale/source/EntityInfo.java index dae98593e..c7111539d 100644 --- a/src/org/redkale/source/EntityInfo.java +++ b/src/org/redkale/source/EntityInfo.java @@ -14,6 +14,7 @@ import java.util.concurrent.atomic.*; import java.util.function.*; import java.util.logging.*; import javax.persistence.*; +import org.redkale.convert.json.*; import org.redkale.util.*; /** @@ -28,6 +29,8 @@ import org.redkale.util.*; @SuppressWarnings("unchecked") public final class EntityInfo { + private static final JsonConvert DEFAULT_JSON_CONVERT = JsonFactory.create().skipAllIgnore(true).getConvert(); + //全局静态资源 private static final ConcurrentHashMap entityInfos = new ConcurrentHashMap<>(); @@ -40,6 +43,9 @@ public final class EntityInfo { //类对应的数据表名, 如果是VirtualEntity 类, 则该字段为null final String table; + //JsonConvert + final JsonConvert jsonConvert; + //Entity构建器 private final Creator creator; @@ -330,6 +336,25 @@ public final class EntityInfo { } } while ((cltmp = cltmp.getSuperclass()) != Object.class); if (idAttr0 == null) throw new RuntimeException(type.getName() + " have no primary column by @javax.persistence.Id"); + cltmp = type; + JsonConvert convert = DEFAULT_JSON_CONVERT; + do { + for (Method method : cltmp.getDeclaredMethods()) { + if (method.getAnnotation(SourceConvert.class) == null) continue; + if (!Modifier.isStatic(method.getModifiers())) throw new RuntimeException("@SourceConvert method(" + method + ") must be static"); + if (method.getReturnType() != JsonConvert.class) throw new RuntimeException("@SourceConvert method(" + method + ") must be return JsonConvert.class"); + if (method.getParameterCount() > 0) throw new RuntimeException("@SourceConvert method(" + method + ") must be 0 parameter"); + try { + method.setAccessible(true); + convert = (JsonConvert) method.invoke(null); + } catch (Exception e) { + throw new RuntimeException(method + " invoke error", e); + } + if (convert != null) break; + } + } while ((cltmp = cltmp.getSuperclass()) != Object.class); + this.jsonConvert = convert == null ? DEFAULT_JSON_CONVERT : convert; + this.primary = idAttr0; this.aliasmap = aliasmap0; this.attributes = attributeMap.values().toArray(new Attribute[attributeMap.size()]); @@ -929,6 +954,9 @@ public final class EntityInfo { if (value == null) return null; if (value instanceof CharSequence) { return new StringBuilder().append('\'').append(value.toString().replace("'", "\\'")).append('\'').toString(); + } else if (!(value instanceof Number) && !(value instanceof java.util.Date) + && !value.getClass().getName().startsWith("java.sql.") && !value.getClass().getName().startsWith("java.time.")) { + return new StringBuilder().append('\'').append(jsonConvert.convertTo(value).replace("'", "\\'")).append('\'').toString(); } return String.valueOf(value); } @@ -1026,6 +1054,8 @@ public final class EntityInfo { } else { o = new AtomicLong(); } + } else if (o != null && !t.isAssignableFrom(o.getClass()) && o instanceof CharSequence) { + o = ((CharSequence) o).length() == 0 ? null : jsonConvert.convertFrom(attr.genericType(), o.toString()); } } return o; diff --git a/src/org/redkale/source/SourceConvert.java b/src/org/redkale/source/SourceConvert.java new file mode 100644 index 000000000..3c7a4b7ab --- /dev/null +++ b/src/org/redkale/source/SourceConvert.java @@ -0,0 +1,28 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.source; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 用于定制Source操作JSON字段的转换策略。
+ * 只能依附在Entity类的静态无参数方法上, 且返回值必须是JsonConvert。
+ * 注意: 如果一个类有两个静态方法标记为@SourceConvert, 框架只会识别第一个。 + * + *

+ * 详情见: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +public @interface SourceConvert { + +} diff --git a/test/org/redkale/test/source/JsonRecord.java b/test/org/redkale/test/source/JsonRecord.java new file mode 100644 index 000000000..9db9341b2 --- /dev/null +++ b/test/org/redkale/test/source/JsonRecord.java @@ -0,0 +1,122 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.test.source; + +import java.io.Serializable; +import java.util.*; +import javax.persistence.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.source.*; + +/** + * + * @author zhangjx + */ +//@Cacheable +public class JsonRecord { + + @SourceConvert + private static JsonConvert createConvert() { + return JsonConvert.root(); + } + + @Id + @Column(comment = "主键ID;") + private long recordid; + + @Column(comment = ";") + private String recordname = ""; + + @Column(comment = ";") + private Map rmap; + + @Column(comment = ";") + private List rlist; + + @Column(comment = ";") + private Set rset; + + public static JsonRecord create() { + JsonRecord record = new JsonRecord(); + record.setRecordid(System.currentTimeMillis()); + record.setRecordname("my name"); + Map map = new HashMap<>(); + map.put("str111", 10000); + map.put("str222", 20000); + record.setRmap(map); + List list = new ArrayList<>(); + list.add("item11"); + list.add("item22"); + list.add("item11"); + record.setRlist(list); + Set set = new HashSet<>(); + set.add("r1"); + set.add("r2"); + record.setRset(set); + return record; + } + + public static void main(String[] args) throws Throwable { + Properties properties = new Properties(); + properties.put("javax.persistence.jdbc.url", "jdbc:mysql://localhost:3306/center?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true"); + properties.put("javax.persistence.jdbc.user", "root"); + properties.put("javax.persistence.jdbc.password", ""); + DataSource source = DataSources.createDataSource("", properties); + JsonRecord record = JsonRecord.create(); + source.insert(record); + source.updateColumn(JsonRecord.class, record.getRecordid(), ColumnValue.mov("recordname", "my name 2")); + record.getRmap().put("haha", 2222); + source.updateColumn(JsonRecord.class, record.getRecordid(), ColumnValue.mov("rmap", (Serializable) (Object) record.getRmap())); + System.out.println(source.find(JsonRecord.class, record.getRecordid())); + System.out.println(source.findColumn(JsonRecord.class, "rmap", record.getRecordid())); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public long getRecordid() { + return recordid; + } + + public void setRecordid(long recordid) { + this.recordid = recordid; + } + + public String getRecordname() { + return recordname; + } + + public void setRecordname(String recordname) { + this.recordname = recordname; + } + + public Map getRmap() { + return rmap; + } + + public void setRmap(Map rmap) { + this.rmap = rmap; + } + + public List getRlist() { + return rlist; + } + + public void setRlist(List rlist) { + this.rlist = rlist; + } + + public Set getRset() { + return rset; + } + + public void setRset(Set rset) { + this.rset = rset; + } + +} diff --git a/test/org/redkale/test/util/UntilTestMain.java b/test/org/redkale/test/util/UntilTestMain.java index 67c78cbe5..98ed7c8d8 100644 --- a/test/org/redkale/test/util/UntilTestMain.java +++ b/test/org/redkale/test/util/UntilTestMain.java @@ -99,5 +99,6 @@ public class UntilTestMain { e = System.nanoTime() - s; System.out.println("动态Attribute耗时: " + e); System.out.println(); + System.out.println("TestBean.map: " + Attribute.create(TestBean.class.getDeclaredField("map")).genericType()); } }