Skip to content

Is there a way for springdoc-openapi to determine Schema discriminatorProperty / discriminatorMapping purely from @JsonTypeInfo / @JsonSubTypes ? #2999

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
bmr-exerp opened this issue May 21, 2025 · 3 comments

Comments

@bmr-exerp
Copy link

bmr-exerp commented May 21, 2025

As title. I'm working on an API in Spring Boot 2.7.17, using springdoc 1.8.0. It seems like I am forced to effectively duplicate my schema specification between @Schema and @JsonTypeInfo, which leaves a sour taste.

@Schema(
	subTypes = {
		Foo1.class,
		Foo2.class,
	},
	discriminatorProperty = "fooType",
	discriminatorMapping = {
		@DiscriminatorMapping(value = "foo1", schema = Foo1.class),
		@DiscriminatorMapping(value = "foo2", schema = Foo2.class),
	})
@JsonTypeInfo(
	use = JsonTypeInfo.Id.NAME,
	visible = true,
	include = JsonTypeInfo.As.EXISTING_PROPERTY,
	property = "fooType")
@JsonSubTypes({
	@Type(value = Foo1.class, name = "foo1"),
	@Type(value = Foo2.class, name = "foo2"),
})
public interface AbstractFoo {
	String getFooType();
}

As is evident, the information on the @Schema annotation exactly matches (and therefore must be kept in sync with) the Jackson type information on JsonTypeInfo and JsonSubTypes. Is there a way to get springdoc to build subschema 'routing' documentation without reiterating myself here?

@Mattias-Sehlstedt
Copy link

More recent versions of springdoc-api introspects the JsonTypeInfo annotation and will construct an allOf-polymorphic schema based upon that information (the drawback is instead that an invalid schema will be generator if there is both a Json-annotation and a Schema annotation that contains a oneOf definition.

See discussion under this issue as an example #2915.

@bmr-exerp
Copy link
Author

Hi @Mattias-Sehlstedt , thanks for getting back to me.

I tried it with a greenfields Spring Boot app, running Java 24, spring-boot-starter-web 3.4.5, and org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8.

While it's correctly showing the discriminator property name, it doesn't add the @JsonSubTypes.Type#name to the discriminator mapping for each subtype.

"discriminator": {
    "propertyName": "fooType"
},

This means I have the 'base' request type, Foo, and the generated schema correctly identifies that the REST controller accepts oneOf [Foo1, Foo2], but that's it. There's no information at all about what magic value for fooType would be required to resolve Foo to either of its subtypes.


As an aside, I don't know if this is how the spec actually works, but given an explicit discriminator mapping via @Schema, ideally I would want the following behaviour:

  • for any given subtype, S, of type T, where:
    • the discriminator property of T is discProp
    • the discriminator mapping of S is some value V
  • then the schema documentation for S should indicate that the only allowed value for discProp is V.

Right now, I do this 'manually'. Example:

@JsonTypeInfo(...property = "fooType")
@JsonSubTypes({
	@Type(value = Foo1.class, name = "foo1"),
})
interface Foo {
    String getFooType();
}

class Foo1 implements Foo {

    @Override
    @Schema(allowableValues = "foo1")
    public final String getFooType() {
        return "foo1";
    }
}

to force the schema to say "If you want to send the API a request of type Foo1, the value of fooType must be 'foo1'". But doing this on all my polymorphic types is a bit of a slog.

Assuming all of the discriminator value / discriminator mapping stuff works as intended, is this the sort of behaviour I should expect?

Would it help if I pushed my findings to a repository for someone such as yourself to sanity check?

@Mattias-Sehlstedt
Copy link

I have so far always relied on my consumers being understanding of the implicit expectation on a discriminator property:

It is implied, that the property to which discriminator refers, contains the name of the target schema.

taken from the section Mapping Type Names at swagger.io.

So I would say it becomes a question of whether your consumers could understand this contract if you were simply to add a general "discriminator properties" section in the service description that covers this behavior. Or is it necessary that the schema object itself exactly states this?

It is of course a different scenario if you cannot ensure that the schema name is the same as the object name, since they you would need an explicit discriminator mapping, but I generally try to always avoid placing myself in that situation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants