0

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.

Behrang
  • 46,888
  • 25
  • 118
  • 160
fumeng
  • 1,771
  • 5
  • 22
  • 61
  • Are you using a 3rd party library to parse the JSON? I would suggest using Jackson and ObjectWriter – EDToaster Jun 22 '19 at 00:00
  • 2
    Perhaps this question is better-suited for the [Code Review site](https://codereview.stackexchange.com/)? – blurfus Jun 22 '19 at 00:00
  • @jclassic - we use Jackson. – fumeng Jun 22 '19 at 00:02
  • 1
    It seems like `columnName` can just be `List` . As for nested lists, check out this answer [here](https://stackoverflow.com/questions/19580856/jackson-list-deserialization-nested-lists) – EDToaster Jun 22 '19 at 00:03
  • Thanks @JClassic - I like the solution on the page you recommended for nested lists but because my nested list only has values, i.e. 'Category One' and '1' but doesn't have keys...I don't know how I would define my 'innerItems' class. Do you know? – fumeng Jun 22 '19 at 01:13
  • @ochi - Thank you, I will move this post over there. – fumeng Jun 22 '19 at 01:13
  • 1
    A side note as you're new to Java, data structures (such as `List`) _can_ be generic, but they should be typed (they're a `Collection` of type `Object` by default). – Wheeler Jun 22 '19 at 04:10

1 Answers1

1

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"));
    }

}
Behrang
  • 46,888
  • 25
  • 118
  • 160