I am developing an application within that I have to create the SHA256 hash for the incoming data. To make that I have to follow the specific sorting order for each property. Hence, I have created a class TemplateNodeMap which extends LinkedHashMap, within that I have specified the order that I need to follow.
Now, I would like to read each property in the incoming JSON data, add a specific field, and create the Hash string. I am a bit confused about adding the data and creating the string. I am worried if I am following the optimal procedure or not as I need to follow the process for a large amount of data.
Can someone please let me know if this is the right approach?
Following is the incoming JSON (Since JSON can have any order I need to obtain properties according to my required Hash String order):
{
"age": 30,
"name": "Batman",
"address": {
"city": "Gotham",
"street": {
"name": "Gotham 123"
}
}
}
Following is my TemplateNodeMap class:
package io.hash;
import java.util.LinkedHashMap;
public class TemplateNodeMap extends LinkedHashMap {
public TemplateNodeMap() {
put("name", null);
put("age", null);
put("address", new LinkedHashMap<>() {{
put("street", new LinkedHashMap<>() {{
put("name", null);
}});
put("city", null);
}});
}
}
Following is my ApplicationMain class which is reading and loading the data to TemplateNodeMap:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.io.InputStream;
public class ApplicationMain {
public static void main(String[] args) throws IOException {
final ObjectMapper objectMapper = new ObjectMapper();
final InputStream jsonStream = ApplicationMain.class.getResourceAsStream("/InputJSON.json");
final ObjectNode inputTemplate = objectMapper.readValue(jsonStream, ObjectNode.class);
System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(inputTemplate));
final TemplateNodeMap templateNodeMap = new TemplateNodeMap();
templateNodeMap.put("name", inputTemplate.get("name"));
templateNodeMap.put("age", inputTemplate.get("age"));
//Unable to understand how to insert the complex object values into LinkedHashMap and follow the order
}
}
I am not understanding how to add the complex object to LinkedHashMap and create a string out of it.
Not all fields are mandatory so I would like to omit the null values during the creation of Hash String.
Can someone please suggest to me how to achieve this and if this is the right approach to creating a Hash String based on the required order?
There are two jackson annotations that can help you to serialize the jackson properties in a custom order excluding the non null values:
JsonPropertyOrder annotation that can be used to define ordering (possibly partial) to use when serializing object properties.
JsonInclude annotation used to indicate when value of the annotated property, or all properties of the annotated class, is to be serialized.
You can then deserialize your json to the pojo java classes and then serialize them obtaining a new json with the expected order of the properties and without null properties:
#Data
#JsonPropertyOrder(value = {"name", "age", "address"})
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Person {
private int age;
private String name;
private Address address;
}
#Data
#JsonPropertyOrder(value = {"street", "city"})
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Address {
private String city;
private Street street;
}
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Street {
private String name;
}
//you can delete for example the name property from your json
Person person = mapper.readValue(json, Person.class);
String output = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(person);
//ok, the name property will not appear in the output because it's null
System.out.println(output);
Requirements:
"I am developing an application within that I have to create the SHA256 hash for the incoming data."
"To make that I have to follow the specific sorting order for each property."
Proposal:
Create data classes for your incoming data, order their attributes as you like
Transform data class into a 'standard' JSON representation using prettyprint
Calculate hash over 'standard' JSON representation
For completeness a manual parsing of the linked hashmap is included
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.*;
import java.nio.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.*;
class Person {
int age; String name; Address address; // Attribute order effects output order!
public Person(){}
public Person(int age, String name, Address address) {
this.age = age; this.address = address; this.name = name;
}
public void setAge(int age){this.age = age;}
public int getAge(){return age;}
public void setName(String name){this.name = name;}
public String getName(){return name;}
public void setAddress(Address address){this.address = address;}
public Address getAddress(){return address;}
}
class Address {
String city;
Street street;
public Address(){}
public Address(String city, Street street){this.city = city; this.street = street;}
public void setCity(String city){this.city = city;}
public String getCity(){return city;}
public void setStreet(Street street){this.street = street;}
public Street getStreet(){return street;}
}
class Street {
String name;
public Street(){}
public Street(String name) {this.name = name;}
public String getName(){return name;}
public void setName(String name) {this.name = name;}
}
public class ApplicationMain {
static String inputJson = "{\"age\": 30,\"name\": \"Batman\",\"address\": {\"city\": \"Gotham\",\"street\": {\"name\": \"Gotham 123\"}}}";
public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
final ObjectMapper objectMapper = new ObjectMapper();
try {
// use Paths.get("InputJSON.json").toFile() as alternative to the string
Map<?, ?> map = objectMapper.readValue(inputJson, Map.class);
System.out.println("The linked hashmap to process for sorting:");
System.out.println(map);
System.out.println("Individual elements:");
System.out.println("name: " + map.get("name"));
System.out.println("age: " + map.get("age"));
System.out.println("address:");
Map<?, ?> addressMap = (Map<?, ?>)map.get("address");
System.out.println(" city: " + addressMap.get("city"));
System.out.println(" street:");
System.out.println(" name: " + ((Map<?, ?>)addressMap.get("street")).get("name"));
} catch (Exception ex) {
ex.printStackTrace();
}
Person person = objectMapper.readValue(inputJson, Person.class);
System.out.println("Original JSON:\n" + inputJson);
String prettyJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(person);
System.out.println("Standardized JSON:\n" + prettyJson);
byte[] hash = MessageDigest.getInstance("SHA-256").digest(prettyJson.getBytes(StandardCharsets.UTF_8));
for ( byte b : hash) {
System.out.printf("%02x", b);
}
System.out.println();
}
}
$ java -cp .:jackson-databind-2.13.3.jar:jackson-core-2.13.3.jar:jackson-annotations-2.13.3.jar ApplicationMain
The linked hashmap to process for sorting:
{age=30, name=Batman, address={city=Gotham, street={name=Gotham 123}}}
Individual elements:
name: Batman
age: 30
address:
city: Gotham
street:
name: Gotham 123
Original JSON:
{"age": 30,"name": "Batman","address": {"city": "Gotham","street": {"name": "Gotham 123"}}}
Standardized JSON:
{
"age" : 30,
"name" : "Batman",
"address" : {
"city" : "Gotham",
"street" : {
"name" : "Gotham 123"
}
}
}
5f962abf0cdc5150eb2614c629592d889d59b82499b13dd1b8d12e421bb0440a
$
You can check the hash value at https://dencode.com/hash
(The link already contains the JSON data. If you paste text there, verify that the correct line ending type is selected.)
Related
I have JSON structure that goes like this
{
"name":"John",
"age":27,
"company":{
"company_name":"ACME LLC",
"address": "1st Street",
"country": "US"
}
}
I know that if I want to map this to java object I need some kind of mapper and I have done that.
My question is: Is there a way to map only part of this json into object. I would like to map only company part of json into object. One more thing, I'm using java 11 with spring boot and I have access to Jackson's Object mapper.
Edit: Also if there is a way to navigate to this object it would be ok. For example $.company
I think the easiest way is to create two model classes. First with one field:
#Data
public class Model {
private Company company;
}
and second:
#Data
public class Company {
#JsonProperty("company_name")
private String companyName;
private String address;
private String country;
}
Then you can use Jackson mapper. You don't need to mention "map" and "age" fields in the Model class.
Ok, I have found an answer, thank you #Jakub on your answer it was a great help. Link to comment.
This is code example of answer based on my question:
public class Company {
private String name;
private String address;
private String country;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
Test method/execution:
#Test
public void testJSON() throws JsonProcessingException {
JsonNode productNode = objectMapper.readTree("{\n" +
" \"name\":\"John\",\n" +
" \"age\":27,\n" +
" \"company\":{\n" +
" \"name\":\"ACME LLC\",\n" +
" \"address\": \"1st Street\",\n" +
" \"country\": \"US\"\n" +
" }\n" +
"}");
Company company = objectMapper.readValue(productNode.get("company").toString(), Company.class);
System.out.println(company.getAddress());
}
I would suggest using DSM library.
define your mapping in yaml file, you only want to company field. So your mapping file will be like below.
result:
type: object
path: /company
fields:
name: # read value from field in path
path: company_name
address: #field name is the same
country:
Java code to read file:
DSM dsm=new DSMBuilder(new File("path/to/mapping.yaml")).create();
Map<String,Object> result= ( Map<String,Object>)dsm.toObject(jsonData);
result is a map that contains information in company field in json.
If you want to directly get instance of the class by deserialization:
public class Company{
String name;
String address;
String country;
}
Java code to deserialize:
DSM dsm=new DSMBuilder(new File("path/to/mapping.yaml")).create();
Company result= dsm.toObject(jsonData,Company.class);
I am having a really hard time understanding how to place a mapped valued into an array and how to iterate that array.
test.json
[
{
"Name": "Bob",
"Nationality": "",
"City": "Chicago",
"Phone" : "451232424234"
},
......continues with more objects
]
testTemplate.java
//imports
#JSONInclude(Json.Include.Non_NULL)
#JsonPropertyOrder({"Name,"Nationality","City","Phone"})
Public class testTemplate {
#JsonProperty("Name")
private String userName;
#JsonProperty("Nationality")
private String nation;
#JsonProperty("City")
private String city;
#JsonProperty("Phone")
private String phone;
#JsonProperty("Name")
public String getName (String userName) {
this.userName = userName;
}
#JsonProperty("Nationality")
public String nation (String nation) {
this.nation = nation;
}
#JsonProperty("City")
public String city (String city) {
this.city = city;
}
#JsonProperty("Phone")
public String phone (String phone) {
this.phone = phone;
}
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
testParse.java
Public Class testParse {
List<testParse> test;
ObjectMapper mapper;
protected void setUp() throws IOException {
mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT();
test = mapper.readValue(this.getClass().getResourcesAsStream("test.json"),
mapper.getTypeFactory().constructCollectionType(List.class, testParse.class));
I need to help first clarifying exactly what the code is doing, and how to put JSON properties (Name, Nationality,City,Phone) into Java.
My understanding is the testTemplate file create the strings in which the properties will be held, then the testParse file has the mapper feature (from Jackson) that reads through the json and puts all into "test" (as an array?)
My goal is in testParse, where if everything thing is in "test", then I read through that, and start to pull it out and place it into a folderList.
public static Map<String, String> userName throws IOException {
Map<String, String> folderList = new TreeMap<>();
//Don't know how, but iterate through "test"
LineIterator it = new LineIterator(//the method used to read the json file);
try {
while(it.hasNext()) {
String line = it.nextLine();
folderList.put(userName,nation) //can I also put city and phone at once as well or should I create another put: folderList.put(userName, city)
return folderList;
How does one do this? Is there a better way to put the properties of json into the folderList after using the jackson mapper?
Actually, testTemplate don't generate anything, what Jackson have done here is just get data from "test.json" as String, then using Reflection read the format of testTemplate.java. Based on template it've just have + setting you add to ObjectMapper object, Jackson will convert test.json to array of object Java.
P/S: you don't need to add annotation in both attributes and get function of POJO class, just do it in get function or attributes only, it's enough for Jackson.
I want to be able to access properties from a JSON string within my Java action method. The string is available by simply saying myJsonString = object.getJson(). Below is an example of what the string can look like:
{
'title': 'ComputingandInformationsystems',
'id': 1,
'children': 'true',
'groups': [{
'title': 'LeveloneCIS',
'id': 2,
'children': 'true',
'groups': [{
'title': 'IntroToComputingandInternet',
'id': 3,
'children': 'false',
'groups': []
}]
}]
}
In this string every JSON object contains an array of other JSON objects. The intention is to extract a list of IDs where any given object possessing a group property that contains other JSON objects. I looked at Google's Gson as a potential JSON plugin. Can anyone offer some form of guidance as to how I can generate Java from this JSON string?
I looked at Google's Gson as a potential JSON plugin. Can anyone offer some form of guidance as to how I can generate Java from this JSON string?
Google Gson supports generics and nested beans. The [] in JSON represents an array and should map to a Java collection such as List or just a plain Java array. The {} in JSON represents an object and should map to a Java Map or just some JavaBean class.
You have a JSON object with several properties of which the groups property represents an array of nested objects of the very same type. This can be parsed with Gson the following way:
package com.stackoverflow.q1688099;
import java.util.List;
import com.google.gson.Gson;
public class Test {
public static void main(String... args) throws Exception {
String json =
"{"
+ "'title': 'Computing and Information systems',"
+ "'id' : 1,"
+ "'children' : 'true',"
+ "'groups' : [{"
+ "'title' : 'Level one CIS',"
+ "'id' : 2,"
+ "'children' : 'true',"
+ "'groups' : [{"
+ "'title' : 'Intro To Computing and Internet',"
+ "'id' : 3,"
+ "'children': 'false',"
+ "'groups':[]"
+ "}]"
+ "}]"
+ "}";
// Now do the magic.
Data data = new Gson().fromJson(json, Data.class);
// Show it.
System.out.println(data);
}
}
class Data {
private String title;
private Long id;
private Boolean children;
private List<Data> groups;
public String getTitle() { return title; }
public Long getId() { return id; }
public Boolean getChildren() { return children; }
public List<Data> getGroups() { return groups; }
public void setTitle(String title) { this.title = title; }
public void setId(Long id) { this.id = id; }
public void setChildren(Boolean children) { this.children = children; }
public void setGroups(List<Data> groups) { this.groups = groups; }
public String toString() {
return String.format("title:%s,id:%d,children:%s,groups:%s", title, id, children, groups);
}
}
Fairly simple, isn't it? Just have a suitable JavaBean and call Gson#fromJson().
See also:
Json.org - Introduction to JSON
Gson User Guide - Introduction to Gson
Bewaaaaare of Gson! It's very cool, very great, but the second you want to do anything other than simple objects, you could easily need to start building your own serializers (which isn't that hard).
Also, if you have an array of Objects, and you deserialize some json into that array of Objects, the true types are LOST! The full objects won't even be copied! Use XStream.. Which, if using the jsondriver and setting the proper settings, will encode ugly types into the actual json, so that you don't loose anything. A small price to pay (ugly json) for true serialization.
Note that Jackson fixes these issues, and is faster than GSON.
Oddly, the only decent JSON processor mentioned so far has been GSON.
Here are more good choices:
Jackson (Github) -- powerful data binding (JSON to/from POJOs), streaming (ultra fast), tree model (convenient for untyped access)
Flex-JSON -- highly configurable serialization
EDIT (Aug/2013):
One more to consider:
Genson -- functionality similar to Jackson, aimed to be easier to configure by developer
Or with Jackson:
String json = "...";
ObjectMapper m = new ObjectMapper();
Set<Product> products = m.readValue(json, new TypeReference<Set<Product>>() {});
Easy and working java code to convert JSONObject to Java Object
Employee.java
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Generated;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#Generated("org.jsonschema2pojo")
#JsonPropertyOrder({
"id",
"firstName",
"lastName"
})
public class Employee {
#JsonProperty("id")
private Integer id;
#JsonProperty("firstName")
private String firstName;
#JsonProperty("lastName")
private String lastName;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
/**
*
* #return
* The id
*/
#JsonProperty("id")
public Integer getId() {
return id;
}
/**
*
* #param id
* The id
*/
#JsonProperty("id")
public void setId(Integer id) {
this.id = id;
}
/**
*
* #return
* The firstName
*/
#JsonProperty("firstName")
public String getFirstName() {
return firstName;
}
/**
*
* #param firstName
* The firstName
*/
#JsonProperty("firstName")
public void setFirstName(String firstName) {
this.firstName = firstName;
}
/**
*
* #return
* The lastName
*/
#JsonProperty("lastName")
public String getLastName() {
return lastName;
}
/**
*
* #param lastName
* The lastName
*/
#JsonProperty("lastName")
public void setLastName(String lastName) {
this.lastName = lastName;
}
#JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
#JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
LoadFromJSON.java
import org.codehaus.jettison.json.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
public class LoadFromJSON {
public static void main(String args[]) throws Exception {
JSONObject json = new JSONObject();
json.put("id", 2);
json.put("firstName", "hello");
json.put("lastName", "world");
byte[] jsonData = json.toString().getBytes();
ObjectMapper mapper = new ObjectMapper();
Employee employee = mapper.readValue(jsonData, Employee.class);
System.out.print(employee.getLastName());
}
}
If, by any change, you are in an application which already uses http://restfb.com/ then you can do:
import com.restfb.json.JsonObject;
...
JsonObject json = new JsonObject(jsonString);
json.get("title");
etc.
HashMap keyArrayList = new HashMap();
Iterator itr = yourJson.keys();
while (itr.hasNext())
{
String key = (String) itr.next();
keyArrayList.put(key, yourJson.get(key).toString());
}
Depending on the input JSON format(string/file) create a jSONString. Sample Message class object corresponding to JSON can be obtained as below:
Message msgFromJSON = new ObjectMapper().readValue(jSONString, Message.class);
If you use any kind of special maps with keys or values also of special maps, you will find it's not contemplated by the implementation of google.
What's wrong with the standard stuff?
JSONObject jsonObject = new JSONObject(someJsonString);
JSONArray jsonArray = jsonObject.getJSONArray("someJsonArray");
String value = jsonArray.optJSONObject(i).getString("someJsonValue");
Pass your JSON file in this way, it will return the object.
File file = new File("D:\\Coding\\tickets\\temp.json");
ObjectMapper om = new ObjectMapper();
Profile profile = om.readValue(file, new TypeReference<Profile>() {});
Give boon a try:
https://github.com/RichardHightower/boon
It is wicked fast:
https://github.com/RichardHightower/json-parsers-benchmark
Don't take my word for it... check out the gatling benchmark.
https://github.com/gatling/json-parsers-benchmark
(Up to 4x is some cases, and out of the 100s of test. It also has a index overlay mode that is even faster. It is young but already has some users.)
It can parse JSON to Maps and Lists faster than any other lib can parse to a JSON DOM and that is without Index Overlay mode. With Boon Index Overlay mode, it is even faster.
It also has a very fast JSON lax mode and a PLIST parser mode. :) (and has a super low memory, direct from bytes mode with UTF-8 encoding on the fly).
It also has the fastest JSON to JavaBean mode too.
It is new, but if speed and simple API is what you are looking for, I don't think there is a faster or more minimalist API.
The easiest way is that you can use this softconvertvalue method which is a custom method in which you can convert jsonData into your specific Dto class.
Dto response = softConvertValue(jsonData, Dto.class);
public static <T> T softConvertValue(Object fromValue, Class<T> toValueType)
{
ObjectMapper objMapper = new ObjectMapper();
return objMapper
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.convertValue(fromValue, toValueType);
}
<!-- GSON -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.7</version>
</dependency>
#Test
void readListJsonFromFileTest() throws IOException {
Type type = new TypeToken<List<SimplePojo>>(){}.getType();
String fromJsonFile = readFromJsonFile("json/simplePojoJsonList.json");
List<SimplePojo> pojoList = gson.fromJson(fromJsonFile, type);
Assertions.assertNotNull(pojoList);
}
#Test
void readJsonFromFileTest() throws IOException {
Type type = new TypeToken<SimplePojo>(){}.getType();
String fromJsonFile = readFromJsonFile("json/simplePojoJson.json");
SimplePojo simplePojo = gson.fromJson(fromJsonFile, type);
Assertions.assertNotNull(simplePojo);
}
String readFromJsonFile(String pathToJson) throws IOException {
InputStream resource = new ClassPathResource(pathToJson).getInputStream();
String json = StreamUtils.copyToString(resource, StandardCharsets.UTF_8);
return json;
}
I have a JSON payload that looks like this:
{
"id": 32,
"name": "[Sample] Tomorrow is today, Red printed scarf",
"primary_image": {
"id": 247,
"zoom_url": "www.site.com/in_123__14581.1393831046.1280.1280.jpg",
"thumbnail_url": "www.site.com/in_123__14581.1393831046.220.290.jpg",
"standard_url": "www.site.com/in_123__14581.1393831046.386.513.jpg",
"tiny_url": "www.site.com/in_123__14581.1393831046.44.58.jpg"
}
}
Can I unwrap a specific field and discard all the others? In other words, can I bind this directly to a POJO like this:
public class Product {
private Integer id;
private String name;
private String standardUrl;
}
There are lots of ways. Do you need to deserialize, serialize or both?
One way to deserialize would be to use a creator method that takes the image as a tree node:
public static class Product {
private Integer id;
private String name;
private String standardUrl;
public Product(#JsonProperty("id") Integer id,
#JsonProperty("name") String name,
#JsonProperty("primary_image") JsonNode primaryImage) {
this.id = id;
this.name = name;
this.standardUrl = primaryImage.path("standard_url").asText();
}
}
The creator doesn't have to be a constructor, you could have a static method that is only used for Jackson deserialization.
You'd have to define a custom serializer to reserialize this, though (e.g. a StdDelegatingSerializer and a converter to wrap the string back up as an ObjectNode)
There are different ways to skin this cat, I hope you can use Jackson 2 for this, since it offers great ways to deserialize Json data, one of my favorites deserialization features is the one I'll show you here (using Builder Pattern) because allows you to validate instances when they are being constructed (or make them immutable!). For you this would look like this:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.util.Map;
#JsonDeserialize(builder = Product.Builder.class)
public class Product {
private Integer id;
private String name;
private String standardUrl;
private Product(Builder builder) {
//Here you can make validations for your new instance.
this.id = builder.id;
this.name = builder.name;
//Here you have access to the primaryImage map in case you want to add new properties later.
this.standardUrl = builder.primaryImage.get("standard_url");
}
#Override
public String toString() {
return String.format("id [%d], name [%s], standardUrl [%s].", id, name, standardUrl);
}
#JsonIgnoreProperties(ignoreUnknown = true)
public static class Builder {
private Integer id;
private String name;
private Map<String, String> primaryImage;
public Builder withId(Integer id) {
this.id = id;
return this;
}
public Builder withName(String name) {
this.name = name;
return this;
}
#JsonProperty("primary_image")
public Builder withPrimaryImage(Map<String, String> primaryImage) {
this.primaryImage = primaryImage;
return this;
}
public Product build() {
return new Product(this);
}
}
}
To test it I created this class:
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class Test {
public static void main(String[] args) {
String serialized = "{" +
" \"id\": 32," +
" \"name\": \"[Sample] Tomorrow is today, Red printed scarf\"," +
" \"primary_image\": {" +
" \"id\": 247," +
" \"zoom_url\": \"www.site.com/in_123__14581.1393831046.1280.1280.jpg\"," +
" \"thumbnail_url\": \"www.site.com/in_123__14581.1393831046.220.290.jpg\"," +
" \"standard_url\": \"www.site.com/in_123__14581.1393831046.386.513.jpg\"," +
" \"tiny_url\": \"www.site.com/in_123__14581.1393831046.44.58.jpg\"" +
" }" +
" }";
ObjectMapper objectMapper = new ObjectMapper();
try {
Product deserialized = objectMapper.readValue(serialized, Product.class);
System.out.print(deserialized.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
The output is (using the override toString() method in Product:
id [32], name [[Sample] Tomorrow is today, Red printed scarf], standardUrl [www.site.com/in_123__14581.1393831046.386.513.jpg].
There are two ways to get the response you required. For both methods, we are going to use JsonView.
Create two types of JsonView:
public interface JViews {
public static class Public { }
public static class Product extends Public { }
}
First method
#JsonView(JViews.Public.class)
public class Product {
private Integer id;
private String name;
#JsonIgnore
private Image primaryImage;
#JsonView(JViews.Product.class)
public String getStandardUrl{
return this.primaryImage.getStandardUrl();
}
}
Second way
Using Jackson's #JsonView and #JsonUnwrapped together.
#JsonView(JViews.Public.class)
public class Product {
private Integer id;
private String name;
#JsonUnwrapped
private Image primaryImage;
}
public class Image {
private String zoomUrl;
#JsonView(JViews.Product.class)
private String standardUrl;
}
#JsonUnwrapped annotation flattens your nested object into Product object. And JsonView is used to filter accessible fields. In this case, only standardUrl field is accessible for Product view, and the result is expected to be:
{
"id": 32,
"name": "[Sample] Tomorrow is today, Red printed scarf",
"standard_url": "url"
}
If you flatten your nested object without using Views, the result will look like:
{
"id": 32,
"name": "[Sample] Tomorrow is today, Red printed scarf",
"id":1,
"standard_url": "url",
"zoom_url":"",
...
}
Jackson provided #JsonUnwrapped annotation.
See below link:
http://jackson.codehaus.org/1.9.9/javadoc/org/codehaus/jackson/annotate/JsonUnwrapped.html
I want to be able to access properties from a JSON string within my Java action method. The string is available by simply saying myJsonString = object.getJson(). Below is an example of what the string can look like:
{
'title': 'ComputingandInformationsystems',
'id': 1,
'children': 'true',
'groups': [{
'title': 'LeveloneCIS',
'id': 2,
'children': 'true',
'groups': [{
'title': 'IntroToComputingandInternet',
'id': 3,
'children': 'false',
'groups': []
}]
}]
}
In this string every JSON object contains an array of other JSON objects. The intention is to extract a list of IDs where any given object possessing a group property that contains other JSON objects. I looked at Google's Gson as a potential JSON plugin. Can anyone offer some form of guidance as to how I can generate Java from this JSON string?
I looked at Google's Gson as a potential JSON plugin. Can anyone offer some form of guidance as to how I can generate Java from this JSON string?
Google Gson supports generics and nested beans. The [] in JSON represents an array and should map to a Java collection such as List or just a plain Java array. The {} in JSON represents an object and should map to a Java Map or just some JavaBean class.
You have a JSON object with several properties of which the groups property represents an array of nested objects of the very same type. This can be parsed with Gson the following way:
package com.stackoverflow.q1688099;
import java.util.List;
import com.google.gson.Gson;
public class Test {
public static void main(String... args) throws Exception {
String json =
"{"
+ "'title': 'Computing and Information systems',"
+ "'id' : 1,"
+ "'children' : 'true',"
+ "'groups' : [{"
+ "'title' : 'Level one CIS',"
+ "'id' : 2,"
+ "'children' : 'true',"
+ "'groups' : [{"
+ "'title' : 'Intro To Computing and Internet',"
+ "'id' : 3,"
+ "'children': 'false',"
+ "'groups':[]"
+ "}]"
+ "}]"
+ "}";
// Now do the magic.
Data data = new Gson().fromJson(json, Data.class);
// Show it.
System.out.println(data);
}
}
class Data {
private String title;
private Long id;
private Boolean children;
private List<Data> groups;
public String getTitle() { return title; }
public Long getId() { return id; }
public Boolean getChildren() { return children; }
public List<Data> getGroups() { return groups; }
public void setTitle(String title) { this.title = title; }
public void setId(Long id) { this.id = id; }
public void setChildren(Boolean children) { this.children = children; }
public void setGroups(List<Data> groups) { this.groups = groups; }
public String toString() {
return String.format("title:%s,id:%d,children:%s,groups:%s", title, id, children, groups);
}
}
Fairly simple, isn't it? Just have a suitable JavaBean and call Gson#fromJson().
See also:
Json.org - Introduction to JSON
Gson User Guide - Introduction to Gson
Bewaaaaare of Gson! It's very cool, very great, but the second you want to do anything other than simple objects, you could easily need to start building your own serializers (which isn't that hard).
Also, if you have an array of Objects, and you deserialize some json into that array of Objects, the true types are LOST! The full objects won't even be copied! Use XStream.. Which, if using the jsondriver and setting the proper settings, will encode ugly types into the actual json, so that you don't loose anything. A small price to pay (ugly json) for true serialization.
Note that Jackson fixes these issues, and is faster than GSON.
Oddly, the only decent JSON processor mentioned so far has been GSON.
Here are more good choices:
Jackson (Github) -- powerful data binding (JSON to/from POJOs), streaming (ultra fast), tree model (convenient for untyped access)
Flex-JSON -- highly configurable serialization
EDIT (Aug/2013):
One more to consider:
Genson -- functionality similar to Jackson, aimed to be easier to configure by developer
Or with Jackson:
String json = "...";
ObjectMapper m = new ObjectMapper();
Set<Product> products = m.readValue(json, new TypeReference<Set<Product>>() {});
Easy and working java code to convert JSONObject to Java Object
Employee.java
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Generated;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#Generated("org.jsonschema2pojo")
#JsonPropertyOrder({
"id",
"firstName",
"lastName"
})
public class Employee {
#JsonProperty("id")
private Integer id;
#JsonProperty("firstName")
private String firstName;
#JsonProperty("lastName")
private String lastName;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
/**
*
* #return
* The id
*/
#JsonProperty("id")
public Integer getId() {
return id;
}
/**
*
* #param id
* The id
*/
#JsonProperty("id")
public void setId(Integer id) {
this.id = id;
}
/**
*
* #return
* The firstName
*/
#JsonProperty("firstName")
public String getFirstName() {
return firstName;
}
/**
*
* #param firstName
* The firstName
*/
#JsonProperty("firstName")
public void setFirstName(String firstName) {
this.firstName = firstName;
}
/**
*
* #return
* The lastName
*/
#JsonProperty("lastName")
public String getLastName() {
return lastName;
}
/**
*
* #param lastName
* The lastName
*/
#JsonProperty("lastName")
public void setLastName(String lastName) {
this.lastName = lastName;
}
#JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
#JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
LoadFromJSON.java
import org.codehaus.jettison.json.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
public class LoadFromJSON {
public static void main(String args[]) throws Exception {
JSONObject json = new JSONObject();
json.put("id", 2);
json.put("firstName", "hello");
json.put("lastName", "world");
byte[] jsonData = json.toString().getBytes();
ObjectMapper mapper = new ObjectMapper();
Employee employee = mapper.readValue(jsonData, Employee.class);
System.out.print(employee.getLastName());
}
}
If, by any change, you are in an application which already uses http://restfb.com/ then you can do:
import com.restfb.json.JsonObject;
...
JsonObject json = new JsonObject(jsonString);
json.get("title");
etc.
HashMap keyArrayList = new HashMap();
Iterator itr = yourJson.keys();
while (itr.hasNext())
{
String key = (String) itr.next();
keyArrayList.put(key, yourJson.get(key).toString());
}
Depending on the input JSON format(string/file) create a jSONString. Sample Message class object corresponding to JSON can be obtained as below:
Message msgFromJSON = new ObjectMapper().readValue(jSONString, Message.class);
If you use any kind of special maps with keys or values also of special maps, you will find it's not contemplated by the implementation of google.
What's wrong with the standard stuff?
JSONObject jsonObject = new JSONObject(someJsonString);
JSONArray jsonArray = jsonObject.getJSONArray("someJsonArray");
String value = jsonArray.optJSONObject(i).getString("someJsonValue");
Pass your JSON file in this way, it will return the object.
File file = new File("D:\\Coding\\tickets\\temp.json");
ObjectMapper om = new ObjectMapper();
Profile profile = om.readValue(file, new TypeReference<Profile>() {});
Give boon a try:
https://github.com/RichardHightower/boon
It is wicked fast:
https://github.com/RichardHightower/json-parsers-benchmark
Don't take my word for it... check out the gatling benchmark.
https://github.com/gatling/json-parsers-benchmark
(Up to 4x is some cases, and out of the 100s of test. It also has a index overlay mode that is even faster. It is young but already has some users.)
It can parse JSON to Maps and Lists faster than any other lib can parse to a JSON DOM and that is without Index Overlay mode. With Boon Index Overlay mode, it is even faster.
It also has a very fast JSON lax mode and a PLIST parser mode. :) (and has a super low memory, direct from bytes mode with UTF-8 encoding on the fly).
It also has the fastest JSON to JavaBean mode too.
It is new, but if speed and simple API is what you are looking for, I don't think there is a faster or more minimalist API.
The easiest way is that you can use this softconvertvalue method which is a custom method in which you can convert jsonData into your specific Dto class.
Dto response = softConvertValue(jsonData, Dto.class);
public static <T> T softConvertValue(Object fromValue, Class<T> toValueType)
{
ObjectMapper objMapper = new ObjectMapper();
return objMapper
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.convertValue(fromValue, toValueType);
}
<!-- GSON -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.7</version>
</dependency>
#Test
void readListJsonFromFileTest() throws IOException {
Type type = new TypeToken<List<SimplePojo>>(){}.getType();
String fromJsonFile = readFromJsonFile("json/simplePojoJsonList.json");
List<SimplePojo> pojoList = gson.fromJson(fromJsonFile, type);
Assertions.assertNotNull(pojoList);
}
#Test
void readJsonFromFileTest() throws IOException {
Type type = new TypeToken<SimplePojo>(){}.getType();
String fromJsonFile = readFromJsonFile("json/simplePojoJson.json");
SimplePojo simplePojo = gson.fromJson(fromJsonFile, type);
Assertions.assertNotNull(simplePojo);
}
String readFromJsonFile(String pathToJson) throws IOException {
InputStream resource = new ClassPathResource(pathToJson).getInputStream();
String json = StreamUtils.copyToString(resource, StandardCharsets.UTF_8);
return json;
}