How do get relativePaths in JsonNode using java and Jackson - java

I am working over JsonNode and trying to get relativePath and add as attribute .
public static void iterateOver(JsonNode masterJSON) {
Iterator<Entry<String, JsonNode>> nodes = masterJSON.fields();
while (nodes.hasNext()) {
Map.Entry<String, JsonNode> entry = (Map.Entry<String, JsonNode>) nodes.next();
JsonNode value = entry.getValue();
if(value.has("current") && value.has("older")) {
System.out.println("key --> " + entry.getKey() + " value-->" + value);
String relativePath = "";// ? how do get relative path e.g /obj/empdetails/data[0]/address;
((ObjectNode)entry.getValue()).put("relativePath", relativePath);
}
if(value.isArray()) {
for (int i = 0; i < value.size(); i++) {
iterateOver(value.get(i));
}
}else if (value.isObject()) {
iterateOver(value);
}
}
}
i want to have relativePath in such a way that at i can get the exact object as node.at(relativePath)

Related

How to obtain json schema from jsonpaths of all the required fields using java

Say the input is:
[{keyname: firstname, path:person.name.firstname,type:string},
{keyname:age, path:person.age,type:number}]
Then jsonschema should be generated from the json
{ person:{
name:{ firstname: guest },
age: 6
}}
I need the json schema
#Component
public class SchemaUtil {
#Autowired
ObjectMapper mapper;
//Converts path of type -> $.eventMessage.phoneNumbers[:1].type to -> /eventMessage/phoneNumbers/0/type
public String pathConverter(String path) {
String newString=path.replace("$", "").replace(".", "/").replaceAll("\\[(.*?)\\]","/0");
return newString;
}
public String getSchema(List<SchemaPOJO> schemaList)
{
ObjectNode rootNode = mapper.createObjectNode();
StringBuilder output = new StringBuilder();
try
{
for(SchemaPOJO schema: schemaList)
{
String path = pathConverter(schema.getPath());
create(rootNode,path,schema.getDataType());
if(path.contains("/0/"))
{
int index1=path.indexOf("/0/");
while(index1 != -1)
{
String temp = path.substring(0,index1+1)+'1'+path.substring(index1+2);
create(rootNode,temp,schema.getDataType());
index1=path.indexOf("/0/",index1+1);
}
}
}
output.append("{\"$schema\":\"http://json-schema.org/draft-04/schema#\","
+ "\"type\": \"object\", \"properties\": {");
output.append(makeSchema(mapper.writeValueAsString(rootNode),null));
}
catch(Exception e)
{
return null;
}
List<String> keys = new ArrayList<>();
Iterator<String> iterator = rootNode.fieldNames();
iterator.forEachRemaining(e -> keys.add(e));
String inParams = String.join(",", keys.stream().map(key1 -> "\""+key1+"\"").collect(Collectors.toList()));
output.append(",\"required\":["+inParams+"]");
output.append("}");
return output.toString();
}
//Creates dummy values in json
private void create(ObjectNode rootNode, String path,String dataType)
{
switch(dataType)
{
case "string":createJson(rootNode, JsonPointer.compile(path), new TextNode("stringdummytext"));break;
case "integer":createJson(rootNode, JsonPointer.compile(path), new IntNode(65734));break;
case "float":createJson(rootNode, JsonPointer.compile(path), new FloatNode(124));break;
case "boolean":createJson(rootNode, JsonPointer.compile(path),BooleanNode.getFalse());break;
default:createJson(rootNode, JsonPointer.compile(path), new TextNode("stringdummytext"));break;
}
}
//Creates dummy json
private void createJson(ObjectNode node, JsonPointer pointer, JsonNode value) {
JsonPointer parentPointer = pointer.head();
JsonNode parentNode = node.at(parentPointer);
String fieldName = pointer.last().toString().substring(1);
if (parentNode.isMissingNode() || parentNode.isNull()) {
parentNode = StringUtils.isNumeric(fieldName) ? mapper.createArrayNode() : mapper.createObjectNode();
createJson(node,parentPointer, parentNode);
}
if (parentNode.isArray()) {
ArrayNode arrayNode = (ArrayNode) parentNode;
int index = Integer.parseInt(fieldName);
for (int i = arrayNode.size(); i <= index; i++) {
arrayNode.addNull();
}
arrayNode.set(index, value);
} else if (parentNode.isObject()) {
((ObjectNode) parentNode).set(fieldName, value);
} else {
throw new IllegalArgumentException("`" + fieldName + "` can't be set for parent node `"
+ parentPointer + "` because parent is not a container but " + parentNode.getNodeType().name());
}
}
//Makes schema from dummy json
private String makeSchema(String json,JsonNodeType jsonNodeType) throws IOException
{
JsonNode jsonNode = mapper.readTree(json);
StringBuilder output = new StringBuilder();
for (Iterator<String> iterator = jsonNode.fieldNames(); iterator.hasNext();)
{
String fieldName = iterator.next();
JsonNodeType nodeType;
nodeType = jsonNode.get(fieldName).getNodeType();
output.append(convertNodeToStringSchemaNode(jsonNode, nodeType, fieldName));
output.append(",");
}
if( (jsonNodeType==null) || (jsonNodeType.name().equals("ARRAY")) || (jsonNodeType.name().equals("OBJECT")))
output.deleteCharAt(output.length()-1);
else if(jsonNode.getNodeType().name().equals("STRING"))
output.append("string\"");
else if(jsonNode.getNodeType().name().equals("NUMBER"))
output.append("integer\"");
output.append("}");
return output.toString();
}
//Util Method to create json schema
private String convertNodeToStringSchemaNode(JsonNode jsonNode, JsonNodeType nodeType, String key) throws IOException
{
StringBuilder result = new StringBuilder("\"" + key + "\": { \"type\": \"");
JsonNode node = null;
switch (nodeType) {
case ARRAY :
node = jsonNode.get(key).get(0);
result.append("array\", \"items\": [{ \"type\":\"");
if(node.getNodeType().name().equals("OBJECT"))
result.append("object\", \"properties\": { ");
result.append(makeSchema(node.toString(), node.getNodeType()));
if(node.getNodeType().name().equals("OBJECT"))
{
List<String> keys = new ArrayList<>();
Iterator<String> iterator = node.fieldNames();
iterator.forEachRemaining(e -> keys.add(e));
String inParams = String.join(",", keys.stream().map(key1 -> "\""+key1+"\"").collect(Collectors.toList()));
result.append(",\"required\":["+inParams+"]");
result.append("}");
}
result.append("]}");
break;
case BOOLEAN:
result.append("boolean\" }");
break;
case NUMBER:
result.append("integer\" }");
break;
case OBJECT:
node = jsonNode.get(key);
result.append("object\", \"properties\": {");
result.append(makeSchema(node.toString(), JsonNodeType.OBJECT));
List<String> keys = new ArrayList<>();
Iterator<String> iterator = node.fieldNames();
iterator.forEachRemaining(e -> keys.add(e));
String inParams = String.join(",", keys.stream().map(key1 -> "\""+key1+"\"").collect(Collectors.toList()));
result.append(",\"required\":["+inParams+"]");
result.append("}");
break;
case STRING:
result.append("string\" }");
break;
default:
result.append("string\" }");
}
return result.toString();
}
}

Java adding unique values to hashmap <string, string>

I made a java program that will check contents of directory and generate for each file a md5 checksum. When the program is done it will save it to a CSV file. So far the lookup of files is working perfectly except that when writing to the CSV i want to make to only add new detected files. I think the issue lies with the md5 string used as key is not correctly found.
Here is an excerpt of the CSV file:
4d1954a6d4e99cacc57beef94c80f994,uiautomationcoreapi.h;E:\Tools\Strawberry-perl-5.24.1.1-64\c\x86_64-w64-mingw32\include\uiautomationcoreapi.h;N/A
56ab7135e96627b90afca89199f2c708,winerror.h;E:\Tools\Strawberry-perl-5.24.1.1-64\c\x86_64-w64-mingw32\include\winerror.h;N/A
146e5c5e51cc51ecf8d5cd5a6fbfc0a1,msimcsdk.h;E:\Tools\Strawberry-perl-5.24.1.1-64\c\x86_64-w64-mingw32\include\msimcsdk.h;N/A
e0c43f92a1e89ddfdc2d1493fe179646,X509.pm;E:\Tools\Strawberry-perl-5.24.1.1-64\perl\vendor\lib\Crypt\OpenSSL\X509.pm;N/A
As you can see first is the MD5 as key and afterwards is a long string containing name, location and score that will be split with the ; character.
and here is the code that should make sure only new ones are added:
private static HashMap<String, String> map = new HashMap<String,String>();
public void UpdateCSV(HashMap<String, String> filemap) {
/*Set set = filemap.entrySet();
Iterator iterator = set.iterator();
while(iterator.hasNext()) {
Map.Entry mentry = (Map.Entry) iterator.next();
String md = map.get(mentry.getKey());
System.out.println("checking key:" + md);
if (md == null) {
String[] line = mentry.getValue().toString().split(";");
System.out.println("Adding new File:" + line[0]);
map.put(mentry.getKey().toString(), mentry.getValue().toString());
}
}*/
for (final String key : filemap.keySet()) {
String md = map.get(key.toCharArray());
if (md == null) {
System.out.println("Key was not found:" + key);
String[] line = filemap.get(key).toString().split(";");
System.out.println("Adding new File:" + line[0]);
map.put(key, filemap.get(key));
}
}
}
As you can see from the commented code i tried in different ways already. hashmap filemap is the current status of the folder structure.
To read the already saved CSV file is use the following code:
private void readCSV() {
System.out.println("Reading CSV file");
BufferedReader br = new BufferedReader(filereader);
String line = null;
try {
while ((line = br.readLine()) != null) {
String str[] = line.split(",");
for (int i = 0; i < str.length; i++) {
String arr[] = str[i].split(":");
map.put(arr[0], arr[1]);
System.out.println("just added to map" + arr[0].toString() + " with value "+ arr[0].toString() );
}
}
}
catch(java.io.IOException e) {
System.out.println("Can't read file");
}
}
So when i run the program it will say that all files are new even tough they are already known in the CSV. So can anyone help to get this key string checked correctly?
As #Ben pointed out, your problem is that you use String as key when putting, but char[] when getting.
It should be something along the lines:
for (final String key : filemap.keySet()) {
map.computeIfAbsent(key, k -> {
System.out.println("Key was not found:" + k);
String[] line = filemap.get(k).toString().split(";");
System.out.println("Adding new File:" + line[0]);
return filemap.get(k);
});
}
Since you need both key as well as value from filemap, you actually better iterate over entrySet. This will save you additional filemap.gets:
for (final Map.Entry<String, String> entry : filemap.entrySet()) {
final String key = entry.getKey();
final String value = entry.getValue();
map.computeIfAbsent(key, k -> {
System.out.println("Key was not found:" + k);
String[] line = value.split(";");
System.out.println("Adding new File:" + line[0]);
return value;
});
}

HashMap repeating the last element [duplicate]

This question already has answers here:
Why does my ArrayList contain N copies of the last item added to the list?
(5 answers)
Closed 5 years ago.
I am trying to create a HashMap in a HashMap so it will be easier for me to access elements of it in the future as shown below.
The problem is it only repeating the last elements of the while loop and not the rest of it.
HashMap<String,String> result = new HashMap<>();
HashMap<Integer, HashMap<String,String>> fr = new HashMap<>();
int i = 0;
try {
ResultSet rq = qexec.execSelect();
// ResultSetFormatter.out(System.out, rq, query);
// get result from SPARQL query
while (rq.hasNext()) {
QuerySolution soln = rq.next();
id = soln.getLiteral("?id").getLexicalForm();
//...
result.put("id",id);
//...
if (soln.getLiteral("?wateruse") != null) {
wateruse = soln.getLiteral("?wateruse").getLexicalForm();
//...
result.put("wateruse",wateruse);
} else {
System.out.println("NO");
}
fr.put(i, result);
i++;
}
} finally {
qexec.close();
}
This is how the result should be:
John001
High usage
John002
John003
Smith001
Moderate
Smith002
Smith003
...
Kevin001
Low usage
But fr only repeats Kevin001 and Low usage without the rest.
I've tried to put fr.put(i,result) outside the loop but that still does not give the correct result.
EDIT
I tried to print all elements from fr that shows the repeating elements.
finally {
qexec.close();
}
for (int index : fr.keySet()) {
for(Map.Entry<String, String> entry :result.entrySet()) {
System.out.println(index + " = " + entry.getKey() + " : " + entry.getValue());
}
}
UPDATE - SOLUTION
Declare HashMap inside the loop as mentioned in comments below.
To print nested HashMap, no need to use result.
I did as shown below and it prints both outermap and innermap as well.
for (int k=0; k < fr.size(); k++) {
HashMap<String,String> innermap = fr.get(k);
for(Map.Entry<String, String> e : innermap.entrySet()) {
System.out.println(k + " = " + e.getKey() + " : " + e.getValue());
}
}
You're adding the same result map to your parent map each time through the loop. Create a new instance of result each time through the loop:
Map<String, String> result = new HashMap<>();
Map<Integer, Map<String, String>> fr = new HashMap<>();
int i = 0;
try {
ResultSet rq = qexec.execSelect();
while (rq.hasNext()) {
// Create your new HashMap inside the loop:
result = new HashMap<>();
QuerySolution soln = rq.next();
id = soln.getLiteral("?id").getLexicalForm();
//...
result.put("id",id);
//...
if (soln.getLiteral("?wateruse") != null) {
wateruse = soln.getLiteral("?wateruse").getLexicalForm();
//...
result.put("wateruse",wateruse);
}
else {
System.out.println("NO");
}
fr.put(i,result);
i++;
}
}
To print the results from fr an its nested map, you can do something like this:
for (Map<String, String> map : fr.values()) {
for(Map.Entry<String, String> e : map.entrySet()) {
System.out.println(index + " = " + e.getKey()
+ " : " + e.getValue());
}
}
Try this a small change here, place the "result" map creation in while loop
Map<Integer, Map<String, String>> fr = new HashMap<>();
int i = 0;
try {
ResultSet rq = qexec.execSelect();
while (rq.hasNext()) {
Map<String, String> result = new HashMap<>();
QuerySolution soln = rq.next();
id = soln.getLiteral("?id").getLexicalForm();
//...
result.put("id",id);
//...
if (soln.getLiteral("?wateruse") != null) {
wateruse = soln.getLiteral("?wateruse").getLexicalForm();
//...
result.put("wateruse",wateruse);
}
else {
System.out.println("NO");
}
fr.put(i,result);
i++;
}
}
This for loop to print elemenets:
for (int i=0;i< fr.size();i++){
Map<String,String> element= fr.get(i);
// use the element here.
}

How can you get the JSON Path?

Given a sample JSON:
{
"hello" : "wolrd",
"arrayField" : ["one", "two", "three"],
"mapField" : {
"name" : "john",
"lastName" : "doe"
}
}
Is there a framework in Java to help me get the JSON path structure from the JSON tree? Something similar to this:
$.hello
$.arrayField[0]
$.arrayField[1]
$.arrayField[2]
$.mapField.name
$.mapField.lastName
EDIT:
I've already coded a first approach using fasterxml's Jackson. But I'd like to know if there's something more robust / flexible.
final JsonNode rootNode = mapper.readValue(jon, JsonNode.class);
printFieldKeys(rootNode, "$");
private static void printFieldKeys(JsonNode rootNode, String parent) {
final Iterator<Entry<String, JsonNode>> fieldIt = rootNode.fields();
while (fieldIt.hasNext()) {
final Entry<String, JsonNode> next = fieldIt.next();
final JsonNode value = next.getValue();
final String path = parent + "." + next.getKey();
if (value.isValueNode()) {
System.out.println(path + " = " + value.asText());
} else {
System.out.println(path);
}
if (value.isArray()) {
for (int i = 0; i < value.size(); i++) {
printFieldKeys(value.get(i), path + "[" + i + "]");
}
} else {
printFieldKeys(value, path);
}
}
}
Take a look at this library: https://github.com/jayway/JsonPath
I believe it does exactly what you want. :)

Json Data Decode In Java

I am trying find some vin data from http://developer.edmunds.com/ using https://api.edmunds.com/v1/api/toolsrepository/vindecoder?vin=1GCEC19C17Z275639&fmt=json&api_key=my_api_key.... I am getting a full json data. I am using simplest way to read json from a URL in java JSONParser and my return data looks like http://pastebin.com/30jXEGvN this.
What is the best way to print all keys and its values from a jsonobject ?
I tried
Iterator<?> keys = object.keys();
while( keys.hasNext() ){
String key = (String)keys.next();
try {
if( object.get(key) instanceof JSONObject ){
detailsTextOut.append(key);
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
But its not working for me :( , any clues ?
Using Jackson ObjectMapper:
String s = "replace_with_your_json_string";
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> values = (Map<String, Object>) mapper.readValue(s, Map.class);
iterate(values, "");
private void iterate(Map<String, Object> map, String indent) {
for(Map.Entry<String, Object> o : map.entrySet()) {
System.out.println(indent + o.getKey());
if(o.getValue() instanceof Map) {
iterate((Map<String, Object>) o.getValue(), indent + "\t");
}
if(o.getValue() instanceof List) {
iterate((List<Object>) o.getValue(), indent + "\t");
}
else if(o.getValue() instanceof String) {
System.out.println(indent + "\t" + o.getValue());
}
else if(o.getValue() instanceof Number) {
System.out.println(indent + "\t" + o.getValue());
}
}
}
private void iterate(List<Object> list, String indent) {
for(Object o : list) {
if(o instanceof Map) {
iterate((Map<String, Object>) o, indent + "\t");
}
if(o instanceof List) {
iterate((List<Object>) o, indent + "\t");
}
else if(o instanceof String) {
System.out.println(indent + "\t" + o);
}
else if(o instanceof Number) {
System.out.println(indent + "\t" + o);
}
}
}
Use the method getNames() to get all the keys (field name) of JSON object.
JSONObject api
String[] keys = JSONObject.getNames(jsonObject);
for (String key : keys) {
//then get value by key (field name)
Object obj = jsonObject.get(key);
System.out.println(key + "-" + obj.toString());
}

Categories