I am retrieving an Json from an API. The problem is that I don't have any idea on how to convert Json format to a format maybe a java class so that it can be used by me to get the intended values.
This is my sample Json format
{
"par_a":".....",
"par_b": [ {
"b1":".....",
"b2":".....",
"b3":".....",
"b4":".....",
"b5":".....",
"b6":".....",
"b7":".....",
"b8":".....",
"b9":".....",
"b10": { "b10-1":".....", "b10-2":".....", "b10-3":"....." } ,
"b11": { "b11-1": ["....." ], "b11-2": ["....." ] } ,
"b13":"......."
} ]
}
I do not have an option to contact the owner of the API and understand how this works and hence any help would be really grateful.
I have seen many posts online but I have nowhere seen a Json format as mine hence no solution has worked for me.
A nice workaround would be to create a Model corresponding to the response you're receiving from the server and using GSON library you can easily deserialize the json to your model.
Your model will be something like this:
public class MyResponseModel {
#SerializedName("par_a")
private String parameterA;
#SerializedName("par_b")
private List<AnotherModel> parametersB;
/.../
}
If you get the data from your json file and it store in your project then
your solution is here.
Gson gson = new Gson();
String customRatioResponse = LocalUtils.loadJSONFromAsset(getActivity(), "custom_ratio.json"); // here custom_ratio.json is my json file. it's store in assets folder of project
CustomRatioList getSampleImageResponse = gson.fromJson(customRatioResponse, CustomRatioList.class); // here CustormRatioList is my POJO file
Log.i(TAG, "getAllCategory() -> Offline list size: " + (getSampleImageResponse.getCustomRatio() != null ? getSampleImageResponse.getCustomRatio().size() : 0));
return getSampleImageResponse.getCustomRatio();
Here, If your Json file having too much data or list of data then it gives you arrayList type of data.
LocalUtils.java
public class LocalUtils {
public static String loadJSONFromAsset(Context context, String jsonFilePath) {
String json = null;
try {
InputStream is = context.getAssets().open(jsonFilePath);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
json = new String(buffer, "UTF-8");
} catch (Throwable e) {
e.printStackTrace();
return "";
}
return json;
}
}
If will you get pojo of your json then go to http://www.jsonschema2pojo.org/ paste your sample data json and get pojo structure. Thank you for read.
You have an excellent library doing that, Use GSON lib. You just have to create an object representing your Json File, and when you will decode it, it will feel your object with your json datas !
Use this way
public String loadJSONFromAsset() {
String json = null;
try {
InputStream is = getActivity().getAssets().open("filename.json");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
json = new String(buffer, "UTF-8");
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
return json;
}
and then parse the json
JSONObject obj = new JSONObject(loadJSONFromAsset());
Install DTO generator plug in for android studio ("this will be useful for future works too"). : File -> settings -> plugins -> search for DTO and install
Create a simple class say DataRetriever. Place cursor in that class and press Alt+insert -> select DTO from JSON
Enter obtained JSON in the window and press generate. This will make your class Gson with all attributes in Json. Create getter and setter for attributes. Result will be like
public class DataRetriever {
#Expose
#SerializedName("par_b")
private List<Par_bEntity> mPar_b;
#Expose
#SerializedName("par_a")
private String mPar_a;
public List<Par_bEntity> getmPar_b() {
return mPar_b;
}
public void setmPar_b(List<Par_bEntity> mPar_b) {
this.mPar_b = mPar_b;
}
public String getmPar_a() {
return mPar_a;
}
public void setmPar_a(String mPar_a) {
this.mPar_a = mPar_a;
}
/**
* Similar to these getter and setter, you can add getter and setter for sub
classes also
*/
}
class Par_bEntity {
#Expose
#SerializedName("b13")
private String mB13;
#Expose
#SerializedName("b11")
private B11Entity mB11;
#Expose
#SerializedName("b10")
private B10Entity mB10;
#Expose
#SerializedName("b9")
private String mB9;
#Expose
#SerializedName("b8")
private String mB8;
#Expose
#SerializedName("b7")
private String mB7;
#Expose
#SerializedName("b6")
private String mB6;
#Expose
#SerializedName("b5")
private String mB5;
#Expose
#SerializedName("b4")
private String mB4;
#Expose
#SerializedName("b3")
private String mB3;
#Expose
#SerializedName("b2")
private String mB2;
#Expose
#SerializedName("b1")
private String mB1;
}
class B10Entity {
#Expose
#SerializedName("b10-3")
private String b10_3;
#Expose
#SerializedName("b10-2")
private String b10_2;
#Expose
#SerializedName("b10-1")
private String b10_1;
}
class B11Entity {
#Expose
#SerializedName("b11-2")
private List<String> b11_2;
#Expose
#SerializedName("b11-1")
private List<String> b11_1;
}
At the place where you obtain json string get values to DataRetriever class by calling
DataRetriever mDataRetriever = new Gson().fromJson(jsonString, DataRetriever.class);
Using mDataRetriever object and getter methods you can retrieve value using
Ex : mDataRetriever.getmPar_a()for value “par_a”
Suppose you are trying to find the string value for b10-1 :
The code will be like below:
String json = "{par_a:.....,par_b: [ {b1:.....,b2:.....,b3:.....,b4:.....,b5:.....,b6:.....,b7:.....,b8:.....,b9:.....,b10: { b10-1:....., b10-2:....., b10-3:..... } ,b11: { b11-1: [..... ], b11-2: [..... ] } , b13:.......} ]}";
try{
String result = new JSONObject(json).getJSONArray("par_b").getJSONObject(0).getJSONObject("b_10").getString("b10-1");
}catch(Exception e){
}
Related
My service can receive several different jsons, such as:
{
"event":"conversation_started",
"context":"context information",
"user":{
"id":"01234567890A=",
"name":"John McClane",
"avatar":"http://avatar.example.com",
"country":"UK",
"language":"en",
"api_version":1
},
"subscribed":false
}
or
{
"event":"message",
"message":{
"type":"text",
"text":"a message to the service",
"location":{
"lat":12.34,
"lon":12.34
}
}
}
or several else jsons. The only field that is the same for all jsons is "event". All other fields can be different (depends on "event" value).
So the question is: how to convert those jsons to java objects (without making messy code)? The only way I know is to manually check "event" value (like json.startsWith("{\n\"event\":\"message\"") but I'm sure that there is any simple decision for doing this.
There are three ways I've done this. The first is to do what you're suggesting - parse the JSON, check the type, and create the object. Be very careful with using a String parser as you may or may not have things like new lines. Instead, do something like:
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(eventString);
String eventType = jsonNode.get("event").asText();
if( eventType.equalsIgnoreCase("conversation_started")) {
// create ConversationStarted object using something like:
ConversationStarted conversationStarted = objectMapper.readValue( eventString, ConversationStarted.class );
}
This, of course, requires all classes to have a concrete POJO to allow for deserialization.
Another way is to do what many other programming languages do and have a key/value map. There are a few ways to do this. One is with the Jackson libraries:
Map<String, Object> map = objectMapper.readValue(eventString, new TypeReference<Map<String,Object>>(){});
Map<String, Object> user = (Map<String, Object>) map.get("user");
System.out.println( "conversation started - avatar is " + user.get("avatar"));
That way you can pass around the Map and extract as needed. Note that you still need to understand the structure of the JSON but you don't need to have a POJO for it.
Lastly is a variation on the second solution. Using JSONPath you can pull out what you need directly. Again you will want to first check out which type of event you have. Something like:
if( JsonPath.read(eventString, "$.event").equals("conversation_started") ) {
String avatar = JsonPath.read(eventString, "$.user.avatar");
System.out.println("conversation started - avatar is " + avatar);
}
The last two methods require you to pull out values one at a time as shown. The first solution gives you a full object to work with. It is your call as to what works best in your environment.
UPD: If you don't want to convert JSON String to JAVA Object via declaring a POJO, you can parse it to JSONObject(com.alibaba.fastjson.JSONObject)
public class Event {
public static void main(String[] args) {
String jsonA = "{\"event\":\"conversation_started\",\"context\":\"context information\",\"user\":{\"id\":\"01234567890A=\",\"name\":\"John McClane\",\"avatar\":\"http://avatar.example.com\",\"country\":\"UK\",\"language\":\"en\",\"api_version\":1},\"subscribed\":false}";
String jsonB = "{\"event\":\"message\",\"message\":{\"type\":\"text\",\"text\":\"a message to the service\",\"location\":{\"lat\":12.34,\"lon\":12.34}}}";
JSONObject jsonObject = JSONObject.parseObject(jsonA);
String event = jsonObject.getString("event");
if (event.equals("message")) {
//do what you want to do
System.out.println("message event......");
} else if ("conversation_started".equals(event)) {
System.out.println("context information event......");
}
}
}
Declaring a class of Event as below, and then convert JSON String to a Event JAVA object.
#Data
public class Event {
private String event;
private String context;
private User user;
private boolean subscribed;
private Message message;
#Data
public static class User {
private String id;
private String name;
private String avatar;
private String country;
private String language;
private int api_version;
}
#Data
public static class Message {
private String type;
private String text;
private Location location;
#Data
public static class Location {
private double lat;
private double lon;
}
}
public static void main(String[] args) {
String jsonA = "{\"event\":\"conversation_started\",\"context\":\"context information\",\"user\":{\"id\":\"01234567890A=\",\"name\":\"John McClane\",\"avatar\":\"http://avatar.example.com\",\"country\":\"UK\",\"language\":\"en\",\"api_version\":1},\"subscribed\":false}";
String jsonB = "{\"event\":\"message\",\"message\":{\"type\":\"text\",\"text\":\"a message to the service\",\"location\":{\"lat\":12.34,\"lon\":12.34}}}";
ObjectMapper objectMapper = new ObjectMapper();
try {
Event eventA = objectMapper.readValue(jsonA, new TypeReference<Event>() {
});
System.out.println(objectMapper.writeValueAsString(eventA));
Event eventB = objectMapper.readValue(jsonB, new TypeReference<Event>() {
});
System.out.println(objectMapper.writeValueAsString(eventB));
} catch (IOException e) {
e.printStackTrace();
}
}
}
Use a JSON object. This is dynamic and can load any json. Then you can reference the event field consistently
Example 1
//import java.util.ArrayList;
//import org.bson.Document;
Document root = Document.parse("{ \"event\" : \"conversation_started\", \"context\" : \"context information\", \"user\" : { \"id\" : \"01234567890A=\", \"name\" : \"John McClane\", \"avatar\" : \"http://avatar.example.com\", \"country\" : \"UK\", \"language\" : \"en\", \"api_version\" : 1 }, \"subscribed\" : false }");
System.out.println(((String)root.get("event")));
Example 2
//import java.util.ArrayList;
//import org.bson.Document;
Document root = Document.parse("{ \"event\" : \"message\", \"message\" : { \"type\" : \"text\", \"text\" : \"a message to the service\", \"location\" : { \"lat\" : 12.34, \"lon\" : 12.34 } } }");
System.out.println(((String)root.get("event")));
I was able to pull data from an api using my get request method
{"vulnerabilities":[{"id":5027994,"status":"open","closed_at":null,"created_at":"2019-06-07T06:10:15Z","due_date":null,"notes":null,"port":[],"priority":null,"identifiers":["adobe-reader-apsb09-15-cve-2009-2990"],"last_seen_time":"2019-07-24T05:00:00.000Z","fix_id":4953,"scanner_vulnerabilities":[{"port":null,"external_unique_id":"adobe-reader-apsb09-15-cve-2009-2990","open":true}],"asset_id":119920,"connectors":[{"name":"Nexpose Enterprise","id":7,"connector_definition_name":"Nexpose Enterprise","vendor":"R7"}],"service_ticket":null,"urls":{"asset":"dummy.com"},"patch":true,"patch_published_at":"2009-10-08T22:40:52.000Z","cve_id":"CVE-2009-2990","cve_description":"Array index error in Adobe Reader and Acrobat 9.x before 9.2, 8.x before 8.1.7, and possibly 7.x through 7.1.4 might allow attackers to execute arbitrary code via unspecified vectors.","cve_published_at":"2009-10-19T22:30:00.000Z","description":null,"solution":null,"wasc_id":null,"severity":9,"threat":9,"popular_target":false,"active_internet_breach":true,"easily_exploitable":true,"malware_exploitable":true,"predicted_exploitable":false,"custom_fields":[],"first_found_on":"2019-06-05T05:22:23Z","top_priority":true,"risk_meter_score":100,"closed":false}
the problem I have encountered is to parse this json data by separating it by colon and comma?
I have created a parser method show below:
public static TableRow parseRequest(String request, TableRow row) {
JsonParser parser= new JsonParser();
try {
Object object = parser.parse(request);
//throws an ClassCastException JsonObject jsonObject = (JsonObject) object;
JsonArray array = (JsonArray) object;
for (Iterator iterator = jsonObject.keySet().iterator(); iterator.hasNext(); ) {
String keyString = (String) iterator.next();
System.out.println("iterator" + iterator);
System.out.println(jsonObject.get(keyString));
}
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}
return parserequesTableRow(row);
}
The results that I get is java.lang.ClassCastException. I am very new to Json so I would like to know if there is a better method than the one I am implementing?
I would advise to use jackson library for this. Jackson is a library for parsing json string to java class. You can also generate a json from a java class. See here for more info and how to use it: https://www.baeldung.com/jackson-object-mapper-tutorial
Here is an example how you can set it up. First create a java pojo which should be equal to your response json:
#JsonInclude(NON_NULL)
class Response {
private List<Vulnerability> vulnerabilities;
// getters and setters
}
#JsonInclude(NON_NULL)
class Vulnerability {
private String id;
private String status;
private String closed_at;
private String created_at;
private String due_date;
private String notes;
private String[] port;
private String priority;
// etc for other class members
// getters and setters
}
And here is your parsing logic:
public static void main(String[] args) throws IOException {
String json = ""; //put here your data which you got from your get request
ObjectMapper objectMapper = new ObjectMapper();
Response response = objectMapper.readValue(json, Response.class);
}
Game class:
public class Game {
private String name;
private int steam_appid;
private boolean isInstalled;
}
Json example: https://store.steampowered.com/api/appdetails/?appids=435150&filters=basic
My attempt:
public static Game readJson(String gameID) throws IOException {
String targetURL = String.format(STEAM_API, gameID);
URL url = new URL(targetURL);
InputStreamReader reader = new InputStreamReader(url.openStream());
Gson gson = new Gson();
Game json = gson.fromJson(reader, Game.class);
return json;
}
When I tried to print the output, I get Name:null steam_appid:0 isInstalled:false
I want to check the key success first, if value is true parse it to Game. Otherwise, do nothing.
How can I parse the Json to my Game?
If a field is marked transient, (by default) it is ignored and not included in the JSON serialization or deserialization.
https://sites.google.com/site/gson/gson-user-guide#TOC-Finer-Points-with-Objects
use below code if you don't want to include name in json:
public class Game
{
private transient String name;
private int steam_appid;
private boolean isInstalled;
}
Option 1:
Ignore Field at the Field Level
public class Game {
private String name;
#JsonIgnore
private int steam_appid;
private boolean isInstalled;
}
We can also ignore a field directly via the #JsonIgnore annotation directly on the field:
Option 2:
In another way you can use #JsonIgnoreProperties annotation to skip pojo properties. Here is the code snippet: You can use either way.
#JsonIgnoreProperties({ "name", "steam_appid" })
public class Game {
private String name;
private int steam_appid;
private boolean isInstalled;
}
Based on the response example the class to use Gson should look like this:
Note the classes need the getters and setters to be added.
class SteamResponseWrapper{
#SerializedName("434150")
private SteamResponse steamResponse;
}
class SteamResponse{
boolean success;
GameData data;
}
class GameData {
String name;
int steam_appid;
// I couldn't find the isInstalled property if you are adding it, make it transient
}
With this structure you would call:
SteamResponseWrapper wrapper = new Gson().fromJson(reader, SteamResponseWrapper.class)
and then
wrapper.getSteamResponse().isSuccess()
to check the success field.
And
wrapper.getSteamResponse().getData()
to access the game object.
But the problem I see is that the top object name is in fact data and will change for every game. So I don't think Gson will be able to handle this because for every request the annotated serialized name should be different.
I think you will be better of handling it with Jackson or as a JsonObject.
EDIT I
This example uses these maven dependencies:
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.0.4</version>
</dependency>
The example:
public class SteamApiReader {
private static final String STEAM_API = "http:// ......";
public static void main(String args[]) {
try {
SteamApiReader.readJson("435150");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static Game readJson(String gameID) throws IOException {
Game rtn = null;
String targetURL = String.format(STEAM_API, gameID);;
URL url = new URL(targetURL);
InputStreamReader reader = new InputStreamReader(url.openStream());
JsonReader jsonReader = Json.createReader(reader);
JsonStructure jsonStructure = jsonReader.read();
JsonObject jsonObject = (JsonObject) jsonStructure;
JsonObject wrapper = jsonObject.getJsonObject(gameID);
boolean success = wrapper.getBoolean("success");
if(success) {
JsonObject data = wrapper.getJsonObject("data");
String name = data.getString("name");
int steamAppId = data.getInt("steam_appid");
rtn = new Game(name, steamAppId);
}
return rtn;
}
public static class Game{
public Game(String name, int steamAppId) {
this.name = name;
this.steamAppId = steamAppId;
}
String name;
int steamAppId;
}
}
I have two object one is Dashboard and second is Room i have a json which is look like this
{
"hotel_id":"1",
"hotel_room":"200",
"hotel_properties":[{
"id":"1",
"room_type":"Single",
"rack_rate":"2000",
"publish_rate":"1800",
"discount":"10",
"availiable":"40",
"total":"50"
},
{
"id":"2",
"room_type":"Double",
"rack_rate":"4000",
"publish_rate":"3600",
"discount":"10",
"availiable":"45",
"total":"50"
}
]
}
And the Object is
public class DashBoard {
private int hotel_id;
private int hotel_room;
#JsonProperty("hotel_properties")
private Room hotel_properties;
}
There is another Object Room which is look like this
public class Room {
private Long id;
private String room_type;
private String rack_rate;
private String publish_rate;
private String discount;
private String availiable;
private String total;
}
I am Hide all constructor,setter and getter for Stackoverflow but it is in my code
i want parse Json to Object using ObjectMapper from an URL using this code
JsonReader jsonReader = new JsonReader();
ObjectMapper mapper = new ObjectMapper();
try {
JSONObject json = jsonReader.readJsonFromUrl("http://localhost/quinchy/json/dashboard.json");
DashBoard dsh = mapper.readValue(json.toString(), DashBoard.class);
System.out.println(json.toString());
} catch (IOException | JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
but i get this error
org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of Object out of START_ARRAY token
please help me out from this
From the JSON String you posted, it looks like there is a list of Room objects. But you have used a single object.
In your DashBoard class, try changing:
private Room hotel_properties;
to:
private List<Room> hotel_properties;
I just try to integrate with external webservice via JSON from Android. I receive following JSON format:
Data that i'm interested in is in "messages" branch.
To access data i'm using :
builder.setFieldNamingPolicy(FieldNamingPolicy.IDENTITY);
Gson gson = builder.create();
ClassToStore response = gson.fromJson(reader, ClassToStore.class);
where reader is a input stream from:
am = getInstrumentation().getContext().getAssets();
am.open("data.json");
Message structure looks like:
ClassToStore has all fields with the same names.
I get all objects but all of theme are null's
PLEASE HELP :(
My classToStore:
public static class ClassToStore implements Serializable {
private static final long serialVersionUID = -1463052486583654136L;
public String id ;
public String replied_to_id ;
public String sender_id ;
public String created_at ;
public String getId() {
return id;
}
public String getReplied_to_id() {
return replied_to_id;
}
public String getSender_id() {
return sender_id;
}
public String getCreated_at() {
return created_at;
}
}
You will need an extra class to match the outer object:
public class OuterObject {
List<ClassToStore> messages;
}
And then load it like this:
Gson gson = new Gson();
Type type = new TypeToken<List<OuterObject>>(){}.getType();
List<OuterObject> outerList = gson.fromJson(reader, type);
List<ClassToStore> listOfMessages = outerlist.get(0).messages;