Having trouble deserializing JSON response with gson - java

I am using an API where I supply an input string, and it returns some keyword autocompletions and product nodes.
My goal is to deserialize the response and get a list of the autocompletion Strings I can use. I'm trying implement this in an android application with the Retrofit library, which uses gson.
First off, I'm not sure the response I have is a typical JSON response. The 'nodes' item has key / value pairs, but the input string and the autocompletions list don't seem to have keys I can use.
["pol",
["polaroid camera",
"polo",
"polo ralph lauren",
"polo ralph lauren men",
"polar heart rate monitor",
"polaroid",
"polo shirt",
"polar watch",
"police scanner",
"polar"],
[{
"nodes": [{
"alias": "electronics",
"name": "Electronics"
},
{
"alias": "electronics-tradein",
"name": "Electronics Trade-In"
}]
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
}],
[]]
This is my attempt at the java classes for gson to deserialize to. However, it doesn't work as from what I understand, gson needs the class variables to match the JSON keys (true for Node class but not the rest).
class Response {
String input;
List<String> keywords;
List<Node> nodes;
}
class Node {
String alias;
String name;
}

the json only has a couple of keys in it, this is largely a Json Array.
if you can change the JSON, make it more like this
{
"input" : "pol",
"keywords" : ["polaroid camera","polo",...],
"nodes": [{
"alias": "electronics",
"name": "Electronics"
},
{
"alias": "electronics-tradein",
"name": "Electronics Trade-In"
}]
}

Related

How to aggregate a 'non - keyword' field in elasticsearch?

I am trying to write an elastic-search query that should list all distinct values held by various fields in a document.When the fields are of type Keyword,the term aggregate query works fine and I can see the values with their counts listed in the buckets.But, I don't get any result when I query for the distinct citrus fruit types, the mapping is as shown below:
{
"vegetables":{
"type": "text",
"fields": {
"keyword" : {
"type" : "keyword",
"ignore_above": 256
}
}
},
"fruits": {
"properties": {
"citrus": {
"properties": {
"orange": {
"type": "long"
},
"lemon": {
"type": "long"
},
"kiwi": {
"type": "long"
}
}
}
}
}
}
and the result I am expecting is :
"aggregations": {
"distinct_citrusy_fruits"{
"buckets" : [
{
"key":"oranges",
"doc_count": 23
},
{
"key":"lemon",
"doc_count": 21
},
{
"key":"kiwi",
"doc_count": 23
}
]
}
}
when I make a term aggregation for the "vegetables" field (which is a keyword type) i am able to get the buckets as above.
How to get the distinct counts in this case?Also, I don't have the option to change the document format.
EDIT- the only workaround I have found till now is to call the mappings api and then parse the nested JSON in my code to get the key values,if there is any better solution possible, please add an answer here.
I think you cannot query or run aggregations on the field names, only on values.
For the fruits i expect the following mapping:
{
"fruits": {
"properties": {
"citrus": {
"properties": {
"kind": {
"type": "keyword"
},
"count": {
"type": "long"
}
}
}
}
}
}
Maybe you can use the _field_names field which contains every fieldname that has a value. (https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-field-names-field.html)

How to make a JSON Parser to parse elasticsearch mapping in java?

I wanted to parse this structure which is an elasticsearch filter:
{
"filter": {
"name_synonyms_filter": {
"synonym_path": "sample.txt",
"type": "abc_synonym_filter"
},
"name_formatter": {
"name": "name_formatter",
"type": "abc_token_filter"
}
}
}
My question is how can I access individual filters without using key ("name_synonyms_filter" , etc) in java?
your JSON was impropertly formatted.
Here it is fixed:
{
"abc": [{
"name": "somename"
},
{
"name": "somename"
}
]
}
How to parse it:
let x = JSON.parse({
"abc": [{
"name": "somename"
},
{
"name": "somename"
}
]
});
console.log(x);
Let me know if you have any questions.

Spring Data Rest + Spring Data Mongo - can't update numer of elements on list in object

so I have got a problem with updating object which contain a list of elements. My object definition:
public class Project {
private String _id;
private String name;
private List<Pair> config;
}
And the Pair object:
public class Pair {
private String key;
private String value;
}
I'm using Spring Rest repository to provide the Rest Api and everything is stored in mongodb. Just using the simple interface to create mongoRepository
#RepositoryRestResource(collectionResourceRel = "project", path = "projects")
public interface ProjectRepository extends MongoRepository<Project, String>{
Project findByName(String name);
}
When I create a project object with json (sending POST to /projects):
{
"name": "test_project",
"config": [{
"key": "port",
"value": "12"
},{
"key": "port2",
"value": "123"
}]
}
I have got the proper response and object has been created:
{
"_id": "58c916fad76a3a186731ad28",
"name": "test_project",
"createdAt": "2017-03-15T10:27:06.295+0000",
"modifiedAt": "2017-03-15T10:27:06.295+0000",
"config":[
{
"key": "port",
"value": "12"
},
{
"key": "port2",
"value": "123"
}]
}
So right now I would like to send PUT to update my object and I'm getting strange results:
For example sending following body with PUT to
localhost:8151/projects/58c916fad76a3a186731ad28
{
"name": "test_project",
"config": [{
"key": "port",
"value": "12"
}]
}
So I want to remove one element from list. The response is (Status OK):
{
"_id": "58c916fad76a3a186731ad28",
"name": "test_project",
"createdAt": "2017-03-15T10:27:06.295+0000",
"modifiedAt": "2017-03-15T10:27:06.295+0000",
"config":[
{
"key": "port",
"value": "12"
},
{
"key": "port2",
"value": "123"
}]
}
So the number of elements didn't change what I expected (my expectations was that the new list replace the old one). Next test:
I would like to add one new element to list:
{
"name": "test_project",
"config": [{
"key": "port",
"value": "12"
},{
"key": "port1",
"value": "13"
},{
"key": "port2",
"value": "14"
}]
}
Gives following result:
{
"_id": "58c916fad76a3a186731ad28",
"name": "test_project",
"createdAt": "2017-03-15T10:27:06.295+0000",
"modifiedAt": "2017-03-15T10:27:06.295+0000",
"config":[
{
"key": "port",
"value": "12"
},
{
"key": "port1",
"value": "13"
}]
}
New element hasn't been added but the second element has changed.
It looks like instead of List mongo save it as an array and can't change the size but can update the element. Am I right?
But, if it would be true the next test should return the same result:
I'm sending the empty list of config and I'm expect that I will have an two-element list.
{
"name": "test_project",
"config": []
}
But what is strange for me I have got the following result:
{
"_id": "58c916fad76a3a186731ad28",
"name": "test_project",
"createdAt": "2017-03-15T10:27:06.295+0000",
"modifiedAt": "2017-03-15T10:27:06.295+0000",
"config":[]
}
So the number of elements has been updated.
To be honest right now I'm totally confused how it works. Could anyone explain how Spring rest repository handle this action and propose a proper solution for this problem?
I am having the same issue. As a workaround you can send a PATCH request. This updates the array properly.

JSONSchema parsing and processing in Java

There is a perfect .NET library Json.NET Schema. I use it in my C# application to parse schemas and make a Dictionary<string, JSchema> with pairs "name_of_simple_element" - "simple_element". Then I process each pair and for example try to find "string" type elements with pattern "[a-z]" or "string" elements with maximumLength > 300.
Now I should create application with same functions in Java. It is very simple in C#:
Jschema schema = JSchema.Parse(string json);
IDictionary<string, JSchema> dict = schema.Properties;
... etc.
But i cant find same way to do that in Java. I need to convert this
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://iitrust.ru",
"type": "object",
"properties": {
"regions": {
"id": "...regions",
"type": "array",
"items": {
"id": "http://iitrust.ru/regions/0",
"type": "object",
"properties": {
"id": {
"id": "...id",
"type": "string",
"pattern": "^[0-9]+$",
"description": "Идентификатор региона"
},
"name": {
"id": "...name",
"type": "string",
"maxLength": 255,
"description": "Наименование региона"
},
"code": {
"id": "...code",
"type": "string",
"pattern": "^[0-9]{1,3}$",
"description": "Код региона"
}
},
"additionalProperties": false,
"required": ["id",
"name",
"code"]
}
}
},
"additionalProperties": false,
"required": ["regions"]
}
to pseudocode dictionary/map like this
["...id" : "id": { ... };
"...name" : "name": { ... };
"...code": "code": { ... }]
What is the best way to do that?
Ok, problem is resolved by Jackson library. Code below is based on generally accepted rule that JSON Schema object is always has a "properties" element, "array" node is always has a "items" element, "id" is always unique. This is my customer's standart format. Instead of a C#'s Dictionary<string, Jschema> I have got a Java's HashMap<String, JsonNode>.
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
...
static Map<String, JsonNode> elementsMap = new HashMap<>();
public static void Execute(File file) {
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(file);
JsonNode rootNode = root.path("properties");
FillTheElementMap(rootNode);
}
private static void FillTheElementMap(JsonNode rootNode) {
for (JsonNode cNode : rootNode){
if(cNode.path("type").toString().toLowerCase().contains("array")){
for(JsonNode ccNode : cNode.path("items")){
FillTheElementMap(ccNode);
}
}
else if(cNode.path("type").toString().toLowerCase().contains("object")){
FillTheElementMap(cNode.path("properties");
}
else{
elementsMap.put(cNode.path("id").asText(), cNode);
}
}
A good option for you should be this Java implementation of JSONPath.
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import net.minidev.json.JSONObject;
...
DocumentContext context = JsonPath.parse(jsonSchemaFile);
//"string" elements with maximumLength == 255
List<Map<String, JSONObject>> arr2 = context.read(
"$..[?(#.type == 'string' && #.maxLength == 255)]");
And if you want to create a JsonSchema from Java code, you could use jackson-module-jsonSchema.
If you want to validate a JsonSchema, then the library from fge is an option: json-schema-validator
You may want to take a look at this library, it's helped me with similar requirements. With a couple lines of code you can traverse a pretty straightforward Java object model that describes a JSON schema.
https://github.com/jimblackler/jsonschemafriend (Apache 2.0 license)
From the README:
jsonschemafriend is a JSON Schema loader and validator, delivered as a Java library...
It is compatible with the following metaschemas
http://json-schema.org/draft-03/schema#
http://json-schema.org/draft-04/schema#
http://json-schema.org/draft-06/schema#
http://json-schema.org/draft-07/schema#
https://json-schema.org/draft/2019-09/schema

parsing complex json object

Hi I am trying to parse json object below. But the problem is, inside the profile attribute, there is an attribute called fields which is sometimes a json object and sometime an json-array, so it is creating a problem when i am trying to use Gson to parse it. I followed this link but it didn't help How to dynamically handle json response array/object using Gson , so help is needed from someone who encountered this before, thanks!.
{
"users": {
"profile": [
{
"fields": {
"key": "fname",
"value": "Michael"
}
},
{
"fields": [
{
"key": "lname",
"value": "Bob"
},
{
"key": "age",
"value": "25"
}
]
}
]
}
}

Categories