Versão atual:

Interpretação de listas com JAXB e GSON

Estou trabalhando em um consumidor de serviços REST.

Para interpretar os retornos em xml, tenho utilizado JAXB. Para interpretar os retornos em json, tenho utilizado GSON.

Tenho tido dificuldades em interpretar retornos de listas. Pois os retornos em json e xml não condizem com o esperado pelo meu interpretador.

Gostaria de encontrar uma forma de dizer ao interpretador como interpretar os retornos sem precisar criar objetos novos (como é a solução utilizando @XmlElementWrapper, para xml).


Serviço

package alive.rest;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

// http://localhost:8080/AliveRest/ServiceSample
@Path("/ServiceSample")
public class ServiceSample {

    private static List<ObjectSample> objectSampleList;

    public ServiceSample() {
        ObjectSample osA = new ObjectSample();
        osA.setText("Object Sample A");
        osA.setNumber(1);
        osA.setDate(Calendar.getInstance());
        osA.setFlag(true);

        ObjectSample osB = new ObjectSample();
        osB.setText("Object Sample B");
        osB.setNumber(2);
        osB.setDate(Calendar.getInstance());
        osB.setFlag(false);

        ObjectSample osC = new ObjectSample();
        osC.setText("Object Sample C");
        osC.setNumber(3);
        osC.setDate(Calendar.getInstance());
        osC.setFlag(true);

        objectSampleList = new ArrayList<ObjectSample>();
        objectSampleList.add(osA);
        objectSampleList.add(osB);
        objectSampleList.add(osC);
    }

    // http://localhost:8080/AliveRest/ServiceSample
    @GET
    @Produces(value={MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public List<ObjectSample> getObjectSampleList() {
        System.out.println("// ----- ----- ----- [ Retornando a lista de objetos ]");
        return objectSampleList;
    }

    // http://localhost:8080/AliveRest/ServiceSample/{index}
    @GET
    @Produces(value={MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Path("/{index}")
    public ObjectSample getObjectSample(@PathParam(value="index") int index) {
        System.out.println("// ----- ----- ----- [ Retornando o objeto no índice da " + index + " lista ]");
        return objectSampleList.get(index);
    }

    // http://localhost:8080/AliveRest/ServiceSample
    @POST
    @Produces(value={MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Consumes(value={MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public List<ObjectSample> postObjectSample(ObjectSample objectSample) {
        System.out.println("// ----- ----- ----- [ Adicionando o objeto à lista ]");
        objectSampleList.add(objectSample);
        return objectSampleList;
    }

    // http://localhost:8080/AliveRest/ServiceSample/{index}
    @DELETE
    @Produces(value={MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Path("/{index}")
    public List<ObjectSample> deleteObjectSample(@PathParam(value="index") int index) {
        System.out.println("// ----- ----- ----- [ Removendo o objeto no índice da " + index + " lista ]");
        objectSampleList.remove(index);
        return objectSampleList;
    }
}

Cliente

package alive.rest.client;

import java.net.URI;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.Response.Status.Family;

import alive.rest.ObjectSample;
import alive.rest.jsonhandler.JsonHandler;
import alive.rest.xmlhandler.XmlHandler;

public class ClientSample {

//    private static MediaType mediaType = MediaType.APPLICATION_XML_TYPE;
    private static MediaType mediaType = MediaType.APPLICATION_JSON_TYPE;

    public static void main(String[] args) {
        ClientBuilder clientBuilder = ClientBuilder.newBuilder();
        Client client = clientBuilder.build();

        WebTarget target = client.target(ClientSample.getBaseURI());

        ping(target);
        getObjectSampleList(target);
        getObjectSample(target, 0);
        postObjectSample(target);
        deleteObjectSample(target, 0);
        try {
            getException(target);
        } catch (Exception e) { e.printStackTrace(); } 
        try {
            getRuntimeException(target);
        } catch (Exception e) { e.printStackTrace(); } 
    }

    private static URI getBaseURI() {
        return UriBuilder.fromUri("http://localhost:8080/AliveRest").build();
    }

    private static void ping(WebTarget target) {
        Response response = target.path("ServiceSample").request()
                .accept(mediaType).get();

        printResponse(response);
    }

    private static void getObjectSampleList(WebTarget target) {
        Response response = target.path("ServiceSample").request()
                .accept(mediaType).get();

        parseResponseListObject(response);
    }

    private static void getObjectSample(WebTarget target, int index) {
        Response response = target.path("ServiceSample/" + index).request()
                .accept(mediaType).get();

        parseResponseSingleObject(response);
    }

    private static void postObjectSample(WebTarget target) {
        Entity<String> post = Entity.entity(getPostMessage(), mediaType);

        Response response = target.path("ServiceSample").request()
                .accept(mediaType).post(post);

        printResponse(response);
    }

    private static void deleteObjectSample(WebTarget target, int index) {
        Response response = target.path("ServiceSample/" + index).request()
                .accept(mediaType).delete();

        printResponse(response);
    }

    private static void getException(WebTarget target) throws Exception {
        Response response = target.path("ServiceSample/Exception").request()
                .accept(mediaType).get();

        verifyException(response);

        printResponse(response);
    }

    private static void getRuntimeException(WebTarget target) throws Exception {
        Response response = target.path("ServiceSample/RuntimeException").request()
                .accept(mediaType).get();

        verifyException(response);

        printResponse(response);
    }

    private static void verifyException(Response response) throws Exception {
        if (! response.getStatusInfo().getFamily().equals(Family.SUCCESSFUL))
            throw new Exception(response.getStatusInfo().getStatusCode() + " - " + response.getStatusInfo().getReasonPhrase());
    }

    private static void printResponse(Response response) {
        System.out.println(response.toString());
        System.out.println(response.readEntity(String.class));
        System.out.println();
    }

    private static String getPostMessage() {
        if (mediaType.equals(MediaType.APPLICATION_JSON_TYPE)) {
            return "{\"text\": \"Text value\", \"number\": \"26\", \"date\": \"1989-08-06\", \"flag\": \"true\"}";
        } else if (mediaType.equals(MediaType.APPLICATION_XML_TYPE)) {
            return "<objectSample><text>Text value</text><number>26</number><date>1989-08-06</date><flag>true</flag></objectSample>";
        } else {
            return null;
        }
    }

    private static void parseResponseSingleObject(Response response) {
        String sResponse = response.readEntity(String.class);
        ObjectSample os = null;
        os = parseResponse(sResponse, ObjectSample.class);
        System.out.println(os);
        System.out.println();
    }

    private static void parseResponseListObject(Response response) {
        String sResponse = response.readEntity(String.class);
        ObjectSample[] osa = null;
        osa = parseResponse(sResponse, ObjectSample[].class);
        System.out.println(osa);
        System.out.println();
    }

    private static <T> T parseResponse(String sResponse, Class<T> c) {
        if (mediaType.equals(MediaType.APPLICATION_JSON_TYPE)) {
            JsonHandler<T> jsonHandler = new JsonHandler<T>(c);
            return jsonHandler.jsonToObject(sResponse.getBytes());
        } else if (mediaType.equals(MediaType.APPLICATION_XML_TYPE)) {
            XmlHandler<T> xmlHandler = new XmlHandler<T>(c);
            return xmlHandler.xmlToObject(sResponse.getBytes());
        }
        return null;
    }

}

Objeto Exemplo

package alive.rest;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Calendar;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import alive.rest.xmlhandler.CalendarAdapter;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "objectSample")
public class ObjectSample implements Serializable {

    private static final long serialVersionUID = 8011262057060204314L;

    private String text;
    private Integer number;
    @XmlJavaTypeAdapter(CalendarAdapter.class)
    private Calendar date;
    private Boolean flag;

    /*Getters & Setters*/

    @Override
    public String toString() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        return "ObjectSample ["
                + "text=" + text + ", "
                + "number=" + number + ", "
                + "date=" + sdf.format(date.getTime()) + ", "
                + "flag=" + flag + "]";
    }

}

Interpretador Json

package alive.rest.jsonhandler;

import java.util.Calendar;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class JsonHandler <T> {

    private Class<T> c;
    private CalendarAdapter calendarAdapter;

    public JsonHandler(Class<T> c) {
        this.c = c;
        this.calendarAdapter = new CalendarAdapter();
    }

    public byte[] objectToJson(T t) {
        Gson gson = new GsonBuilder()
                .registerTypeHierarchyAdapter(Calendar.class, this.calendarAdapter)
                .setPrettyPrinting()
                .create();
        return gson.toJson(t).getBytes();
    }

    public T jsonToObject(byte[] json) {
        Gson gson = new GsonBuilder()
                .registerTypeHierarchyAdapter(Calendar.class, this.calendarAdapter)
                .create();
        return gson.fromJson(new String(json), c);
    }

    public CalendarAdapter getCalendarAdapter() {
        return calendarAdapter;
    }

    public void setCalendarAdapter(CalendarAdapter calendarAdapter) {
        this.calendarAdapter = calendarAdapter;
    }

}

Interpretador Xml

package alive.rest.xmlhandler;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.bind.Unmarshaller;

public class XmlHandler <T> {

    private Class<T> c;

    public XmlHandler(Class<T> c) {
        this.c = c;
    }

    public byte[] objectToXml(T t) {
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(this.c);
            Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

            // output pretty printed
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            jaxbMarshaller.marshal(t, baos);
            return baos.toByteArray();
        } catch (PropertyException e) {
            e.printStackTrace();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    public T xmlToObject(byte[] xml) {
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(this.c);
            Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();

            ByteArrayInputStream bais = new ByteArrayInputStream(xml);
            T t = (T) jaxbUnmarshaller.unmarshal(bais);
            return t;
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

}

Xml recebido

<objectSamples>
    <objectSample/>
    ...
    <objectSample/>
</objectSamples>

Xml esperado

<objectSample/>
...
<objectSample/>

Json recebido

{"objectSample":[
    {}, 
    ..., 
    {}
]}

Json esperado

[
    {}, 
    ..., 
    {}
]

Segue artigo que me ajudou a resolver o problema em Xml (Ainda falta a solução para Json).

Solução para Xml

Versões(2):

Ver a versão formatada

Interpretação de listar com JAXB e GSON

Comentário

new question