Retrieving multiple JSON objects from a JSON array within another JSON array? - java

For a college assignment I need to create an app that retrieves product data from the API of a well known Dutch online store. I need to store the title, summary, price and image URLs of each product into a new Product object. These Products are stored into an ArrayList and the ArrayList is then returned.
Each product within the products array has a nested array called "images", which contains 6 product images. These images need to stored into my Product object's HashMap attribute, with the image size as key and the URL as value. However, I can't seem to get it right.
JSON data with the query "pokemon": https://api.bol.com/catalog/v4/search/?apikey=25C4742A92BF468EB2BD888FC8FBFF40&format=json&q=pokemon
Product class:
package com.example.bolcombrowser.domain;
import java.util.Map;
public class Product {
// Attributes
private String mTitle;
private String mSummary;
private double mPrice;
private Map < String, String > mImageUrls;
// Constructor
public Product(String mTitle, String mSummary, double mPrice, Map < String, String > mImageUrls) {
this.mTitle = mTitle;
this.mSummary = mSummary;
this.mPrice = mPrice;
this.mImageUrls = mImageUrls;
}
// Getters and Setters
public String getmTitle() {
return mTitle;
}
public void setmTitle(String mTitle) {
this.mTitle = mTitle;
}
public String getmSummary() {
return mSummary;
}
public void setmSummary(String mSummary) {
this.mSummary = mSummary;
}
public double getmPrice() {
return mPrice;
}
public void setmPrice(double mPrice) {
this.mPrice = mPrice;
}
public Map < String, String > getImageUrls() {
return mImageUrls;
}
public void setImageUrls(Map < String, String > imageUrls) {
this.mImageUrls = imageUrls;
}
}
parseJson method:
public static ArrayList < Product > parseJson(String productJsonStr) throws JSONException {
/* JSON array names. */
final String BOL_PRODUCTS = "products";
final String BOL_IMAGES = "images";
final String BOL_OFFERS = "offers";
/* JSON key names. */
final String BOL_TITLE = "title";
final String BOL_SUMMARY = "summary";
final String BOL_OFFERDATA = "offerData";
final String BOL_PRICE = "price";
final String BOL_KEY = "key";
final String BOL_URL = "url";
/* Variables to store product data into, and is then used to create new Product objects. */
String title;
String summary;
double price;
Map < String, String > imageUrls = new HashMap < > ();
/* ArrayList to store products into. */
ArrayList < Product > productList = new ArrayList < > ();
JSONObject productsJson = new JSONObject(productJsonStr);
JSONArray productsArray = productsJson.getJSONArray(BOL_PRODUCTS);
for (int i = 0; i < productsArray.length(); i++) {
JSONObject product = productsArray.getJSONObject(i);
/* Retrieve the title and summary of each product. */
title = product.getString(BOL_TITLE);
summary = product.getString(BOL_SUMMARY);
JSONArray imagesArray = product.getJSONArray(BOL_IMAGES);
for (int j = 0; j < imagesArray.length(); j++) {
JSONObject image = imagesArray.getJSONObject(j);
/* Retrieve each product's image sizes and URLs and store them into a HashMap. */
String imageSize = image.getString(BOL_KEY);
String imageUrl = image.getString(BOL_URL);
imageUrls.put(imageSize, imageUrl);
}
JSONObject offerData = product.getJSONObject(BOL_OFFERDATA);
JSONArray offers = offerData.getJSONArray(BOL_OFFERS);
JSONObject offer = offers.getJSONObject(0);
price = offer.getDouble(BOL_PRICE);
productList.add(new Product(title, summary, price, imageUrls));
}
return productList;
}
onPostExecute method:
#Override
protected void onPostExecute(String productData) {
if (productData != null) {
ArrayList < Product > productList;
try {
productList = JsonUtils.parseJson(productData);
for (Product product: productList) {
String title = product.getmTitle();
String summary = product.getmSummary();
double price = product.getmPrice();
String hashMap = product.getImageUrls().toString();
mTextViewOutput.append(title + "\n\n" + summary + "\n\n" + price + "\n\n" +
hashMap + "\n\n\n\n\n");
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
When I test out my app, it seems to have stored the image URLs of the last product into every product's HashMap:
I've been staring at my code for hours and I can't seem to find out why it does this. I'm probably making a very silly mistake but I just can't seem to figure out what it is exactly.

Your Map<String, String> imageUrls = new HashMap<>(); is in the wrong place. It should be inside your first for loop, otherwise you are using the same Map for all your products.
...
for (int i = 0; i < productsArray.length(); i++) {
Map<String, String> imageUrls = new HashMap<>();
...
By the way, I suggest using gson library. It will make your code less boilerplate

Related

How to put Gson value into HashMap

I have a Firebase database and I want to store users information in my app. In my firebase database, I have 4 string and 1 arraylist like this..
I want to store these values in my app with using SharedPreferences. I did retrieve Phone number, Birthdate, First name and Gender and I stored into a Hashmap. But I couldn't get User hobbies. I use Gson library for User hobbies, but I don't know how to use with other string values.
public static final String IS_LOGIN = "IsLoggedIn";
public static final String KEY_NAME = "name";
public static final String KEY_BIRTHDATE = "birthdate";
public static final String KEY_GENDER = "gender";
public static final String KEY_PHONE = "phone";
public static final String KEY_HOBBIES = "hobbies";
public SessionManager(Context _context) {
context = _context;
usersSession = _context.getSharedPreferences("userLoginSession", Context.MODE_PRIVATE);
editor = usersSession.edit();
}
public void createLoginSession(String name, String birthdate, String gender, String phone, ArrayList<String> hobby) {
Gson gson = new Gson();
String json = gson.toJson(hobby);
editor.putBoolean(IS_LOGIN, true);
editor.putString(KEY_NAME, name);
editor.putString(KEY_BIRTHDATE, birthdate);
editor.putString(KEY_GENDER, gender);
editor.putString(KEY_PHONE, phone);
editor.putString(KEY_HOBBIES, json);
editor.commit();
}
public HashMap<String, String> getUsersDetailFromSession() {
HashMap<String, String> userData = new HashMap<String, String>();
userData.put(KEY_NAME, usersSession.getString(KEY_NAME, null));
userData.put(KEY_BIRTHDATE, usersSession.getString(KEY_BIRTHDATE, null));
userData.put(KEY_GENDER, usersSession.getString(KEY_GENDER, null));
userData.put(KEY_PHONE, usersSession.getString(KEY_PHONE, null));
return userData;
}
In createLoginSession, I defined a gson variable and I used putString value to KEY_HOBBIES like other strings. What should I do to put User Hobbies with other strings in Hashmap function? I want to load and read all datas in Hashmap. My english is not very good, thank you for all.
You can use jsonArray like this
JSONArray jsonArray = object.getJSONArray("response");
for (int i = 0; i <= jsonArray.length(); i++)
{
JSONObject obj = jsonArray.getJSONObject(i);
//here you use your objects
}

Java count method for duplicate element in array List

say I have an array List of type Order Details
private static List<OrderDetails> orderDetails = new ArrayList<OrderDetails>();
and the fields in orderDetails are
private String productCode = null;
private int revenue = 0;
my arrayList contains the values`
A012 69
A012 36
I need to change the output of the list so that if something is added to the list of the same productCode the revenues get added together
so the output of the example above would be
A012 105
how will the method work
This should work assuming you have the appropriate getters for the class. It just creates a stream of OrderDetails objects, filters out null productCodes and creates a map of the revenue sums.
Map<String,Integer> results = orderDetails.stream()
.filter(od->od.getProductCode() != null)
.collect(Collectors.groupingBy(OrderDetails::getProductCode,
Collectors.summingInt(OrderDetails::getRevenue)));
If desired, you can then return the values back to a list by creating a new instance of each OrderDetails class.
orderDetails = results.entrySet().stream()
.map(e->new OrderDetails(e.getKey(), e.getValue()))
.collect(Collectors.toList());
Using a map might be more useful since you can get the revenue for any product code.
For example
System.out.println(results.get("A012"));
The small code snippet by using a Map as below may be helpful:
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test {
private static List<OrderDetails> orderDetails = new ArrayList<OrderDetails>();
public static void main(String[] args) {
final OrderDetails o1 = new OrderDetails("A12", 69);
final OrderDetails o2 = new OrderDetails("A12", 36);
final OrderDetails o3 = new OrderDetails("A13", 136);
addToList(o1);
addToList(o2);
addToList(o3);
orderDetails.stream().map(orderDetail -> orderDetail.getProductCode() + " " + orderDetail.getRevenue()).forEach(System.out::println);
}
private static synchronized void addToList(OrderDetails orderDet) {
final Map<String, OrderDetails> map = orderDetails.stream().collect(Collectors.toMap(OrderDetails::getProductCode, orderDetail -> orderDetail, (a, b) -> b));
final OrderDetails objectFromMap = map.get(orderDet.getProductCode());
if (objectFromMap != null) {
objectFromMap.setRevenue(objectFromMap.getRevenue() + orderDet.getRevenue());
} else {
map.put(orderDet.getProductCode(), orderDet);
}
orderDetails.clear();
orderDetails.addAll(map.values());
}
}
class OrderDetails {
private String productCode = null;
private int revenue = 0;
public OrderDetails(String productCode, int revenue) {
this.productCode = productCode;
this.revenue = revenue;
}
public String getProductCode() {
return productCode;
}
public int getRevenue() {
return revenue;
}
public void setRevenue(int revenue) {
this.revenue = revenue;
}
}
You can use a Map like this:
Map<String, Integer> orderDetails = new new HashMap<>();
and use this method for adding a new order:
void addOrder(Order orderToAdd) {
Order findOrder = orderDetails.get(orderToAdd.productCode);
if (findOrder != null) {
findOrder.revenue += orderToAdd.revenue ;
} else {
orderDetails.put(orderToAdd.productCode, orderToAdd.revenue );
}
}

Process array list from map

We are trying to access the array of object that placed inside a map.
Can any one guide us to get length of the array as well as fetching each element from the list. Sample map object given bellow.
{
storeId = 1,
ShipToStreetLine1 = test 123,
ShipToCity = Seattle,
OrderDetails = [{
distributor_name = SS,
product_name = HORN 80897 AM GUN 300BO 125 HP 50/10
}]
}
We need to get the size of orderDetails array and if data present, then I want to fetch product_name.
You can try this:
Create a POJO which is type of what you are getting in orderDetails
Like
public class OrderDetailElement{
private String distributor_name;
private String product_name;
public String getDistributor_name() {
return distributor_name;
}
public void setDistributor_name(String distributor_name) {
this.distributor_name = distributor_name;
}
public String getProduct_name() {
return product_name;
}
public void setProduct_name(String product_name) {
this.product_name = product_name;
}
}
in your logic class you can do is
ArrayList<OrderDetailElement> orderDetails = yourMap.get("OrderDetails");
List<String> products = new ArrayList<String>();
if (orderDetails.size() > 0) {
for (OrderDetailElement orderDetailElement : orderDetails) {
products.add(orderDetailElement.getProduct_name());
}
}

java ArrayList with two columns

I have to update a table with two columns and I have created a class
public class Country {
private String url;
private String search;
public Country(String url, String search) {
this.url = url;
this.search = search;
}
// ...
}
List<Country> countries = new ArrayList<Country>();
countries.add(new Country(urls, txt));
...
Countries has a data {java.com.main#yfxse34567}
Could be {www.google.com, main string...}
How can I put a proper data into countries list
Override the toString() method
Example
List<Country> countries = new ArrayList<Country>() {
#Override
public String toString() {
String result = "{";
for (int index= 0; index < size(); index++){
result = result.concat(this.get(index).url);
if (index != size()-1) {
result = result.concat(", ");
}
}
result = result.concat("}");
return result;
}
};
For me your solution should work, however try to instantiate the parent first and then add the instance ... Something like
Country instanceCountry = new Country();
instanceCountry.setUrl("www.google.com");
instanceCountry.setSearch("xpto");
countries.add(instanceCountry);
Do not forget to generate the Getters and Setters

Mapping JSON to Class not working

I have a class which contains other some properties of another classes and when I try to convert from json to my class, there is an error displayed.
This is my class:
import org.jongo.marshall.jackson.oid.MongoObjectId;
import org.json.JSONObject;
import java.util.List;
public class BusinessTravelDTO {
#MongoObjectId
private String id;
private String travelerId;
private BusinessTravelStatus status;
List<FlightDTO> flights;
List<HotelDTO> hotels;
List<CarDTO> cars;
public BusinessTravelDTO() { }
public BusinessTravelDTO(JSONObject data) {
this.travelerId = data.getString("travelerId");
this.status = BusinessTravelStatus.valueOf(data.getString("status"));
this.flights = HandlerUtil.getInputFlights(data.getJSONArray("flights"));
this.hotels = HandlerUtil.getInputHotels(data.getJSONArray("hotels"));
this.cars = HandlerUtil.getInputCars(data.getJSONArray("cars"));
}
public JSONObject toJson() {
return new JSONObject()
.put("id", this.id)
.put("travelerId", this.travelerId)
.put("status", this.status)
.put("flights", this.flights)
.put("hotels", this.hotels)
.put("cars", this.cars);
}
And here is where I try to convert to class:
public static JSONObject acceptBusinessTravel(JSONObject input) {
String btId = getStringField(input, "id");
MongoCollection businessTravels = getBTCollection();
// Here is the problem...
BusinessTravelDTO bt = businessTravels.findOne(new ObjectId(btId)).as(BusinessTravelDTO.class);
bt.setStatus(BusinessTravelStatus.Accepted);
businessTravels.save(bt);
return new JSONObject().put("message", "The business travel has been ACCEPTED by your manager. Check your email.");
}
Here is the error I receive:
"error": "org.jongo.marshall.MarshallingException: Unable to unmarshall result to class path.data.BusinessTravelDTO from content { \"_id\" : { \"$oid\" : \"59d6905411d58632fd5bd8a5\"} , \"travelerId\"
In jongo docs is specified that the class should have an empty constructor... http://jongo.org/#mapping I have 2 constructors, I have tried also with #JsonCreator, but no success... :(
Do you have an idea why it doesn't convert? Could it be something related to fields inside BusinesTravelDTO like List CarDTO for ex ?
I finnally found the solution;
There is needed an empty constructor in all classes FlightDTO, HotelDTO, CarDTO plus I should rewrite the toJson method as following:
public JSONObject toJson() {
JSONObject obj = new JSONObject().put("id", this.id).put("travelerId", this.travelerId).put("status", this.status);
if (flights != null) {
JSONArray flightArray = new JSONArray();
for (int i = 0; i < flights.size(); ++i) {
flightArray.put(flights.get(i).toJson());
}
obj.put("flights", flightArray);
}
if (hotels != null) {
JSONArray hotelArray = new JSONArray();
for (int i = 0; i < hotels.size(); ++i) {
hotelArray.put(hotels.get(i).toJson());
}
obj.put("hotels", hotelArray);
}
if (cars != null) {
JSONArray carArray = new JSONArray();
for (int i = 0; i < cars.size(); ++i) {
carArray.put(cars.get(i).toJson());
}
obj.put("cars", carArray);
}
return obj;
}
And this is the FlightDTO;
public class FlightDTO {
#MongoObjectId
private String id;
private String departure;
private String arrival;
private String airline;
private Double price;
public FlightDTO() {
}
public FlightDTO(JSONObject data) {
this.departure = data.getString("departure");
this.arrival = data.getString("arrival");
this.airline = data.getString("airline");
this.price = data.getDouble("price");
}
public JSONObject toJson() {
return new JSONObject()
.put("id", this.id)
.put("departure", this.departure)
.put("arrival", this.arrival)
.put("airline", this.airline)
.put("price", this.price);
}
}
now it works well! :)

Categories