【问题标题】:Using XStream and JsonHierarchicalStreamDriver to output values, how do I round doubles?使用 XStream 和 JsonHierarchicalStreamDriver 输出值,如何舍入双精度数?
【发布时间】:2012-06-03 21:44:46
【问题描述】:

这里有一个类似的问题,我确实尝试过使用转换器,正如答案所暗示的那样。

Formatting decimal values for XML

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

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

<value>3.14159265</value>

在 json 中是:

value: 3.14159265

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

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

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

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

谢谢

【问题讨论】:

  • 快速浏览 xstream 转换器教程显示了以下示例:“@XStreamConverter(value=BooleanConverter.class, booleans={false}, strings={"yes", "no"})"。所以看起来你可以给转换器一些额外的参数。你能用这些吗?
  • @DenisTulskiy 谢谢,但每个实例可能有不同的小数位数。如果有办法将当前对象或当前“小数位数”传递给转换器,那将解决我的问题......
  • 我认为这项任务远远超出了任何编组库的能力。

标签: java xml json xstream


【解决方案1】:

如果有人感兴趣,似乎 JsonHierarchicalStreamDriver 使用了一个名为 JsonWriter 的类。在它们之间,它们假设任何 Doubles、Integers 等转换为 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);
        }
    }
}

用以下方式覆盖writer的创建:

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(它非常脆弱,可能有很多我什至没有发现的问题),而且我可能在研究如何做时触犯了法律。我什至可能不会使用它,但它回答了我最初的问题。

【讨论】:

    猜你喜欢
    • 2019-05-18
    • 1970-01-01
    • 2011-01-08
    • 1970-01-01
    • 1970-01-01
    • 2018-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多