I want to serialize my java data classes to JSON. To be honest, I posted a relevant question few days ago, however I haven't got my answer so far. At the moment, all answers suggest the Jackson's annotations. But I prefer not to get the classes involved directly and I think it's better that delegate this work to views.
Nevertheless, I found out that SpringMVC supports GroovyTemplate and I've a pleasant experience to deal with Groovy templating and builders and so I've a good sense about them. But I could find Groovy templates to build only html files. All of the examples begin with similar lines like this:
html {
head {
title( ... )
...
}
}
Is there any way to write Groovy template in context of SpringMVC that provide JSON? For example, something like Grails JSON views known as gson files(see this).
I appreciate all for paying attention.
Groovy itself has good functionality to produce json.
Your classes can be easily converted into json:
import groovy.json.*
class SomeClass{
String name
int value
List someList = ['value1', 'value2', 'value3']
}
assert JsonOutput.toJson(new SomeClass(name:'myClass', value: 3)) ==
'{"value":3,"someList":["value1","value2","value3"],"name":"myClass"}'
it is also easy to create your own template engine.
For example:
def SOME_CLASS_TEMPLATE = {SomeClass someClass->
[
the_json:[
message: 'Message',
name: someClass.name,
first_list_value: someClass.someList?.getAt(0)
]
]
}
assert JsonOutput.toJson(SOME_CLASS_TEMPLATE(new SomeClass(name:'myClass', value: 3))) ==
'{"the_json":{"message":"Message","name":"myClass","first_list_value":"value1"}}'
formatted json output:
assert JsonOutput.prettyPrint(JsonOutput.toJson(SOME_CLASS_TEMPLATE(new SomeClass(name:'myClass', value: 3)))) ==
'''{
"the_json": {
"message": "Message",
"name": "myClass",
"first_list_value": "value1"
}
}'''
Also check other classes from groovy.json package (JsonGenerator, JsonBuilder) they may be more preferable for your tasks.
Related
I have a JSON which has an attribute with its List type. Can someone help me on how to read the value in Apache Velocity template? Following is an example of JSON. The challenge is to read the list of University from JSON and iterate through it.
{
"StudentName":"XYZ",
"List<Univesity>": [
{
"Name": "NYU",
"City": "NY",
"Country":"US",
} ]
}
The solution is dependent upon the JSON library you use, but for many of them, the following code should work:
#set( $universities = $document.get('List<University>') )
#foreach( $university in $universities )
... do something ...
#end
The main point to note here is that you can call any Java method on the object you get.
Also, if the security uberspector is not present, for debugging purposes you can display the Java class name of any object in the context, for instance: $document.class.name should display, in your case, something like com.fasterxml.jackson.databind.node.ObjectNode.
I have an API endpoint which, when called with GET, returns an array of JSON objects in the body, like this:
[
{"id": "321", "created": "2019-03-01", "updated": "2019-03-15"},
{"id": "123", "created": "2019-03-02", "updated": "2019-03-16"}
]
I would like to check the body with a Spring MockMvc test case.
The statement currently looks like this:
mockMvc.perform(get("/myapi/v1/goodstuff").
andExpect(status().isOk()).
andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)).
andExpect(jsonPath("$.*", isA(ArrayList.class))).
andExpect(jsonPath("$.*", hasSize(2))).
andExpect(jsonPath("$[0].id", is("321"))).
andExpect(jsonPath("$[0].created", is("2019-03-01"))).
andExpect(jsonPath("$[0].updated*", is("2019-03-15"))).
andExpect(jsonPath("$[1].id", is("1232"))).
andExpect(jsonPath("$[1].created", is("2019-03-02"))).
andExpect(jsonPath("$[1].updated*", is("2019-03-16")));
However, the implementation of my API doesn't guarantee the order of JSON object in the returned array.
Were this an array of strings, I would solve this via matcher generated by org.hamcrest.collection.IsIterableContainingInAnyOrder<T>.containsInAnyOrder.
But I cannot see any suitable matcher for my situation in their doc, nor any clue in the description of jsonPath method in Spring docs
From a quick search I didn't manage find anything related to my situation on SO, either, beyond a list of strings situation I described above.
Of course, I could convert JSON objects to strings.
But I'm wondering, could I solve this problem for a list of JSON objects, comparing each of the fields of each objects one-by-one (like shown in the code snippet above), but ignoring the order of objects in the collection?
Update: Zgurskyi has suggested a solution that helps with my original simplified example. However, with a real-life practical example there are 2 more inputs:
the number of fields is 10-20 instead of 3
not all of matchers are plain is, for instance:
(a bit closer to my original code)
mockMvc.perform(get("/myapi/v1/greatstuff").
andExpect(status().isOk()).
andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)).
andExpect(jsonPath("$.*", isA(ArrayList.class))).
andExpect(jsonPath("$.*", hasSize(2))).
andExpect(jsonPath("$[0].id", is("321"))).
andExpect(jsonPath("$[0].did", anything())).
andExpect(jsonPath("$[0].createdTs", startsWith("2019-03-01"))).
andExpect(jsonPath("$[0].updatedTs", startsWith("2019-03-15"))).
andExpect(jsonPath("$[0].name", equalToIgnoringCase("wat"))).
andExpect(jsonPath("$[0].stringValues", containsInAnyOrder("a","b","c"))).
andExpect(jsonPath("$[1].id", is("1232"))).
andExpect(jsonPath("$[1].did", anything())).
andExpect(jsonPath("$[1].createdTs", startsWith("2019-03-01"))).
andExpect(jsonPath("$[1].updatedTs", startsWith("2019-03-15"))).
andExpect(jsonPath("$[1].name", equalToIgnoringCase("taw"))).
andExpect(jsonPath("$[1].stringValues", containsInAnyOrder("d","e","f"))).
andReturn();
So far it seems that I can't do anything better than implementing my own matcher class.
Or...can I?
You can assert list items fields ignoring order:
.andExpect(jsonPath("$[*].id", containsInAnyOrder("321", "123")))
.andExpect(jsonPath("$[*].created", containsInAnyOrder("2019-03-01", "2019-03-02")))
.andExpect(jsonPath("$[*].updated", containsInAnyOrder("2019-03-15", "2019-03-16")))
Another approach would be to check that specific list items exist in response:
.andExpect(jsonPath("$.[?(#.id == 123 && #.created == \"2019-03-02\" && #.updated == \"2019-03-16\")]").exists())
.andExpect(jsonPath("$.[?(#.id == 321 && #.created == \"2019-03-01\" && #.updated == \"2019-03-15\")]").exists())
Additionally there is another way to assert the json without being strict about order using MockMvcResultMatchers
.andExpect(MockMvcResultMatchers.content().json(<json-here>, false))
By setting the strict=false, it can do a fussy search.
I think a better solution could be something like that:
.andExpect(jsonPath("$.violations", hasSize(3)))
.andExpect(jsonPath("$.violations", containsInAnyOrder(
Map.of("field", "name", "message", "must not be empty"),
Map.of("field", "email", "message", "must not be empty"),
Map.of("field", "birthdate", "message", "must not be null")
)
))
It worked for me, but I have to be honest, I don't like to use Map instead a domain type, like Violation, Tuple, Category etc. Unfortunately, I could not make it work with a type different than Map.
Since my very first days of Java + JSON I tried to extract just some certain parts of a JSON.
But no matter if which of the libraries I used:
Gson
json-simple
javax.json
it never was possible to make it quick and comfortable. Mostly for easy task or even prototyping. It already cost me many hours of different approaches.
Going trough the hierarchy of an JSON
Object jsonObject = gson.fromJson(output, Object.class);
JsonElement jsonTree = gson.toJsonTree(jsonObject);
JsonArray commitList = jsonTree.getAsJsonArray();
JsonElement firstElement = commitList.get(0);
JsonObject firstElementObj = firstElement.getAsJsonObject();
System.out.println(firstElementObj.get("sha"));
JsonElement fileList = firstElementObj.get("files");
This is dirty code for a reason. It shows how many early approaches looks like and how many people cannot achieve it to do it better early.
Deserializing JSON to a Java Object
Your have to analyse the complete JSON to create an complete Java-Object representation just to get access to some single memebers of it. This is a way I never wanted to do for prototyping
JSON is an easy format. But using libraries like that is quite difficult and often an problem for beginner. I've found several different answers via Google and even StackOverflow. But most were quite big larged which required to create a own specific class for the whole JSON-Object.
What is the best approach to make it more beginner-friendly?
or
What is the best beginner-friendly approach?
Using Jackson (which you tagged), you can use JsonPointer expressions to navigate through a tree object:
ObjectMapper mapper = new ObjectMapper();
JsonNode tree = mapper
.readTree("[ { \"sha\": \"foo\", \"files\": [ { \"sha\": \"bar\" }, { \"sha\": \"quux\" } ] } ]");
System.out.println(tree.at("/0/sha").asText());
for (JsonNode file : tree.at("/0/files")) {
System.out.println(file.get("sha").asText());
}
You could also use the ObjectMapper to convert just parts of a tree to your model objects, if you want to start using that:
for (JsonNode fileNode : tree.at("/0/files")) {
FileInfo fileInfo = mapper.convertValue(fileNode, FileInfo.class);
System.out.println(fileInfo.sha);
}
If your target class (FileInfo) specifies to ignore unknown properties (annotate target class with #JsonIgnoreProperties(ignoreUnknown = true) or disable DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES on the mapper), then you can simply declare the properties you are interested in.
"Best" is whatever works to get you going.
Generate Plain Old Java Objects from JSON or JSON-Schema
One little helper I found via my research was an Online-Tool like
http://www.jsonschema2pojo.org/
This is a little help, when you know about that. But the negative side I mentioned at point 2 is still there.
You can use JsonSurfer to selectively extract value or object from big json with streaming JsonPath processor.
JsonSurfer jsonSurfer = JsonSurfer.gson();
System.out.println(jsonSurfer.collectOne(json, "$[0].sha"));
System.out.println(jsonSurfer.collectOne(json, "$[0].files"));
I am working on a Spring MVC and I want to insert javascript into the html output for analytics purpose. I am only partially familiar with serialization but I figured it does the job nicely rather than manually constructing a string containing javascript.
Would it be possible to generate something the following snippet? Any pointers would be great!
"emd" : new Date('6/6/2014')
Update:
I need to output a javascript object which has many fields which may be complex. Hence, on the backend I am gathering all the data into java beans with all the information and I plan to use Jackson mapper to convert to string that I can just output through JSP.
Generating the above snippet does not seem straightforward though, not sure if it is even possible. For context, the rest of that javascript looks something like this.
Analytics.items["item_123"] = {
//ratings and reviews
"rat" : a.b, //the decimal value for the rating
"rev" : xxxx, //integer
//list of flags that indicate how the product was displayed to the customer
//add as needed...tracking code will pick up flags as needed when they are available
"dec" : ["mbe", "green", "recycled"],
//delivery messaging
"delivery" : {
"cd" : new Date() //current date
"offers" : [{
"type" : "abcd"
"emd" : new Date('6/6/2014'),
"weekend" : true
}
]
},
};
JSON.stringify should do the trick. It will be built into your browser, unless you're using a very old browser, in which case you can use a polyfill.
I am planning to implement a JavaScript parser in java. I know that there are several ways to do it. There are view frameworks/engines/parsers which could help to do it right, like:
ANTLR 3/4:
it seems like there is only a js grammer for v3
Mozilla Rhino: atm i can parse variable names on initital (top-) namespace. but i am not able to parse nested scopes e.g. object members.. hm..
Nashorn: maybe i should give it a try..?
Maybe:
closure-compiler: IMHO this is very nice. but not for "non-google" js-code :) e.g. you have to apply several coding conventions to your javascript sources to get it working properly..
maybe it is possible to adapt Packer to do it? Is there a Java implementation of Packer???
There is EcmaScript 5.1 related to this article. it seems to be very comfortable. But this is not exactly what I´am looking for.. And still no java :)
My question is:
What could/would be the best way to parse JavaScript for:
(object-)function names
(object-)member names e.g. variables
Is it even possible to do it?
What would be your approach? For me it is not essential to parse ALL special markups of JavaScript.. The important factor would be to parse function/variables in a consistent context for the typical markups like this:
// Avoid `console` errors in browsers that lack a console.
function Object() {
var method;
var noop = function() {
};
var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];
var length = methods.length;
var console = (window.console = window.console || {});
while (length--) {
method = methods[length];
// Only stub undefined methods.
if (!console[method]) {
console[method] = noop;
}
}
};
var obj = new Object();
var test = "Hello World";
The parse should be able to deliver this information:
Node: Object
Node: Object.method
Node: Object.noop
Node: Object.length
Node: Object.console
Node: Object
Node: obj
Node: test
There is no direct need of any determination if the node is a function/variable.