Boon JSON in five minutes
Boon and JSON
Boon is not a JSON parsing project. It is more than that, but JSON parsing is intrinsic to what Boon is all about. Boon is the fastest way to serialize and parse JSON in Java so far. It is faster at object serialization, enabling JSON expressions, JSON parsing and much more. Boon JSON is FAST! In addition it has a very easy to use, convention-based API.
Latest round of benchmarks to coincide with release (older now)
Update: The new Groovy JSON parser based on Boon JSON parser is 20x faster than the previous Groovy JSON parser circa Groovy 2.2! Groovy JSON support and the Boon JSON parser are up to 3x to 5x faster than Jackson at parsing JSON from String and char[], and 2x to 4x faster at parsing byte[]. Groovy now has the fastest JSON parser on the JVM.
Update: The new Groovy JSON parser based on Boon JSON parser is 20x faster than the previous Groovy JSON parser circa Groovy 2.2! Groovy JSON support and the Boon JSON parser are up to 3x to 5x faster than Jackson at parsing JSON from String and char[], and 2x to 4x faster at parsing byte[]. Groovy now has the fastest JSON parser on the JVM.
Updated Benchmark from April 2014
TOC
- Process Model For Data Binding and Serialization
- JSON full data binding
- Simple Data Binding - working with maps and lists
- Complete code listing so far
- Just works philosophy by example
- Boon and REST, HTTP GET POST
- Code Listing so far
- Working with Dates - smart standard date handling
- Raw data binding
- Data bindings with Generics
- Using Annotations to include or exclude properties
- Complete Code listing so far
- Primitive Parsing - parse primitive and primitive arrays
- Customizing JSON parser and serializer with factories
- Boon is faster than Jackson, GSON and others
Processing model: Data Binding
Boon mainly focuses on data binding and index overlay. The final interface is always about data binding as it is the most convenient one to use. It gets this idea from Jackson. Boon data binding allows for conversion between JSON data and Java objects.
There is no public tree model in Boon JSON or streaming model. The end users view is always a data binding view.
The ObjectMapper enables data binding and is built on top of the Boon JsonParser and JsonSerializer APIs, and mimics the Jackson API, which is the most popular Java JSON serializer/parser.
You can do simple data binding that only uses standard JDK container types (List, Maps) and scalar types (String, Boolean, Number, nulls). There is even a low-level API that can do wrapper-less (no auto-boxing) primitive arrays. You can also do full data binding that can use full range of Java types including "POJOs" (Plain Old Java Objects) such as Java Beans. Both can be used via the all-powerful ObjectMapper interface. The learning curve from Jackson should be minimal, and the speed-up can be up to 5x.
Serialization
Serialization is achieved by:
ObjectMapper mapper = ObjectMapperFactory.create();
mapper.writeValue(dst, myBean); // where 'dst' can be File, OutputStream or Writer
Full Data Binding
When using full data binding, deserialization type must be fully specified as something other than Object.class. For example:
MyBean value = mapper.readValue(src, MyBean.class); // 'src' can be File, InputStream, Reader, String
The main complication is handling of Generic types: if they are used, one has to use the two argument version of readValue to work around Java Type Erasure:
List<MyBean> beans = mapper.readValue(src, List.class, MyBean.class);
"Simple" Data Binding
As mentioned above, simple here just means that range of value types is limited to core JDK types. If this is acceptable, deserialization type can be simply defined as Object.class. This can apply at root level (for calls to ObjectMapper, as well as at lower level -- whatever value are declared to be of basic Object type will use Simple data binding. Simple like this:
Object root = mapper.readValue(src, Object.class);
Map<String,Object> rootAsMap = mapper.readValue(src, Map.class);
Complete code listing for tutorial so far
package org.boon.json;
import org.boon.Lists;
import java.io.File;
import java.util.List;
import java.util.Map;
import static org.boon.Boon.puts;
/**
* Created by rick on 1/4/14.
*/
public class JsonTutorial {
public static class MyBean {
String name = "Rick";
@Override
public String toString() {
return "MyBean{" +
"name='" + name + '\'' +
'}';
}
}
public static void main (String... args) throws Exception {
MyBean myBean = new MyBean();
File dst = File.createTempFile("emp", ".json");
ObjectMapper mapper = ObjectMapperFactory.create();
puts ("json string", mapper.writeValueAsString( myBean ));
mapper.writeValue( dst, myBean ); // where 'dst' can be File, OutputStream or Writer
File src = dst;
MyBean value = mapper.readValue(src, MyBean.class); // 'src' can be File, InputStream, Reader, String
//MyBean value = mapper.readValue(src, MyBean.class); // 'src' can be File, InputStream, Reader, String
puts ("mybean", value);
Object root = mapper.readValue(src, Object.class);
Map<String,Object> rootAsMap = mapper.readValue(src, Map.class);
puts ("root", root);
puts ("rootAsMap", rootAsMap);
MyBean myBean1 = new MyBean(); myBean1.name = "Diana";
MyBean myBean2 = new MyBean(); myBean2.name = "Rick";
dst = File.createTempFile("empList", ".json");
final List<MyBean> list = Lists.list( myBean1, myBean2 );
puts ("json string", mapper.writeValueAsString( list ));
mapper.writeValue( dst, list );
src = dst;
List<MyBean> beans = mapper.readValue(src, List.class, MyBean.class);
puts ("mybeans", beans);
}
}
Output from the above listing:
json string {"name":"Rick"}
mybean MyBean{name='Rick'}
root {name=Rick}
rootAsMap {name=Rick}
json string [{"name":"Diana"},{"name":"Rick"}]
mybeans [MyBean{name='Diana'}, MyBean{name='Rick'}]
Examples of it "just works"
Full Data Binding (POJO) Example
Boon's ObjectMapper "just works" for mapping JSON data into plain old Java objects ("POJOs"). For example, given JSON data:
{
"gender": "MALE",
"name": {
"first": "Richard",
"last": "Hightower"
},
"verified": true
}
To create the above JSON file, you could serialize this Java POJO:
public class User {
public enum Gender { MALE, FEMALE };
public static class Name {
private String first, last;
public Name( String _first, String _last ) {
this.first = _first;
this.last = _last;
}
public String getFirst() { return first; }
public String getLast() { return last; }
public void setFirst(String s) { first = s; }
public void setLast(String s) { last = s; }
}
private Gender gender;
private Name name;
private boolean isVerified;
public Name getName() { return name; }
public boolean isVerified() { return isVerified; }
public Gender getGender() { return gender; }
public void setName(Name n) { name = n; }
public void setVerified(boolean b) { isVerified = b; }
public void setGender(Gender g) { gender = g; }
}
To produce the above JSON, you can create a serialize User as follows:
ObjectMapper mapper = ObjectMapperFactory.create();
User user = new User();
user.setGender( User.Gender.MALE );
user.setName(new User.Name("Richard", "Hightower"));
user.setVerified( true );
puts ( mapper.writeValueAsString( user ) );
This JSON gets produced:
{
"gender": "MALE",
"name": {
"first": "Richard",
"last": "Hightower"
},
"verified": true
}
It is just as easy to read and write files:
Now to write/serialize and then read/deserialize this user to/fro to a file.
Write to a file:
File file = File.createTempFile( "user", ".json" );
mapper.writeValue( file, user );
Read from a file
User userFromFile = mapper.readValue( file, User.class );
puts ( userFromFile );
The puts method is like System.out.println of sorts and is part of Boon.
Using Streams, Readers, Writers, etc.
Boon also works with Streams, Readers, Writers, etc.
Read from a inputStream using JDK 1.7 Files utility:
Path path = Paths.get(file.toString());
InputStream inputStream = Files.newInputStream(path);
User userFromInput = mapper.readValue( inputStream, User.class );
puts ( "userFromInput", userFromInput );
Read from a reader using JDK 1.7 Files utility:
Reader reader = Files.newBufferedReader( path, StandardCharsets.UTF_8 );
User userFromReader = mapper.readValue( reader, User.class );
puts ( "userFromReader", userFromReader );
Boon and REST
Boon ships with an IO library that makes it easy to read/write from URLs, and other file systems:
User userFromURL = mapper.readValue( IO.read("http://fromsomewebsite/user.json"), User.class );
puts ( "userFromURL", userFromURL );
Boon also makes making JSON calls to REST web services easy as you can use Boon's HTTP utilities as follows:
String results = HTTP.postJSON("http://foo.com/bar/add/user", mapper.writeValueAsString( user ) );
AddUserResponse response = mapper.readValue( results, AddUserResponse.class );
Here is an example of getting a listing of users from a REST call:
List <User> userList = mapper.readValue( HTTP.getJSON("http://foo.com/bar/user/listing"),
List.class, User.class );
Complete code listing so far for tutorial
package org.boon.json;
import org.boon.Lists;
import org.boon.core.Dates;
import java.io.File;
import java.io.InputStream;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.List;
import java.util.Map;
import static org.boon.Boon.puts;
/**
* Created by rick on 1/4/14.
*/
public class JsonTutorial {
public static class MyBean {
String name = "Rick";
@Override
public String toString() {
return "MyBean{" +
"name='" + name + '\'' +
'}';
}
}
public static class User {
public enum Gender { MALE, FEMALE };
public static class Name {
private String first, last;
public Name( String _first, String _last ) {
this.first = _first;
this.last = _last;
}
public String getFirst() { return first; }
public String getLast() { return last; }
public void setFirst(String s) { first = s; }
public void setLast(String s) { last = s; }
@Override
public String toString() {
return "Name{" +
"first='" + first + '\'' +
", last='" + last + '\'' +
'}';
}
}
private Gender gender;
private Name name;
private boolean verified;
private Date birthDate;
public Name getName() { return name; }
public boolean isVerified() { return verified; }
public Gender getGender() { return gender; }
public void setName(Name n) { name = n; }
public void setVerified(boolean b) { verified = b; }
public void setGender(Gender g) { gender = g; }
public Date getBirthDate() { return birthDate; }
public void setBirthDate( Date birthDate ) { this.birthDate = birthDate; }
@Override
public String toString() {
return "User{" +
"gender=" + gender +
", name=" + name +
", isVerified=" + verified +
'}';
}
}
public static void part1 () throws Exception {
MyBean myBean = new MyBean();
File dst = File.createTempFile("emp", ".json");
ObjectMapper mapper = ObjectMapperFactory.create();
puts ("json string", mapper.writeValueAsString( myBean ));
mapper.writeValue( dst, myBean ); // where 'dst' can be File, OutputStream or Writer
File src = dst;
MyBean value = mapper.readValue(src, MyBean.class); // 'src' can be File, InputStream, Reader, String
puts ("mybean", value);
Object root = mapper.readValue(src, Object.class);
Map<String,Object> rootAsMap = mapper.readValue(src, Map.class);
puts ("root", root);
puts ("rootAsMap", rootAsMap);
MyBean myBean1 = new MyBean(); myBean1.name = "Diana";
MyBean myBean2 = new MyBean(); myBean2.name = "Rick";
dst = File.createTempFile("empList", ".json");
final List<MyBean> list = Lists.list( myBean1, myBean2 );
puts ("json string", mapper.writeValueAsString( list ));
mapper.writeValue( dst, list );
src = dst;
List<MyBean> beans = mapper.readValue(src, List.class, MyBean.class);
puts ("mybeans", beans);
}
public static void part2 () throws Exception {
ObjectMapper mapper = ObjectMapperFactory.create();
User user = new User();
user.setGender( User.Gender.MALE );
user.setName(new User.Name("Richard", "Hightower"));
user.setVerified( true );
user.setBirthDate( Dates.getUSDate( 5, 25, 1980 ) );
puts (mapper.writeValueAsString( user ));
//Now to write and then read this as a file.
File file = File.createTempFile( "user", ".json" );
mapper.writeValue( file, user );
User userFromFile = mapper.readValue( file, User.class );
puts ( "userFromFile", userFromFile );
Path path = Paths.get(file.toString());
InputStream inputStream = Files.newInputStream(path);
User userFromInput = mapper.readValue( inputStream, User.class );
puts ( "userFromInput", userFromInput );
Reader reader = Files.newBufferedReader( path, StandardCharsets.UTF_8 );
User userFromReader = mapper.readValue( reader, User.class );
puts ( "userFromReader", userFromReader );
}
public static void main (String... args) throws Exception {
part1();
part2();
}
}
Working with dates
Going back to our user example. By default if you print out a date, it looks like this:
ObjectMapper mapper = ObjectMapperFactory.create();
puts ( mapper.writeValueAsString( user ) );
The above generates this:
{
"gender": "MALE",
"name": {
"first": "Richard",
"last": "Hightower"
},
"verified": true,
"birthDate": 328147200766
}
...
//user was initialized as follows:
static User user = new User();
static {
user.setGender( User.Gender.MALE );
user.setName(new User.Name("Richard", "Hightower"));
user.setVerified( true );
user.setBirthDate( Dates.getUSDate( 5, 25, 1980 ) );
}
The issue is 328147200766 is not very friendly way to write a date. One of the nice things about JSON is it is readable, and that date is not very readable. JavaScript formats a date using a standard format, and if you are working with JavaScript, it can easily parse this standard format if you enable it.
Since this date format is the de facto standard, Boon makes it easy to use this format as follows:
ObjectMapper mapper = ObjectMapperFactory.create();
puts ( mapper.writeValueAsString( user ) );
Generates this user with a human readable date.
{
"gender": "MALE",
"name": {
"first": "Richard",
"last": "Hightower"
},
"verified": true,
"birthDate": "1980-05-26T00:00:00.014Z"
}
You can customize how Strings, Dates, Arrays, Collections, etc. are output quite easily, but that is beyond the scope of the five minute guide.
Boon can read and write this date format on the fly, and this is the date format that JavaScript browser use to convey dates.
Example of reading LONG date format on the fly to/for:
ObjectMapper mapper = ObjectMapperFactory.create();
puts ( mapper.writeValueAsString( user ) );
User user2 = mapper.readValue( mapper.writeValueAsString( user ), User.class );
puts (user2);
Example of reading JSON string date format on the fly to/for:
ObjectMapper mapper = ObjectMapperFactory.createUseJSONDates();
puts ( mapper.writeValueAsString( user ) );
User user2 = mapper.readValue( mapper.writeValueAsString( user ), User.class );
puts (user2);
Output:
{"gender":"MALE","name":{"first":"Richard","last":"Hightower"},"verified":true,"birthDate":328147200193}
User{gender=MALE, name=Name{first='Richard', last='Hightower'}, verified=true, birthDate=Sun May 25 17:00:00 PDT 1980}
{"gender":"MALE","name":{"first":"Richard","last":"Hightower"},"verified":true,"birthDate":"1980-05-26T00:00:00.193Z"}
User{gender=MALE, name=Name{first='Richard', last='Hightower'}, verified=true, birthDate=Sun May 25 17:00:00 PDT 1980}
Notice that the long and the JSON style date are written and read with ease.
"Raw" Data Binding Example
In cases where you do not have (and don't want to create) specific Java classes to bind JSON to/from, "Untyped data binding" may be a better approach. It is used same way as full data binding, except that the formal binding type is specified simply as Object.class (or Map.class, List.class, String[].class, int[].class, etc. if more specific typing is wanted). The earlier binding of JSON that represent User data could have been done by:
Map userData = mapper.readValue(new File("user.json"), Map.class); and userData would be like one we would explicit construct by:
ObjectMapper mapper = ObjectMapperFactory.createUseJSONDates();
puts( mapper.writeValueAsString( user ) );
//Now to write and then read this as a file.
File file = File.createTempFile( "user", ".json" );
mapper.writeValue( file, user );
//Reading the value as Object returns a list of map, and in this case a map.
Object userFromFile = mapper.readValue( file, Object.class );
puts( "userFromFile", "type", userFromFile.getClass(), "value", userFromFile );
//Here we can read it as a map.
Map<String, Object> map = (Map<String, Object>) mapper.readValue( file, Map.class );
puts( "userFromFile", "type", map.getClass(), "value", map );
//We can access this individual properties with the map interface
puts( "userFromFile.name", "type", map.get("name").getClass(),
"value", map.get("name") );
//We can even get to the birthdate, notice birthdate gets converted to a date because
//boon recognizes the date format string
puts( "userFromFile.birthDate", "type", map.get("birthDate").getClass(),
"value", map.get("birthDate") );
//Gender gets read in as a string since we did not have an class to let us know it was an enum
puts( "userFromFile.gender", "type", map.get("gender").getClass(),
"value", map.get("gender") );
//Since this is boon, we can always convert the map into a field later.
User userFromMap =
MapObjectConversion.fromMap(
map, User.class);
puts ( userFromMap );
Output
{"gender":"MALE","name":{"first":"Richard","last":"Hightower"},"verified":true,"birthDate":"1980-05-26T00:00:00.826Z"}
userFromFile type class org.boon.core.value.LazyValueMap value {gender=MALE, birthDate=Sun May 25 17:00:00 PDT 1980, verified=true, name={last=Hightower, first=Richard}}
userFromFile type class org.boon.core.value.LazyValueMap value {gender=MALE, birthDate=Sun May 25 17:00:00 PDT 1980, verified=true, name={last=Hightower, first=Richard}}
userFromFile.name type class org.boon.core.value.LazyValueMap value {last=Hightower, first=Richard}
userFromFile.birthDate type class java.util.Date value Sun May 25 17:00:00 PDT 1980
userFromFile.gender type class java.lang.String value MALE
User{gender=MALE, name=Name{first='Richard', last='Hightower'}, verified=true, birthDate=Sun May 25 17:00:00 PDT 1980}
The class LazyValueMap implements java.util.Map. The boon utility class MapObjectConversion can read to/fro maps just likeObjectMapper can read to/fro JSON.
This obviously works both ways: if you did construct such a Map (or bind from JSON and modify), you could write out just as before, by:
mapper.writeValue(new File("user-modified.json"), userMap);
How does this work? By specifying Map.class, we do not specify generic key/value types. But ObjectMapper does know how to bind JSON data to and from Maps (and Lists, arrays, wrapper types, primitives, primitive arrays), and does just that. Fundamentally JSON data has no "real" type as far as Boon is concerned -- if it can be properly mapped to a type you give, it will be mapped.
Data Binding with Generics
In addition to binding to POJOs and "simple" types, there is one additional variant: that of binding to generic (typed) containers. This case requires special handling due to so-called Type Erasure (used by Java to implement generics in somewhat backwards compatible way), which prevents you from using something like Collection.class (which does not compile).
So if you want to bind data into a List you will need to use:
Working with generics
mapper.writeValue( file, users );
List<User> userList = mapper.readValue( file, List.class, User.class );
puts (userList);
Output
[
{
"gender": "FEMALE",
"name": {
"first": "Diana",
"last": "Hightower"
},
"verified": true,
"birthDate": "1984-08-22T00:00:00.002Z"
},
{
"gender": "MALE",
"name": {
"first": "Rick",
"last": "Hightower"
},
"verified": true,
"birthDate": "1980-05-26T00:00:00.941Z"
}
]
Full listing so far:
package org.boon.json;
import org.boon.Lists;
import org.boon.core.Dates;
import org.boon.core.reflection.BeanUtils;
import org.boon.core.reflection.MapObjectConversion;
import java.io.File;
import java.io.InputStream;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.List;
import java.util.Map;
import static org.boon.Boon.puts;
/**
* Created by rick on 1/4/14.
*/
public class JsonTutorial {
public static class MyBean {
String name = "Rick";
@Override
public String toString() {
return "MyBean{" +
"name='" + name + '\'' +
'}';
}
}
public static class User {
public enum Gender {MALE, FEMALE}
;
public static class Name {
private String first, last;
public Name( String _first, String _last ) {
this.first = _first;
this.last = _last;
}
public String getFirst() {
return first;
}
public String getLast() {
return last;
}
public void setFirst( String s ) {
first = s;
}
public void setLast( String s ) {
last = s;
}
@Override
public String toString() {
return "Name{" +
"first='" + first + '\'' +
", last='" + last + '\'' +
'}';
}
}
private Gender gender;
private Name name;
private boolean verified;
private Date birthDate;
public Name getName() {
return name;
}
public boolean isVerified() {
return verified;
}
public Gender getGender() {
return gender;
}
public void setName( Name n ) {
name = n;
}
public void setVerified( boolean b ) {
verified = b;
}
public void setGender( Gender g ) {
gender = g;
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate( Date birthDate ) {
this.birthDate = birthDate;
}
@Override
public String toString() {
return "User{" +
"gender=" + gender +
", name=" + name +
", verified=" + verified +
", birthDate=" + birthDate +
'}';
}
}
static User user = new User();
static {
user.setGender( User.Gender.MALE );
user.setName( new User.Name( "Richard", "Hightower" ) );
user.setVerified( true );
user.setBirthDate( Dates.getUSDate( 5, 25, 1980 ) );
}
public static void part1() throws Exception {
MyBean myBean = new MyBean();
File dst = File.createTempFile( "emp", ".json" );
ObjectMapper mapper = ObjectMapperFactory.create();
puts( "json string", mapper.writeValueAsString( myBean ) );
mapper.writeValue( dst, myBean ); // where 'dst' can be File, OutputStream or Writer
File src = dst;
MyBean value = mapper.readValue( src, MyBean.class ); // 'src' can be File, InputStream, Reader, String
puts( "mybean", value );
Object root = mapper.readValue( src, Object.class );
Map<String, Object> rootAsMap = mapper.readValue( src, Map.class );
puts( "root", root );
puts( "rootAsMap", rootAsMap );
MyBean myBean1 = new MyBean();
myBean1.name = "Diana";
MyBean myBean2 = new MyBean();
myBean2.name = "Rick";
dst = File.createTempFile( "empList", ".json" );
final List<MyBean> list = Lists.list( myBean1, myBean2 );
puts( "json string", mapper.writeValueAsString( list ) );
mapper.writeValue( dst, list );
src = dst;
List<MyBean> beans = mapper.readValue( src, List.class, MyBean.class );
puts( "mybeans", beans );
}
public static void part2() throws Exception {
ObjectMapper mapper = ObjectMapperFactory.create();
puts( mapper.writeValueAsString( user ) );
//Now to write and then read this as a file.
File file = File.createTempFile( "user", ".json" );
mapper.writeValue( file, user );
User userFromFile = mapper.readValue( file, User.class );
puts( "userFromFile", userFromFile );
Path path = Paths.get( file.toString() );
InputStream inputStream = Files.newInputStream( path );
User userFromInput = mapper.readValue( inputStream, User.class );
puts( "userFromInput", userFromInput );
Reader reader = Files.newBufferedReader( path, StandardCharsets.UTF_8 );
User userFromReader = mapper.readValue( reader, User.class );
puts( "userFromReader", userFromReader );
}
public static void part3() throws Exception {
part3_1();
part3_2();
}
public static void part3_1() throws Exception {
ObjectMapper mapper = ObjectMapperFactory.create();
puts( mapper.writeValueAsString( user ) );
User user2 = mapper.readValue( mapper.writeValueAsString( user ), User.class );
puts( user2 );
}
public static void part3_2() throws Exception {
ObjectMapper mapper = ObjectMapperFactory.createUseJSONDates();
puts( mapper.writeValueAsString( user ) );
User user2 = mapper.readValue( mapper.writeValueAsString( user ), User.class );
puts( user2 );
}
public static void part5() throws Exception {
puts ("\n\n\n", "\npart5");
ObjectMapper mapper = ObjectMapperFactory.createUseJSONDates();
final User diana = BeanUtils.copy( user );
final User rick = BeanUtils.copy( user );
diana.getName().setFirst( "Diana" );
rick.getName().setFirst( "Rick" );
diana.setBirthDate( Dates.getUSDate( 8, 21, 1984 ) );
File file = File.createTempFile( "userList", ".json" );
List<User> users = Lists.list( diana, rick );
mapper.writeValue( file, users );
List<User> userList = mapper.readValue( file, List.class, User.class );
puts (userList);
puts ( mapper.writeValueAsString( userList ) );
}
public static void part4() throws Exception {
ObjectMapper mapper = ObjectMapperFactory.createUseJSONDates();
puts( mapper.writeValueAsString( user ) );
//Now to write and then read this as a file.
File file = File.createTempFile( "user", ".json" );
mapper.writeValue( file, user );
Object userFromFile = mapper.readValue( file, Object.class );
puts( "userFromFile", "type", userFromFile.getClass(), "value", userFromFile );
Map<String, Object> map = (Map<String, Object>) mapper.readValue( file, Map.class );
puts( "userFromFile", "type", map.getClass(), "value", map );
puts( "userFromFile.name", "type", map.get("name").getClass(),
"value", map.get("name") );
puts( "userFromFile.birthDate", "type", map.get("birthDate").getClass(),
"value", map.get("birthDate") );
puts( "userFromFile.gender", "type", map.get("gender").getClass(),
"value", map.get("gender") );
User userFromMap =
MapObjectConversion.fromMap(
map, User.class);
puts ( userFromMap );
}
public static void part6() throws Exception {
puts ("\n\n\n", "\npart5");
ObjectMapper mapper = ObjectMapperFactory.createUseJSONDates();
final User diana = BeanUtils.copy( user );
final User rick = BeanUtils.copy( user );
diana.getName().setFirst( "Diana" );
diana.setGender( User.Gender.FEMALE );
rick.getName().setFirst( "Rick" );
diana.setBirthDate( Dates.getUSDate( 8, 21, 1984 ) );
File file = File.createTempFile( "userList", ".json" );
List<User> users = Lists.list( diana, rick );
mapper.writeValue( file, users );
List<User> userList = mapper.readValue( file, List.class, User.class );
puts (userList);
puts ( mapper.writeValueAsString( userList ) );
}
public static void main( String... args ) throws Exception {
part1();
part2();
part3();
part4();
part5();
}
}
Annotations
Working with annotations. Boon in general and Boon JSON support specifically is not driven entirely by annotations. There is both aJsonParserFactory and a JsonSerializerFactory and with those you can override certain behaviors of JSON parsing and serializing.
There are some annotations that Boon JSON does recognize and they are JsonIgnore, JsonInclude and JsonIncludeProperties. These JSON properties exist in Boon, but Boon will also recognize these annotations from JsonSmart and Jackson and handle them the same way.
By default (can be overridden with the factory) Boon will not write out nulls, empty lists or values that are default values (int primitive has a default of 0, boolean primitive has a default of false). If you want a value to be written out even if it is empty, null, false or 0, you can use the @JsonInclude annotation.
Boon by default outputs all properties and/or fields of an object. Let's say you had an employee directory and an employee has a SSN. You don't want to output an SSN so you can leave it out with a @JsonIgnore. Let's show how these work in practice.
Continuing our example before, let's create an SSN that we don't want output with JsonIgnore and a status string that we want written even if it is null or empty.
Using @JsonIgnore and @JsonInclude
public class User {
@JsonIgnore
private String ssn = "555-55-5555";
@JsonInclude
private String status = null;
Write them out
/* Write users out to file. */
mapper.writeValue( file, users );
/* Reader Users back from file. */
List<User> userList = mapper.readValue( file, List.class, User.class );
puts ("userListBeansReadFromFile", userList);
/* Inspect the JSON of the users from the file. */
puts ("usersFromFileAsJSON", mapper.writeValueAsString( userList ) );
Output
usersFromFileAsJSON
[
{
"status": null,
"gender": "FEMALE",
"name": {
"first": "Diana",
"last": "Hightower"
},
"verified": true,
"birthDate": "1984-08-22T00:00:00.910Z"
},
{
"status": null,
"gender": "MALE",
"name": {
"first": "Rick",
"last": "Hightower"
},
"verified": true,
"birthDate": "1980-05-26T00:00:00.822Z"
}
]
Complete code listing so far
package org.boon.json;
import org.boon.Lists;
import org.boon.core.Dates;
import org.boon.core.reflection.BeanUtils;
import org.boon.core.reflection.MapObjectConversion;
import org.boon.json.annotations.JsonIgnore;
import org.boon.json.annotations.JsonInclude;
import java.io.File;
import java.io.InputStream;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.List;
import java.util.Map;
import static org.boon.Boon.puts;
/**
* Created by rick on 1/4/14.
*/
public class JsonTutorial {
public static class MyBean {
String name = "Rick";
@Override
public String toString() {
return "MyBean{" +
"name='" + name + '\'' +
'}';
}
}
public static class User {
@JsonIgnore
private String ssn = "555-55-5555";
@JsonInclude
private String status = null;
public enum Gender {MALE, FEMALE}
public static class Name {
private String first, last;
public Name( String _first, String _last ) {
this.first = _first;
this.last = _last;
}
public String getFirst() {
return first;
}
public String getLast() {
return last;
}
public void setFirst( String s ) {
first = s;
}
public void setLast( String s ) {
last = s;
}
@Override
public String toString() {
return "Name{" +
"first='" + first + '\'' +
", last='" + last + '\'' +
'}';
}
}
private Gender gender;
private Name name;
private boolean verified;
private Date birthDate;
public Name getName() {
return name;
}
public boolean isVerified() {
return verified;
}
public Gender getGender() {
return gender;
}
public void setName( Name n ) {
name = n;
}
public void setVerified( boolean b ) {
verified = b;
}
public void setGender( Gender g ) {
gender = g;
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate( Date birthDate ) {
this.birthDate = birthDate;
}
@Override
public String toString() {
return "User{" +
"gender=" + gender +
", name=" + name +
", verified=" + verified +
", birthDate=" + birthDate +
'}';
}
}
static User user = new User();
static {
user.setGender( User.Gender.MALE );
user.setName( new User.Name( "Richard", "Hightower" ) );
user.setVerified( true );
user.setBirthDate( Dates.getUSDate( 5, 25, 1980 ) );
}
public static void part1() throws Exception {
MyBean myBean = new MyBean();
File dst = File.createTempFile( "emp", ".json" );
ObjectMapper mapper = ObjectMapperFactory.create();
puts( "json string", mapper.writeValueAsString( myBean ) );
mapper.writeValue( dst, myBean ); // where 'dst' can be File, OutputStream or Writer
File src = dst;
MyBean value = mapper.readValue( src, MyBean.class ); // 'src' can be File, InputStream, Reader, String
puts( "mybean", value );
Object root = mapper.readValue( src, Object.class );
Map<String, Object> rootAsMap = mapper.readValue( src, Map.class );
puts( "root", root );
puts( "rootAsMap", rootAsMap );
MyBean myBean1 = new MyBean();
myBean1.name = "Diana";
MyBean myBean2 = new MyBean();
myBean2.name = "Rick";
dst = File.createTempFile( "empList", ".json" );
final List<MyBean> list = Lists.list( myBean1, myBean2 );
puts( "json string", mapper.writeValueAsString( list ) );
mapper.writeValue( dst, list );
src = dst;
List<MyBean> beans = mapper.readValue( src, List.class, MyBean.class );
puts( "mybeans", beans );
}
public static void part2() throws Exception {
ObjectMapper mapper = ObjectMapperFactory.create();
puts( mapper.writeValueAsString( user ) );
//Now to write and then read this as a file.
File file = File.createTempFile( "user", ".json" );
mapper.writeValue( file, user );
User userFromFile = mapper.readValue( file, User.class );
puts( "userFromFile", userFromFile );
Path path = Paths.get( file.toString() );
InputStream inputStream = Files.newInputStream( path );
User userFromInput = mapper.readValue( inputStream, User.class );
puts( "userFromInput", userFromInput );
Reader reader = Files.newBufferedReader( path, StandardCharsets.UTF_8 );
User userFromReader = mapper.readValue( reader, User.class );
puts( "userFromReader", userFromReader );
}
public static void part3() throws Exception {
part3_1();
part3_2();
}
public static void part3_1() throws Exception {
ObjectMapper mapper = ObjectMapperFactory.create();
puts( mapper.writeValueAsString( user ) );
User user2 = mapper.readValue( mapper.writeValueAsString( user ), User.class );
puts( user2 );
}
public static void part3_2() throws Exception {
ObjectMapper mapper = ObjectMapperFactory.createUseJSONDates();
puts( mapper.writeValueAsString( user ) );
User user2 = mapper.readValue( mapper.writeValueAsString( user ), User.class );
puts( user2 );
}
public static void part5() throws Exception {
puts ("\n\n\n", "\npart5");
ObjectMapper mapper = ObjectMapperFactory.createUseJSONDates();
final User diana = BeanUtils.copy( user );
final User rick = BeanUtils.copy( user );
diana.getName().setFirst( "Diana" );
rick.getName().setFirst( "Rick" );
diana.setBirthDate( Dates.getUSDate( 8, 21, 1984 ) );
File file = File.createTempFile( "userList", ".json" );
List<User> users = Lists.list( diana, rick );
mapper.writeValue( file, users );
List<User> userList = mapper.readValue( file, List.class, User.class );
puts (userList);
puts ( mapper.writeValueAsString( userList ) );
}
public static void part4() throws Exception {
ObjectMapper mapper = ObjectMapperFactory.createUseJSONDates();
puts( mapper.writeValueAsString( user ) );
//Now to write and then read this as a file.
File file = File.createTempFile( "user", ".json" );
mapper.writeValue( file, user );
Object userFromFile = mapper.readValue( file, Object.class );
puts( "userFromFile", "type", userFromFile.getClass(), "value", userFromFile );
Map<String, Object> map = (Map<String, Object>) mapper.readValue( file, Map.class );
puts( "userFromFile", "type", map.getClass(), "value", map );
puts( "userFromFile.name", "type", map.get("name").getClass(),
"value", map.get("name") );
puts( "userFromFile.birthDate", "type", map.get("birthDate").getClass(),
"value", map.get("birthDate") );
puts( "userFromFile.gender", "type", map.get("gender").getClass(),
"value", map.get("gender") );
User userFromMap =
MapObjectConversion.fromMap(
map, User.class);
puts ( userFromMap );
}
public static void part6() throws Exception {
puts ("\n\n\n", "\npart6");
ObjectMapper mapper = ObjectMapperFactory.createUseJSONDates();
final User diana = BeanUtils.copy( user );
final User rick = BeanUtils.copy( user );
diana.getName().setFirst( "Diana" );
diana.setGender( User.Gender.FEMALE );
rick.getName().setFirst( "Rick" );
diana.setBirthDate( Dates.getUSDate( 8, 21, 1984 ) );
File file = File.createTempFile( "userList", ".json" );
List<User> users = Lists.list( diana, rick );
mapper.writeValue( file, users );
List<User> userList = mapper.readValue( file, List.class, User.class );
puts (userList);
puts ( mapper.writeValueAsString( userList ) );
}
public static void part7() throws Exception {
puts ("\n\n\n", "\npart7");
ObjectMapper mapper = ObjectMapperFactory.createUseAnnotations( true );
/* Create two users. */
final User diana = BeanUtils.copy( user );
final User rick = BeanUtils.copy( user );
diana.getName().setFirst( "Diana" );
diana.setGender( User.Gender.FEMALE );
rick.getName().setFirst( "Rick" );
diana.setBirthDate( Dates.getUSDate( 8, 21, 1984 ) );
File file = File.createTempFile( "userList", ".json" );
List<User> users = Lists.list( diana, rick );
/* Inspect the JSON of the users from the file. */
puts ("users", mapper.writeValueAsString( users ) );
/* Write users out to file. */
mapper.writeValue( file, users );
/* Reader Users back from file. */
List<User> userList = mapper.readValue( file, List.class, User.class );
puts ("userListBeansReadFromFile", userList);
/* Inspect the JSON of the users from the file. */
puts ("usersFromFileAsJSON", mapper.writeValueAsString( userList ) );
}
public static void main( String... args ) throws Exception {
part1();
part2();
part3();
part4();
part5();
part6();
part7();
}
}
Output so far
json string {"name":"Rick"}
mybean MyBean{name='Rick'}
root {name=Rick}
rootAsMap {name=Rick}
json string [{"name":"Diana"},{"name":"Rick"}]
mybeans [MyBean{name='Diana'}, MyBean{name='Rick'}]
{"ssn":"555-55-5555","gender":"MALE","name":{"first":"Richard","last":"Hightower"},"verified":true,"birthDate":328147200833}
userFromFile User{gender=MALE, name=Name{first='Richard', last='Hightower'}, verified=true, birthDate=Sun May 25 17:00:00 PDT 1980}
userFromInput User{gender=MALE, name=Name{first='Richard', last='Hightower'}, verified=true, birthDate=Sun May 25 17:00:00 PDT 1980}
userFromReader User{gender=MALE, name=Name{first='Richard', last='Hightower'}, verified=true, birthDate=Sun May 25 17:00:00 PDT 1980}
{"ssn":"555-55-5555","gender":"MALE","name":{"first":"Richard","last":"Hightower"},"verified":true,"birthDate":328147200833}
User{gender=MALE, name=Name{first='Richard', last='Hightower'}, verified=true, birthDate=Sun May 25 17:00:00 PDT 1980}
{"ssn":"555-55-5555","gender":"MALE","name":{"first":"Richard","last":"Hightower"},"verified":true,"birthDate":"1980-05-26T00:00:00.833Z"}
User{gender=MALE, name=Name{first='Richard', last='Hightower'}, verified=true, birthDate=Sun May 25 17:00:00 PDT 1980}
{"ssn":"555-55-5555","gender":"MALE","name":{"first":"Richard","last":"Hightower"},"verified":true,"birthDate":"1980-05-26T00:00:00.833Z"}
userFromFile type class org.boon.core.value.LazyValueMap value {ssn=555-55-5555, gender=MALE, birthDate=Sun May 25 17:00:00 PDT 1980, verified=true, name={last=Hightower, first=Richard}}
userFromFile type class org.boon.core.value.LazyValueMap value {ssn=555-55-5555, gender=MALE, birthDate=Sun May 25 17:00:00 PDT 1980, verified=true, name={last=Hightower, first=Richard}}
userFromFile.name type class org.boon.core.value.LazyValueMap value {last=Hightower, first=Richard}
userFromFile.birthDate type class java.util.Date value Sun May 25 17:00:00 PDT 1980
userFromFile.gender type class java.lang.String value MALE
User{gender=MALE, name=Name{first='Richard', last='Hightower'}, verified=true, birthDate=Sun May 25 17:00:00 PDT 1980}
part5
[User{gender=MALE, name=Name{first='Diana', last='Hightower'}, verified=true, birthDate=Tue Aug 21 17:00:00 PDT 1984}, User{gender=MALE, name=Name{first='Rick', last='Hightower'}, verified=true, birthDate=Sun May 25 17:00:00 PDT 1980}]
[{"ssn":"555-55-5555","gender":"MALE","name":{"first":"Diana","last":"Hightower"},"verified":true,"birthDate":"1984-08-22T00:00:00.989Z"},{"ssn":"555-55-5555","gender":"MALE","name":{"first":"Rick","last":"Hightower"},"verified":true,"birthDate":"1980-05-26T00:00:00.833Z"}]
part6
[User{gender=FEMALE, name=Name{first='Diana', last='Hightower'}, verified=true, birthDate=Tue Aug 21 17:00:00 PDT 1984}, User{gender=MALE, name=Name{first='Rick', last='Hightower'}, verified=true, birthDate=Sun May 25 17:00:00 PDT 1980}]
[{"ssn":"555-55-5555","gender":"FEMALE","name":{"first":"Diana","last":"Hightower"},"verified":true,"birthDate":"1984-08-22T00:00:00.991Z"},{"ssn":"555-55-5555","gender":"MALE","name":{"first":"Rick","last":"Hightower"},"verified":true,"birthDate":"1980-05-26T00:00:00.833Z"}]
part7
users [{"status":null,"gender":"FEMALE","name":{"first":"Diana","last":"Hightower"},"verified":true,"birthDate":"1984-08-22T00:00:00.992Z"},{"status":null,"gender":"MALE","name":{"first":"Rick","last":"Hightower"},"verified":true,"birthDate":"1980-05-26T00:00:00.833Z"}]
userListBeansReadFromFile [User{gender=FEMALE, name=Name{first='Diana', last='Hightower'}, verified=true, birthDate=Tue Aug 21 17:00:00 PDT 1984}, User{gender=MALE, name=Name{first='Rick', last='Hightower'}, verified=true, birthDate=Sun May 25 17:00:00 PDT 1980}]
usersFromFileAsJSON [{"status":null,"gender":"FEMALE","name":{"first":"Diana","last":"Hightower"},"verified":true,"birthDate":"1984-08-22T00:00:00.992Z"},{"status":null,"gender":"MALE","name":{"first":"Rick","last":"Hightower"},"verified":true,"birthDate":"1980-05-26T00:00:00.833Z"}]
Process finished with exit code 0
Primitive parsing
At times it is nice to have a light weight parser that can handling Java primitive types, Strings, etc.
Boon JSON can read int, float, double, long, int arrays, dates, strings, etc.
ObjectMapper mapper = ObjectMapperFactory.create();
String intStr = "123456";
int someNumber = mapper.parser().parseInt( intStr );
boolean ok = someNumber == 123456 || die( "" + someNumber );
String jsonArray = "[0,1,2,3,4,5,6,7,8]";
int [] intArray = mapper.parser().parseIntArray( jsonArray );
ok |= Arrays.equals( new int[]{1,2,3,4,5,6,7,8}, intArray );
String jsonMap = "{\"race\":true, \"speedup\": false, \"name\": \"bob\"}";
Map <String, Object> map = mapper.parser().parseMap( jsonMap );
ok |= ( map.get("race") == true && map.get("name").equals( "bob" ) ) || die(map.toString());
puts("ok?", ok);
The main interface to Boon parsing is not ObjectMapper, but JsonParser. The ObjectMapper interface is the one most people are familiar with thanks to the success of Jackson.
You could easily use JsonParser to read configuration settings stored as strings in a database or a properties files, etc. It allows you to parse arrays, strings, maps easily. No fuss no muss. No need for object serialization or annotations. Boon's JsonParser is first and foremost a fast and lightweight parser.
Notice as you ponder the overview of JsonParser that it supports BigDecmimal and BigInteger as well.
Overview of what the parser can do
package org.boon.json;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.List;
import java.util.Map;
public interface JsonParser {
Map<String, Object> parseMap( String value );
Map<String, Object> parseMap( char [] value );
Map<String, Object> parseMap( byte[] value );
Map<String, Object> parseMap( byte[] value, Charset charset );
Map<String, Object> parseMap( InputStream value, Charset charset );
Map<String, Object> parseMap( CharSequence value );
Map<String, Object> parseMap( InputStream value );
Map<String, Object> parseMap( Reader value );
Map<String, Object> parseMapFromFile( String file );
<T> List<T> parseList( Class<T> componentType, String jsonString );
<T> List<T> parseList( Class<T> componentType, InputStream input );
<T> List<T> parseList( Class<T> componentType, Reader reader );
<T> List<T> parseList( Class<T> componentType, InputStream input, Charset charset );
<T> List<T> parseList( Class<T> componentType, byte[] jsonBytes );
<T> List<T> parseList( Class<T> componentType, byte[] jsonBytes, Charset charset );
<T> List<T> parseList( Class<T> componentType, char[] chars );
<T> List<T> parseList( Class<T> componentType, CharSequence jsonSeq );
<T> List<T> parseListFromFile( Class<T> componentType, String fileName );
<T> T parse( Class<T> type, String jsonString );
<T> T parse( Class<T> type, byte[] bytes );
<T> T parse( Class<T> type, byte[] bytes, Charset charset );
<T> T parse( Class<T> type, CharSequence charSequence );
<T> T parse( Class<T> type, char[] chars );
<T> T parse( Class<T> type, Reader reader );
<T> T parse( Class<T> type, InputStream input );
<T> T parse( Class<T> type, InputStream input, Charset charset );
<T> T parseDirect( Class<T> type, byte[] value );
<T> T parseAsStream( Class<T> type, byte[] value );
<T> T parseFile( Class<T> type, String fileName);
int parseInt( String jsonString );
int parseInt( InputStream input );
int parseInt( InputStream input, Charset charset );
int parseInt( byte[] jsonBytes );
int parseInt( byte[] jsonBytes, Charset charset );
int parseInt( char[] chars );
int parseInt( CharSequence jsonSeq );
int parseIntFromFile( String fileName );
long parseLong( String jsonString );
long parseLong( InputStream input );
long parseLong( InputStream input, Charset charset );
long parseLong( byte[] jsonBytes );
long parseLong( byte[] jsonBytes, Charset charset );
long parseLong( char[] chars );
long parseLong( CharSequence jsonSeq );
long parseLongFromFile( String fileName );
double parseDouble( String value );
double parseDouble( InputStream value );
double parseDouble( byte[] value );
double parseDouble( char[] value );
double parseDouble( CharSequence value );
double parseDouble( byte[] value, Charset charset );
double parseDouble( InputStream value, Charset charset );
double parseDoubleFromFile( String fileName );
float parseFloat( String value );
float parseFloat( InputStream value );
float parseFloat( byte[] value );
float parseFloat( char[] value );
float parseFloat( CharSequence value );
float parseFloat( byte[] value, Charset charset );
float parseFloat( InputStream value, Charset charset );
float parseFloatFromFile( String fileName );
BigDecimal parseBigDecimal( String value );
BigDecimal parseBigDecimal( InputStream value );
BigDecimal parseBigDecimal( byte[] value );
BigDecimal parseBigDecimal( char[] value );
BigDecimal parseBigDecimal( CharSequence value );
BigDecimal parseBigDecimal( byte[] value, Charset charset );
BigDecimal parseBigDecimal( InputStream value, Charset charset );
BigDecimal parseBigDecimalFromFile( String fileName );
BigInteger parseBigInteger( String value );
BigInteger parseBigInteger( InputStream value );
BigInteger parseBigInteger( byte[] value );
BigInteger parseBigInteger( char[] value );
BigInteger parseBigInteger( CharSequence value );
BigInteger parseBigInteger( byte[] value, Charset charset );
BigInteger parseBigInteger( InputStream value, Charset charset );
BigInteger parseBigIntegerFile( String fileName );
Date parseDate( String jsonString );
Date parseDate( InputStream input );
Date parseDate( InputStream input, Charset charset );
Date parseDate( byte[] jsonBytes );
Date parseDate( byte[] jsonBytes, Charset charset );
Date parseDate( char[] chars );
Date parseDate( CharSequence jsonSeq );
Date parseDateFromFile( String fileName );
short parseShort ( String jsonString );
byte parseByte ( String jsonString );
char parseChar ( String jsonString );
<T extends Enum> T parseEnum ( Class<T> type, String jsonString );
public char [] parseCharArray ( String jsonString );
public byte [] parseByteArray ( String jsonString );
public short [] parseShortArray ( String jsonString );
public int [] parseIntArray ( String jsonString );
public float [] parseFloatArray ( String jsonString );
public double [] parseDoubleArray ( String jsonString );
public long [] parseLongArray ( String jsonString );
Object parse( String jsonString );
Object parse( byte[] bytes );
Object parse( byte[] bytes, Charset charset );
Object parse( CharSequence charSequence );
Object parse( char[] chars );
Object parse( Reader reader );
Object parse( InputStream input );
Object parse( InputStream input, Charset charset );
Object parseDirect( byte[] value );
Object parseAsStream( byte[] value );
Object parseFile( String fileName);
void close();
}
Advanced JSON Boon
With Boon you can customize the output and input with JsonParserFactory and JsonSerializerFactory as follows:
You can basically install custom field serializers and type serializer on the factory:
AllTypes foo = new AllTypes ();
foo.ingnoreMe = "THIS WILL NOT PASS";
foo.ignoreMe2 = "THIS WILL NOT PASS EITHER";
foo.ignoreMe3 = "THIS WILL NOT PASS TOO";
foo.setDate ( new Date() );
foo.setBar ( FooEnum.BAR );
foo.setFoo ( FooEnum.FOO );
foo.setString ( "Hi Mom" );
AllTypes foo2 = BeanUtils.copy( foo );
foo.setAllType ( foo2 );
foo2.setString ( "Hi Dad" );
foo.setAllTypes ( Lists.list( BeanUtils.copy( foo2 ), BeanUtils.copy( foo2 )) );
final JsonSerializer serializer = new JsonSerializerFactory ()
.useAnnotations ()
.addFilter ( new FieldFilter () {
@Override
public boolean include ( Object parent, FieldAccess fieldAccess ) {
if ( fieldAccess.getName().equals( "ignoreMe3" ) ) {
return false;
} else {
return true;
}
}
} ).addPropertySerializer ( new CustomFieldSerializer () {
@Override
public boolean serializeField ( JsonSerializerInternal serializer, Object parent,
FieldAccess fieldAccess, CharBuf builder ) {
if ( fieldAccess.getType ().equals ( long.class ) &&
fieldAccess.getName ().endsWith ( "Date" ) ) {
builder.addJsonFieldName ( fieldAccess.getName () );
Date date = Conversions.toDate ( fieldAccess.getLong ( parent ) );
final String jsonDateString = Dates.jsonDate ( date );
builder.add ( jsonDateString );
return true;
} else {
return false;
}
}
} ).addTypeSerializer ( FooBasket.class, new AbstractCustomObjectSerializer ( FooBasket.class ) {
@Override
public void serializeObject ( JsonSerializerInternal serializer, Object instance, CharBuf builder ) {
builder.addString ( "[\"wiki\",\"wiki\",\"wiki\"]" );
}
} )
.create ();
String json = serializer.serialize ( foo ).toString ();
puts (json);
boolean ok = json.contains ("[\"wiki\",\"wiki\",\"wiki\"]" ) || die();
puts (json);
AllTypes testMe = jsonParser.parse( AllTypes.class, json);
ok |= testMe.equals ( foo ) || die();
ok |= testMe.ingnoreMe == null || die();
puts (testMe.ignoreMe2);
ok |= testMe.ignoreMe2 == null || die();
puts (testMe.ignoreMe3);
ok |= testMe.ignoreMe3 == null || die();
ok |= testMe.someDate > 0 || die();
This is just a quick example. A full listing and explanation is due, but that would not fit in a five minute discussion. :)
The AllType class used in the example:
package org.boon.json;
import org.boon.json.annotations.JsonIgnore;
import org.boon.json.annotations.JsonIgnoreProperties;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@JsonIgnoreProperties ("ignoreMe2")
public class AllTypes {
public FooBasket getFooBasket () {
return fooBasket;
}
public void setFooBasket ( FooBasket fooBasket ) {
this.fooBasket = fooBasket;
}
FooBasket fooBasket = new FooBasket ();
String ignoreMe3;
String ignoreMe2;
int myInt;
boolean myBoolean;
short myShort;
long myLong;
String string;
String string2;
BigDecimal bigDecimal;
BigInteger bigInteger;
Date date;
float myFloat;
double myDouble;
byte myByte;
FooEnum foo;
FooEnum bar;
@JsonIgnore
String ingnoreMe;
long someDate = new Date ( ).getTime ();
AllTypes allType;
List<AllTypes> allTypes = new ArrayList<> ( );
public String getString2 () {
return string2;
}
public void setString2 ( String string2 ) {
this.string2 = string2;
}
public List<AllTypes> getAllTypes () {
return allTypes;
}
public void setAllTypes ( List<AllTypes> allTypes ) {
this.allTypes = allTypes;
}
public AllTypes getAllType () {
return allType;
}
public void setAllType ( AllTypes allType ) {
this.allType = allType;
}
public byte getMyByte () {
return myByte;
}
public void setMyByte ( byte myByte ) {
this.myByte = myByte;
}
public int getMyInt () {
return myInt;
}
public void setMyInt ( int myInt ) {
this.myInt = myInt;
}
public boolean isMyBoolean () {
return myBoolean;
}
public void setMyBoolean ( boolean myBoolean ) {
this.myBoolean = myBoolean;
}
public short getMyShort () {
return myShort;
}
public void setMyShort ( short myShort ) {
this.myShort = myShort;
}
public long getMyLong () {
return myLong;
}
public void setMyLong ( long myLong ) {
this.myLong = myLong;
}
public String getString () {
return string;
}
public void setString ( String string ) {
this.string = string;
}
public float getMyFloat () {
return myFloat;
}
public void setMyFloat ( float myFloat ) {
this.myFloat = myFloat;
}
public double getMyDouble () {
return myDouble;
}
public void setMyDouble ( double myDouble ) {
this.myDouble = myDouble;
}
public BigDecimal getBigDecimal () {
return bigDecimal;
}
public void setBigDecimal ( BigDecimal bigDecimal ) {
this.bigDecimal = bigDecimal;
}
public BigInteger getBigInteger () {
return bigInteger;
}
public void setBigInteger ( BigInteger bigInteger ) {
this.bigInteger = bigInteger;
}
public Date getDate () {
return date;
}
public void setDate ( Date date ) {
this.date = date;
}
public FooEnum getFoo () {
return foo;
}
public void setFoo ( FooEnum foo ) {
this.foo = foo;
}
public FooEnum getBar () {
return bar;
}
public void setBar ( FooEnum bar ) {
this.bar = bar;
}
@Override
public boolean equals ( Object o ) {
if ( this == o ) return true;
if ( !( o instanceof AllTypes ) ) return false;
AllTypes allTypes1 = ( AllTypes ) o;
if ( myBoolean != allTypes1.myBoolean ) return false;
if ( myByte != allTypes1.myByte ) return false;
if ( Double.compare ( allTypes1.myDouble, myDouble ) != 0 ) return false;
if ( Float.compare ( allTypes1.myFloat, myFloat ) != 0 ) return false;
if ( myInt != allTypes1.myInt ) return false;
if ( myLong != allTypes1.myLong ) return false;
if ( myShort != allTypes1.myShort ) return false;
if ( bigDecimal != null ? !bigDecimal.equals ( allTypes1.bigDecimal ) : allTypes1.bigDecimal != null )
return false;
if ( bigInteger != null ? !bigInteger.equals ( allTypes1.bigInteger ) : allTypes1.bigInteger != null )
return false;
if ( string != null ? !string.equals ( allTypes1.string ) : allTypes1.string != null ) return false;
if ( string2 != null ? !string2.equals ( allTypes1.string2 ) : allTypes1.string2 != null ) return false;
if (allTypes == null && allTypes1.allTypes.size () == 0) {
return true;
} else {
if ( allTypes != null ? !allTypes.equals ( allTypes1.allTypes ) : allTypes1.allTypes != null ) return false;
}
if ( date != null && allTypes1.date!=null) {
long delta = Math.abs ( date.getTime () - allTypes1.date.getTime ());
if ( delta < 1000) {
return true;
} else {
return false;
}
}
if ( allType != null ? !allType.equals ( allTypes1.allType ) : allTypes1.allType != null ) return false;
if ( bar != allTypes1.bar ) return false;
if ( foo != allTypes1.foo ) return false;
return true;
}
@Override
public int hashCode () {
int result;
long temp;
result = myInt;
result = 31 * result + ( myBoolean ? 1 : 0 );
result = 31 * result + ( int ) myShort;
result = 31 * result + ( int ) ( myLong ^ ( myLong >>> 32 ) );
result = 31 * result + ( string != null ? string.hashCode () : 0 );
result = 31 * result + ( string2 != null ? string2.hashCode () : 0 );
result = 31 * result + ( bigDecimal != null ? bigDecimal.hashCode () : 0 );
result = 31 * result + ( bigInteger != null ? bigInteger.hashCode () : 0 );
result = 31 * result + ( date != null ? date.hashCode () : 0 );
result = 31 * result + ( myFloat != +0.0f ? Float.floatToIntBits ( myFloat ) : 0 );
temp = Double.doubleToLongBits ( myDouble );
result = 31 * result + ( int ) ( temp ^ ( temp >>> 32 ) );
result = 31 * result + ( int ) myByte;
result = 31 * result + ( foo != null ? foo.hashCode () : 0 );
result = 31 * result + ( bar != null ? bar.hashCode () : 0 );
result = 31 * result + ( allType != null ? allType.hashCode () : 0 );
result = 31 * result + ( allTypes != null ? allTypes.hashCode () : 0 );
return result;
}
@Override
public String toString () {
return "AllTypes{" +
"myInt=" + myInt +
", myBoolean=" + myBoolean +
", myShort=" + myShort +
", myLong=" + myLong +
", string='" + string + '\'' +
", string2='" + string2 + '\'' +
", bigDecimal=" + bigDecimal +
", bigInteger=" + bigInteger +
", date=" + date +
", myFloat=" + myFloat +
", myDouble=" + myDouble +
", myByte=" + myByte +
", foo=" + foo +
", bar=" + bar +
", allType=" + allType +
", allTypes=" + allTypes +
'}';
}
}
Json parse and serialize options
You customize the settings via the factories. You can customize if the parser and serializer uses fields, properties or both. You can also customize how the parser should parser the data (strict or relaxed or even ASCII PLIST style).
JsonParserFactory jsonParserFactory = new JsonParserFactory()
.useFieldsFirst().useFieldsOnly().usePropertiesFirst().usePropertyOnly() //one of these
.plistStyle() //allow parsing of ASCII PList style files
.lax() //allow loose parsing of JSON like JSON Smart
.strict() //opposite of lax
.setCharset( StandardCharsets.UTF_8 ) //Set the standard charset, defaults to UTF_8
.setChop( true ) //chops up buffer overlay buffer (more discussion of this later)
.setLazyChop( true ) //similar to chop but only does it after map.get
;
JsonSerializerFactory jsonSerializerFactory = new JsonSerializerFactory()
.useFieldsFirst().useFieldsOnly().usePropertiesFirst().usePropertyOnly() //one of these
//.addPropertySerializer( ) customize property output
//.addTypeSerializer( ) customize type output
.useJsonFormatForDates() //use json dates
//.addFilter( ) add a property filter to exclude properties
.includeEmpty().includeNulls().includeDefaultValues() //override defaults
.handleComplexBackReference() //uses identity map to track complex back reference and avoid them
.setHandleSimpleBackReference( true ) //looks for simple back reference for parent
.setCacheInstances( true ) //turns on caching for immutable objects
;
Once you have the factories you can create parsers, serializers or object mappers with them as follows:
//You can use parser and serializer directly.
final JsonParser jsonParser = jsonParserFactory.create();
final JsonSerializer jsonSerializer = jsonSerializerFactory.create();
File file = File.createTempFile( "userList", ".json" );
String jsonString = jsonSerializer.serialize( users ).toString();
IO.write( IO.path( file.toString()), jsonString);
List<User> users2 = jsonParser.parseListFromFile( User.class, file.toString() );
// Or you can pass them to the ObjectMapper interface you know and love,
// just pass the factories to it.
ObjectMapper mapper = ObjectMapperFactory.create(jsonParserFactory, jsonSerializerFactory);
mapper.writeValue( file, users );
List<User> userList = mapper.readValue( file, List.class, User.class );
puts (userList);
puts ( mapper.writeValueAsString( userList ) );
Boon speed
Boon is the all around fastest JSON parser out of GSON, Jackson and JsonSmart (so far). Boon now has input stream, reader, byte[], char[], CharSequence and String support.
Run on 17" 2011 Mac Book Pro with SSD and 16 GB or RAM.
1/5/2014
String
Testing against a 1.7 MB string.
java -jar target/microbenchmarks.jar ".string.Catalog" -wi 3 -i 5 -f 1 -t 8
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.s.StatelessBoonBenchMark.citmCatalog thrpt 8 5 1 979.087 234.875 ops/s
i.g.j.s.BoonBenchmark.citmCatalog thrpt 8 5 1 975.467 155.524 ops/s
i.g.j.s.BoonClassicBenchmark.citmCatalog thrpt 8 5 1 724.397 76.153 ops/s
i.g.j.s.JsonSmartBenchmark.citmCatalog thrpt 8 5 1 423.947 45.707 ops/s
i.g.j.s.GSONBenchmark.citmCatalog thrpt 8 5 1 373.203 38.523 ops/s
i.g.j.s.JacksonASTBenchmark.citmCatalog thrpt 8 5 1 269.490 30.313 ops/s
i.g.j.s.JacksonObjectBenchmark.citmCatalog thrpt 8 5 1 263.187 95.644 ops/s
Boon is 3x+ some of the competitors.
Jackson did so poorly that I ran it again by itself.
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.s.JacksonASTBenchmark.citmCatalog thrpt 8 5 1 314.703 96.497 ops/s
i.g.j.s.JacksonObjectBenchmark.citmCatalog thrpt 8 5 1 381.953 11.466 ops/s
Then to be fair to boon, I ran the two top performing Boon parser configurations as well
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.s.BoonBenchmark.citmCatalog thrpt 8 5 1 1249.423 215.237 ops/s
i.g.j.s.StatelessBoonBenchMark.citmCatalog thrpt 8 5 1 1074.957 255.704 ops/s
Then the run off test:
Fastest Jackson against Fastest Boon
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.s.BoonBenchmark.citmCatalog thrpt 8 5 1 1306.067 75.496 ops/s
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.s.JacksonObjectBenchmark.citmCatalog thrpt 8 5 1 369.557 16.925 ops/s
Boon maintains its 4x status over Jackson for this test. citmCatalog is a 1.7 MB file.
Boon is 4x faster when you run them by themselves.
Testing against a 2K JSON file
java -jar target/microbenchmarks.jar ".string.medium" -wi 3 -i 5 -f 3 -t 8
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.s.StatelessBoonBenchMark.medium thrpt 8 15 1 828614.167 113309.263 ops/s
i.g.j.s.BoonBenchmark.medium thrpt 8 15 1 655723.022 113194.181 ops/s
i.g.j.s.BoonClassicBenchmark.medium thrpt 8 15 1 544726.818 31969.515 ops/s
i.g.j.s.JsonSmartBenchmark.medium thrpt 8 15 1 261257.857 15178.567 ops/s
i.g.j.s.JacksonASTBenchmark.medium thrpt 8 15 1 244845.260 4459.778 ops/s
i.g.j.s.GSONBenchmark.medium thrpt 8 15 1 242176.437 5552.595 ops/s
i.g.j.s.JacksonObjectBenchmark.medium thrpt 8 15 1 239011.644 9544.070 ops/s
Boon is nearly 4x faster than Jackson in this configuration.
Now lets run the fastest boon against the fastest Jackson by themselves.
java -jar target/microbenchmarks.jar ".string.JacksonASTBenchmark.*medium" -wi 3 -i 5 -f 1 -t 8
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.s.JacksonASTBenchmark.medium thrpt 8 5 1 285827.937 30910.474 ops/s
Now the fastest Boon
java -jar target/microbenchmarks.jar ".string.BoonBenchmark.*medium" -wi 3 -i 5 -f 1 -t 8
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.s.BoonBenchmark.medium thrpt 8 5 1 1053372.327 16233.011 ops/s
The conclusion from 12/15/2013 to 1/4/2014 Boon is 100% faster than Boon, and where it was 50% to 100% faster than Jackson. Boon is now 200%, 300% and sometimes up to 400% faster than Jackson.
Boon wins by large margins when it comes to String parsing.
byte[] parsing
How does Boon do against the competitors when it is a byte[] instead of a String?
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.b.BoonBenchmark.medium thrpt 8 5 1 618123.037 29518.544 ops/s
i.g.j.b.JacksonObjectBenchmark.medium thrpt 8 5 1 379202.950 22999.872 ops/s
i.g.j.b.JacksonASTBenchmark.medium thrpt 8 5 1 293054.527 23981.011 ops/s
i.g.j.b.GSONBenchmark.medium thrpt 8 5 1 205735.037 207194.930 ops/s
i.g.j.b.JsonSmartBenchmark.medium thrpt 8 5 1 250384.043 25851.296 ops/s
Jackson does much better on this test than GSON and JsonSmart, but not better than Boon.
Now lets run them by themselves.
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.b.BoonBenchmark.medium thrpt 8 5 1 827191.353 19862.004 ops/s
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.b.JacksonObjectBenchmark.medium thrpt 8 5 1 354519.703 28758.081 ops/s
Boon is over 2x faster at parsing byte arrays then Jackson is. (Boon has about 5 different ways to parse a byte[] and all are faster than Jackson.)
Jackson on all files from json.org.
java -jar target/microbenchmarks.jar ".bytes.JacksonObjectBenchmark.*" -wi 3 -i 5 -f 1 -t 8
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.b.JacksonObjectBenchmark.actionLabel thrpt 8 5 1 320460.340 72131.986 ops/s
i.g.j.b.JacksonObjectBenchmark.citmCatalog thrpt 8 5 1 268.130 55.186 ops/s
i.g.j.b.JacksonObjectBenchmark.medium thrpt 8 5 1 197295.940 22306.259 ops/s
i.g.j.b.JacksonObjectBenchmark.menu thrpt 8 5 1 976004.950 268554.107 ops/s
i.g.j.b.JacksonObjectBenchmark.sgml thrpt 8 5 1 572307.433 163097.782 ops/s
i.g.j.b.JacksonObjectBenchmark.small thrpt 8 5 1 2275296.777 304454.266 ops/s
i.g.j.b.JacksonObjectBenchmark.webxml thrpt 8 5 1 111176.677 19523.744 ops/s
i.g.j.b.JacksonObjectBenchmark.widget thrpt 8 5 1 343268.823 119559.082 ops/s
Boon all files on JSON.org
java -jar target/microbenchmarks.jar ".bytes.BoonBenchmark.*" -wi 3 -i 5 -f 1 -t 8
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.b.BoonBenchmark.actionLabel thrpt 8 5 1 618993.350 48683.336 ops/s
i.g.j.b.BoonBenchmark.citmCatalog thrpt 8 5 1 492.307 80.017 ops/s
i.g.j.b.BoonBenchmark.medium thrpt 8 5 1 458555.533 10036.229 ops/s
i.g.j.b.BoonBenchmark.menu thrpt 8 5 1 1959464.230 505004.028 ops/s
i.g.j.b.BoonBenchmark.sgml thrpt 8 5 1 1300516.190 59998.099 ops/s
i.g.j.b.BoonBenchmark.small thrpt 8 5 1 10017411.120 171608.588 ops/s
i.g.j.b.BoonBenchmark.webxml thrpt 8 5 1 253177.177 141918.931 ops/s
i.g.j.b.BoonBenchmark.widget thrpt 8 5 1 1045186.440 95933.625 ops/s
i.g.j.b.BoonBenchmark.actionLabel thrpt 8 5 1 618993.350 48683.336 ops/s
i.g.j.b.JacksonObjectBenchmark.actionLabel thrpt 8 5 1 320460.340 72131.986 ops/s
Boon nearly 2x faster
1.7 MB
i.g.j.b.BoonBenchmark.citmCatalog thrpt 8 5 1 492.307 80.017 ops/s
i.g.j.b.JacksonObjectBenchmark.citmCatalog thrpt 8 5 1 268.130 55.186 ops/s
Boon nearly 2x faster
i.g.j.b.JacksonObjectBenchmark.small thrpt 8 5 1 2275296.777 304454.266 ops/s
i.g.j.b.BoonBenchmark.small thrpt 8 5 1 10017411.120 171608.588 ops/s
Boon nearly 5x faster!
i.g.j.b.JacksonObjectBenchmark.widget thrpt 8 5 1 343268.823 119559.082 ops/s
i.g.j.b.BoonBenchmark.widget thrpt 8 5 1 1045186.440 95933.625 ops/s
Boon almost 3x faster!
i.g.j.b.BoonBenchmark.medium thrpt 8 5 1 458555.533 10036.229 ops/s
i.g.j.b.JacksonObjectBenchmark.medium thrpt 8 5 1 197295.940 22306.259 ops/s
Boon over 2x faster!
i.g.j.b.JacksonObjectBenchmark.menu thrpt 8 5 1 976004.950 268554.107 ops/s
i.g.j.b.BoonBenchmark.menu thrpt 8 5 1 1959464.230 505004.028 ops/s
Boon over 2x faster!
Winner overall for byte[]. Boon KILLS IT! Sweep!
InputStream
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.inputStream.BoonBenchmark.actionLabel thrpt 8 5 1 168598.707 10702.291 ops/s
i.g.j.inputStream.JacksonObjectBenchmark.actionLabel thrpt 8 5 1 165700.530 7939.486 ops/s
Boon barely wins
i.g.j.inputStream.BoonBenchmark.citmCatalog thrpt 8 5 1 555.373 50.952 ops/s
i.g.j.inputStream.JacksonObjectBenchmark.citmCatalog thrpt 8 5 1 285.610 66.244 ops/s
Boon wins by 2x
i.g.j.inputStream.BoonBenchmark.medium thrpt 8 5 1 159105.320 19057.916 ops/s
i.g.j.inputStream.JacksonObjectBenchmark.medium thrpt 8 5 1 122754.690 130516.150 ops/s
Boon wins
i.g.j.inputStream.JacksonObjectBenchmark.menu thrpt 8 5 1 252556.270 179084.546 ops/s
i.g.j.inputStream.BoonBenchmark.menu thrpt 8 5 1 184977.057 5153.660 ops/s
Jackson wins
i.g.j.inputStream.JacksonObjectBenchmark.sgml thrpt 8 5 1 193714.667 3526.321 ops/s
i.g.j.inputStream.BoonBenchmark.sgml thrpt 8 5 1 180970.150 3499.859 ops/s
Jackson barely wins
i.g.j.inputStream.BoonBenchmark.webxml thrpt 8 5 1 132207.987 110279.994 ops/s
i.g.j.inputStream.JacksonObjectBenchmark.webxml thrpt 8 5 1 87252.977 16961.356 ops/s
Boon wins by a really good margin!
i.g.j.inputStream.BoonBenchmark.widget thrpt 8 5 1 178216.637 21779.520 ops/s
i.g.j.inputStream.JacksonObjectBenchmark.widget thrpt 8 5 1 171787.453 28138.131 ops/s
Boon wins
Boon wins nearly all, but Jackson wins a few here. GSON also does well at inputStream. Winner overall for inputStream. Boon!
Reader
Benchmark Mode Thr Count Sec Mean Mean error Units
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.r.BoonBenchmark.actionLabel thrpt 8 5 1 186001.097 18425.520 ops/s
i.g.j.r.JacksonObjectBenchmark.actionLabel thrpt 8 5 1 163270.073 3730.813 ops/s
Boon wins!
i.g.j.r.BoonBenchmark.citmCatalog thrpt 8 5 1 530.150 108.657 ops/s
i.g.j.r.JacksonObjectBenchmark.citmCatalog thrpt 8 5 1 226.990 81.640 ops/s
Boon wins by a large margin! Close to 2x
i.g.j.r.BoonBenchmark.medium thrpt 8 5 1 136242.553 4719.231 ops/s
i.g.j.r.JacksonObjectBenchmark.medium thrpt 8 5 1 105882.313 3083.148 ops/s
Boon wins by 30%!
i.g.j.r.BoonBenchmark.menu thrpt 8 5 1 145418.360 19145.101 ops/s
i.g.j.r.JacksonObjectBenchmark.menu thrpt 8 5 1 134975.063 7718.413 ops/s
Boon wins by a tad!
i.g.j.r.BoonBenchmark.sgml thrpt 8 5 1 128216.103 141559.091 ops/s
i.g.j.r.JacksonObjectBenchmark.sgml thrpt 8 5 1 140934.190 123224.172 ops/s
Jackson wins!
i.g.j.r.JacksonObjectBenchmark.small thrpt 8 5 1 145166.813 3960.731 ops/s
i.g.j.r.BoonBenchmark.small thrpt 8 5 1 145121.580 19487.609 ops/s
Almost a tie, but Jackson wins.
i.g.j.r.BoonBenchmark.webxml thrpt 8 5 1 116019.730 10943.316 ops/s
i.g.j.r.JacksonObjectBenchmark.webxml thrpt 8 5 1 71660.963 43656.284 ops/s
Boon wins by a large margin about 35%.
i.g.j.r.BoonBenchmark.widget thrpt 8 5 1 143853.053 11396.247 ops/s
i.g.j.r.JacksonObjectBenchmark.widget thrpt 8 5 1 119811.283 14264.563 ops/s
Boon wins by a large margin about 30%
In two instances Jackson barely beats boon. In one instance Jackson wins by 15%. Boon wins by 200%, 35%, 30% and 30%. Then there are a few smaller wins for Boon.
Winner overall for reader. Boon!
Object Serialization
Jackson
Benchmark Mode Thr Count Sec Mean Mean error Units
i.g.j.s.BoonSerializer.roundTriper thrpt 8 5 1 214115.270 64366.819 ops/s
i.g.j.s.JacksonSerializer.roundTriper thrpt 8 5 1 96239.373 91586.021 ops/s
Boon over 2x faster!
i.g.j.s.BoonSerializer.serializeSmall thrpt 8 5 1 692168.577 70292.894 ops/s
i.g.j.s.JacksonSerializer.serializeSmall thrpt 8 5 1 436992.523 68051.334 ops/s
Boon is substantially faster!
Boon wins the object serialization battle.
Boon is part of QBit. QBit uses Boon. QBit is a microservice lib featuring REST, HTTP, JSON and WebSocket and an event bus that can be easily integrated in with Kafka, STOMP, etc. QBit picks up where Boon left off.
Learn more about QBit and microservices:
[Detailed Tutorial] QBit microservice example
[Doc] Queue Callbacks for QBit queue based services
[Quick Start] Building a simple Rest web microservice server with QBit
[Quick Start] Building a TODO web microservice client with QBit
[Quick Start] Building a TODO web microservice server with QBit
[Quick Start] Building boon for the QBit microservice engine
[Quick Start] Building QBit the microservice lib for Java
[Rough Cut] Delivering up Single Page Applications from QBit Java JSON Microservice lib
[Rough Cut] Working with event bus for QBit the microservice engine
[Rough Cut] Working with inproc MicroServices
[Rough Cut] Working with private event bus for inproc microservices
[Rough Cut] Working with strongly typed event bus proxies for QBit Java Microservice lib
[Rough Cut] Working with System Manager for QBit Mircoservice lib
[Z Notebook] More benchmarking internal
[Z Notebook] Performance testing for REST
[Z Notebook] Roadmap
Home
Introduction to QBit
Local Service Proxies
QBit Boon New Wave of JSON HTTP and Websocket
QBit Docs
Boon is part of QBit. QBit uses Boon. QBit is a microservice lib featuring REST, HTTP, JSON and WebSocket and an event bus that can be easily integrated in with Kafka, STOMP, etc. QBit picks up where Boon left off.
Learn more about QBit and microservices:
[Detailed Tutorial] QBit microservice example
No comments:
Post a Comment