1

I need a Java data structure for some JSON data passed to me by the Datatables Editor. The format of the data received is this:

{
    "action":"edit",
    "data": {
        "1009558":{
            "weekNumber":"2"
            ... (more properties)
         }
     }
}

Here's the full documentation: https://editor.datatables.net/manual/server

Edit: The documentation shows the data sent as form params. I am stringifying the data and sending it as JSON. An example is above.

"1009558" is the row ID. If there are multiple rows sent by the editor, there would be multiple array entries (each with an ID).

Can anyone offer some advice on how to make a Java data structure for deserialization (by Spring MVC)? I can map "action" easy enough, but I'm getting stuck on the "data" element.

Brian Kates
  • 480
  • 4
  • 14
  • Look into Jackson and by creating a custom deserializer. – Murat Karagöz Jun 02 '16 at 14:30
  • Can you provide the full JSON object that you are trying to map (at least for one entry)? – Edd Jun 02 '16 at 14:39
  • Can you double check the sample JSON ? It doesn't look like the examples provided on the website you linked. – JHarnach Jun 02 '16 at 15:00
  • @JHarnach Good point... On the website the example shows the data sent as a form param: action = create data[0][extn] = 2947 data[0][first_name] = .... I'm sending it as JSON though. See my post for an example of what it looks like – Brian Kates Jun 02 '16 at 15:02
  • I added an edit to my original post to hopefully add some clarity – Brian Kates Jun 02 '16 at 15:07

3 Answers3

1

I'm a huge fan of Joe Littlejohn's JSON tool. Provide it with a sample JSON file and it can generate POJOs for you.

Here's a sample of what it generated, based on a snipped of JSON from the site you posted.

JSON:

{
"data": [
    {
        "DT_RowId":   "row_29",
        "first_name": "Fiona",
        "last_name":  "Green",
        "position":   "Chief Operating Officer (COO)",
        "office":     "San Francisco",
        "extn":       "2947",
        "salary":     "850000",
        "start_date": "2010-03-11"
    }
]

}

JAVA:

@Generated("org.jsonschema2pojo")
public class Datum {

    public String dTRowId;
    public String firstName;
    public String lastName;
    public String position;
    public String office;
    public String extn;
    public String salary;
    public String startDate;
}

@Generated("org.jsonschema2pojo")
public class Example {
    public List<Datum> data = new ArrayList<Datum>();
}

Update:

It looks like this is what the form submit actually sends:

action:edit
data[row_1][first_name]:Tiger23
data[row_1][last_name]:Nixon
data[row_1][position]:System Architect
data[row_1][office]:Edinburgh
data[row_1][extn]:5421
data[row_1][start_date]:2011-04-25
data[row_1][salary]:320800

I don't think this is Json, and I dunno if I would try to treat it as such. If you need to submit form data with Java, you might be better of using the Apache HttpComponents. You can reuse the Java "data" object above as a domain object, and then populate the POST content with Strings of the format:

data[ \DT_RowId\ ][\PropertyName\]: \PropertyValue\
JHarnach
  • 3,944
  • 7
  • 43
  • 48
  • `data` property seems to be a Map instead of a List – Edd Jun 02 '16 at 14:47
  • @Edd I'd assumed that was a typo in his example, the examples on the site linked show "data" to be an array. – JHarnach Jun 02 '16 at 15:00
  • @JHarnach It produced not so great java structures using example data: { "action":"edit", "data": { "1009558":{ "weekNumber":"2" }, "1009557":{ "weekNumber":"2" } } } – Brian Kates Jun 02 '16 at 15:14
  • @BrianKates Gotcha, I thought you were trying to parse the response, I'll update my answer. – JHarnach Jun 02 '16 at 15:22
1

I'd rather suggest you to use jackson.

Here's an example, that you're asking for:

package com.github.xsavikx.jackson;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.HashMap;
import java.util.Map;

public class JacksonTest {
    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, DatabaseRow> data = new HashMap<>();
        DatabaseRow row = new DatabaseRow(2, "someData");
        data.put("1009558", row);
        String action = "action";
        DatabaseEntry dbEntry = new DatabaseEntry();
        dbEntry.setAction(action);
        dbEntry.setData(data);
        System.out.println(objectMapper.writeValueAsString(dbEntry));
    }
}

And the result:

{"action":"action","data":{"1009558":{"weekNumber":2,"someData":"someData"}}}

Models:

package com.github.xsavikx.jackson;

import java.util.Map;

public class DatabaseEntry {
    private String action;
    private Map<String, DatabaseRow> data;

    public DatabaseEntry() {

    }

    public DatabaseEntry(String action, Map<String, DatabaseRow> data) {
        this.action = action;
        this.data = data;
    }

    public Map<String, DatabaseRow> getData() {

        return data;
    }

    public void setData(Map<String, DatabaseRow> data) {
        this.data = data;
    }

    public String getAction() {
        return action;
    }

    public void setAction(String action) {
        this.action = action;
    }
}

package com.github.xsavikx.jackson;

public class DatabaseRow {
    private int weekNumber;
    private String someData;
    public DatabaseRow(){
    }
    public DatabaseRow(int weekNumber, String someData) {
        this.weekNumber = weekNumber;
        this.someData = someData;
    }

    public int getWeekNumber() {
        return weekNumber;
    }

    public void setWeekNumber(int weekNumber) {
        this.weekNumber = weekNumber;
    }

    public String getSomeData() {
        return someData;
    }

    public void setSomeData(String someData) {
        this.someData = someData;
    }
}

Update: more generic solution with Map of maps:

package com.github.xsavikx.jackson;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class JacksonTest {
    public static void main(String[] args) throws IOException {
        serializeTest();
        deserializeTest();
    }
    private static void deserializeTest() throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        DatabaseEntry databaseEntry = objectMapper.readValue("{\"action\":\"action\",\"data\":{\"1009558\":{\"weekNumber\":2,\"someData\":\"someData\"}}}", DatabaseEntry.class);
        System.out.println(databaseEntry);
    }

    private static void serializeTest() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String,Map<String,String>> data = new HashMap<>();
        Map<String,String> values = new HashMap<>();
        values.put("weekDay","2");
        values.put("unpredictableValue","value");
        data.put("1009558", values);
        String action = "action";
        DatabaseEntry dbEntry = new DatabaseEntry();
        dbEntry.setAction(action);
        dbEntry.setData(data);
        System.out.println(objectMapper.writeValueAsString(dbEntry));
    }
}

Model: package com.github.xsavikx.jackson;

import java.util.Map;

public class DatabaseEntry {
    private String action;
    private Map<String, Map<String,String>> data;

    public DatabaseEntry() {

    }

    public String getAction() {
        return action;
    }

    public void setAction(String action) {
        this.action = action;
    }

    public Map<String, Map<String, String>> getData() {
        return data;
    }

    public void setData(Map<String, Map<String, String>> data) {
        this.data = data;
    }
}
xSAVIKx
  • 463
  • 4
  • 12
  • I'd like to make the DatabaseRow class a little more generic so I can reuse it for other instances of the Editor. i.e. instead of weekNumber and someData, how about a map of name/value pairs? – Brian Kates Jun 02 '16 at 15:07
  • 1
    @BrianKates, it's up to you now, how to change it with your own requirements. I just suggest you to use jackson (cause it's easy to integrate with Spring MVC) and proposed some examples. You could use Map> or whatever you want for Data field. – xSAVIKx Jun 02 '16 at 15:22
  • Thanks, I like the idea of Map>, but I'll need to wrap my brain around that :) – Brian Kates Jun 02 '16 at 15:23
  • 1
    @BrianKates, I've updated my answer with Map of maps. – xSAVIKx Jun 02 '16 at 15:28
0

With Spring Boot the json conversion between server and client is automatic (https://stackoverflow.com/a/44842806/3793165).

This way is working for me:

Controller

@PostMapping(value="/nuevoVideo")
    @ResponseBody
    public RespuestaCreateVideo crearNuevoVideo(@RequestBody PeticionVideos datos) {
       RespuestaCreateVideo respuesta = new RespuestaCreateVideo();
       respuesta.setData("datos");
       //respuesta.setError("error"); // implement the logic for error and return the message to show to the user.
      return respuesta;
    }

where PeticionVideos (RequestVideos) is the create structure Datatables editor sends (with setters, getters...):

public class PeticionVideos {
    private Map<String, Video> data;
    private String action;
}

The response from the server to the client datatable is waiting for has a particular format (check at https://editor.datatables.net/manual/server).

I often use this:

public class RespuestaCreateVideo { //ResponseCreateVideo
    private String data;
    private String error;
}

After two days trying this is working perfect now!

abanet
  • 1,327
  • 17
  • 22