แจ็คสัน - การเข้ารหัส json ของสองเท่าพร้อมความแม่นยำที่ควบคุม

ฉันกำลังเข้ารหัสโครงสร้างแผนที่ที่ซับซ้อนด้วยอาร์เรย์ที่มีค่าสองเท่า ความแม่นยำสูงไม่สำคัญและขนาดเอาต์พุตก็เป็นเช่นนั้น ดังนั้นฉันจึงพยายามรับเครื่องมือ JSON (ในกรณีนี้คือแจ็คสัน) เพื่อทำให้ค่าสองเท่าเป็นอนุกรมโดยใช้ DecimalFormat ที่ให้มา

ต่อไปนี้เป็นช็อตที่ดีที่สุดของฉัน แต่สิ่งนี้ล้มเหลวเนื่องจากตัวทำแผนที่วัตถุไม่ได้เลือกซีเรียลไลเซอร์เพื่อเข้ารหัสอาร์เรย์:

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 และการเขียนเป็นแบบ raw - ฉันสามารถป้อน StringBuffer ลงใน DecimalFormat เพื่อทำสิ่งนี้ได้หรือไม่

ขอบคุณ


person user927590    schedule 04.09.2011    source แหล่งที่มา


คำตอบ (1)


จัดการเพื่อแก้ไขปัญหานี้โดยการยืมจากซีเรียลไลเซอร์ในตัวสำหรับ Double

มันค่อนข้างแฮ็คนิดหน่อย เพราะ writeRaw() ไม่สนใจบริบท และไม่เขียนลูกน้ำระหว่างสมาชิกอาร์เรย์ ดังนั้นฉันจึงเลือกตัวเขียน Json และเรียกใช้เมธอด 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() );
    }
}
person user927590    schedule 05.09.2011