Skip to content

Formatting your output as JSON

julgus edited this page Apr 6, 2018 · 11 revisions

Often when you write database applications you will need to send different output to a client app. There are many protocols for sending results over a network. One of the most common is json.

Speedment can handle JSON output using the json plugin.

Single entity

// Single user as json.
User user = ...;
String json = allOf(users).apply(user);

Multiple entities

Using method references, this can be done inline in the stream declaration.

// List of all users as json.
List<String> userJsonList = users.stream()
    .map(JsonEncoder.allOf(users)::apply)
    .collect(toList());

If you want to parse the complete result to one single json array, simply call collect.

// Json array of all users.
String many = users.stream().collect(JsonCollector.toJson(allOf(users)));

Choose which data to include

Often you don't want every column to be included in the json output. In the User example above, you might have hashed passwords and other sensitive user information that you don't want to expose. Limiting which columns to expose is easy using the JsonEncoder-object.

// Only include the first and last name of users.
JsonEncoder<User> encoder = JsonEncoder.noneOf(users)
    .put(User.FIRSTNAME)
    .put(User.LASTNAME);
        
String json = users.stream().collect(JsonCollector.toJson(encoder));

Follow foreign-keys

The encoder can be configured to follow foreign keys. In this example, we also want to include all the images posted by every user in the json output. In the database, each Image has a foreign key to a User. Speedment uses this to create a backward stream from User to Image.

// Include a list of image titles for each user.
JsonEncoder<User> encoder = JsonEncoder.noneOf(users)
    .put(User.FIRSTNAME)
    .put(User.LASTNAME)
    .put("images", (user, imageManager) -> users.findImages(users), JsonFormatter.noneOf(images)
        .put(Image.TITLE)
    );

String json = User.stream().collect(CollectorUtil.toJson(encoder));

Result

[
    {
        "firstname" : "Spire",
        "lastname" : "Harrysson",
        "images" : [
            {"title" : "sunset.jpg"},
            {"title" : "desert.jpg"},
            ...
            {"title" : "forest.jpg"}
        ]
    },
    ...
]

Grab all columns

If you don't want to add every single column manually, you can simply include all in the creation of the encoder object.

// Include all columns in the table 'User'
JsonEncoder<User> encoder = JsonEncoder.allOf(users);

Sometimes you want to use all the columns except for some that might contain sensitive data. In those cases, the .remove()-method is handy.

// Include all columns in the table 'User' except 'password'
JsonEncoder<User> encoder = JsonEncoder
    .allOf(users)
    .remove(User.PASSWORD)
;

If you put() a field association that already in the JsonEncoder, the new field will replace the old one.