I am having a JSON data and I am converting that payload into a map object of nested. But it is overriding according to my logic.
I am having input json like this
{"mapping": {
"EVENT.alertMessage": "input.Message",
"EVENT.id": "input.id",
"EVENT.severity": "Functions.toString(\"P1\")",
"EVENT.eventTime": "input.eventTime",
"EVENT.eventType": "input.alertType",
"EVENT.geocoordinates.location": "Functions.toString(\"\")",
"EVENT.deviceName": "Functions.toString(\"\")",
"EVENT.visualInfo.imageUrl": "input.imageUrl",
"EVENT.deviceId": "input.cameraId",
"EVENT.geocoordinates.longitude": "Functions.toString(\"\")",
"EVENT.visualInfo.videoUrl": "input.videoUrl",
"EVENT.tenantCode": "Functions.toString(\"\")",
"EVENT.MAC": "input.cameraId",
"EVENT.DATE_TIME": "Functions.currentDate(\"yyyy-MM-dd HH:mm:ss\",\"UTC\")",
"EVENT.geocoordinates.latitude": "Functions.toString(\"\")"
}
}
Here from the above input JSON Keys I am iterating and forming map object.
ForEx:
INPUT:
{"mapping": {
"TEST.key1": "a",
"TEST.key2.key3": "b",
}
}
OUTPUT:
{
"TEST":{
"key1":a,
"key2":{
"key3":b
}
}
}
The code that I have written is
JSONObject json=new JSONObject(mappingData).getJSONObject("mapping");
Iterator<String> keys=new JSONObject(mappingData).getJSONObject("mapping").keys();
Map<String,Object> map = new HashMap<>();
while(keys.hasNext()) {
String val = keys.next();
String[] key=val.split("(?<!/)\\.");
Map<String, Object> lastKeyMap = null;
for(int i=0;i<key.length;i++)
{
if(i== 0 && key.length==1){
String outputVal=json.getString(val);
if(outputVal.contains("[]")){
outputVal=outputVal.replace("[]", "[i]");
}
//Matcher m = Pattern.compile("\\.([a-zA-Z0-9]{0,}\\/.[a-zA-Z0-9])|([a-zA-Z0-9]{0,}\\/.[a-zA-Z0-9])")
// .matcher(outputVal);
Matcher m = Pattern.compile("\\.([a-zA-Z0-9]{0,}\\/.[a-zA-Z0-9]{0,})")
.matcher(outputVal);
while (m.find()) {
outputVal=m.replaceAll("[`$1`]").replace("/", "");
}
if(key[i].contains("/"))
{
map.put("`"+key[i].replace("/", "")+"`",outputVal);
}
else{
map.put(key[i],outputVal);
}
}
else if(i== 0 && key.length>1){
if(map.containsKey(key[i])){
lastKeyMap = (Map<String, Object>) map.get(key[i]);
}else{
if(key[i].contains("/"))
{
lastKeyMap = new HashMap<String,Object>();
map.put("`"+key[i].replace("/", "")+"`",lastKeyMap);
}
else{
lastKeyMap = new HashMap<String,Object>();
map.put(key[i],lastKeyMap);
}
}
}else if(i== key.length-1 ){
String outputVal=json.getString(val);
if(outputVal.contains("[]")){
outputVal=outputVal.replace("[]", "[i]");
}
//Matcher m = Pattern.compile("\\.([a-zA-Z0-9]{0,}\\/.[a-zA-Z0-9])|([a-zA-Z0-9]{0,}\\/.[a-zA-Z0-9])")
// .matcher(outputVal);
Matcher m = Pattern.compile("\\.([a-zA-Z0-9]{0,}\\/.[a-zA-Z0-9]{0,})")
.matcher(outputVal);
while (m.find()) {
outputVal=m.replaceAll("[`$1`]").replace("/", "");
}
if(key[i].contains("/"))
{
lastKeyMap.put("`"+key[i].replace("/", "")+"`", outputVal);
}
else{
lastKeyMap.put(key[i], outputVal);
}
}else{
Map<String,Object> objMap = new HashMap<>();
if(key[i].contains("/"))
{
lastKeyMap.put("`"+key[i].replace("/", "")+"`", objMap);
lastKeyMap = objMap;
}
else{
lastKeyMap.put(key[i], objMap);
lastKeyMap = objMap;
}
}
}
}
The output I am getting is :
{EVENT={severity=Functions.toString("P1"), alertMessage=input.alertMessage, id=input.id, eventTime=input.eventTime, visualInfo={videoUrl=input.videoUrl}, eventType=input.alertType, tenantCode=Functions.toString(""), DATE_TIME=Functions.currentDate("yyyy-MM-dd HH:mm:ss","UTC"), geocoordinates={latitude=Functions.toString("")}, deviceName=Functions.toString(""), deviceId=input.cameraId, MAC=input.cameraId}}
But in the result EVENT.geocoordinates.longitude and EVENT.geocoordinates.longitude is skipped as the map is being overridden. Like that EVENT.visualInfo.imageUrl is also overridden by EVENT.visualInfo.videoUrl.So, how can I overcome this one and form a map or json with all the json keys by iterating without veing overriden.
The best approach is to create java class according to json schema:
public class Test {
#SerializedName("mapping")
public Mapping mapping;
static public class Mapping {
#SerializedName("EVENT.alertMessage")
public String alertMessage;
#SerializedName("EVENT.id")
public String id;
#SerializedName("EVENT.severity")
public String severity;
#SerializedName("EVENT.eventTime")
public String eventTime;
#SerializedName("EVENT.eventType")
public String eventType;
#SerializedName("EVENT.geocoordinates.location")
public String location;
#SerializedName("EVENT.deviceName")
public String deviceName;
#SerializedName("EVENT.visualInfo.imageUrl")
public String imageUrl;
#SerializedName("EVENT.deviceId")
public String deviceId;
#SerializedName("EVENT.geocoordinates.longitude")
public String longitude;
#SerializedName("EVENT.visualInfo.videoUrl")
public String videoUrl;
#SerializedName("EVENT.tenantCode")
public String tenantCode;
#SerializedName("EVENT.MAC")
public String mac;
#SerializedName("EVENT.DATE_TIME")
public String dateTime;
#SerializedName("EVENT.geocoordinates.latitude")
public String latitude;
}
}
And then parse it with google gson library
Test test = new Gson().fromJson("jsonString", Test.class);
Working with your own java object is much easier than with JSONObject
My current dependency for gson in gradle file:
implementation("com.google.code.gson:gson:2.8.6")
Related
I have a properties file like this.
property[0].name=A
property[0].value=1
property[1].name=B
property[1].value=2
property[2].name=C
property[2].value=3
How to read this file as a list of objects of a class {name, value} in plain java program using ResourceBundle or Properties?
Here is the class.
public class XYZ {
private String name;
private String value;
// Getters & Setters
}
I need to get like this.
ArrayList<XYZ> propertiesList = SomeUtility.getProperties("property", XYZ.class);
Utility class might be like this.
public class SomeUtility {
public static ArrayList getProperties(String key, Class cls) {
//logic
}
}
I might not understand exactly what you want so feel free to correct me and give me more constraints to work with but here is a simple way to read a Properties file located somewhere in your project:
private static void readPropertiesFile(String path) throws IOException {
java.util.Map<String, String> map = new java.util.LinkedHashMap<>();
Properties properties = new Properties();
InputStream inputStream = new FileInputStream(path);
properties.load(inputStream);
for (String name : properties.stringPropertyNames()) {
map.put(name, properties.getProperty(name));
}
for (java.util.Map.Entry<String, String> entry : map.entrySet()) {
System.out.printf("Property Key: %s, Property Value: %s%n", entry.getKey(), entry.getValue());
}
}
Output
Property Key: property[0].name, Property Value: A
Property Key: property[1].name, Property Value: B
Property Key: property[0].value, Property Value: 1
Property Key: property[1].value, Property Value: 2
Property Key: property[2].name, Property Value: C
Property Key: property[2].value, Property Value: 3
This is the solution I wrote, but it involves Reflect and Gson. Is there any better way to do this? Anything already available which is fine tuned like Apache's.
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.lang.reflect.Field;
import java.util.*;
public class ListResourceBundle {
public static final Gson gson = new Gson();
private final ResourceBundle bundle;
public ListResourceBundle(ResourceBundle bundle) {
this.bundle = bundle;
}
public List<?> getProperties(String key, Class<?> cls) {
final int maxArraySize = getMaxArraySize(key, getMatchingKeys(key));
final List<String> fields = getFields(cls);
final List<Object> result = new ArrayList<>();
for (int i = 0; i < maxArraySize; i++) {
JsonObject jsonObject = new JsonObject();
for (String field : fields) {
jsonObject.addProperty(field, getStringOrNull(key + "[" + i + "]." + field));
}
result.add(gson.fromJson(jsonObject, cls));
}
System.out.println("result.toString() = " + result.toString());
return result;
}
public List<String> getMatchingKeys(String key) {
Enumeration<String> keys = bundle.getKeys();
List<String> matchingKeys = new ArrayList<>();
while(keys.hasMoreElements()) {
String k = keys.nextElement();
if(k.startsWith(key)) {
matchingKeys.add(k);
}
}
Collections.sort(matchingKeys);
return matchingKeys;
}
public int getMaxArraySize(String key, List<String> matchingKeys) {
int maxArraySize = 0;
for (int i = 0; ; i++) {
boolean indexAvailable = false;
for (String matchingKey : matchingKeys) {
if(matchingKey.startsWith(key + "[" + i + "]")) {
indexAvailable = true;
break;
}
}
if(indexAvailable) {
maxArraySize++;
} else {
break;
}
}
return maxArraySize;
}
public String getStringOrNull(String key) {
try {
return bundle.getString(key);
} catch (MissingResourceException e) {
return null;
}
}
public List<String> getFields(Class<?> cls) {
final List<String> fields = new ArrayList<>();
for (Field field : cls.getDeclaredFields()) {
fields.add(field.getName());
}
return fields;
}
public static void main(String[] args) {
ResourceBundle bundle = ResourceBundle.getBundle("com.example.application.resources.Resource");
ListResourceBundle applicationResourceBundle = new ListResourceBundle(bundle);
applicationResourceBundle.getProperties("property", ReportParam.class);
}
}
Resource:
property[0].name=A
property[0].value=1
property[1].name=B
property[1].value=2
property[2].name=C
property[2].value=3
Output:
result.toString() = [
ReportParam{name='A', value='1'},
ReportParam{name='B', value='2'},
ReportParam{name='C', value='3'}]
Process finished with exit code 0
I know it's bit late of an answer, but if I understand your problem statement correctly, you can use :
#ConfigurationProperties
to get your job done.
Here is my spring-boot example with a YAML file for the sake of convenience (same can be achieved through properties file as well).
application.yaml:
xyz:
xyzprops :
-
name: cbc
value: 441
-
name: obc
value: 443
XYZ class:
#Component
#ConfigurationProperties(prefix = "xyz")
public class XYZ{
private List<XYZProps> xyzprops;
public List<XYZProps> getXyzprops() {
return xyzprops;
}
public void setXyzprops(List<XYZProps> xyzprops) {
this.xyzprops = xyzprops;
}
public class XYZProps{
String name;
String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
And then #Autowire XYZ where you want to use it.
I would use JSON:
in your file:
property=[{"name":"A","value":"1"},{"name":"B","value":"2"},{"name":"C","value":"3"}]
and then deserialize it using com.google.gson.gson (or any other) library:
ArrayList<XYZ> propertiesList;
propertiesList = new gsonbuilder().create().fromjson(property, propertiesList.class);
NOTE: I haven't tested this code, and i'm not very familiar with java so i am sure there is a better,cleaner way to implement this.
I am a beginner to regex.
I have below String:
fail:2,success:1,fetch:1
Output Map: Get Map which contains all key-values as below:
fail - 2 (key=fail, value=2)
success - 1
fetch - 1
I have tried using below solution:
public static void main(String arg[]) {
String msg = "fail:1,success:1,policyfetch:1";
System.out.println(getKeyValuesFromMsg(msg));
}
public static Map getKeyValuesFromMsg(String msg) {
if (msg != null) {
Map keyvalues = new HashMap();
Pattern p = Pattern.compile("(\\w+):(,+)");
Matcher m = p.matcher(msg);
while (m.find()) {
keyvalues.put(m.group(1), m.group(2));
}
return keyvalues;
} else
return Collections.emptyMap();
}
You can use the split function, The following snippet should work fine
Map<String,String> map = new HashMap();
String str = "fail:2,success:1,fetch:1";
String[] keyValueParts = str.split(",");
for(String s : keyValueParts){
String parts[] = s.split(":");
map.put(parts[0],parts[1]);
}
System.out.println(map);
i would have used below method for the same.
public static void main(String arg[]) {
String msg = "fail:1,success:1,policyfetch:1";
System.out.println(getKeyValuesFromMsg(msg));
}
private static Map<Object, Object> getKeyValuesFromMsg(String msg) {
Map<Object,Object> mapObj = new HashMap<Object,Object>();
for (int i=0;i<msg.split(",").length;i++)
mapObj.put(msg.split(",")[i].split(":")[0],msg.split(",")[i].split(":")[1]);
return mapObj;
}
my solution:
public static Map<String, Integer> trans2Map(String source) {
if (null == source) {
return Collections.emptyMap();
}
Map<String, Integer> result = new HashMap<>();
Arrays.stream(source.split(","))
.filter(pair -> pair.split(":").length == 2)
.forEach(pair -> {
String key = pair.split(":")[0];
Integer value;
try {
value = Integer.parseInt(pair.split(":")[1]);
} catch (Exception e) {
return;
}
result.put(key, value);
});
return result;
}
I am trying to build a json string in java but I am a bit confused as how I should go about it. This is what I tried so far.
String jsonString = new JSONObject()
.put("JSON1", "Hello World!")
.put("JSON2", "Hello my World!")
.put("JSON3", new JSONObject()
.put("key1", "value1")).toString();
System.out.println(jsonString);
The output is :
{"JSON2":"Hello my World!","JSON3":{"key1":"value1"},"JSON1":"Hello World!"}
The Json I want is as follows :-
{
"data":{
"nightclub":["abcbc","ahdjdjd","djjdjdd"],
"restaurants":["fjjfjf","kfkfkfk","fjfjjfjf"],
"response":"sucess"
}
}
How should I go about it?
You will need to use JSONArray and JsonArrayBuilder to map these json arrays.
This is the code you need to use:
String jsonString = new JSONObject()
.put("data", new JSONObject()
.put("nightclub", Json.createArrayBuilder()
.add("abcbc")
.add("ahdjdjdj")
.add("djdjdj").build())
.put("restaurants", Json.createArrayBuilder()
.add("abcbc")
.add("ahdjdjdj")
.add("djdjdj").build())
.put("response", "success"))
.toString();
You can use gson lib.
First create pojo object:
public class JsonReponse {
private Data data;
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
public class Data {
private String reponse;
private List<String> nightclub;
private List<String> restaurants;
public String getReponse() {
return reponse;
}
public void setReponse(String reponse) {
this.reponse = reponse;
}
public List<String> getNightclub() {
return nightclub;
}
public void setNightclub(List<String> nightclub) {
this.nightclub = nightclub;
}
public List<String> getRestaurants() {
return restaurants;
}
public void setRestaurants(List<String> restaurants) {
this.restaurants = restaurants;
}
}
}
and next complite data and generate json:
JsonReponse jsonReponse = new JsonReponse();
JsonReponse.Data data = jsonReponse.new Data();
data.setReponse("sucess");
data.setNightclub(Arrays.asList("abcbc","ahdjdjd","djjdjdd"));
data.setRestaurants(Arrays.asList("fjjfjf","kfkfkfk","fjfjjfjf"));
jsonReponse.setData(data);
Gson gson = new Gson();
System.out.println(gson.toJson(jsonReponse));
I'm trying to make a test where I get some documents based on the id of the batch they belong to. More specifically, I want to check that a specific batchPublicId is in the response body. I am using okhttp for the test.
This a shorter version of the json:
{
"_embedded": {
"invoices": [
{
"type": "INVOICE",
"publicId": "27bc8426-17cf-4fe5-9278-64108ae05e4b",
"deliveryStatus": null,
"processingStatus": "INITIATED",
"batchPublicId": "0000000000000000000000001"
}
]
}
}
I'm new to json and this is how far I got with the problem:
String invoicesJsonData = response.body().string();
JSONObject invoicesJsonObject = new JSONObject(invoicesJsonData);
Assert.assertTrue(invoicesJsonObject.getJSONObject("_embedded") !=null && invoicesJsonObject.getJSONObject("_embedded").has("invoices"));
I would like to verify that batchPublicId has the value mentioned in the json. Is there a way to do this? Thank you.
String invoicesJsonData = response.body().string();
JSONObject invoicesJsonObject = new JSONObject(invoicesJsonData);
JSONObject invoicesJsonObject1 = invoicesJsonObject.getJSONObject("_embedded");
JSONArray f2=invoicesJsonObject1.getJSONArray("invoices");
for(int i=0;i<f2.length();i++){
JSONObject obj=f2.getJSONObject(i);
if(obj.get("batchPublicId")!=null){
System.out.println(obj.get("batchPublicId"));
}
You can do something like this,Which worked out for me sometimes back.
String invoicesJsonData = response.body().string();
JSONObject invoicesJsonObject = new JSONObject(invoicesJsonData);
JSONObject invoicesJsonObject = json.getJSONObject("invoicesJsonObject");
String batchPublicId = invoicesJsonObject.getString("batchPublicId");
System.out.println( "batchPublicId: " + batchPublicId );
if(batchPublicId !=null){
// do something
}
Not sure about the syntax.Giving you a hint.
you can check any keys is there in json object or not like below :
if(jsonObject1.has("batchPublicId")){
String batchPublicId = jsonObject1.optString("batchPublicId");
Log.i(getClass().getSimpleName(), "batchPublicId=" + batchPublicId);}
has method is used to find any key is there in jsonobject or not.
In my opinion, a better approach for this would be to create a POJO from this JSON string, and extract the information you need using simply the getters
For example:
Wrapper class:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonRootName(value = "_embedded")
public class Embeded {
#JsonProperty("invoices")
private List<Invoice> invoices;
public Embeded() {}
public List<Invoice> getInvoices() {
return invoices;
}
public void setInvoices(List<Invoice> invoices) {
this.invoices = invoices;
}
}
Invoice class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Invoice {
#JsonProperty("type")
private String type;
#JsonProperty("publicId")
private String publicId;
#JsonProperty("deliveryStatus")
private String deliveryStatus;
#JsonProperty("processingStatus")
private String processingStatus;
#JsonProperty("batchPublicId")
private String batchPublicId;
public Invoice() {}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPublicId() {
return publicId;
}
public void setPublicId(String publicId) {
this.publicId = publicId;
}
public String getDeliveryStatus() {
return deliveryStatus;
}
public void setDeliveryStatus(String deliveryStatus) {
this.deliveryStatus = deliveryStatus;
}
public String getProcessingStatus() {
return processingStatus;
}
public void setProcessingStatus(String processingStatus) {
this.processingStatus = processingStatus;
}
public String getBatchPublicId() {
return batchPublicId;
}
public void setBatchPublicId(String batchPublicId) {
this.batchPublicId = batchPublicId;
}
}
Test:
public void json_test() throws JsonParseException, JsonMappingException, IOException {
String json = "{"
+ "\"_embedded\": {"
+ "\"invoices\": ["
+ "{"
+ "\"type\": \"INVOICE\","
+ "\"publicId\": \"27bc8426-17cf-4fe5-9278-64108ae05e4b\","
+ "\"deliveryStatus\": null,"
+ "\"processingStatus\": \"INITIATED\","
+ "\"batchPublicId\": \"0000000000000000000000001\""
+ "}"
+ "]"
+ "}"
+ "}";
ObjectMapper mapper = new ObjectMapper();
mapper.configure(Feature.UNWRAP_ROOT_VALUE, true);
List<Invoice> invoices = mapper.readValue(json, Embeded.class).getInvoices();
Assert.assertTrue(StringUtils.equals(invoices.get(0).getBatchPublicId(), "0000000000000000000000001"));
}
If I understand your right, you just need to call:
Assert.assertTrue(invoicesJsonObject.getString("batchPublicId").equals("0000000000000000000000001"));"
If you want to create a test for JSON Validation, you can use the JSONAssert.
JSONAsset give the method assertEquals, that compare two json structures, strict identic or not.
final String expected_result = YOUR_EXPECTED_RESULT;
JSONAssert.assertEquals(YOUR_EXPECTED_JSON_RESULT, RESULT_FROM_RESPONSE_BODY, false);
The last boolean parameter defines if you want an strict comparation or just compare if your expected result is in result from response.
I have a decent amount of experience with REST and JSON, but I'm failing at coming up with a way to read some JSON as a Java object.
The response is here: https://api.kraken.com/0/public/OHLC?pair=XBTCZEUR&interval=60
Notice how one of the names (the relevant data) is dependent on a query parameter. I'm not sure how to create a Java object for Gson to use for deserialization, as one of the variable names can change.
I thought that maybe using a JsonReader to read the response in a streaming fashion might work, but when I do this I get a 403 error response.
Any ideas?
If you don't have exact knowledge regarding what the response will contain, you can always use an implementation of map class to pass on to gson, as I have tried to demonstrate in here :
public class RestResponse {
private boolean success;
private String errorDescription;
private Map<String, Object> data;
private static Gson GSON = new Gson();
private RestResponse()
{
data = new HashMap<String, Object>();
}
public boolean isSuccess() {
return success;
}
private void setSuccess(boolean success) {
this.success = success;
}
public String getErrorDescription() {
return errorDescription;
}
private void setErrorDescription(String errorDescription) {
this.errorDescription = errorDescription;
}
public Object getData(String... nestedKeys)
{
List<String> nestedKeysAsList = Arrays.asList(nestedKeys);
return getData(nestedKeysAsList);
}
public Object getData(List<String> nestedKeys)
{
String firstKey = nestedKeys.get(0);
if(!data.containsKey(firstKey))
throw new IllegalArgumentException("Key not found");
Object mapValue = data.get(firstKey);
if(!(mapValue instanceof Map))
return mapValue;
String finalKey = nestedKeys.get(nestedKeys.size()-1);
if(nestedKeys.size() > 2)
{
for(String nextKey : nestedKeys.subList(1,nestedKeys.size()-1))
{
Map<String,Object> tempMap = (Map)mapValue;
mapValue = tempMap.get(nextKey);
}
}
Map<String,Object> tempMap = (Map)mapValue;
return tempMap.get(finalKey);
}
private Map<String, Object> getData() {
return data;
}
private void setData(Map<String, Object> map){
this.data = map;
}
public static RestResponse createUnsuccessfulResponse(Exception e)
{
return createUnsuccessfulResponse(e.getMessage());
}
public static RestResponse createUnsuccessfulResponse(String reason)
{
RestResponse res = new RestResponse();
res.setSuccess(false);
res.setErrorDescription(reason);
return res;
}
public static RestResponse createSuccessfulResponse(String jsonString)
{
Map<String, Object> jsonToDataMap = GSON.fromJson(jsonString, Map.class);
return createSuccessfulResponseByMap(jsonToDataMap);
}
private static RestResponse createSuccessfulResponseByMap(Map<String, Object> jsonToDataMap)
{
RestResponse res = new RestResponse();
res.setSuccess(true);
res.setErrorDescription("Success");
res.setData(jsonToDataMap);
return res;
}
}
Usage examples can be found over here :
https://github.com/cgunduz/btcenter/blob/master/src/main/java/com/cemgunduz/utils/entity/RestResponse.java