简体   繁体   English

序列化 avro 生成的 object 到 json 时出现 JsonMappingException

[英]JsonMappingException when serializing avro generated object to json

I used avro-tools to generate java classes from avsc files, using:我使用 avro-tools 从 avsc 文件生成 java 类,使用:

java.exe -jar avro-tools-1.7.7.jar compile -string schema myfile.avsc 

Then I tried to serialize such objects to json by ObjectMapper, but always got a JsonMappingException saying "not an enum" or "not a union".然后我尝试通过 ObjectMapper 将这些对象序列化为 json,但总是得到一个 JsonMappingException 说“不是枚举”或“不是联合”。 In my test I create the generated object using it's builder or constructor.在我的测试中,我使用它的构建器或构造器创建了生成的 object。 I got such exceptions for objects of different classes...我对不同类的对象有这样的例外......

Sample Code:示例代码:

ObjectMapper serializer = new ObjectMapper(); // com.fasterxml.jackson.databind
serializer.register(new JtsModule()); // com.bedatadriven.jackson.datatype.jts
...
return serializer.writeValueAsBytes(avroConvertedObject); // => JsonMappingException

I also tried many configurations using: serializer.configure(...) but still failed.我还尝试了许多配置: serializer.configure(...) 但仍然失败。 Versions: Java 1.8, jackson-datatype-jts 2.3, jackson-core 2.6.5, jackson-databind 2.6.5, jackson-annotations 2.6.5版本: Java 1.8,jackson-datatype-jts 2.3,jackson-core 2.6.5,jackson-databind 2.6.5,jackson-annotations 2.6.5

Any suggestions?有什么建议么? Thanks!谢谢!

If the SCHEMA member is really the case (we don't see the full error message), then you can switch it off.如果SCHEMA成员确实如此(我们没有看到完整的错误消息),那么您可以将其关闭。 I use a mixin to do it, like this:我使用 mixin 来做到这一点,就像这样:

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.apache.avro.Schema;
import org.junit.Test;

import java.io.File;
import java.io.IOException;

public class AvroGenerTests
{
  abstract class IgnoreSchemaProperty
  {
    // You have to use the correct package for JsonIgnore,
    // fasterxml or codehaus
    @JsonIgnore abstract void getSchema();
  }

  @Test
  public void writeJson() throws IOException {
    BookAvro b = BookAvro.newBuilder()
      .setTitle("Wilk stepowy")
      .setAuthor("Herman Hesse")
      .build();
    ObjectMapper om = new ObjectMapper();
    om.enable(SerializationFeature.INDENT_OUTPUT);
    om.addMixIn(BookAvro.class, IgnoreSchemaProperty.class);
    om.writeValue(new File("plik_z_gen.json"), b);
  }
}

The previous post answers the question correctly.上一篇文章正确回答了这个问题。 I am just adding on to the previous answer.我只是补充上一个答案。 Instead of writing it to a file I converted it to a string before sending it as body in a POST request.我没有将其写入文件,而是在将其作为 POST 请求中的正文发送之前将其转换为字符串。

public class AvroGenerateJSON
{
  abstract class IgnoreSchemaProperty
  {
    // You have to use the correct package for JsonIgnore,
    // fasterxml or codehaus
    @JsonIgnore abstract void getSchema();
  }

  public String convertToJson() throws IOException {
    BookAvro b = BookAvro.newBuilder()
      .setTitle("Wilk stepowy")
      .setAuthor("Herman Hesse")
      .build();
    ObjectMapper om = new ObjectMapper();
    om.enable(SerializationFeature.INDENT_OUTPUT);
    om.addMixIn(BookAvro.class, IgnoreSchemaProperty.class);
    String jsonString = om.writeValueAsString(b);
    return jsonString;
  }
}

After finding the code example at https://www.programcreek.com/java-api-examples/?api=org.apache.avro.io.JsonEncoder I wrote a method that should convert any given Avro object (they extend GenericRecord) to a Json String.https://www.programcreek.com/java-api-examples/?api=org.apache.avro.io.JsonEncoder找到代码示例后,我编写了一个方法来转换任何给定的 Avro 对象(它们扩展了 GenericRecord)到一个 Json 字符串。 Code:代码:

import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.io.JsonEncoder;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;

// ... Class header etc. ...

public static <T extends GenericRecord> String convertToJsonString(T event) throws IOException {

    String jsonstring = "";

    try {
        DatumWriter<T> writer = new GenericDatumWriter<T>(event.getSchema());
        OutputStream out = new ByteArrayOutputStream();
        JsonEncoder encoder = EncoderFactory.get().jsonEncoder(event.getSchema(), out);
        writer.write(event, encoder);
        encoder.flush();
        jsonstring = out.toString();
    } catch (IOException e) {
        log.error("IOException occurred.", e);
        throw e;
    }

    return jsonstring;
}

My req'ts got changed on me and I was told I needed to convert Avro objects straight to JSON without preserving any of the meta-data.我的要求发生了变化,有人告诉我需要将 Avro 对象直接转换为 JSON,而不保留任何元数据。 My other answer herein that specified a method convertToJsonString converts the entire Avro object to JSON so that using a de-encoder you can re-create the original Avro object as an Avro object.我在此处指定了一个方法 convertToJsonString 的另一个答案将整个 Avro 对象转换为 JSON,以便使用解码器可以将原始 Avro 对象重新创建为 Avro 对象。 That isn't what my mgt.那不是我的mgt。 wanted anymore so I was back to the old drawing board.不再想要了,所以我又回到了旧的绘图板。

As a Hail Mary pass I tried using Gson and it works to do what I now had to do.作为 Hail Mary 通行证,我尝试使用 Gson,它可以完成我现在必须做的事情。 It's very simple:这很简单:

 Gson gson = new Gson();
 String theJsonString = gson.toJson(object_ur_converting);

And you're done.你已经完成了。

Agree with Shivansh's answer.同意 Shivansh 的回答。 To add, there might be instances where we need to use the avro-generated pojo in other classes.另外,在某些情况下,我们可能需要在其他类中使用 avro 生成的 pojo。 Under the hood, spring uses jackson library in handling this so we need to override global jackson config by adding a class在底层,spring 使用 jackson 库来处理这个问题,所以我们需要通过添加一个类来覆盖全局 jackson 配置

@Configuration
public class JacksonConfiguration {
    public abstract IgnoreSchemaProperty {
          @JsonIgnore abstract void getSchema();
    }
    @Bean
    public ObjectMapper objectMapper() {
          ObjectMapper om = new ObjectMapper();
          om.addMixIn(SpecificRecordBase.class, IgnoreSchemaProperty.class);
          return om;
    }
}

SpecificRecordBase -if we want to ignore the schema field from all avro generated classes. SpecificRecordBase - 如果我们想从所有 avro 生成的类中忽略模式字段。 In this way, we can serialize/deserialize our avro classes and use it anywhere in our application without getting the issue.通过这种方式,我们可以序列化/反序列化我们的 avro 类并在我们的应用程序中的任何地方使用它而不会出现问题。

2022 Avro field names 2022 Avro 字段名称

abstract class IgnoreSchemaPropertyConfig {
   // You have to use the correct package for JsonIgnore,
   // fasterxml or codehaus
   @JsonIgnore
   abstract void getClassSchema();

   @JsonIgnore
   abstract void getSpecificData();

   @JsonIgnore
   abstract void get();

   @JsonIgnore
   abstract void getSchema();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM