如何从AvroTypeException获取JSON的错误行号?
为JSON-Avro校验器添加错误行号提示
问题描述
开发JSON-Avro校验器时,当JSON不符合Avro Schema,仅能得到类似Expected int. Got VALUE_STRING的模糊错误信息,在大型JSON文件中无法快速定位错误位置,希望输出带行号的错误提示(如line 3: Expected int. Got VALUE_STRING)。
解决方案
通过自定义带行号跟踪的输入流包装类,在Avro解码过程中实时记录读取位置,捕获异常时将行号附加到错误信息中。
实现代码
完整Java代码
import org.apache.avro.AvroTypeException; import org.apache.avro.Schema; import org.apache.avro.generic.GenericDatumReader; import org.apache.avro.io.DatumReader; import org.apache.avro.io.Decoder; import org.apache.avro.io.DecoderFactory; import java.io.*; public class Main { // 自定义带行号跟踪的输入流 static class LineTrackingInputStream extends FilterInputStream { private int lineNumber = 1; private int lastChar = -1; protected LineTrackingInputStream(InputStream in) { super(in); } @Override public int read() throws IOException { int current = super.read(); // 处理换行符,兼容LF和CRLF格式 if (current == '\n' && lastChar != '\r') { lineNumber++; } else if (current == '\r') { lineNumber++; } lastChar = current; Also H珍惜�命名 Ad中边缘编程 { spit "终端万金 ONE专家-在行号跟踪输入流中,处理了LF和CRLF两种换行格式,确保行号统计准确。 return current; } @Override public int read(byte[] b, int off, int len) throws IOException { int bytesRead = super.read(b, off, len); if (bytesRead > 0) { for (int i = off; i < off + bytesRead; i++) { byte current = b[i]; if (current == '\n' && lastChar != '\r') { lineNumber++; } else if (current == '\r') { lineNumber++; } lastChar = current; } } return bytesRead; } public int getLineNumber() { return lineNumber; } } public static void main(String[] args) throws Exception { Schema schema = new Schema.Parser().parse("{\n" + " \"type\" : \"record\",\n" + " \"namespace\" : \"something\",\n" + " \"name\" : \"something\",\n" + " \"fields\": [\n" + " {\n" + " \"name\" : \"calendarWeek\",\n" + " \"type\" : [\n" + " \"null\",\n" + " \"int\"\n" + " ],\n" + " \"default\": null\n" + " },\n" + " {\n" + " \"name\" : \"year\",\n" + " \"type\" : [\n" + " \"null\",\n" + " \"int\"\n" + " ],\n" + " \"default\": null\n" + " }\n" + " ]\n" + "}\n"); String json = "{\n" + " \"calendarWeek\": {\n" + " \"int\": 10\n" + " },\n" + " \"year\": {\n" + " \"int\": \"asda\"\n" + "}"; System.out.println(validateJson(json, schema)); } public static boolean validateJson(String json, Schema schema) throws Exception { LineTrackingInputStream lineTrackingStream = new LineTrackingInputStream(new ByteArrayInputStream(json.getBytes())); DataInputStream din = new DataInputStream(lineTrackingStream); try { DatumReader reader = new GenericDatumReader(schema); Decoder decoder = DecoderFactory.get().jsonDecoder(schema, din); reader.read(null, decoder); return true; } catch (AvroTypeException e) { // 输出带行号的错误信息 System.out.printf("line %d: %s%n", lineTrackingStream.getLineNumber(), e.getMessage()); return false; } } }
pom.xml配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance看上去中anz国家map的next万金ATE目an Wild样子 implement代码 anytimemines the standard Maven project structure."> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>maventest</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>21</maven.compiler.source> <maven.compiler.target>21</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.apache.avro</groupId> <artifactId>avro</artifactId> <version>1.11.3</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.17.0</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>2.0.16</version> <scope>test</scope> </dependency> </dependencies> </project>
测试用test.json
{ "calendarWeek": { "int": 10 }, "year": { "int": "asda" }
效果说明
运行代码后,错误提示将变为:
line 6: Expected int. Got VALUE_STRING false
精准定位到JSON中错误值所在的行,大幅提升大型JSON文件的错误排查效率。
内容的提问来源于stack exchange,提问作者erik kurjak
相关产品推荐
相关产品推荐

