以下是如何完成此操作的完整示例:
XML 响应
下面我将演示如何获得以下响应,其中address
元素中的 URI 通过一个XmlAdapter
知道UriInfo
.
<?xml version="1.0" encoding="UTF-8"?>
<customer id="1">
<name>Jane Doe</name>
<address>http://localhost:9999/address/123</address>
</customer>
Java 模型
下面是我将用于此示例的 Java 模型。
顾客
默认情况下,类的内容将被编组在元素Address
之下。customer
我们将使用 anXmlAdapter
对此进行特殊处理。
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
@XmlType(propOrder={"name", "address"})
public class Customer {
private int id;
private String name;
private Address address;
@XmlAttribute
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlJavaTypeAdapter(AddressAdapter.class)
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
地址
import javax.xml.bind.annotation.XmlAttribute;
public class Address {
private int id;
@XmlAttribute
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
xml适配器
下面是XmlAdapter
我们将使用的。注意它是如何从AddressResource
构建URI
. 它需要一个UriInfo
,这使它有状态。我们需要在 上设置 this 的实例XmlAdapter
以Marshaller
使一切正常工作。
import javax.ws.rs.core.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class AddressAdapter extends XmlAdapter<String, Address> {
private UriInfo uriInfo;
public AddressAdapter() {
}
public AddressAdapter(UriInfo uriInfo) {
this.uriInfo = uriInfo;
}
@Override
public Address unmarshal(String v) throws Exception {
// TODO Auto-generated method stub
return null;
}
@Override
public String marshal(Address v) throws Exception {
if(null == uriInfo) {
return "";
}
UriBuilder builder = UriBuilder.fromResource(AddressResource.class);
System.out.println(uriInfo.getAbsolutePath().getHost());
builder.scheme(uriInfo.getAbsolutePath().getScheme());
builder.host(uriInfo.getAbsolutePath().getHost());
builder.port(uriInfo.getAbsolutePath().getPort());
builder.path(AddressResource.class, "get");
return builder.build(v.getId()).toString();
}
}
JAX-RS 服务
在此示例中,有两种服务,一种用于Address
,另一种用于Customer
。
地址资源
import javax.ws.rs.*;
import javax.ws.rs.ext.Provider;
@Provider
@Path("/address")
public class AddressResource {
@GET
@Path("{id}")
public Address get(@PathParam("id") int id) {
Address address = new Address();
address.setId(id);
return address;
}
}
客户资源
由于我们有一个有状态的XmlAdapter
,我们不能只通过默认绑定来利用 JAXB。相反,我们可以通过StreamingOutput
.
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.*;
@Provider
@Path("/customer")
public class CustomerResource {
private JAXBContext jaxbContext;
public CustomerResource() {
try {
jaxbContext = JAXBContext.newInstance(Customer.class);
} catch (JAXBException e) {
// TODO - Handle Exception
}
}
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_XML)
public StreamingOutput get(@Context UriInfo uriInfo, @PathParam("id") int id) {
Customer customer = new Customer();
customer.setId(id);
customer.setName("Jane Doe");
Address address = new Address();
address.setId(123);
customer.setAddress(address);
return new MyStreamingOutput(jaxbContext, customer, uriInfo);
}
}
流输出
import java.io.*;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.*;
import javax.xml.bind.*;
public class MyStreamingOutput implements StreamingOutput {
private JAXBContext jaxbContext;
private Object object;
private UriInfo uriInfo;
public MyStreamingOutput(JAXBContext jc, Object object, UriInfo uriInfo) {
this.jaxbContext = jc;
this.object = object;
this.uriInfo = uriInfo;
}
@Override
public void write(OutputStream os) throws IOException,
WebApplicationException {
try {
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setAdapter(new AddressAdapter(uriInfo));
marshaller.marshal(object, os);
} catch(JAXBException jaxbException) {
throw new WebApplicationException(jaxbException);
}
}
}