1

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

Poklakni
  • 193
  • 2
  • 10

2 Answers2

1

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

Poklakni
  • 193
  • 2
  • 10
0

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();
    }
Deb Das
  • 264
  • 1
  • 7
  • That would solve the error, but not the problem. To ensure the correct subclass is instantiated there are JsonTypeInfo and JsonSubTypes annotations on the abstract class. The Color enum is a discriminant for this purpose @Deb Das – Poklakni Apr 11 '22 at 16:42
  • please add this ```@Bean public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.enable(MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL); jsonConverter.setObjectMapper(objectMapper); return jsonConverter; }``` its a feature that you need to enable in order to directly deserialize the object using concrete subclass without type information – Deb Das Apr 11 '22 at 16:49