DataSource增加部分JSON功能
This commit is contained in:
@@ -167,27 +167,35 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
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<T, Serializable> 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 <T> int batchStatementParameters(Connection conn, PreparedStatement prestmt, EntityInfo<T> info, Attribute<T, Serializable>[] attrs, T value) throws SQLException {
|
||||
int i = 0;
|
||||
for (Attribute<T, Serializable> 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 <T> CompletableFuture<Integer> deleteDB(EntityInfo<T> info, Flipper flipper, String sql) {
|
||||
Connection conn = null;
|
||||
@@ -224,21 +232,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
||||
char[] sqlchars = debugfinest ? updateSQL.toCharArray() : null;
|
||||
final Attribute<T, Serializable> primary = info.getPrimary();
|
||||
for (final T value : values) {
|
||||
int k = 0;
|
||||
for (Attribute<T, Serializable> 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<Connection> {
|
||||
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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<T> {
|
||||
|
||||
private static final JsonConvert DEFAULT_JSON_CONVERT = JsonFactory.create().skipAllIgnore(true).getConvert();
|
||||
|
||||
//全局静态资源
|
||||
private static final ConcurrentHashMap<Class, EntityInfo> entityInfos = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -40,6 +43,9 @@ public final class EntityInfo<T> {
|
||||
//类对应的数据表名, 如果是VirtualEntity 类, 则该字段为null
|
||||
final String table;
|
||||
|
||||
//JsonConvert
|
||||
final JsonConvert jsonConvert;
|
||||
|
||||
//Entity构建器
|
||||
private final Creator<T> creator;
|
||||
|
||||
@@ -330,6 +336,25 @@ public final class EntityInfo<T> {
|
||||
}
|
||||
} 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<T> {
|
||||
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<T> {
|
||||
} 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;
|
||||
|
||||
28
src/org/redkale/source/SourceConvert.java
Normal file
28
src/org/redkale/source/SourceConvert.java
Normal file
@@ -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字段的转换策略。 <br>
|
||||
* 只能依附在Entity类的静态无参数方法上, 且返回值必须是JsonConvert。 <br>
|
||||
* 注意: 如果一个类有两个静态方法标记为@SourceConvert, 框架只会识别第一个。
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({METHOD})
|
||||
@Retention(RUNTIME)
|
||||
public @interface SourceConvert {
|
||||
|
||||
}
|
||||
122
test/org/redkale/test/source/JsonRecord.java
Normal file
122
test/org/redkale/test/source/JsonRecord.java
Normal file
@@ -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<String, Integer> rmap;
|
||||
|
||||
@Column(comment = ";")
|
||||
private List<String> rlist;
|
||||
|
||||
@Column(comment = ";")
|
||||
private Set<String> rset;
|
||||
|
||||
public static JsonRecord create() {
|
||||
JsonRecord record = new JsonRecord();
|
||||
record.setRecordid(System.currentTimeMillis());
|
||||
record.setRecordname("my name");
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
map.put("str111", 10000);
|
||||
map.put("str222", 20000);
|
||||
record.setRmap(map);
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add("item11");
|
||||
list.add("item22");
|
||||
list.add("item11");
|
||||
record.setRlist(list);
|
||||
Set<String> 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<String, Integer> getRmap() {
|
||||
return rmap;
|
||||
}
|
||||
|
||||
public void setRmap(Map<String, Integer> rmap) {
|
||||
this.rmap = rmap;
|
||||
}
|
||||
|
||||
public List<String> getRlist() {
|
||||
return rlist;
|
||||
}
|
||||
|
||||
public void setRlist(List<String> rlist) {
|
||||
this.rlist = rlist;
|
||||
}
|
||||
|
||||
public Set<String> getRset() {
|
||||
return rset;
|
||||
}
|
||||
|
||||
public void setRset(Set<String> rset) {
|
||||
this.rset = rset;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user