You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 15:02:03