6

I'm using Jackson to serialize/deserialize JSON objects.

I have the following JSON for a Study object:

{
    "studyId": 324,
    "patientId": 12,
    "patient": {
        "name": "John",
        "lastName": "Doe"
    }
}

UPDATE: Unfortunately the JSON structure cannot be modified. It's part of the problem.

I would like to deserialize the object to the following classes:

public class Study {
    Integer studyId;
    Patient patient;
}

and

public class Patient {
    Integer patientId;
    String name;
    String lastName;
}

Is it possible to include the patientId property in the Patient object?

I am able to deserialize the patient object into the Patient class (with the corresponding name and lastName properties), but unable to include the patientId property.

Any ideas?

Jackall
  • 1,120
  • 1
  • 9
  • 18
monsieurBelbo
  • 727
  • 1
  • 8
  • 16
  • I really don't know if Jackson is going to like this but you could try putting `Patient` as an inner class in `Study` and implement `getPatientId()` as `return Study.this.patientId` in order to make it seem as if the data is where it would have belonged in the first place. (No. I wouldn't do this if I don't must.) – Scheintod Oct 04 '13 at 22:02

4 Answers4

7

You can use a custom deserializer for your use case. Here is what it will look like:

import java.io.IOException;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;

public class StudyDeserializer extends JsonDeserializer<Study>
{
    @Override
    public Study deserialize(JsonParser parser, DeserializationContext context)
        throws IOException, JsonProcessingException
    {
        JsonNode studyNode = parser.readValueAsTree();

        Study study = new Study();
        study.setStudyId(studyNode.get("studyId").asInt());

        Patient patient = new Patient();
        JsonNode patientNode = studyNode.get("patient");
        patient.setPatientId(studyNode.get("patientId").asInt());
        patient.setName(patientNode.get("name").asText());
        patient.setLastName(patientNode.get("lastName").asText());
        study.setPatient(patient);

        return study;
    }
}

Specify the above class as your deserializer in the Study class:

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

@JsonDeserialize(using = StudyDeserializer.class)
public class Study
{
    Integer studyId;
    Patient patient;

    // Getters and setters
}

Now, the JSON input you have specified should get deserialized as expected.

Jackall
  • 1,120
  • 1
  • 9
  • 18
  • It will break very soon since hard-coded field names are used in the code. New fields added(or removed) - Change, Field name use snake case - change. :( There should be some declarative way. – Nilesh Jan 05 '18 at 07:12
1

There is no declarative way to do such object transformation: you are transforming structure between JSON and POJOs. Jackson's support in this area is limited by design: two things are out of scope: validation (use external validation; Bean Validation API or JSON Schema validator) and transformations (can use JsonNode or external libraries).

StaxMan
  • 113,358
  • 34
  • 211
  • 239
0

Depending on how stable this format is (and in what mood your QA guy is) you could alter the Json directly before passing it to Jackson. This would be fixing what is broken. Regex would be one idea. Reading it in a Hashmap, moving the value there and writing it out as fixed Json another. But even more simple in pseudocode:

String json = "...";
String lines = json.split( "\r" );
swap( lines[2], lines[3] ); //*1
String fixed = join( lines ); //*2

where

*1: tmp = lines[2]; lines[2] = lines[3]; lines[3] = tmp;
*2: http://stackoverflow.com/questions/1515437/java-function-for-arrays-like-phps-join

(if I had to take this route I would use the hashmap aproach)

Scheintod
  • 7,953
  • 9
  • 42
  • 61
  • The JSON structure cannot be modified since it comes from an external source. Check the update to the question. – monsieurBelbo Oct 04 '13 at 22:16
  • 1
    Yes, you wrote this. This answer is about modifing it *after you got it*. And yes, this is ugly but could work depending on the nature of your project. – Scheintod Oct 04 '13 at 22:19
-1

You have your patientId stored outside of your patient object. Put it in and everything is shiny ;)

If you insist on putting it exactly there in the json I'm afraid you are in trouble. (Best would be to convince the Json designer to store it where it belongs which is in the Patient object as you have it in Java.)

If nothing helps you have to use a Data Transfer Object (https://en.wikipedia.org/wiki/Data_transfer_object) or a custom deserializer (Setting up JSON custom deserializer) in order to translate between the sane and insane representations.

Community
  • 1
  • 1
Scheintod
  • 7,953
  • 9
  • 42
  • 61