ConvertFactory增加nullable配置

This commit is contained in:
redkale
2023-07-29 09:20:13 +08:00
parent e20d398a73
commit b84006d8db
24 changed files with 436 additions and 130 deletions

View File

@@ -60,7 +60,9 @@ public final class ApiDocCommand {
if (params != null && params.length > 0) { if (params != null && params.length > 0) {
for (String param : params) { for (String param : params) {
if (param == null) continue; if (param == null) {
continue;
}
param = param.toLowerCase(); param = param.toLowerCase();
if (param.startsWith("--api-skiprpc=")) { if (param.startsWith("--api-skiprpc=")) {
skipRPC = "true".equalsIgnoreCase(param.substring("--api-skiprpc=".length())); skipRPC = "true".equalsIgnoreCase(param.substring("--api-skiprpc=".length()));
@@ -80,7 +82,9 @@ public final class ApiDocCommand {
List<Map> swaggerTags = new ArrayList<>(); List<Map> swaggerTags = new ArrayList<>();
Map<String, Map<String, Object>> swaggerComponentsMap = new LinkedHashMap<>(); Map<String, Map<String, Object>> swaggerComponentsMap = new LinkedHashMap<>();
for (NodeServer node : app.servers) { for (NodeServer node : app.servers) {
if (!(node instanceof NodeHttpServer)) continue; if (!(node instanceof NodeHttpServer)) {
continue;
}
final Map<String, Object> map = new LinkedHashMap<>(); final Map<String, Object> map = new LinkedHashMap<>();
serverList.add(map); serverList.add(map);
HttpServer server = node.getServer(); HttpServer server = node.getServer();
@@ -89,12 +93,20 @@ public final class ApiDocCommand {
List<Map<String, Object>> servletsList = new ArrayList<>(); List<Map<String, Object>> servletsList = new ArrayList<>();
map.put("servlets", servletsList); map.put("servlets", servletsList);
String plainContentType = server.getResponseConfig() == null ? "application/json" : server.getResponseConfig().plainContentType; String plainContentType = server.getResponseConfig() == null ? "application/json" : server.getResponseConfig().plainContentType;
if (plainContentType == null || plainContentType.isEmpty()) plainContentType = "application/json"; if (plainContentType == null || plainContentType.isEmpty()) {
if (plainContentType.indexOf(';') > 0) plainContentType = plainContentType.substring(0, plainContentType.indexOf(';')); plainContentType = "application/json";
}
if (plainContentType.indexOf(';') > 0) {
plainContentType = plainContentType.substring(0, plainContentType.indexOf(';'));
}
for (HttpServlet servlet : server.getDispatcherServlet().getServlets()) { for (HttpServlet servlet : server.getDispatcherServlet().getServlets()) {
if (!(servlet instanceof HttpServlet)) continue; if (!(servlet instanceof HttpServlet)) {
if (servlet instanceof WebSocketServlet) continue; continue;
}
if (servlet instanceof WebSocketServlet) {
continue;
}
if (servlet.getClass().getAnnotation(MessageMultiConsumer.class) != null) { if (servlet.getClass().getAnnotation(MessageMultiConsumer.class) != null) {
node.logger.log(Level.INFO, servlet + " be skipped because has @MessageMultiConsumer"); node.logger.log(Level.INFO, servlet + " be skipped because has @MessageMultiConsumer");
continue; continue;
@@ -128,16 +140,29 @@ public final class ApiDocCommand {
Class clz = servlet.getClass(); Class clz = servlet.getClass();
HashSet<String> actionUrls = new HashSet<>(); HashSet<String> actionUrls = new HashSet<>();
do { do {
if (Modifier.isAbstract(clz.getModifiers())) break; if (Modifier.isAbstract(clz.getModifiers())) {
break;
}
for (Method method : clz.getMethods()) { for (Method method : clz.getMethods()) {
if (method.getParameterCount() != 2) continue; if (method.getParameterCount() != 2) {
continue;
}
HttpMapping action = method.getAnnotation(HttpMapping.class); HttpMapping action = method.getAnnotation(HttpMapping.class);
if (action == null) continue; if (action == null) {
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法 continue;
if (actionUrls.contains(action.url())) continue; }
if (HttpScope.class.isAssignableFrom(action.result())) continue; //忽略模板引擎的方法 if (!action.inherited() && selfClz != clz) {
if (action.rpconly() && skipRPC) continue; //不生成RPC接口 continue; //忽略不被继承的方法
}
if (actionUrls.contains(action.url())) {
continue;
}
if (HttpScope.class.isAssignableFrom(action.result())) {
continue; //忽略模板引擎的方法
}
if (action.rpconly() && skipRPC) {
continue; //不生成RPC接口
}
final List<Map<String, Object>> swaggerParamsList = new ArrayList<>(); final List<Map<String, Object>> swaggerParamsList = new ArrayList<>();
final Map<String, Object> mappingMap = new LinkedHashMap<>(); final Map<String, Object> mappingMap = new LinkedHashMap<>();
@@ -241,20 +266,36 @@ public final class ApiDocCommand {
swaggerParamsList.add(swaggerParamMap); swaggerParamsList.add(swaggerParamMap);
} }
} }
if (param.style() == HttpParam.HttpParameterStyle.BODY) hasbodyparam = true; if (param.style() == HttpParam.HttpParameterStyle.BODY) {
if (ptype.isPrimitive() || ptype == String.class) continue; hasbodyparam = true;
if (typesMap.containsKey(ptype.getName())) continue; }
if (ptype.getName().startsWith("java.")) continue; if (ptype.isPrimitive() || ptype == String.class) {
if (ptype.getName().startsWith("javax.")) continue; continue;
}
if (typesMap.containsKey(ptype.getName())) {
continue;
}
if (ptype.getName().startsWith("java.")) {
continue;
}
if (ptype.getName().startsWith("javax.")) {
continue;
}
final Map<String, Map<String, Object>> typeMap = new LinkedHashMap<>(); final Map<String, Map<String, Object>> typeMap = new LinkedHashMap<>();
Class loop = ptype; Class loop = ptype;
final boolean filter = FilterBean.class.isAssignableFrom(loop); final boolean filter = FilterBean.class.isAssignableFrom(loop);
do { do {
if (loop == null || loop.isInterface()) break; if (loop == null || loop.isInterface()) {
break;
}
for (Field field : loop.getDeclaredFields()) { for (Field field : loop.getDeclaredFields()) {
if (Modifier.isFinal(field.getModifiers())) continue; if (Modifier.isFinal(field.getModifiers())) {
if (Modifier.isStatic(field.getModifiers())) continue; continue;
}
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
Map<String, Object> fieldmap = new LinkedHashMap<>(); Map<String, Object> fieldmap = new LinkedHashMap<>();
fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName()); fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
@@ -276,7 +317,9 @@ public final class ApiDocCommand {
fieldmap.put("updatable", (filter || col == null || col.updatable())); fieldmap.put("updatable", (filter || col == null || col.updatable()));
if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) { if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) {
if (field.getAnnotation(RestAddress.class) != null) continue; if (field.getAnnotation(RestAddress.class) != null) {
continue;
}
} }
typeMap.put(field.getName(), fieldmap); typeMap.put(field.getName(), fieldmap);
@@ -301,11 +344,17 @@ public final class ApiDocCommand {
Map<String, Object> respMap = new LinkedHashMap<>(); Map<String, Object> respMap = new LinkedHashMap<>();
respMap.put("schema", respSchemaMap); respMap.put("schema", respSchemaMap);
Object example = formatExample(returnFactory, action.example(), action.result(), resultType); Object example = formatExample(returnFactory, action.example(), action.result(), resultType);
if (example != null) respSchemaMap.put("example", example); if (example != null) {
if (!swaggerRequestBody.isEmpty()) swaggerOperatMap.put("requestBody", swaggerRequestBody); respSchemaMap.put("example", example);
}
if (!swaggerRequestBody.isEmpty()) {
swaggerOperatMap.put("requestBody", swaggerRequestBody);
}
swaggerOperatMap.put("parameters", swaggerParamsList); swaggerOperatMap.put("parameters", swaggerParamsList);
String actiondesc = action.comment(); String actiondesc = action.comment();
if (action.rpconly()) actiondesc = "[Only for RPC API] " + actiondesc; if (action.rpconly()) {
actiondesc = "[Only for RPC API] " + actiondesc;
}
swaggerOperatMap.put("responses", Utility.ofMap("200", Utility.ofMap("description", actiondesc, "content", Utility.ofMap("application/json", respMap)))); swaggerOperatMap.put("responses", Utility.ofMap("200", Utility.ofMap("description", actiondesc, "content", Utility.ofMap("application/json", respMap))));
String m = action.methods() == null || action.methods().length == 0 ? null : action.methods()[0].toLowerCase(); String m = action.methods() == null || action.methods().length == 0 ? null : action.methods()[0].toLowerCase();
@@ -319,7 +368,9 @@ public final class ApiDocCommand {
} while ((clz = clz.getSuperclass()) != HttpServlet.class); } while ((clz = clz.getSuperclass()) != HttpServlet.class);
mappingsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url"))); mappingsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
servletsList.add(servletMap); servletsList.add(servletMap);
if (!actionUrls.isEmpty()) swaggerTags.add(Utility.ofMap("name", tag, "description", ws.comment())); if (!actionUrls.isEmpty()) {
swaggerTags.add(Utility.ofMap("name", tag, "description", ws.comment()));
}
} }
servletsList.sort((o1, o2) -> { servletsList.sort((o1, o2) -> {
String[] urlregs1 = (String[]) o1.get("urlregs"); String[] urlregs1 = (String[]) o1.get("urlregs");
@@ -337,7 +388,9 @@ public final class ApiDocCommand {
swaggerResultMap.put("servers", swaggerServers); swaggerResultMap.put("servers", swaggerServers);
swaggerResultMap.put("paths", swaggerPathsMap); swaggerResultMap.put("paths", swaggerPathsMap);
swaggerResultMap.put("tags", swaggerTags); swaggerResultMap.put("tags", swaggerTags);
if (!swaggerComponentsMap.isEmpty()) swaggerResultMap.put("components", Utility.ofMap("schemas", swaggerComponentsMap)); if (!swaggerComponentsMap.isEmpty()) {
swaggerResultMap.put("components", Utility.ofMap("schemas", swaggerComponentsMap));
}
final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "openapi-doc.json")); final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "openapi-doc.json"));
out.write(JsonConvert.root().convertTo(swaggerResultMap).getBytes(StandardCharsets.UTF_8)); out.write(JsonConvert.root().convertTo(swaggerResultMap).getBytes(StandardCharsets.UTF_8));
out.close(); out.close();
@@ -421,8 +474,12 @@ public final class ApiDocCommand {
Set<Type> types = new HashSet<>(); Set<Type> types = new HashSet<>();
Encodeable encodeable = JsonFactory.root().loadEncoder(genericType); Encodeable encodeable = JsonFactory.root().loadEncoder(genericType);
String ct = componentKey(factory, logger, types, componentsMap, null, encodeable, true); String ct = componentKey(factory, logger, types, componentsMap, null, encodeable, true);
if (ct == null || ct.length() == 0) return null; if (ct == null || ct.length() == 0) {
if (componentsMap.containsKey(ct)) return ct; return null;
}
if (componentsMap.containsKey(ct)) {
return ct;
}
Map<String, Object> cmap = new LinkedHashMap<>(); Map<String, Object> cmap = new LinkedHashMap<>();
componentsMap.put(ct, cmap); //必须在调用simpleSchemaType之前put不然嵌套情况下死循环 componentsMap.put(ct, cmap); //必须在调用simpleSchemaType之前put不然嵌套情况下死循环
@@ -440,11 +497,15 @@ public final class ApiDocCommand {
FilterColumn fcol = member.getField().getAnnotation(FilterColumn.class); FilterColumn fcol = member.getField().getAnnotation(FilterColumn.class);
if (fcol != null) { if (fcol != null) {
desc = fcol.comment(); desc = fcol.comment();
if (fcol.required()) requireds.add(member.getAttribute().field()); if (fcol.required()) {
requireds.add(member.getAttribute().field());
}
} }
} else { } else {
desc = col.comment(); desc = col.comment();
if (!col.nullable()) requireds.add(member.getAttribute().field()); if (!col.nullable()) {
requireds.add(member.getAttribute().field());
}
} }
if (desc.isEmpty() && member.getField().getAnnotation(Comment.class) != null) { if (desc.isEmpty() && member.getField().getAnnotation(Comment.class) != null) {
desc = member.getField().getAnnotation(Comment.class).value(); desc = member.getField().getAnnotation(Comment.class).value();
@@ -457,11 +518,15 @@ public final class ApiDocCommand {
FilterColumn fcol = member.getMethod().getAnnotation(FilterColumn.class); FilterColumn fcol = member.getMethod().getAnnotation(FilterColumn.class);
if (fcol != null) { if (fcol != null) {
desc = fcol.comment(); desc = fcol.comment();
if (fcol.required()) requireds.add(member.getAttribute().field()); if (fcol.required()) {
requireds.add(member.getAttribute().field());
}
} }
} else { } else {
desc = col.comment(); desc = col.comment();
if (!col.nullable()) requireds.add(member.getAttribute().field()); if (!col.nullable()) {
requireds.add(member.getAttribute().field());
}
} }
if (desc.isEmpty() && member.getMethod().getAnnotation(Comment.class) != null) { if (desc.isEmpty() && member.getMethod().getAnnotation(Comment.class) != null) {
desc = member.getMethod().getAnnotation(Comment.class).value(); desc = member.getMethod().getAnnotation(Comment.class).value();
@@ -469,11 +534,15 @@ public final class ApiDocCommand {
desc = member.getMethod().getAnnotation(org.redkale.util.Comment.class).value(); desc = member.getMethod().getAnnotation(org.redkale.util.Comment.class).value();
} }
} }
if (!desc.isEmpty()) schemaMap.put("description", desc); if (!desc.isEmpty()) {
schemaMap.put("description", desc);
}
properties.put(member.getAttribute().field(), schemaMap); properties.put(member.getAttribute().field(), schemaMap);
} }
} }
if (!requireds.isEmpty()) cmap.put("required", requireds); if (!requireds.isEmpty()) {
cmap.put("required", requireds);
}
cmap.put("properties", properties); cmap.put("properties", properties);
return ct; return ct;
} catch (Exception e) { } catch (Exception e) {
@@ -484,7 +553,9 @@ public final class ApiDocCommand {
private static String componentKey(JsonFactory factory, Logger logger, Set<Type> types, Map<String, Map<String, Object>> componentsMap, EnMember field, Encodeable encodeable, boolean first) { private static String componentKey(JsonFactory factory, Logger logger, Set<Type> types, Map<String, Map<String, Object>> componentsMap, EnMember field, Encodeable encodeable, boolean first) {
if (encodeable instanceof ObjectEncoder) { if (encodeable instanceof ObjectEncoder) {
if (types.contains(encodeable.getType())) return ""; if (types.contains(encodeable.getType())) {
return "";
}
types.add(encodeable.getType()); types.add(encodeable.getType());
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(((ObjectEncoder) encodeable).getTypeClass().getSimpleName()); sb.append(((ObjectEncoder) encodeable).getTypeClass().getSimpleName());
@@ -492,19 +563,33 @@ public final class ApiDocCommand {
if (member.getEncoder() instanceof ArrayEncoder if (member.getEncoder() instanceof ArrayEncoder
|| member.getEncoder() instanceof CollectionEncoder) { || member.getEncoder() instanceof CollectionEncoder) {
String subsb = componentKey(factory, logger, types, componentsMap, member, member.getEncoder(), false); String subsb = componentKey(factory, logger, types, componentsMap, member, member.getEncoder(), false);
if (subsb == null) return null; if (subsb == null) {
return null;
}
AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField(); AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField();
if (real == null) continue; if (real == null) {
continue;
}
Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType(); Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType();
Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType(); Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType();
if (cz == ct) continue; if (cz == ct) {
if (field == null && encodeable.getType() instanceof Class) continue; continue;
if (sb.length() > 0 && subsb.length() > 0) sb.append("_"); }
if (field == null && encodeable.getType() instanceof Class) {
continue;
}
if (sb.length() > 0 && subsb.length() > 0) {
sb.append("_");
}
sb.append(subsb); sb.append(subsb);
} else if (member.getEncoder() instanceof ObjectEncoder || member.getEncoder() instanceof SimpledCoder) { } else if (member.getEncoder() instanceof ObjectEncoder || member.getEncoder() instanceof SimpledCoder) {
AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField(); AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField();
if (real == null) continue; if (real == null) {
if (types.contains(member.getEncoder().getType())) continue; continue;
}
if (types.contains(member.getEncoder().getType())) {
continue;
}
types.add(member.getEncoder().getType()); types.add(member.getEncoder().getType());
if (member.getEncoder() instanceof SimpledCoder) { if (member.getEncoder() instanceof SimpledCoder) {
simpleSchemaType(factory, logger, componentsMap, ((SimpledCoder) member.getEncoder()).getType(), ((SimpledCoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true); simpleSchemaType(factory, logger, componentsMap, ((SimpledCoder) member.getEncoder()).getType(), ((SimpledCoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true);
@@ -513,11 +598,19 @@ public final class ApiDocCommand {
} }
Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType(); Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType();
Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType(); Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType();
if (cz == ct) continue; if (cz == ct) {
continue;
}
String subsb = componentKey(factory, logger, types, componentsMap, member, member.getEncoder(), false); String subsb = componentKey(factory, logger, types, componentsMap, member, member.getEncoder(), false);
if (subsb == null) return null; if (subsb == null) {
if (field == null && member.getEncoder().getType() instanceof Class) continue; return null;
if (sb.length() > 0 && subsb.length() > 0) sb.append("_"); }
if (field == null && member.getEncoder().getType() instanceof Class) {
continue;
}
if (sb.length() > 0 && subsb.length() > 0) {
sb.append("_");
}
sb.append(subsb); sb.append(subsb);
} else if (member.getEncoder() instanceof MapEncoder) { } else if (member.getEncoder() instanceof MapEncoder) {
continue; continue;
@@ -529,9 +622,13 @@ public final class ApiDocCommand {
} else if (encodeable instanceof ArrayEncoder || encodeable instanceof CollectionEncoder) { } else if (encodeable instanceof ArrayEncoder || encodeable instanceof CollectionEncoder) {
final boolean array = (encodeable instanceof ArrayEncoder); final boolean array = (encodeable instanceof ArrayEncoder);
Encodeable subEncodeable = array ? ((ArrayEncoder) encodeable).getComponentEncoder() : ((CollectionEncoder) encodeable).getComponentEncoder(); Encodeable subEncodeable = array ? ((ArrayEncoder) encodeable).getComponentEncoder() : ((CollectionEncoder) encodeable).getComponentEncoder();
if (subEncodeable instanceof SimpledCoder && field != null) return ""; if (subEncodeable instanceof SimpledCoder && field != null) {
return "";
}
final String sb = componentKey(factory, logger, types, componentsMap, null, subEncodeable, false); final String sb = componentKey(factory, logger, types, componentsMap, null, subEncodeable, false);
if (sb == null || sb.isEmpty()) return sb; if (sb == null || sb.isEmpty()) {
return sb;
}
if (field != null && field.getField() != null && field.getField().getDeclaringClass() == Sheet.class) { if (field != null && field.getField() != null && field.getField().getDeclaringClass() == Sheet.class) {
return sb; return sb;
} }
@@ -550,7 +647,9 @@ public final class ApiDocCommand {
} }
private static Object formatExample(JsonFactory factory, String example, Class type, Type genericType) { private static Object formatExample(JsonFactory factory, String example, Class type, Type genericType) {
if (example != null && !example.isEmpty()) return example; if (example != null && !example.isEmpty()) {
return example;
}
JsonFactory jsonFactory = factory == null || factory == JsonFactory.root() ? exampleFactory : factory; JsonFactory jsonFactory = factory == null || factory == JsonFactory.root() ? exampleFactory : factory;
if (type == Flipper.class) { if (type == Flipper.class) {
return new Flipper(); return new Flipper();
@@ -642,8 +741,12 @@ public final class ApiDocCommand {
json.append("{"); json.append("{");
int index = 0; int index = 0;
for (DeMember member : ((ObjectDecoder) decoder).getMembers()) { for (DeMember member : ((ObjectDecoder) decoder).getMembers()) {
if (!(member.getDecoder() instanceof ObjectDecoder)) continue; if (!(member.getDecoder() instanceof ObjectDecoder)) {
if (index > 0) json.append(","); continue;
}
if (index > 0) {
json.append(",");
}
json.append('"').append(member.getAttribute().field()).append("\":{}"); json.append('"').append(member.getAttribute().field()).append("\":{}");
index++; index++;
} }
@@ -659,6 +762,6 @@ public final class ApiDocCommand {
return example; return example;
} }
private static final JsonFactory exampleFactory = JsonFactory.create().tiny(false); private static final JsonFactory exampleFactory = JsonFactory.create().tiny(false).nullable(false);
} }

View File

@@ -24,21 +24,42 @@ import static java.lang.annotation.RetentionPolicy.*;
public @interface ConvertCoder { public @interface ConvertCoder {
/** /**
* 需要指定的字段类型,指定了coder字段值则可以不设置此字段 * 需要指定的字段类型,类型必须是原字段类型的子类。
* 例如: <br>
* <blockquote><pre>
* &#64;ConvertCoder(column = String.class)
* private CharSequence name;
* </pre></blockquote>
*
* 通常此字段值与encoder/decoder是二选一指定了coder字段值则可以不设置此字段。
* *
* @return 字段类名 * @return 字段类名
*/ */
Class column() default Object.class; Class column() default Object.class;
/** /**
* 序列化定制化的 Encodeable * 序列化定制化的 Encodeable, 构造函数的参数可以是:<br>
* 1、ConvertFactory
* 2、Type
* 3、Class
* 4、ConvertFactory和Type
* 5、ConvertFactory和Class
*
* 类如果存在instance单实例对象字段值则优先使用instance对象
* *
* @return Encodeable 类 * @return Encodeable 类
*/ */
Class<? extends Encodeable> encoder() default Encodeable.class; Class<? extends Encodeable> encoder() default Encodeable.class;
/** /**
* 反序列化定制化的 Decodeable * 反序列化定制化的 Decodeable, 构造函数的参数可以是:<br>
* 1、ConvertFactory
* 2、Type
* 3、Class
* 4、ConvertFactory和Type
* 5、ConvertFactory和Class
*
* 类如果存在instance单实例对象字段值则优先使用instance对象
* *
* @return Decodeable 类 * @return Decodeable 类
*/ */

View File

@@ -44,7 +44,9 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
protected Convert<R, W> convert; protected Convert<R, W> convert;
protected boolean tiny; //String类型值为""Boolean类型值为false时是否需要输出, 默认为false protected boolean tiny; //值为true时 String类型值为""Boolean类型值为false时不会输出默认为false
protected boolean nullable; ///值为true时 字段值为null时会输出默认为false
private final Encodeable<W, ?> anyEncoder = new AnyEncoder(this); private final Encodeable<W, ?> anyEncoder = new AnyEncoder(this);
@@ -72,8 +74,9 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
private boolean skipAllIgnore = false; private boolean skipAllIgnore = false;
protected ConvertFactory(ConvertFactory<R, W> parent, boolean tiny) { protected ConvertFactory(ConvertFactory<R, W> parent, boolean tiny, boolean nullable) {
this.tiny = tiny; this.tiny = tiny;
this.nullable = nullable;
this.parent = parent; this.parent = parent;
if (parent == null) { if (parent == null) {
//--------------------------------------------------------- //---------------------------------------------------------
@@ -251,7 +254,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
public abstract ConvertFactory createChild(); public abstract ConvertFactory createChild();
public abstract ConvertFactory createChild(boolean tiny); public abstract ConvertFactory createChild(boolean tiny, boolean nullable);
protected SimpledCoder createEnumSimpledCoder(Class enumClass) { protected SimpledCoder createEnumSimpledCoder(Class enumClass) {
return new EnumSimpledCoder(this, enumClass); return new EnumSimpledCoder(this, enumClass);
@@ -335,6 +338,11 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
return this; return this;
} }
public ConvertFactory nullable(boolean nullable) {
this.nullable = nullable;
return this;
}
public boolean isConvertDisabled(AccessibleObject element) { public boolean isConvertDisabled(AccessibleObject element) {
ConvertDisabled[] ccs = element.getAnnotationsByType(ConvertDisabled.class); ConvertDisabled[] ccs = element.getAnnotationsByType(ConvertDisabled.class);
if (ccs.length == 0 && element instanceof Method) { if (ccs.length == 0 && element instanceof Method) {
@@ -630,7 +638,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
} }
} }
ConvertFactory columnFactory(Class type, ConvertCoder[] coders, boolean encode) { ConvertFactory columnFactory(Type type, ConvertCoder[] coders, boolean encode) {
if (coders == null || coders.length < 1) { if (coders == null || coders.length < 1) {
return this; return this;
} }
@@ -642,7 +650,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
if (!ann.type().contains(ct)) { if (!ann.type().contains(ct)) {
continue; continue;
} }
Class colType = type; Type colType = type;
if (ann.column() != Object.class) { if (ann.column() != Object.class) {
colType = ann.column(); colType = ann.column();
} }
@@ -679,7 +687,9 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
if (paramTypes.length == 0) { if (paramTypes.length == 0) {
encoder = creator.create(); encoder = creator.create();
} else if (paramTypes.length == 1) { } else if (paramTypes.length == 1) {
if (Type.class.isAssignableFrom(paramTypes[0])) { if (Class.class.isAssignableFrom(paramTypes[0])) {
encoder = creator.create((Object) TypeToken.typeToClass(colType));
} else if (Type.class.isAssignableFrom(paramTypes[0])) {
encoder = creator.create((Object) colType); encoder = creator.create((Object) colType);
} else if (ConvertFactory.class.isAssignableFrom(paramTypes[0])) { } else if (ConvertFactory.class.isAssignableFrom(paramTypes[0])) {
encoder = creator.create(this); encoder = creator.create(this);
@@ -687,7 +697,11 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
throw new ConvertException(enClazz + " not found public empty-parameter Constructor"); throw new ConvertException(enClazz + " not found public empty-parameter Constructor");
} }
} else if (paramTypes.length == 2) { } else if (paramTypes.length == 2) {
if (ConvertFactory.class.isAssignableFrom(paramTypes[0]) && Type.class.isAssignableFrom(paramTypes[1])) { if (ConvertFactory.class.isAssignableFrom(paramTypes[0]) && Class.class.isAssignableFrom(paramTypes[1])) {
encoder = creator.create(this, TypeToken.typeToClass(colType));
} else if (Class.class.isAssignableFrom(paramTypes[0]) && ConvertFactory.class.isAssignableFrom(paramTypes[1])) {
encoder = creator.create(TypeToken.typeToClass(colType), this);
} else if (ConvertFactory.class.isAssignableFrom(paramTypes[0]) && Type.class.isAssignableFrom(paramTypes[1])) {
encoder = creator.create(this, colType); encoder = creator.create(this, colType);
} else if (Type.class.isAssignableFrom(paramTypes[0]) && ConvertFactory.class.isAssignableFrom(paramTypes[1])) { } else if (Type.class.isAssignableFrom(paramTypes[0]) && ConvertFactory.class.isAssignableFrom(paramTypes[1])) {
encoder = creator.create(colType, this); encoder = creator.create(colType, this);
@@ -740,7 +754,9 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
if (paramTypes.length == 0) { if (paramTypes.length == 0) {
decoder = creator.create(); decoder = creator.create();
} else if (paramTypes.length == 1) { } else if (paramTypes.length == 1) {
if (Type.class.isAssignableFrom(paramTypes[0])) { if (Class.class.isAssignableFrom(paramTypes[0])) {
decoder = creator.create((Object) TypeToken.typeToClass(colType));
} else if (Type.class.isAssignableFrom(paramTypes[0])) {
decoder = creator.create((Object) colType); decoder = creator.create((Object) colType);
} else if (ConvertFactory.class.isAssignableFrom(paramTypes[0])) { } else if (ConvertFactory.class.isAssignableFrom(paramTypes[0])) {
decoder = creator.create(this); decoder = creator.create(this);
@@ -748,7 +764,11 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
throw new ConvertException(deClazz + " not found public empty-parameter Constructor"); throw new ConvertException(deClazz + " not found public empty-parameter Constructor");
} }
} else if (paramTypes.length == 2) { } else if (paramTypes.length == 2) {
if (ConvertFactory.class.isAssignableFrom(paramTypes[0]) && Type.class.isAssignableFrom(paramTypes[1])) { if (ConvertFactory.class.isAssignableFrom(paramTypes[0]) && Class.class.isAssignableFrom(paramTypes[1])) {
decoder = creator.create(this, TypeToken.typeToClass(colType));
} else if (Class.class.isAssignableFrom(paramTypes[0]) && ConvertFactory.class.isAssignableFrom(paramTypes[1])) {
decoder = creator.create(TypeToken.typeToClass(colType), this);
} else if (ConvertFactory.class.isAssignableFrom(paramTypes[0]) && Type.class.isAssignableFrom(paramTypes[1])) {
decoder = creator.create(this, colType); decoder = creator.create(this, colType);
} else if (Type.class.isAssignableFrom(paramTypes[0]) && ConvertFactory.class.isAssignableFrom(paramTypes[1])) { } else if (Type.class.isAssignableFrom(paramTypes[0]) && ConvertFactory.class.isAssignableFrom(paramTypes[1])) {
decoder = creator.create(colType, this); decoder = creator.create(colType, this);

View File

@@ -6,7 +6,7 @@
package org.redkale.convert; package org.redkale.convert;
/** /**
* Convert的扩展实现类加载器 * Convert的扩展实现类加载器, 通过此类可以创建自定义的序列化格式例如protobuf、xmlbean
* *
* *
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -5,12 +5,12 @@
*/ */
package org.redkale.convert; package org.redkale.convert;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*; import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*; import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* 序列化时标记String字段的值是否为无转义字符且长度不超过255的字符串 * 序列化时标记String字段的值是否为无转义字符且长度不超过255的字符串,通常用于类名、字段名、枚举值字符串等
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org

View File

@@ -114,7 +114,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
continue; continue;
} }
ConvertSmallString small = field.getAnnotation(ConvertSmallString.class); ConvertSmallString small = field.getAnnotation(ConvertSmallString.class);
colFactory = factory.columnFactory(field.getType(), field.getAnnotationsByType(ConvertCoder.class), false); colFactory = factory.columnFactory(field.getGenericType(), field.getAnnotationsByType(ConvertCoder.class), false);
Decodeable<R, ?> fieldCoder; Decodeable<R, ?> fieldCoder;
if (small != null && field.getType() == String.class) { if (small != null && field.getType() == String.class) {
fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance;
@@ -197,9 +197,9 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
ConvertSmallString small = method.getAnnotation(ConvertSmallString.class); ConvertSmallString small = method.getAnnotation(ConvertSmallString.class);
Field maybeField = ConvertFactory.readGetSetField(method); Field maybeField = ConvertFactory.readGetSetField(method);
colFactory = factory.columnFactory(method.getParameterTypes()[0], method.getAnnotationsByType(ConvertCoder.class), false); colFactory = factory.columnFactory(method.getGenericParameterTypes()[0], method.getAnnotationsByType(ConvertCoder.class), false);
if (maybeField != null && colFactory == factory) { if (maybeField != null && colFactory == factory) {
colFactory = factory.columnFactory(maybeField.getType(), maybeField.getAnnotationsByType(ConvertCoder.class), false); colFactory = factory.columnFactory(maybeField.getGenericType(), maybeField.getAnnotationsByType(ConvertCoder.class), false);
} }
Decodeable<R, ?> fieldCoder; Decodeable<R, ?> fieldCoder;
if (small != null && method.getParameterTypes()[0] == String.class) { if (small != null && method.getParameterTypes()[0] == String.class) {

View File

@@ -95,7 +95,7 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
continue; continue;
} }
ConvertSmallString small = field.getAnnotation(ConvertSmallString.class); ConvertSmallString small = field.getAnnotation(ConvertSmallString.class);
colFactory = factory.columnFactory(field.getType(), field.getAnnotationsByType(ConvertCoder.class), true); colFactory = factory.columnFactory(field.getGenericType(), field.getAnnotationsByType(ConvertCoder.class), true);
Encodeable<W, ?> fieldCoder; Encodeable<W, ?> fieldCoder;
if (small != null && field.getType() == String.class) { if (small != null && field.getType() == String.class) {
fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance;
@@ -165,9 +165,9 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
} }
} }
Field maybeField = ConvertFactory.readGetSetField(method); Field maybeField = ConvertFactory.readGetSetField(method);
colFactory = factory.columnFactory(method.getReturnType(), method.getAnnotationsByType(ConvertCoder.class), true); colFactory = factory.columnFactory(method.getGenericReturnType(), method.getAnnotationsByType(ConvertCoder.class), true);
if (maybeField != null && colFactory == factory) { if (maybeField != null && colFactory == factory) {
colFactory = factory.columnFactory(maybeField.getType(), maybeField.getAnnotationsByType(ConvertCoder.class), true); colFactory = factory.columnFactory(maybeField.getGenericType(), maybeField.getAnnotationsByType(ConvertCoder.class), true);
} }
Encodeable<W, ?> fieldCoder; Encodeable<W, ?> fieldCoder;
if (small != null && method.getReturnType() == String.class) { if (small != null && method.getReturnType() == String.class) {

View File

@@ -74,6 +74,13 @@ public abstract class Writer {
*/ */
public abstract boolean tiny(); public abstract boolean tiny();
/**
* 当nullable=true时 字段值为null时会输出该字段
*
* @return 是否简化
*/
public abstract boolean nullable();
/** /**
* 输出null值 * 输出null值
*/ */
@@ -132,6 +139,12 @@ public abstract class Writer {
value = objFieldFunc.apply(member.attribute, obj); value = objFieldFunc.apply(member.attribute, obj);
} }
if (value == null) { if (value == null) {
if (nullable()) {
Attribute attr = member.getAttribute();
this.writeFieldName(member, attr.field(), attr.genericType(), member.getPosition());
writeNull();
this.comma = true;
}
return; return;
} }
if (tiny()) { if (tiny()) {
@@ -164,6 +177,11 @@ public abstract class Writer {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void writeObjectField(final String fieldName, Type fieldType, int fieldPos, Encodeable anyEncoder, Object value) { public void writeObjectField(final String fieldName, Type fieldType, int fieldPos, Encodeable anyEncoder, Object value) {
if (value == null) { if (value == null) {
if (nullable()) {
this.writeFieldName(null, fieldName, fieldType, fieldPos);
writeNull();
this.comma = true;
}
return; return;
} }
if (fieldType == null) { if (fieldType == null) {

View File

@@ -26,12 +26,13 @@ public class BsonByteBufferWriter extends BsonWriter {
private int index; private int index;
public BsonByteBufferWriter(Supplier<ByteBuffer> supplier) { public BsonByteBufferWriter(Supplier<ByteBuffer> supplier) {
this(false, supplier); this(false, false, supplier);
} }
protected BsonByteBufferWriter(boolean tiny, Supplier<ByteBuffer> supplier) { protected BsonByteBufferWriter(boolean tiny, boolean nullable, Supplier<ByteBuffer> supplier) {
super((byte[]) null); super((byte[]) null);
this.tiny = tiny; this.tiny = tiny;
this.nullable = nullable;
this.supplier = supplier; this.supplier = supplier;
} }
@@ -76,6 +77,12 @@ public class BsonByteBufferWriter extends BsonWriter {
return this; return this;
} }
@Override
public BsonByteBufferWriter nullable(boolean nullable) {
this.nullable = nullable;
return this;
}
@Override @Override
protected int expand(final int byteLength) { protected int expand(final int byteLength) {
if (this.buffers == null) { if (this.buffers == null) {

View File

@@ -48,9 +48,12 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
private final boolean tiny; private final boolean tiny;
protected BsonConvert(ConvertFactory<BsonReader, BsonWriter> factory, boolean tiny) { private final boolean nullable;
protected BsonConvert(ConvertFactory<BsonReader, BsonWriter> factory, boolean tiny, boolean nullable) {
super(factory); super(factory);
this.tiny = tiny; this.tiny = tiny;
this.nullable = nullable;
} }
@Override @Override
@@ -79,7 +82,7 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
@Override @Override
public BsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc, BiFunction<Object, Object, Object> mapFieldFunc, Function<Object, ConvertField[]> objExtFunc) { public BsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc, BiFunction<Object, Object, Object> mapFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
return new BsonConvert(getFactory(), tiny) { return new BsonConvert(getFactory(), tiny, nullable) {
@Override @Override
protected <S extends BsonWriter> S configWrite(S writer) { protected <S extends BsonWriter> S configWrite(S writer) {
return fieldFunc(writer, fieldFunc, mapFieldFunc, objExtFunc); return fieldFunc(writer, fieldFunc, mapFieldFunc, objExtFunc);
@@ -117,11 +120,11 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
//------------------------------ writer ----------------------------------------------------------- //------------------------------ writer -----------------------------------------------------------
public BsonByteBufferWriter pollWriter(final Supplier<ByteBuffer> supplier) { public BsonByteBufferWriter pollWriter(final Supplier<ByteBuffer> supplier) {
return configWrite(new BsonByteBufferWriter(tiny, supplier)); return configWrite(new BsonByteBufferWriter(tiny, nullable, supplier));
} }
protected BsonWriter pollWriter(final OutputStream out) { protected BsonWriter pollWriter(final OutputStream out) {
return configWrite(new BsonStreamWriter(tiny, out)); return configWrite(new BsonStreamWriter(tiny, nullable, out));
} }
@Override @Override
@@ -132,7 +135,7 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
} else { } else {
writerPool.set(null); writerPool.set(null);
} }
return configWrite(writer.tiny(tiny)); return configWrite(writer.tiny(tiny).nullable(nullable));
} }
@Override @Override
@@ -237,7 +240,7 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
@Override @Override
public void convertToBytes(final ByteArray array, final Type type, final Object value) { public void convertToBytes(final ByteArray array, final Type type, final Object value) {
Objects.requireNonNull(array); Objects.requireNonNull(array);
final BsonWriter writer = configWrite(new BsonWriter(array).tiny(tiny)); final BsonWriter writer = configWrite(new BsonWriter(array).tiny(tiny).nullable(nullable));
if (value == null) { if (value == null) {
writer.writeNull(); writer.writeNull();
} else { } else {
@@ -283,7 +286,7 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
if (value == null) { if (value == null) {
return null; return null;
} }
final BsonWriter writer = writerPool.get().tiny(tiny); final BsonWriter writer = writerPool.get().tiny(tiny).nullable(nullable);
factory.loadEncoder(type == null ? value.getClass() : type).convertTo(writer, value); factory.loadEncoder(type == null ? value.getClass() : type).convertTo(writer, value);
return writer; return writer;
} }

View File

@@ -24,7 +24,9 @@ import org.redkale.util.TypeToken;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> { public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
private static final BsonFactory instance = new BsonFactory(null, getSystemPropertyBoolean("redkale.convert.bson.tiny", "redkale.convert.tiny", false)); private static final BsonFactory instance = new BsonFactory(null,
getSystemPropertyBoolean("redkale.convert.bson.tiny", "redkale.convert.tiny", true),
getSystemPropertyBoolean("redkale.convert.bson.nullable", "redkale.convert.nullable", false));
static final Decodeable objectDecoder = instance.loadDecoder(Object.class); static final Decodeable objectDecoder = instance.loadDecoder(Object.class);
@@ -48,8 +50,8 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
//instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class)); //instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class));
} }
private BsonFactory(BsonFactory parent, boolean tiny) { private BsonFactory(BsonFactory parent, boolean tiny, boolean nullable) {
super(parent, tiny); super(parent, tiny, nullable);
} }
@Override @Override
@@ -62,6 +64,16 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
return this.tiny; return this.tiny;
} }
@Override
public BsonFactory nullable(boolean nullable) {
this.nullable = nullable;
return this;
}
protected boolean nullable() {
return this.nullable;
}
@Override @Override
public BsonFactory skipAllIgnore(final boolean skipIgnore) { public BsonFactory skipAllIgnore(final boolean skipIgnore) {
this.registerSkipAllIgnore(skipIgnore); this.registerSkipAllIgnore(skipIgnore);
@@ -73,25 +85,26 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
} }
public static BsonFactory create() { public static BsonFactory create() {
return new BsonFactory(null, getSystemPropertyBoolean("redkale.convert.bson.tiny", "redkale.convert.tiny", false)); return new BsonFactory(null, getSystemPropertyBoolean("redkale.convert.bson.tiny", "redkale.convert.tiny", true),
getSystemPropertyBoolean("redkale.convert.bson.nullable", "redkale.convert.nullable", false));
} }
@Override @Override
public final BsonConvert getConvert() { public final BsonConvert getConvert() {
if (convert == null) { if (convert == null) {
convert = new BsonConvert(this, tiny); convert = new BsonConvert(this, tiny, nullable);
} }
return (BsonConvert) convert; return (BsonConvert) convert;
} }
@Override @Override
public BsonFactory createChild() { public BsonFactory createChild() {
return new BsonFactory(this, this.tiny); return new BsonFactory(this, this.tiny, this.nullable);
} }
@Override @Override
public BsonFactory createChild(boolean tiny) { public BsonFactory createChild(boolean tiny, boolean nullable) {
return new BsonFactory(this, tiny); return new BsonFactory(this, tiny, nullable);
} }
@Override @Override

View File

@@ -18,8 +18,8 @@ class BsonStreamWriter extends BsonByteBufferWriter {
private OutputStream out; private OutputStream out;
protected BsonStreamWriter(boolean tiny, OutputStream out) { protected BsonStreamWriter(boolean tiny, boolean nullable, OutputStream out) {
super(tiny, null); super(tiny, nullable, null);
this.out = out; this.out = out;
} }

View File

@@ -29,6 +29,8 @@ public class BsonWriter extends Writer implements ByteTuple {
protected boolean tiny = BsonFactory.root().tiny(); protected boolean tiny = BsonFactory.root().tiny();
protected boolean nullable = BsonFactory.root().nullable();
public static ObjectPool<BsonWriter> createPool(int max) { public static ObjectPool<BsonWriter> createPool(int max) {
return ObjectPool.createSafePool(max, (Object... params) -> new BsonWriter(), null, (t) -> t.recycle()); return ObjectPool.createSafePool(max, (Object... params) -> new BsonWriter(), null, (t) -> t.recycle());
} }
@@ -105,6 +107,16 @@ public class BsonWriter extends Writer implements ByteTuple {
return this; return this;
} }
@Override
public final boolean nullable() {
return nullable;
}
public BsonWriter nullable(boolean nullable) {
this.nullable = nullable;
return this;
}
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
/** /**

View File

@@ -34,12 +34,13 @@ public class JsonByteBufferWriter extends JsonWriter {
private int index; private int index;
public JsonByteBufferWriter(boolean tiny, Supplier<ByteBuffer> supplier) { public JsonByteBufferWriter(boolean tiny, boolean nullable, Supplier<ByteBuffer> supplier) {
this(tiny, null, supplier); this(tiny, nullable, null, supplier);
} }
public JsonByteBufferWriter(boolean tiny, Charset charset, Supplier<ByteBuffer> supplier) { public JsonByteBufferWriter(boolean tiny, boolean nullable, Charset charset, Supplier<ByteBuffer> supplier) {
this.tiny = tiny; this.tiny = tiny;
this.nullable = nullable;
this.charset = charset; this.charset = charset;
this.supplier = supplier; this.supplier = supplier;
} }
@@ -311,6 +312,10 @@ public class JsonByteBufferWriter extends JsonWriter {
*/ */
@Override @Override
public void writeLatin1To(final boolean quote, final String value) { public void writeLatin1To(final boolean quote, final String value) {
if (value == null) {
writeNull();
return;
}
byte[] bs = Utility.latin1ByteArray(value); byte[] bs = Utility.latin1ByteArray(value);
int expandsize = expand(bs.length + (quote ? 2 : 0)); int expandsize = expand(bs.length + (quote ? 2 : 0));
if (expandsize == 0) {// 只需要一个buffer if (expandsize == 0) {// 只需要一个buffer
@@ -564,6 +569,12 @@ public class JsonByteBufferWriter extends JsonWriter {
@Override @Override
public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) { public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) {
if (value == null && nullable()) {
writeTo(fieldBytes);
writeNull();
writeTo('}');
return;
}
if (value == null || (tiny && value.isEmpty())) { if (value == null || (tiny && value.isEmpty())) {
expand(1); expand(1);
this.buffers[index].put((byte) '}'); this.buffers[index].put((byte) '}');
@@ -616,6 +627,13 @@ public class JsonByteBufferWriter extends JsonWriter {
@Override //firstFieldBytes 必须带{开头 @Override //firstFieldBytes 必须带{开头
public void writeObjectByOnlyOneLatin1FieldValue(final byte[] firstFieldBytes, final String value) { public void writeObjectByOnlyOneLatin1FieldValue(final byte[] firstFieldBytes, final String value) {
if (value == null && nullable()) {
writeTo('{');
writeTo(firstFieldBytes);
writeNull();
writeTo('}');
return;
}
if (value == null || (tiny && value.isEmpty())) { if (value == null || (tiny && value.isEmpty())) {
int expandsize = expand(2); int expandsize = expand(2);
if (expandsize == 0) { // 只需要一个buffer if (expandsize == 0) { // 只需要一个buffer

View File

@@ -5,9 +5,9 @@
*/ */
package org.redkale.convert.json; package org.redkale.convert.json;
import java.lang.reflect.*; import java.lang.reflect.Type;
import java.nio.charset.*; import java.nio.charset.StandardCharsets;
import java.util.function.*; import java.util.function.Consumer;
import org.redkale.convert.*; import org.redkale.convert.*;
import static org.redkale.convert.json.JsonWriter.*; import static org.redkale.convert.json.JsonWriter.*;
import org.redkale.util.*; import org.redkale.util.*;
@@ -55,8 +55,9 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
this.count = array.length(); this.count = array.length();
} }
public JsonBytesWriter(boolean tiny, ByteArray array) { public JsonBytesWriter(boolean tiny, boolean nullable, ByteArray array) {
this.tiny = tiny; this.tiny = tiny;
this.nullable = nullable;
this.content = array.content(); this.content = array.content();
this.count = array.length(); this.count = array.length();
} }
@@ -158,6 +159,10 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
*/ */
@Override @Override
public void writeLatin1To(final boolean quote, final String value) { public void writeLatin1To(final boolean quote, final String value) {
if (value == null) {
writeNull();
return;
}
byte[] bs = Utility.latin1ByteArray(value); byte[] bs = Utility.latin1ByteArray(value);
int len = bs.length; int len = bs.length;
if (quote) { if (quote) {
@@ -271,6 +276,12 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
@Override @Override
public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) { public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) {
if (value == null && nullable()) {
writeTo(fieldBytes);
writeNull();
writeTo('}');
return;
}
if (value == null || (tiny && value.isEmpty())) { if (value == null || (tiny && value.isEmpty())) {
expand(1); expand(1);
content[count++] = '}'; content[count++] = '}';
@@ -294,6 +305,13 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
@Override //firstFieldBytes 必须带{开头 @Override //firstFieldBytes 必须带{开头
public void writeObjectByOnlyOneLatin1FieldValue(final byte[] firstFieldBytes, final String value) { public void writeObjectByOnlyOneLatin1FieldValue(final byte[] firstFieldBytes, final String value) {
if (value == null && nullable()) {
writeTo('{');
writeTo(firstFieldBytes);
writeNull();
writeTo('}');
return;
}
if (value == null || (tiny && value.isEmpty())) { if (value == null || (tiny && value.isEmpty())) {
expand(2); expand(2);
content[count++] = '{'; content[count++] = '{';

View File

@@ -104,6 +104,10 @@ public class JsonCharsWriter extends JsonWriter {
*/ */
@Override @Override
public void writeLatin1To(final boolean quote, final String value) { public void writeLatin1To(final boolean quote, final String value) {
if (value == null) {
writeNull();
return;
}
int len = value.length(); int len = value.length();
expand(len + (quote ? 2 : 0)); expand(len + (quote ? 2 : 0));
if (quote) { if (quote) {
@@ -220,6 +224,12 @@ public class JsonCharsWriter extends JsonWriter {
@Override @Override
public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) { public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) {
if (value == null && nullable()) {
writeTo(fieldBytes);
writeNull();
writeTo('}');
return;
}
if (value == null || (tiny && value.isEmpty())) { if (value == null || (tiny && value.isEmpty())) {
expand(1); expand(1);
content[count++] = '}'; content[count++] = '}';
@@ -241,6 +251,13 @@ public class JsonCharsWriter extends JsonWriter {
@Override //firstFieldBytes 必须带{开头 @Override //firstFieldBytes 必须带{开头
public void writeObjectByOnlyOneLatin1FieldValue(final byte[] firstFieldBytes, final String value) { public void writeObjectByOnlyOneLatin1FieldValue(final byte[] firstFieldBytes, final String value) {
if (value == null && nullable()) {
writeTo('{');
writeTo(firstFieldBytes);
writeNull();
writeTo('}');
return;
}
if (value == null || (tiny && value.isEmpty())) { if (value == null || (tiny && value.isEmpty())) {
expand(2); expand(2);
content[count++] = '{'; content[count++] = '{';

View File

@@ -42,13 +42,16 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
private final boolean tiny; private final boolean tiny;
private final boolean nullable;
private Encodeable lastConvertEncodeable; private Encodeable lastConvertEncodeable;
private Decodeable lastConvertDecodeable; private Decodeable lastConvertDecodeable;
protected JsonConvert(JsonFactory factory, boolean tiny) { protected JsonConvert(JsonFactory factory, boolean tiny, boolean nullable) {
super(factory); super(factory);
this.tiny = tiny; this.tiny = tiny;
this.nullable = nullable;
} }
@Override @Override
@@ -77,7 +80,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
@Override @Override
public JsonConvert newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc, BiFunction<Object, Object, Object> mapFieldFunc, Function<Object, ConvertField[]> objExtFunc) { public JsonConvert newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc, BiFunction<Object, Object, Object> mapFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
return new JsonConvert(getFactory(), tiny) { return new JsonConvert(getFactory(), tiny, nullable) {
@Override @Override
protected <S extends JsonWriter> S configWrite(S writer) { protected <S extends JsonWriter> S configWrite(S writer) {
return fieldFunc(writer, objFieldFunc, mapFieldFunc, objExtFunc); return fieldFunc(writer, objFieldFunc, mapFieldFunc, objExtFunc);
@@ -112,7 +115,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
} else { } else {
bytesWriterPool.set(null); bytesWriterPool.set(null);
} }
return configWrite((JsonBytesWriter) writer.tiny(tiny)); return configWrite((JsonBytesWriter) writer.tiny(tiny).nullable(nullable));
} }
@Override @Override
@@ -132,7 +135,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
} else { } else {
bytesWriterPool.set(null); bytesWriterPool.set(null);
} }
return configWrite((JsonBytesWriter) writer.tiny(tiny)); return configWrite((JsonBytesWriter) writer.tiny(tiny).nullable(nullable));
} }
private void offerJsonBytesWriter(final JsonBytesWriter writer) { private void offerJsonBytesWriter(final JsonBytesWriter writer) {
@@ -392,7 +395,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
@Override @Override
public void convertToBytes(final ByteArray array, final Type type, final Object value) { public void convertToBytes(final ByteArray array, final Type type, final Object value) {
Objects.requireNonNull(array); Objects.requireNonNull(array);
JsonBytesWriter writer = configWrite(new JsonBytesWriter(tiny, array)); JsonBytesWriter writer = configWrite(new JsonBytesWriter(tiny, nullable, array));
if (value == null) { if (value == null) {
writer.writeNull(); writer.writeNull();
} else { } else {
@@ -412,10 +415,10 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
public void convertTo(final OutputStream out, final Type type, final Object value) { public void convertTo(final OutputStream out, final Type type, final Object value) {
if (value == null) { if (value == null) {
configWrite(new JsonStreamWriter(tiny, out)).writeNull(); configWrite(new JsonStreamWriter(tiny, nullable, out)).writeNull();
} else { } else {
final Type t = type == null ? value.getClass() : type; final Type t = type == null ? value.getClass() : type;
JsonStreamWriter writer = configWrite(new JsonStreamWriter(tiny, out)); JsonStreamWriter writer = configWrite(new JsonStreamWriter(tiny, nullable, out));
Encodeable encoder = this.lastConvertEncodeable; Encodeable encoder = this.lastConvertEncodeable;
if (encoder == null || encoder.getType() != t) { if (encoder == null || encoder.getType() != t) {
encoder = factory.loadEncoder(t); encoder = factory.loadEncoder(t);
@@ -431,7 +434,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
@Override @Override
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) { public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
Objects.requireNonNull(supplier); Objects.requireNonNull(supplier);
JsonByteBufferWriter out = configWrite(new JsonByteBufferWriter(tiny, supplier)); JsonByteBufferWriter out = configWrite(new JsonByteBufferWriter(tiny, nullable, supplier));
if (value == null) { if (value == null) {
out.writeNull(); out.writeNull();
} else { } else {

View File

@@ -386,7 +386,7 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
final Map<String, AccessibleObject> mixedNames = mixedNames0; final Map<String, AccessibleObject> mixedNames = mixedNames0;
final ClassLoader loader = Thread.currentThread().getContextClassLoader(); final ClassLoader loader = Thread.currentThread().getContextClassLoader();
final String newDynName = "org/redkaledyn/json/_Dyn" + JsonDynEncoder.class.getSimpleName() final String newDynName = "org/redkaledyn/json/_Dyn" + JsonDynEncoder.class.getSimpleName()
+ "__" + clazz.getName().replace('.', '_').replace('$', '_') + "_" + factory.tiny() + "_" + Utility.md5Hex(memberb.toString()); //tiny必须要加上, 同一个类会有多个字段定制Convert + "__" + clazz.getName().replace('.', '_').replace('$', '_') + "_" + factory.tiny() + "_" + factory.nullable() + "_" + Utility.md5Hex(memberb.toString()); //tiny必须要加上, 同一个类会有多个字段定制Convert
try { try {
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz; Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz;
@@ -512,7 +512,7 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
int maxLocals = 4; int maxLocals = 4;
int elementIndex = -1; int elementIndex = -1;
final Class firstType = readGetSetFieldType(members.get(0)); final Class firstType = readGetSetFieldType(members.get(0));
final boolean mustHadComma = firstType.isPrimitive() && (firstType != boolean.class || !factory.tiny()); //byte/short/char/int/float/long/double final boolean mustHadComma = firstType.isPrimitive() && (firstType != boolean.class || !factory.tiny() || factory.nullable()); //byte/short/char/int/float/long/double
if (onlyOneLatin1FieldObjectFlag) { if (onlyOneLatin1FieldObjectFlag) {
//out.writeObjectByOnlyOneLatin1FieldValue(messageFirstFieldBytes, value.getMessage());elementIndex++; //out.writeObjectByOnlyOneLatin1FieldValue(messageFirstFieldBytes, value.getMessage());elementIndex++;
@@ -670,7 +670,7 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
} }
} }
Label msgnotemptyif = null; Label msgnotemptyif = null;
if (!fieldtype.isPrimitive()) { //if (message != null) { start if (!fieldtype.isPrimitive() && !factory.nullable()) { //if (message != null) { start
mv.visitVarInsn(loadid, maxLocals); mv.visitVarInsn(loadid, maxLocals);
msgnotemptyif = new Label(); msgnotemptyif = new Label();
mv.visitJumpInsn(IFNULL, msgnotemptyif); mv.visitJumpInsn(IFNULL, msgnotemptyif);
@@ -794,7 +794,7 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
mv.visitVarInsn(loadid, maxLocals); mv.visitVarInsn(loadid, maxLocals);
mv.visitMethodInsn(INVOKEINTERFACE, encodeableName, "convertTo", "(" + writerDesc + "Ljava/lang/Object;)V", true); mv.visitMethodInsn(INVOKEINTERFACE, encodeableName, "convertTo", "(" + writerDesc + "Ljava/lang/Object;)V", true);
} }
if (!fieldtype.isPrimitive()) { //if (message != null) } end if (!fieldtype.isPrimitive() && !factory.nullable()) { //if (message != null) } end
mv.visitLabel(msgnotemptyif); mv.visitLabel(msgnotemptyif);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
} else if (fieldtype == boolean.class && factory.tiny()) { } else if (fieldtype == boolean.class && factory.tiny()) {

View File

@@ -24,7 +24,9 @@ import org.redkale.util.Uint128;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> { public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
private static final JsonFactory instance = new JsonFactory(null, getSystemPropertyBoolean("redkale.convert.json.tiny", "redkale.convert.tiny", false)); private static final JsonFactory instance = new JsonFactory(null,
getSystemPropertyBoolean("redkale.convert.json.tiny", "redkale.convert.tiny", false),
getSystemPropertyBoolean("redkale.convert.json.nullable", "redkale.convert.nullable", false));
static { static {
instance.register(Serializable.class, instance.loadEncoder(Object.class)); instance.register(Serializable.class, instance.loadEncoder(Object.class));
@@ -33,8 +35,8 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
//instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class)); //instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class));
} }
private JsonFactory(JsonFactory parent, boolean tiny) { private JsonFactory(JsonFactory parent, boolean tiny, boolean nullable) {
super(parent, tiny); super(parent, tiny, nullable);
if (parent == null) { if (parent == null) {
this.register(InetAddress.class, InetAddressSimpledCoder.InetAddressJsonSimpledCoder.instance); this.register(InetAddress.class, InetAddressSimpledCoder.InetAddressJsonSimpledCoder.instance);
this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance); this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance);
@@ -59,6 +61,12 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
return this; return this;
} }
@Override
public JsonFactory nullable(boolean nullable) {
this.nullable = nullable;
return this;
}
@Override @Override
public JsonFactory skipAllIgnore(final boolean skipIgnore) { public JsonFactory skipAllIgnore(final boolean skipIgnore) {
this.registerSkipAllIgnore(skipIgnore); this.registerSkipAllIgnore(skipIgnore);
@@ -70,7 +78,8 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
} }
public static JsonFactory create() { public static JsonFactory create() {
return new JsonFactory(null, getSystemPropertyBoolean("redkale.convert.json.tiny", "redkale.convert.tiny", false)); return new JsonFactory(null, getSystemPropertyBoolean("redkale.convert.json.tiny", "redkale.convert.tiny", false),
getSystemPropertyBoolean("redkale.convert.json.nullable", "redkale.convert.nullable", false));
} }
@Override @Override
@@ -92,22 +101,26 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
return this.tiny; return this.tiny;
} }
protected boolean nullable() {
return this.nullable;
}
@Override @Override
public final JsonConvert getConvert() { public final JsonConvert getConvert() {
if (convert == null) { if (convert == null) {
convert = new JsonConvert(this, tiny); convert = new JsonConvert(this, tiny, nullable);
} }
return (JsonConvert) convert; return (JsonConvert) convert;
} }
@Override @Override
public JsonFactory createChild() { public JsonFactory createChild() {
return new JsonFactory(this, this.tiny); return new JsonFactory(this, this.tiny, this.nullable);
} }
@Override @Override
public JsonFactory createChild(boolean tiny) { public JsonFactory createChild(boolean tiny, boolean nullable) {
return new JsonFactory(this, tiny); return new JsonFactory(this, tiny, nullable);
} }
@Override @Override

View File

@@ -21,12 +21,12 @@ class JsonStreamWriter extends JsonByteBufferWriter {
private OutputStream out; private OutputStream out;
protected JsonStreamWriter(boolean tiny, OutputStream out) { protected JsonStreamWriter(boolean tiny, boolean nullable, OutputStream out) {
this(tiny, null, out); this(tiny, nullable, null, out);
} }
protected JsonStreamWriter(boolean tiny, Charset charset, OutputStream out) { protected JsonStreamWriter(boolean tiny, boolean nullable, Charset charset, OutputStream out) {
super(tiny, charset, null); super(tiny, nullable, charset, null);
this.out = out; this.out = out;
} }
@@ -101,6 +101,10 @@ class JsonStreamWriter extends JsonByteBufferWriter {
*/ */
@Override @Override
public void writeLatin1To(final boolean quote, final String value) { public void writeLatin1To(final boolean quote, final String value) {
if (value == null) {
writeNull();
return;
}
char[] chs = Utility.charArray(value); char[] chs = Utility.charArray(value);
writeTo(quote, chs, 0, chs.length); writeTo(quote, chs, 0, chs.length);
} }

View File

@@ -23,6 +23,8 @@ public abstract class JsonWriter extends Writer {
protected boolean tiny = JsonFactory.root().tiny(); protected boolean tiny = JsonFactory.root().tiny();
protected boolean nullable = JsonFactory.root().nullable();
@Override @Override
public boolean tiny() { public boolean tiny() {
return tiny; return tiny;
@@ -37,6 +39,16 @@ public abstract class JsonWriter extends Writer {
return this.objExtFunc == null && this.objFieldFunc == null; return this.objExtFunc == null && this.objFieldFunc == null;
} }
@Override
public boolean nullable() {
return nullable;
}
public JsonWriter nullable(boolean nullable) {
this.nullable = nullable;
return this;
}
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
public abstract void writeTo(final char ch); //只能是 0 - 127 的字符 public abstract void writeTo(final char ch); //只能是 0 - 127 的字符

View File

@@ -20,6 +20,19 @@ import org.redkale.util.*;
*/ */
public class BsonMainTest { public class BsonMainTest {
public static void main(String[] args) throws Throwable {
BsonMainTest test = new BsonMainTest();
test.run1();
test.run2();
test.run3();
test.run4();
test.run5();
test.run6();
test.run7();
test.run8();
}
@Test @Test
public void run1() throws Throwable { public void run1() throws Throwable {
Serializable[] sers = new Serializable[]{"aaa", 4}; Serializable[] sers = new Serializable[]{"aaa", 4};
@@ -38,7 +51,7 @@ public class BsonMainTest {
SimpleChildEntity entry = SimpleChildEntity.create(); SimpleChildEntity entry = SimpleChildEntity.create();
byte[] bytes = convert.convertTo(SimpleEntity.class, entry); byte[] bytes = convert.convertTo(SimpleEntity.class, entry);
System.out.println("长度: " + bytes.length); System.out.println("长度: " + bytes.length);
Assertions.assertEquals(271, bytes.length); Assertions.assertEquals(260, bytes.length);
BsonByteBufferWriter writer = convert.pollWriter(() -> ByteBuffer.allocate(1)); BsonByteBufferWriter writer = convert.pollWriter(() -> ByteBuffer.allocate(1));
convert.convertTo(writer, SimpleEntity.class, entry); convert.convertTo(writer, SimpleEntity.class, entry);
ByteBuffer[] buffers = writer.toBuffers(); ByteBuffer[] buffers = writer.toBuffers();
@@ -52,7 +65,7 @@ public class BsonMainTest {
b.flip(); b.flip();
} }
System.out.println("长度: " + len); System.out.println("长度: " + len);
Assertions.assertEquals(271, len); Assertions.assertEquals(260, len);
SimpleChildEntity entry2 = convert.convertFrom(SimpleChildEntity.class, buffers); SimpleChildEntity entry2 = convert.convertFrom(SimpleChildEntity.class, buffers);
System.out.println(entry); System.out.println(entry);
Assertions.assertEquals(entry.toString(), entry2.toString()); Assertions.assertEquals(entry.toString(), entry2.toString());

View File

@@ -17,11 +17,21 @@ public class Json5Test {
public static void main(String[] args) throws Throwable { public static void main(String[] args) throws Throwable {
Json5Test test = new Json5Test(); Json5Test test = new Json5Test();
test.main = true; test.main = true;
test.run(); test.run1();
test.run2();
} }
@Test @Test
public void run() throws Exception { public void run1() throws Exception {
JsonFactory factory = JsonFactory.root().tiny(true).nullable(true);
final JsonConvert convert = factory.getConvert();
Json5Bean bean = new Json5Bean();
bean.id = 60;
System.out.println(convert.convertTo(bean));
}
@Test
public void run2() throws Exception {
JsonConvert convert = JsonConvert.root(); JsonConvert convert = JsonConvert.root();
Json5Bean bean = new Json5Bean(); Json5Bean bean = new Json5Bean();
bean.id = 500; bean.id = 500;

View File

@@ -37,6 +37,7 @@ public class JsonMainTest {
String json = "{\"access_token\":\"null\",\"priv\":null, vvv:nulla,\"priv2\":\"nulla\",\"expires_in\":7200, \"aa\":\"\"}"; String json = "{\"access_token\":\"null\",\"priv\":null, vvv:nulla,\"priv2\":\"nulla\",\"expires_in\":7200, \"aa\":\"\"}";
Map<String, String> map = convert.convertFrom(JsonConvert.TYPE_MAP_STRING_STRING, json); Map<String, String> map = convert.convertFrom(JsonConvert.TYPE_MAP_STRING_STRING, json);
System.out.println(map); System.out.println(map);
System.out.println(map.get("priv") == null);
String rs = convert.convertTo(map); String rs = convert.convertTo(map);
System.out.println(rs); System.out.println(rs);
ByteBuffer[] buffers = convert.convertTo(() -> ByteBuffer.allocate(1024), map); ByteBuffer[] buffers = convert.convertTo(() -> ByteBuffer.allocate(1024), map);
@@ -52,7 +53,7 @@ public class JsonMainTest {
SimpleChildEntity entry = SimpleChildEntity.create(); SimpleChildEntity entry = SimpleChildEntity.create();
String json = convert.convertTo(SimpleEntity.class, entry); String json = convert.convertTo(SimpleEntity.class, entry);
System.out.println("长度: " + json.length()); System.out.println("长度: " + json.length());
JsonByteBufferWriter writer = new JsonByteBufferWriter(false, () -> ByteBuffer.allocate(1)) { JsonByteBufferWriter writer = new JsonByteBufferWriter(false, false, () -> ByteBuffer.allocate(1)) {
}; };
convert.convertTo(writer, SimpleEntity.class, entry); convert.convertTo(writer, SimpleEntity.class, entry);
ByteBuffer[] buffers = writer.toBuffers(); ByteBuffer[] buffers = writer.toBuffers();