2014-12-30 1 views
8

Ich habe eine tatsächliche JSON-Zeichenfolge, die ich avro binäre Codierung zu einem Byte-Array benötigen. Nachdem ich die Apache Avro specification durchgegangen bin, kam ich auf den folgenden Code.Wie avro binäre Codierung meiner JSON-Zeichenfolge zu einem Byte-Array?

Ich bin mir nicht sicher, ob dies der richtige Weg ist oder nicht. Kann jemand mal schauen ob die Art und Weise wie ich versuche den binären AVR Code meines JSON String zu kodieren richtig ist oder nicht ?. Ich benutze Apache Avro 1.7.7 Version.

public class AvroTest { 

    private static final String json = "{" + "\"name\":\"Frank\"," + "\"age\":47" + "}"; 
    private static final String schema = "{ \"type\":\"record\", \"namespace\":\"foo\", \"name\":\"Person\", \"fields\":[ { \"name\":\"name\", \"type\":\"string\" }, { \"name\":\"age\", \"type\":\"int\" } ] }"; 

    public static void main(String[] args) throws IOException { 
     byte[] data = jsonToAvro(json, schema); 

     String jsonString = avroToJson(data, schema); 
     System.out.println(jsonString); 
    } 

    /** 
    * Convert JSON to avro binary array. 
    * 
    * @param json 
    * @param schemaStr 
    * @return 
    * @throws IOException 
    */ 
    public static byte[] jsonToAvro(String json, String schemaStr) throws IOException { 
     InputStream input = null; 
     GenericDatumWriter<Object> writer = null; 
     Encoder encoder = null; 
     ByteArrayOutputStream output = null; 
     try { 
      Schema schema = new Schema.Parser().parse(schemaStr); 
      DatumReader<Object> reader = new GenericDatumReader<Object>(schema); 
      input = new ByteArrayInputStream(json.getBytes()); 
      output = new ByteArrayOutputStream(); 
      DataInputStream din = new DataInputStream(input); 
      writer = new GenericDatumWriter<Object>(schema); 
      Decoder decoder = DecoderFactory.get().jsonDecoder(schema, din); 
      encoder = EncoderFactory.get().binaryEncoder(output, null); 
      Object datum; 
      while (true) { 
       try { 
        datum = reader.read(null, decoder); 
       } catch (EOFException eofe) { 
        break; 
       } 
       writer.write(datum, encoder); 
      } 
      encoder.flush(); 
      return output.toByteArray(); 
     } finally { 
      try { 
       input.close(); 
      } catch (Exception e) { 
      } 
     } 
    } 

    /** 
    * Convert Avro binary byte array back to JSON String. 
    * 
    * @param avro 
    * @param schemaStr 
    * @return 
    * @throws IOException 
    */ 
    public static String avroToJson(byte[] avro, String schemaStr) throws IOException { 
     boolean pretty = false; 
     GenericDatumReader<Object> reader = null; 
     JsonEncoder encoder = null; 
     ByteArrayOutputStream output = null; 
     try { 
      Schema schema = new Schema.Parser().parse(schemaStr); 
      reader = new GenericDatumReader<Object>(schema); 
      InputStream input = new ByteArrayInputStream(avro); 
      output = new ByteArrayOutputStream(); 
      DatumWriter<Object> writer = new GenericDatumWriter<Object>(schema); 
      encoder = EncoderFactory.get().jsonEncoder(schema, output, pretty); 
      Decoder decoder = DecoderFactory.get().binaryDecoder(input, null); 
      Object datum; 
      while (true) { 
       try { 
        datum = reader.read(null, decoder); 
       } catch (EOFException eofe) { 
        break; 
       } 
       writer.write(datum, encoder); 
      } 
      encoder.flush(); 
      output.flush(); 
      return new String(output.toByteArray()); 
     } finally { 

     } 
    } 

} 

Antwort

11

Es scheint zumindest zu funktionieren. Es kann jedoch vereinfacht werden: Die Schleifen sind nutzlos, da mehr als ein Objekt zu ungültigem JSON führen würde. Es könnte auch eine gute Idee sein, unnötiges Parsen des Schemas durch Vorbereiten zu vermeiden.

Hier ist meine Version:

public class AvroTest { 

    private static final String JSON = "{" + "\"name\":\"Frank\"," + "\"age\":47" + "}"; 
    private static final Schema SCHEMA = new Schema.Parser().parse("{ \"type\":\"record\", \"namespace\":\"foo\", \"name\":\"Person\", \"fields\":[ { \"name\":\"name\", \"type\":\"string\" }, { \"name\":\"age\", \"type\":\"int\" } ] }"); 

    public static void main(String[] args) throws IOException { 
     byte[] data = jsonToAvro(JSON, SCHEMA); 

     String jsonString = avroToJson(data, SCHEMA); 
     System.out.println(jsonString); 
    } 

    /** 
    * Convert JSON to avro binary array. 
    * 
    * @param json 
    * @param schema 
    * @return 
    * @throws IOException 
    */ 
    public static byte[] jsonToAvro(String json, Schema schema) throws IOException { 
     DatumReader<Object> reader = new GenericDatumReader<>(schema); 
     GenericDatumWriter<Object> writer = new GenericDatumWriter<>(schema); 
     ByteArrayOutputStream output = new ByteArrayOutputStream(); 
     Decoder decoder = DecoderFactory.get().jsonDecoder(schema, json); 
     Encoder encoder = EncoderFactory.get().binaryEncoder(output, null); 
     Object datum = reader.read(null, decoder); 
     writer.write(datum, encoder); 
     encoder.flush(); 
     return output.toByteArray(); 
    } 

    /** 
    * Convert Avro binary byte array back to JSON String. 
    * 
    * @param avro 
    * @param schema 
    * @return 
    * @throws IOException 
    */ 
    public static String avroToJson(byte[] avro, Schema schema) throws IOException { 
     boolean pretty = false; 
     GenericDatumReader<Object> reader = new GenericDatumReader<>(schema); 
     DatumWriter<Object> writer = new GenericDatumWriter<>(schema); 
     ByteArrayOutputStream output = new ByteArrayOutputStream(); 
     JsonEncoder encoder = EncoderFactory.get().jsonEncoder(schema, output, pretty); 
     Decoder decoder = DecoderFactory.get().binaryDecoder(avro, null); 
     Object datum = reader.read(null, decoder); 
     writer.write(datum, encoder); 
     encoder.flush(); 
     output.flush(); 
     return new String(output.toByteArray(), "UTF-8"); 
    } 
}