如何为复杂的情况自定义JAXBContext Unmarshaller

时间:2012-08-16 09:52:50

标签: java xml jaxb

我有关于将XML转换为Java Object的问题,在这里我使用JAXB 就我而言:

XML DATA:

<persons>
  <person>
     <name>Aris Tonar</name>
     <age />
     <nickname />
     <saldo />
  </person>
</persons>

JAVA类XML数据:

public class Person{
   private String name;
   private Integer age;
   private String nickName;
   private Integer id;
   private Double saldo;

   /**
   *Setter and Getter
   */

}

当我使用标准的JAXBContext Unmarshaller代码将其解析为Java Object时。代码:

JAXBContext context = JAXBContext.newInstance(Person.class.getPackage().getName());
Unmarshaller unmarshaller = context.createUnmarshaller();
JAXBElement element = (JAXBElement) unmarshaller.unmarshal(new StreamSource(new StringReader(stringOfXmlData.toString())));
Person obj = (Person) element.getValue();

它会给出结果: 人名=“Aris Tonar”
人年龄= null
人昵称=“”
人id = null
人saldo = null

但不是我想要的结果,我希望JAXB会给出结果:

人名=“Aris Tonar”
人年龄= 0
人昵称=“”
人id = null
人saldo = 0

  1. 我希望在XML DATA中声明的每个元素都将:如果指定了值,jaxb会将其解释为正常(如name元素)但如果未指定值,jaxb会将其解释为默认值(如age,nickname,saldo元素) )
  2. 如果元素未在XML Data中声明,那么jaxb会将其解释为null。(如id元素)
  3. 我是否可以这样做?可能是自定义JAXBContext Code ??

4 个答案:

答案 0 :(得分:3)

这有点麻烦,但你应该能够使用类型适配器实现你想要的东西:

public class Person{
   private String name;
   @XmlJavaTypeAdapter(IntegerZeroDefaultAdapter.class)
   @XmlSchemaType(name = "integer")
   private Integer age;
   private String nickName;
   private Integer id;
   @XmlJavaTypeAdapter(DoubleZeroDefaultAdapter.class)
   @XmlSchemaType(name = "double")
   private Double saldo;
   // ...    
}

public class IntegerZeroDefaultAdapter extends XmlAdapter<String, Integer> {
  public String marshal(Integer n) {
    return String.valueOf(n);
  }

  public Integer unmarshal(String val) {
    if(val == null) return null;
    else if("".equals(val)) return 0;
    else return Integer.valueOf(val);
  }
}

// likewise for DoubleZeroDefaultAdapter

您不需要名称或昵称的适配器,除非您要使用的默认值不是空字符串 - 字符串值的默认值是缺少的元素表示null和指定的 - 但是 - empty元素表示空字符串,请记住XML <nickname />中的字符完全等同于<nickname></nickname>

答案 1 :(得分:3)

@XmlType(name = "person", propOrder = {"name", "age", "nickName" , "saldo"})
public class Person {

private String name;
private Integer age;
private String nickName;
private Integer id;
private Double saldo;

public Person(String name, Integer age, String nickName, Integer id, Double saldo) {
  this.name = name;
  this.age = age;
  this.nickName = nickName;
  this.id = id;
  this.saldo = saldo;
}

public Person() {
  //jaxb constructor
}

@XmlElement(defaultValue="0")
public Integer getAge() {
  return age;
}

@XmlTransient
public Integer getId() {
  return id;
}

@XmlElement(defaultValue="")
public String getName() {
  return name;
}

@XmlElement(name="nickname" , defaultValue="")
public String getNickName() {
 return nickName;
}

@XmlElement(defaultValue="0")
public Double getSaldo() {
  return saldo;
}

public void setAge(Integer age) {
  this.age = age;
}

public void setId(Integer id) {
  this.id = id;
}

public void setName(String name) {
  this.name = name;
}

public void setNickName(String nickName) {
  this.nickName = nickName;
}

public void setSaldo(Double saldo) {
  this.saldo = saldo;
}


}

答案 2 :(得分:1)

如果在声明成员时使用默认值实例化成员,则应该解决第一个问题。

尝试:

public class Person{
 private String name = "";
 private Integer age = 0;
 private String nickName; = ""
 private Integer id = 0;
 private Double saldo =0.0;

HTH,
mcalex

答案 3 :(得分:0)

我使用cxf-codegen-plugin,你可以(从XSD / WSDL开始)

  1. 在数据模型的XSD中设置默认值(每种类型的“default”关键字)
  2. 使用插件的cxf-xjc-dv扩展来处理生成的类的getter中的默认值。
  3. 例如,这将为您的现场年龄创建一个getter:

    public Integer getAge() {
       if (age == null)
          return new Interger(0);
       return age;
    }