JSON variable substitution placeholders - java

I'm looking for a Java library that can do variable substitution when marshaling Json to an Object on-the-fly.
For example, the Json template would have variable substitution sites/placeholders like:
{
"User": {
"Name": "${name}",
"Age": ${age}
}
}
that would result in the Java Object representing the following once marshaled:
{
"User": {
"Name": "Elvis",
"Age": 80
}
}
What I want is something along the lines of this:
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(new File("c:\\user.json.template"), User.class, "Elvis", 80);

This is really out of scope for JSON libraries, since JSON format itself has no support or notion of variable substitution. Your best bet may be to use a JSON library (like Jackson) to get a tree representation (for Jackson that would be JsonNode), then traverse it, and use another library for handling textual substitution. There are many that can do that, from stringtemplate to others (perhaps MessageFormat that other answer refers to).
It may also be possible to revert the other, if your substitutions will never funny "funny characters" (quotes, linefeeds); if so, you could use string templating lib first, JSON parser next feeding processed text.
But it is bit riskier, as usually there is eventually one case where you do end up trying to add a quote, say, and then parsing fails.

You can use a template engine such as Apache Velocity to preprocess the input stream, and then parse the result with a JSON parser. To make the process "on-the-fly", you can run Velocity in a separate thread, and let it write it's output to a PipedOutputStream.

May be the MessageFormat object from apache commons could help ?
Here is an example : http://examples.javacodegeeks.com/core-java/text/messageformat/java-messageformat-example/

Related

How to serialize a Java Map to PHP's array serialization format

I want to convert HashMap to a String, which corresponds to PHP's Array serialization format as described here:
http://php.net/manual/en/function.serialize.php
For example:
a:5:{s:5:"width";i:450;s:6:"height";i:352;s:4:"file";s:32:"2018/09/Sawtooth-Oak_450_a-1.jpg";s:5:"sizes";a:9:{s:9:"thumbnail";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-150x150.jpg";s:5:"width";i:150;s:6:"height";i:150;s:9:"mime-type";s:10:"image/jpeg";}s:6:"medium";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-300x235.jpg";s:5:"width";i:300;s:6:"height";i:235;s:9:"mime-type";s:10:"image/jpeg";}s:32:"twentyseventeen-thumbnail-avatar";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-100x100.jpg";s:5:"width";i:100;s:6:"height";i:100;s:9:"mime-type";s:10:"image/jpeg";}s:21:"woocommerce_thumbnail";a:5:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-250x250.jpg";s:5:"width";i:250;s:6:"height";i:250;s:9:"mime-type";s:10:"image/jpeg";s:9:"uncropped";b:1;}s:18:"woocommerce_single";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-350x274.jpg";s:5:"width";i:350;s:6:"height";i:274;s:9:"mime-type";s:10:"image/jpeg";}s:29:"woocommerce_gallery_thumbnail";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-100x100.jpg";s:5:"width";i:100;s:6:"height";i:100;s:9:"mime-type";s:10:"image/jpeg";}s:12:"shop_catalog";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-250x250.jpg";s:5:"width";i:250;s:6:"height";i:250;s:9:"mime-type";s:10:"image/jpeg";}s:11:"shop_single";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-350x274.jpg";s:5:"width";i:350;s:6:"height";i:274;s:9:"mime-type";s:10:"image/jpeg";}s:14:"shop_thumbnail";a:4:{s:4:"file";s:32:"Sawtooth-Oak_450_a-1-100x100.jpg";s:5:"width";i:100;s:6:"height";i:100;s:9:"mime-type";s:10:"image/jpeg";}}s:10:"image_meta";a:12:{s:8:"aperture";s:1:"0";s:6:"credit";s:0:"";s:6:"camera";s:0:"";s:7:"caption";s:0:"";s:17:"created_timestamp";s:1:"0";s:9:"copyright";s:0:"";s:12:"focal_length";s:1:"0";s:3:"iso";s:1:"0";s:13:"shutter_speed";s:1:"0";s:5:"title";s:0:"";s:11:"orientation";s:1:"0";s:8:"keywords";a:0:{}}}
I've started with the following test Map:
HashMap images2 = new HashMap();
images2.put("test1", "t1");
imagesArray.put("width", image.getWidth());
imagesArray.put("height", image.getHeight());
imagesArray.put("file", destinationFile);
imagesArray.put("sizes", images2);
String jsonResult = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(imageMap);
System.out.println(jsonResult);
and the reasult is:
{
"file" : "/images/bolivia.jpg",
"sizes" : {
"test1" : "t1"
},
"width" : 450,
"height" : 450
}
Java does not use PHP's array serialization format so you have to write it yourself or change approach. You have the following options:
Iterate through the entries of your Map and for each entry output its type, s for String, i for int etc. together with the rest of the information (a String includes the length etc.)
From your PHP script, change approach and instead of reading PHP's array serialization use JSON. This is more of an open defacto standard, and you will be able to use other programming languages too since most languages support JSON or have easy libraries to do so these days.
Use a library which saves Java objects to PHP's serialization format. I would only recommend this option if you have no control on the PHP script and you absolutely cannot change it without breaking something else. If you do not own the PHP code, or you cannot maintain it effectively it may be a viable option. Do a quick search for Java libraries that do this such as this one:
https://github.com/marcospassos/java-php-serializer
Ok, i found solution - i will use
<!-- https://mvnrepository.com/artifact/com.xk72/pherialize -->
<dependency>
<groupId>com.xk72</groupId>
<artifactId>pherialize</artifactId>
<version>1.2.4</version>
</dependency>
Consider using Google's protobufs (prototype buffers). Protobufs are implemented in several languages, including Java, PHP, Python, C++, and so on.
It has the advantage of language independence--you define the buffer structure and compile the definition file into the language(s) of your choice.
Here's a trivial example of a protobuf with 2 fields, just to give an idea:
syntax = "proto2";
message CookiejarTransaction {
optional string action = 1; // Action is either "bake" or "eat"
optional uint32 amount = 2; // Amount is number of cookies
}
Disclaimer: I have no interest in Protobufs other than a happy developer who uses the tool.
https://developers.google.com/protocol-buffers/

Will using Jackson input stream bring all contents into memory

I have a JSON (from stream). The data is huge. So I don't want to deserialize into a concrete Java Object. So I'm thinking to use Jackson parser.
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createJsonParser(stream);
My goal is to get specific sections from stream(specific properties from the object)
{
"array": [],
"map": {},
"bool": "true",
"string": "abcd"
}
For example: I want to get only the map or the array and so on
However my question is when I use inputstream and parse it( to get specific sections of the stream) will it(the entire JSON) be brought into the memory all at once?
What is the difference between this(parsing) way and deserializing it into an object(and then getting the specific members from the object)?
Of 3 major processing modes that Jackson supports, Streaming Processing (also known as Incremental Processing) is the most efficient way to process JSON content. It has the lowest memory and processing overhead, and can often match performance of many binary data formats available on Java platform (see "Performance Comparison" link below)
According to fasterxml documentation ( http://wiki.fasterxml.com/JacksonStreamingApi ), the JsonParser does not read all the stream in the memory. It only read the stream everytime it is needed.

How can I serialize a Java object to a escaped JSON string?

Is there a way to convert a Java object to a string like below?
Note that all the filed names should be escaped, and "\n" is used as to separate records.
{
"content":"{\"field1\":123, \"field2\":1, \"field3\":0, \"field4\":{\"sub1\":\"abc\", \"sub2\":\"xyz\"}}\n
{\"field1\":234, \"field2\":9, \"field3\":1, \"field4\":{\"sub1\":\"xyz\", \"sub2\":\"abc\"}}"
}
Thanks,
You can use GSON for that task.
Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of.
If you need to have a better readable representation, you may use the pretty-print feature.
Gson gson = new GsonBuilder().setPrettyPrinting().create();
To realize something like your example, you could in a first step serialize your content class, put the resulting string as a property in another class and serialize that one again.
That way GSON takes care of the escaping of ".
If you collect your strings in an array and use the pretty print option shown above, you get something similar to your line-break requirement, but not quite the exact same.
The result of the process described above may look like the following:
{
"content": [
"{\"field1\":123, \"field2\":1, \"field3\":0, \"field4\":{\"sub1\":\"abc\", \"sub2\":\"xyz\"}}",
"{\"field1\":234, \"field2\":9, \"field3\":1, \"field4\":{\"sub1\":\"xyz\", \"sub2\":\"abc\"}}"
]
}
Another alternative is to use the Json-lib library http://json-lib.sourceforge.net
String jsonStrData = " ....... ";
JSONObject jsonObj = JSONObject.fromObject(jsonStrData);
System.out.println(jsonObj);
Like GSON, json-lib handles escaping for you, more info on how to use it here http://json-lib.sourceforge.net/usage.html

How to parse a file in INI/JSON-like non-standard format?

Suppose I have a text file in the following (non-standard) format:
xxx { a = v1; b = v2 }
yyy { a = v3; c = v4 }
I cannot change it to any standard (INI/XML/YAML, etc.) format.
Now I would like to find the value of property a in section xxx (that is v1). What is the simplest way to do it in Java/Groovy?
With Groovy, you could leverage the ConfigSlurper.
However, you would first need to hack a map of valid values together, so that it doesn't choke trying to work out what v1, v2, v3, etc are:
This seems to work:
def input = '''xxx { a = v1; b = v2 }
|yyy { a = v3; c = v4 }'''.stripMargin()
def slurper = new ConfigSlurper()
// Find all words 'w' and make a map of [ w1:'w1', w2:'w2', ... ]
slurper.binding = ( ( input =~ /\w+/ ) as List ).collectEntries { w -> [ (w):w ] }
def result = slurper.parse( input )
println result
That prints out:
[xxx:[a:v1, b:v2], yyy:[a:v3, c:v4]]
(Groovy 1.8.4)
For a true INI-format file: What is the easiest way to parse an INI file in Java?
What you're showing here looks more like JSON than INI format to me. Perhaps look at JSON parsing libraries. The truth here is that you're not using an established format, so you probably won't be using an established format parser. Your best bet is probably to refactor the file you're dealing with (if possible) into a well-known format to begin with. Don't try to reinvent the wheel unless you absolutely have to.
There's likely not going to be an out-of-box solution if you're dealing with a non-standard format. Here's a few approaches you might want to look into:
if the format is simple, write a custom recursive descent parser
write a filter to transform your format into INI, JSON, etc. and use existing libraries
create a groovy DSL that matches your format and execute your file as a groovy script
use a parser generator tool like antlr or parboiled to create a parser from a language specification
Firstly, you've given an example, not specified a format. Before you go any further, you need to get hold of a complete specification for the format. Or if there isn't one, you need to see the code that generates it, and reverse engineer a specification.
(If you try to implement based on a small example, there's a good chance that your parser will encounter real life examples that don't fit the patterns that you have intuited.)
Having done that you can look for an off-the-shelf parser that can cope with your format. If you are lucky, it might be close enough to INI, or JSON or YAML or something else for the corresponding parser to (mostly) work.
But the chances are that it won't, and that you will need to write your own parser. There are various ways you could do this, for instance:
You could split the file into lines and "parse" each line with a regex.
You could parse the file using a Scanner with appropriate delimiters.
You could use a parser generator to implement a lexer and parser.
You could implement a simple lexer and parser by hand.
There are probably Groovy specific solutions.
In reality the correct choice(s) depend on how simple or complex the actual format is. We can't tell that from a single example.

JSON-lib escaping / preserving strings

I am using JSON-lib library for java http://json-lib.sourceforge.net
I just want to add simple string which can look like JSON (but i do not want library to automatically figure out that it might be json and just to treat it as string). Looking into source of library I can't find the way to do it without ugly hacks.
example:
JSONObject object = new JSONObject();
String chatMessageFromUser = "{\"dont\":\"treat it as json\"}";
object.put("myString", chatMessageFromUser);
object.toString() will give us {"myString":{"dont":"treat it as json"}}
and i want just to have {"myString":"{\"dont\":\"treat it as json\"}"}
How to achieve it without modifying source code ? I am using this piece of code as transport for chat messages from users - so it works OK for normal chat messages, but when user will enter JSON format as message it will break it because of default behavior of JSON-lib described here.
If I understand question correctly, I think json-lib is unique in its assumption of a String being passed needing to be parsed. Other libs typically treat it as String to include (with escaping of double-quotes and backslashes as necessary), i.e. work as you would expect.
So you may want to consider other libraries: I would recommend Jackson, Gson also works.
json-simple offers a JSONObject.escape() method.

Categories