【问题标题】:How to use Inteface as a field type in Request Body model class in Rest API如何在 Rest API 的 Request Body 模型类中使用 Interface 作为字段类型
【发布时间】:2022-01-01 17:24:53
【问题描述】:

我们有一个 Java SpringBoot API 端点,我们传递了一个 NotifyMoiChanges 类类型的 RequestBody。在 NotifyMoiChanges 模型类中,我们有一个字段是接口类型。

端点 sn-p:

@PostMapping("/notifyMOIChanges")
public ResponseEntity<Void> notifyMOIChangesPost(@RequestBody NotifyMoiChanges notifyMoiChanges) {
        logger.info("Received notifyMOIChanges request.");
        return ResponseEntity.noContent().build();
    }

RequestBody 模型 sn-p:

public class NotifyMoiChanges {
  @JsonProperty("moiChanges")
  @Valid
  private List<MoiChange> moiChanges = new ArrayList<MoiChange>();
  ..... other attributes
}

public class MoiChange   {
      @JsonProperty("operation")
      private String operation = null;   //operation value can be "Type1" or "Type2"
    
      @JsonProperty("value")
      private OneOfMoiChangeValue value = null;   //value filed can be mapped with any of the OneOfMoiChangeValue Interface implentations  Type1MoiChangeValue or Type2MoiChangeValue.
    }

OneOfMoiChangeValue 是一个接口,它有两个实现 Type1MoiChangeValue 和 Type2MoiChangeValue。

现在,当我根据“操作”字段数据传递 RequestBody 时,我必须将 Request Body 的“value”字段与任何接口实现 Type1MoiChangeValue 或 Type2MoiChangeValue 进行映射。

public interface OneOfMoiChangeValue {

}

Type1MoiChangeValue:

@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2021-11-16T11:51:46.436+05:30[Asia/Calcutta]")
public class Type1MoiChangeValue  extends ArrayList<Type2MoiChangeValue > implements OneOfMoiChangeValue {

  @Override
  public boolean equals(java.lang.Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    return true;
  }

  @Override
  public int hashCode() {
    return Objects.hash(super.hashCode());
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("class Type1MoiChangeValue {\n");
    sb.append("    ").append(toIndentedString(super.toString())).append("\n");
    sb.append("}");
    return sb.toString();
  }

  /**
   * Convert the given object to string with each line indented by 4 spaces
   * (except the first line).
   */
  private String toIndentedString(java.lang.Object o) {
    if (o == null) {
      return "null";
    }
    return o.toString().replace("\n", "\n    ");
  }
}

Type2MoiChangeValue:

@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2021-11-16T11:51:46.436+05:30[Asia/Calcutta]")
public class Type2MoiChangeValue extends HashMap<String, Object> implements OneOfMoiChangeValue {

  @Override
  public boolean equals(java.lang.Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    return true;
  }

  @Override
  public int hashCode() {
    return Objects.hash(super.hashCode());
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("class Type2MoiChangeValue {\n");
    sb.append("    ").append(toIndentedString(super.toString())).append("\n");
    sb.append("}");
    return sb.toString();
  }

  /**
   * Convert the given object to string with each line indented by 4 spaces
   * (except the first line).
   */
  private String toIndentedString(java.lang.Object o) {
    if (o == null) {
      return "null";
    }
    return o.toString().replace("\n", "\n    ");
  }
}

我们正在使用杰克逊解析器。我该怎么做。请指教!

【问题讨论】:

  • 能否添加OneOfMoiChangeValueType1MoiChangeValueType2MoiChangeValue的代码?谢谢!
  • 嗨@JoãoDias,我已经更新了完整的代码。请检查。

标签: java spring spring-boot interface jackson


【解决方案1】:

您需要对代码进行一些更改,因此需要对请求正文进行一些更改。第一个是用几个 Jackson 注释更新 OneOfMoiChangeValue,以便它可以知道如何根据名为 operation 的属性处理不同的子类型:

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

import static com.fasterxml.jackson.annotation.JsonTypeInfo.As.PROPERTY;
import static com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME;

@JsonTypeInfo(use = NAME, include = PROPERTY, property = "operation")
@JsonSubTypes({
  @JsonSubTypes.Type(value=Type1MoiChangeValue.class, name = "Type1"),
  @JsonSubTypes.Type(value=Type2MoiChangeValue.class, name = "Type2")
})
public interface OneOfMoiChangeValue {

}

这意味着您不再需要MoiChange 中的operation 属性:

public class MoiChange {
      @JsonProperty("value")
      private OneOfMoiChangeValue value = null;   //value filed can be mapped with any of the OneOfMoiChangeValue Interface implentations  Type1MoiChangeValue or Type2MoiChangeValue.
}

相反,它必须与OneOfMoiChangeValue 的所有其他属性一起发送,因此请遵循以下几行:

{
    "moiChanges": 
    [
        {
            "value": {
                "operation": "Type1",
                (...)
            }    
        },
        {
            "value": {
                "operation": "Type2",
                (...)
            }    
        },
        (...)
    ]
}

【讨论】:

  • 这看起来不错。让我试试并更新你。
  • 嗨@João,我刚刚才知道我无法更改请求正文并在“值”属性中添加额外字段“操作”,因为请求正文被视为标准格式并且不要无权操纵它。那么在请求正文中不添加任何额外字段我们可以做到吗?
  • 我不知道。唯一的选择可能是自定义反序列化器。我真的很喜欢人们认为软件是一成不变的东西,并且无法以任何方式进行更改(我知道这不是您的决定;))。
  • 是的,同意你的看法。 :) 在这种情况下,我们必须使用自定义反序列化器。我是新手。所以如果我能做到的话,试着写一些。
  • 嗨@João Dias,我已经按照您的说法编写了一个自定义反序列化器,并且它有效。您在答案中的建议也适用于大多数情况,因为我们通常可以在 json.xml 中传递额外的字段。我接受您的解决方案,因为它是正确的。感谢您帮助解决它:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-03
  • 2021-09-30
  • 1970-01-01
  • 2023-03-20
  • 2017-07-13
相关资源
最近更新 更多