JSON-P and JSON-B

JavaScript Object Notation (JSON) is the go-to format for sharing data in microservices-based systems. It’s lightweight, human-readable, and requires far less formatting than XML. It also transfers across different platforms and programming languages, in a format that all the participating languages can access.

JSON supports two standard data structures: objects, which are sets of key-value pairs usually surrounded by curly brackets, and arrays, which collect objects into larger sets. These objects and arrays are serialized and deserialized for transfer between different microservices.

Java provides two API specifications for converting plain Java objects (POJOs) to and from JSON data: JSON processing (JSON-P) and JSON binding (JSON-B). JSON-P provides a Java API for processing JSON-formatted data. JSON-B provides a binding layer on top of JSON-P, making it even easier to convert objects to and from JSON.

JSON-P: Java EE’s original API

Before the release of JSON-B (which arrived as part of Java EE 8), JSON-P was Java EE’s standardized way to interact with JSON. JSON-P is a lower-level API that provides two models (streaming and object) for JSON processing and transformation. The streaming model provides an event-based parser that allows a developer to ask for the next event rather than handling the event in a callback, offering more control over the processing. The object model creates a random access structure to represent the JSON data in memory. This programming model is more flexible but sometimes requires more memory than the streaming model.

In contrast to JSON-B, JSON-P avoids data loss by retaining all the information in a call. This can be either an advantage or a liability, depending on what the code is doing.

Higher-level API with JSON-B

JSON-B is a standard binding layer for converting Java objects to and from JSON data. It provides default mapping to convert existing Java classes to JSON, but also enables developers to customize mapping by using Java annotations. JSON-B is a direct object-to-JSON mapping, requiring much less code than JSON-P. Its intuitive default configurations make it easy to use. Even developers with no prior experience with JSON can use JSON-B because it’s based around annotations and semantics that are already commonplace for Java developers.

JSON-P or JSON-B?

Since its introduction as part of Java EE 8, JSON-B has become the preferred API for converting Java objects to and from JSON, thanks to its type safety, ease-of-use, and compile-time feedback. However, there are cases where JSON-P might be a better fit.

Consider the subject of data loss. Say that you have JSON data representing a user that is being sent between microservices. The object might contain the following data:

{
  "id" : 5678,
  "name" : "Hank",
  "age": 55,
  "roles" : [ "member" ]
}

If a service that uses JSON-B received this object, but only asked for id and name, the other information would be lost. A service that uses JSON-P would retain all the data in the object.

JSON-P is also useful in rare cases where an application needs to parse an arbitrary set of JSON data and the schema is not known ahead of time. With JSON-B, the developer must know the schema of the JSON up front.

Basic usage of JSON-B

Suppose that we have the following data class:

public static class User {

    // Public fields are included in the JSON data by default
    public long id;
    public Set<String> roles;
    public String name;
    public int age;

    // Private fields are ignored by JSON-B by default
    private String somethingSecret = "hello";

    // Static fields are also ignored by default
    public static String FOO_CONSTANT = "FOO";

    public User() {
        // A default constructor is required (by default)
        // If no default constructor is present, it must be annotated with @JsonbCreator
    }

    public User(long id, String name, int age, Set<String> roles) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.roles = roles;
    }
}

Note that the data class does not need any annotations or any reference to the JSON-B API.

The next code example shows how we can rely on the default mappings of JSON-B to marshal and unmarshal the object for us. The main JSON-B entry point is the javax.json.bind.Jsonb class. It provides all necessary methods to serialize and deserialize Java objects. Jsonb instances are thread safe. They can be cached and reused whenever possible.

// Always cache Jsonb objects when possible! They are relatively expensive to create
private static final Jsonb jsonb = JsonbBuilder.create();
// ...

// Convert POJO --> JSON
User andy = new User(1234, "Andy", 77, Collections.singleton("admin"));
String andyJson = jsonb.toJson(andy);
System.out.println(andyJson); // prints: {"age":77,"id":1234,"name":"Andy","roles":["admin"]}

// Convert JSON --> POJO
String jsonData = "{\"age\":55,\"id\":5678,\"name\":\"Hank\",\"roles\":[\"member\"]}";
User hank = jsonb.fromJson(jsonData, User.class);

Customize mappings

By default, JSON property names match Java field or method names. If this is not wanted or possible, new mappings can be defined:

// maps the 'name' field to the 'fullName' JSON property
@JsonbProperty("fullName")
public String name;

// even though the field is public, tell JSON-B to ignore this field so it is not included in the JSON output
@JsonbTransient
public Set<String> roles;

Using JSON-B through JAX-RS

JSON-B works well with JAX-RS because JAX-RS resources often consume or produce JSON data over HTTP, but within endpoints that want to interact with the data as POJOs. The following code example is a simple JAX-RS endpoint that sends and receives information using JSON. However, the implementation of the endpoint works with POJOs, without needing to explicitly translate to and from JSON data.

@Path("/user")
@ApplicationScoped
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class UserService {

    @Inject
    UserDB db;

    @GET
    @Path("/{userId}")
    public User getUserById(@PathParam("userId") String id) {
        User u = db.get(id);
        return u;
        // returned User object will be converted to JSON data using JSON-B
    }

    @POST
    @Path("/{userId}")
    public String createUser(User updatedUser, @PathParam("userId")) {
        // The incoming 'updatedUser' parameter gets read from the incoming
        // request body's JSON data and automatically converted to a User object
        updatedUser.id = // generate an ID
        db.save(updatedUser);
        return updatedUser.id;
    }
}

Where to next?

Now that you’ve seen how JSON-B works, learn how to use it to create a RESTful web service. Check out the REST guides written by our team.