2011-09-04 2 views
5

double 값 배열을 갖는 복잡한 Map 구조를 인코딩합니다. 고정밀도가 중요하지 않고 출력 크기가 있으므로 제공된 DecimalFormat을 사용하여 double 값을 직렬화하기 위해 JSON 도구 (이 경우 Jackson)를 얻으려고합니다.jackson-json 제어 된 정밀도를 가진 double의 인코딩

다음은 내 최선이지만, 시리얼 라이저는 배열 인코딩하는 객체 매퍼에 의해 포착되지 않는이 실패

class MyTest 
{ 
    public class MyDoubleSerializer extends JsonSerializer<double[]> 
    { 
    public void serialize(double[] value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException 
    { 
     for (double d : value) 
     { 
     jgen.writeStartArray(); 
     jgen.writeRaw(df.format(d)); 
     jgen.writeEndArray(); 
     } 
    } 
    } 

    @Test 
    public void test1() throws Exception 
    { 
    ObjectMapper mapper = new ObjectMapper(); 
    SimpleModule module = new SimpleModule("MyModule", new Version(0, 1, 0, "alpha")); 
    module.addSerializer(double[].class, new MyDoubleSerializer()); 
    mapper.registerModule(module); 

    Map<String, Object> data = new HashMap<String, Object>(); 
    double[] doubleList = { 1.1111111111D, (double) (System.currentTimeMillis()) }; 
    data.put("test", doubleList); 
    System.out.print(mapper.writeValueAsString(data)); 
    } 
} 

출력은을 :

{ "테스트" [1.1111111111,1.315143204964E12}

내가 찾던 :

{ "테스트": [1.32E12, 1.11E0]}

어떤 아이디어가?

또한 String을 생성하지 않고 원시 코드로 작성하는 것을 좋아하지 않습니다. 거기에 DecimalFormat에 StringBuffer를 공급할 수 있습니까?

감사

답변

4

은 차용하여이 문제를 해결하기 위해 관리 내장 번에 시리얼.

writeRaw()가 컨텍스트를 신경 쓰지 않고 배열 멤버 사이에 쉼표를 쓰지 않기 때문에 Json writer를 캐스팅하고 writeValue() 메서드를 호출하여 처리 할 수 ​​있기 때문에 약간의 해킹입니다. 이.

이상하게도이 질문에있는 예제에서는 작동하지 않지만 (이 두 가지를 직렬화하기 위해 다시 호출되지는 않음) 더 복잡한 실제 객체에서 작동합니다.

는 ... 즐겨

public class JacksonDoubleArrayTest 
{ 
    private DecimalFormat df = new DecimalFormat("0.##E0"); 

    public class MyDoubleSerializer extends org.codehaus.jackson.map.ser.ScalarSerializerBase<Double> 
    { 
     protected MyDoubleSerializer() 
     { 
      super(Double.class); 
     } 

     @Override 
     public final void serializeWithType(Double value, JsonGenerator jgen, SerializerProvider provider, TypeSerializer typeSer) throws IOException, 
       JsonGenerationException 
     { 
      serialize(value, jgen, provider); 
     } 

     @Override 
     public void serialize(Double value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException 
     { 
      if (Double.isNaN(value) || Double.isInfinite(value)) 
      { 
       jgen.writeNumber(0); // For lack of a better alternative in JSON 
       return; 
      } 

      String x = df.format(value); 
      if (x.endsWith("E0")) 
      { 
       x = x.substring(0, x.length() - 2); 
      } 
      else if (x.endsWith("E1") && x.length() == 6) 
      { 
       x = "" + x.charAt(0) + x.charAt(2) + '.' + x.charAt(3); 
      } 
      JsonWriteContext ctx = (JsonWriteContext)jgen.getOutputContext(); 
      ctx.writeValue(); 
      if (jgen.getOutputContext().getCurrentIndex() > 0) 
      { 
       x = "," + x; 
      } 
      jgen.writeRaw(x); 
     } 

     @Override 
     public JsonNode getSchema(SerializerProvider provider, Type typeHint) 
     { 
      return createSchemaNode("number", true); 
     } 
    } 

    @SuppressWarnings("unchecked") 
    private static Map<String, Object> load() throws JsonParseException, JsonMappingException, IOException 
    { 
     ObjectMapper loader = new ObjectMapper(); 
     return (Map<String, Object>)loader.readValue(new File("x.json"), Map.class); 
    } 

    @Test 
    public void test1() throws JsonGenerationException, JsonMappingException, IOException 
    { 
     ObjectMapper mapper = new ObjectMapper(); 
     SimpleModule module = new SimpleModule("StatsModule", new Version(0, 1, 0, "alpha")); 
     module.addSerializer(Double.class, new MyDoubleSerializer()); 
     mapper.registerModule(module); 
     String out = mapper.writeValueAsString(load()); 
     // System.out.println(out.length()); 
    } 
} 
관련 문제