How to query a json object in java? - java

I have a test.json file with data:
{
"name":"tet",
"id":"1",
"age" : "34"
}
Now when I query select * from test; should show me the result as
name id age
-----------
tet 1 34
Is it possible to directly query a JSON Object as we do for XML?

The popular Jackson XML library supports JsonPointer since version 2.3. This is a query language similar to XPath
Input
[{
"name":"tet",
"id":"1",
"age" : "34"
},{
"name":"tet",
"id":"1",
"age" : "34"
},{
"name":"tet",
"id":"1",
"age" : "34"
},{
"name":"tet",
"id":"1",
"age" : "34"
}]
Example
ObjectMapper objectMapper = new ObjectMapper();
JsonNode root = objectMapper.readTree(new File("foo.json"));
System.out.println(root.at("/0/name").asText());

I would say you can either try looking for a library which allows you to search throught JSON data or to convert your json to JSONObjects and query your data in a Object Oriented way.
Perhaps this thread will help:
Query a JSONObject in java

there is no way to query directly from the Json, if you want you have to create a new class that will do your requirement, OR you can use the ObjectMapper (download and add to your class path) from jackson-all-1.9.0.jar, and create a new transfer Object TestTO.java expose the setters and getters you will get your data like below..
1.create TestTO.java
public class TestTO{
private String name;
private int id;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2.read your data from the object.
final ObjectMapper mapper = new ObjectMapper();
Test test = mapper.readValue(yourJson.json, TestTO.class);
String name = test.getName();
int id = test.getId();
int age = test.getAge();
if your json contains the multiple test objects, use an test array like below, it will give you the array of tests, you can iterate over and get the data, like below.
final ObjectMapper mapper = new ObjectMapper();
TestTO[] test = mapper.readValue(yourJson.json, TestTO.class[]);
for(Test tst:test){
String name = test.getName();
int id = test.getId();
int age = test.getAge();
}

Related

Convert Java object list to correct name value pair format in Json using Gson

I have a Java Class named User with
#Column(name = "id")
private Long id;
#NotNull
#Column(name = "NAME")
private String name;
I am trying to get some details in a list and convert it into JSOn like so:
Session session = this.sessionFactory.getCurrentSession();
String queryString="select id,name from User where unit=:name";
Query query= sessionFactory.getCurrentSession().createQuery(queryString);
query.setParameter("name", name);
List<User> users= (List<User>) query.list();
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Map<String, List<User>> wrap = new HashMap<>();
wrap.put("users", users); // wrap user list in a map
String json = gson.toJson(wrap);
This produces a JSON
{
"users": [
[
1,
"Room"
],
[
2,
"Regi"
],
]
}
How do I change it so that I get a JSON like
{
"users": [
[
"id":1,
"name":"Rovom"
],
[
"id":2,
"name":"Regi"
],
]
}
Edit
I realized it is the query that is causing the issue. If i use
String queryString="from User where unit=:name";
It gives the correct format. How do I fix this?
Whith jackson, it'll look like this:
String json = new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueToString(wrap);
You'd want jackson-core and jackson-databind for this at least.
Full example using Jackson:
public static class User {
private Long id;
private String name;
public User(long i, String n) {
id = i;
name = n;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String... args) {
try {
Map<String,Object> map = new HashMap<>();
map.put("users", Arrays.asList(new User(1, "Stack"), new User(2, "Overflow")));
System.out.println(new ObjectMapper().writerWithDefaultPrettyPrinter()
.writeValueAsString(map));
} catch (Exception e) {
e.printStackTrace();
}
}
produced this output:
{
"users" : [ {
"id" : 1,
"name" : "Stack"
}, {
"id" : 2,
"name" : "Overflow"
} ]
}
Hm, looks like type erasure at runtime.
Your List<User> is with the first query actually a List<Object[]> as which it got serialized. Would you try to access an User-object out of the list, you'd get a runtime error, I suppose.
See hibernate documentation:
Return the query results as a List. If the query contains multiple
results pre row, the results are returned in an instance of Object[].
EDIT
to get a list of Users with only the two fields filled, create the apropriate constructur and use a query like
select new package.path.to.class.User(id,name) from User where unit=:name"
As mentioned by user #Turo this is because of type erasure at runtime.
To fix this, the query has to be changed to
String queryString="select id,name from User where unit=:name";
Query query= sessionFactory.getCurrentSession().createSQLQuery(queryString).addScalar("name", new StringType()).addScalar("id", new IntType()).setResultTransformer(Transformers.aliasToBean(User.class));
query.setParameter("name", name);
the addScalar() will map the values to the User objects and this gives the required result.

How to get the data from the JSON list of JSON list

I've got an JSON string from my API, looks like this:
[
{
"id": "abc",
"data": {
"Name": "Peter",
"Date": "2017/12/01"
}
},
{
"id": "def",
"data": {
"Name": "Tina",
"Date": "2017/12/20"
}
},
{
"id": "ghi",
"data": {
"Name": "Amy",
"Date": "2017/12/16"
}
}
]
Then, I use (java):
Gson gson = new Gson();
Type resultType = new TypeToken<List<Map<String, Object>>>() {
}.getType();
List<Map<String, Object>> result = gson.fromJson(info, resultType);
if I call result.get(0).toString());
then it returned:
{id=abc, data={Name=Peter, Date=2017/12/01}}
if I call result.get(0).get("id").toString();
then it returned
abc
Now I want to get the data of "data", when I call result.get(0).get("data").toString();
then it returned
{Name=Peter, Date=2017/12/01}
Finally I want to get the "Name" info, but when I tried to convert this string to Map, it cause some problem, the code is like this:
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> myMap = gson.fromJson(str, type);
This doesn't work. I found that maybe the string is not a general type of JSON, it is like "Name=Peter, Date=2017/12/01", but it needs "Name": "Peter", "Date": "2017/12/01" , right? Is that the problem? How can I get the data of Name? Can anyone help me?
Updated:
I found that if "Name" = "", then I couldn't get it as string type, I cannot use "data.get("Name");". But I still need it. Anyone can fix it? Thanks.
You can directly convert the response into the POJO/Model class. Check this and this
You don't need manual parsing, if you are using Gson. See how-
List<Response> responseList = new Gson().fromJson(yourJson, new TypeToken<List<Response>>() {
}.getType());
Data data = responseList.get(0).getData();
String id = responseList.get(0).getId();
String date = data.getDate();
String name = data.getName();
Isn't this magic? No manual parsing at all.
Response.java class
public class Response {
private Data data;
private String id;
public void setData(Data data) {
this.data = data;
}
public Data getData() {
return data;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
Data.java class
public class Data {
private String date;
private String name;
public void setDate(String date) {
this.date = date;
}
public String getDate() {
return date;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
How to generate Pojo classes? So here is several websites jsonschema2pojo. Also many Android Studio plugins available, I use RoboPOJOGenerator.
First of all, your JSON is malformed, it shouldn't have a comma after date.
and to answer your question, don't use map at all.
If you really want to do it without creating a model and additional classes, do it this way:
Gson gson = new Gson();
Type resultType = new TypeToken<List<JsonObject>>() {}.getType();
List<JsonObject> result = gson.fromJson(info, resultType);
System.out.println(result.get(0).get("data").toString());
JsonObject data = result.get(0).get("data").getAsJsonObject();
System.out.println(data.get("Name"));

Mapping Json into nested POJO

I've the following JSON from some upstream api
{
"Id": "",
"Name": "",
"Age": ""
}
And I need to map this above json to a downstream request paylaod (POJO) .
public class Employee
{
#JsonProperty("Id")
private Integer Id;
private User user;
}
public class User {
#JsonProperty("Name")
private String name;
#JsonProperty("Age")
private String age;
}
Right now I'm doing something like
Employee employee = new ObjectMapper().treeToValue(JsonNode node,Employee.class);
But this is giving null in User Object.
The challenge here is , that the json we are getting from upstream can't be changed . So , is there is any way to map the fields into the nested User object , without changing the structure of json received from upstream.
One Solution is : map the fields separately into User object and then set it into the Employee object . But that's not an efficient solution , because for null validations we would need to do validations separately for User and Employee objects. If the nesting is complex then , validation will be hell of replicated code .
Your JSON does not comply with your Employee class.
Because name and age is at the same level as id, but you want to wrapped in a class User.
So either:
Change the json the structure to
{
"id": "",
"user": {
"name": "",
"age": ""
}
}
Or
Unwrap the User class, the Employee class will be:
public class Employee
{
#JsonProperty("Id")
private Integer Id;
#JsonProperty("Name")
private String name;
#JsonProperty("Age")
private String age;
}
Edit
If you can't choose either option 1 or 2, you have only one option left is to create custom deserializer:
Write a deserializer:
public class EmployeeDeserializer extends StdDeserializer<Item> {
public EmployeeDeserializer() {
this(null);
}
public EmployeeDeserializer(Class<?> vc) {
super(vc);
}
#Override
public Employee deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
int id = (Integer) ((IntNode) node.get("Id")).numberValue();
String name = node.get("Name").asText();
String age = node.get("Age")).asText();
User user = new User(name, age);
return new Employee(id, user);
}
}
Then register this deserializer:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Employee.class, new EmployeeDeserializer());
mapper.registerModule(module);
Employee readValue = mapper.readValue(json, Employee.class);
Another way to register deserializer is:
#JsonDeserialize(using = EmployeeDeserializer.class)
public class Employee {
It seems you are not nesting your JSON correctly. Or your Object Structure is wrong.
JSON should be:
{
"Id": "",
"user" : {
"Name": "",
"Age": ""
}
}
The json structure does not match the structure of your classes.
if the json was like;
{
"Id": "an-id,
"user": {
"Name": "Joe",
"Age": "21"
}
}
Then your code to deserialise to an Employee object would work.

How to create a JSON array with this specific structure?

I intend to create a JSON Array with the following structure. The metadata tag is going to constant in all the entries. I am stumped.
[{
"metadata": {
"Value": "String"
},
"name": "String",
"id": "String"
},
{
"metadata": {
"Value": "String"
},
"name": "String",
"id": "String"
}
]
public class yourJsonObject {
private Map<String, String> metadata;
private String name;
private string id;
public yourJsonObject() {
}
public Map<String, String> getMetadata(){
return metadata;
}
public void setMetadata(Map<String, String> metadata){
this.metadata = metadata;
}
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId(){
return id;
}
public void setId(String id){
this.id = id;
}
}
Then somewhere else you can just do this:
ObjectMapper mapper = new ObjectMapper(); // create once, reuse
yourJsonObject example = new yourJsonObject(); // have your POJO you want to save
mapper.writeValue(new File("result.json"), example);
To read you can just use:
ObjectMapper mapper = new ObjectMapper(); // create once, reuse
yourJsonObject value = mapper.readValue(new File("data.json"), yourJsonObject .class);
Both snippets are taken from my linked wiki article from jackson themselves.
Jackson should automatically be able to parse this POJO to an equivalent JSON if configured correctly.
Note: Jackson has to be globally registered and has to know about it. Please read the wiki of what you use to know about it... Jackson in 5 Minutes
Else you could just manually build the JSON like Neeraj said.
JSONArray array = new JSONArray(); // Create JSONArray Object
JSONObject jsonObject = new JSONObject(); // Your JSONObject which gets added into array
jsonObject.put("metadata",new MetaDataCustomClass("SomeRandomStringValue"));
jsonObject.put("name", "Neeraj");
jsonObject.put("id", "123");
array.add(jsonObject); // Here you push the jsonObject into Array.
Note: MetaDataCustomClass is just a custom Class having a Value instance variable of type String.
Class MetaDataCustomClass {
private String value;
public MetaDataCustomClass(String value){
this.value = value;
}
}

Java - Jackson JSON Library and ObjectMapper.readValue

I have the following json data (patients.json):
{
"A" : {
"name" : "Tom",
"age" : 12
},
"B" : {
"name" : "Jim",
"age" : 54
}
}
Using the Jackson JSON library, how can I get something like the following:
HashMap<String, ???> patients = objectMapper.readValue(new File("patients.json"), ???);
String Aname = patients.get("A").get("name");
int Aname = patients.get("A").get("age");
Deserialize your JSON into Jackson's JSON Object type, ObjectNode. You can then traverse it as you see fit.
For example
ObjectNode patients = objectMapper.readValue(new File("test.json"), ObjectNode.class);
// you can check if it is actually an ObjectNode with JsonNode#isObject()
ObjectNode nodeA = (ObjectNode)patients.get("A");
String name = nodeA.get("name").asText();
int age = (int) nodeA.get("age").asLong();
Note that the methods asXyz() return default values if the target node cannot be converted to that type. You can check with the corresponding isXyz() methods before invoking them.
You could create a class to map your patients to;
private static class Patient {
#JsonProperty("name")
private String name;
#JsonProperty("age")
private int age;
public Patient() { }
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
Then read your json into it via jackson
HashMap<String, Patient> patients = objectMapper.readValue(new File("patients.json"), new TypeReference<HashMap<String,Patient>>() {});
Patient patientA = patients.get("A");
String patientAName = patientA.getName();
int pateintAAge = patientA.getAge();

Categories