我正在使用由字符串和地图组成的简单记录来测试Avro for java。这是我的架构:
{
"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
答案 0 :(得分:3)
我弄清楚了什么是“捕获”。我正在比较包含java.lang.String
的地图和包含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
类型。我以为它会按原样重现我的地图,但事实并非如此。奇怪的是,对Map的类型转换成功,我不清楚这是怎么发生的。
答案 1 :(得分:1)
是的,Avro map使用org.apache.avro.util.Utf8作为1.5以来的默认密钥,可以更改为String。有关详细信息,请参阅:https://issues.apache.org/jira/browse/AVRO-803或Apache Avro: map uses CharSequence as key