0

I have following classes

public class Car {
     private String make; 
     private String model; 
     
     private TransmissionType transmissionType; // Manual/Automatic
     private Transmission transmission; 
}

public class Transmission {
}

public class AutomaticTransmission {
     public Technology technology; // DCT/CVT/AMT
}

public class ManualTransmission {
     public int numGears; 
}

In this example, when the payload passed could be

{
    "make": "Toyota", 
    "model": "Iris", 
    "transmissionType": "Automatic", 
    "transmission" {
         "technology": "DCT"
    }
}

or it could be

{
    "make": "Merc", 
    "model": "C", 
    "transmissionType": "Manual", 
    "transmission" {
         "numGears": 5
    }
}

When this is passed to controller as body, it should be able to create respective class. How do I achieve this.

I tried using JsonTypeInfo and JsonSubTypes as shown in this answer but it necessitates me to move transmissionType within Transmission class, which is not the case for me.

Ganesh Satpute
  • 3,664
  • 6
  • 41
  • 78
  • You can use custom deserializer with annotation.https://stackoverflow.com/questions/11747370/jackson-how-to-process-deserialize-nested-json – Gurkan İlleez Jan 14 '21 at 08:12

2 Answers2

1

You're looking for @JsonTypeInfo(include = As.EXTERNAL_PROPERTY) Transmission transmission. This tells Jackson to look for the property that defines the type in the containing object.

That said, if you have any opportunity of changing your JSON shape, you should avoid "externally tagged types" like this and put the type property into the object.

chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152
0

With help of @chrylis's pointers.

I wrote the code as below

class Car { 
    ... 
    private TransmissionType transmissionType;
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "transmissionType")
    private Transmission transmission; 
}
@JsonSubTypes({
        @JsonSubTypes.Type(value = AutomaticTransmission.class, name = "AUTOMATIC"),
        @JsonSubTypes.Type(value = ManualTransmission.class, name = "MANUAL")
})
public abstract class Transmission {
}

Few gotchas I found, mentioning FYI.

If you put JsonSubTypes on the field in Car class, Swagger documentation won't work. If you put, @JsonTypeInfo on the class Transmission then SpringBoot won't recognise the field "transmissionType".

Ganesh Satpute
  • 3,664
  • 6
  • 41
  • 78
  • 1
    Thanks Ganesh & @chrylis-cautiouslyoptimistic, Really very helpful knowledge for me It is working with RequestBody. In my case, I have to upload a file along with data. I've tried the same with ModelAttribute but, It is not working. Is there any way to achieve the same with ModelAttribute too. – Raj Chauhan Feb 21 '22 at 04:48
  • As per my information, you can't upload file with data unless you move everything to form fields from JSON. Better way is to upload the file separately and send the URL along with the REST request. I've worked on the cases, where files are uploaded along with fields using forms but it becomes to cumbersome. I'd suggest not to do that. – Ganesh Satpute Feb 22 '22 at 05:38