Here's the problem:
public static <T> T execute(String query, Function<List<JsonNode>, T> function) {
String jsonString = HttpRequest.get("http://overpass-api.de/api/interpreter", true, "data", query).body();
List<JsonNode> list = toJsonNodeList(jsonString);
T res = function.apply(list);
return res;
}
This method:
perform a query that returns a json string
transform that string into a JsonNode list
finally, transform each JsonNode into a particular object
This is an example of function that convert each JsonNode into a geojson geometry and returns a geojson result set:
public class GeojsonMapper implements Function<List<JsonNode>, GeojsonSingleListResultSet> {
#Override
public GeojsonSingleListResultSet apply(List<JsonNode> list) {
List<Element> elementList = list.parallelStream()
.map(jsonNode -> {
String id = jsonNode.get("id").asText();
JsonNode tags = jsonNode.get("tags");
switch (jsonNode.get("type").asText()) {
case "node":
return new Point(jsonNode.get("lat").asDouble(), jsonNode.get("lon").asDouble(), id, tags);
case "way":
ArrayList<Point> points = new ArrayList<>();
JsonNode nodeList = jsonNode.get("geometry");
for (int j = 0; j < nodeList.size(); j++) {
JsonNode wayNode = nodeList.get(j);
points.add(j, new Point(wayNode.get("lat").asDouble(), wayNode.get("lon").asDouble()));
}
if (Polygon.isPolygon(points, tags)) {
return new Polygon(points, id, tags);
} else {
return new LineString(points, id, tags);
}
default:
Iterator<JsonNode> iterator = jsonNode.get("members").getElements();
List<List<Point>> rings = new ArrayList<>();
List<Point> ring = null;
while (iterator.hasNext()) {
JsonNode member = iterator.next();
JsonNode geometry = member.get("geometry");
ring = new ArrayList<>();
for (int ringIndex = 0; ringIndex < geometry.size(); ringIndex++) {
JsonNode coordinates = geometry.get(ringIndex);
ring.add(new Point(coordinates.get("lat").asDouble(), coordinates.get("lon").asDouble()));
}
rings.add(ring);
}
return new Multipolygon(Polygon.buildPolygons(rings), id, tags);
}
})
.collect(toList());
return new GeojsonSingleListResultSet(elementList);
}
}
Everything works well, but the toJsonNodeList() method is very slow in comparison to the method function.apply() that use a Stream. This is the toJsonNodeList()'s code:
private static List<JsonNode> toJsonNodeList(String s){
ObjectMapper mapper = new ObjectMapper();
List<JsonNode> list = new ArrayList<>();
try{
JsonNode resultSet = mapper.readTree(s).get("elements");
Iterator<JsonNode> iterator = resultSet.getElements();
while (iterator.hasNext()) {
list.add(iterator.next());
}
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
Is there a way to parse a json string using a parallelStream so as to extract each element and convert it to a JsonNode?
Related
I am trying to write a test case for the service using Junit Mockito.
Controller class:
public class ReporteesService {
ReporteeList reportee = new ReporteeList();
GetEmpId EmpId = new GetEmpId();
public ReporteesService(ReporteeList reportee) {
this.reportee = reportee;
}
public ReporteesService(EmpJiraList NumberOfJiras) {
this.NumberOfJiras = NumberOfJiras;
}
public ReporteesService(GetEmpId EmpId) {
this.EmpId = EmpId;
}
#GET
#Path("/ReporteeList/{empid}")
#Produces(MediaType.APPLICATION_JSON)
public List<Map<Object, Object>> getList(#PathParam("empid")String
emp ) throws Exception {
String id = EmpId.getEmpId(emp);
int employeeid = Integer.parseInt(id);
return reportee.getReportees(employeeid);
}
ReporteeList class:
public class ReporteeList {
public List<Map<Object,Object>> getReportees(int idOfEmp) throws
Exception {
Authentication auth = new Authentication();
JiraCount count = new JiraCount();
String api = "https://*******/core/v3/people/";
int id = idOfEmp;
String ext = "/#reports";
String url = api + id + ext;
String authToken = auth.getToken();
Client restClient = Client.create();
WebResource webResource = restClient.resource(url);
ClientResponse resp =
webResource.accept("application/json").header("Authorization",
"Basic " + authToken)
.get(ClientResponse.class);
if (resp.getStatus() != 200) {
System.err.println("Unable to connect to the server");
}
String output = resp.getEntity(String.class);
// JSONParser reads the data from string object and break each
data into key
// value pairs
JSONParser parse = new JSONParser();
// Type caste the parsed json data in json object
JSONObject jobj = (JSONObject) parse.parse(output);
// Store the JSON object in JSON array as objects (For level 1
array element i.e list)
JSONArray jsonarr_s = (JSONArray) jobj.get("list");
List<Map<Object, Object>> List = new
ArrayList<Map<Object,Object>>();
// Get data for List array
for (int i = 0; i < jsonarr_s.size(); i++) {
Map<Object,Object> map = new HashMap<>();
JSONObject jsonobj_1 = (JSONObject) jsonarr_s.get(i);
JSONObject jive = (JSONObject) jsonobj_1.get("jive");
Object names = jsonobj_1.get("displayName");
Object userid = jive.get("username");
String UserId = userid.toString();
//return the map with the key value pairs
int jiracount = count.getJiraCount(UserId);
map.put("Name", names);
map.put("UserId", userid);
map.put("count", jiracount);
List.add(map);
}
return List;
}
}
Test class:
public class ReporteesListTesting {
ReporteesService Reportee_Service=null;
ReporteeList Reportee_List = mock(ReporteeList.class);
GetEmpId empid = mock(GetEmpId.class);
#Before
public void setup() {
Reportee_Service = new ReporteesService(empid);
}
#Test
public void testReporteeList() throws Exception {
when(Reportee_List.getReportees(54591)).thenReturn("");
assertEquals("",Reportee_Service.getList("vb256121"));
}
}
Now in the Return part I have to return the list, as my getReportees() return the list.
The List contains this data:
"[{UserId=at1234,count=0,Name=Amrith Taj},
{UserId=AR1234,count=1,Name=Anaga R},
{UserId=MS1234,count=4,Name=Madhu S}]"
Please let me know how can this be done,and whether I am on the right track.Please help,I am new to Junits Mockito.
Reportee_Service.getList("vb256121") returns a List of Maps, not a string.
when(Reportee_List.getReportees(54591)).thenReturn(new ArrayList<>());
assertEquals(0 ,Reportee_Service.getList("vb256121").size());
You can do this for a longer query
List<Map<Object, Object>> users = new ArrayList<>();
Map<Object, Object> map = new HashMap<>();
map.put("Name", "Amrith Taj");
map.put("UserId", "at1234");
map.put("count", "0");
users.add(map);
map = new HashMap<>();
map.put("Name", "Anaga R");
map.put("UserId", "AR1234");
map.put("count", "1");
users.add(map);
map = new HashMap<>();
map.put("Name", "Anaga R");
map.put("UserId", "MS1234");
map.put("count", "4");
users.add(map);
when(Reportee_List.getReportees(54591)).thenReturn(users);
assertEquals(3 ,Reportee_Service.getList("vb256121").size());
How can I convert a json string like
{
"a.b": 1,
"a.c.d": 2
}
into json string
{
"a": {
"b": 1,
"c": {
"d": 2
}
}
}
by using ObjectMapper?
The easiest option is to create custom deserializer or custom been with #JsonAnySetter and #JsonAnyGetter Here is example:
public static final String json = "{\"a.b\": 1,\"a.c.d\": 2}";
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
HelperBean bean = mapper.readValue(json, HelperBean.class);
System.out.println(mapper.writeValueAsString(bean));
// result: {"a":{"b":1,"c":{"d":2}}}
}
public static class HelperBean{
#JsonIgnore
private Map<String, Object> data = new TreeMap<>();
#JsonAnySetter
public void setDays(String key, Object value){
String[] parts = key.split("\\.");
Map<String, Object> currMap = data;
for (int i = 0; i< parts.length; i++){
String part = parts[i];
Object subMap = currMap.get(part);
if (i == parts.length - 1) // last node
currMap.put(part, value);
else if(subMap == null){ // new node
subMap = new TreeMap<>();
currMap.put(part, subMap);
currMap = (Map<String, Object>) subMap;
}else if (subMap instanceof Map){ // existing node
currMap.put(part, subMap);
currMap = (Map<String, Object>) subMap;
} else { // node conflict
// handle exception when a.b = 1 and a.b.c = 1
}
}
}
#JsonAnyGetter
public Map<String, Object> getData() {
return data;
}
}
I have a custom map implementation called ObjectMap as follows:
public class ObjectMap extends LinkedHashMap<String, Object> implements Serializable {
...
}
I can convert any POJO to this ObjectMap using jackson ObjectMapper as follows:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(
objectMapper.getSerializationConfig().
getDefaultVisibilityChecker().
withFieldVisibility(JsonAutoDetect.Visibility.ANY).
withGetterVisibility(JsonAutoDetect.Visibility.NONE).
withIsGetterVisibility(JsonAutoDetect.Visibility.NONE)
);
ObjectMap objectMap = objectMapper.convertValue(object, new TypeReference<ObjectMap>() {});
But the problem is if my POJO's complex fields are being mapped to a LinkedHashMap not ObjectMap. So how do I enforce ObjectMapper to map internal fields also into a ObjectMap instead of LinkedHashMap?
I have come up with below solution at last:
public class Document extends LinkedHashMap<String, Object> implements Serializable {
}
public class JacksonMapper {
private ObjectMapper objectMapper;
public <T> Document asDocument(T object) {
ObjectMapper objectMapper = getObjectMapper();
JsonNode node = objectMapper.convertValue(object, JsonNode.class);
return loadDocument(node);
}
protected ObjectMapper getObjectMapper() {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
objectMapper.setVisibility(
objectMapper.getSerializationConfig().
getDefaultVisibilityChecker().
withFieldVisibility(JsonAutoDetect.Visibility.ANY).
withGetterVisibility(JsonAutoDetect.Visibility.NONE).
withIsGetterVisibility(JsonAutoDetect.Visibility.NONE)
);
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
}
return objectMapper;
}
private Document loadDocument(JsonNode node) {
Document document = new Document();
Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> entry = fields.next();
String name = entry.getKey();
JsonNode value = entry.getValue();
document.put(name, loadObject(value));
}
return document;
}
private Object loadObject(JsonNode node) {
if (node == null) return null;
try {
switch (node.getNodeType()) {
case ARRAY:
return loadArray(node);
case BINARY:
return node.binaryValue();
case BOOLEAN:
return node.booleanValue();
case MISSING:
case NULL:
return null;
case NUMBER:
return node.numberValue();
case OBJECT:
return loadDocument(node);
case POJO:
return loadDocument(node);
case STRING:
return node.textValue();
}
} catch (IOException e) {
return null;
}
return null;
}
private List loadArray(JsonNode array) {
if (array.isArray()) {
List list = new ArrayList();
Iterator iterator = array.elements();
while (iterator.hasNext()) {
Object element = iterator.next();
if (element instanceof JsonNode) {
list.add(loadObject((JsonNode) element));
} else {
list.add(element);
}
}
return list;
}
return null;
}
}
Hope this will help someone someday.
I am trying to acheive JSON to JSON conversion in java based on the specification given on runtime.
Example : if at runtime source : com.gsdetails.gname,target : com.track.trackName (i.e source field should be mapped to target field in generated JSON)
My approach was to create N-array tree for the specification part and do breadth first travesal (get queue with it to craeate structure for resulting json)
I am using Jackson api to create tree from input JSON and traversing both queue(bfs) and input tree to create resulting json.
Unable to get expected output
PS : I thought of using JOLT api but it will not serve my purpose
Tree (for specification)
public class TrieBuilder {
public static void main(String[] args) throws Exception {
createSpec();
}
public static Trie createSpec() throws Exception {
BufferedReader reader = new BufferedReader(
new FileReader(""));
String currentLine = reader.readLine();
Trie trie = new Trie();
while (currentLine != null) {
String[] lines = currentLine.split(",");
String sourceLine = lines[0];
String targetLine = lines[1];
String sourcePath = sourceLine.split("=")[1];
String targetPath = targetLine.split("=")[1];
trie.insertWord(sourcePath.trim(), targetPath.trim());
currentLine = reader.readLine();
}
return trie;
}
}
class TrieNode {
String source;// consider this as content/reference point of a tree
String target;
boolean isEnd;
int count;
List childList;
boolean isRoot;
/* Constructor */
public TrieNode(String source, String target) {
childList = new ArrayList<TrieNode>();
isEnd = false;
count = 0;
this.source = source;
this.target = target;
}
public TrieNode subNodeWord(String word) {
if (childList != null) {
for (TrieNode eachChild : childList)
if (eachChild.source.equals(word))
return eachChild;
}
return null;
}
}
class Trie {
public TrieNode root;
/* Constructor */
public Trie() {
root = new TrieNode("", "");
}
public void insertWord(String sourceWords, String targetWords) {
if (searchWord(sourceWords) == true)
return;
TrieNode current = root;
String[] sourceArray = sourceWords.split(":");
String[] targetArray = targetWords.split(":");
for (int i = 0; i < sourceArray.length; i++) {
TrieNode child = current.subNodeWord(sourceArray[i]);
if (child != null) {
current = child;
} else {
current.childList.add(new TrieNode(sourceArray[i],
targetArray[i]));
current = current.subNodeWord(sourceArray[i]);
}
current.count++;
}
current.isEnd = true;
}
public boolean searchWord(String words) {
TrieNode current = root;
for (String word : words.split(":")) {
if (current.subNodeWord(word) == null) {
return false;
} else {
current = current.subNodeWord(word);
}
}
if (current.isEnd == true)
return true;
return false;
}
public Queue<TrieNode> bfsTraversal(TrieNode node) {
// TODO need to add logic for bfs/dfs for traversing the trie
Queue<TrieNode> queue = new LinkedList<>();
Queue<TrieNode> tempQueue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
TrieNode tempNode = queue.poll();
tempQueue.add(tempNode);
int counter = tempNode.childList.size(), i = 0;
if (tempNode == null)
break;
if (!tempNode.source.isEmpty())
System.out.println("Source :" + tempNode.source
+ " Target : " + tempNode.target);
while (i < counter) {
queue.add(tempNode.childList.get(i++));
}
}
tempQueue.poll();
return tempQueue;
}
Source to target mapping file :
source = com:track:trackDetails:fname, target = gsUser:gsProp:gsDetails:gsFirstName
source = com:track:trackDetails:lname, target = gsUser:gsProp:gsDetails:gsLastName
helper class (Actual transform):
public class JsonHelperClass{
// private Files file = null;// create a tempfile
private JsonNodeFactory factory;
private JsonFactory jsonFactory;
private ObjectMapper mapper;
private JsonNode jsonRoot;
private Queue<TrieNode> queue;
// private JsonParser jsonParser =
public JsonHelperClass() throws JsonProcessingException, IOException {
this.factory = JsonNodeFactory.instance;
this.jsonFactory = new JsonFactory();
this.mapper = new ObjectMapper();
this.jsonRoot = mapper.readTree(new File("json with data"));
}
public static void main(String[] args) throws Exception, Exception {
JsonHelperClass helperClass = new JsonHelperClass();
helperClass.jsonCreator();
ObjectNode objectNode = null;
ObjectNode result = helperClass.createJsonRecursively(objectNode);
System.out.println(result.toString());
}
public void jsonCreator() throws Exception {
Trie trie = TrieBuilder.createSpec();
queue = trie.bfsTraversal(trie.root);
}
public ObjectNode createJsonRecursively(ObjectNode outputJson) throws Exception {
TrieNode nodeOfQueue = queue.poll();
if(outputJson == null){
// create a root of the JSON
outputJson = factory.objectNode();
outputJson.put(nodeOfQueue.target, createJsonRecursively(outputJson));
}else if (jsonRoot.get(nodeOfQueue.source).isObject()){
// create an object to conatin other values/object
ObjectNode objectNode = factory.objectNode();
objectNode.put(nodeOfQueue.target,createJsonRecursively(outputJson));
outputJson.putAll(objectNode);
}else if(jsonRoot.get(nodeOfQueue.source).isArray()){
// create an array node and call for to create value it contains
ArrayNode arrayNode = factory.arrayNode();
int size = jsonRoot.get(nodeOfQueue.source).size();
for(int index = 0 ; index < size ; index++){
arrayNode.add(jsonRoot.get(nodeOfQueue.source).get(index));
}
outputJson.put(nodeOfQueue.target,arrayNode);
}else if(nodeOfQueue.isEnd){
// create leaf node
outputJson.put(nodeOfQueue.target, jsonRoot.get(nodeOfQueue.source));
return outputJson;
}
return outputJson;
}
I want to extract JSON structure (only keyNames structure) by preserving the hierarchy (parent child relationship); I don't want values from the JSON yet.
I am new to Java and have been tying to achieve this using Jackson , but with no success.
Any direction on this will be much appreciated.
I created a static inner class for you by using JSONObject (http://www.json.org/javadoc/org/json/JSONObject.html)
public static class KeyNode {
private String name;
private ArrayList<KeyNode> children;
public KeyNode(String name) {
this.name = name;
this.children = new ArrayList<KeyNode>();
}
public void addChild(KeyNode child) {
this.children.add(child);
}
public static void parseJsonToKeys(KeyNode node, JSONObject json) throws JSONException {
Iterator<?> keys = json.keys();
while (keys.hasNext()) {
String name = (String) keys.next();
KeyNode child = new KeyNode(name);
node.addChild(child);
if (json.optJSONObject(name) != null) {
parseJsonToKeys(child, json.getJSONObject(name));
} else if (json.optJSONArray(name) != null) {
JSONArray array = json.getJSONArray(name);
for (int i = 0; i < array.length(); i++) {
try {
array.getJSONObject(i);
parseJsonToKeys(child, json.getJSONObject(name));
} catch (JSONException e) {
// this is ok
}
}
}
}
}
public static void exampleCodeUsage() {
try {
JSONObject json = new JSONObject("your json");
KeyNode keyHierarchy = new KeyNode("root");
parseJsonToKeys(keyHierarchy, json);
} catch (JSONException e) {
// your json is not formatted correctly
}
}
}
JSONParser parser = parser;
Object obj = parser.parse(new FileReader(FileName.Json));
JSONObject jobj = (JSONObject) obj;
obj.keys()
The method will give you the list of all keys in JSONObject