使用XStream和JsonHierarchicalStreamDriver输出值,我该如何舍入双打?

时间:2012-05-29 16:23:23

标签: java xml json xstream

类似的问题在这里,我确实试图使用转换器,正如答案所示。

Formatting decimal values for XML

我将对象序列化为xml和json。我在需要时使用XStream和JsonHierarchicalStreamDriver。

对象具有double类型的属性。这些序列化很好。在xml中,它被序列化为:

<value>3.14159265</value>

在json中,它是:

value: 3.14159265

我现在要求将值四舍五入到给定的小数位数。

在我的第一次尝试中,我写了一个转换器,它将所有双打四舍五入到小数点后两位。这是如上所示(除了值被舍入),但问题是不同的属性需要舍入到不同的有效数字,并且转换器不知道在“marshal”方法时有多少小数位。

我的第二次尝试使用自定义对象替换double,它保存double对象和小数位数。另一个转换器是必需的,这适用于xml,但在json中它将值呈现为字符串(即引号)而不是数字(这是我真正想要的)。

如何将圆角双精​​度渲染为数字?

由于

1 个答案:

答案 0 :(得分:0)

如果有人感兴趣,似乎JsonHierarchicalStreamDriver使用了一个名为JsonWriter的类。在它们之间,它们假设任何双打,整数等转换为JSON数字,而自定义对象将被翻译为文本(即用引号括起来)。似乎无论如何都没有指定你想要渲染的值。

如果您仍需要它,有几种选择。您可以使用JsonHierarchicalStreamDriver的替代方法。该文档暗示JettisonMappedXmlDriver的一个版本将所有数字字符串转换为JSON数字(并不总是需要)。

我选择了以下肮脏的黑客:

创建一个允许您删除引号的新编写器:

public static class HackJsonWriter extends JsonWriter {
    public HackJsonWriter(Writer writer) {
        super(writer);
    }

    private boolean dropQuotes = false;

    public void dropQuotes() {
        dropQuotes = true;
    }

    public void allowQuotes() {
        dropQuotes = false;
    }

    @Override
    protected void addValue(String value, AbstractJsonWriter.Type type)
    {
        if (dropQuotes) {
            super.addValue(value, AbstractJsonWriter.Type.NULL);
        }
        else {
            super.addValue(value, type);
        }
    }
}

以下列方式覆盖编写器的创建:

new XStream(new JsonHierarchicalStreamDriver() {
    @Override
    public HierarchicalStreamWriter createWriter(Writer writer) {
        return new HackJsonWriter(writer);
    }
});

创建一个可以发现黑客的转换器并对其进行处理。

public static class HackRoundedDoubleConverter implements Converter {

    private HackRoundedDoubleConverter() {
    }

    @Override
    public boolean canConvert(Class clazz) {
        return RoundedDouble.class.isAssignableFrom(clazz);
    }

    @Override
    public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {
        if (value == null) {
            return; // now that i think about it, this should probably write "null" (no quotes), but I was handling that elsewhere
        }
        RoundedDouble number = (RoundedDouble)value;
        if (Double.isNaN(number.getValue()) || Double.isInfinite(number.getValue())) {
            return; // at this point, we would have a problem.  an empty node will be created no matter what (and it translates to an empty object in javascript).
        }

        if (writer.underlyingWriter() instanceof HackJsonWriter) {
            HackJsonWriter hackWriter = (HackJsonWriter)writer.underlyingWriter();
            hackWriter.dropQuotes();
            writer.setValue(number.getRoundedValue());
            hackWriter.allowQuotes();
        }
        else {
            writer.setValue(number.getRoundedValue());
        }
    }

    @Override
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        // only interested in the one direction
        return null;
    }
}

注册转换器:

    xstream.registerConverter(new HackRoundedDoubleConverter());

RoundedDouble是一个具有两个属性的类,一个double值和一些小数位。

正如我所说,它是一个黑客(它非常脆弱,可能有许多我甚至没有发现的问题),我可能在弄清楚如何做到这一点时违法。我可能甚至不会使用它,但它回答了我原来的问题。