2017-06-17 149 views
0

目前我正在使用Avro 1.8.0來序列化/反序列化對象,但是面臨的問題尤其是java.util.Map對象。不面臨與其他類型的對象的問題。Avro Map序列化/反序列化問題

樣品這裏的代碼 -

class AvroUtils { 

    public byte[] serialize(Object payload) { 
     final ByteArrayOutputStream out = new ByteArrayOutputStream(); 
     Schema schema = new ReflectDatumWriter().getData().induce(payload); //---> getting proper map schema as {"type":"map","values":"string"} 
     JsonEncoder jsonEncoder = EncoderFactory.get().jsonEncoder(schema, out); 
     final GenericDatumWriter<Object> writer = new GenericDatumWriter(schema); 
     writer.write(payload, jsonEncoder); 
     jsonEncoder.flush(); 
     return out.toByteArray(); 
    } 

    public <R> R deserialize(Object o, Class<R> aClass) { 
     Schema schema = new ReflectDatumWriter().getData().induce(o); //------> getting error - unable to get schema 
     final ByteArrayInputStream bin = new ByteArrayInputStream((byte[]) o); 
     JsonDecoder jsonDecoder = DecoderFactory.get().jsonDecoder(schema, bin); 
     final GenericDatumReader<R> reader = new GenericDatumReader<>(schema); 
     return reader.read(null, jsonDecoder); 
    } 

    public static void main(String[] args) { 
     Map<String, Object> map = new HashMap<String, Object>(); 
     map.put("Key1", "Value1"); 
     map.put("Key2", "Value2"); 

     // Serialization 
     byte[] result = this.serialize(map); 
     System.out.println("Serialized Data : " + new String(mapDes, "UTF-8")); 

     // Deserialization 
     Map<String, Object> mapDes = (Map<String, Object>) this.deserialize(result, Map.class); 
     System.out.println("Deserialized Data : " + mapDes); 
    } 
} 

在反序列化方法,我試圖讓基於輸入數據,但Avro的模式拋出錯誤 -

`Exception in thread "main" java.lang.ClassCastException: [B cannot be cast to java.util.Collection 
at org.apache.avro.reflect.ReflectData.getArrayAsCollection(ReflectData.java:196) 
at org.apache.avro.generic.GenericData.induce(GenericData.java:612)` 

注:在結束這兩種方法將被放置在不同的庫中(avro-serializer/avro-deserializer)。

請建議在反序列化方法中獲取模式的最佳方法。

謝謝。

回答

0

你得到java.lang.ClassCastException: [B cannot be cast to java.util.Collection因爲你試圖調用induce()方法與對象是字節數組,但不是一個地圖。

如果你想序列化映射在一個地方,在其他反序列化,你可以使用一個更好的辦法:

Schema schema = Schema.createMap(Schema.create(Schema.Type.STRING)); 

如果你這樣做,你就不需要在desirialize方法的其他任何參數。

此外,GenericDatumWriter只能用於通用記錄,因此您需要ReflectDatumWriter

這裏是你的代碼的變化在於一個例子:

public class AvroUtils { 

    public static byte[] serialize(Object payload) throws IOException { 
     final ByteArrayOutputStream out = new ByteArrayOutputStream(); 
     Schema schema = Schema.createMap(Schema.create(Schema.Type.STRING)); //---> getting proper map schema as {"type":"map","values":"string"} 
     JsonEncoder jsonEncoder = EncoderFactory.get().jsonEncoder(schema, out); 
     final DatumWriter<Object> writer = new ReflectDatumWriter<>(schema); 
     writer.write(payload, jsonEncoder); 
     jsonEncoder.flush(); 
     return out.toByteArray(); 
    } 

    public static <R> R deserialize(Object o) throws IOException { 
     Schema schema = Schema.createMap(Schema.create(Schema.Type.STRING)); 
     JsonDecoder jsonDecoder = DecoderFactory.get().jsonDecoder(schema, new ByteArrayInputStream((byte[]) o)); 
     final DatumReader<R> reader = new ReflectDatumReader<>(schema); 
     return reader.read(null, jsonDecoder); 
    } 

    public static void main(String[] args) throws IOException { 
     Map<String, Object> map = new HashMap<>(); 
     map.put("Key1", "Value1"); 
     map.put("Key2", "Value2"); 

     // Serialization 
     byte[] result = serialize(map); 

     // Deserialization 
     Map<String, Object> mapDes = deserialize(result); 
     System.out.println("Deserialized Data : " + mapDes); 
    } 
} 

結果,你會得到這樣的事情:

Deserialized Data : {Key2=Value2, Key1=Value1}