How to convert a json to json using external mapping - java

We are calling an API in our java server which returns a json.
Now we want to convert this json into another json. But we want to have the conversion mapping in a separate file.
As an example,
Json A:
{
"json_id":"3",
"json_another_id":"43",
"code":34,
"json_name":"Yey"
}
To convert into Json B:
{
"id":"3",
"another_id":"43",
"code":34,
"name":"Yeyproto"
}
Below is the mapping which I want it to be present in the separate file:
"json_id" -> "id"
"json_another_id" -> "another_id"
"json_name" -> "name"
Please let me know a good solution for this. I have checked out jackson mixin but it converts from json to pojo

Try JOLT. It is a JSON to JSON transformation library written in Java where the "specification" for the transform is itself a JSON document. It was created on a project that was transforming lot of JSON from an ElasticSearch "backend" to a frontend api.

One popular tool for JSON to JSON transforms in Java is Jolt. You can simply achieve this with given Jolt Spec as follows:
Jolt Spec
[
{
"operation": "shift",
"spec": {
"#json_id": "id",
"#json_another_id": "another_id",
"#code": "code",
"#json_name": "name"
}
}
]
You can verify it by Jolt Transform Demo to put your original JSON string and the Jolt Spec, then press Transform button to see the result. Following code snippet shows how to achieve this in Java.
Maven dependency
<dependency>
<groupId>com.bazaarvoice.jolt</groupId>
<artifactId>jolt-core</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>com.bazaarvoice.jolt</groupId>
<artifactId>json-utils</artifactId>
<version>0.1.0</version>
</dependency>
Code snippet
String spec = "[\r\n" +
" {\r\n" +
" \"operation\": \"shift\",\r\n" +
" \"spec\": {\r\n" +
" \"#json_id\": \"id\",\r\n" +
" \"#json_another_id\": \"another_id\",\r\n" +
" \"#code\": \"code\",\r\n" +
" \"#json_name\": \"name\"\r\n" +
" }\r\n" +
" }\r\n" +
"]";
Chainr chainr = Chainr.fromSpec(JsonUtils.jsonToList(spec));
Object transformedOutput = chainr.transform(JsonUtils.jsonToObject(jsonStr));
System.out.println(transformedOutput.toString());
Console output
{id=3, another_id=43, code=34, name=Yey}

Related

how to parse a xml with html content as value in java/groovy

I need to convert the below xml to json with the nested HTML content intact.
<example>
<value attribute="value">some treatment <b>plant</b> with bio chemicals</value>
</example>
To Json
{
"example": {
"value": {
"attribute": "value",
"content": "some treatment <b>plant</b> with bio chemicals"
}
}
}
I tried to do it with all popular libaraies like jackson, org.json, json-simple , JSON-lib. But i could not find a possibly library that can do it out of the box.
Can i get an idea if there are any possible libraries to do this if not any way to achieve this conversion
A solution using XmlSlurper from Groovy to parse the XML (which internally uses SAX Parser which is light weight). In java, we can do the same, but groovy GPath made it even easier.
def parseXMLWithMarkup() {
String xmlWithMarkup = """
<example>
<value attribute="value">some treatment <b>plant</b> with bio chemicals</value>
</example>
""";
example = new groovy.util.XmlSlurper().parseText(xmlWithMarkup)
textInsideValueWithMarkup = example.childNodes().findAll { it.name() == 'value' }.collect {
it.children().collect { child ->
if (child instanceof groovy.util.slurpersupport.Node) {
return "<" + child.name() + ">" + child.text() + "</" + child.name() + ">"
} else {
return child
}
}.join('')
}
println textInsideValueWithMarkup[0]
}
We can access XML values with
example.value.text()
we can access XML attribute values with
example.value.#attribute.text()

Java : How to extract parameters from Google Dialogflow V2 response

Does anyone know how to extract the parameters returned by the Google dialogflow v2 response? I am able to get the intents and confidence properly as there are high level methods available to do so. But it seems there is no method to get the parameters/list of params. The response contains a google protobuf Struct that has the params. Does anyone know how to extract the parameter names and values from it.
Here is a sample response
query_text: "next friday"
parameters {
fields {
key: "appointmentDate"
value {
struct_value {
fields {
key: "date"
value {
string_value: "2019-05-31T12:00:00+10:00"
}
}
}
}
}
}
all_required_params_present: true
fulfillment_messages {
text {
text: ""
}
}
intent {
name: "projects/dksjdkjsjksd-c824f/agent/intents/89a100c4973a"
display_name: "captureDate"
}
intent_detection_confidence: 1.0
language_code: "en"
It would be something lilke this:
for (Entry<String, Value> entry : queryResult.getParameters().getFieldsMap().entrySet()) {
if (entry.getValue().getKindCase().getNumber() == Value.STRING_VALUE_FIELD_NUMBER) {
log.debug("FOUND PARAM. KEY:" + entry.getKey() + " STRING VALUE: "
+ entry.getValue().getStringValue());
} else if (entry.getValue().getKindCase().getNumber() == Value.STRUCT_VALUE_FIELD_NUMBER) {
log.debug("FOUND PARAM. KEY:" + entry.getKey() + " STRUCT VALUE: "
+ entry.getValue().getStructValue());
}
else if (entry.getValue().getKindCase().getNumber() == Value.NUMBER_VALUE_FIELD_NUMBER) {
log.debug("FOUND PARAM. KEY:" + entry.getKey() + " NUMBER VALUE: "
+ String.valueOf(entry.getValue().getNumberValue()));
}
}
I was too focussed to parse and map the proto buffer to a Java bean. After spending hours and posting a question, a simple thought striked to my mind to find a way to convert the proto buffer to a json. And then it was all simple because I found this API
JsonFormat.printToString(protoMessage)
It sounds simple now but that is all because I changed my problem solving strategy from learning proto buffer and decoding it, to rather use a proto to json convertor and work with json format, which understand much better.

MarkLogic Wilcard Search - QConsole vs. Java API

I believe I’m seeing different results from a Java-based query and what I believe is the equivalent cts:search in the query console. There's a lot of information here and I tried to organize it appropriately. Here are the steps to set up a simple example that replicates what I’m seeing.
Create new database with default settings
Add new forest with default settings
Enable three character searches (only non-default database setting)
Insert the three json documents below into the database
Query console returns doc2. Java client returns doc2 AND doc1. Why? I would expect the same results from each. I want to get the results in Java that the query console is returning. Am I writing the query definition in Java incorrectly?
It looks like the Java client wildcard search is searching the entire document even though I’ve specified that I only want to do a wildcard search inside of the given json-property (name.)
Is there a way to see or log the resultant server-side “cts query” given a client-side RawCombinedQueryDefinition? I'd like to see what the Java request gets translated into on the server side.
doc1.json
{
"state": "OH",
"city": "Dayton",
"notes": "not Cincinnati"
}
doc2.json
{
"state": "OH",
"city": "Cincinnati",
"notes": "real city"
}
doc3.json
{
"state": "OH",
"city": "Daytona",
"notes": "this is a made up city"
}
Query console code used to insert documents
xquery version "1.0-ml";
xdmp:document-load("/some/path/doc1.json",
<options xmlns="xdmp:document-load">
<uri>/doc1.json</uri>
</options>
);
Query console code used to search
xquery version "1.0-ml";
cts:search(fn:collection(),
cts:and-query((
cts:json-property-value-query("state", "OH"),
cts:json-property-value-query("city", "*Cincinnati*")
))
)
Java QueryManager query in easy to read text
{
"search": {
"query": {
"queries": [
{
"value-query": {
"type": "string",
"json-property": "state",
"text": "OH"
}
},
{
"value-query": {
"type": "string",
"json-property": "city",
"text": "*Cincinnati*"
}
}
]
}
}
}
Java code
import com.marklogic.client.DatabaseClient;
import com.marklogic.client.DatabaseClientFactory;
import com.marklogic.client.document.DocumentPage;
import com.marklogic.client.document.DocumentRecord;
import com.marklogic.client.document.JSONDocumentManager;
import com.marklogic.client.io.Format;
import com.marklogic.client.io.StringHandle;
import com.marklogic.client.query.QueryManager;
import com.marklogic.client.query.RawCombinedQueryDefinition;
import org.junit.Test;
public class MarkLogicTest
{
#Test
public void testWildcardSearch()
{
DatabaseClientFactory.SecurityContext securityContext = new DatabaseClientFactory.DigestAuthContext("admin", "admin");
DatabaseClient client = DatabaseClientFactory.newClient("localhost", 8000, "test", securityContext);
QueryManager queryManager = client.newQueryManager();
JSONDocumentManager documentManager = client.newJSONDocumentManager();
String query = "{\n" +
" \"search\": {\n" +
" \"query\": {\n" +
" \"queries\": [\n" +
" {\n" +
" \"value-query\": {\n" +
" \"type\": \"string\",\n" +
" \"json-property\": \"state\",\n" +
" \"text\": \"OH\"\n" +
" }\n" +
" },\n" +
" {\n" +
" \"value-query\": {\n" +
" \"type\": \"string\",\n" +
" \"json-property\": \"city\",\n" +
" \"text\": \"*Cincinnati*\"\n" +
" }\n" +
" }\n" +
" ]\n" +
" }\n" +
" }\n" +
"}";
StringHandle queryHandle = new StringHandle(query).withFormat(Format.JSON);
RawCombinedQueryDefinition queryDef = queryManager.newRawCombinedQueryDefinition(queryHandle);
DocumentPage documents = documentManager.search(queryDef, 1);
while (documents.hasNext())
{
DocumentRecord document = documents.next();
StringHandle resultHandle = document.getContent(new StringHandle());
String result = resultHandle.get();
System.out.println(result);
}
}
}
System.out.println() results
{"state":"OH", "city":"Dayton", "notes":"not Cincinnati"}
{"state":"OH", "city":"Cincinnati", "notes":"real city"}
Why does the Java client return the first result where city = Dayton?
Thanks in advance!
The REST API and thus the Java API executes an unfiltered search by default (meaning, the matches are based entirely on the indexes). By contrast, cts:search() executes a filtered search by default (meaning, the result documents are inspected to throw out false positives).
If you add the "unfiltered" option to cts:search(), it also returns both documents.
The quick fix is to add the "filtered" option to the Java API search, but the better fix for performance at scale is to refine the indexes to support exact matching for the required wildcard queries.
Elements are correlated with wildcards based on position.
Thus, for this query, I believe you need to turn on the index configurations for element word positions and for three character word positions.
Hoping that helps,
From a quick look at the above code, You do not have the AND query in your java example. Therefore it is an or-query fo Ohio OR Cincinnati.

VelocyPack VPackParser returns null _key from toJson method

I have the following document in a collection named test:
[
{
"_key": "2469",
"_id": "test/2469",
"_rev": "_Ujegqfu---",
"fieldName": "some value"
}
]
I'm retrieving this with the following two methods:
public Result helloWorldJson() {
ArangoDB db = new ArangoDB.Builder().user("<user>").password("<pass>").build();
VPackParser parser = new VPackParser() ;
VPackSlice slice = db.db("<db>").collection("test").getDocument("2469", VPackSlice.class);
String json = db.db("cms").collection("test").getDocument("2469", String.class);
return Results.text().render("{velocy: " + parser.toJson(slice, true) + ", json: " + json);
}
Which produces this output:
{velocy: {"_key":"2469","_id":null,"_rev":"_Ujegqfu---","fieldName":"some value"}, json: {"_key":"2469","_id":"test\/2469","_rev":"_Ujegqfu---","fieldName":"some value"}
Does the VPackParser leave the _id null on purpose or am I missing something?
The _id field in stored documents is from a special velocypack type which isn't supported by Json and inlcudes the collection-id, the document is stored in.
To correctly deserialize this field in the human readable "collection-name/document-key" the deserialization process needs to know the collection-name of the given collection-id. This is only possible if the process can call the database or the internal collection-cache of the java-driver. Only when you call getDocument(String,Type) or another API method the deserialization process has access to this. VPackParser is a standalone Velocypack<->Json parser which isn't able to resolve the field _id.
String json = db.db("cms").collection("test").getDocument("2469", String.class);
As in your call, when you set type to String the method toJson() on an instance of VPackParser is used which has access to the dabase and the collection-cache and so can correctly desialize the field _id when parsing the velocypack to json.
If you want to deserialize a Velocypack separately from an api call (with correct parsing of _id) you can use the class ArangoUtil which you get from the method util() on ArangoDB,ArangoDatabase or ArangoCollection.
VPackSlice slice = db.db("<db>").collection("test").getDocument("2469", VPackSlice.class);
String json = db.util().deserialize(slice, String.class);

Jackson - Variable key

I'm facing a little problem, I think some workaround can be find but I'm searching for the proper way to do it.
I use Selenium with Grid, and then I configure all my nodes with JSON files. Some browsers (Chrome, IE) needs specific drivers.
These drivers are defined by a key of that form: webdriver.browser.driver with browser = chrome or ie. So, we've got for example:
{"browserName": "chrome",
"maxInstances": 5,
"platform": "WINDOWS",
"webdriver.chrome.driver": "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe" }
{"browserName": "internet explorer",
"maxInstances": 1,
"platform": "WINDOWS",
"webdriver.ie.driver": "C:/Program Files (x86)/Internet Explorer/iexplore.exe" }
I want to get the value and put it in: private String driverPath of my POJO.
Is there a way to get the value of the key dynamically? Like a regex?
Conceptually speaking, in both of your objects, the attributes "webdriver.chrome.driver" and "webdriver.ie.driver" represents the same entity: the driver, so the attribute should just be called driver.
Usually a POJO <-> JSON conversion is intended to be one to one, so one Java field per JSON field.
If you cannot change the JSON or you feel that you need them to be like they are right now, at least in Jackson and GSON, you can register a Custom Deserializer and manually make the parsing for that value.
You can see examples here: http://www.baeldung.com/jackson-deserialization
Parse it as a List, for example using jackson:
List<Map> list = (List<Map>) new ObjectMapper().readValue(json, List.class);
Here's some working code:
String json = "[{\"browserName\": \"chrome\", \"maxInstances\": 5,\n \"platform\": \"WINDOWS\",\n" +
" \"webdriver.chrome.driver\": \"C:/Program Files (x86)/Google/Chrome/Application/chrome.exe\" }," +
"{\"browserName\": \"internet explorer\", \"maxInstances\": 1," +
" \"platform\": \"WINDOWS\", \"webdriver.ie.driver\": \"C:/Program Files (x86)/Internet Explorer/iexplore.exe\" }]";
List<Map> list = (List<Map>) new ObjectMapper().readValue(json, List.class);
String browser = "chrome";
String driver = list.stream()
.<String>map(m -> (String) m.get("webdriver." + browser + ".driver"))
.filter(s -> s != null)
.findFirst()
.orElse(null); // C:/Program Files (x86)/Google/Chrome/Application/chrome.exe
driver will be null if not found

Categories

Resources