2

I'm retrieving a JSON string from an API using a RESTEasy client. The JSON payload looks something like this:

{
  "foo1" : "",
  "foo2" : "",
  "_bar" : {
    "items" : [
      { "id" : 1 , "name" : "foo", "foo" : "bar" },
      { "id" : 2 , "name" : "foo", "foo" : "bar" },
      { "id" : 3 , "name" : "foo", "foo" : "bar" },
      { "id" : 4 , "name" : "foo", "foo" : "bar" }
    ]
  }
}

Now I'd like to extract only the items node for object mapping. What is the best way to intercept the JSON response body and modify it to have items as root node?

I'm using the RESTEasy proxy framework for my API methods.

The REST client code:

ResteasyWebTarget target = client.target("https://"+server);
target.request(MediaType.APPLICATION_JSON);
client.register(new ClientAuthHeaderRequestFilter(getAccessToken()));
MyProxyAPI api = target.proxy(MyProxyAPI.class);
MyDevice[] result = api.getMyDevice();

RESTEasy proxy interface:

public interface MyProxyAPI {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/device")
    public MyDevice[] getMyDevices();

    ...
}
cassiomolin
  • 124,154
  • 35
  • 280
  • 359
Martin Peter
  • 3,565
  • 2
  • 23
  • 26
  • Convert to the Javascript object and retrieve it as a Object. – SaviNuclear Sep 08 '16 at 11:46
  • Is it important that `items` be the root, or just that you don't want to map any other elements of the message? Doing a quick look at RestEasy docs, you're using automatic marshalling/unmarshalling to Java beans, through a JAXB provider? – dbreaux Sep 08 '16 at 16:25
  • @dbreaux Yes, I just don't want to map any other elements. See my edit of the OP for a simplified implementation code. I could of course register a provider to change the message body but I wonder how the implementation of such provider would look like. – Martin Peter Sep 09 '16 at 08:29
  • When the mapping is done automatically, why add the complexity of preprocess the response and not simply extract the objects afterwards? – Smutje Sep 09 '16 at 08:31
  • 1
    I think, I would need to model the complete Json structure in java, which i consider messy. In reality there is a whole lot more objects around my "items" node. – Martin Peter Sep 09 '16 at 08:36
  • Depends on you finally, but have in mind that when preprocessing the response you also store model knowledge - as processing information. It would save you from storing the model knowlede persistently but model changes will be harder to comprehend as you have to understand changes in the process rather than in the structure. – Smutje Sep 09 '16 at 08:53

2 Answers2

3

I had the same desire to not have to define complex Java classes for messages that contain way more fields than I care about. In my JEE server (WebSphere), Jackson is the underlying JSON implementation, which does appear to be an option with RESTEasy. Jackson has an @JsonIgnoreProperties annotation that can ignore unknown JSON fields:

import javax.xml.bind.annotation.XmlType;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;

@XmlType
@JsonIgnoreProperties(ignoreUnknown = true)
public class JsonBase {}

I don't know if other JSON implementations have a similar capability, but it certainly seems a natural use-case.

(I also wrote a blog post with this and some other JAX-RS techniques relevant to my WebSphere environment.)

dbreaux
  • 4,982
  • 1
  • 25
  • 64
  • It's a nice solution, but it might not work for the situation described by the OP. The `items` node is a child of `_bar` and not a child of the root node. – cassiomolin Sep 09 '16 at 14:54
  • You can still do this by defining wrapper classes which have almost nothing in them. In my case, this was better than the alternatives. – dbreaux Sep 09 '16 at 14:55
1

You could create a ReaderInterceptor and use Jackson to manipulate your JSON:

public class CustomReaderInterceptor implements ReaderInterceptor {

    private ObjectMapper mapper = new ObjectMapper();

    @Override
    public Object aroundReadFrom(ReaderInterceptorContext context) 
                      throws IOException, WebApplicationException {

        JsonNode tree = mapper.readTree(context.getInputStream());
        JsonNode items = tree.get("_bar").get("items");
        context.setInputStream(new ByteArrayInputStream(mapper.writeValueAsBytes(items)));
        return context.proceed();
    }
}

Then register the ReaderInterceptor created above in your Client:

Client client = ClientBuilder.newClient();
client.register(CustomReaderInterceptor.class);
cassiomolin
  • 124,154
  • 35
  • 280
  • 359
  • 1
    Actually, one of your answers to another question might be a simple solution to this too: http://stackoverflow.com/a/38352932/796761 – dbreaux Sep 09 '16 at 17:02
  • 1
    Your older solution linked by dbreaux (getting the JSON and accessing the desired node via the Jackson tree) is what I was doing as a workaround until now. This of course won't work with the proxy framework. I will try the interceptor. Thanks. – Martin Peter Sep 12 '16 at 08:47
  • @MartinPeter Sure! Try it an let me know if it works for you :) – cassiomolin Sep 12 '16 at 08:51