fumeng
fumeng

Reputation: 1820

How to model hierarchical json in java

I'm a front end developer who is brand new to backend development. My task is to model json in a Java object. It's just some mock data for now that my controller returns.

{
   "data":{
      "objectId":25,
      "columnName":[
         "myCategory",
         "myCategoryId"
      ],
      "columnValues":[
         [
            "Category One",
            1
         ],
         [
            "Category Two",
            2
         ],
         [
            "Category Three",
            3
         ],
         [
            "Category Four",
            4
         ],
         [
            "Category Five",
            5
         ]
      ]
   }
}

And here's my attempt. The controller returns this json correctly. But isn't this too simple? What I believe should be done is extrapolate the columnName and columnValues arrays into separate classes but I'm not sure how.

package com.category;

import java.util.List;

public class MyObjectData {
    private int objectId;
    private List columnName;
    private List columnValues;

    public int getObjectId() {
        return objectId;
    }
    public void setObjectId(int objectId) {
        this.objectId = objectId;
    }

    public List getColumnName() {
        return columnName;
    }

    public void setColumnName(List colName) {
        this.columnName = colName;
    }

    public List getColumnValues() {
        return columnValues;
    }

    public void setValues(List values) {
        this.columnValues = values;
    }

}

Regarding the columnNames and columnValues, I feel like I should be doing something like this in the model instead:

private List<ColumnNames> columnNames;
    private List<ColumnValues> columnValues;

    public List<ColumnNames> getColumnNames() {
        return columnNames;
    }

    public void setColumnNames(List<ColumnNames> columnNames) {
        this.columnNames = columnNames;
    }

    public List<ColumnValues> getColumnValues() {
        return columnValues;
    }

    public void setColumnValues(List<ColumnValues> columnValues) {
        this.columnValues = columnValues;
    }

And then I'd have two separate classes for them like this:

package com.category;

import java.util.List;

public class ColumnName {

    private String columnName;

    public String getColumnName() {
        return columnName;
    }

    public void setColumnName(String columnName) {
        this.columnName = columnName;
    }

}

package com.category;

import java.util.List;

public class ColumnValue {

    private String columnValue;
    private int columnValueId;

    public String getColumnValue() {
        return columnValue;
    }

    public void setColumnValue(String columnValue) {
        this.columnValue = columnValue;
    }

    public String getColumnValueId() {
        return columnValueId;
    }

    public void setColumnValueId(int columnValueId) {
        this.columnValueId = columnValueId;
    }

}

I feel like I have all the right pieces but just not sure if this is a better approach than my initial attempt...which works. Just looking for input. Thanks in advance.

Upvotes: 0

Views: 220

Answers (1)

Behrang Saeedzadeh
Behrang Saeedzadeh

Reputation: 47933

In your structure, columnValues is actually the rows of your table that has two columns: myCategory and myCategoryId.

A more "object oriented" Java class could be something like this instead:

public class MyObjectData {

    private int objectId;

    private List<MyObjectRow> columnValues; // I would have named this as rows

}

public class MyObjectRow {

    private String myCategory;

    private String myCategoryId;

}

Now you need a custom serializer to turn this into your expected JSON structure:

public class MyObjectDataSerializer extends StdSerializer<MyObjectData> {

    public MyObjectDataSerializer() {
        super(MyObjectData.class);
    }

    public void serialize(MyObjectData value, JsonGenerator generator, SerializerProvider provider) throws IOException {
        generator.writeStartObject();
        generator.writeNumberField("objectId", value.getObjectId());

        generator.writeArrayFieldStart("columnName");
        generator.writeString("myCategory");
        generator.writeString("myCategoryId");
        generator.writeEndArray();

        generator.writeArrayFieldStart("columnValues");
        for (MyObjectRow row : value.getColumnValues()) {
            generator.writeStartArray();
            generator.writeString(row.getMyCategory());
            generator.writeNumber(row.getMyCategoryId());
            generator.writeEndArray();
        }
        generator.writeEndArray();


        generator.writeEndObject();
    }
}

Note: You can use reflection to extract the field names and values dynamically.

Then you can serialize MyObjectData objects into your expected form:

public class MyObjectDataSerializerTest {

    @Test
    public void shouldCustomSerializeMyObjectData() throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        SimpleModule module = new SimpleModule();
        module.addSerializer(MyObjectData.class, new MyObjectDataSerializer());
        mapper.registerModule(module);

        MyObjectData myObjectData = new MyObjectData();
        myObjectData.setObjectId(25);
        myObjectData.setColumnValues(Arrays.asList(
                new MyObjectRow("Category One", 1),
                new MyObjectRow("Category Two", 2),
                new MyObjectRow("Category Three", 3)
        ));


        String serialized = mapper.writeValueAsString(myObjectData);

        assertThat(serialized, equalTo("{\"objectId\":25,\"columnName\":[\"myCategory\",\"myCategoryId\"],\"columnValues\":[[\"Category One\",1],[\"Category Two\",2],[\"Category Three\",3]]}\n"));
    }

}

Upvotes: 1

Related Questions