2013-03-28 82 views
2

我正在用一個由字符串和映射組成的簡單記錄測試Avro for java。這裏是我的架構:Avro和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

我不這麼認爲。試着創建兩個具有相同內容的哈希表並對它們進行比較。你會成真的。下面是java.util.Map的equals方法的javadoc: 「將指定對象與此映射進行比較以獲得相等性。如果給定對象也是映射並且這兩個映射表示相同的映射,則返回true。更正式地,如果m1.entrySet()。equals(m2.entrySet()),則映射m1和m2表示相同的映射。這確保了equals方法在Map接口的不同實現之間正常工作。 –

+0

由於entrySet()返回一個Set,下面是Set的equals方法的javadoc: 「將指定對象與此集合相比較,如果指定對象也是一個集合,則返回true,這兩個集合具有相同的大小,並且指定集合中的每個成員都包含在該集合中(或者等價地,該集合中的每個成員都包含在指定集合中)。此定義確保equals方法在集合接口的不同實現之間正常工作。 –

+0

你能逐個查看地圖的入口集,看看哪一個失敗了嗎? –

回答

2

我想通了什麼 「捕捉」 了。我正在比較一個包含java.lang.String s的地圖和一個包含org.apache.avro.util.Utf8的地圖。事實證明,如果使用字符串,則Utf8等於方法不起作用。我意識到這一點,加入到我的測試情況如下:

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的類型成功了,這很奇怪,我不清楚發生了什麼。

+0

投射到Map 會忽略模板參數,因爲該信息在運行時不可用。編譯器應該能夠給你一個警告。 –