杰克逊 - json编码双精度控制精度 [英] jackson - json encoding of doubles with controlled precision

查看:155
本文介绍了杰克逊 - json编码双精度控制精度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用double值数组编码复杂的Map结构。
高精度并不重要,输出大小也是如此,所以我试图使用JSON工具(在本例中为Jackson)使用提供的DecimalFormat序列化double值。

I'm encoding a complex Map structure with arrays of double values. High precision is not important and output size is, so I'm trying to get the JSON tool (Jackson in this case) to serialize the double values using a provided DecimalFormat.

以下是我最好的镜头,但由于对象映射器没有选择序列化器来编码数组,因此失败了:

The following is my best shot, but this fails as the serializer is not picked by the object mapper to encode the array:

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

输出为:


{test:[1.1111111111,1.315143204964E12}

{"test":[1.1111111111,1.315143204964E12}

什么我一直在寻找:


{test:[1.32E12,1.11E0]}

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

任何想法?

另外,我不喜欢生成一个字符串并且写入是原始的 - 是我可以将一个StringBuffer输入到DecimalFormat中吗?

Also, I don't like having to generate a String and write is as raw - is there I could feed a StringBuffer into into DecimalFormat to do this?

谢谢

推荐答案

通过借用内置的Double序列化程序来管理解决这个问题。

Managed to resolve this, by borrowing from the built-in serializer for Double.

这有点像黑客,因为writeRaw()并不关心关于上下文并且不在数组成员之间写逗号,所以我正在编译Json编写器并调用它的writeValue()方法来处理它。

It's a bit of a hack, because writeRaw() doesn't care about the context and doesn't write a comma between array members, so I'm casting the Json writer and calling its writeValue() method to handle this.

奇怪的是,这不适用于问题中的示例(再次没有被要求序列化虽然双打,但确实对我的现实世界对象起作用更复杂。

Strangely enough, this does not work on the example in the question (again doesn't get called for serializing these doubles), but does work on my real-world object which is more complex.

享受......

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

这篇关于杰克逊 - json编码双精度控制精度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆