将对象转换为 JSON 字符串时发生 JsonMappingException - org.apache.avro.AvroRuntimeException:不是数组:

Nic*_*las 7 java json jackson json-deserialization objectmapper

在将 Java 对象转换为 JSON 字符串时,我遇到了 JsonMappingException。以下是完整的异常消息。

com.fasterxml.jackson.databind.JsonMappingException: Not an array: {"type":"record","name":"ClearingSystemMemberIdentification2","namespace":"com.sam.eps.paymentdomain.avro.pacs002","doc":"Schema for com.sam.eps.iso.pacs002.ClearingSystemMemberIdentification2","fields":[{"name":"clearing_system_identification","type":["null",{"type":"record","name":"ClearingSystemIdentification2Choice","doc":"Schema for com.sam.eps.iso.pacs002.ClearingSystemIdentification2Choice","fields":[{"name":"code","type":["null",{"type":"string","avro.java.string":"String"}],"default":null},{"name":"proprietary","type":["null",{"type":"string","avro.java.string":"String"}],"default":null}]}],"default":null},{"name":"member_identification","type":["null",{"type":"string","avro.java.string":"String"}],"default":null}]} (through reference chain: com.sam.eps.paymentdomain.avro.pacs002.Document["fi_to_fi_payment_status_report"]->com.sam.eps.paymentdomain.avro.pacs002.FIToFIPaymentStatusReportV10["group_header"]->com.sam.eps.paymentdomain.avro.pacs002.GroupHeader91["instructed_agent"]->com.sam.eps.paymentdomain.avro.pacs002.BranchAndFinancialInstitutionIdentification6["financial_institution_identification"]->com.sam.eps.paymentdomain.avro.pacs002.FinancialInstitutionIdentification18["clearing_system_member_identification"]->com.sam.eps.paymentdomain.avro.pacs002.ClearingSystemMemberIdentification2["schema"]->org.apache.avro.Schema$RecordSchema["elementType"])
Run Code Online (Sandbox Code Playgroud)

下面是我用来将 Java 对象转换为 JSON 字符串的 java 代码。我尝试启用 ACCEPT_SINGLE_VALUE_AS_ARRAY、ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT 但仍然面临问题。不确定导致JsonMappingException 的原因:不是数组问题。

private String convertObjectToJson(Object request) throws JsonProcessingException {

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(OffsetDateTime.class, new JsonSerializer<OffsetDateTime>() {
            @Override
            public void serialize(OffsetDateTime offsetDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                jsonGenerator.writeString(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(offsetDateTime));
            }
        });
        simpleModule.addSerializer(LocalDate.class, new JsonSerializer<LocalDate>() {
            @Override
            public void serialize(LocalDate localDate, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                jsonGenerator.writeString(DateTimeFormatter.ISO_LOCAL_DATE.format(localDate));
            }
        });
        objectMapper.registerModule(simpleModule);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
        objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        return objectMapper.writeValueAsString(request);
    }
Run Code Online (Sandbox Code Playgroud)

sap*_*ati 9

当您使用 Avro 编译器从 Avro 模式自动生成 POJO 时,就会出现此问题。此自动生成的 POJO 包含以下额外字段等(除了用户在 Avro 架构中指定的字段)

public static final org.apache.avro.Schema SCHEMA$;
Run Code Online (Sandbox Code Playgroud)

由于 Avro API 中的一些错误,该Schema.getElementType()方法在序列化期间导致Not an array异常。下面是方法定义

 public Schema getElementType() {
    throw new AvroRuntimeException("Not an array: " + this);
  }
Run Code Online (Sandbox Code Playgroud)

要解决此问题,只需在序列化期间忽略自动生成的 POJO 中的 SCHEMA$ 字段,如下所示

// create this class to ignore one or more fields
public abstract class IgnoreSchemaProperty
{
    @JsonIgnore
    abstract void getSchema();
}

public class Test{
    public static void main(String args[]) {
        ObjectMapper objectMapper=new ObjectMapper();
        //pass the above created class in the mixIn
        objectMapper.addMixIn(YourPojo.class, IgnoreSchemaProperty.class);
        String pojoJson = objectMapper.writeValueAsString(YourPojo);
        System.out.println(pojoJson);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!在测试我的 Spring Rest 控制器时遇到了同样的问题,该控制器使用我的 avro 自动生成的类作为 JSON 进行响应。只需添加您提到的“IgnoreSchemaProperty”类,并使用“.addMixIn(SpecificRecordBase::class.java, IgnoreSchemaProperty::class.java)”删除修改后的“ObjectMapper”(提示:适用于我刚刚生成的所有类)使用接口“SpecificRecordBase”代替) (2认同)

Kje*_*eld 3

Jackson 转换过程递归地评估对象的每个字段或 getter,因此它可以创建 JSON 节点。

您可能正在此处转换生成的 AVRO 类型。它包含一个名为 的字段$SCHEMA,该字段本身没有名为 已getElementType()实现的方法。默认方法显式getElementType()抛出org.apache.avro.Schema此异常。由于 Jackson 在转换过程中遇到了这个方法,因此抛出了异常。

getElementType()只是该 Schema 类中默认抛出异常的许多默认实现之一。我认为没有任何办法可以解决这个问题,除了不使用 Jackson 创建 JSON,而是使用最初创建 AVRO 类型的相同 API。

编辑:也许您可以向映射器注册JsonSerializer<Schema>,并自己自定义架构的序列化。