Split data in JSON file based on a key value using java - java

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

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 long id;
private final String name;
private final long price;
private final Category category;
public Item(long id, String name, long price, Category category) {
this.id = id;
this.name = name;
this.price = price;
this.category = category;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public long 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) {
long itemId = (Long) jsonObject.get("item-id");
String itemName = (String) jsonObject.get("name");
long itemPrice = (Long) 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.
EDIT Fix problem with integers by replacing them with long.
Good luck with Java :)

You can't alter a collection while iterating it. Try this:
Object[] subOrderArray = subOrders.toArray();
for(Object o: subOrderArray) {
JSONObject sitem = (JSONObject) o;

Here you want to group the JSON data by category under items array. The code will be very long if you try to get this done in Java. Just try using SPL, an open-source Java package, to do this. You only need one line of code:
A
1
=json(file("data.json").read()).items.group(#4;~:items)
SPL offers JDBC driver to be invoked by Java. Just store the above SPL script as group.splx and invoke it in a Java application as you call a stored procedure:
…
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
st = con.prepareCall("call group()");
st.execute();
…

Library Josson can do the job with a very simple statement.
https://github.com/octomix/josson
Deserialization
Josson josson = Josson.fromJsonString(
"{" +
" \"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\"" +
" }" +
" ]" +
"}");
Transformation
JsonNode node = josson.getNode("items.group(category, items:?)");
System.out.println(node.toPrettyString());
Output
[ {
"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"
} ]
} ]

Related

How to create JSON dynamically in java?

I have a CustomerEntiy with getter and setter the sample customerEntity is
customerEntity =
{
"customerNumber": "1234",
"firstName": "Test",
"email": "test#gmail.com",
"id": "1",
"middleName": "doe",
"phone": "11111"
}
I have java class Attributes of JsonProperty with getter and Setters as below
Attributes =
{
"name": "string"
"value": "string"
}
I have a list which will contains random elements from CustomerEntiy for example:
List<String> stringlist = { "firstName" , "phone"}
I have created an List of type Attributes
List<Attributes> Attributeslist = new ArrayList<>();
I want to create Attributelist of all the elements in stringlist for Example here it would be:
Attributeslist =[
{
"name": "firstName"
"value": "Test"
},
{
"name": "phone"
"value": "11111"
}
]
For this i have written the code as below but what to pass in previewattributes.setValue(); because that value would depends on what is mystring in below for loop. In this example it would be previewattributes.setValue(customerEntity.getFirstName()); and previewattributes.setValue(customerEntity.getPhone()); for different iteration but how do i code it??
for (String mystring : stringlist) {
Attributes previewattributes;
previewattributes = new Attributes();
previewattributes.setName(mystring);
previewattributes.setValue(value here would be of customerentity);
Attributeslist.add(previewattributes);
}
CustomerEntity:
#Entity
#Table(name = "Customer_tbl")
public class CustomerEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long rowId;
#Column(name = "customer_number")
private String customerNumber;
public String getCustomerNumber() {
return customerNumber;
}
public void setCustomerNumber(String customerNumber) {
this.customerNumber = customerNumber;
}
}
You can make use reflection in Java.
Even more simple way is to store the customerEntity in HashMap and fetch from it.
HashMap<String,String> m=new HashMap<>();
m.put("customerNumber", customerEntity.getCustomerNumber());
m.put("firstName", customerEntity.getFirstName());
m.put("email", customerEntity.getEmail());
m.put("id", customerEntity.getId());
m.put("middleName", customerEntity.getMiddleName());
m.put("phone", customerEntity.getPhone());
And inside for loop:
previewattributes.setValue(m.get(attribute));
If I understood u correctly u have an Array of Customer Json in which u want some attribute separated , check below code
public static void main(String[] args) {
String jsonArray = "[\r\n" +
" {\r\n" +
" \"customerNumber\":\"1234\",\r\n" +
" \"firstName\":\"Test\",\r\n" +
" \"email\":\"test#gmail.com\",\r\n" +
" \"id\":\"1\",\r\n" +
" \"middleName\":\"doe\",\r\n" +
" \"phone\":\"11111\"\r\n" +
" },\r\n" +
" {\r\n" +
" \"customerNumber\":\"1235\",\r\n" +
" \"firstName\":\"Test2\",\r\n" +
" \"email\":\"test2#gmail.com\",\r\n" +
" \"id\":\"2\",\r\n" +
" \"middleName\":\"doe2\",\r\n" +
" \"phone\":\"2222\"\r\n" +
" }\r\n" +
"]";
List<String> requiredKeys = Arrays.asList("firstName" , "phone");
JSONArray array = new JSONArray(jsonArray);
Iterator iterator = array.iterator();
JSONArray outputArray = new JSONArray();
while(iterator.hasNext()) {
JSONObject jsonObject = (JSONObject)iterator.next();
Iterator<String> keys = jsonObject.keys();
while(keys.hasNext()) {
String key = keys.next();
if(requiredKeys.contains(key)) {
JSONObject attribute = new JSONObject();
attribute.put("name", key);
attribute.put("value", jsonObject.get(key));
outputArray.put(attribute);
}
}
}
System.out.println(outputArray);
}
}
output
[
{
"name":"firstName",
"value":"Test"
},
{
"name":"phone",
"value":"11111"
},
{
"name":"firstName",
"value":"Test2"
},
{
"name":"phone",
"value":"2222"
}
]

Java: Convert List of Object to Set of Map

Say I have a list of of Objects (say List<User>), something like
[
{
"name": "myName",
"age": 1,
"someField": "foo"
},
{
"name": "otherName",
"age": 2,
"someField": "bar"
},
]
I want to convert this to Set<Map<String, Integer>> such that I get a set of name => age pair. So final result should be [{"myName": 1},{"otherName": 2}]
How can I use the stream and collector to do this?
You can use below piece of code for parsing JSON String and then doing some manipulation with that :
public static void main(String[] args) {
String str = "[ { \"name\": \"myName\", \"age\": 1, \"someField\": \"foo\" }, { \"name\": \"otherName\", \"age\": 2, \"someField\": \"bar\" }, ]";
JSONArray jsonobj = new JSONArray(str);
Map<String,Integer> map = new HashMap<>();
for(int i = 0;i<jsonobj.length();i++){
JSONObject obj = jsonobj.getJSONObject(i);
map.put(obj.getString("name"), obj.getInt("age"));
}
Set<Map<String,Integer>> set = new HashSet<>();
set.add(map);
System.out.println(set);
}
Library used : org.json
I ended up doing this:
final List<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);
Set<Map<String, Integer>> usersSet =
users
.stream()
.map(u -> Collections.singletonMap(u.getName(), u.getAge()))
.collect(Collectors.toSet());
Here is a possible conversion to Map<String, Integer> with duplicate handling:
final List<User> users = new ArrayList<>();
users.add(new User("name 1", 25));
users.add(new User("name 1", 49));
users.add(new User("name 2", 67));
final Map<String, Integer> nameToAge = users.stream().collect(
Collectors.toMap(
user -> user.name,
user -> user.age,
(user1, user2) -> {
System.out.println("Resolving duplicates...");
return user1;
})
);
In this case the definition for type User is:
public class User {
public final String name;
public final int age;
public User(final String name, final int age) {
this.name = name;
this.age = age;
}
}

How to filter JSON String array based on attributes?

I have a JSON-String array, where its entry has the following properties, firstName, lastName, loginName, Country, phoneNumber, and status. Here's an example
[
{
"firstName": "Patrick",
"lastName": "Smith",
"loginName":"test0003#test.com",
"Country":"US",
"phoneNumber": "287 125-1434",
"status": "340"
},
{
"firstName": "Bob",
"lastName": "Williams",
"loginName":"test0002#test.com",
"Country":"US",
"phoneNumber": "213 111-9943",
"status": "215"
},
{
"firstName": "John",
"lastName": "Johnson",
"loginName":"test0001#test.com",
"Country":"DE",
"phoneNumber": "212 555-1234",
"status": "167"
},
{
"firstName": "George",
"lastName": "Jones",
"loginName":"test0004#test.com",
"Country":"FR",
"phoneNumber": "217 987-2634",
"status": "340"
}
]
Now, I want to search for a specific entry based on the properties loginName and status
For example
loginName: test0001#test.com
status: 167
{
"firstName": "John",
"lastName": "Johnson",
"loginName":"test0001#test.com",
"Country":"DE",
"phoneNumber": "212 555-1234",
"status": "167"
}
What would be the most optimized solution?
I use JSONObject and here is another way to parse.
1. Parse using JSONArray
2. Loop the array and read into UserProfile objects
3. Store it in HashMap to get using key
import java.util.HashMap;
import java.util.Map;
import org.json.*;
class UserProfile{
String loginName;
int status;
String firstName;
String key;
UserProfile(){
}
String getLoginName(){
return loginName;
}
String getFirstName(){
return firstName;
}
void setKey(String key){
this.key = key;
}
void setLoginName(String loginName){
this.loginName = loginName;
}
void setStatus(int status){
this.status = status;
}
void setFirstName(String firstName){
this.firstName = firstName;
}
}
public class JSONObjParser {
public static void main(String[] args){
Map<String, UserProfile> map = new HashMap<String, UserProfile>();
String msg ="[{ firstName: Patrick, lastName: Smith, loginName:test0003#test.com, Country:US, phoneNumber: 287 125-1434, status: 340 }, { firstName: Bob, lastName: Williams, loginName:test0002#test.com, Country:US, phoneNumber: 213 111-9943, status: 215 }]";
JSONArray jsonarray = new JSONArray(msg);
for (int i = 0; i < jsonarray.length(); i++) {
JSONObject jsonobject = jsonarray.getJSONObject(i);
String loginName = jsonobject.getString("loginName");
int status = jsonobject.getInt("status");
String firstName = jsonobject.getString("firstName");
UserProfile profile = new UserProfile();
profile.setFirstName(firstName);
profile.setLoginName(loginName);
profile.setStatus(status);
String key = loginName + Integer.toString(status);
map.put(key, profile);
}
for (String key : map.keySet()) {
UserProfile profile = map.get(key);
System.out.println("Key = " + key + ", FirstName = " + profile.getFirstName());
}
}
}
Using Jackson, this is the crudest snippet I can think of:
private static ObjectMapper mapper = new ObjectMapper();
public static void main(String[] args) throws IOException {
System.out.println(filterJsonArray(JSON, "loginName", "test0001#test.com", "status", "167"));
}
public static String filterJsonArray(String array, String keyOne, Object valueOne, String keyTwo, Object valueTwo) throws IOException {
Map[] nodes = mapper.readValue(array, HashMap[].class);
for (Map node : nodes) {
if (node.containsKey(keyOne) && node.containsKey(keyTwo)) {
if (node.get(keyOne).equals(valueOne) && node.get(keyTwo).equals(valueTwo)) {
return mapper.writeValueAsString(node);
}
}
}
return null;
}
Of course it will only returns the first match to the given pairs. If you need all the values, make it return a list instead and populate it inside the loop.

How to ignore a specific field while parsing a JSON into map

I want to parse the below JSON into POJO. I am using jackson to parse the json.
{
"totalSize": 4,
"done": true,
"records": [
{
"attributes": {
"type": "oppor",
"url": "/service/oppor/456"
},
"AccountId": "123",
"Id": "456",
"ProposalID": "103"
}
]
}
In the above JSON, the fields "totalSize", "done", "records" and "attributes" are known fields. Whereas, "AccountId", "Id" and "ProposalID" are unknown fields. And in the above JSON, I don't need "attributes" to be part of my bean object.
And here is equivalent bean class for my JSON
public class Result {
private int totalSize;
private boolean done;
private List<Map<String, String>> records;
public int getTotalSize() {
return totalSize;
}
public void setTotalSize(int totalSize) {
this.totalSize = totalSize;
}
public boolean isDone() {
return done;
}
public void setDone(boolean done) {
this.done = done;
}
public List<Map<String,String>> getRecords() {
return records;
}
public void setRecords(List<Map<String, String>> records) {
this.records = records;
}
}
Hence there are unknown fields in the records element I just used List to get the results element in bean. Here in this Map, I don't want the field "attributes". How can I ignore this while parsing?
And below is the exception that I am getting as attributes is not a string element.
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: [B#66fdec9; line: 1, column: 40] (through reference chain: com.sample.json.Result["records"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:691)
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:46)
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:11)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringMap(MapDeserializer.java:430)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:312)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:26)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:227)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:204)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:23)
UPDATE 2015/08/29:
As you have commented that
I achieved dynamic field support by parsing the JSON into map. Ignoring bad JSON element is what pending
I suggest that you should process original JSONObject to remove the "attributes" element from it.
Original JSONObject, for example:
{
"totalSize": 4,
"done": true,
"records": [
{
"attributes": {
"type": "oppor",
"url": "/service/oppor/456"
},
"AccountId": "123",
"Id": "456",
"ProposalID": "103"
}
]
}
After process, new JSONObject will be like the following:
{
"records": {
"AccountId": "123",
"Id": "456",
"ProposalID": "103"
},
"totalSize": 4,
"done": true
}
Use the code as the following:
JSONObject jsonObject;
try {
jsonObject = new JSONObject(jsonString1);
JSONArray jsonArray = new JSONArray(jsonObject.get("records").toString());
JSONObject jsonObject1 = jsonArray.getJSONObject(0);
jsonObject1.remove("attributes");
jsonObject.put("records", jsonObject1);
} catch (JSONException e) {
e.printStackTrace();
}
Then, use your own code that achieved dynamic field support by parsing the JSON into map.
END OF UPDATE 2015/08/29
I suggest that you use Gson and transient in this case
Like this
String jsonString1 = "{\n" +
" \"totalSize\": 4,\n" +
" \"done\": true,\n" +
" \"records\": [\n" +
" {\n" +
" \"attributes\": {\n" +
" \"type\": \"oppor\",\n" +
" \"url\": \"/service/oppor/456\"\n" +
" },\n" +
" \"AccountId\": \"123\",\n" +
" \"Id\": \"456\",\n" +
" \"ProposalID\": \"103\"\n" +
" }\n" +
" ]\n" +
"}";
Gson gson = new Gson();
Result result1 = gson.fromJson(jsonString1, Result.class);
Your classes, pay attention to transient:
public class Result {
private int totalSize;
private boolean done;
private List<Record> records;
}
public class Record {
private transient Map<String, String> attributes;
private int AccountId;
private int Id;
private int ProposalID;
}
You will get the result:
P/S: I tested in Android Studio :)
UPDATE:
String jsonString1 = "{\n" +
" \"totalSize\": 4,\n" +
" \"done\": true,\n" +
" \"records\": [\n" +
" {\n" +
" \"attributes\": {\n" +
" \"type\": \"oppor\",\n" +
" \"url\": \"/service/oppor/456\"\n" +
" },\n" +
" \"AccountId\": \"123\",\n" +
" \"Id\": \"456\",\n" +
" \"ProposalID\": \"103\"\n" +
" }\n" +
" ]\n" +
"}";
Gson gson = new Gson();
Object object = gson.fromJson(jsonString1, Object.class);
Map<String, String> stringMap = (Map<String, String>) object;
Result myResult = new Result();
Iterator entries = stringMap.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry entry = (Map.Entry) entries.next();
String key = entry.getKey().toString();
String value = entry.getValue().toString();
switch (key) {
case "totalSize":
myResult.totalSize = (int) Double.parseDouble(entry.getValue().toString());
break;
case "done":
myResult.done = Boolean.valueOf(entry.getValue().toString());
break;
case "records":
try{
Object object1 = entry.getValue();
List<Object> objectList = (List<Object>) object1;
Map<String, Object> stringMap2 = (Map<String, Object>) objectList.get(0);
Map<String, String> recordMap = new HashMap<>();
Iterator entries2 = stringMap2.entrySet().iterator();
while (entries2.hasNext()) {
Map.Entry entry2 = (Map.Entry) entries2.next();
String key2 = entry2.getKey().toString();
String value2 = entry2.getValue().toString();
if (!"attributes".equals(key2)) {
recordMap.put(key2, value2);
}
entries2.remove();
}
myResult.records = recordMap;
} catch (Exception e) {
e.printStackTrace();
}
break;
}
entries.remove();
}
Classes:
public class Result {
private int totalSize;
private boolean done;
private Map<String, String> records;
}
Debug result:
1) Create a Record class object
2) Add #JsonIgnore Annotation on fields you won't
public class Result {
private int totalSize;
private boolean done;
private Record records;
[..]
}
public class Record {
#JsonIgnore
private Map<String, String> attributes;
private int accountID;
private int id;
private int approvalID;
[..]
}
Create a new POJO class for attributes,
public class Result {
private int totalSize;
private boolean done;
private List<Attributes> records;
// Your Getters & Setters
}
public class Attributes{
List<Map<String,String>> attributes;
// Add other variables if necessary like AccountId, etc.,
// Your Getters & Setters
}
I would suggest to use [Google gson API][1]'s #Expose annotation. (if that is allowed in your environment).
You can simply annotate the fields(with #Expose) which are required in your generated json file, and leave it other fields. And during generating json, use API method, excludeFieldsWithoutExposeAnnotation.
Sample example can be seen here.
Note : In your example, treat your Result as Main POJO, and records is another POJO which has attributes,accountId etc fields.
Then there is has-a relationship (Java composition) between them.
And after that, you can invoke Json to pojo conversion like below--
com.google.gson.Gson gson = new com.google.gson.GsonBuilder()
.excludeFieldsWithoutExposeAnnotation().create();
Result result= gson.fromJson(yourjsonString, Result.class);
If you have specific fields you don't want to map, u can use #JsonIgnore annotation over the field name
public class MyJsonObj{
#JsonProperty("name")
String fieldName
#JsonIgnore
String fieldNameIgnored;
}
If you want to ignore all the fields not mentioned in your POJO, you can use
#JsonIgnoreProperties annotation over class
#JsonIgnoreProperties(ignoreUnknown = true)
public class MyJsonObj{
strong text
}

How can I convert the following JSON string to Java Object by Gson?

I am having a problem to convert this json string to java object now. I have tried many ways, what I have got so far either errors like "Exception in thread "main" com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Expected value at line 1 column 44" I know the problem is from here \"errmsg\": in the string i made. Or errors like "Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 49", if I delete the errmsg part of my string. While i was trying, i made it run several times, but all the values I got either null or 0's, and it didn't even go into class Products.
One additional question: how to write a website link to a string, I always got errors on this part, that's why I comment out those links in the string I made.
Thank you !
Here is my json:
{"data":{"results":4,"returned":1,"errmsg":""},"products":
[{"name":"aaa", "region":"USA > CA","price":"1,231.00","year":"2011",
"link":"http:\/\/www.aaa.com\/abc\/sss-ttt-2011\/",
"image":"http:\/\/pic.aaa.com\/media\/8\/aaa_12_abc.jpeg"},
{"name":"bbb","region":"USA > WA","price":"31.00","year":"2012",
"link":"http:\/\/www.bbb.com\/abc\/sss-ttt-2012\/",
"image":"http:\/\/pic.bbb.com\/media\/7\/bbb_12_abc.jpeg"}]}
This is what I have done:
import java.util.Arrays;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class product {
static String jsonInput = "{" +
"\"data\":" +
"{\"results\":4,\"returned\":2,\"errmsg\":}," +
"\"products\":" +
"[" +
"{\"name\":\"aaa\",\"region\":\"USA > CA\",\"price\":1,231.00,\"year\":2011,"+
//\"link\":\"http:\/\/www.aaa.com\/abc\/sss-ttt-2011\/\", +
//\"image\":\"http:\/\/pic.aaa.com\/media\/8\/aaa_12_abc.jpeg\" +
"{\"name\":\"bbb\",\"region\":\"USA > WA\",\"price\":31.00,\"year\":2012,"+
//\"link\":\"http:\/\/www.bbb.com\/abc\/sss-ttt-2012\/\", +
//\"image\":\"http:\/\/pic.bbb.com\/media\/8\/bbb_12_abc.jpeg\" +
"}"+
"]" +
"}";
public static void main(String[] args) {
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
Data data = gson.fromJson(jsonInput, Data.class);
System.out.println(data);
}
}
class Data {
private int results;
private int returned;
private String errmsg;
private Products products;
#Override
public String toString() {
return String.format(
"[data: results=%1$d, returned=%2$d, errmsg=%3$s, products=%4$s]",
results, returned, errmsg, products);
}
}
class Products {
private Products_info[] products_info;
#Override
public String toString() {
return String.format("[%1$s]", Arrays.toString(products_info));
}
}
class Products_info {
private String name;
private String region;
private double price;
private int year;
//private String link;
//private String image;
#Override
public String toString() {
return "[name=" + name + ", region=" + region + ", price=" + price +
", year=" + year +
//", link=" + link +
//", image=" + image +
"]";
}
}
Thank you so much!
Your String may be malformed, but as far as I can tell, the java objects you have defined doesn't translate into the JSON data at all.
This JSON:
{
"data": {
"results": 4,
"returned": 1,
"errmsg": ""
},
"products": [
{
"name": "aaa",
"region": "USA > CA",
"price": "1,231.00",
"year": "2011",
"link": "http://www.aaa.com/abc/sss-ttt-2011/",
"image": "http://pic.aaa.com/media/8/aaa_12_abc.jpeg"
},
{
"name": "bbb",
"region": "USA > WA",
"price": "31.00",
"year": "2012",
"link": "http://www.bbb.com/abc/sss-ttt-2012/",
"image": "http://pic.bbb.com/media/7/bbb_12_abc.jpeg"
}
]
}
Should translate into the following objects:
SomeObject {
public class Data {
private int results;
private int returned;
private String errmsg;
}
public class Product {
private String name;
private String regsion;
private String price;
private String year;
private String link;
private String image;
}
private Data data;
private List<Product> products;
}
Worth noting is that there are numerous online formatters that can escape strings properly so you don't have to do it by hand:
http://www.freeformatter.com/java-dotnet-escape.html#ad-output
http://www.htmlescape.net/javaescape_tool.html

Categories