Получить текущий хост в XmlAdapter

Есть ли способ получить текущий базовый URI в XmlAdapter? Или как это обычно архивируется?

public class Service{
...
    @GET
    public MyEntity getEntity() {
        return em.find(MyEntity.class, "dummy");
    }
...
}


@XmlRootElement(name = "myEntity")
public class MyEntity {

    @XmlJavaTypeAdapter(MyAdapter.class)
    private Entity2 entity2Ref;
...

}



public class MyAdapter extends XmlAdapter<Entity2Ref, Entity2> {

// Is NULL but shold be injected with host URI
@Context
UriInfo uri;

...

}

1 ответ

Ниже приведен полный пример того, как это можно сделать:

XML Response

Ниже я собираюсь продемонстрировать, как получить следующий ответ, где URI в address элемент вводится через 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 элемент. Мы будем использовать XmlAdapter выполнить специальную обработку для этого.

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;
    }

}

XMLAdapter

Ниже XmlAdapter что мы будем использовать. Обратите внимание, как он получает информацию от AddressResource для построения URI, Требуется UriInfoэто делает его состоящим. Нам нужно будет установить экземпляр этого 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,

AddressResource

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;
    }

}

CustomerResource

Так как у нас есть состояние XmlAdapter мы не можем просто использовать JAXB через привязку по умолчанию. Вместо этого мы можем получить доступ к 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);
    }

}

StreamingOutput

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);
        }
    }

}
Другие вопросы по тегам