JAXB里对象成员的处理

2 篇文章 0 订阅
今天同事找我咨询JAXB的处理问题,为什么在soap里面一直报infinite loop,我和他解释了这种问题产生的原因是因为2个对象互相引用()在工作代码中是一个复杂的A onetomany B, B manytoone A, A onetomany A, A manytoone A的关系)导致xml解析的时候产生了死循环,为了解决这种死循环只要简单的在一端断开这种引用, JAXB提供的相应的annotation来解决这个问题,可是当我们把 @XmlTransient加在字段上面却发现不起作用,还是跑infinite loop exception,上网google了一把,没发现什么问题,后来去jaxb的网站看了,发现是annotation的生效性没有申明在地段上,问题解决后发现 @XmlTransient直接去掉了引用,使用麻烦,从xml转回对象时需要自己加回成员对象,@XmlInverseReference简化了相关操作,推荐使用。

Reference:
https://jaxb.java.net/tutorial/index.html
http://blog.bdoughan.com/2010/07/jpa-entities-to-xml-bidirectional.html
http://blog.bdoughan.com/2013/03/moxys-xmlinversereference-is-now-truly.html
Top-level Elements: XmlRootElement

A class that describes an XML element that is to be a top-level element, i.e., one that can function as an XML document, should be annotated with XmlRootElement. Its optional elements are name and namespace. By default, the class name is used as the name

XmlAccessorType
You can annotate a package or a top level class with XmlAccessorType, setting its value element to one of the enum constants FIELD, PROPERTY, PUBLIC_MEMBER (default) or NONE. If FIELD is set every non static, non transient field will be automatically bound. PROPERTY instructs JAXB to do this for getter and setter pairs. NONE suppresses bind except for explicitly annotated fields or properties. A class without this annotation inherits the XmlAccessorType setting either from its superclass or from the package setting.

FIELD
          Every non static, non transient field in a JAXB-bound class will be automatically bound to XML, unless annotated by XmlTransient.
NONE
          None of the fields or properties is bound to XML unless they are specifically annotated with some of the JAXB annotations.
PROPERTY
          Every getter/setter pair in a JAXB-bound class will be automatically bound to XML, unless annotated by XmlTransient.
PUBLIC_MEMBER
          Every public getter/setter pair and every public field will be automatically bound to XML, unless annotated by XmlTransient.

The other annotation to be mentioned in this context is XmlTransient. It suppresses binding for its target which can be an entire class or a field or a method. This is also useful if you have a name clash resulting from a public field, say foo, and methods getFoo and setFoo.
 javax.xml.bind.annotation
Annotation Type XmlAccessorType

@Inherited
@Retention(value=RUNTIME)
@Target(value={PACKAGE,TYPE})
public @interface XmlAccessorType

Controls whether fields or Javabean properties are serialized by default.

Usage

@XmlAccessorType annotation can be used with the following program elements:

    package
    a top level class

See "Package Specification" in javax.xml.bind.package javadoc for additional common information.

This annotation provides control over the default serialization of properties and fields in a class.

The annotation @XmlAccessorType on a package applies to all classes in the package. The following inheritance semantics apply:

    If there is a @XmlAccessorType on a class, then it is used.
    Otherwise, if a @XmlAccessorType exists on one of its super classes, then it is inherited.
    Otherwise, the @XmlAccessorType on a package is inherited.

Defaulting Rules:

By default, if @XmlAccessorType on a package is absent, then the following package level annotation is assumed.

   @XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
 

By default, if @XmlAccessorType on a class is absent, and none of its super classes is annotated with @XmlAccessorType, then the following default on the class is assumed:

   @XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
 
Example
1.
 @XmlAccessorType( XmlAccessType.PUBLIC_MEMBER )
public class SomeClass {
    private String a;
    private String b;

    public SomeClass(){ ... }

    public String getA(){ ... }
    public void setA( String value ){ ... }

    @XmlTransient //transient should mentioned on get/set method or public field for public_memeber type
    public String getB(){ ... }
    public void setB( String value ){ ... }
}
package blog.inversereference;
 
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlInverseReference;
 
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
 
    String name;
 
    @XmlElement
    @XmlInverseReference(mappedBy="customer")
//transient/xmlInverseReference should metioned on private field for field type
    Address address;
 
}


Address

Here the @XmlInverseReference annotation is used to specify that when the address property is populated on the Customer object, the customer property on the Address object will be set as a back pointer.

package blog.inversereference;
 
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
 
 
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Address {
 
    String street;
 
    String city;
 
    @XmlElement
    @XmlInverseReference(mappedBy="address")
    Customer customer;
 
}

import javax.persistence.*;
 
@Entity
public class Customer {
 
    @Id
    private long id;
 
    @OneToOne(mappedBy="customer", cascade={CascadeType.ALL})
    private Address address;
 
}
    
import javax.persistence.*;
 
@Entity
public class Address implements Serializable {
 
    @Id
    private long id;
 
    @MapsId
    @OneToOne
    @JoinColumn(name="ID")
    private Customer customer;
 
}


Using vanilla JAXB to marshal these objects to XML you need to mark one direction @XmlTrasient, this prevents JAXB from entering an infinite loop during marshalling (object-to-XML).  During unmarshalling (XML-to-object) however you are responsible for populating the back pointer yourself.
import javax.persistence.*;
import javax.xml.bind.annotation.*;
 
@Entity
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Address implements Serializable {
 
    @Id
    private long id;
 
    @OneToOne
    @JoinColumn(name="ID")
    @MapsId
    @XmlTransient
    private Customer customer;
 
}


MOXy offers an extension that will populate the back pointer for you, this is done with the @XmlInverseReference annotation.  Note how @XmlInverseReference annotation leverages the same "mappedBy" concept.
import javax.persistence.*;
import org.eclipse.persistence.oxm.annotations.*;
 
@Entity
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Address implements Serializable {
 
    @Id
    private long id;
 
    @OneToOne
    @JoinColumn(name="ID")
    @MapsId
    @XmlInverseReference(mappedBy="address")
    private Customer customer;
 
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值