0
votes

I invoke some web service (constructed in Ruby) and get JSON response like this:

{
    "error_code": "02",
    "message": "Param not valid",
    "field_name": "title"
}

To model that response object in Java I try with:

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "response")
public class Response {

    private String error_code;
    private String message;
    private String field_name;

    public String getError_code() {
        return error_code;
    }
    public void setError_code(String error_code) {
        this.error_code = error_code;
    }

    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }

    public String getField_name() {
        return field_name;
    }
    public void setField_name(String field_name) {
        this.field_name = field_name;
    }

}

... and to read the response of a WS invocation in my WS Client I try:

Response response = responseWs.readEntity(Response.class);

... but I get following exception:

org.jboss.resteasy.plugins.providers.jaxb.JAXBUnmarshalException: javax.xml.bind.UnmarshalException 
 - with linked exception: 
[com.sun.istack.internal.SAXParseException2; columnNumber: 0 unexpected element ... Expected elements are

That is because my code is trying to handle JSON response object like this (with some 'root' element):

{
    "response":
    {
        "error_code": "02",
        "message": "Param not valid",
        "field_name": "title"
    }       
}

Does somebody knows how can I solve this situation, on my side?

Thanks

3

3 Answers

1
votes

From the code snippet you posted

Response response = responseWs.readEntity(Response.class);

I would recommend using some other name for your entity object. Response class is also used by jaxrs framework itself.

I am assuming you are using RestEasyClient to call this (external) service to receive JSON. If it is understood that the response from this service is in JSON, you can use JSON (jackson) marshaller/unmarshaller instead of JAXB. Assuming you already have "resteasy-client" dependency available on your classpath. The maven form of this dependency looks as follows:

<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-client</artifactId>
    <version>3.0.19.Final</version>
</dependency>

  1. Change the name of the DTO to something ExternalServiceResponse
  2. While executing GET request you specify explicitly the response media type
Response response = target.request(MediaType.APPLICATION_JSON).get();
ExternalServiceResponse result = response.readEntity(ExternalServiceResponse.class)
  1. Finally I don't see why you need to specify @XmlRootElement annotation on your DTO
public class ExternalServiceResponse implements Serializeable {

    private String error_code;
    private String message;
    private String field_name;

    public String getError_code() {
        return error_code;
    }
    public void setError_code(String error_code) {
        this.error_code = error_code;
    }

    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }

    public String getField_name() {
        return field_name;
    }
    public void setField_name(String field_name) {
        this.field_name = field_name;
    }

}
0
votes

There where you configured JAXB (a properties file or a config method) you should set jaxbUnmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false)

0
votes

For me, this snippet solves the issue:

String responseAsString = responseWs.readEntity(String.class);
ObjectMapper mapper = new ObjectMapper();
JsonNode pathNode = mapper.readTree(responseAsString);
Response response = mapper.convertValue(pathNode, Response.class);