从JDK 1.8.0.77升级到1.8.0.162后,Jaxb2Marshaller失败

时间:2018-04-17 19:20:25

标签: java spring jaxb unmarshalling jaxb2

这个让我难过。我有一个Java String Batch应用程序,在针对Java 1.8.0.77运行时运行时没有任何错误。它读入XML文件并将其完美地写入数据库。

更新到JDK 1.8.0.162后,即使将日志记录设置为DEBUG,阅读器也无法正常工作,也不会发送任何错误消息。更改回Java 1.8.0.77可以解决此问题。我们的服务器运行162,所以我必须在162中完成这项工作。

以下是读者:

      @Bean
      ItemReader<Product> reviewItemReader() {
        StaxEventItemReader<Product> xmlFileReader = new StaxEventItemReader<>();
        xmlFileReader.setResource(new FileSystemResource(this.fileName));
        xmlFileReader.setFragmentRootElementName("Product");
        Jaxb2Marshaller feedMarshaller = new Jaxb2Marshaller();
        feedMarshaller.setClassesToBeBound(Product.class);
        xmlFileReader.setUnmarshaller(feedMarshaller);
        return xmlFileReader;
      }

当我针对Java 1.0.8.77运行它时,我获得了完整的产品记录,所有子类都用文件中的数据填充。当我针对Java 1.0.8.162运行它时,我只返回产品标记上的3个属性,而不是内部的任何字段。

XML看起来像:

...
  <Product id="asdsada" removed="false" disabled="true">
      <Descriptoin> Blah blah blah</Descriptoin>
      <UPCs>
         <UPC> 123423432</UPC>
      </UPCs> 
      <Rating>5</Rating>
      <Name>name here</Name>
      <Categories>
         <Category> Cat 1 </Category>
         <Category> Cat 2 </Category>
         <Category> Cat 3 </Category>
      </Categories>
      ...
  </Product>
  <Product id="zxcvzxcvxcv" removed="true" disabled="false">
      <Descriptoin> Blah blah blah</Descriptoin>
      <UPCs>
         <UPC> 123222423432</UPC>
      </UPCs> 
      <Rating>5</Rating>
      <Name>name here</Name>
      <Categories>
         <Category> Cat 1 </Category>
         <Category> Cat 2 </Category>
         <Category> Cat 3 </Category>
      </Categories>
      ....
   </Product>

产品类是这样的

@XmlRootElement(name = "Product", namespace = "FOO POWER")
public class Product {

  @XmlAttribute(name = "removed")
  public String removed;
  @XmlAttribute(name = "disabled")
  public String disabled;
  @XmlAttribute(name = "id")
  public String id;
  public String Name;
  public String Rating;

  public UPCs UPCs;

  public Brand Brand;
  ...

同样,它在1.8.0.77中完全没有任何问题。我在测试中通过它运行了数百万条记录。在1.8.0.162

中运行时,这些相同的记录失败
Someone asked to see what a child class looks like. They are pretty much like this: 

public class Brand {
  public String Name;

    public Attributes Attributes;

    public String ExternalId;

    public String disabled;
    ...

1 个答案:

答案 0 :(得分:1)

今年早些时候,我遇到了类似问题。我正在将项目从Java 1.8.0_92升级到1.8.0_152,并且一些使用1.8.0_92的JAXB解组已停止使用1.8.0_152。我在下面的答案中更多地作为实验结果而不是文献参考,因为我一直在努力寻找相关文档来支持我的发现。如果其他人可以找到相关文档,我有兴趣看到它。

我的理解是,如果Java类中的字段或属性没有@XmlElement注释,JAXB会将字段或属性视为具有注释@XmlElement(name = "fieldName")@XmlElement(name = "propertyName")作为适当的。因此,例如,Product类中未注释的字段将被视为如下:

@XmlElement(name = "Name")
public String Name;

@XmlElement(name = "Rating")
public String Rating;

@XmlElement(name = "UPCs")
public UPCs UPCs;

@XmlElement(name = "Brand")
public Brand Brand;

此外,在Java 8更新101和111之间,JAXB中处理名称空间的方式发生了变化。 Java 8 update 101允许元素单独匹配本地名称,而不管命名空间如何,但是从更新111开始,元素命名空间也必须匹配。如果您没有指定命名空间(特别是,如果您根本没有指定@XmlElement注释),则假定使用默认命名空间。

Product元素的子元素不在默认命名空间中,因此它们不再与上面的@XmlElement注释匹配。但是,例如,尝试将xmlns=""添加到Rating元素。您应该会发现该产品的评级已被读入。

因此,您的问题的一个可能解决方案是向所有子元素添加带有名称空间的@XmlElement注释。这就是我需要做的就是解决我遇到的问题:我已经有了必要的@XmlElement注释,我只需要在一个这样的注释中添加命名空间。但是,我怀疑你有更多的子元素,并且你指定的示例文档已从更大的真实文档中删除。考虑到这一点,使用相关注释创建package-info.java文件可能会更快,并将其放在包含POJO的包中(希望它们都在同一个包中):

@XmlSchema( 
    namespace = "FOO POWER", 
    elementFormDefault = XmlNsForm.QUALIFIED) 
package your.package.name.here;

import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

我将此添加到我创建的小型Java项目中以测试您的代码,我发现解组似乎有效。 Product类中的子属性正在填充XML文档中的值。我想到了使用this page中的package-info.java文件。