smallrye / smallrye-open-api

SmallRye implementation of Eclipse MicroProfile OpenAPI
Apache License 2.0
117 stars 89 forks source link

OpenAPI generation of JsonView annotated classes or Ignored fields does not work #1764

Open AlanSage11 opened 6 months ago

AlanSage11 commented 6 months ago

The issue here shows a previous problem where OpenAPI was not respecting fields annotated with @JsonView. The applied fix seems to work for simple cases, but does not work when a class is annotated with @JsonView or if the ObjectMapper is set not to add fields to views by default. Examples are in Kotlin/Quarkus, using version 3.10.0 of smallrye-open-api via Quarkus 3.8.1.

Example 1 (works as expected):

    @JsonView(View.Public::class)
    @GET
    @Path("/public")
    fun userPublic(): User? {
        return User().also {
            it.id = 123
            it.name = "Person"
        }
    }

    class User {
        @JsonView(View.Private::class)
        var id = 0

        @JsonView(View.Public::class)
        var name: String? = null
    }

    class View {
        open class Public
        class Private : Public()
    }

Endpoint /public returns {"name":"Person"} Generated type schema (as expected):

    User_Public:
      type: object
      properties:
        name:
          type: string
          nullable: true

Example 2 (annotate class definition with @JsonView):

    @JsonView(View.Public::class)
    @GET
    @Path("/public")
    fun userPublic(): User? {
        return User().also {
            it.id = 123
            it.name = "Person"
        }
    }

    @JsonView(View.Private::class)
    class User {
        var id = 123

        @JsonView(View.Public::class)
        var name: String? = null
    }

    class View {
        open class Public
        class Private : Public()
    }

Endpoint /public returns {"name":"Person"} (as expected) Generated type schema (Note: id field should not be shown here):

    User_Public:
      type: object
      properties:
        id:
          format: int32
          type: integer
        name:
          type: string
          nullable: true

Example 3 (change ObjectMapper to exclude fields from @JsonView by default):

ObjectMapper can be setup as follows to exclude fields by default from @JsonView:

@Singleton
class RegisterCustomModuleCustomizer : ObjectMapperCustomizer {
    override fun customize(mapper: ObjectMapper) {
        mapper.apply {
            disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
        }
    }
}

Neither the id field or the User class now need to be annotated to be ignored by Jackson:

    @JsonView(View.Public::class)
    @GET
    @Path("/public")
    fun userPublic(): User? {
        return User().also {
            it.id = 123
            it.name = "Person"
        }
    }

    class User {
        var id = 123

        @JsonView(View.Public::class)
        var name: String? = null
    }

    class View {
        open class Public
        class Private : Public()
    }

Endpoint /public returns {"name":"Person"} (as expected) Generated type schema (Note: id field should not be shown here):

    User_Public:
      type: object
      properties:
        id:
          format: int32
          type: integer
        name:
          type: string
          nullable: true
MikeEdgar commented 6 months ago

Thanks for the issue. I think the class-level annotation handling should be an easy fix for the next release. The ObjectMapper functionality will probably need to be handled as a configuration property since the scanner doesn't have knowledge of or a reference to the runtime mapper the application is using.