Search code examples
javajsonrestweb-servicesjersey

RESTful Java client convert JSON responses to Objects


EDITED:

I am trying to convert the JSON responses that i am getting from REST API service to objects inside my application. I use Jersey to perform “GET” requests to REST the service.

Lets say that i have the following two API calls, each one having its corresponding JSON response as:

First call: Get a specific myEntity object with its code value: https://www.test.com/webservice/entity/get?code=BOBS-JC6L (GET)

Response:

{
  "isOk": 1,
  "isAuthError": 0,
  "error": false,
  "myEntity":{
        "id": "123",
        "code": "BOBS-JC6L",
        "type": "ZZZ",
        "value": "15.00", 
    }
}

Second call: Get all myEntity objects: https://www.test.com/webservice/entity/get-all (GET)

Response:

{
  "isOk": 1,
  "isAuthError": 0,
  "error": false,
  "myEntities": [
    {
        "id": "123",
        "code": "BOBS-JC6L",
        "type": "ZZZ",
        "value": "15.00",      
    },
    {
        "id": "456",
        "code": "BOBS-JC7L",
        "type": "CCC",
        "value": "32.00",
    }
    {...}
  ]
}

So in both cases the fundamental object (of type MyEntity) is included in JSON as nested element(s). I am trying to map JSON structure into POJO objects.

So i have created the following POJO classes:

MyEntity POJO (this is the fundamental nested element(s) class):

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Date;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

import javax.xml.bind.annotation.XmlRootElement;

public class MyEntity {

    private int id;
    private String code;
    private String type;
    private BigDecimal value;

    public MyEntity(){

    }

    public MyEntity(String code, String type, BigDecimal value){
        this.code = code;
        this.type = type;
        this.value = value;
    }

    ....

}

Then there is a class for the first API call response (we get a single MyEntity object):

@XmlRootElement
public class GetSingleMyEntityResponse {

    private int isOk;
    private int isAuthError;
    private boolean error;
    private MyEntity myEntity;

    ...

}

And another class for the second API call response (we get multiple nested MyEntity objects):

@XmlRootElement
public class GetMultipleMyEntityResponse {

    private int isOk;
    private int isAuthError;
    private boolean error;
    private List<MyEntity> myEntities;

    ...

}

In my code i first try to get a single myEntity object, calling: https://www.test.com/webservice/entity/get?code=BOBS-JC6L

try {

      ClientConfig clientConfig = new DefaultClientConfig();
      Client client = Client.create(clientConfig);

      WebResource webResource1 = client
              .resource("https://www.test.com/webservice/entity/get?code=MESM-ZB2NEJ");

      Builder builder = webResource1.accept(MediaType.APPLICATION_JSON) //
              .header("content-type", MediaType.APPLICATION_JSON);

      ClientResponse response = builder.get(ClientResponse.class);

      // Status 200 is successful.
      if (response.getStatus() != 200) {
          System.out.println("Failed with HTTP Error code: " + response.getStatus());
          String error = response.getEntity(String.class);
          System.out.println("Error: " + error);
          return;
      }

      System.out.println("\n\nOutput from Server .... \n");

      GetSingleMyEntityResponse vResp = (GetSingleMyEntityResponse) response.getEntity(GetSingleMyEntityResponse.class);
      MyEntity v = vResp.getMyEntity();

      if(v.getId()>0) {
          System.out.println("Id .... " + v.getId());
          System.out.println("Code .... " + v.getCode());
          System.out.println("Type .... " + v.getType());      
          System.out.println("Value .... " + v.getValue());
      }
    } catch (Exception e) {
        e.printStackTrace();
}

This works and i am able to get MyEntity object:

Output from Server .... 

Id .... 123
Code .... BOBS-JC6L
Type .... ZZZ
Value .... 15.00

I am also trying to map multiple MyEntity objects from: https://www.test.com/webservice/entity/get-all

try {

            Client client = Client.create();

            WebResource webResource = client
               .resource("https://www.test.com/webservice/entity/get-all");

            ClientResponse response = webResource.accept("application/json")
                       .get(ClientResponse.class);

            if (response.getStatus() != 200) {
               throw new RuntimeException("Failed : HTTP error code : "
                + response.getStatus());
            }

            String output = response.getEntity(String.class);

            GetMultipleMyEntityResponse vResp = (GetMultipleMyEntityResponse) response.getEntity(GetMultipleMyEntityResponse.class);
            List<MyEntity> vRespList = new ArrayList<>();
            vRespList = vResp.getMyEntities();

            if(vRespList.size()>0) {

                for(MyEntity v:vRespList) {
                    System.out.println("Id .... " + v.getId());
                    System.out.println("Code .... " + v.getCode());
                    System.out.println("Type .... " + v.getType());      
                    System.out.println("Value .... " + v.getValue());
                }

            }

          } catch (Exception e) {

            e.printStackTrace();

}

But is seems that the GetMultipleMyEntityResponse POJO class is not working for it, and i am getting:

j

avax.ws.rs.WebApplicationException: HTTP 400 Bad Request
    at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.readFrom(AbstractRootElementProvider.java:113)
    at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:553)
    at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:506)
    at com.mspos.mesmo.JerseyClientGet.main(JerseyClientGet.java:97)
Caused by: javax.xml.bind.UnmarshalException: Error creating JSON-based XMLStreamReader
 - with linked exception:
[javax.xml.stream.XMLStreamException: java.io.IOException: stream is closed]
    at com.sun.jersey.json.impl.BaseJSONUnmarshaller.createXmlStreamReader(BaseJSONUnmarshaller.java:116)
    at com.sun.jersey.json.impl.BaseJSONUnmarshaller.unmarshalJAXBElementFromJSON(BaseJSONUnmarshaller.java:108)
    at com.sun.jersey.json.impl.BaseJSONUnmarshaller.unmarshalFromJSON(BaseJSONUnmarshaller.java:97)
    at com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider.readFrom(JSONRootElementProvider.java:125)
    at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.readFrom(AbstractRootElementProvider.java:111)
    ... 3 more
Caused by: javax.xml.stream.XMLStreamException: java.io.IOException: stream is closed
    at com.sun.jersey.json.impl.Stax2JsonFactory.ensureNonEmptyReader(Stax2JsonFactory.java:173)
    at com.sun.jersey.json.impl.Stax2JsonFactory.createReader(Stax2JsonFactory.java:117)
    at com.sun.jersey.json.impl.Stax2JsonFactory.createReader(Stax2JsonFactory.java:111)
    at com.sun.jersey.json.impl.BaseJSONUnmarshaller.createXmlStreamReader(BaseJSONUnmarshaller.java:113)
    ... 7 more
Caused by: java.io.IOException: stream is closed
    at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.ensureOpen(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(Unknown Source)
    at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
    at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
    at sun.nio.cs.StreamDecoder.read(Unknown Source)
    at java.io.InputStreamReader.read(Unknown Source)
    at java.io.BufferedReader.fill(Unknown Source)
    at java.io.BufferedReader.read(Unknown Source)
    at com.sun.jersey.json.impl.Stax2JsonFactory.ensureNonEmptyReader(Stax2JsonFactory.java:167)
    ... 10 more

Any ideas of what am i missing?


Solution

  • You're calling response.getEntity() twice. Call it only once.