SpringBoot @RequestBody validation of abstract class

1.3k Views Asked by At

I am trying to simulate the oneOf construct from OpenAPI spec in my spring-boot application. I have an abstract class Apple

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "color")
@JsonSubTypes({
        @JsonSubTypes.Type(value = RedApple.class, name = "RED"),
        @JsonSubTypes.Type(value = GreenApple.class, name = "GREEN")
})
public abstract class Apple {

    @NotNull
    private Color color;

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public enum Color {
        RED, GREEN
    }
}

and two subclasses

public class RedApple extends Apple {

}

public class GreenApple extends Apple {

}

Also here is my rest controller

@RestController
@RequestMapping("/apples")
public class AppleController {

    @PostMapping
    public ResponseEntity<Void> createApple(@Valid @RequestBody Apple apple) {
        return ResponseEntity.created(URI.create("/foo")).build();
    }
}

The problem is that @Valid does not validate the enum field correctly. Even if I send {"color": "RED"} as a body, the validation fails with a message saying that color must not be null

When I do the exact same thing with a non-abstract class and without JsonSubTypes & JsonTypeInfo annotations everything works like a charm. What am I missing here?

Thanks

2

There are 2 best solutions below

0
Poklakni On BEST ANSWER

adding visible = true as parameter to the JsonTypeInfo solved the issue @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, visible = true, property = "color")

2
Deb Das On

The object you are trying to create is of the abstract class, as we know Abstract classes cannot be instantiated the whole idea of abstraction is to refrain from access of that class itself, instead if you pass the class object which has implemented the abstract class would solve your issue

eg to pass RED

 public ResponseEntity<Void> createApple(@Valid @RequestBody RedApple apple) {
        return ResponseEntity.created(URI.create("/foo")).build();
    }