Specify output attributes for generated JSON for polymorphic associations

67 Views Asked by At

I linked 2 tables to its common one using polymorphic association:

@BelongsToPolymorphic(parents = {Application.class, SiteSection.class})
public class Parameter extends Model {
    static {
        validatePresenceOf("parent_id", "parent_type");
    }
}

The query used in the controller is like that:

String siteSettingsParameters = SiteSection.where("site_id=?", site.getId()).include(Parameter.class).toJson(false);

The result JSON contains children node:

[
    {
        "id": 253,
        "section_id": 60,
        "site_id": 61,
        "children": {
            "parameters": [
                {
                    "created_at": "2017-12-19T15:50:28Z",
                    "id": 145,
                    "parent_id": 253,
                    "parent_type": "app.models.SiteSection",
                    "updated_at": "2017-12-19T15:50:28Z",
                    "value": "Terrible Swift Sword"
                }
            ]
        }
    },  
    {
        "id": 254,
        "section_id": 61,
        "site_id": 61,
        "children": {
            "parameters": [
                {
                    "created_at": "2017-12-19T15:50:28Z",
                    "id": 146,
                    "parent_id": 254,
                    "parent_type": "app.models.SiteSection",
                    "updated_at": "2017-12-19T15:50:28Z",
                    "value": "Sleep the Brave"
                }
            ]
        }
    },
...]

Is it possible to skip the children node in a Java class to map to the above JSON ?

Here is the content of the java class I'd like to map the JSON (I omitted the accessors methods):

@JsonIgnoreProperties(ignoreUnknown = true)
public class SiteSectionDTO {
    private Integer id;
    private SectionDTO section;
    private SiteDTO site;

    @JsonProperty("children")
    private List<ParameterDTO> parameters;
...
accessors come here

Thank you.

1

There are 1 best solutions below

4
On

You can do this in one of two ways:

  1. Write getter methods on your models, and use Jackson to generate JSON rather than rely on a built-in mechanizm.
  2. Use ActiveWeb views and partials to generate your JSON.

I personally opt for the second approach since it is already built into the framework, and is the most flexible and readable.

Let's say you need to return people and their addresses. Here is your PeopleController#index() method:

public void index(){
   view("people", Person.findAll().include(Address.class).orderBy("id"));
   render().contentType("application/json");
}

As you can see, we use an include() method to pre-cache addresses.

The index.ftl view looks like this:

[<@render partial="person" collection=people spacer="comma"/>]

Now, pay attention here.The first and last characters are [ and ], which are brackets identifying an array in JSON. The content is a partial called person. This will be automatically invoked for every value in a collection 'people', and their contents will be interleaved by a content from a partial comma.

Lets see the contents of a partial person:

{
   "id" : ${person.id},
   "first_name" : "${person.first_name}",
   "last_name" : "${person.last_name}",
   "addresses" : [<@render partial="address" collection=person.getAddresses() spacer="comma"/> ]
}

ActiveWeb automatically has an object available named by the name of the partial itself, in this case person.

Here you can make choices as far as what property to display and in what order. The addresses collection uses the same technique, and just calls the address partial with a collection person.getAddresses(). The contents of a comma partial is a single character: ,.

You can examine/run example app REST service build in JavaLite/ActiveWeb: https://github.com/javalite/activeweb-rest/tree/master/src/main/webapp/WEB-INF/views/people

If you run this sample app and follow the steps in the README file, you will see this JSON in your output:

[
  {
    "id": 1,
    "first_name": "Marylin",
    "last_name": "Monroe",
    "addresses": [
      {
        "address_type": "residential",
        "address1": "123 Pine St",
        "address2": "Apt 3",
        "city": "Chicago",
        "state": "IL",
        "zip": "60606"
      },
      {
        "address_type": "shipping",
        "address1": "135 S LaSalle St",
        "address2": "",
        "city": "Chicago",
        "state": "IL",
        "zip": "60604"
      }
    ]
  },
  {
    "id": 2,
    "first_name": "John",
    "last_name": "Kennedy",
    "addresses": [
      {
        "address_type": "residential",
        "address1": "456 Pine St",
        "address2": "Apt 5",
        "city": "Chicago",
        "state": "IL",
        "zip": "60606"
      },
      {
        "address_type": "shipping",
        "address1": "200 N LaSalle St",
        "address2": "",
        "city": "Chicago",
        "state": "IL",
        "zip": "60604"
      }
    ]
  }
]

I hope it helps