JAXB使用fractionDigits对BigDecimal进行编组

6
所以我的问题是这样的。我有一个XSD文件,我的生成XML文件应该符合它。使用org.apache.cxf.cxf-xjc-plugin Maven插件和外部绑定文件来生成源代码。但是当我尝试marshal对象时,生成的XML不符合我的要求。
我的XSD包含以下内容:
<xsd:element maxOccurs="1" minOccurs="0" name="amount">
  <xsd:simpleType>
    <xsd:restriction base="xsd:decimal">
      <xsd:totalDigits value="13" />
      <xsd:fractionDigits value="2" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>
...
<xsd:element maxOccurs="1" minOccurs="0" name="rate">
  <xsd:simpleType>
    <xsd:restriction base="xsd:decimal">
      <xsd:totalDigits value="8" />
      <xsd:fractionDigits value="5" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>

生成的XML片段如下:

<amount>109.5</amount>
...
<rate>10.25</rate>

尽管我期望它是这样的:

<amount>109.50</amount>
...
<rate>10.25000</rate>

有没有一种干净的方法来解决这个问题?

我希望不用为每个单独的totalDigits, fractionDigits组合编写多个适配器。而且由于XSD可能会更改,所以我想保留生成的源代码。


3
W3C文件中关于十进制数据类型的说明称,“fractionDigits”指定小数分隔符后数字位数的上限。如果右侧的零位不存在,对读取数据的任何内容都没有影响。需要使用零填充的用例是什么? - Jim Garrison
@Jim,(遗留)应用程序解析我生成的XML文件需要零填充;-) - Jasper
你能像我的答案一样使用 precisionDecimal 吗? - Jim Garrison
4个回答

6

您需要使用XmlAdapter来处理这种情况。以下是一个示例绑定文件,可帮助您生成它们。逻辑将包含在一个DecimalFormatter类中,该类包含所有所需格式的方法。

<jxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:jxb="http://java.sun.com/xml/ns/jaxb" version="2.1">
    <jxb:bindings schemaLocation="schema.xsd">
        <jxb:bindings node="//xs:element[@name='amount']">
            <jxb:property>
                <jxb:baseType>
                    <jxb:javaType name="java.math.BigDecimal"
                        parseMethod="org.example.DecimalFormatter.parseDecimal"
                        printMethod="org.example.DecimalFormatter.printDecimal_2Places" />
                </jxb:baseType>
            </jxb:property>
        </jxb:bindings>
        <jxb:bindings node="//xs:element[@name='rate']">
            <jxb:property>
                <jxb:baseType>
                    <jxb:javaType name="java.math.BigDecimal"
                        parseMethod="org.example.DecimalFormatter.parseDecimal"
                        printMethod="org.example.DecimalFormatter.printDecimal_5Places" />
                </jxb:baseType>
            </jxb:property>
        </jxb:bindings>
    </jxb:bindings>
</jxb:bindings>

更多信息


我现在正在做这件事,但我试图找到一个更简洁的解决方案,因为这需要我为每个totalDigits - fractionDigits组合创建一个printMethod - Jasper

1

我创建了一些特殊的XmlAdapter,例如

public class BigDecimal8PlaceAdapter extends XmlAdapter<String, BigDecimal> {

@Override
public String marshal(BigDecimal v) throws Exception {
  DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols();
  otherSymbols.setDecimalSeparator('.');
  DecimalFormat df = new DecimalFormat("#0.00000000",otherSymbols);
  return df.format(v);
}

@Override
public BigDecimal unmarshal(String v) throws Exception {
    Double d = Double.valueOf(v);
    return BigDecimal.valueOf(d);
}

}

然后我在属性中添加了XmlAdapter:
@XmlElement(name = "rate", required = true)
@XmlJavaTypeAdapter(BigDecimal8PlaceAdapter.class)
protected BigDecimal rate;

然后,用两位小数适配器做同样的事情。

0
如果您可以更改XSD以使用文档此处记录的precisionDecimal类型,则可能能够将minScalemaxScale限制设置为相同的值。

根据这个答案,JAXB规范不涵盖将XML Schema 1.1转换为Java的内容。当我尝试时,XJC会抛出以下异常[ERROR] src-resolve: Cannot resolve the name 'xsd:precisionDecimal' to a(n) 'type definition' component. - Jasper

0

我对保留尾随零所能带来的好处感到困惑。

如果保留尾随零很重要,那么请使用字符串值代替数字,并使用属性指定其宽度和小数位数。

无论如何,尾随零永远不会影响使用这些值进行计算,您唯一能够呈现它们的方式是将结果转换为字符串并自行填充。如果需要帮助,请参见...

CXF客户端SOAP消息格式化


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接