In one of my past articles, I talked about my opensorce pet project useful-java-links , the idea of which is to collect as many links as possible to useful Java libraries and frameworks. He also has a Hello World project subproject whose idea for each library is to collect a few simple examples of its use.
The problem of programmers in the Java world is that in addition to the standard JDK library there are huge other useful libraries, and the transition from one library to another can cause problems due to incomplete documentation, the lack of simple examples or even the difficulty to understand what dependencies need to be added to maven so that everything runs . And in the new work they can easily use the one that you do not know instead of your favorite library. The idea of my project is to facilitate the study and selection of different libraries.
1. JPA and Hibernate in questions and answers
2. Three hundred fifty most popular non-mobile Java opensource projects on github
3. Java collections (standard, guava, apache, trove, gs-collections, and others)
4. Java Stream API
5. Two hundred and fifty Russian-language teaching videos of lectures and reports on Java.
6. List of useful links for Java programmer
7 Typical tasks
7.1 Optimum way to convert an InputStream to a string
7.2 The most productive way to bypass the Map, count the number of occurrences of the substring
8. Libraries for working with Json (Gson, Fastjson, LoganSquare, Jackson, JsonPath and others)
So let's see what famous libraries are there for working with JSON in Java ...
Quote from useful-java-links :
So, we have eight libraries for serialization and deserialization in json, two libraries for generating Java classes according to the scheme or json file, one library for validating the scheme and two XPath analogs, but for json. Let's look at each of them.
There are three main ways of serialization and deserialization among the specified libraries (from the simplest to the most complex) and one additional:
Let's consider what they eat with:
Data bind is the most popular and simplest way, you simply specify the class that needs to be converted to json, maybe some of the fields are annotated (and often even not necessary), and the library itself turns this class and its entire class hierarchy into json. Analog when working with xml is JAXB (Java Architecture for XML Binding)
Pros : the simplest of all, in fact, the main thing is to implement only Java classes, moreover, you can simply generate Java classes from a json or json schema.
Cons : speed and memory. Most libraries use reflection, etc. methods for working with Java classes (although not all), which is obviously not very fast. In addition, the entire json file is immediately converted to Java objects, which can simply exhaust all available memory if you try to process very large json.
Conclusion : if there are no problems with performance, memory and you are not going to handle multi-gigabyte json's most likely the best way.
Tree Model - this parser represents json in the form of Java classes such as Node or JsonElement with a hierarchical structure, and the programmer himself bypasses them and gets information from them. This method is similar to DOM parsers in xml.
Pros : usually faster than the first method and easier than the third,
Minuses : Data Bind is inferior in simplicity, plus a number of libraries are able to generate classes with Data bind , and not use reflection, in this case, the fact that the Tree Model will be faster is not obvious, and the problem of huge files and memory limitations are not solved.
Streaming API is the lowest-level method, in fact, the programmer himself manually parses the json'a tokens. But no restrictions on memory and in theory the maximum performance.
Pros : performance and minimum memory consumption,
Cons : difficulty of use,
$.store.book[*].author
expression $.store.book[*].author
and get a list of all the authors of all books from the json'a shop. That is easy to get some information from json'a.The way | Fastjson | Gson | Logan square | Json java | Moshi | Ig json parser | Jackson | Genson | Jsonpath |
---|---|---|---|---|---|---|---|---|---|
1. Data bind | Yes | Yes | Yes | - | Yes | Yes | Yes | Yes | - |
2. Tree Model | - | Yes | - | Yes | - | - | Yes | - | - |
3. Streaming API | - | Yes | - | - | - | - | Yes | - | - |
4. XPath Analogs | Yes | - | - | - | - | - | - | - | Yes |
5. Generating classes for Data bind * | - | - | Yes | - | - | Yes | - | - | - |
6. Github's star | 4851 | 4120 | 2188 | 1937 | 1732 | 921 | 881 | 108 | 849 |
7. Works with static inner class ** | Yes | Yes | Not | - | Yes | Not | Yes | Yes | - |
8. Mandatory annotations *** | Not | Not | Yes | - | Not | Yes | Not | Not | - |
By reference to Yes you can find examples of use.*
- Generation of classes for Data bind allows you to generate classes at the compilation stage, which in theory should give a significant increase in library performance,**
- Works with the static inner class only makes sense for the case of Data bind, is serialization and deserialization possible for the case of static inner classes (non-static inner classes are not recommended to be serialized),***
- also only for the case of Data bind, is it possible not to use annotations or their use is highly recommended,
To demonstrate the work of libraries, we will use the following json:
jsonString = { "message": "Hi", "place": { "name": "World" } }
And the following Java classes (in different examples they may differ slightly by the presence of annotations, if they are required):
class Human { private String message; private Place place; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public Place getPlace() { return place; } public void setPlace(Place place) { this.place = place; } public void say() { System.out.println(); System.out.println(getMessage() + " , " + getPlace().getName() + "!"); } } class Place { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
// init class Place place = new Place(); place.setName("World"); Human human = new Human(); human.setMessage("Hi"); human.setPlace(place);
As you can see, Java classes are only made up of two classes, Human and Place, in which the message Hi World! Is stored. Json also contains these two nested objects.
Examples of use (Data bind) : The way | Fastjson | Gson | Logan square | Moshi | Ig json parser | Jackson | Genson |
---|---|---|---|---|---|---|---|
Initialization | --- | Gson gson = new Gson() | --- | Moshi moshi = new Moshi. Builder().build(); JsonAdapter<Human> jsonAdapter = moshi.adapter(Human.class) | --- | ObjectMapper mapper = new ObjectMapper() | Genson genson = new Genson() |
Java to json | JSON.toJSONString(human) | gson.toJson(human) | LoganSquare.serialize(human) | jsonAdapter.toJson(human) | Human__JsonHelper.serializeToJson(human) | mapper.writeValueAsString(human) | genson.serialize(human) |
Json to java | JSON.parseObject(jsonString, Human.class) | gson.fromJson(jsonString, Human.class) | LoganSquare.parse(jsonString, Human.class) | jsonAdapter.fromJson(jsonString) | Human__JsonHelper.parseFromJson(jsonString) | mapper.readValue(jsonString, Human.class) | genson.deserialize(jsonString, Human.class) |
Human__JsonHelper is a class that Ig json parser generated at the compilation stage, LoganSquare also has a generation at the compilation stage, but there the classes are connected "under the hood" inside LoganSquare.
Let's look at examples in more detail.
// convert to json String jsonString = JSON.toJSONString(human); System.out.println("json " + jsonString); // "json {"message":"Hi","place":{"name":"World"}}" // convert from json Human newHuman = JSON.parseObject(jsonString, Human.class); newHuman.say(); // "Hi , World!"
// convert to json Gson gson = new Gson(); String jsonString = gson.toJson(human); System.out.println("json " + jsonString); // "json {"message":"Hi","place":{"name":"World"}}" // convert from json Human newHuman = gson.fromJson(jsonString, Human.class); newHuman.say(); // "Hi , World!"
@JsonObject public class Human { @JsonField(name="message") public String message; @JsonField(name="place") public Place place; .... // convert to json String jsonString = LoganSquare.serialize(human); System.out.println("json " + jsonString); // "json {"place":{"name":"World"},"message":"Hi"}" // convert from json Human newHuman = LoganSquare.parse(jsonString, Human.class); newHuman.say(); // "Hi , World!"
// convert to json Moshi moshi = new Moshi.Builder().build(); JsonAdapter<Human> jsonAdapter = moshi.adapter(Human.class); String jsonString = jsonAdapter.toJson(human); System.out.println("json " + jsonString); // "json {"message":"Hi","place":{"name":"World"}}" // convert from json Human newHuman = jsonAdapter.fromJson(jsonString); newHuman.say(); // "Hi , World!"
@JsonType public class Human { @JsonField(fieldName="message") public String message; @JsonField(fieldName="place") public Place place; ... // convert to json String jsonString = Human__JsonHelper.serializeToJson(human); System.out.println("json " + jsonString); // "json {"place":{"name":"World"},"message":"Hi"}" // convert from json Human newHuman = Human__JsonHelper.parseFromJson(jsonString); newHuman.say(); // "Hi , World!"
// convert to json ObjectMapper mapper = new ObjectMapper(); String jsonString = mapper.writeValueAsString(human); System.out.println("json " + jsonString); // "json {"message":"Hi","place":{"name":"World"}}" // convert from json Human newHuman = mapper.readValue(jsonString, Human.class); newHuman.say(); // "Hi , World!"
// convert to json String jsonString = new Genson().serialize(human); System.out.println("json " + jsonString); // "json {"message":"Hi","place":{"name":"World"}}" // convert from json Human newHuman = new Genson().deserialize(jsonString, Human.class); newHuman.say(); // "Hi , World!"
To study more complex examples of libraries, see the documentation and generation of java classes from json. Using generation, you can quickly get the necessary java classes with all the annotations for the jackson or gson libraries.
The use of Tree Model is in three libraries: Gson, Jackson and Json Java. Let's see their implementation.
To demonstrate the work of libraries, we will use the same json:
jsonString = { "message": "Hi", "place": { "name": "World" } }
Json'a parsing methods:
Act | Gson | Jackson | Json java |
---|---|---|---|
Initialization | JsonParser parser = new JsonParser() | new ObjectMapper() | - |
Json's parsing | parser.parse(<>) | mapper.readValue(<>, JsonNode.class) | new JSONObject(<>) |
Getting the main object | root.getAsJsonObject() | - | - |
Getting string | root.get(<>).getAsString() | root.get(<>).asText() | root.getString(<>) |
Getting a child | root.getAsJsonObject(<>) | root.get(<>) | root.getJSONObject(<>) |
Methods of generating json'a:
Act | Gson | Jackson | Json java |
---|---|---|---|
Initialization | - | new ObjectMapper() | - |
Creating the main object | new JsonObject() | mapper.createObjectNode() | new JSONObject() |
Add string field | root.addProperty(<>, <>) | root.put(<>, <>) | root.put(<>, <>) |
Add child object | root.add(<>, <>); | root.putObject(<>) | root.put(<>, <>) |
Examples:
1) Reading Gson
JsonParser parser = new JsonParser(); JsonElement jsonElement = parser.parse("{\"message\":\"Hi\",\"place\":{\"name\":\"World!\"}}"); JsonObject rootObject = jsonElement.getAsJsonObject(); // String message = rootObject.get("message").getAsString(); // "message" JsonObject childObject = rootObject.getAsJsonObject("place"); // Place String place = childObject.get("name").getAsString(); // "name" System.out.println(message + " " + place); // "Hi World!"*/
2) Generate Gson
JsonObject rootObject = new JsonObject(); // rootObject.addProperty("message", "Hi"); // "message" JsonObject childObject = new JsonObject(); // Place childObject.addProperty("name", "World!"); // "name" Place rootObject.add("place", childObject); // "place" Gson gson = new Gson(); String json = gson.toJson(rootObject); // json System.out.println(json); // "{"message":"Hi","place":{"name":"World!"}}"
3) Reading Jackson
ObjectMapper mapper = new ObjectMapper(); JsonNode rootNode = mapper.readValue("{\"message\":\"Hi\",\"place\":{\"name\":\"World!\"}}", JsonNode.class); // String message = rootNode.get("message").asText(); // "message" JsonNode childNode = rootNode.get("place"); // Place String place = childNode.get("name").asText(); // "name" System.out.println(message + " " + place); // "Hi World!"
4) Generate Jackson
OutputStream outputStream = new ByteArrayOutputStream(); ObjectMapper mapper = new ObjectMapper(); ObjectNode rootNode = mapper.createObjectNode(); // rootNode.put("message", "Hi"); ObjectNode childNode = rootNode.putObject("place"); // Place childNode.put("name", "World!"); mapper.writeValue(outputStream, childNode); // json System.out.println(outputStream.toString()); // "{"message":"Hi","place":{"name":"World!"}}"
5) Reading and Generating Json Java
And Json Java (reference implementation from the developers of the standard json), which uses JSONObject
// convert Java to json JSONObject root = new JSONObject(); // root.put("message", "Hi"); JSONObject place = new JSONObject(); // Place place.put("name", "World!"); root.put("place", place); // Place place String json = root.toString(); System.out.println(json); // "{"message":"Hi","place":{"name":"World!"}}" System.out.println(); // convert json to Java JSONObject jsonObject = new JSONObject(json); // json String message = jsonObject.getString("message"); String name = jsonObject.getJSONObject("place").getString("name"); System.out.println(message + " " + name); // "Hi World!"
In general, it can be noted that in all libraries approximately the same actions are performed, only the class names differ.
To demonstrate the work of the libraries, we will use the same json:
jsonString = { "message": "Hi", "place": { "name": "World" } }
Typically, the Streaming API is used extremely rarely, only in tasks requiring very high performance or with very large files.
Json'a parsing methods:
Act | Gson | Jackson |
---|---|---|
Initialization | - | new JsonFactory() |
Json's parsing | reader = new JsonReader((<input_stream>) | parser = jsonFactory.createParser(<>) |
Check if there are more tokens | reader.hasNext() | parser.hasCurrentToken() |
Getting token type | reader.peek() | parser.nextToken() |
Getting the next token | reader.nextString() reader.beginObject() reader.endObject() etc. | parser.nextToken() |
Skip token | reader.skipValue() | parser.nextToken() |
Getting string | reader.nextString() | parser.getText() |
Methods of generating json'a:
Act | Gson | Jackson |
---|---|---|
Initialization | writer = new JsonWriter (<output_stream>) | generator = new JsonFactory().createGenerator(<output_stream>, <>) |
Object start token | writer.beginObject() | generator.writeStartObject() |
Object End Token | writer.endObject() | generator.writeEndObject() |
Field name token | writer.name(<>) | generator.writeFieldName(<>) |
String value token | writer.value(<>) | generator.writeStringField(<>, <>) |
Examples:
1) Reading in Gson
String str = "{\"message\":\"Hi\",\"place\":{\"name\":\"World!\"}}"; InputStream in = new ByteArrayInputStream(str.getBytes(Charset.forName("UTF-8"))); JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8")); while (reader.hasNext()) { // JsonToken jsonToken = reader.peek(); // if(jsonToken == JsonToken.BEGIN_OBJECT) { // reader.beginObject(); } else if(jsonToken == JsonToken.END_OBJECT) { // reader.endObject(); } if(jsonToken == JsonToken.STRING) { // - System.out.print(reader.nextString() + " "); // Hi World! } else { reader.skipValue(); // } } reader.close();
2) Record in Gson
OutputStream outputStream = new ByteArrayOutputStream(); JsonWriter writer = new JsonWriter(new OutputStreamWriter(outputStream, "UTF-8")); writer.beginObject(); // writer.name("message"); // message writer.value("Hi"); writer.name("place"); // Place place writer.beginObject(); // Place writer.name("name"); writer.value("World!"); writer.endObject(); // Place writer.endObject(); // writer.close(); System.out.println(outputStream.toString()); // "{"message":"Hi","place":{"name":"World!"}}"
3) Reading in Jackson
JsonFactory jsonFactory = new JsonFactory(); JsonParser jsonParser = jsonFactory.createParser("{\"message\":\"Hi\",\"place\":{\"name\":\"World!\"}}"); JsonToken jsonToken = jsonParser.nextToken(); while(jsonParser.hasCurrentToken()) { // if(jsonToken == VALUE_STRING) { // - System.out.print(jsonParser.getText() + " "); // "Hi World!" } jsonToken = jsonParser.nextToken(); }
2) Record in Jackson
JsonFactory jsonFactory = new JsonFactory(); OutputStream outputStream = new ByteArrayOutputStream(); JsonGenerator jsonGenerator = jsonFactory.createGenerator(outputStream, JsonEncoding.UTF8); jsonGenerator.writeStartObject(); // jsonGenerator.writeStringField("message", "Hi"); // message jsonGenerator.writeFieldName("place"); jsonGenerator.writeStartObject(); // Place jsonGenerator.writeStringField("name", "World!"); jsonGenerator.writeEndObject(); // Place jsonGenerator.writeEndObject(); // jsonGenerator.close(); System.out.println(outputStream.toString()); // "{"message":"Hi","place":{"name":"World!"}}"
Methods:
Act | Jsonpath | Fastjson |
---|---|---|
Getting the value of the filter | JsonPath.read(<json>, <>) | JSONPath.eval(<java_>, <>) |
Getting collection by filter | JsonPath.read(<json>, <>) | JSONPath.eval(<java_>, <>) |
Let's see examples, we will use the same json
jsonString = { "message": "Hi", "place": { "name": "World" } }
String jsonHiWorld = "{\"message\":\"Hi\",\"place\":{\"name\":\"World!\"}}\""; String message = JsonPath.read(jsonHiWorld, "$.message"); String place = JsonPath.read(jsonHiWorld, "$.place.name"); System.out.println(message + " " + place); // "Hi World!"
// json'a Java String jsonString = "{\"message\":\"Hi\",\"place\":{\"name\":\"World!\"}}\""; Human newHuman = JSON.parseObject(jsonString, Human.class); // Java eval Object message = JSONPath.eval(newHuman, "$.message"); Object world = JSONPath.eval(newHuman, "$.place.name"); System.out.println(message + " " + world); // print Hi World
List<String> authors = JsonPath.read(json, "$.store.book[*].author"); System.out.println("authors: " + authors); // print ["Nigel Rees","Evelyn Waugh","Herman Melville","JRR Tolkien"] List<Map<String, Object>> expensiveBooks = JsonPath .using(Configuration.defaultConfiguration()) .parse(json) .read("$.store.book[?(@.price > 22)].title", List.class); System.out.println(expensiveBooks); // print ["Hello, Middle-earth! "]
where json is
String json = "{\n" + " \"store\": {\n" + " \"book\": [\n" + " {\n" + " \"category\": \"reference\",\n" + " \"author\": \"Nigel Rees\",\n" + " \"title\": \"Sayings of the Century\",\n" + " \"price\": 8.95\n" + " },\n" + " {\n" + " \"category\": \"fiction\",\n" + " \"author\": \"Evelyn Waugh\",\n" + " \"title\": \"Sword of Honour\",\n" + " \"price\": 12.99\n" + " },\n" + " {\n" + " \"category\": \"fiction\",\n" + " \"author\": \"Herman Melville\",\n" + " \"title\": \"Moby Dick\",\n" + " \"isbn\": \"0-553-21311-3\",\n" + " \"price\": 8.99\n" + " },\n" + " {\n" + " \"category\": \"fiction\",\n" + " \"author\": \"JRR Tolkien\",\n" + " \"title\": \"Hello, Middle-earth! \",\n" + " \"isbn\": \"0-395-19395-8\",\n" + " \"price\": 22.99\n" + " }\n" + " ],\n" + " \"bicycle\": {\n" + " \"color\": \"red\",\n" + " \"price\": 19.95\n" + " }\n" + " },\n" + " \"expensive\": 10\n" + "}";
It remains to consider the issues of generating Java classes and validating json. I advise you to look at the following two online resources:
Let's consider the options for using these libraries in Java code.
// Init json String source = "{\n" + " \"type\":\"object\",\n" + " \"properties\": {\n" + " \"messageHiWorld\": {\n" + " \"type\": \"string\"\n" + " },\n" + " \"bar\": {\n" + " \"type\": \"integer\"\n" + " },\n" + " \"baz\": {\n" + " \"type\": \"boolean\"\n" + " }\n" + " }\n" + "}"; // Init config JCodeModel codeModel = new JCodeModel(); GenerationConfig config = new DefaultGenerationConfig() { @Override public boolean isGenerateBuilders() { // set config option by overriding method return true; } }; // Generate Java POJO from json SchemaMapper mapper = new SchemaMapper(new RuleFactory(config, new Jackson2Annotator(), new SchemaStore()), new SchemaGenerator()); mapper.generate(codeModel, "HelloWorldClass", "com.github.vedenin", source); // Save generated class to file File directory = new File("helloworlds/3.8-json/jsonschema2pojo/output"); directory.mkdirs(); codeModel.build(directory); // Show generated class File cls = new File("helloworlds/3.8-json/jsonschema2pojo/output/com/github/vedenin/HelloWorldClass.java"); String codeHelloWorld = Files.toString(cls, Charsets.UTF_8); System.out.println(codeHelloWorld);
final JsonNode fstabSchema = Utils.loadResource("/fstab.json"); final JsonNode good = Utils.loadResource("/fstab-good.json"); final JsonNode bad = Utils.loadResource("/fstab-bad.json"); final JsonNode bad2 = Utils.loadResource("/fstab-bad2.json"); final JsonSchemaFactory factory = JsonSchemaFactory.byDefault(); final JsonSchema schema = factory.getJsonSchema(fstabSchema); ProcessingReport report; report = schema.validate(good); System.out.println(report); report = schema.validate(bad); System.out.println(report); report = schema.validate(bad2); System.out.println(report);
1) Add the following code to maven, changing the sourceDirectory (where the json schemas lie) and targetPackage (the package of the generated classes)
<build> <plugins> <plugin> <groupId>org.jsonschema2pojo</groupId> <artifactId>jsonschema2pojo-maven-plugin</artifactId> <version>0.4.22</version> <configuration> ```${basedir}/src/main/resources</sourceDirectory> <targetPackage>com.github.vedenin</targetPackage> </configuration> <executions> <execution> <goals> <goal>generate</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
2) Put the necessary json schema in sourceDirectory
3) After launching install maven, all classes will generate Java classes.
Documentation of all libraries :
All examples :
I hope you enjoyed this article, more information about libraries and code samples can be found on github'e . The English version can be found here , the updated Russian version will be on github .
Project assistance :
I would be grateful both for adding new useful links to the list of libraries, for adding Hello world examples, and for correcting Russian and English grammar in articles (for more details see here ). I would be grateful for any comments and additions.
1. JPA and Hibernate in questions and answers
2. Three hundred fifty most popular non-mobile Java opensource projects on github
3. Java collections (standard, guava, apache, trove, gs-collections, and others)
4. Java Stream API
5. Two hundred and fifty Russian-language teaching videos of lectures and reports on Java.
6. List of useful links for Java programmer
7 Typical tasks
7.1 Optimum way to convert an InputStream to a string
7.2 The most productive way to bypass the Map, count the number of occurrences of the substring
8. Libraries for working with Json (Gson, Fastjson, LoganSquare, Jackson, JsonPath and others)
Source: https://habr.com/ru/post/280782/
All Articles