Updating JSON Key within Json File - java

I have the following code to update the key "runTimeDate" within my json file.
`final LocalDate plus180Days = LocalDate.now().plusDays(180);
DateTimeFormatter dateTimeFormatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd");
String substituteDate = plus180Days.format(dateTimeFormatter);
String jsonFile = "src/examples/sample.json";
public String Body_ValueDate()
{
return jsonFile.replaceAll("\"runTimeDate\"", "\"" + substituteDate +
"\"");
}
public String Body_KeyDate()
{
return Body_ValueDate().replaceAll("\"keyDate\"", "\"" +
substituteDate + "\"");
}`
I used the code above from here: https://stackoverflow.com/questions/7463414/what-s-the-best-way-to-load-a-jsonobject-from-a-json-text-file#:~:text=23-,With%20java%208,-you%20can%20try
Thing is, the date is not getting updated. plus180Days is basically a function adding 180 days from current date. Can anyone share what I am missing here?
final LocalDate plus180Days = LocalDate.now().plusDays(180);
Sample Json
{
"city": {
"details": {
"a1": "AUS",
"a2": "AUS",
"country": "AUS"
}
},
"detail": {
"getCountryDetail": {
"b1": "SYD",
"b2": "MEL",
"country": {
"keyDate|AUS|1234|SYD|MEL": {
"date1": "runTimeDate",
"time1": "15:38",
"date2": "runTimeDate",
"time2": "19:13"
},
"keyDate|AUS|1234|ADL|MEL": {
"date1": "runTimeDate",
"time1": "15:38",
"date2": "runTimeDate",
"time2": "19:13"
}
}
}
}
}
I am using the updated json method "Body_KeyDate" as body parameter for my rest assured method as per here:
#Test
public void UA_Avail_Cascading_Request()
throws IOException
{
Response response = RestAssured.given()
.header(readConfigFile())
.contentType("application/json")
.body(Body_KeyDate())
.when()
.post(readBaseUrl() + "samplePage")
.then().statusCode(200)
.log().all()
.extract().response();
}
Following solution worked: with ObjectMapper
public JsonNode RequestBody_DynamicDate() throws Exception
{
String requestBodyJson = loadJson("Sample.json");
String removeKeyDate = requestBodyJson.replace("keyDate", NEW_DATE);
String removeValueDate = removeKeyDate.replace("runTimeDate", NEW_DATE);
JsonNode processedNewDates = OBJECT_MAPPER.readTree(removeValueDate);
System.out.println("New JSON Body: "
+ OBJECT_MAPPER
.writerWithDefaultPrettyPrinter()
.writeValueAsString(processedNewDates));
return processedNewDates;
}
Here is the code for loadJson: BASEPATH is the folder location
String loadJson(String filePath)
{
try
{
return new String(Files.readAllBytes(Paths.get(BASEPATH + filePath)));
}
catch (Exception e)
{
Assertions.fail("unable to load test data, check file path, and format");
throw new RuntimeException();
}
Hope this helps someone. Also turns there was some restrictions and limitations on which library and packages can be used.

Related

Gson howto parse different data types in a single array?

I have an API response that includes METAR weather data as well as string error responses, both contained in the same "data" array. I am using Gson to parse the json response on Android. This works great until I get a string error response. I've tried my hand at trying to write a custom Gson deserializer with no luck. Can someone give me a working example or point me in the correct direction on how to handle this?
The response looks like this:
{
"results": 4,
"data": [
{
"icao": "KAJO",
"name": "Corona Municipal",
"observed": "05-11-2018 # 18:56Z",
"raw_text": "KAJO 051856Z AUTO VRB03KT 10SM CLR 23/08 A2989 RMK AO2 SLP129 T02330078 $",
"barometer": {
"hg": 29.890000000000001,
"kpa": 101.22,
"mb": 1012.9
},
"clouds": [
{
"code": "CLR",
"text": "Clear skies",
"base_feet_agl": 0,
"base_meters_agl": 0
}
],
"dewpoint": {
"celsius": 8,
"fahrenheit": 46
},
"elevation": {
"feet": 535,
"meters": 163
},
"flight_category": "VFR",
"humidity_percent": 38,
"temperature": {
"celsius": 23,
"fahrenheit": 73
},
"visibility": {
"miles": "10",
"meters": "16,093"
},
"wind": {
"degrees": 0,
"speed_kts": 3,
"speed_mph": 3,
"speed_mps": 2
}
},
"KGNG METAR Currently Unavailable",
"CXCY Invalid Station ICAO"
]
}
As you can see the "data" array may return a metar object (I have this part working) or an unnamed error string. It is when I get the error string returned that my parsing fails.
As a test I wrote the following. But it is also not working. How can I parse the both the raw unnamed string and the metar object?
import com.google.gson.*;
import java.lang.reflect.Type;
import java.util.List;
public class Main {
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(Response.class, new MyDeserializer())
.registerTypeAdapter(String.class, new String())
.create();
Response response = gson.fromJson(str_json, Response.class);
System.out.println("Hello World!");
}
static class MyDeserializer implements JsonDeserializer<Response> {
#Override
public Response deserialize(JsonElement json, Type typeOfT
,JsonDeserializationContext context) throws JsonParseException {
// Get the "data" element from the parsed json
JsonElement data = json.getAsJsonObject().get("data ");
// Deserialize it. You use a new instance of Gson to avoid
// infinite recursion
return new Gson().fromJson(data, Response.class);
}
}
/*===============================
* Data Definitions
*==============================*/
class Response {
public String results;
public List<Station> Stations;
}
class Station {
public String name;
public String icao;
}
public static String str_json = "{\n" +
" \"results\": 3,\n" +
" \"data\": [\n" +
" {\n" +
" \"name\": \"Billings Logan Intl\"," +
" \"icao\":\"KBIL\"," +
" },\n" +
" \"CYPG METAR Currently Unavailable\",\n" +
" \"KGNG METAR Currently Unavailable\"\n" +
" ]\n" +
"}";
}
First it would make thing seasier if you changed the DTOs a bit, for the Response
public class Response {
public String results;
public List<Station> data; // it is named data in JSON not Stations
}
Then the rest is done depending on how you would like to handle the error text. One easy way would be to just add error field to your Station so that it would be:
public class Station {
public String name;
public String icao;
public String error; // used if there is only error string
}
With a custom deserialiser like:
public class StationDeserializer implements JsonDeserializer<Station> {
private final Gson gson = new Gson();
#Override
public Station deserialize(JsonElement json, Type typeOfT
,JsonDeserializationContext context)
throws JsonParseException {
try {
return gson.fromJson(json, Station.class);
} catch (JsonSyntaxException e) {
// it was not a Station object
Station station = new Station();
// so try to set the error string
station.error = json.getAsString();
return station;
}
}
}
The try to deserialize:
Response response = new GsonBuilder()
.registerTypeAdapter(Station.class, new StationDeserializer())
.create()
.fromJson(str_json, Response.class);
Checking if there is an error string in a Station or not you can see if the data is valid.

JSON Post Response from JSON Post Request

I have created a REST webservice which gives me
'GET JSON Response' as :
{
"payload": {
"RFID": "E2005180040F003122202E5F",
"chassisNumber": "4654689761",
"vehicleNumber": "TN 01 1991"
},
"success": "true"
}
Now I want Post Response from below Post Request :
Vehicle tag Request
{
"vehicle_no": "TN07B0054"
}
I have created the post method but it takes the whole thing as argument.
How to take vehicle argument as "TN07B0054" only from the Vehicle tag request.
Below is the POST response when I give above Vehicle Tag Request :
{
"payload": {
"vehicleNumber": "\"vehicle_no\": \"TN 07 B 0054\""
},
"success": "false"
}
You can make a entity named VehicleTagRequest
public class VehicleTagRequest {
private String vehicle_no;
public String getVehicle_no() {
return vehicle_no;
}
public void setVehicle_no(String vehicle_no) {
this.vehicle_no = vehicle_no;
}
}
Easiest way to deserialise your string to above java object is to use Jackson library (https://github.com/FasterXML/jackson)
If you are Maven for dependency management, you can add dependency like below in your pom.xml (this step is not required if you are maintaining your dependencies locally)
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0.pr4</version>
</dependency>
Now comes deserialisation of your vehicle tag request json
Deserialisation using Jackson is done using ObjectMapper API if you are not using annotations,
I have made a sample code snippet attached below-
public class VehicleSerialisation {
public static void main(String[] args) {
String vehicle = "{\"vehicle_no\": \"TN07B0054\"}";
ObjectMapper objectMapper = new ObjectMapper();
VehicleTagRequest vehicleTagRequest = null;
try {
vehicleTagRequest = objectMapper.readValue(vehicle, VehicleTagRequest.class);
} catch (IOException e) {
e.printStackTrace();
}
System.out.print(vehicleTagRequest.getVehicle_no());
}
}
You can then use the vehicleTagRequest.getVehicle_no() to form your request of GET JSON Response
This is not valid Json
{
"payload": {
"vehicleNumber": "\"vehicle_no\": \"TN 07 B 0054\""
},
"success": "false"
}
Without escape char
{
"payload": {
"vehicleNumber": "vehicle_no": "TN 07 B 0054"
},
"success": "false"
}
You can use like this
{
"payload": {
"vehicleNumber": {
"vehicle_no": "TN 07 B 0054"
}
},
"success": "false"
}
And your POJO should be like
public class MyPojo
{
private Payload payload;
private String success;
public Payload getPayload ()
{
return payload;
}
public void setPayload (Payload payload)
{
this.payload = payload;
}
public String getSuccess ()
{
return success;
}
public void setSuccess (String success)
{
this.success = success;
}
#Override
public String toString()
{
return "ClassPojo [payload = "+payload+", success = "+success+"]";
}
}

Error java.lang.NullPointerException in JSON parsing

I am new to Java,and using below code to parse JSON,but I am getting java.lang.NullPointerException error when the offers {} node is coming with empty values ,which is public class in my code.
How to handle empty JSON nodes/keys ??
The code is able to parse JSON if there is data under "offers" like "info",but exiting with NULL exception error when JSON returns and empty as shown below.
ERROR MSG :
Exception in thread "api_temp_1.dat" java.lang.NullPointerException
at com.t.dw.dl.api.data.Pkg_Data.getCount(Pkg_Data.java:57)
at com.t.dw.dl.api.DataRetrieveRunnable.run(DataRetrieveRunnable.java:185)
Code extracts from error lines shown
public long getCount() {
if (offers != null)
return offers.getPkg().size();
return 0;
}
**Code from com.t.dw.dl.api.DataRetrieveRunnable.run(DataRetrieveRunnable.java:185)**
try
{
Pkg_Data dls = parseResult(result);
if (dls.getCount() > 0)
{
fw.write(deals.writeResults(fields, delimiter));
threadStats.increment(Stats2.COUNT_OF_ROWS_PROCESSED,
dls.getCount());
}
}
Parsing code:
private Pkg_Data parseResult( String result ) throws JsonParseException {
JsonParser parser = new JsonParser();
JsonElement jo = parser.parse(result);
Gson gson = new Gson();
Pkg_Data ehw = gson.fromJson(jo, Pkg_Data.class);
return ehw;
}
CODE:
import java.util.ArrayList;
public class offers
{
private ArrayList<PkgData> pkg;
class Pkgdata
{
Info Info;
class Info
{
String Id;
String Url;
}
public String getId() {
if (Info != null && Info.Id != null)
return Info.Id;
return "";
}
SAMPLE JSON: NOT working for this where "offers" returns empty
{
"offerInfo":{
"siteID":"1",
"language":"en_US",
"currency":"USD"
},
"offers":{ }
}
That is because offer is compared to the Class that you giving to refer so in that case Json will be wrong try with this Json it will work.
{
"offerInfo": {
"siteID": "1",
"language": "en_US",
"currency": "USD"
},
"offers": {
"siteID": " ",
"language": "",
"currency": " "
}
}
Because Compiler not able to find any field attribute in side your offer object so its giving error.
try this Json.

Parsing the nested JSON Array using Jackson library in java

I would like to know how to parse the following JSON using jackson library in java to construct the URI like http://api.statdns.com/google.com/cname
{
"status": {
"status": 200,
"msg": "SUCCESS"
},
"apicalls": [
{
"API": {
"method": "get",
"success": "200",
"baseURL": "http://api.statdns.com/",
"param1": "google.com/",
"param2": "cname",
"continue_on_fail": "1",
"add_header2": "'Accept', 'application/json'",
"add_header1": "'Content-Type', 'application/json'",
"client_id": "101"
},
"id": 1385
}
]
}
I have written bad code to parse the above json array. Following is the code i used,
public void parseJSON(String json) {
try{
JsonFactory factory = new JsonFactory();
JsonParser parser;
parser = factory.createJsonParser(json);
parser.setCodec(new ObjectMapper()); // to avoid IllegalStateException
JsonToken current;
current = parser.nextToken();
if (current != JsonToken.START_OBJECT) {
System.out.println("Error: root should be object: quiting.");
return;
}
while (parser.nextToken() != JsonToken.END_OBJECT) {
String fieldName = parser.getCurrentName();
// Move from field name to field value
current = parser.nextToken();
if (fieldName.equals("APIcalls")) {
JsonNode node = parser.readValueAsTree();
JsonNode currentJson = node.findValue("API");
System.out.println("Current JSON :: " + currentJson);
JsonNode url = currentJson.get("baseURL");
JsonNode param1 = currentJson.get("param1");
JsonNode param2 = currentJson.get("param2");
String baseURL = url.asText();
String params1 = param1.asText();
String params2 = param2.asText();
String uri = baseURL + params1 + params2;
System.out.println("URL :: " + uri);
initiateRESTCall(uri);
}
}
} catch (JsonParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Could anyone help me to know parsing the JSON using jackson? Help is highly appreciated.
If you are using jackson library, then you should go something like this:
I am using response from http://api.statdns.com/google.com/cname
public void parseJSON(String json) {
JSONObject parse = new JSONObject(data);
if(parse.get("question") instanceof JSONObject){
JSONObject questionJson = (JSONObject) parse.get("question");
System.out.println("Name"+questionJson.getString("name"));
System.out.println("Type"+questionJson.getString("type"));
System.out.println("Class"+questionJson.getString("class"));
}
else if(parse.get("question") instanceof JSONArray){
JSONArray questionJson = (JSONArray) parse.get("question");
String[] nameAttrib=new String[questionJson.length()];
String[] typeAttrib=new String[questionJson.length()];
String[] classAttrib=new String[questionJson.length()];
for(int i=0;i<questionJson.length();i++){
JSONObject questionJsonData=(JSONObject)questionJson.get(i);
nameAttrib[i]=questionJsonData.getString("name");
typeAttrib[i]=questionJsonData.getString("type");
classAttrib[i]=questionJsonData.getString("class");
System.out.println("Name: "+nameAttrib[i]);
System.out.println("Type: "+typeAttrib[i]);
System.out.println("Class: "+classAttrib[i]);
}
}
else if (parse.get("question").equals(null)){
System.out.println("question"+null);
}
}
Here I am doing for "question" only, similarly you can do other as well say "answer", "authority" in case url you have mentioned http://api.statdns.com/google.com/cname.
Hopefully it helps you with your problem..!!!!
If you are confident in the JSON not changing, a quick and dirty way to simplify your code is to use JSON Pointers.
// prefer injecting your project's ObjectMapper
private static final ObjectMapper om = new ObjectMapper();
public void parseJSON(String json) throws IOException {
JsonNode jsonNode = om.readTree(json);
String uri = new StringBuilder(jsonNode.findValue("baseURL").asText())
.append(jsonNode.findValue("param1").asText())
.append(jsonNode.findValue("param2").asText())
.toString();
initiateRESTCall(uri);
}
This becomes vulnerable if multiple apicalls entries are returned.
I don't know JACKSON library but I think it is similar to GSON. You just have to make some POJO and the library will take care of filling the fields for you.
For instance to convert your string to MyJSONClass use the following classes :
class Status {
int status;
String msg;
}
class APIClass {
String method;
String success;
String baseURL;
String param1;
String param2;
String continue_on_fail;
String add_header2;
String add_header1;
String client_id;
}
class APICall {
APIClass API;
int id;
}
class MyJSONClass {
Status status;
List<APICall> apicalls;
}
This set of classes could be transformed to JSON with JACKSON library (thanks to this stackoverflow answer) like that:
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = ow.writeValueAsString(object);

GSON identifying JSON Object as Primitive

I am writing a relatively simple messaging app that saves its logs in the JSON format, and I am using the GSON library to parse these. I load a JSON file from a server, and put it trough Gson.toJsonTree() function. I'm not sure this is expected, but when I test the result from the previous function with the isJsonSomething() functions (isJsonObject,isJsonAray,isJsonNull,isJsonPrimitive), isJsonPrimitive returns true, and I can't parse it into a object. This is my JSON file's contents:
{
"users": [
{
"picture": "",
"type": "user",
"name": "kroltan"
}
],
"description": "No description",
"messages": [
{
"content": "something",
"time": "2013-08-30 00:38:17.212000",
"type": "message",
"author": "someone"
}
],
"type": "channel",
"name": "default"
}
And here is the class used to parse it into POJOs: (CLEANUP comments is where I've removed irrelevant code from the post)
package com.example.testapp;
//CLEANUP: All needed imports
import com.example.testapp.data.*;
import com.google.gson.*;
public class JSONConverter {
public interface JsonTypeLoadedListener {
public void onSucess(JSONType jsonType);
public void onFailure(Exception e);
}
public static final String DATE_FORMAT = "dd-MM-yyyy HH:mm:ss.SSS";
public static final HashMap<String, Class<?>> JSON_TYPES = new HashMap<String, Class<?>>();
public JSONConverter() {
JSON_TYPES.clear();
JSON_TYPES.put("channel", Channel.class);
JSON_TYPES.put("user", User.class);
JSON_TYPES.put("message", Message.class);
}
public void loadFromURL(final URL url, final JsonTypeLoadedListener listener) {
new Thread(new Runnable() {
#Override
public void run() {
JsonObject result = null;
Gson gson = new GsonBuilder().setDateFormat(DATE_FORMAT).create();
if (url.getProtocol().equals("http")) {
try {
String content = //Loads from a server, omitted for clarity
result = gson.toJsonTree(content).getAsJsonObject();
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
listener.onFailure(e);
return;
}
} else if (url.getProtocol().equals("file")) {
try {
String content = //Loads from a file, omitted for clarity
result = gson.toJsonTree(content).getAsJsonObject();
br.close();
} catch (Exception e) {
e.printStackTrace();
listener.onFailure(e);
return;
}
}
listener.onSucess((JSONType) gson.fromJson(result, JSON_TYPES.get(result.get("type").getAsString())));
}
}, "URLLoader").start();
}
public JSONType loadFromString(String s) {
Gson gson = new Gson();
JsonObject result = gson.toJsonTree(s).getAsJsonObject();
return (JSONType) gson.fromJson(result, JSON_TYPES.get(result.get("type").getAsString()));
}
}
The classes Message, User and Channel all inherit from JSONType (a custom class with a field called type and some utility methods) and contain all values present in the above mentioned JSON file.
When it reaches gson.toJsonTree(content).getAsJsonObject(), I get this error in Logcat (string omitted for clarity, it's just the full file):
java.lang.IllegalStateException: Not a JSON Object: "String containing all the file with tabs represented as \t"
I'm guessing that the tabs are causing your issue. Try to remove them with:
content = content.replaceAll("\\s","")
this will simply clean your json string from any whitespace.
Btw I suggests you to get rid of Gson library and use directly the JSONObject provided in the android sdk. You can initialize it directly with the json string, as new JSONObject(content). :)

Categories