Spring query convert to a nested JSON structure - java

I'm new to spring and Java and trying to figure out how to go about formatting the json response into the desired structure.
I have a spring query that's returning 2 columns from a table like below which are really the key and values I need for the json structure:
Names
Values
Car
Toyota
Bike
Schwinn
Scooter
Razor
A0
11
A1
12
A2
13
B0
2000
B1
4000
B2
22000
The current json output from the controller is this:
[{
"names": "Car",
"values": "Toyota"
},
{
"names": "Bike",
"values": "Schwinn"
},
{
"names": "Scooter",
"values": "Razor"
},
{
"names": "A0",
"values": "11"
},
{
"names": "A1",
"values": "12"
},
{
"names": "A2",
"values": "13"
},
{
"names": "B0",
"values": "2000"
},
{
"names": "B1",
"values": "4000"
},
{
"names": "B2",
"values": "22000"
}
]
And the desired json format is this where the table column names are removed and instead json structure is created using the names column for the keys:
{
"Car": "Toyota",
"Bike": "Schwinn",
"Scooter": "Razor",
"Data": [{
"A0": "11",
"B0": "2000"
}, {
"A1": "12",
"B1": "4000"
}, {
"A2": "13",
"B2": "22000"
}]
}
Repository
#Query (value = "Select names, values ... :id")
List<Data> findData(#Param("id") Long id) ;
interface Data {
String getnames();
String getvalues();
}
Service
public List<Data> getData(Long id) {return repo.findData(id);}
Controller
#GetMapping("/getdata/{id}")
public ResponseEntity<List<Data>> getData(#PathVariable Long id) {
List<Data> c = service.getData(id);
return new ResponseEntity<>(c, HttpStatus.OK);
}
It seems that I need to process the result set and need to loop through them to create the desired structure but not sure how to proceed with that, or perhaps there is an easier way to get to the desired structure. Any guidance would be appreciated.

So return a ResponseEntity<Map<String, Object>> instead of a List to simulate a Json object.
List<Data> c = service.getData(id);
Map<String, Object> map = new HashMap<>();
map.put("Key", "Value");
map.put("Car", c.get(0).getvalues());
map.put("Entire List", c);
return new ResponseEntity<>(c, HttpStatus.OK);
Obviously you'll have to write your own logic but it should be pretty straight forward. Or, even better, consider making a class for the object returned if you're going to be using it a lot, and just return ResponseEntity< YourCustomObject >

This looks a bit complicated, I think you should set the primary key association for values like A0 B0
import com.black_dragon.utils.JacksonUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.groupingBy;
/**
* #author black_dragon
* #version V1.0
* #Package com.black_dragon.swing
* #date 2022/9/6 10:35
* #Copyright
*/
public class ConvertToMap {
String names;
String values;
public String getNames() {
return names;
}
public void setNames(String names) {
this.names = names;
}
public String getValues() {
return values;
}
public void setValues(String values) {
this.values = values;
}
private static String DIGIT_REGEX = "[^0-9]";
private static String LETTER_DIGIT_REGEX = "[a-zA-Z]+";
public static Integer getDigit(String str){
Pattern pattern = Pattern.compile(DIGIT_REGEX);
if(!isLetterDigit(str)){
String[] keySet = pattern.split(str);
if(keySet.length > 0){
return Integer.valueOf(keySet[1]);
}
}
return -1;
}
public static boolean isLetterDigit(String str){
return str.matches(LETTER_DIGIT_REGEX);
}
private static String fetchGroupKey(ConvertToMap convertToMap){
return String.valueOf(getDigit(convertToMap.names));
}
public static void main(String[] args) {
String jsonString = "[{\n" +
" \"names\": \"Car\",\n" +
" \"values\": \"Toyota\"\n" +
" },\n" +
" {\n" +
" \"names\": \"Bike\",\n" +
" \"values\": \"Schwinn\"\n" +
" },\n" +
" {\n" +
" \"names\": \"Scooter\",\n" +
" \"values\": \"Razor\"\n" +
" },\n" +
" {\n" +
" \"names\": \"A0\",\n" +
" \"values\": \"11\"\n" +
" },\n" +
" {\n" +
" \"names\": \"A1\",\n" +
" \"values\": \"12\"\n" +
" },\n" +
" {\n" +
" \"names\": \"A2\",\n" +
" \"values\": \"13\"\n" +
" },\n" +
" {\n" +
" \"names\": \"B0\",\n" +
" \"values\": \"2000\"\n" +
" },\n" +
" {\n" +
" \"names\": \"B1\",\n" +
" \"values\": \"4000\"\n" +
" },\n" +
" {\n" +
" \"names\": \"B2\",\n" +
" \"values\": \"22000\"\n" +
" }\n" +
"]";
List<ConvertToMap> convertToMaps = JacksonUtils.toJavaList(jsonString, ConvertToMap.class);
// Extract a string that does not contain numbers and convert it to a map
Map<String, Object> result = convertToMaps.stream()
.filter(x -> isLetterDigit(x.names))
.collect(Collectors.toMap(ConvertToMap::getNames, ConvertToMap::getValues));
List<Map<String, String>> mapList = new ArrayList<>();
// Group by string numbers containing numbers
Map<String, List<ConvertToMap>> stringListMap = convertToMaps.stream().collect(groupingBy(convertToMap -> fetchGroupKey(convertToMap)));
for (String key : stringListMap.keySet()) {
if(Integer.valueOf(key) >= 0){
mapList.add(stringListMap.get(key)
.stream()
.collect(Collectors.toMap(ConvertToMap::getNames, ConvertToMap::getValues)));
}
}
result.put("Data", mapList);
System.out.println(JacksonUtils.toJSONString(result));
}
}

Assume that your data key name pattern is one non-digit followed by digits.
https://github.com/octomix/josson
Deserialization
Josson josson = Josson.fromJsonString(
"[" +
" {" +
" \"names\": \"Car\"," +
" \"values\": \"Toyota\"" +
" }," +
" {" +
" \"names\": \"Bike\"," +
" \"values\": \"Schwinn\"" +
" }," +
" {" +
" \"names\": \"Scooter\"," +
" \"values\": \"Razor\"" +
" }," +
" {" +
" \"names\": \"A0\"," +
" \"values\": \"11\"" +
" }," +
" {" +
" \"names\": \"A1\"," +
" \"values\": \"12\"" +
" }," +
" {" +
" \"names\": \"A2\"," +
" \"values\": \"13\"" +
" }," +
" {" +
" \"names\": \"B0\"," +
" \"values\": \"2000\"" +
" }," +
" {" +
" \"names\": \"B1\"," +
" \"values\": \"4000\"" +
" }," +
" {" +
" \"names\": \"B2\"," +
" \"values\": \"22000\"" +
" }" +
"]");
Transformation
JsonNode node = josson.getNode(
"#collect([names !=~ '\\D\\d+']*" +
" .map(names::values)" +
" ,[names =~ '\\D\\d+']*" +
" .group(names.substr(1), map(names::values))#" +
" .elements" +
" .mergeObjects()" +
" .#toObject('Data')" +
")" +
".flatten(1)" +
".mergeObjects()");
System.out.println(node.toPrettyString());
Output
{
"Car" : "Toyota",
"Bike" : "Schwinn",
"Scooter" : "Razor",
"Data" : [ {
"A0" : "11",
"B0" : "2000"
}, {
"A1" : "12",
"B1" : "4000"
}, {
"A2" : "13",
"B2" : "22000"
} ]
}

Related

Deeply nested JSON response from third party

I'm getting this deeply nested JSON response from an api that I have no control,
What should be the best way to get to "generalDetails" and then find the first true value under security, address, account and mobile?
{
"info_code": "201",
"info_description": "info description",
"data": {
"status": "here goes the status",
"failure_data": {
"source": "anySource",
"details": {
"data": {
"server_response": {
"generalDetails": {
"security": {
"isAccountLocked": "false"
},
"address": {
"isAddresExists": "true"
},
"account": {
"accountExists": "true",
"isValidAccount": "true"
},
"mobile": {
"mobileExists": "true"
}
}
}
}
}
}
}
}
My request looks like:
#Autowired
private WebClient.Builder webClientBuilder;
String resp = webClientBuilder.build().get().uri(URL)
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(String.class).block();
First, build the model, automatic here https://codebeautify.org/json-to-java-converter.
Then read data with the model
.bodyToMono(MyData.class)
Then decide how you want evaluate the requirement find the first true value under security, address, account and mobile.
What means "first" ? JSON has no natural order without indicating explicity (e.g. field "order": 2).
N.B. "true", "false" of the response are Strings, not booleans.
Once you have the model with data, you may do:
Object firstTrue(GeneralDetails gd) {
// No null checks here
if ("true".equals(gd.getSecurtity().isLockedAccount())) return gd.getSecurtity();
if ("true".equals(gd.getAddress().isAddressExists())) return gd.getAddress();
if ("true".equals(gd.getAccount().isAccountExists()) || "true".equals(gd.getAccount().isAccountValid())) return gd.getAccount();
if ("true".equals(gd.getMobile().isMobileExists())) return gd.getMobile();
return null;
}
https://github.com/octomix/josson
Deserialization
Josson josson = Josson.fromJsonString(
"{" +
" \"info_code\": \"201\"," +
" \"info_description\": \"info description\"," +
" \"data\": {" +
" \"status\": \"here goes the status\"," +
" \"failure_data\": {" +
" \"source\": \"anySource\"," +
" \"details\": {" +
" \"data\": {" +
" \"server_response\": {" +
" \"generalDetails\": {" +
" \"security\": {" +
" \"isAccountLocked\": \"false\"" +
" }," +
" \"address\": {" +
" \"isAddresExists\": \"true\"" +
" }," +
" \"account\": {" +
" \"accountExists\": \"true\"," +
" \"isValidAccount\": \"true\"" +
" }," +
" \"mobile\": {" +
" \"mobileExists\": \"true\"" +
" }" +
" }" +
" }" +
" }" +
" }" +
" }" +
" }" +
"}");
Query
JsonNode node = josson.getNode(
"data.failure_data.details.data.server_response" +
".generalDetails.**.mergeObjects().assort().[*]");
System.out.println(node.toPrettyString());
Output
{
"isAddresExists" : "true"
}
If changed isAddresExists and accountExists to false
" \"generalDetails\": {" +
" \"security\": {" +
" \"isAccountLocked\": \"false\"" +
" }," +
" \"address\": {" +
" \"isAddresExists\": \"false\"" +
" }," +
" \"account\": {" +
" \"accountExists\": \"false\"," +
" \"isValidAccount\": \"true\"" +
" }," +
" \"mobile\": {" +
" \"mobileExists\": \"true\"" +
" }" +
" }" +
Output
{
"isValidAccount" : "true"
}
If you only want the key name
String firstTureKey = josson.getString(
"data.failure_data.details.data.server_response" +
".generalDetails.**.mergeObjects().assort().[*].keys().[0]");
System.out.println(firstTureKey);
Output
isValidAccount

Traversing through dynamic JSON to read properties of every child node

I have some JSON which is subject to change but one constant is it will always contain multiple objects with two properties; text and answerText. An example JSON would be
{
"food": {
"eggTolerance": {
"answerText": "None",
"text": "What is your egg tolerance?"
},
"lactoseTolerance": null
},
"cookingExperience": {
"experienceInLastFiveYears": {
"answerText": "Yes",
"text": "Was this experience within the last 5 years?"
},
"numberOfPies": {
"answerText": "More than 50",
"text": "How many pies have you baked?"
},
"significantPies": {
"answerText": "More than 50",
"text": "How many of these pies per quarter were at tasty?"
},
"spanOfExperience": {
"answerText": "Yes",
"text": "Do you have at least 12 months' experience baking pies?"
}
},
"cocktails": {
"manhattans": {
"answerText": "The kiss of death",
"text": "What have I done to deserve this flat, flavourless Manhattan?"
},
"Gin Martini": null
},
"waitressing": null
}
This can be changed by making it deeper or wider. For example the lactoseTolerance could have another object added to it or another object could be added to the root object.
How can I traverse this object to visit every object to get the properties of the deepest object?
I have seen this example but this just gives me the first level. In this instance I know I can then iterate the children of those objects but if the hierarchy changes the implementation is ruined.
I have used GSON lib:
Please try below code:
pom.xml
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
Then I have created QA class that have your fixed two properties; text and answerText
import com.google.gson.annotations.SerializedName;
public class QA {
#SerializedName("answerText")
private String answerText;
#SerializedName("text")
private String text;
public QA(String answerText, String text) {
this.answerText = answerText;
this.text = text;
}
#Override
public String toString() {
return "QA{" +
"answerText='" + answerText + '\'' +
", text='" + text + '\'' +
'}';
}
public String getAnswerText() {
return answerText;
}
public void setAnswerText(String answerText) {
this.answerText = answerText;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
Now in driver code:
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.Map;
public class Main {
public static void main(String[] args) {
System.out.println("running!!");
InputStream inputStream = Main.class.getResourceAsStream("json.json");
String json = "{\n" +
" \"food\": {\n" +
" \"eggTolerance\": {\n" +
" \"answerText\": \"None\",\n" +
" \"text\": \"What is your egg tolerance?\"\n" +
" },\n" +
" \"lactoseTolerance\": null\n" +
" },\n" +
" \"cookingExperience\": {\n" +
" \"experienceInLastFiveYears\": {\n" +
" \"answerText\": \"Yes\",\n" +
" \"text\": \"Was this experience within the last 5 years?\"\n" +
" },\n" +
" \"numberOfPies\": {\n" +
" \"answerText\": \"More than 50\",\n" +
" \"text\": \"How many pies have you baked?\"\n" +
" },\n" +
" \"significantPies\": {\n" +
" \"answerText\": \"More than 50\",\n" +
" \"text\": \"How many of these pies per quarter were at tasty?\"\n" +
" },\n" +
" \"spanOfExperience\": {\n" +
" \"answerText\": \"Yes\",\n" +
" \"text\": \"Do you have at least 12 months' experience baking pies?\"\n" +
" }\n" +
" },\n" +
" \"cocktails\": {\n" +
" \"manhattans\": {\n" +
" \"answerText\": \"The kiss of death\",\n" +
" \"text\": \"What have I done to deserve this flat, flavourless Manhattan?\"\n" +
" },\n" +
" \"Gin Martini\": null\n" +
" },\n" +
" \"waitressing\": null\n" +
"}";
final Gson gson = new Gson();
Type type = new TypeToken<Map<String, Map<String, QA>>>(){}.getType();
Map<String, Map<String, QA>> myMap = gson.fromJson(json, type);
System.out.println("Data:"+ myMap.get("food").get("eggTolerance").getAnswerText());
}
}

3 levels Json how can I make a count inside

I want to consume an api that returns a json like this one:
{
"startDate": "2019-06-23T16:07:21.205Z",
"endDate": "2019-07-24T16:07:21.205Z",
"status": "Complete",
"usages": [
{
"name": "PureCloud Edge Virtual Usage",
"resources": [
{
"name": "Edge01-VM-GNS-DemoSite01 (1f279086-a6be-4a21-ab7a-2bb1ae703fa0)",
"date": "2019-07-24T09:00:28.034Z"
},
{
"name": "329ad5ae-e3a3-4371-9684-13dcb6542e11",
"date": "2019-07-24T09:00:28.034Z"
},
{
"name": "e5796741-bd63-4b8e-9837-4afb95bb0c09",
"date": "2019-07-24T09:00:28.034Z"
}
]
},
{
"name": "PureCloud for SmartVideo Add-On Concurrent",
"resources": [
{
"name": "jpizarro#gns.com.co",
"date": "2019-06-25T04:54:17.662Z"
},
{
"name": "jaguilera#gns.com.co",
"date": "2019-06-25T04:54:17.662Z"
},
{
"name": "dcortes#gns.com.co",
"date": "2019-07-15T15:06:09.203Z"
}
]
},
{
"name": "PureCloud 3 Concurrent User Usage",
"resources": [
{
"name": "jpizarro#gns.com.co",
"date": "2019-06-25T04:54:17.662Z"
},
{
"name": "jaguilera#gns.com.co",
"date": "2019-06-25T04:54:17.662Z"
},
{
"name": "dcortes#gns.com.co",
"date": "2019-07-15T15:06:09.203Z"
}
]
},
{
"name": "PureCloud Skype for Business WebSDK",
"resources": [
{
"name": "jpizarro#gns.com.co",
"date": "2019-06-25T04:54:17.662Z"
},
{
"name": "jaguilera#gns.com.co",
"date": "2019-06-25T04:54:17.662Z"
},
{
"name": "dcortes#gns.com.co",
"date": "2019-07-15T15:06:09.203Z"
}
]
}
],
"selfUri": "/api/v2/billing/reports/billableusage"
}
I have to count the amount of name in the last level. Looking on the web I´ve found a library and I just tried to adapt the example, but I have some doubts: one is that it starts with a string, not the route of the json file I have to test. I´ve put it in there manually, buy Eclipse added a lot of: /
When I try to run this:
String jsonString = "{\r\n" +
" \"startDate\": \"2019-06-23T16:07:21.205Z\",\r\n" +
" \"endDate\": \"2019-07-24T16:07:21.205Z\",\r\n" +
" \"status\": \"Complete\",\r\n" +
" \"usages\": [\r\n" +
" {\r\n" +
" \"name\": \"PureCloud Edge Virtual Usage\",\r\n" +
" \"resources\": [\r\n" +
" {\r\n" +
" \"name\": \"Edge01-VM-GNS-DemoSite01 (1f279086-a6be-4a21-ab7a-2bb1ae703fa0)\",\r\n" +
" \"date\": \"2019-07-24T09:00:28.034Z\"\r\n" +
" },\r\n" +
" {\r\n" +
" \"name\": \"329ad5ae-e3a3-4371-9684-13dcb6542e11\",\r\n" +
" \"date\": \"2019-07-24T09:00:28.034Z\"\r\n" +
" }, \r\n" +
" {\r\n" +
" \"name\": \"e5796741-bd63-4b8e-9837-4afb95bb0c09\",\r\n" +
" \"date\": \"2019-07-24T09:00:28.034Z\"\r\n" +
" }\r\n" +
" ]\r\n" +
" },\r\n" +
" {\r\n" +
" \"name\": \"PureCloud for SmartVideo Add-On Concurrent\",\r\n" +
" \"resources\": [\r\n" +
" {\r\n" +
" \"name\": \"jpizarro#gns.com.co\",\r\n" +
" \"date\": \"2019-06-25T04:54:17.662Z\"\r\n" +
" },\r\n" +
" {\r\n" +
" \"name\": \"jaguilera#gns.com.co\",\r\n" +
" \"date\": \"2019-06-25T04:54:17.662Z\"\r\n" +
" }, \r\n" +
" {\r\n" +
" \"name\": \"dcortes#gns.com.co\",\r\n" +
" \"date\": \"2019-07-15T15:06:09.203Z\"\r\n" +
" }\r\n" +
" ]\r\n" +
" },\r\n" +
" {\r\n" +
" \"name\": \"PureCloud 3 Concurrent User Usage\",\r\n" +
" \"resources\": [\r\n" +
" {\r\n" +
" \"name\": \"jpizarro#gns.com.co\",\r\n" +
" \"date\": \"2019-06-25T04:54:17.662Z\"\r\n" +
" },\r\n" +
" {\r\n" +
" \"name\": \"jaguilera#gns.com.co\",\r\n" +
" \"date\": \"2019-06-25T04:54:17.662Z\"\r\n" +
" }, \r\n" +
" {\r\n" +
" \"name\": \"dcortes#gns.com.co\",\r\n" +
" \"date\": \"2019-07-15T15:06:09.203Z\"\r\n" +
" }\r\n" +
" ]\r\n" +
" },\r\n" +
" {\r\n" +
" \"name\": \"PureCloud Skype for Business WebSDK\",\r\n" +
" \"resources\": [\r\n" +
" {\r\n" +
" \"name\": \"jpizarro#gns.com.co\",\r\n" +
" \"date\": \"2019-06-25T04:54:17.662Z\"\r\n" +
" },\r\n" +
" {\r\n" +
" \"name\": \"jaguilera#gns.com.co\",\r\n" +
" \"date\": \"2019-06-25T04:54:17.662Z\"\r\n" +
" }, \r\n" +
" {\r\n" +
" \"name\": \"dcortes#gns.com.co\",\r\n" +
" \"date\": \"2019-07-15T15:06:09.203Z\"\r\n" +
" }\r\n" +
" ]\r\n" +
" }\r\n" +
" ],\r\n" +
" \"selfUri\": \"/api/v2/billing/reports/billableusage\"\r\n" +
"}\r\n" +
"";
int cantidadDeLicencias = 0;
JSONObject jsonObject = new JSONObject(jsonString);
JSONArray usages = jsonObject.getJSONArray("usages");
System.out.println("usages " + usages);
for (int i = 0; i < usages.length(); i++) {
JSONArray resources = jsonObject.getJSONArray("resources");
for (int j = 0; j < resources.length(); j++) {
JSONArray names = jsonObject.getJSONArray("name");
cantidadDeLicencias = cantidadDeLicencias + names.length();
//String name = jsonObject.getJSONObject(j).getString("name");
}
}
System.out.println("Cantidad de licencias" + cantidadDeLicencias);
An error comes out: JSONObject["resources"] not found.
If the program would work, what changes I have to make cause, the api returns a json, you know, without all those: /. So this library is going to be useful?
Update
Now it works
int cantidadDeLicencias = 0;
JSONObject jsonObject = new JSONObject(jsonString);
JSONArray usages = jsonObject.getJSONArray("usages");
System.out.println("usages " + usages);
for (int i = 0; i < usages.length(); i++) {
JSONObject innerTemp = usages.getJSONObject(i);
JSONArray resources = innerTemp.getJSONArray("resources");
//JSONArray resources = usages.getJSONArray("resources");
for (int j = 0; j < resources.length(); j++) {
String names = resources.getJSONObject(j).getString("name");
cantidadDeLicencias = cantidadDeLicencias + 1;
//String name = jsonObject.getJSONObject(j).getString("name");
}
}
System.out.println("Cantidad de licencias " + cantidadDeLicencias);
What should I do with the json? cause, here it has a lot of: / and the api doesn´t return that?
resources is inside a JSONObject, not directly inside the JSONArray.
Access it like this:
JSONArray usages = jsonObject.getJSONArray("usages");
for (int i = 0; i < usages.length(); i++) {
JSONObject innerTemp = usages.getJSONObject(i);
JSONArray resources = innerTemp.getJSONArray("resources");
// more code here
}

Json Response to string Array

I want to convert my json string to string array. My JSON string is having two parameters "href" and "name". I want to create List of string of values of "name" parameter using java. I am using NetBeans for my application. please help me out to resolve this issue. I am getting error as
Exception in thread "AWT-EventQueue-0" org.json.JSONException: A JSONArray text must start with '[' at 1 [character 2 line 1]
JSONArray arr = new JSONArray(response);
List<String> list = new ArrayList<String>();
for(int i = 0; i < arr.length(); i++){
list.add(arr.getJSONObject(i).getString("name"));
System.out.println(arr.getJSONObject(i).getString("name"));
}
This is my JSON string
[
{
"href": "\/api\/rest\/v1\/protocols\/bacnet\/local\/objects\/analog-value\/1",
"name": "analogValue_1"
},
{
"href": "\/api\/rest\/v1\/protocols\/bacnet\/local\/objects\/analog-value\/9",
"name": "analogValue_9"
},
{
"href": "\/api\/rest\/v1\/protocols\/bacnet\/local\/objects\/analog-value\/2",
"name": "analogValue_2"
},
{
"href": "\/api\/rest\/v1\/protocols\/bacnet\/local\/objects\/analog-value\/8",
"name": "analogValue_8"
},
{
"href": "\/api\/rest\/v1\/protocols\/bacnet\/local\/objects\/analog-value\/7",
"name": "analogValue_7"
},
{
"href": "\/api\/rest\/v1\/protocols\/bacnet\/local\/objects\/analog-value\/3",
"name": "analogValue_3"
},
{
"href": "\/api\/rest\/v1\/protocols\/bacnet\/local\/objects\/analog-value\/6",
"name": "analogValue_6"
},
{
"href": "\/api\/rest\/v1\/protocols\/bacnet\/local\/objects\/analog-value\/5",
"name": "analogValue_5"
},
{
"href": "\/api\/rest\/v1\/protocols\/bacnet\/local\/objects\/analog-value\/4",
"name": "analogValue_4"
}
]
Fix your json. 1. Change square brackets to curly brackets. 2. Each dictionary inside of your json is a value which must have a corresponding key. You code should look like this:
public static void main(String[] args) {
String myJSON = "{data_0:\n"
+ " {\n"
+ " \"href\": \"\\/api\\/rest\\/v1\\/protocols\\/bacnet\\/local\\/objects\\/analog-value\\/1\",\n"
+ " \"name\": \"analogValue_1\"\n"
+ " },\n data_1:"
+ " {\n"
+ " \"href\": \"\\/api\\/rest\\/v1\\/protocols\\/bacnet\\/local\\/objects\\/analog-value\\/9\",\n"
+ " \"name\": \"analogValue_9\"\n"
+ " },\n data_2:"
+ " {\n"
+ " \"href\": \"\\/api\\/rest\\/v1\\/protocols\\/bacnet\\/local\\/objects\\/analog-value\\/2\",\n"
+ " \"name\": \"analogValue_2\"\n"
+ " },\n data_3:"
+ " {\n"
+ " \"href\": \"\\/api\\/rest\\/v1\\/protocols\\/bacnet\\/local\\/objects\\/analog-value\\/8\",\n"
+ " \"name\": \"analogValue_8\"\n"
+ " },\n data_4:"
+ " {\n"
+ " \"href\": \"\\/api\\/rest\\/v1\\/protocols\\/bacnet\\/local\\/objects\\/analog-value\\/7\",\n"
+ " \"name\": \"analogValue_7\"\n"
+ " },\n data_5:"
+ " {\n"
+ " \"href\": \"\\/api\\/rest\\/v1\\/protocols\\/bacnet\\/local\\/objects\\/analog-value\\/3\",\n"
+ " \"name\": \"analogValue_3\"\n"
+ " },\n data_6:"
+ " {\n"
+ " \"href\": \"\\/api\\/rest\\/v1\\/protocols\\/bacnet\\/local\\/objects\\/analog-value\\/6\",\n"
+ " \"name\": \"analogValue_6\"\n"
+ " },\n data_7:"
+ " {\n"
+ " \"href\": \"\\/api\\/rest\\/v1\\/protocols\\/bacnet\\/local\\/objects\\/analog-value\\/5\",\n"
+ " \"name\": \"analogValue_5\"\n"
+ " },\n data_8:"
+ " {\n"
+ " \"href\": \"\\/api\\/rest\\/v1\\/protocols\\/bacnet\\/local\\/objects\\/analog-value\\/4\",\n"
+ " \"name\": \"analogValue_4\"\n"
+ " }\n"
+ "}";
JSONObject jsonObject = new JSONObject(myJSON);
System.out.println("jsonObject: " + jsonObject.toString());
List<String> list = new ArrayList<String>();
System.out.println("jsonObject length: " + jsonObject.length());
for (int i = 0; i < jsonObject.length(); i++) {
list.add(jsonObject.getJSONObject("data_" + i).toString());
System.out.println(jsonObject.getJSONObject("data_" + i));
}
}
I added keys from data_0 to data_8. Then you create a list. Probably that does not exactly solve your problem, but least gives an idea where you're making a mistake.
From your comment we can see that you're using okhttp3.internal.http.RealResponseBody. Since the toString() method is not overwritten, the default implementation is used which is why System.out.println(response.body().toString()); prints okhttp3.internal.http.RealResponseBody#66cdc1bd.
To get the actual raw response use the string() method:
JSONArray arr = new JSONArray(responseBody.string());
According to the documentation (RealResponseBody extends ResponseBody):
String string()
Returns the response as a string decoded with the charset of the Content-Type header.
This also has already been discussed here by the way.

Elasticsearch: rewrite a query using java native api

I have this query in Elasticsearch that is working perfectly if I run it from the command line:
POST http://localhost:9200/YOUR_INDEX_NAME/_search/
{
"size": 0,
"aggs": {
"autocomplete": {
"terms": {
"field": "autocomplete",
"order": {
"_count": "desc"
},
"include": {
"pattern": "c.*"
}
}
}
},
"query": {
"prefix": {
"autocomplete": {
"value": "c"
}
}
}
}
I have tried to rewrite it in java using the native client:
SearchResponse searchResponse2 = newClient.prepareSearch(INDEX_NAME)
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery("{\n" +
" \"size\": 0,\n" +
" \"aggs\": {\n" +
" \"autocomplete\": {\n" +
" \"terms\": {\n" +
" \"field\": \"autocomplete\",\n" +
" \"order\": {\n" +
" \"_count\": \"desc\"\n" +
" },\n" +
" \"include\": {\n" +
" \"pattern\": \"c.*\"\n" +
" }\n" +
" }\n" +
" }\n" +
" },\n" +
" \"query\": {\n" +
" \"prefix\": {\n" +
" \"autocomplete\": {\n" +
" \"value\": \"c\"\n" +
" }\n" +
" }\n" +
" }\n" +
"}").get();
for (SearchHit res : searchResponse2.getHits()){
System.out.println(res.getSourceAsString());
}
Seems, that I'm missing something in this translation process. Thanks in advance
The Java client setQuery() method doesn't take a String with the JSON query, you need to build the query using the QueryBuilders helper methods and build the aggregation your the AggregationBuilders helper methods.
In your case that would go like this:
// build the aggregation
TermsBuilder agg = AggregationBuilders.terms("autocomplete")
.field("autocomplete")
.include("c.*")
.order(Terms.Order.count(false));
// build the query
SearchResponse searchResponse2 = newClient.prepareSearch(INDEX_NAME)
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setSize(0)
.setQuery(QueryBuilders.prefixQuery("autocomplete", "c"))
.addAggregation(agg)
.get();

Categories