I have a json file with which has an array of product items i want to split them based on the category of the item, This is my json file looks like,
{
"items":[
{
"item-id": 123,
"name": "Cheese",
"price": 8,
"category": "Dairy"
},
{
"item-id": 124,
"name": "Milk",
"price": 23,
"category": "Dairy"
},
{
"item-id": 125,
"name": "Chicken",
"price": 100,
"category": "Meat"
},
{
"item-id": 126,
"name": "Fish",
"price": 45,
"category": "Meat"
}
]
}
i want to split them like like this,
[
{
"category":"Dairy",
"items":[
{
"item-id": 123,
"name": "Cheese",
"price": 8,
"category": "Dairy"
},
{
"item-id": 124,
"name": "Milk",
"price": 23,
"category": "Dairy"
}
]
},
{
"category":"Meat",
"items":[
{
"item-id": 125,
"name": "Chicken",
"price": 100,
"category": "Meat"
},
{
"item-id": 126,
"name": "Fish",
"price": 45,
"category": "Meat"
}
]
}
]
this is the code i tried so far but can't find way to split them like the way i wanted, I'm using java and also i am new to java
import java.io.*;
import java.util.*;
import org.json.simple.*;
import org.json.simple.parser.*;
public class ReadOrderDetails {
@SuppressWarnings("unused")
public static void main(String[] args) {
JSONParser parser = new JSONParser();
JSONObject subOrder = new JSONObject();
JSONArray gitems = new JSONArray();
JSONArray subOrders = new JSONArray();
try {
Object obj = parser.parse(new FileReader("order-details.json"));
JSONObject jsonObject = (JSONObject)obj;
String orderId = (String)jsonObject.get("orderId");
JSONArray items = (JSONArray)jsonObject.get("items");
@SuppressWarnings("rawtypes")
Iterator iterator = items.iterator();
System.out.println("Order Id: " orderId);
while(iterator.hasNext()) {
JSONObject item = (JSONObject)iterator.next();
if(subOrders.isEmpty()) {
subOrder.put("category", item.get("category"));
gitems.add(item);
subOrder.put("items", gitems);
subOrders.add(subOrder);
} else {
Iterator subOrdersIterator = subOrders.iterator();
for(int i=0; i<subOrders.size(); i ) {
JSONObject sitem = (JSONObject) subOrdersIterator.next();
if(sitem.get("category") == item.get("category")) {
gitems.add(item);
subOrder.put("items", gitems);
subOrders.add(subOrder);
} else {
subOrder.put("category", item.get("category"));
gitems.add(item);
subOrder.put("items", gitems);
subOrders.add(subOrder);
}
}
}
}
} catch(Exception e) {
e.printStackTrace();
}
System.out.println(subOrders);
}
}
and also i'm getting an error at java.util.ConcurrentModificationException but that's not my main question, what i really wnated a way to split them i tried couple of things didn't working
CodePudding user response:
In general, you violated the Single Responsibility principal (SOLID), because your code do two different things together: parse a file and categorize items. You should split these responsibilities.
One of ways how you do this is to create classes that represents your data. Let's assume that these classes are Item
, Category
, Order
and CategorizedItems
. Order
is a class that represents your source JSONObject
and CategorizedItems
- represents your result JSONArray
.
In this case, you should firstly parse the file into these classes and only after that transform them into JSONArray
.
Code sample:
Data classes:
class Order {
private final List<Item> items = new ArrayList<>();
public void addItem(Item item) {
items.add(item);
}
public List<Item> getAllItems() {
return new ArrayList<>(items);
}
}
enum Category {
DAIRY("Dairy"),
MEAT("Meat");
private final String value;
Category(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public static Category of(String value) {
for (Category category : values()) {
if (category.value.equals(value)) {
return category;
}
}
throw new IllegalArgumentException("Unknown category");
}
}
class CategorizedItems {
private final Category category;
private final List<Item> items;
public CategorizedItems(Category category, List<Item> items) {
this.category = category;
this.items = items;
}
public Category getCategory() {
return category;
}
public List<Item> getItems() {
return items;
}
}
class Item {
private final int id;
private final String name;
private final int price;
private final Category category;
public Item(int id, String name, int price, Category category) {
this.id = id;
this.name = name;
this.price = price;
this.category = category;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getPrice() {
return price;
}
public Category getCategory() {
return category;
}
}
Now you should write methods, for example, static ones in your ReadOrderDetails
:
private static JSONArray categorizedItemsToJSONArray(List<CategorizedItems> categorizedItems) {
JSONArray jsonArray = new JSONArray();
categorizedItems.forEach(category -> jsonArray.add(toJSONObject(category)));
return jsonArray;
}
private static JSONObject toJSONObject(CategorizedItems categorizedItems) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("category", categorizedItems.getCategory().getValue());
jsonObject.put("items", itemsToJSONArray(categorizedItems.getItems()));
return jsonObject;
}
private static JSONArray itemsToJSONArray(List<Item> items) {
JSONArray jsonArray = new JSONArray();
items.forEach(item -> jsonArray.add(toJSONObject(item)));
return jsonArray;
}
private static JSONObject toJSONObject(Item item) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("item-id", item.getId());
jsonObject.put("name", item.getName());
jsonObject.put("price", item.getName());
jsonObject.put("category", item.getCategory().getValue());
return jsonObject;
}
private static List<CategorizedItems> categorize(Order order) {
List<CategorizedItems> categorizedItems = new ArrayList<>();
for (Category category : Category.values()) {
categorizedItems.add(
new CategorizedItems(
category,
order.getAllItems()
.stream()
.filter(item -> item.getCategory() == category)
.collect(Collectors.toList())
)
);
}
return categorizedItems;
}
private static Order orderFrom(JSONObject jsonObject) {
JSONArray itemsJsonArray = (JSONArray) jsonObject.get("items");
Order order = new Order();
for (Object jsonArrayMember : itemsJsonArray) {
JSONObject itemJsonObject = (JSONObject) jsonArrayMember;
order.addItem(itemFrom(itemJsonObject));
}
return order;
}
private static Item itemFrom(JSONObject jsonObject) {
int itemId = (Integer) jsonObject.get("item-id");
String itemName = (String) jsonObject.get("name");
int itemPrice = (Integer) jsonObject.get("price");
Category category = Category.of((String) jsonObject.get("category"));
return new Item(
itemId,
itemName,
itemPrice,
category
);
}
After that you should do the last step. Write a main function like:
public static void main(String[] args) {
JSONParser parser = new JSONParser();
try {
JSONObject orderJsonObject = (JSONObject) parser.parse(new FileReader("order-details.json"));
Order order = orderFrom(orderJsonObject);
List<CategorizedItems> categorizedItems = categorize(order);
JSONArray categorizedItemsJsonArray = categorizedItemsToJSONArray(categorizedItems);
// write categorizedItemsJsonArray to a file here
} catch(IOException | ParseException e) {
throw new RuntimeException(e);
}
}
Now your code is simply readable and clear. You can easily maintain it. I advise you to read about SOLID principals and about code style (I highly recommend Robert Martin. "Clean code"). These topics will help you learn how to write elegant and clear code.
Besides, ConcurrentModificationException
is a sign that you do something wrong with collections. In your particular case, I guess (not sure) the problem is modifying the JSONArray while you are iteratting it. Only some of Java collections allow it.
Good luck with Java :)
CodePudding user response:
You can't alter a collection while iterating it. Try this:
Object[] subOrderArray = subOrders.toArray();
for(Object o: subOrderArray) {
JSONObject sitem = (JSONObject) o;