Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @RequestBody inheritance

I've read several posts where this was tried to be explained, but I couldn't get it working. I have a scenario where the input JSON to my service can be of several subtypes. Basically, I have a base class UserDto and then ClientDto and OwnerDto both of which extend from UserDto. I'd like to achieve that the controller is able to resolve concrete subtype of UserDto into object of the correct class. So something like this.

@ResponseStatus(HttpStatus.OK)
    @RequestMapping(value = "/", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public void doSomething(@RequestBody UserDto user) {
        ClientDto client = (ClientDto) user;
        // do something
    }

I tried something like this. Basically I want to determine the type of the concrete object by the field profileType which is of type enum ProfileType with values OWNER and CLIENT.

UserDto.java

@JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY, property = "profileType", visible = true)
@JsonSubTypes({
    @JsonSubTypes.Type(value = ClientDto.class, name = "Client"),
    @JsonSubTypes.Type(value = OwnerDto.class, name = "Owner")
})
public class UserDTO {

    @NotNull
    @Size(min = 0, max = 256)
    private ProfileType profileType;

    @NotNull
    @Size(min = 0, max = 512)
    private String email;

    // ...
}

ClientDto.java

public class ClientDto extends UserDto {

    private Integer salary;

    private Integer efficiency;

    // ... 
}

I tried posting the following JSON to this end-point.

{
        "email": "[email protected]",
        "profileType": "CLIENT",
        "salary": "100",
        "efficiency": "99"
    }

And I expected this to be resolved to a type of ClientDto. Instead, I only got a 400 Bad Request error.

The questions are:

  1. How do I fix this, and have the @RequestBody inheritance working?
  2. Is there a way to specify annotations on the subtypes rather than defining all of them on the supertype?
like image 282
wesleyy Avatar asked Feb 11 '18 15:02

wesleyy


1 Answers

Couple of mistakes in your code.

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "profileType", visible = true)
@JsonSubTypes({
    @JsonSubTypes.Type(value = ClientDto.class, name = "CLIENT"),
    @JsonSubTypes.Type(value = OwnerDto.class, name = "OWNER")
})
public class UserDTO {
 .....
}
  1. You said ProfileType enum has OWNER and CLIENT. But you have specified in JsonSubTypes.Type as Client and Owner. hence doesn't match
  2. change JsonTypeInfo.Id.CLASS to JsonTypeInfo.Id.NAME
like image 63
pvpkiran Avatar answered Sep 17 '22 16:09

pvpkiran