I have an API which returns the following schema for all requests to collections of models:
{
item_count: 83,
items_per_page: 25,
offset: 25,
<Model>s: [
{ ... },
{ ... },
{ ... },
...
]
}
For instance, if I make a request to /api/v1/customers then this JSON will contain a customers key. If I make a request to /api/v1/products then this JSON will contain a products key.
I with to create a generic PaginatedResponse<T> class to handle the item_count, items_per_page, and offset variables like so:
public class PaginatedResponse<T> {
private int item_count;
private int items_per_page;
private int offset;
private List<T> data;
public PaginatedResponse<T>(int item_count, int items_per_page, int offset, List<T> data) {
this.item_count = item_count;
this.items_per_page = items_per_page;
this.offset = offset;
this.data = data;
}
public List<T> getData() {
return this.data;
}
}
Is there a way to parse this JSON into my PaginatedResponse POJO?
As you have different keys for model list, <Model>s:, IMHO, you better use different models for each response. You have to remove private List<T> data; from the base response model and move it to the child model.
I've modified your code and created some sample models for your products and customers. Below given detailed example,
BasePaginatedResponse.java
public class BasePaginatedResponse {
private int item_count;
private int items_per_page;
private int offset;
public BasePaginatedResponse(
int item_count, int items_per_page, int offset) {
this.item_count = item_count;
this.items_per_page = items_per_page;
this.offset = offset;
}
}
CustomersResponse.java
public class CustomersResponse extends BasePaginatedResponse {
private final List<Customer> customers;
public CustomersResponse(int item_count, int items_per_page, int offset, List<Customer> customers) {
super(item_count, items_per_page, offset);
this.customers = customers;
}
public List<Customer> getCustomers() {
return customers;
}
public class Customer {
private final String id, name;
public Customer(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
}
ProductsResponse.java
public class ProductsResponse extends BasePaginatedResponse {
private final List<Customer> products;
public ProductsResponse(int item_count, int items_per_page, int offset, List<Customer> products) {
super(item_count, items_per_page, offset);
this.products = products;
}
public List<Customer> getProducts() {
return products;
}
public class Customer {
private final String id, name;
public Customer(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
}
Here, I've created 3 classes. 1 base response class (parent), and 2 child classes.
Parent class contains fields that are common to both child classes.
As you're using Retrofit, your ApiInterface should be something like this
interface ApiInterface{
#GET("api/v1/customers")
Call<CustomersResponse> getCustomers();
#GET("api/v1/products")
Call<ProductsResponse> getProducts();
}
If you need more clarification, ask me in the comments.
Related
I would like to iterate Products and get the list of name,code and price and set in my Model class. Any help would be really appreciated - how can I iterate this. When I use obj.get("Products") - it just printing as string - got stuck to iterate.
{
"id": "skd3303ll333",
"Products": [{
"name": "apple",
"code": "iphone-393",
"price": "1939"
},
{
"name": "ipad",
"code": "ipad-3939",
"price": "900"
}
]
}
#PostMapping(path="/create", consumes=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> create(#RequestBody Map<String, Object> obj ) {
System.out.println("Products :" + obj.get("Products"));
}
There are two ways to do this,
1) By type casting (personally i will not prefer this)
List<Map<Object,Object>> productslist = (List<Map<Object, Object>>) obj.get("products");
for(Map entry: productslist) {
for(Object s: entry.keySet()) {
System.out.println(s.toString());
System.out.println(entry.get(s).toString());
}
}
2) Mapping directly to Model class, for this approach you need Jackson library in buildpath
#JsonIgnoreProperties(unknown =true)
public class Customer {
#JsonProperty("id")
private String id;
#JsonProperty("products")
private List<Products> products;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<Products> getProducts() {
return products;
}
public void setProducts(List<Products> products) {
this.products = products;
}
}
#JsonIgnoreProperties(unknown =true)
class Products{
#JsonProperty("name")
private String name;
#JsonProperty("code")
private String code;
#JsonProperty("price")
private String price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
Controller
public ResponseEntity<Object> create(#RequestBody Customer obj ) {
You need POJO structure with two classes:
public class Product {
private String name;
private String code;
private int price;
}
public class ProductsGroup {
private long id;
private List<Product> products;
// getters/setters
}
And change your method signature to:
#PostMapping(path="/create", consumes=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ProductsGroup> create(#RequestBody ProductsGroup productGroup)
{
System.out.println("Products :" + productGroup.getProducts());
}
You are trying to process the json using a Map<String, Object> obj, which could be possible in some way, but mostly what you want to do is define a single or multiple POJO classes. These represent the json.
public class IdWrapper {
private String id;
#JsonProperty("Products")
private List<Product> products;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<Product> getProducts() {
return products;
}
}
public class Product {
private String name;
private String code;
private String price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
And in you controller like this:
#RestController
#RequestMapping("test")
public class DemoController {
#PostMapping()
public void test(#RequestBody IdWrapper productsWrapper) {
System.out.println();
}
}
In Java project I used WebSocket to get subscription and I get many different responses from socket as JSONArray, the one which I need looks as below:
[
68,
"te",
[
80588348,
1508768162000,
0.01569882,
5700.8
]
]
How should look JAVA object for this response?
How can I convert it to this object?
[
68, <- Integer
"te", <- String
[
80588348, <- Long
1508768162000, <- Long
0.01569882, <- Double
5700.8 <- Double
]
]
There is one problem that there are other responses like:
{"event":"subscribed","channel":"trades","chanId":68,"symbol":"tBTCUSD","pair":"BTCUSD"}
And when I try convert it by new JSONArray(response) it throws org.json.JSONException: A JSONArray text must start with '[' at 1 [character 2 line 1].
How to get and convert this fields which I need(the first response example) ?
I want get something like this:
public class Details{
public Long id;
public Long timestamp;
public Double amount;
public Double price;
}
public class Response{
public Integer id;
public String type;
public Details details;
}
The parser class as requested:
public class JsonParser {
public static Response toJavaObject(String str) {
String[] fields = str.split(",");
Response res = new Response();
res.setId(Integer.valueOf(fields[0].substring(1)));
res.setType(fields[1].replaceAll("\"", ""));
Details dtl = new Details();
dtl.setId(Long.valueOf(fields[2].substring(1)));
dtl.setTimestamp(Long.valueOf(fields[3]));
dtl.setAmount(Double.valueOf(fields[4]));
dtl.setPrice(Double.valueOf(fields[5].substring(0, fields[5].length() - 2)));
res.setDetails(dtl);
return res;
}
}
class Details {
public Long id;
public Long timestamp;
public Double amount;
public Double price;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
public Double getAmount() {
return amount;
}
public void setAmount(Double amount) {
this.amount = amount;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
}
class Response {
public Integer id;
public String type;
public Details details;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Details getDetails() {
return details;
}
public void setDetails(Details details) {
this.details = details;
}
}
To make use of this JsonParser,
for example in your code now:
public static void main(String args[]) {
String str = "[68,\"te\",[80588348,1508768162000,0.01569882,5700.8]]";
Response res = JsonParser.toJavaObject(str);
// your logic below...
}
If your response is in fixed format,
example:
JSONString : {"color":"yellow","type":"renault"}
In Java, you can use the following code:
Car car = objectMapper.readValue(jsonString, Car.class);
Where you have the Car class as:
public class Car {
private String color;
private String type;
// standard getters setters
}
I'm having trouble trying to understand how realm.io persist/save objects.
I have 3 Objects (Inventory, InventoryItem and Product);
When I create a Inventory containing InventoryItems it works fine until i close the app. When i re-open the app all InventoryItems loses the reference to Product and start to show "null" instead.
Strange thing is all other attributes like Inventory reference to InventoryItem is persisted fine. Just problem with Products.
this is how i'm trying to do:
Model
Product
public class Product extends RealmObject {
#PrimaryKey
private String id;
#Required
private String description;
private int qtdUnityType1;
private int qtdUnityType2;
private int qtdUnityType3;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getQtdUnityType1() {
return qtdUnityType1;
}
public void setQtdUnityType1(int qtdUnityType1) {
this.qtdUnityType1 = qtdUnityType1;
}
public int getQtdUnityType2() {
return qtdUnityType2;
}
public void setQtdUnityType2(int qtdUnityType2) {
this.qtdUnityType2 = qtdUnityType2;
}
public int getQtdUnityType3() {
return qtdUnityType3;
}
public void setQtdUnityType3(int qtdUnityType3) {
this.qtdUnityType3 = qtdUnityType3;
}
}
Inventory
public class Inventory extends RealmObject {
#PrimaryKey
private String id;
#Required
private String type;
#Required
private Date createdAt;
#Required
private String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
private RealmList<InventoryItem> listItems;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public RealmList<InventoryItem> getListItems() {
return listItems;
}
public void setListItems(RealmList<InventoryItem> listItems) {
this.listItems = listItems;
}
}
InventoryItem
public class InventoryItem extends RealmObject {
#PrimaryKey
private String idItem;
private Inventory inventory;
private Product product;
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
private Date expirationDate;
private int qtdUnityType1;
private int qtdUnityType2;
private int qtdUnityType3;
private int qtdDiscard;
public String getIdItem() {
return idItem;
}
public void setIdItem(String idItem) {
this.idItem = idItem;
}
public Inventory getInventory() {
return inventory;
}
public void setInventory(Inventory inventory) {
this.inventory = inventory;
}
public Date getExpirationDate() {
return expirationDate;
}
public void setExpirationDate(Date expirationDate) {
this.expirationDate = expirationDate;
}
public int getQtdUnityType1() {
return qtdUnityType1;
}
public void setQtdUnityType1(int qtdUnityType1) {
this.qtdUnityType1 = qtdUnityType1;
}
public int getQtdUnityType2() {
return qtdUnityType2;
}
public void setQtdUnityType2(int qtdUnityType2) {
this.qtdUnityType2 = qtdUnityType2;
}
public int getQtdUnityType3() {
return qtdUnityType3;
}
public void setQtdUnityType3(int qtdUnityType3) {
this.qtdUnityType3 = qtdUnityType3;
}
public int getQtdDiscard() {
return qtdDiscard;
}
public void setQtdDiscard(int qtdDiscard) {
this.qtdDiscard = qtdDiscard;
}
}
and finally one of the millions ways i tried to persist
realm.beginTransaction();
Inventory inventory = realm.createObject(Inventory.class);
inventory.setId(id);
inventory.setCreatedAt(new DateTime().toDate());
if (radioGroup.getCheckedRadioButtonId() == R.id.rbInventario) {
inventory.setType("Inventário");
} else {
inventory.setType("Validade");
}
inventory.setStatus("Aberto");
RealmList<InventoryItem> inventoryItems = new RealmList<>();
RealmResults<Product> productsRealmResults = realm.allObjects(Product.class);
for (int i = 1; i <= productsRealmResults.size(); i++) {
InventoryItem item = realm.createObject(InventoryItem.class);
item.setIdProduct(productsRealmResults.get(i - 1).getId() + " - " + productsRealmResults.get(i - 1).getDescription());
item.setProduct(productsRealmResults.get(i - 1));
item.setIdItem(i + "-" + id);
item.setInventory(inventory);
item = realm.copyToRealmOrUpdate(item);
item = realm.copyToRealmOrUpdate(item);
inventoryItems.add(item);
}
inventory.setListItems(inventoryItems);
realm.copyToRealmOrUpdate(inventory);
realm.commitTransaction();
I already looked trough some answers here like this one:
stack answer
and the Java-examples (person, dog, cat)
provided with the API
but I can't understand how to properly insert this.
The problem is that you are setting a list of InventoryItem elements which are not added to the Realm database.
Change InventoryItem item = new InventoryItem(); to InventoryItem item = realm.createObject(InventoryItem.class);
Also, the inventoryItems themselves aren't stored in Realm db. Add realm.copyToRealmOrUpdate(inventoryItems) after the loop.
I have a object structure like the following:
public class Product {
int id;
String name;
Size[] sizes;
boolean organic;
}
public class Size {
int id;
String value;
#JsonIgnore String info;
}
While parsing the JSON for the Product class, I want to set the info for each of the sizes to the String "Organic". In the setter for the organic property I check the value and iterate over the sizes, setting the info for each.
#JsonProperty("organic")
public void setOrganic(boolean organic) {
this.organic = organic;
if (organic)
for(Size size : sizes) size.info = "Organic";
}
First, this approach seems to be brittle as it depends on the order of properties in the JSON and secondly, it doesn't always seem to work. For a production environment, where JSON has a lot more properties, I seem to be able to set the properties on the sub-object (Size here) and read and log them during parsing but when I read it from the final deserialized object, those values are always null. Again, this behavior seems to be different for the smaller test cases I set up to test.
Does anyone know of a better way to do this ?
The appropriate place to do this would be outside of these classes and some place where this type of business logic is more appropriate.
You could create a Builder class that allows you to set all of the properties for the resulting object and when the build() method that constructs the final object is called, set any additional values as appropriate. You would apply the Jackson annotations to the Builder class then, and apply any validation to it instead of the class that it creates. This way, you guarantee that any instance of a Product would be complete and valid.
If you take my original suggestion and move the logic into a business layer of your application then you would simply pass the Builders to the appropriate method, check the value of organic on the Product.Builder, and then iterate over the Size.Builder list and change their info values appropriately.
Using the Builders to hold the logic might look something like this (the logic you're looking for is all the way at the bottom):
public class Size {
private final int id;
private final String value;
private final String info;
public Size(int id, String value, String info) {
this.id = id;
this.value = value;
this.info = info;
}
public int getId() {
return id;
}
public String getValue() {
return value;
}
public String getInfo() {
return info;
}
public static class Builder {
private int id;
private String value;
private String info;
public Builder setId(int id) {
this.id = id;
return this;
}
public Builder setValue(String value) {
this.value = value;
return this;
}
#JsonIgnore
public Builder setInfo(String info) {
this.info = info;
return this;
}
public Size build() {
return new Size(id, value, info);
}
}
}
public class Product {
private final int id;
private final String name;
private final Size[] sizes;
private final boolean organic;
public Product(int id, String name, Size[] sizes, boolean organic) {
this.id = id;
this.name = name;
this.sizes = sizes;
this.organic = organic;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public Size[] getSizes() {
return sizes;
}
public boolean isOrganic() {
return organic;
}
public static class Builder {
private int id;
private String name;
private List<Size.Builder> sizeBuilders;
private boolean organic;
public Builder setId(int id) {
this.id = id;
return this;
}
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setSizeBuilders(List<Size.Builder> sizeBuilders) {
this.sizeBuilders = sizeBuilders;
return this;
}
public Builder setOrganic(boolean organic) {
this.organic = organic;
return this;
}
public Product build() {
if (organic) {
for (Size.Builder sizeBuilder : sizeBuilders) {
sizeBuilder.setInfo("Organic");
}
}
Size[] sizes = new Size[sizeBuilders.size()];
for (int i = 0; i < sizeBuilders.size(); i++) {
sizes[i] = sizeBuilders.get(i).build();
}
return new Product(id, name, sizes, organic);
}
}
}
I am quite interested in a Hibernate mapping such as the Order/Product/LineItem described here:
http://docs.jboss.org/hibernate/stable/core/reference/en/html/example-mappings.html#example-mappings-customerorderproduct
The documentation seems quite thorough, but I am a bit unclear on the semantics of the Java classes that one would create...
Any hints much appreciated.
Thank you!
Misha
Using that example, you would have classes that looked like the following:
import java.util.HashSet;
import java.util.Set;
public class Customer {
private String name = null;
private Set<Order> orders = new HashSet<Order>();
private long id = 0;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class Order {
private long id = 0;
private Date date = null;
private Customer customer = null;
private List<LineItem> lineItems = new ArrayList<LineItem>();
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public List<LineItem> getLineItems() {
return lineItems;
}
public void setLineItems(List<LineItem> lineItems) {
this.lineItems = lineItems;
}
}
public class LineItem {
private int quantity = 0;
private Product product = null;
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
public class Product {
private long id = 0;
private String serialNumber = null;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getSerialNumber() {
return serialNumber;
}
public void setSerialNumber(String serialNumber) {
this.serialNumber = serialNumber;
}
}
If you create the tables as per the structure in the example, that should set you up.
They show the UML and the class members in the diagram.
A Customer can have zero to many Order objects (Set).
An Order has at least one to many LineItem objects. {List).
A LineItem entry corresponds to a Product. So LineItem has exactly one Product object.
Not sure what your question is?