feat: int/float/decimal精度优化
All checks were successful
序列化结构检查 / serialization-schema-check (push) Has been skipped
All checks were successful
序列化结构检查 / serialization-schema-check (push) Has been skipped
This commit is contained in:
@@ -45,7 +45,7 @@ public class SkeletonJsonRenderer {
|
|||||||
private Node buildTree(TypeSchema schema) {
|
private Node buildTree(TypeSchema schema) {
|
||||||
Node root = new Node(JsonType.OBJECT);
|
Node root = new Node(JsonType.OBJECT);
|
||||||
for (FieldSchema field : schema.getFields().values()) {
|
for (FieldSchema field : schema.getFields().values()) {
|
||||||
putPath(root, field.getPath(), field.getJsonType());
|
putPath(root, field.getPath(), field.getJsonType(), field.getJavaType());
|
||||||
}
|
}
|
||||||
// 根数组:字段以 [] / [].xxx 记录
|
// 根数组:字段以 [] / [].xxx 记录
|
||||||
if (root.children.size() == 1 && root.children.containsKey("[]")) {
|
if (root.children.size() == 1 && root.children.containsKey("[]")) {
|
||||||
@@ -56,7 +56,7 @@ public class SkeletonJsonRenderer {
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putPath(Node root, String path, JsonType type) {
|
private void putPath(Node root, String path, JsonType type, String javaType) {
|
||||||
List<Seg> segs = parsePath(path);
|
List<Seg> segs = parsePath(path);
|
||||||
if (segs.isEmpty()) {
|
if (segs.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -70,10 +70,9 @@ public class SkeletonJsonRenderer {
|
|||||||
arr.type = JsonType.ARRAY;
|
arr.type = JsonType.ARRAY;
|
||||||
Node elem = arr.children.computeIfAbsent("[]", k -> new Node(JsonType.OBJECT));
|
Node elem = arr.children.computeIfAbsent("[]", k -> new Node(JsonType.OBJECT));
|
||||||
if (last) {
|
if (last) {
|
||||||
if (type == JsonType.OBJECT || type == JsonType.ARRAY || type == JsonType.MAP) {
|
elem.type = type;
|
||||||
elem.type = type;
|
elem.javaType = javaType;
|
||||||
} else {
|
if (type != JsonType.OBJECT && type != JsonType.ARRAY && type != JsonType.MAP) {
|
||||||
elem.type = type;
|
|
||||||
elem.leaf = true;
|
elem.leaf = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,6 +82,7 @@ public class SkeletonJsonRenderer {
|
|||||||
k -> new Node(last ? type : JsonType.OBJECT));
|
k -> new Node(last ? type : JsonType.OBJECT));
|
||||||
if (last) {
|
if (last) {
|
||||||
child.type = type;
|
child.type = type;
|
||||||
|
child.javaType = javaType;
|
||||||
child.leaf = type != JsonType.OBJECT && type != JsonType.ARRAY && type != JsonType.MAP;
|
child.leaf = type != JsonType.OBJECT && type != JsonType.ARRAY && type != JsonType.MAP;
|
||||||
} else if (child.type != JsonType.ARRAY) {
|
} else if (child.type != JsonType.ARRAY) {
|
||||||
child.type = JsonType.OBJECT;
|
child.type = JsonType.OBJECT;
|
||||||
@@ -129,7 +129,7 @@ public class SkeletonJsonRenderer {
|
|||||||
return "[" + write(elem, elemPath, protectedPaths, compact) + "]";
|
return "[" + write(elem, elemPath, protectedPaths, compact) + "]";
|
||||||
}
|
}
|
||||||
if (node.leaf || isScalar(node.type)) {
|
if (node.leaf || isScalar(node.type)) {
|
||||||
return placeholder(node.type);
|
return placeholder(node.type, node.javaType);
|
||||||
}
|
}
|
||||||
if (node.type == JsonType.MAP) {
|
if (node.type == JsonType.MAP) {
|
||||||
return "{}";
|
return "{}";
|
||||||
@@ -161,7 +161,7 @@ public class SkeletonJsonRenderer {
|
|||||||
} else if (child.type == JsonType.ARRAY) {
|
} else if (child.type == JsonType.ARRAY) {
|
||||||
sb.append(write(child, childPath, protectedPaths, compact));
|
sb.append(write(child, childPath, protectedPaths, compact));
|
||||||
} else if (child.leaf || isScalar(child.type)) {
|
} else if (child.leaf || isScalar(child.type)) {
|
||||||
sb.append(placeholder(child.type));
|
sb.append(placeholder(child.type, child.javaType));
|
||||||
} else {
|
} else {
|
||||||
sb.append(write(child, childPath, protectedPaths, compact));
|
sb.append(write(child, childPath, protectedPaths, compact));
|
||||||
}
|
}
|
||||||
@@ -177,7 +177,7 @@ public class SkeletonJsonRenderer {
|
|||||||
if (child.type == JsonType.OBJECT || child.type == JsonType.MAP) {
|
if (child.type == JsonType.OBJECT || child.type == JsonType.MAP) {
|
||||||
return "\"...\"";
|
return "\"...\"";
|
||||||
}
|
}
|
||||||
return placeholder(child.type);
|
return placeholder(child.type, child.javaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isProtectedUnder(String pathPrefix, Set<String> protectedPaths) {
|
private boolean isProtectedUnder(String pathPrefix, Set<String> protectedPaths) {
|
||||||
@@ -327,13 +327,17 @@ public class SkeletonJsonRenderer {
|
|||||||
|| type == JsonType.BOOLEAN || type == JsonType.UNKNOWN;
|
|| type == JsonType.BOOLEAN || type == JsonType.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String placeholder(JsonType type) {
|
/**
|
||||||
|
* 数字类型示意占位(合法 JSON number):整数 {@code 0}、浮点 {@code 0.0}、BigDecimal {@code 0.00}。
|
||||||
|
* 仅用于通知可读性,不代表真实精度/scale。
|
||||||
|
*/
|
||||||
|
private String placeholder(JsonType type, String javaType) {
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
return "null";
|
return "null";
|
||||||
}
|
}
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case NUMBER:
|
case NUMBER:
|
||||||
return "0";
|
return numberPlaceholder(javaType);
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
return "false";
|
return "false";
|
||||||
case STRING:
|
case STRING:
|
||||||
@@ -349,6 +353,37 @@ public class SkeletonJsonRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String numberPlaceholder(String javaType) {
|
||||||
|
String simple = simpleJavaType(javaType);
|
||||||
|
if ("BigDecimal".equals(simple)) {
|
||||||
|
return "0.00";
|
||||||
|
}
|
||||||
|
if ("float".equals(simple) || "Float".equals(simple)
|
||||||
|
|| "double".equals(simple) || "Double".equals(simple)) {
|
||||||
|
return "0.0";
|
||||||
|
}
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String simpleJavaType(String javaType) {
|
||||||
|
if (javaType == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String s = javaType.trim();
|
||||||
|
if (s.isEmpty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int lt = s.indexOf('<');
|
||||||
|
if (lt > 0) {
|
||||||
|
s = s.substring(0, lt).trim();
|
||||||
|
}
|
||||||
|
int dot = s.lastIndexOf('.');
|
||||||
|
if (dot >= 0 && dot < s.length() - 1) {
|
||||||
|
s = s.substring(dot + 1);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
private String escape(String s) {
|
private String escape(String s) {
|
||||||
return s.replace("\\", "\\\\").replace("\"", "\\\"");
|
return s.replace("\\", "\\\\").replace("\"", "\\\"");
|
||||||
}
|
}
|
||||||
@@ -365,6 +400,7 @@ public class SkeletonJsonRenderer {
|
|||||||
|
|
||||||
private static final class Node {
|
private static final class Node {
|
||||||
JsonType type;
|
JsonType type;
|
||||||
|
String javaType;
|
||||||
boolean leaf;
|
boolean leaf;
|
||||||
final Map<String, Node> children = new LinkedHashMap<>();
|
final Map<String, Node> children = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
|||||||
@@ -80,4 +80,31 @@ class SkeletonJsonRendererTest {
|
|||||||
"截断后仍应保留改动相关字段: " + truncated);
|
"截断后仍应保留改动相关字段: " + truncated);
|
||||||
assertEquals(true, truncated.length() >= 10);
|
assertEquals(true, truncated.length() >= 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void numberPlaceholdersDistinguishIntegerFloatAndBigDecimal() {
|
||||||
|
TypeSchema schema = new TypeSchema("MoneyVo");
|
||||||
|
schema.add(new FieldSchema("count", JsonType.NUMBER, "Integer"));
|
||||||
|
schema.add(new FieldSchema("rate", JsonType.NUMBER, "Double"));
|
||||||
|
schema.add(new FieldSchema("amount", JsonType.NUMBER, "BigDecimal"));
|
||||||
|
schema.add(new FieldSchema("score", JsonType.NUMBER, "Float"));
|
||||||
|
|
||||||
|
String json = new SkeletonJsonRenderer().render(schema);
|
||||||
|
assertTrue(json.contains("\"count\":0"), json);
|
||||||
|
assertTrue(json.contains("\"rate\":0.0"), json);
|
||||||
|
assertTrue(json.contains("\"amount\":0.00"), json);
|
||||||
|
assertTrue(json.contains("\"score\":0.0"), json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void integerToBigDecimalSkeletonsLookDifferent() {
|
||||||
|
TypeSchema oldS = new TypeSchema("A");
|
||||||
|
oldS.add(new FieldSchema("amount", JsonType.NUMBER, "Integer"));
|
||||||
|
TypeSchema newS = new TypeSchema("A");
|
||||||
|
newS.add(new FieldSchema("amount", JsonType.NUMBER, "BigDecimal"));
|
||||||
|
|
||||||
|
SkeletonJsonRenderer renderer = new SkeletonJsonRenderer();
|
||||||
|
assertEquals("{\"amount\":0}", renderer.render(oldS));
|
||||||
|
assertEquals("{\"amount\":0.00}", renderer.render(newS));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user