简体   繁体   中英

Play Framework: Rendering custom JSON objects

I am using Play Framework 1.2.4 with Java and using JPA to persist my database objects. I have several Model classes to be rendered as JSON. But the problem is I would like to customize these JSON responses and simplify the objects just before rendering as JSON.

For instance, assume that I have an object named ComplexClass and having properties id, name, property1,...,propertyN. In JSON response I would like to render only id and name fields.

What is the most elegant way of doing this? Writing custom binder objects or is there simple JSON mapping such as using a template?

Play Framework 1.2.4 directly depends on the gson library so you could use that to render your JSON strings. All you have to do is use gson's @Expose annotation. So in your example, you would mark the fields you want in your JSON string like this:

public class ComplexClass {

    @Expose
    public Long id;

    @Expose
    public String name;

    ...
}

Then in your controller, you would just do this:

public static void someActionMethod() {
    // get an instance of your ComplexClass here
    ComplexClass complex = ...
    Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()
    String json = gson.toJson(complex);
    renderJson(json);
}

See documentation here .

If ComplexClass is actually a play.db.jpa.Model and therefore the id field is abstracted away in a parent class and you can't put the @Expose annotation on it, then you could create your own ExclusionStrategy that skips fields that aren't annotated with @Expose and are not called id . So something like this (pseudo-code):

public final class ComplexClassExclusionStrategy implements ExclusionStrategy {

    public boolean shouldSkipField(FieldAttributes attributes) {
        if (name of field is "id") return false;
        if (field is annotated with @Expose) return false;
        return true;
    }

Then the controller would altered slightly to look like this:

    GsonBuilder builder = new GsonBuilder();
    ComplexClassExclusionStrategy strategy = new ComplexClassExclusionStrategy();
    builder.setExclusionStrategies(strategy);
    Gson gson = builder.create();
    String json = gson.toJson(complex);
    renderJson(json);

Use FlexJSON, it's really easy. It allows you to create JSONSerializers which can include/exclude the fields you want.

Check out this article for some examples of using it with Play! Framework.
Here's a simple example:

public ComplexClass {
   public Long id;
   public String name;
   // And lots of other fields you don't want

   public String toJsonString() {
     // Include id & name, exclude all others.
     JSONSerializer ser = new JSONSerializer().include(
            "id",
            "name",
     ).exclude("*");
    return ser.serialize(this);
  }

}

You can add it to your dependencies.yml like so:

require:
    - play
    - net.sf.flexjson -> flexjson 2.1

What I usually do is write an interface for models that implements a toJSONString() method so that I can call renderJSON(someModel.toJSONString()) in the controller.

Link to official website

EDIT : Extra example for lists/collections

Ok, when you start serializing list you might get some unexpected results. This is because the order of evaluation is important. The first include() or exclude() takes precedence over the following ones.

Here's an example of serializing the childs of a parent entity (OneToMany relation).

JSONSerializer ser = new JSONSerializer();
// Exclude these standard fields from childs
ser.exclude(
    "*.persistent", 
    "*.class",
    "*.entityId"
);
// Include childs and all its other fields
ser.include(
    "childs",
    "childs.*"
);
// Exclude everything else
ser.exclude("*"); 
String data = ser.serialize(parent);

The * is a wildcard by the way. This piece of documentation explains it perfectly:
An exclude of *.class will match to any path depth. So if flexjson is serializing the field with path of "foo.bar.class" the * in *.class will match foo.bar.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM