feat: 修改字段类型修改不生效的问题
All checks were successful
序列化结构检查 / serialization-schema-check (push) Has been skipped

This commit is contained in:
2026-07-15 13:50:14 +08:00
parent fd5aab5e7f
commit 27dfeb8a4c
7 changed files with 285 additions and 35 deletions

View File

@@ -51,6 +51,57 @@ class SchemaDifferTest {
assertEquals(1, changes.size());
assertEquals(ChangeType.TYPE_CHANGED, changes.get(0).getChangeType());
assertEquals(Severity.P0, changes.get(0).getSeverity());
assertTrue(changes.get(0).getMessage().contains("String"));
assertTrue(changes.get(0).getMessage().contains("Integer"));
}
@Test
void detectsBigDecimalToStringEvenWhenBothWereStringBucketHistorically() {
// 即便 JsonType 同为 STRINGjavaType 变化也必须检出(用户真实漏报场景)
TypeSchema oldS = new TypeSchema("A");
oldS.add(new FieldSchema("amount", JsonType.STRING, "BigDecimal"));
TypeSchema newS = new TypeSchema("A");
newS.add(new FieldSchema("amount", JsonType.STRING, "String"));
List<SchemaChange> changes = new SchemaDiffer().diff(oldS, newS);
assertEquals(1, changes.size());
assertEquals(ChangeType.TYPE_CHANGED, changes.get(0).getChangeType());
assertEquals("amount", changes.get(0).getFieldPath());
assertTrue(changes.get(0).getOldValue().contains("BigDecimal"));
assertTrue(changes.get(0).getNewValue().contains("String"));
}
@Test
void detectsBigDecimalToStringViaJsonTypeAndJavaType() {
TypeSchema oldS = new TypeSchema("A");
oldS.add(new FieldSchema("amount", JsonType.NUMBER, "BigDecimal"));
TypeSchema newS = new TypeSchema("A");
newS.add(new FieldSchema("amount", JsonType.STRING, "String"));
List<SchemaChange> changes = new SchemaDiffer().diff(oldS, newS);
assertEquals(1, changes.size());
assertEquals(ChangeType.TYPE_CHANGED, changes.get(0).getChangeType());
}
@Test
void detectsIntegerToLongWithinNumberBucket() {
TypeSchema oldS = new TypeSchema("A");
oldS.add(new FieldSchema("id", JsonType.NUMBER, "Integer"));
TypeSchema newS = new TypeSchema("A");
newS.add(new FieldSchema("id", JsonType.NUMBER, "Long"));
List<SchemaChange> changes = new SchemaDiffer().diff(oldS, newS);
assertEquals(1, changes.size());
assertEquals(ChangeType.TYPE_CHANGED, changes.get(0).getChangeType());
}
@Test
void noChangeWhenPrimitiveAndWrapperEquivalent() {
TypeSchema a = new TypeSchema("A");
a.add(new FieldSchema("n", JsonType.NUMBER, "int"));
TypeSchema b = new TypeSchema("A");
b.add(new FieldSchema("n", JsonType.NUMBER, "Integer"));
assertTrue(new SchemaDiffer().diff(a, b).isEmpty());
}
@Test

View File

@@ -111,6 +111,57 @@ class ReportBuilderTest {
assertFalse(newMd.startsWith("`"));
}
@Test
void typeChangedHighlightedOrangeInBothSkeletons() {
SchemaChange typeChanged = new SchemaChange(ChangeType.TYPE_CHANGED);
typeChanged.setFieldPath("amount");
typeChanged.setOldValue("BigDecimal/NUMBER");
typeChanged.setNewValue("String/STRING");
typeChanged.setMessage("字段 amount 类型由 BigDecimal/NUMBER 变为 String/STRING");
String oldJson = "{\"amount\":0,\"name\":\"\"}";
String newJson = "{\"amount\":\"\",\"name\":\"\"}";
List<SchemaChange> details = Collections.singletonList(typeChanged);
Set<String> oldPaths = SkeletonAnnotator.pathsForOldSkeleton(details);
Set<String> newGreen = SkeletonAnnotator.pathsForNewSkeleton(details);
Set<String> newOrange = SkeletonAnnotator.pathsForTypeChanged(details);
assertEquals(Collections.singleton("amount"), oldPaths);
assertTrue(newGreen.isEmpty());
assertEquals(Collections.singleton("amount"), newOrange);
String oldMd = SkeletonAnnotator.annotateOldForWecom(oldJson, oldPaths);
String newMd = SkeletonAnnotator.annotateNewForWecom(newJson, newGreen, newOrange);
assertTrue(oldMd.contains("<font color=\"warning\">\"amount\":0</font>"));
assertFalse(oldMd.contains("<font color=\"warning\">\"name\":\"\"</font>"));
assertTrue(newMd.contains("<font color=\"warning\">\"amount\":\"\"</font>"));
assertFalse(newMd.contains("<font color=\"info\">\"amount\""));
assertFalse(newMd.contains("<font color=\"warning\">\"name\":\"\"</font>"));
CheckReport report = baseReport();
KeyStructureChange key = new KeyStructureChange();
key.setKeyPattern("cache:amount");
key.setWriteLocation("Demo#put:1");
key.setValueType("AmountVo");
key.setOldSkeletonJson(oldJson);
key.setNewSkeletonJson(newJson);
key.getFieldDetails().add(typeChanged);
report.getKeyChanges().add(key);
String md = new ReportBuilder("[序列化结构变更]").toMarkdown(report);
int oldSection = md.indexOf("> **value值由**");
int newSection = md.indexOf("> **变更为:**");
assertTrue(oldSection >= 0);
assertTrue(newSection > oldSection);
String oldPart = md.substring(oldSection, newSection);
String newPart = md.substring(newSection);
assertTrue(oldPart.contains("<font color=\"warning\">\"amount\":0</font>"));
assertTrue(newPart.contains("<font color=\"warning\">\"amount\":\"\"</font>"));
assertFalse(newPart.contains("<font color=\"info\">\"amount\""));
}
@Test
void consoleContainsFieldDetailsAndWecomMarkdown() {
CheckReport report = new CheckReport();

View File

@@ -81,4 +81,21 @@ class JavaSchemaExtractorTest {
assertTrue(AnnotationSupport.ignoredProperties(type).contains("a"));
assertTrue(AnnotationSupport.ignoredProperties(type).contains("b"));
}
@Test
void bigDecimalMappedAsNumberNotString() {
String source = ""
+ "package demo;\n"
+ "import java.math.BigDecimal;\n"
+ "public class MoneyVo {\n"
+ " private BigDecimal amount;\n"
+ " private String currency;\n"
+ "}\n";
SourceIndex index = new SourceIndex();
index.addSource(source);
TypeSchema schema = new JavaSchemaExtractor(index, 8).extract("demo.MoneyVo");
assertEquals(JsonType.NUMBER, schema.getFields().get("amount").getJsonType());
assertEquals("BigDecimal", schema.getFields().get("amount").getJavaType());
assertEquals(JsonType.STRING, schema.getFields().get("currency").getJsonType());
}
}