[
https://issues.apache.org/jira/browse/AVRO-2799?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Ryan Skraba updated AVRO-2799:
------------------------------
Summary: [Java] protobuf map types are not supported (was: Endless
recursive calls by using ProtobufDatumReader when decoding proto map)
> [Java] protobuf map types are not supported
> -------------------------------------------
>
> Key: AVRO-2799
> URL: https://issues.apache.org/jira/browse/AVRO-2799
> Project: Apache Avro
> Issue Type: Bug
> Components: java
> Affects Versions: 1.9.2
> Reporter: Allen Wang
> Priority: Major
>
> I have a protobuf message defined as this:
>
> {code:java}
> syntax = "proto3";
> package ExampleProtobuf;
> option java_package = "com.example";
> import "google/protobuf/any.proto";
> import "google/protobuf/timestamp.proto";
> import "google/protobuf/wrappers.proto";
> enum EventType {
> TYPE_UNKNOWN = 0;
> TYPE_ORDER_RECEIVED = 1;
> TYPE_PAYMENT_AUTHORIZED = 2;
> TYPE_PAYMENT_CAPTURED = 3;
> TYPE_ORDER_SUBMITTED = 4;
> TYPE_ORDER_DELIVERY_CREATED = 5;
> TYPE_MERCHANT_CONFIRM_ORDER = 6;
> }
> message RevenueEvent {
> google.protobuf.StringValue id = 1;
> EventType type = 2;
> google.protobuf.Timestamp change_time = 3;
> google.protobuf.StringValue country = 4;
> map <string, google.protobuf.Any> payload = 5;
> google.protobuf.StringValue source = 6;
> bool is_test = 7;
> google.protobuf.StringValue version = 8;
> google.protobuf.StringValue checksum = 9;
> }
> {code}
>
>
> I wrote a program to encode such Protobuf message with Avro schema and
> convert it back to Protobuf message:
>
>
> {code:java}
> public class EventTest {
> public static void main(String[] args) throws Exception {
> Example.RevenueEvent event = RevenueEvent.newBuilder()
> .setId(StringValue.newBuilder()
> .setValue("12345")
> .build())
> .setChangeTime(Timestamp.newBuilder()
> .setSeconds(System.currentTimeMillis())
> .build())
> .setChecksum(StringValue.newBuilder()
> .setValue("xyz")
> .build())
> .setCountry(StringValue.newBuilder()
> .setValue("US")
> .build())
> .setSource(StringValue.newBuilder()
> .setValue("unknown")
> .build())
> .setType(EventType.TYPE_MERCHANT_CONFIRM_ORDER)
> .putPayload("key",
> Any.newBuilder().setValue(ByteString.copyFromUtf8("xyz")).build())
> .build();
> ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
> Encoder encoder = EncoderFactory.get().directBinaryEncoder(outputStream,
> null);
> GenericDatumWriter<Example.RevenueEvent> datumWriter = new
> ProtobufDatumWriter<Example.RevenueEvent>(RevenueEvent.class);
> datumWriter.write(event, encoder);
> encoder.flush();
> byte[] bytes = outputStream.toByteArray();
> DatumReader<RevenueEvent> datumReader = new
> ProtobufDatumReader<>(RevenueEvent.class);
> InputStream inputStream = new ByteArrayInputStream(bytes);
> Decoder decoder = DecoderFactory.get().binaryDecoder(inputStream, null);
> datumReader.read(null, decoder);
> }
> }
> {code}
>
>
> The program crashed with java.lang.StackOverflowError:
>
> Exception in thread "main" java.lang.StackOverflowErrorException in thread
> "main" java.lang.StackOverflowError at
> java.base/java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
> at org.apache.avro.specific.SpecificData.getClass(SpecificData.java:250) at
> org.apache.avro.protobuf.ProtobufData.newRecord(ProtobufData.java:141) at
> org.apache.avro.protobuf.ProtobufData.newRecord(ProtobufData.java:143) at
> org.apache.avro.protobuf.ProtobufData.newRecord(ProtobufData.java:143) at
> org.apache.avro.protobuf.ProtobufData.newRecord(ProtobufData.java:143)
> ...
>
> Looking into ProtoData.java, there seems to be a situation where the
> recursion would not end:
>
> {code:java}
> @Override
> public Object newRecord(Object old, Schema schema) {
> try {
> Class c = SpecificData.get().getClass(schema);
> if (c == null)
> return newRecord(old, schema); // punt to generic <-- endless recursion
> if (c.isInstance(old))
> return old; // reuse instance
> return c.getMethod("newBuilder").invoke(null);
> } catch (Exception e) {
> throw new RuntimeException(e);
> }
> }
> {code}
> Further experiment shows that if the map payload is not set, the decoding
> would be successful.
>
> protobuf-java:3.8.0 is used.
>
--
This message was sent by Atlassian Jira
(v8.3.4#803005)