How to consider JSON structure when write into file - java

I want to save the entities in our program into .json files to get a better connection between backend and our Angular frontend. For this, I wrote some tests and during the execution, the structure is saved in the files as desired.
The structure is sampled by
ObjectMapper objectMapper = new ObjectMapper();
try{
ObjectWriter writer = objectMapper.wrtier(new DefaultPrettyPrinter());
String result = objectMapper.writerWirthDefaultPrettyPrinter().writeValueAsString(new OurObject());
writer.writerValue(new File("path"), result);
}
What I got
"{\r\n \"firstProp\": something,\r\n \"secondProp\": anything,\r\n...
But I want, that the file contains the classical JSON structure to make it better readable, this means:
{
"firstProp": something,
"secondProp": anything,
...
What can I do, to write it in the desired JSON structure?
Thanks for any help
Matthias

You're double-encoding the json string
Remove writeValueAsString and try to directly use writer.writerValue(file, object)
But if you're emitting this from a Java backend, it's typically best practice to serve it from an HTTP request, not as a file to any front-end

Related

Missing part in MultipartFormDataOutput depending on order of keys

I have a Java REST endpoint which should return a multipart response with a json document and a pdf file. I chose "form-data" and not "mixed" because I want to assign a name to the parts in case I have multiple different json or file parts in the future.
The problem: In the output, the parts seem to be sorted depending on the key I specify, which makes sense, since formDataMap of MultipartFormDataOutput is a HashMap. If the json part is first, everything works as it should. BUT if the file part is sorted first, then the json part is missing in the output, as well as the form-data boundary at the end.
I feel I've tried every possible variation by switching out media types, response types, annotations, trying different pdf files, etc but nothing seems to help.
Does anyone have an idea how to explain this behavior? Any help is welcome, thanks!
#POST
#Path("test")
#Consumes(MediaType.APPLICATION_JSON)
#Produces("multipart/form-data")
public Response test(MyObject o)
{
// process input and get the byte arrays for the json document and pdf file
var output = new MultipartFormDataOutput();
output.addFormData("foo.json", new ByteArrayInputStream(myJsonByteArray), MediaType.APPLICATION_JSON_TYPE.withCharset("UTF-8"), "foo.json");
output.addFormData("document.pdf", new ByteArrayInputStream(myPdfByteArray), MediaType.valueOf("application/pdf"), "document.pdf");
return Response.ok(output).build();
}
I'm on Quarkus 1.13.7 with Resteasy 4.5.12
Not sure if this helps, but try wrapping MultipartFormDataOutput with GenericEntity before returning.
GenericEntity<MultipartFormDataOutput> outputGen = new GenericEntity<MultipartFormDataOutput>(output) {};
return Response.ok(outputGen).build();

How to Embed and Bind JSON Data to HTML Template in Java Web Service

I am working on a Java PDF Generation micro service using spring boot. The pdf generation is meant to be a 2 stage process.
Templating - html template with some sort of expression language, which reads a json structure directly
HTML to PDF - this generates a pdf from the html produced in step 1
Note: I have some java and JavaScript (nunjucks/nodejs) solution for steps 1 and 2, but I really need a more maintainable approach as follows.
My restful endpoint will take 2 parameters an html template and a json
The json structure maps to the html template one to one and both files have been predefined to strict contract.
The service endpoint should not do any object mapping of json data to html Dom elements e.g. table, rows, etc
The endpoint only embeds the json data to the html using logic in java code
The html gets executed/rendered and reads the json directly using some sort of expression language, since it contains the json structure
The endpoint then response with an html with the dynamic data, which can be sent to the pdf generator web service endpoint
Below is a sample code:
#POST
#Path("createPdf")
public Response createPdf(String htmlTemplateParam, String json) {
//Read template from endpoint param or start off with reading local html template from resource folder
String templateHtml = IOUtils.toString(getClass().getResourceAsStream(HTMLTemplateFiles.INCOMING_TEMPLATE));
RequestJson requestJson = [Prepare json before passing to HTML Template]];
if(requestJson.isContentValid()) {
LOG.info("incoming data successfully validated");
// TODO
// Pass the requestJson (Endpoint Param JSON ) to templateHtml
// Trigger the reading of the Json data and populating different HTML DOM elements using some sort of expression predefined in HTML
// Get hold of the rendered HTML
String resolvedHtml = [HTML with data from json param into endpoint];
// The next bit is done
String pdf = htmlToPdfaHandler.generatePdfFromHtml(resolvedHtml);
javax.ws.rs.core.Response response = Response.ok().entity(Base64.decodeBase64(pdf)).build();
}
}
The templating stage one is where I need help.
Please, what is the best technical solution for this?
I am comfortable with Java and JavaScript framework and happy to learn any framework you suggest.
But, my main design goal is to ensure that as we have new templates and a template and data changes, a non-techie can change html/json and generate pdf.
Also, no java code changes should be required for template and data changes.
There are a few things in my head like jsonpath, thyme leaf, JavaScript, etc But, I love best practice and like to learn from someone with the real-life experience of similar use case.
After further research and first answer I am also thinking of the freemarker solution below.
But, how would I create a free marker template-data auto-magically from reading input json.i.e. without creating POJO/DTO?
Based on first answer :
Configuration cfg = new Configuration(new Version("2.3.23"));
cfg.setDefaultEncoding("UTF-8");
// Loading you HTML template (via file or input stream):
Template template = cfg.getTemplate("template.html");
// Will this suffice for all JSON Structure, including nested deep ones
Type mapType = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, String[]> templateData = new Gson().fromJson(json, mapType);
try (StringWriter out = new StringWriter()) {
// In output stream the result will be template with values from map:
template.process(templateData, out);
System.out.println(out.getBuffer().toString());
out.flush();
}
Thanks in advance.
NOTE: Code snippets, pseudo code, references are welcomed.
One of the options might be FreeMarker usage:
Configuration cfg = new Configuration(new Version("2.3.23"));
cfg.setDefaultEncoding("UTF-8");
// Loading you HTML template (via file or input stream):
Template template = cfg.getTemplate("template.html");
// You need convert json to map of parameters (key-value):
Map<String, Object> templateData = new HashMap<>();
templateData.put("msg", "Today is a beautiful day");
try (StringWriter out = new StringWriter()) {
// In output stream the result will be template with values from map:
template.process(templateData, out);
System.out.println(out.getBuffer().toString());
out.flush();
}

Converting JSON file to string in RestAssured (Java)

I'm using IntelliJ to learn RestAssured; this is completely new territory for me. I have a simple .json file in place and I want to have a API Response to assert if it's the same as the mentioned .json file.
Basically: If the output of the call equals what I have in the json file, it's all good.
I used the demo restapi.demoqa.com for quick reference. This is what I have right now:
#Test
public void ComparewithJSONinResources()
{
String CityResponse = ?????
RestAssured.baseURI = "http://restapi.demoqa.com/utilities/weather/city";
RequestSpecification httpRequest = RestAssured.given();
Response response = httpRequest.request(Method.GET, "/Hyderabad");
String responseBody = response.getBody().asString();
System.out.println(responseBody);
Assert.assertTrue(responseBody.equals(CityResponse));
response.body();
}
I have the .json file in place called CityResponse.json. For easy reference, say on the location c:/CityResponse.
Is it possible to convert the Json file to a string to assert that the API and the JSON are equal?
Comparing JSON as String will never give accurate results, as you will possibly see inconsistency in space, tabs (indentation), property (key-value pair) sequencing etc. Your best bet is to parse JSON into POJO using one of the many popular libraries (Ex. Jackson, GSON etc). And this deserialization you need for both RestAssured Http response & one you are reading from .json file, and once you have two java objects, use standard Java comparision by overriding equals method.

Alternatives to JSON-object binding in Android application

From my Android application I need to use a RESTful web service that returns me a list of objects in json format.
This list can be very long (about 1000/2000 object.).
What I need to do is to search and retrive just some of the objects inside the json file.
Due to the limited memory of mobile device, I was thinking that using object-binding (using for example GSON library) can be dangerous.
Which are the alternatives for solving this problem?
If you are using gson, use gson streaming.
I've added the sample from the link and added my comment inside of it:
public List<Message> readJsonStream(InputStream in) throws IOException {
JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
List<Message> messages = new ArrayList<Message>();
reader.beginArray();
while (reader.hasNext()) {
Message message = gson.fromJson(reader, Message.class);
// TODO : write an if statement
if(someCase) {
messages.add(message);
// if you want to use less memory, don't add the objects into an array.
// write them to the disk (i.e. use sql lite, shared preferences or a file...) and
// and retrieve them when you need.
}
}
reader.endArray();
reader.close();
return messages;
}
For example
1) Read the list as a stream and handle the single JSON entities on the fly and save only those that are of interest to you
2) Read the data into String object/objects and then find the JSON entities and handle them one by one instead of everything at the same time. Ways to analyse the String for JSON structures include regular expressions or manual indexOf combined with substring -type analysis.
1) is more efficient but requires a bit more work as you have to handle the stream at the same time where as 2) is probably more simple but it requires you to use quite a big Strings as temporary means.

Formatting JSON before writing to File

Currently I'm using the Jackson JSON Processor to write preference data and whatnot to files mainly because I want advanced users to be able to modify/backup this data. Jackson is awesome for this because its incredibly easy to use and, apparently performs decently (see here), however the only problem I seem to be having with it is when I run myObjectMapper.writeValue(myFile, myJsonObjectNode) it writes all of the data in the ObjectNode to one line. What I would like to do is to format the JSON into a more user friendly format.
For example, if I pass a simple json tree to it, it will write the following:
{"testArray":[1,2,3,{"testObject":true}], "anotherObject":{"A":"b","C":"d"}, "string1":"i'm a string", "int1": 5092348315}
I would want it to show up in the file as:
{
"testArray": [
1,
2,
3,
{
"testObject": true
}
],
"anotherObject": {
"A": "b",
"C": "d"
},
"string1": "i'm a string",
"int1": 5092348315
}
Is anyone aware of a way I could do this with Jackson, or do I have to get the String of JSON from Jackson and use another third party lib to format it?
Thanks in advance!
try creating Object Writer like this
ObjectWriter writer = mapper.defaultPrettyPrintingWriter();
You need to configure the mapper beforehand as follows:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
mapper.writeValue(myFile, myJsonObjectNode);
As per above mentioned comments this worked for me very well,
Object json = mapper.readValue(content, Object.class);
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(json);
Where content is your JSON string response
Jackson version:2.12
To enable standard indentation in Jackson 2.0.2 and above use the following:
ObjectMapper myObjectMapper = new ObjectMapper();
myObjectMapper.enable(SerializationFeature.INDENT_OUTPUT);
myObjectMapper.writeValue(myFile, myJsonObjectNode)
source:https://github.com/FasterXML/jackson-databind

Categories

Resources