为什么鉴别器属性被序列化两次?

时间:2019-08-29 08:35:42

标签: java jackson swagger swagger-codegen openapi-generator

我在组件模式中使用OpenAPI 3.0继承,并且我有openapi-generator(使用Jackson)生成的(Java)类。

为什么discriminator属性在生成的JSON中被序列化两次?

这是一个JHipster API-First项目,应该使用openapi-generator来生成Java模型(带有Jackson注释的POJO)和API控制器(带有Spring的@Api注释的接口)。

通过遵循OpenAPI 3.x文档/示例,似乎还必须在模式的discriminator列表中指定用作properties的属性。

这样,生成的Java类似乎与带注释(here的多态类型处理的Jackson准则有所不同,在该准则中,用作鉴别符的属性必须不存在于类中。相反,生成的代码还将此属性作为具有getter / setter的类属性包括在内。这将导致JSON输出两次包含该属性,如下所示。

我还尝试了从OpenAPI properties列表中删除该属性,而保留了discriminator部分;这样,生成的代码符合Jackson的准则,并且序列化工作正常。另一方面,在反序列化过程中出现错误,因为在目标类中找不到(已删除)属性。

遵循OpenAPI 3.x文档准则:

TicketEvent:
  type: object
  description: A generic event
  discriminator:
    propertyName: type
  required:
    - id
    - sequenceNumber
    - timestamp
    - type
  properties:
    id:
      type: integer
      format: int64
      readOnly: true
    sequenceNumber:
      type: integer
      readOnly: true
    timestamp:
      type: string
      format: date-time
      readOnly: true
    type:
      type: string
      readOnly: true
TicketMovedEvent:
  description: A ticket move event
  allOf:
    - $ref: '#/components/schemas/Event'
    - type: object
      required:
        - source
        - target
      properties:
        source:
          $ref: '#/components/schemas/Queue'
        target:
          $ref: '#/components/schemas/Queue'

生成的类:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type", visible = true)
@JsonSubTypes({
  @JsonSubTypes.Type(value = TicketMovedEvent.class, name = "TicketMovedEvent")
})

public class TicketEvent   {
   ...

   @JsonProperty("type")
   private String type;

JSON包含属性两次

{
        ...
    "type": "TicketMovedEvent",
    "type": null,
        ...
}

properties列表中删除鉴别属性:

TicketEvent:
  type: object
  description: A generic event
  discriminator:
    propertyName: type
  required:
    - id
    - sequenceNumber
    - timestamp
  properties:
    id:
      type: integer
      format: int64
      readOnly: true
    sequenceNumber:
      type: integer
      readOnly: true
    timestamp:
      type: string
      format: date-time
      readOnly: true

不具有type属性的生成的类:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type", visible = true)
@JsonSubTypes({
  @JsonSubTypes.Type(value = TicketMovedEvent.class, name = "TicketMovedEvent")
})

public class TicketEvent   {
   ...

   // now the "type" property is missing
})

JSON现在是正确的:

{
        ...
    "type": "TicketMovedEvent",
        ...
}

但是在反序列化期间,出现以下错误:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "type" (class it.blutec.bludesk.web.api.model.TicketMovedEvent), not marked as ignorable ...

我希望遵循OpenAPI 3.x准则,可以正确地对生成的类进行序列化/反序列化。

4 个答案:

答案 0 :(得分:1)

我自己碰到了这个。实际上,在OpenApi属性列表中不包括discriminator字段确实可以解决序列化时的双字段问题,同时在反序列化时导致UnrecognizedPropertyException。 经过反复试验,我发现可以通过在生成的代码中删除"visible = true"批注的@JsonTypeInfo属性(或将其设置为false)来解决第二个问题。 (如果您有构建过程的设置,可以始终根据开放的API规范重新生成代码,那么,这当然不是真正的解决方案。)

答案 1 :(得分:1)

我相信我在https://github.com/OpenAPITools/openapi-generator/pull/5120中解决了该问题,该问题应该与openapi-generator 4.3版本一起发布。随时检查一下(由于该PR,oneOf支持也应大大改善)。

答案 2 :(得分:0)

我刚遇到同样的问题。问题出在生成的模型类上的@JsonTypeInfo注释上。

其生成方式为-

@JsonTypeInfo(... include = JsonTypeInfo.As.PROPERTY ...)

这会在模型中添加一个额外的属性。

如果我在生成的代码中将其更改为-

@JsonTypeInfo(... include = JsonTypeInfo.As.EXISTING_PROPERTY ...)

它使用模型中已经存在的属性,并且一切正常。

但是,当我重新生成代码时,此更改当然会丢失。 如果有人找到了永久解决方案,那就太好了。

答案 3 :(得分:0)

只想为 Soham 的回答中描述的问题添加一个解决方法。

如果您使用 spring-boot-maven-plugin,您可以覆盖项目中的 mustache 模板以修复生成的代码。

在项目的根目录中添加一个名为 openapi-generator-templates 的文件夹。

在 pom.xml 文件中,在插件的配置节点(NOT configOptions)中添加这一行

<templateDirectory>${project.basedir}/openapi-generator-templates</templateDirectory>

在文件夹内从 Github 上的 openapi-generator project 复制 mustache 模板。

我使用的是 kotlin-spring 生成器,所以对我来说模板是 here

编辑小胡子文件,将 JsonTypeInfo.As.PROPERTY 替换为 JsonTypeInfo.As.EXISTING_PROPERTY

(作为旁注,要在 kotlin-spring 生成器中进行继承,您还应该对 dataClass.mustache 模板使用类似的解决方法。有关此错误 here 的更多信息)。

相关问题