ConvertFactory增加nullable配置
This commit is contained in:
@@ -60,7 +60,9 @@ public final class ApiDocCommand {
|
||||
|
||||
if (params != null && params.length > 0) {
|
||||
for (String param : params) {
|
||||
if (param == null) continue;
|
||||
if (param == null) {
|
||||
continue;
|
||||
}
|
||||
param = param.toLowerCase();
|
||||
if (param.startsWith("--api-skiprpc=")) {
|
||||
skipRPC = "true".equalsIgnoreCase(param.substring("--api-skiprpc=".length()));
|
||||
@@ -80,7 +82,9 @@ public final class ApiDocCommand {
|
||||
List<Map> swaggerTags = new ArrayList<>();
|
||||
Map<String, Map<String, Object>> swaggerComponentsMap = new LinkedHashMap<>();
|
||||
for (NodeServer node : app.servers) {
|
||||
if (!(node instanceof NodeHttpServer)) continue;
|
||||
if (!(node instanceof NodeHttpServer)) {
|
||||
continue;
|
||||
}
|
||||
final Map<String, Object> map = new LinkedHashMap<>();
|
||||
serverList.add(map);
|
||||
HttpServer server = node.getServer();
|
||||
@@ -89,12 +93,20 @@ public final class ApiDocCommand {
|
||||
List<Map<String, Object>> servletsList = new ArrayList<>();
|
||||
map.put("servlets", servletsList);
|
||||
String plainContentType = server.getResponseConfig() == null ? "application/json" : server.getResponseConfig().plainContentType;
|
||||
if (plainContentType == null || plainContentType.isEmpty()) plainContentType = "application/json";
|
||||
if (plainContentType.indexOf(';') > 0) plainContentType = plainContentType.substring(0, plainContentType.indexOf(';'));
|
||||
if (plainContentType == null || plainContentType.isEmpty()) {
|
||||
plainContentType = "application/json";
|
||||
}
|
||||
if (plainContentType.indexOf(';') > 0) {
|
||||
plainContentType = plainContentType.substring(0, plainContentType.indexOf(';'));
|
||||
}
|
||||
|
||||
for (HttpServlet servlet : server.getDispatcherServlet().getServlets()) {
|
||||
if (!(servlet instanceof HttpServlet)) continue;
|
||||
if (servlet instanceof WebSocketServlet) continue;
|
||||
if (!(servlet instanceof HttpServlet)) {
|
||||
continue;
|
||||
}
|
||||
if (servlet instanceof WebSocketServlet) {
|
||||
continue;
|
||||
}
|
||||
if (servlet.getClass().getAnnotation(MessageMultiConsumer.class) != null) {
|
||||
node.logger.log(Level.INFO, servlet + " be skipped because has @MessageMultiConsumer");
|
||||
continue;
|
||||
@@ -128,16 +140,29 @@ public final class ApiDocCommand {
|
||||
Class clz = servlet.getClass();
|
||||
HashSet<String> actionUrls = new HashSet<>();
|
||||
do {
|
||||
if (Modifier.isAbstract(clz.getModifiers())) break;
|
||||
if (Modifier.isAbstract(clz.getModifiers())) {
|
||||
break;
|
||||
}
|
||||
for (Method method : clz.getMethods()) {
|
||||
if (method.getParameterCount() != 2) continue;
|
||||
if (method.getParameterCount() != 2) {
|
||||
continue;
|
||||
}
|
||||
HttpMapping action = method.getAnnotation(HttpMapping.class);
|
||||
if (action == null) continue;
|
||||
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
|
||||
if (actionUrls.contains(action.url())) continue;
|
||||
if (HttpScope.class.isAssignableFrom(action.result())) continue; //忽略模板引擎的方法
|
||||
if (action.rpconly() && skipRPC) continue; //不生成RPC接口
|
||||
|
||||
if (action == null) {
|
||||
continue;
|
||||
}
|
||||
if (!action.inherited() && selfClz != clz) {
|
||||
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 Map<String, Object> mappingMap = new LinkedHashMap<>();
|
||||
@@ -241,20 +266,36 @@ public final class ApiDocCommand {
|
||||
swaggerParamsList.add(swaggerParamMap);
|
||||
}
|
||||
}
|
||||
if (param.style() == HttpParam.HttpParameterStyle.BODY) hasbodyparam = true;
|
||||
if (ptype.isPrimitive() || ptype == String.class) continue;
|
||||
if (typesMap.containsKey(ptype.getName())) continue;
|
||||
if (ptype.getName().startsWith("java.")) continue;
|
||||
if (ptype.getName().startsWith("javax.")) continue;
|
||||
if (param.style() == HttpParam.HttpParameterStyle.BODY) {
|
||||
hasbodyparam = true;
|
||||
}
|
||||
if (ptype.isPrimitive() || ptype == String.class) {
|
||||
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<>();
|
||||
Class loop = ptype;
|
||||
final boolean filter = FilterBean.class.isAssignableFrom(loop);
|
||||
do {
|
||||
if (loop == null || loop.isInterface()) break;
|
||||
if (loop == null || loop.isInterface()) {
|
||||
break;
|
||||
}
|
||||
for (Field field : loop.getDeclaredFields()) {
|
||||
if (Modifier.isFinal(field.getModifiers())) continue;
|
||||
if (Modifier.isStatic(field.getModifiers())) continue;
|
||||
if (Modifier.isFinal(field.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<String, Object> fieldmap = new LinkedHashMap<>();
|
||||
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()));
|
||||
|
||||
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);
|
||||
@@ -301,11 +344,17 @@ public final class ApiDocCommand {
|
||||
Map<String, Object> respMap = new LinkedHashMap<>();
|
||||
respMap.put("schema", respSchemaMap);
|
||||
Object example = formatExample(returnFactory, action.example(), action.result(), resultType);
|
||||
if (example != null) respSchemaMap.put("example", example);
|
||||
if (!swaggerRequestBody.isEmpty()) swaggerOperatMap.put("requestBody", swaggerRequestBody);
|
||||
if (example != null) {
|
||||
respSchemaMap.put("example", example);
|
||||
}
|
||||
if (!swaggerRequestBody.isEmpty()) {
|
||||
swaggerOperatMap.put("requestBody", swaggerRequestBody);
|
||||
}
|
||||
swaggerOperatMap.put("parameters", swaggerParamsList);
|
||||
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))));
|
||||
|
||||
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);
|
||||
mappingsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
|
||||
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) -> {
|
||||
String[] urlregs1 = (String[]) o1.get("urlregs");
|
||||
@@ -337,7 +388,9 @@ public final class ApiDocCommand {
|
||||
swaggerResultMap.put("servers", swaggerServers);
|
||||
swaggerResultMap.put("paths", swaggerPathsMap);
|
||||
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"));
|
||||
out.write(JsonConvert.root().convertTo(swaggerResultMap).getBytes(StandardCharsets.UTF_8));
|
||||
out.close();
|
||||
@@ -421,8 +474,12 @@ public final class ApiDocCommand {
|
||||
Set<Type> types = new HashSet<>();
|
||||
Encodeable encodeable = JsonFactory.root().loadEncoder(genericType);
|
||||
String ct = componentKey(factory, logger, types, componentsMap, null, encodeable, true);
|
||||
if (ct == null || ct.length() == 0) return null;
|
||||
if (componentsMap.containsKey(ct)) return ct;
|
||||
if (ct == null || ct.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
if (componentsMap.containsKey(ct)) {
|
||||
return ct;
|
||||
}
|
||||
Map<String, Object> cmap = new LinkedHashMap<>();
|
||||
componentsMap.put(ct, cmap); //必须在调用simpleSchemaType之前put,不然嵌套情况下死循环
|
||||
|
||||
@@ -440,11 +497,15 @@ public final class ApiDocCommand {
|
||||
FilterColumn fcol = member.getField().getAnnotation(FilterColumn.class);
|
||||
if (fcol != null) {
|
||||
desc = fcol.comment();
|
||||
if (fcol.required()) requireds.add(member.getAttribute().field());
|
||||
if (fcol.required()) {
|
||||
requireds.add(member.getAttribute().field());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
desc = member.getField().getAnnotation(Comment.class).value();
|
||||
@@ -457,11 +518,15 @@ public final class ApiDocCommand {
|
||||
FilterColumn fcol = member.getMethod().getAnnotation(FilterColumn.class);
|
||||
if (fcol != null) {
|
||||
desc = fcol.comment();
|
||||
if (fcol.required()) requireds.add(member.getAttribute().field());
|
||||
if (fcol.required()) {
|
||||
requireds.add(member.getAttribute().field());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
if (!desc.isEmpty()) schemaMap.put("description", desc);
|
||||
if (!desc.isEmpty()) {
|
||||
schemaMap.put("description", desc);
|
||||
}
|
||||
properties.put(member.getAttribute().field(), schemaMap);
|
||||
}
|
||||
}
|
||||
if (!requireds.isEmpty()) cmap.put("required", requireds);
|
||||
if (!requireds.isEmpty()) {
|
||||
cmap.put("required", requireds);
|
||||
}
|
||||
cmap.put("properties", properties);
|
||||
return ct;
|
||||
} 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) {
|
||||
if (encodeable instanceof ObjectEncoder) {
|
||||
if (types.contains(encodeable.getType())) return "";
|
||||
if (types.contains(encodeable.getType())) {
|
||||
return "";
|
||||
}
|
||||
types.add(encodeable.getType());
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(((ObjectEncoder) encodeable).getTypeClass().getSimpleName());
|
||||
@@ -492,19 +563,33 @@ public final class ApiDocCommand {
|
||||
if (member.getEncoder() instanceof ArrayEncoder
|
||||
|| member.getEncoder() instanceof CollectionEncoder) {
|
||||
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();
|
||||
if (real == null) continue;
|
||||
if (real == null) {
|
||||
continue;
|
||||
}
|
||||
Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType();
|
||||
Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType();
|
||||
if (cz == ct) continue;
|
||||
if (field == null && encodeable.getType() instanceof Class) continue;
|
||||
if (sb.length() > 0 && subsb.length() > 0) sb.append("_");
|
||||
if (cz == ct) {
|
||||
continue;
|
||||
}
|
||||
if (field == null && encodeable.getType() instanceof Class) {
|
||||
continue;
|
||||
}
|
||||
if (sb.length() > 0 && subsb.length() > 0) {
|
||||
sb.append("_");
|
||||
}
|
||||
sb.append(subsb);
|
||||
} else if (member.getEncoder() instanceof ObjectEncoder || member.getEncoder() instanceof SimpledCoder) {
|
||||
AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField();
|
||||
if (real == null) continue;
|
||||
if (types.contains(member.getEncoder().getType())) continue;
|
||||
if (real == null) {
|
||||
continue;
|
||||
}
|
||||
if (types.contains(member.getEncoder().getType())) {
|
||||
continue;
|
||||
}
|
||||
types.add(member.getEncoder().getType());
|
||||
if (member.getEncoder() instanceof SimpledCoder) {
|
||||
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();
|
||||
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);
|
||||
if (subsb == null) return null;
|
||||
if (field == null && member.getEncoder().getType() instanceof Class) continue;
|
||||
if (sb.length() > 0 && subsb.length() > 0) sb.append("_");
|
||||
if (subsb == null) {
|
||||
return null;
|
||||
}
|
||||
if (field == null && member.getEncoder().getType() instanceof Class) {
|
||||
continue;
|
||||
}
|
||||
if (sb.length() > 0 && subsb.length() > 0) {
|
||||
sb.append("_");
|
||||
}
|
||||
sb.append(subsb);
|
||||
} else if (member.getEncoder() instanceof MapEncoder) {
|
||||
continue;
|
||||
@@ -529,9 +622,13 @@ public final class ApiDocCommand {
|
||||
} else if (encodeable instanceof ArrayEncoder || encodeable instanceof CollectionEncoder) {
|
||||
final boolean array = (encodeable instanceof ArrayEncoder);
|
||||
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);
|
||||
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) {
|
||||
return sb;
|
||||
}
|
||||
@@ -550,7 +647,9 @@ public final class ApiDocCommand {
|
||||
}
|
||||
|
||||
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;
|
||||
if (type == Flipper.class) {
|
||||
return new Flipper();
|
||||
@@ -642,8 +741,12 @@ public final class ApiDocCommand {
|
||||
json.append("{");
|
||||
int index = 0;
|
||||
for (DeMember member : ((ObjectDecoder) decoder).getMembers()) {
|
||||
if (!(member.getDecoder() instanceof ObjectDecoder)) continue;
|
||||
if (index > 0) json.append(",");
|
||||
if (!(member.getDecoder() instanceof ObjectDecoder)) {
|
||||
continue;
|
||||
}
|
||||
if (index > 0) {
|
||||
json.append(",");
|
||||
}
|
||||
json.append('"').append(member.getAttribute().field()).append("\":{}");
|
||||
index++;
|
||||
}
|
||||
@@ -659,6 +762,6 @@ public final class ApiDocCommand {
|
||||
return example;
|
||||
}
|
||||
|
||||
private static final JsonFactory exampleFactory = JsonFactory.create().tiny(false);
|
||||
private static final JsonFactory exampleFactory = JsonFactory.create().tiny(false).nullable(false);
|
||||
|
||||
}
|
||||
|
||||
@@ -24,21 +24,42 @@ import static java.lang.annotation.RetentionPolicy.*;
|
||||
public @interface ConvertCoder {
|
||||
|
||||
/**
|
||||
* 需要指定的字段类型,指定了coder字段值则可以不设置此字段
|
||||
* 需要指定的字段类型,类型必须是原字段类型的子类。
|
||||
* 例如: <br>
|
||||
* <blockquote><pre>
|
||||
* @ConvertCoder(column = String.class)
|
||||
* private CharSequence name;
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* 通常此字段值与encoder/decoder是二选一,指定了coder字段值则可以不设置此字段。
|
||||
*
|
||||
* @return 字段类名
|
||||
*/
|
||||
Class column() default Object.class;
|
||||
|
||||
/**
|
||||
* 序列化定制化的 Encodeable
|
||||
* 序列化定制化的 Encodeable, 构造函数的参数可以是:<br>
|
||||
* 1、ConvertFactory
|
||||
* 2、Type
|
||||
* 3、Class
|
||||
* 4、ConvertFactory和Type
|
||||
* 5、ConvertFactory和Class
|
||||
*
|
||||
* 类如果存在instance单实例对象字段值,则优先使用instance对象
|
||||
*
|
||||
* @return Encodeable 类
|
||||
*/
|
||||
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 类
|
||||
*/
|
||||
|
||||
@@ -44,7 +44,9 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
|
||||
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);
|
||||
|
||||
@@ -72,8 +74,9 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
|
||||
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.nullable = nullable;
|
||||
this.parent = parent;
|
||||
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(boolean tiny);
|
||||
public abstract ConvertFactory createChild(boolean tiny, boolean nullable);
|
||||
|
||||
protected SimpledCoder createEnumSimpledCoder(Class enumClass) {
|
||||
return new EnumSimpledCoder(this, enumClass);
|
||||
@@ -335,6 +338,11 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConvertFactory nullable(boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isConvertDisabled(AccessibleObject element) {
|
||||
ConvertDisabled[] ccs = element.getAnnotationsByType(ConvertDisabled.class);
|
||||
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) {
|
||||
return this;
|
||||
}
|
||||
@@ -642,7 +650,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
if (!ann.type().contains(ct)) {
|
||||
continue;
|
||||
}
|
||||
Class colType = type;
|
||||
Type colType = type;
|
||||
if (ann.column() != Object.class) {
|
||||
colType = ann.column();
|
||||
}
|
||||
@@ -679,7 +687,9 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
if (paramTypes.length == 0) {
|
||||
encoder = creator.create();
|
||||
} 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);
|
||||
} else if (ConvertFactory.class.isAssignableFrom(paramTypes[0])) {
|
||||
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");
|
||||
}
|
||||
} 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);
|
||||
} else if (Type.class.isAssignableFrom(paramTypes[0]) && ConvertFactory.class.isAssignableFrom(paramTypes[1])) {
|
||||
encoder = creator.create(colType, this);
|
||||
@@ -740,7 +754,9 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
if (paramTypes.length == 0) {
|
||||
decoder = creator.create();
|
||||
} 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);
|
||||
} else if (ConvertFactory.class.isAssignableFrom(paramTypes[0])) {
|
||||
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");
|
||||
}
|
||||
} 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);
|
||||
} else if (Type.class.isAssignableFrom(paramTypes[0]) && ConvertFactory.class.isAssignableFrom(paramTypes[1])) {
|
||||
decoder = creator.create(colType, this);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
package org.redkale.convert;
|
||||
|
||||
/**
|
||||
* Convert的扩展实现类加载器
|
||||
* Convert的扩展实现类加载器, 通过此类可以创建自定义的序列化格式,例如:protobuf、xmlbean
|
||||
*
|
||||
*
|
||||
* 详情见: https://redkale.org
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
*/
|
||||
package org.redkale.convert;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* 序列化时标记String字段的值是否为无转义字符且长度不超过255的字符串
|
||||
* 序列化时标记String字段的值是否为无转义字符且长度不超过255的字符串,通常用于类名、字段名、枚举值字符串等
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
|
||||
@@ -114,7 +114,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
if (small != null && field.getType() == String.class) {
|
||||
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);
|
||||
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) {
|
||||
colFactory = factory.columnFactory(maybeField.getType(), maybeField.getAnnotationsByType(ConvertCoder.class), false);
|
||||
colFactory = factory.columnFactory(maybeField.getGenericType(), maybeField.getAnnotationsByType(ConvertCoder.class), false);
|
||||
}
|
||||
Decodeable<R, ?> fieldCoder;
|
||||
if (small != null && method.getParameterTypes()[0] == String.class) {
|
||||
|
||||
@@ -95,7 +95,7 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
if (small != null && field.getType() == String.class) {
|
||||
fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance;
|
||||
@@ -165,9 +165,9 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
|
||||
}
|
||||
}
|
||||
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) {
|
||||
colFactory = factory.columnFactory(maybeField.getType(), maybeField.getAnnotationsByType(ConvertCoder.class), true);
|
||||
colFactory = factory.columnFactory(maybeField.getGenericType(), maybeField.getAnnotationsByType(ConvertCoder.class), true);
|
||||
}
|
||||
Encodeable<W, ?> fieldCoder;
|
||||
if (small != null && method.getReturnType() == String.class) {
|
||||
|
||||
@@ -74,6 +74,13 @@ public abstract class Writer {
|
||||
*/
|
||||
public abstract boolean tiny();
|
||||
|
||||
/**
|
||||
* 当nullable=true时, 字段值为null时会输出该字段
|
||||
*
|
||||
* @return 是否简化
|
||||
*/
|
||||
public abstract boolean nullable();
|
||||
|
||||
/**
|
||||
* 输出null值
|
||||
*/
|
||||
@@ -132,6 +139,12 @@ public abstract class Writer {
|
||||
value = objFieldFunc.apply(member.attribute, obj);
|
||||
}
|
||||
if (value == null) {
|
||||
if (nullable()) {
|
||||
Attribute attr = member.getAttribute();
|
||||
this.writeFieldName(member, attr.field(), attr.genericType(), member.getPosition());
|
||||
writeNull();
|
||||
this.comma = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (tiny()) {
|
||||
@@ -164,6 +177,11 @@ public abstract class Writer {
|
||||
@SuppressWarnings("unchecked")
|
||||
public void writeObjectField(final String fieldName, Type fieldType, int fieldPos, Encodeable anyEncoder, Object value) {
|
||||
if (value == null) {
|
||||
if (nullable()) {
|
||||
this.writeFieldName(null, fieldName, fieldType, fieldPos);
|
||||
writeNull();
|
||||
this.comma = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (fieldType == null) {
|
||||
|
||||
@@ -26,12 +26,13 @@ public class BsonByteBufferWriter extends BsonWriter {
|
||||
private int index;
|
||||
|
||||
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);
|
||||
this.tiny = tiny;
|
||||
this.nullable = nullable;
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
@@ -76,6 +77,12 @@ public class BsonByteBufferWriter extends BsonWriter {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BsonByteBufferWriter nullable(boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int expand(final int byteLength) {
|
||||
if (this.buffers == null) {
|
||||
|
||||
@@ -48,9 +48,12 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||
|
||||
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);
|
||||
this.tiny = tiny;
|
||||
this.nullable = nullable;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,7 +82,7 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||
|
||||
@Override
|
||||
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
|
||||
protected <S extends BsonWriter> S configWrite(S writer) {
|
||||
return fieldFunc(writer, fieldFunc, mapFieldFunc, objExtFunc);
|
||||
@@ -117,11 +120,11 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||
|
||||
//------------------------------ writer -----------------------------------------------------------
|
||||
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) {
|
||||
return configWrite(new BsonStreamWriter(tiny, out));
|
||||
return configWrite(new BsonStreamWriter(tiny, nullable, out));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,7 +135,7 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||
} else {
|
||||
writerPool.set(null);
|
||||
}
|
||||
return configWrite(writer.tiny(tiny));
|
||||
return configWrite(writer.tiny(tiny).nullable(nullable));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -237,7 +240,7 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||
@Override
|
||||
public void convertToBytes(final ByteArray array, final Type type, final Object value) {
|
||||
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) {
|
||||
writer.writeNull();
|
||||
} else {
|
||||
@@ -283,7 +286,7 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||
if (value == 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);
|
||||
return writer;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@ import org.redkale.util.TypeToken;
|
||||
@SuppressWarnings("unchecked")
|
||||
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);
|
||||
|
||||
@@ -48,8 +50,8 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
|
||||
//instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class));
|
||||
}
|
||||
|
||||
private BsonFactory(BsonFactory parent, boolean tiny) {
|
||||
super(parent, tiny);
|
||||
private BsonFactory(BsonFactory parent, boolean tiny, boolean nullable) {
|
||||
super(parent, tiny, nullable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,6 +64,16 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
|
||||
return this.tiny;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BsonFactory nullable(boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected boolean nullable() {
|
||||
return this.nullable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BsonFactory skipAllIgnore(final boolean skipIgnore) {
|
||||
this.registerSkipAllIgnore(skipIgnore);
|
||||
@@ -73,25 +85,26 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
|
||||
}
|
||||
|
||||
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
|
||||
public final BsonConvert getConvert() {
|
||||
if (convert == null) {
|
||||
convert = new BsonConvert(this, tiny);
|
||||
convert = new BsonConvert(this, tiny, nullable);
|
||||
}
|
||||
return (BsonConvert) convert;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BsonFactory createChild() {
|
||||
return new BsonFactory(this, this.tiny);
|
||||
return new BsonFactory(this, this.tiny, this.nullable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BsonFactory createChild(boolean tiny) {
|
||||
return new BsonFactory(this, tiny);
|
||||
public BsonFactory createChild(boolean tiny, boolean nullable) {
|
||||
return new BsonFactory(this, tiny, nullable);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,8 +18,8 @@ class BsonStreamWriter extends BsonByteBufferWriter {
|
||||
|
||||
private OutputStream out;
|
||||
|
||||
protected BsonStreamWriter(boolean tiny, OutputStream out) {
|
||||
super(tiny, null);
|
||||
protected BsonStreamWriter(boolean tiny, boolean nullable, OutputStream out) {
|
||||
super(tiny, nullable, null);
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ public class BsonWriter extends Writer implements ByteTuple {
|
||||
|
||||
protected boolean tiny = BsonFactory.root().tiny();
|
||||
|
||||
protected boolean nullable = BsonFactory.root().nullable();
|
||||
|
||||
public static ObjectPool<BsonWriter> createPool(int max) {
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean nullable() {
|
||||
return nullable;
|
||||
}
|
||||
|
||||
public BsonWriter nullable(boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
return this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
|
||||
@@ -34,12 +34,13 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
|
||||
private int index;
|
||||
|
||||
public JsonByteBufferWriter(boolean tiny, Supplier<ByteBuffer> supplier) {
|
||||
this(tiny, null, supplier);
|
||||
public JsonByteBufferWriter(boolean tiny, boolean nullable, Supplier<ByteBuffer> 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.nullable = nullable;
|
||||
this.charset = charset;
|
||||
this.supplier = supplier;
|
||||
}
|
||||
@@ -311,6 +312,10 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
*/
|
||||
@Override
|
||||
public void writeLatin1To(final boolean quote, final String value) {
|
||||
if (value == null) {
|
||||
writeNull();
|
||||
return;
|
||||
}
|
||||
byte[] bs = Utility.latin1ByteArray(value);
|
||||
int expandsize = expand(bs.length + (quote ? 2 : 0));
|
||||
if (expandsize == 0) {// 只需要一个buffer
|
||||
@@ -564,6 +569,12 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
|
||||
@Override
|
||||
public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) {
|
||||
if (value == null && nullable()) {
|
||||
writeTo(fieldBytes);
|
||||
writeNull();
|
||||
writeTo('}');
|
||||
return;
|
||||
}
|
||||
if (value == null || (tiny && value.isEmpty())) {
|
||||
expand(1);
|
||||
this.buffers[index].put((byte) '}');
|
||||
@@ -616,6 +627,13 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
|
||||
@Override //firstFieldBytes 必须带{开头
|
||||
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())) {
|
||||
int expandsize = expand(2);
|
||||
if (expandsize == 0) { // 只需要一个buffer
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
*/
|
||||
package org.redkale.convert.json;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.charset.*;
|
||||
import java.util.function.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.function.Consumer;
|
||||
import org.redkale.convert.*;
|
||||
import static org.redkale.convert.json.JsonWriter.*;
|
||||
import org.redkale.util.*;
|
||||
@@ -55,8 +55,9 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
|
||||
this.count = array.length();
|
||||
}
|
||||
|
||||
public JsonBytesWriter(boolean tiny, ByteArray array) {
|
||||
public JsonBytesWriter(boolean tiny, boolean nullable, ByteArray array) {
|
||||
this.tiny = tiny;
|
||||
this.nullable = nullable;
|
||||
this.content = array.content();
|
||||
this.count = array.length();
|
||||
}
|
||||
@@ -158,6 +159,10 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
|
||||
*/
|
||||
@Override
|
||||
public void writeLatin1To(final boolean quote, final String value) {
|
||||
if (value == null) {
|
||||
writeNull();
|
||||
return;
|
||||
}
|
||||
byte[] bs = Utility.latin1ByteArray(value);
|
||||
int len = bs.length;
|
||||
if (quote) {
|
||||
@@ -271,6 +276,12 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
|
||||
|
||||
@Override
|
||||
public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) {
|
||||
if (value == null && nullable()) {
|
||||
writeTo(fieldBytes);
|
||||
writeNull();
|
||||
writeTo('}');
|
||||
return;
|
||||
}
|
||||
if (value == null || (tiny && value.isEmpty())) {
|
||||
expand(1);
|
||||
content[count++] = '}';
|
||||
@@ -294,6 +305,13 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
|
||||
|
||||
@Override //firstFieldBytes 必须带{开头
|
||||
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())) {
|
||||
expand(2);
|
||||
content[count++] = '{';
|
||||
|
||||
@@ -104,6 +104,10 @@ public class JsonCharsWriter extends JsonWriter {
|
||||
*/
|
||||
@Override
|
||||
public void writeLatin1To(final boolean quote, final String value) {
|
||||
if (value == null) {
|
||||
writeNull();
|
||||
return;
|
||||
}
|
||||
int len = value.length();
|
||||
expand(len + (quote ? 2 : 0));
|
||||
if (quote) {
|
||||
@@ -220,6 +224,12 @@ public class JsonCharsWriter extends JsonWriter {
|
||||
|
||||
@Override
|
||||
public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) {
|
||||
if (value == null && nullable()) {
|
||||
writeTo(fieldBytes);
|
||||
writeNull();
|
||||
writeTo('}');
|
||||
return;
|
||||
}
|
||||
if (value == null || (tiny && value.isEmpty())) {
|
||||
expand(1);
|
||||
content[count++] = '}';
|
||||
@@ -241,6 +251,13 @@ public class JsonCharsWriter extends JsonWriter {
|
||||
|
||||
@Override //firstFieldBytes 必须带{开头
|
||||
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())) {
|
||||
expand(2);
|
||||
content[count++] = '{';
|
||||
|
||||
@@ -42,13 +42,16 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
|
||||
private final boolean tiny;
|
||||
|
||||
private final boolean nullable;
|
||||
|
||||
private Encodeable lastConvertEncodeable;
|
||||
|
||||
private Decodeable lastConvertDecodeable;
|
||||
|
||||
protected JsonConvert(JsonFactory factory, boolean tiny) {
|
||||
protected JsonConvert(JsonFactory factory, boolean tiny, boolean nullable) {
|
||||
super(factory);
|
||||
this.tiny = tiny;
|
||||
this.nullable = nullable;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,7 +80,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
|
||||
@Override
|
||||
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
|
||||
protected <S extends JsonWriter> S configWrite(S writer) {
|
||||
return fieldFunc(writer, objFieldFunc, mapFieldFunc, objExtFunc);
|
||||
@@ -112,7 +115,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
} else {
|
||||
bytesWriterPool.set(null);
|
||||
}
|
||||
return configWrite((JsonBytesWriter) writer.tiny(tiny));
|
||||
return configWrite((JsonBytesWriter) writer.tiny(tiny).nullable(nullable));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,7 +135,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
} else {
|
||||
bytesWriterPool.set(null);
|
||||
}
|
||||
return configWrite((JsonBytesWriter) writer.tiny(tiny));
|
||||
return configWrite((JsonBytesWriter) writer.tiny(tiny).nullable(nullable));
|
||||
}
|
||||
|
||||
private void offerJsonBytesWriter(final JsonBytesWriter writer) {
|
||||
@@ -392,7 +395,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
@Override
|
||||
public void convertToBytes(final ByteArray array, final Type type, final Object value) {
|
||||
Objects.requireNonNull(array);
|
||||
JsonBytesWriter writer = configWrite(new JsonBytesWriter(tiny, array));
|
||||
JsonBytesWriter writer = configWrite(new JsonBytesWriter(tiny, nullable, array));
|
||||
if (value == null) {
|
||||
writer.writeNull();
|
||||
} else {
|
||||
@@ -412,10 +415,10 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
|
||||
public void convertTo(final OutputStream out, final Type type, final Object value) {
|
||||
if (value == null) {
|
||||
configWrite(new JsonStreamWriter(tiny, out)).writeNull();
|
||||
configWrite(new JsonStreamWriter(tiny, nullable, out)).writeNull();
|
||||
} else {
|
||||
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;
|
||||
if (encoder == null || encoder.getType() != t) {
|
||||
encoder = factory.loadEncoder(t);
|
||||
@@ -431,7 +434,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
@Override
|
||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
||||
Objects.requireNonNull(supplier);
|
||||
JsonByteBufferWriter out = configWrite(new JsonByteBufferWriter(tiny, supplier));
|
||||
JsonByteBufferWriter out = configWrite(new JsonByteBufferWriter(tiny, nullable, supplier));
|
||||
if (value == null) {
|
||||
out.writeNull();
|
||||
} else {
|
||||
|
||||
@@ -386,7 +386,7 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
|
||||
final Map<String, AccessibleObject> mixedNames = mixedNames0;
|
||||
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
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 {
|
||||
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
|
||||
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 elementIndex = -1;
|
||||
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) {
|
||||
//out.writeObjectByOnlyOneLatin1FieldValue(messageFirstFieldBytes, value.getMessage());elementIndex++;
|
||||
@@ -670,7 +670,7 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
|
||||
}
|
||||
}
|
||||
Label msgnotemptyif = null;
|
||||
if (!fieldtype.isPrimitive()) { //if (message != null) { start
|
||||
if (!fieldtype.isPrimitive() && !factory.nullable()) { //if (message != null) { start
|
||||
mv.visitVarInsn(loadid, maxLocals);
|
||||
msgnotemptyif = new Label();
|
||||
mv.visitJumpInsn(IFNULL, msgnotemptyif);
|
||||
@@ -794,7 +794,7 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
|
||||
mv.visitVarInsn(loadid, maxLocals);
|
||||
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.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
} else if (fieldtype == boolean.class && factory.tiny()) {
|
||||
|
||||
@@ -24,7 +24,9 @@ import org.redkale.util.Uint128;
|
||||
@SuppressWarnings("unchecked")
|
||||
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 {
|
||||
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));
|
||||
}
|
||||
|
||||
private JsonFactory(JsonFactory parent, boolean tiny) {
|
||||
super(parent, tiny);
|
||||
private JsonFactory(JsonFactory parent, boolean tiny, boolean nullable) {
|
||||
super(parent, tiny, nullable);
|
||||
if (parent == null) {
|
||||
this.register(InetAddress.class, InetAddressSimpledCoder.InetAddressJsonSimpledCoder.instance);
|
||||
this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance);
|
||||
@@ -59,6 +61,12 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonFactory nullable(boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonFactory skipAllIgnore(final boolean skipIgnore) {
|
||||
this.registerSkipAllIgnore(skipIgnore);
|
||||
@@ -70,7 +78,8 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
||||
}
|
||||
|
||||
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
|
||||
@@ -92,22 +101,26 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
||||
return this.tiny;
|
||||
}
|
||||
|
||||
protected boolean nullable() {
|
||||
return this.nullable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final JsonConvert getConvert() {
|
||||
if (convert == null) {
|
||||
convert = new JsonConvert(this, tiny);
|
||||
convert = new JsonConvert(this, tiny, nullable);
|
||||
}
|
||||
return (JsonConvert) convert;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonFactory createChild() {
|
||||
return new JsonFactory(this, this.tiny);
|
||||
return new JsonFactory(this, this.tiny, this.nullable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonFactory createChild(boolean tiny) {
|
||||
return new JsonFactory(this, tiny);
|
||||
public JsonFactory createChild(boolean tiny, boolean nullable) {
|
||||
return new JsonFactory(this, tiny, nullable);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,12 +21,12 @@ class JsonStreamWriter extends JsonByteBufferWriter {
|
||||
|
||||
private OutputStream out;
|
||||
|
||||
protected JsonStreamWriter(boolean tiny, OutputStream out) {
|
||||
this(tiny, null, out);
|
||||
protected JsonStreamWriter(boolean tiny, boolean nullable, OutputStream out) {
|
||||
this(tiny, nullable, null, out);
|
||||
}
|
||||
|
||||
protected JsonStreamWriter(boolean tiny, Charset charset, OutputStream out) {
|
||||
super(tiny, charset, null);
|
||||
protected JsonStreamWriter(boolean tiny, boolean nullable, Charset charset, OutputStream out) {
|
||||
super(tiny, nullable, charset, null);
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
@@ -101,6 +101,10 @@ class JsonStreamWriter extends JsonByteBufferWriter {
|
||||
*/
|
||||
@Override
|
||||
public void writeLatin1To(final boolean quote, final String value) {
|
||||
if (value == null) {
|
||||
writeNull();
|
||||
return;
|
||||
}
|
||||
char[] chs = Utility.charArray(value);
|
||||
writeTo(quote, chs, 0, chs.length);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ public abstract class JsonWriter extends Writer {
|
||||
|
||||
protected boolean tiny = JsonFactory.root().tiny();
|
||||
|
||||
protected boolean nullable = JsonFactory.root().nullable();
|
||||
|
||||
@Override
|
||||
public boolean tiny() {
|
||||
return tiny;
|
||||
@@ -37,6 +39,16 @@ public abstract class JsonWriter extends Writer {
|
||||
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 的字符
|
||||
|
||||
|
||||
@@ -20,6 +20,19 @@ import org.redkale.util.*;
|
||||
*/
|
||||
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
|
||||
public void run1() throws Throwable {
|
||||
Serializable[] sers = new Serializable[]{"aaa", 4};
|
||||
@@ -38,7 +51,7 @@ public class BsonMainTest {
|
||||
SimpleChildEntity entry = SimpleChildEntity.create();
|
||||
byte[] bytes = convert.convertTo(SimpleEntity.class, entry);
|
||||
System.out.println("长度: " + bytes.length);
|
||||
Assertions.assertEquals(271, bytes.length);
|
||||
Assertions.assertEquals(260, bytes.length);
|
||||
BsonByteBufferWriter writer = convert.pollWriter(() -> ByteBuffer.allocate(1));
|
||||
convert.convertTo(writer, SimpleEntity.class, entry);
|
||||
ByteBuffer[] buffers = writer.toBuffers();
|
||||
@@ -52,7 +65,7 @@ public class BsonMainTest {
|
||||
b.flip();
|
||||
}
|
||||
System.out.println("长度: " + len);
|
||||
Assertions.assertEquals(271, len);
|
||||
Assertions.assertEquals(260, len);
|
||||
SimpleChildEntity entry2 = convert.convertFrom(SimpleChildEntity.class, buffers);
|
||||
System.out.println(entry);
|
||||
Assertions.assertEquals(entry.toString(), entry2.toString());
|
||||
|
||||
@@ -17,11 +17,21 @@ public class Json5Test {
|
||||
public static void main(String[] args) throws Throwable {
|
||||
Json5Test test = new Json5Test();
|
||||
test.main = true;
|
||||
test.run();
|
||||
test.run1();
|
||||
test.run2();
|
||||
}
|
||||
|
||||
@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();
|
||||
Json5Bean bean = new Json5Bean();
|
||||
bean.id = 500;
|
||||
|
||||
@@ -37,6 +37,7 @@ public class JsonMainTest {
|
||||
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);
|
||||
System.out.println(map);
|
||||
System.out.println(map.get("priv") == null);
|
||||
String rs = convert.convertTo(map);
|
||||
System.out.println(rs);
|
||||
ByteBuffer[] buffers = convert.convertTo(() -> ByteBuffer.allocate(1024), map);
|
||||
@@ -52,7 +53,7 @@ public class JsonMainTest {
|
||||
SimpleChildEntity entry = SimpleChildEntity.create();
|
||||
String json = convert.convertTo(SimpleEntity.class, entry);
|
||||
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);
|
||||
ByteBuffer[] buffers = writer.toBuffers();
|
||||
|
||||
Reference in New Issue
Block a user