Avro 和 java:字符串的反序列化映射不"equals"原始映射



我正在用一个由字符串和映射组成的简单记录测试Avro的java。下面是我的schema:

{
  "type":"record",
  "name":"TableRecord",
  "fields":[
    {"name":"ActionCode","type":"string"},
    {
      "name":"Fields",
      "type":{"type":"map","values":["string","long","double","null"]}
    }
  ]
}

这里有一个非常简单的失败的测试用例:

@Test
public void testSingleMapSerialization() throws IOException {
    final String schemaStr; // see above
    // create some data
    Map<String, Object> originalMap = new Hashtable<>();
    originalMap.put("Ric", "sZwmXAdYKv");
    originalMap.put("QuoteId", 4342740204922826921L);
    originalMap.put("CompanyName", "8PKQ9va3nW8pRWb4SjPF2DvdQDBmlZ");
    originalMap.put("Category", "AvrIfd");
    // serialize data
    Schema.Parser parser = new Schema.Parser();
    Schema schema = parser.parse(schemaStr);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    DatumWriter<GenericRecord> writer = new GenericDatumWriter<>(schema);
    Encoder encoder = EncoderFactory.get().binaryEncoder(out, null);
    GenericRecord datum = new GenericData.Record(schema);
    datum.put("ActionCode", "R");
    datum.put("Map", originalMap);
    writer.write(datum, encoder);
    encoder.flush();
    out.flush();
    // deserialize data
    DatumReader<GenericRecord> reader = new GenericDatumReader<>(schema);
    Decoder decoder = DecoderFactory.get().binaryDecoder(out.toByteArray(), null);
    datum = new GenericData.Record(schema);
    Map<String, Object> deserializedMap = (Map<String, Object>) reader.read(datum, decoder).get("Map");
    System.out.println(originalMap);
    System.out.println(deserializedMap);
    Assert.assertEquals("Maps data don't match", originalMap, deserializedMap);
}

下面是测试的输出:

{CompanyName=8PKQ9va3nW8pRWb4SjPF2DvdQDBmlZ, Ric=sZwmXAdYKv, Category=AvrIfd, QuoteId=4342740204922826921}
{QuoteId=4342740204922826921, Category=AvrIfd, CompanyName=8PKQ9va3nW8pRWb4SjPF2DvdQDBmlZ, Ric=sZwmXAdYKv}
java.lang.AssertionError: Maps data don't match expected:<{CompanyName=8PKQ9va3nW8pRWb4SjPF2DvdQDBmlZ, Ric=sZwmXAdYKv, Category=AvrIfd, QuoteId=4342740204922826921}> but was:<{QuoteId=4342740204922826921, Category=AvrIfd, CompanyName=8PKQ9va3nW8pRWb4SjPF2DvdQDBmlZ, Ric=sZwmXAdYKv}>

可以看到,两个映射看起来完全相同,但是测试失败了。JUnit在后台调用"equals"方法,该方法应该返回true。顺便说一句,如果你想知道什么是胡言乱语,我通常用随机生成的数据创建测试用例,所以这就是它的来源。

我做错了什么吗?字符串序列化/反序列化是否有我不知道的问题?我在网上搜索了,没有成功。

想法?

感谢

Giodude

我明白了"catch"是什么。我正在比较包含java.lang.String s和包含org.apache.avro.util.Utf8的映射。事实证明,Utf8 equals方法如果与字符串一起使用是不起作用的。我通过向测试用例中添加以下内容来实现这一点:

for (Object o : deserializedMap.values())
  System.out.println(o.getClass());
for (Object o : deserializedMap.keySet())
  System.out.println(o.getClass());

打印以下内容:

class java.lang.Long
class org.apache.avro.util.Utf8
class org.apache.avro.util.Utf8
class org.apache.avro.util.Utf8
class org.apache.avro.util.Utf8
class org.apache.avro.util.Utf8
class org.apache.avro.util.Utf8
class org.apache.avro.util.Utf8

我猜这是意料之中的,因为Avro总是将字符串转换为其原生Utf8类型。我以为它会按原样复制我的地图,但事实并非如此。奇怪的是,映射的类型转换成功了,我不清楚这是怎么发生的。

是的,Avro地图使用org.apache.avro.util。自1.5以来,Utf8作为默认键,并且可以更改为String。要了解更多细节,您可以参考:https://issues.apache.org/jira/browse/AVRO-803或Apache Avro: map使用CharSequence作为键

最新更新