Looping rest api - java

I've REST API which exposes the JSON with a link to the next page and data as shown below:
{
"nextPageLink" : "rest_api_url_to_next_page"
"myData" : [ {
"key" : {
"d1" : "d1_value",
"d2" : "d2_value"
},
"productData" : {
"d3" : "d3_value",
"d4" : "d4_value"
}
"d5" : "d5_value",
"d6" : "d6_value"
}
There are around 1000s of pages with nextPageLink. On the last page, its empty. Can you please guide me how to design this in java. Also, I've such 10 more different REST APIs to handle.
My approach:
Create 2 pojos, one for key (keyPojo) and another for rest of the data(restDataPojo). Create a map with key as keyPojo and value as restDataPojo.
Create a pojo which has all the values, and dump data in the list of type pojo.
Is there any better approach to store such data? is this approach efficient enough?

The 'standard' solution to this sort of problem recommended by the RESTful Web Services Cookbook is to have an array of links tagged by a relationship type (typically called rel).
A typical 'page' would look like this:
{
"links": [{
"rel": "previous",
"href": "http://example.com/pages/41"
},
{
"rel": "next",
"href": "http://example.com/pages/43"
}
],
"otherAttributes": "go here"
}
On the first page, you omit the previous link:
{
"links": [
{
"rel": "next",
"href": "http://example.com/pages/43"
}
],
"otherAttributes": "go here"
}
and on the last page, you omit the next link:
{
"links": [{
"rel": "previous",
"href": "http://example.com/pages/41"
}
],
"otherAttributes": "go here"
}
Since links is an array, you can back all three cases with the same underlying DTO.

Related

Read hateoas response with embedded HAL collection with spring

I'm trying to read a REST HATEOAS response like this one :
{
"_embedded": {
"tasks": [
{
"id": 1,
"name":"task1"
"_links": {
"self": {
"href": "http://localhost:8080/v1/tasks/1"
},
"tasks": {
"href": "http://localhost:8080/v1/tasks"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/v1/tasks?page=0&size=1"
}
},
"page": {
"size": 1,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}
I'm trying to folloaw the example of spring's documentation : spring hateoas traverson.
Java code :
...
TypeReferences.ResourcesType<Resources<Task>> resourceParameterizedTypeReference = new TypeReferences.ResourcesType<Resources<Task>>(){};
Traverson traverson = new Traverson(new URI("http://localhost:8080/v1/tasks"), MediaTypes.HAL_JSON);
Traverson.TraversalBuilder builder = traverson.follow(rel("tasks")).withHeaders(headers);
Resources<Resources<Task>> taskResources = builder.toObject(resourceParameterizedTypeReference);
...
But I obtain this error :
Did not find LinkDiscoverer supporting media type text/html!
Cause : "follow(rel("tasks"))" don't find "tasks".
I'm trying other solutions like this one :
Deserialize JSON containing (_links and _embedded) using spring-hateoas, I obtain the error "Expected to find link with rel ..." too.
Maybe finaly I'm not understand the good manner to use traverson object.
I solve my problem by parsing myself the response in Json, but are they another way to get the list contains in the "_embedded" tags in a list of beans ?
If you have some examples I'm interesting :).
I think you need to use a Json Path expression to access the embedded content.
Traverson.TraversalBuilder builder = traverson.follow("$._embedded.tasks[0]").withHeaders(headers);
Resources<Resources<Task>> taskResources = builder.toObject(resourceParameterizedTypeReference);
The following tool is useful for playing with the path expression: http://www.jsonquerytool.com/
BTW, your JSON is missing a "," after the "name".

JSONPath and Traverson filtering: single element array

Here is the Json I am trying to handle with Traverson to extract a single link from this HAL:
{
"_links": {
"curies": [
{
"href": "https://localhost/auth/def/rels/{rel}",
"name": "auth",
"templated": true
}
],
"self": {
"href": "https://localhost/auth/identity"
}
},
"_embedded": {
"auth": [
{
"_links": {
"auth:ad": [
{
"href": "https://localhost/auth/ad"
}
]
},
"kind": "oauth2"
},
{
"_links": {
"auth:default": [
{
"href": "https://localhost/auth/default" // **Link that I need**
}
]
},
"kind": "oauth2"
}
]
}
}
Java code responsible for handling ideally should look like this:
Link test = traverson
.follow("auth")
.follow("$.['_embedded']['auth']..['_links']['auth:default']..['href'][0]")
.asLink();
But for some reason I am getting no hits despite the fact that right before adding the last [0] in the JSONPath expression I am getting an array of one element. Is there a way to extract this single link so that I am not returned with an array? I used this tool for testing.
The code necessary to achieve what I should look like this:
JsonPathLinkDiscoverer disc = new JsonPathLinkDiscoverer("$._embedded..auth.._links..['%s']..href", MediaTypes.HAL_JSON);
Link authLink = disc.findLinksWithRel("auth:default", <json>).get(0);
where <json> should be the json representation of the example in the original question (probably like a reponse from other call).

Jackson map JSON containing different items for same object

I've got the follwoing JSON structure with the corresponding DTOs in Java:
{
"kind": "object 1",
"selfLink": "some_link",
"items": [
{
"kind": "subkind 1",
"name": "server 1",
"anotherObject": {
"link": "some_link",
"isSubcollection": true,
"items": [
{
"att 1": "value",
"att2": "value",
"att3": "value"
},
{
"att5": "value" ,
"att6": "value" ,
"att7": "value" ,
"att8": "value"
}
]
}
}
]
}
Now I want to map this into corresponding DTOs using Jackson. Using the #JsonIgnoreUnknown annotation, this works fine. The problem is within the items array: How can I map different classes from the same JSON list in Jackson? Of course I could create a huge class containing both's attributes, but that would not be my way of choice.
I hope you can help me.

Show JSON data in grid in vaadin

Am a new bee to vaadin. I have to show the data from a JSON file (which is fetching from MySQL db) in Grid/Table(vaadin). I am able show the data in table if JSON in the below format.
[
{
"id": "ex-wardrobe",
"productId": "ex-wardrobe",
"name": "exWardrobe",
"desc": "Some description",
"dimension": "WxDxH 148\" X 24\" X 112\" ",
"category": "Bedroom",
"subcategory": "Wardrobe",
"categoryId": "bedroom",
"subcategoryId": "wardrobe",
"tags": "all, Space Design Bedroom, Space Details Wardrobe",
"designer": "hb",
"curr": "INR",
"popularity": "1",
"relevance": "1",
"shortlisted": "1",
"likes": "1",
"createDt": "",
"pageId": "ex-wardrobe",
"styleName": "Fresh",
"styleId": "cfresh",
"priceRange": "Premium",
"priceId": "premium",
"defaultPrice": "123",
"defaultMaterial": "MDF ",
"defaultFinish": "LAMINATE"
}
]
But, if i get JSON(data is related to same product) in the below format am unable to add data in table.
[
{
"id": "ex-wardrobe",
"productId": "ex-wardrobe",
"name": "exWardrobe",
"desc": "Some description",
"dimension": "WxDxH 148\" X 24\" X 112\" ",
"category": "Bedroom",
"subcategory": "Wardrobe",
"categoryId": "bedroom",
"subcategoryId": "wardrobe",
"tags": "all, Space Design Bedroom, Space Details Wardrobe",
"designer": "hb",
"curr": "INR",
"popularity": "1",
"relevance": "1",
"shortlisted": "1",
"likes": "1",
"createDt": "",
"pageId": "ex-wardrobe",
"styleName": "Fresh",
"styleId": "cfresh",
"priceRange": "Premium",
"priceId": "premium",
"defaultPrice": "123",
"defaultMaterial": "MDF ",
"defaultFinish": "LAMINATE",
"mf": [
{
"basePrice": "123",
"material": "MDF ",
"finish": "LAMINATE"
}
],
"images": [
"066___ex_WARDROBE_Dim.jpg",
"067___ex_WARDROBE_close_door.jpg",
"068___ex_DOVE_dim.jpg"
],
"components": [],
"accessories": []
}
]
This is the code which am using to show JSON data in table,
Table grid = new Table();
root.addComponent(grid);
grid.setStyleName("iso3166");
grid.setPageLength(6);
grid.setSizeFull();
grid.setSelectable(true);
grid.setMultiSelect(false);
grid.setImmediate(true);
grid.setColumnReorderingAllowed(true);
grid.setColumnCollapsingAllowed(true);
try {
JSONArray products = productsDataProvider.getCatalogs();
JsonContainer dataSource =
JsonContainer.Factory.newInstance(products.toString());
grid.setContainerDataSource(dataSource);
grid.setColumnReorderingAllowed(true);
grid.setWidth("98%");
grid.addStyleName(ChameleonTheme.TABLE_STRIPED);
} catch (IllegalArgumentException ignored) {
}
grid.setWidth("100%");
grid.setHeight("100%");
root.addComponent(grid);
Am stuck on this and i have sleepless night on this. Million tons of thanks in advance. I hope you GURU's can help me in this :)
Sorry not vaadin expert. See it first time and like it. I guess your problem are the arrays inside your object. I mean this:
"mf": [
{
"basePrice": "173881",
"material": "MDF ",
"finish": "LAMINATE"
}
],
"images": [
"066___ex_WARDROBE_Dim.jpg",
"067___ex_WARDROBE_close_door.jpg",
"068___ex_DOVE_dim.jpg"
],
"components": [],
"accessories": []
No idea how the component should display this. Have you tried it without mf, images, components and accessories?
You are using a very simple JSONContainer. As can be seen in the source code, this implementation does not support nested / compound elements and arrays.
First you have to ask yourself how these complex objects need to be displayed (UX), especially the "mf" field.
UPDATE
Simple compound objects (like "simpleCompound": {"name": "foo", number: 123}) can be shown in a table column (not supported by the JSONContainer you use, but similar functionality is available by the BeanItemContainer, so look there for how to implement this functionality).
The array fields are more problematic from a UX standpoint. Mostly this information is only shown on demand or in separate panels. The Vaadin Grid component offers the possibility to show a details view, see the wiki. Maybe that will fit your requirements.
Currently nested json data is not supported unless you create your own advance template for that. There is currently an online json container application demo that is used to test if the data is really json or json array but not nested. Then it displays that data in grid table. So you can use this to verify your data.
You can also get the application template with source code on github

Most memory efficient way to re format a JSON array in Java

Say I have a JSON array similar to the following:
[
{
"title": "This is a title",
"year": 2013,
"images": {
"image": "http://........jpg",
},
"ratings": {
"thumbsup": 1053,
"thumbsdown": 256
}
},
{
"title": "This is a title",
"year": 2013,
"images": {
"image": "http://........jpg",
},
"ratings": {
"thumbsup": 1053,
"thumbsdown": 256
}
}
]
And the required output is a JSON array like this:
[
{
"title": "This is a title",
"images": {
"image": "http://........jpg",
},
"ratings": {
"thumbsup": 1053,
}
},
{
"title": "This is a title",
"images": {
"image": "http://........jpg",
},
"ratings": {
"thumbsup": 1053,
}
}
]
Iv'e been researching and it's suggested that the most efficient way would be to parse it using the Jackson streaming API. This is for use on a PaaS with limited memory, so I wish to keep the memory usage to the bare minimum.
Is the best way to parse the JSON with Jackson Streaming API, and construct a new JSON array at the same time or simply remove the elements somehow?
I did something similiar with XML once. You can have the requestor tell you what fields you want to get back, and have it only emit those. In my case I had no control over the 3rd party axis xml view, but once I had the view, when I asked for things from it if it was already there I could give back just the pieces I was interested in. As a bonus, if you are marshalling or unmarshalling real java objects from the JSON after getting the json or XML you don't need to build the part of the object graph you don't care about.

Categories

Resources