2011-09-04 10 views
5

Estoy codificando una estructura de mapa compleja con matrices de valores dobles. La alta precisión no es importante y el tamaño de salida es, por lo que estoy tratando de obtener la herramienta JSON (Jackson en este caso) para serializar los valores dobles utilizando un DecimalFormat proporcionado.codificación jackson - json de dobles con precisión controlada

La siguiente es mi mejor tiro, pero esto no funciona como el serializador no es recogido por el mapeador objeto a codificar la matriz:

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)); 
    } 
} 

La salida es:

{ "prueba" : [1.1111111111,1.315143204964E12}

lo que estaba buscando:

{ "prueba": [1.32E12, 1.11E0]}

¿Alguna idea?

Además, no me gusta tener que generar un String y escribir es tan crudo, ¿podría alimentar un StringBuffer en DecimalFormat para hacer esto?

Gracias

Respuesta

4

logrado resolver esto, tomando prestado de la incorporada en el serializador para el doble.

Es un poco hackeo, porque writeRaw() no se preocupa por el contexto y no escribe una coma entre los miembros de la matriz, entonces estoy lanzando el escritor Json y llamando a su método writeValue() para manejar esta.

Por extraño que parezca, esto no funciona en el ejemplo de la pregunta (de nuevo no se llama para serializar estos dobles), pero funciona en mi objeto del mundo real que es más complejo.

gustarán ...

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()); 
    } 
} 
Cuestiones relacionadas