1

类似的问题是here,正如答案所示,我确实尝试过使用转换器。

格式化 XML 的十进制值

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

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

<value>3.14159265</value>

在 json 中是:

value: 3.14159265

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

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

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

如何将四舍五入的双精度数呈现为数字?

谢谢

4

1 回答 1

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 是一个具有两个属性、一个双精度值和多个小数位的类。

正如我所说,它是一种 hack(它非常脆弱,可能有很多我什至没有发现的问题),而且我可能在研究如何做时触犯了法律。我可能什至不会使用它,但它回答了我最初的问题。

于 2012-06-01T09:34:35.943 回答