2014-12-30 2 views
8

바이트 배열에 이진 인코딩해야하는 실제 JSON String이 있습니다. Apache Avro specification을 거친 후 아래 코드를 작성했습니다.avro 바이너리 인코딩 내 json 문자열을 바이트 배열로?

나는 이것이 올바른 방법인지 아닌지 잘 모르겠습니다. 누구든지 JSON 문자열이 맞는지 아닌지 알고 싶습니다. Apache Avro 1.7.7 버전을 사용하고 있습니다.

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 { 

     } 
    } 

} 

답변

11

적어도 효과가있는 것 같습니다. 그것은 단순화 될 수 있습니다 : 두 개 이상의 객체가 있으면 JSON이 유효하지 않으므로 루프가 쓸모 없습니다. 또한 스키마를 준비하여 불필요한 구문 분석을 피하는 것이 좋습니다.

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"); 
    } 
} 
: 여기

내 버전입니다
관련 문제