Spring Java POST 一个字段可以是不同数据类型的端点

Spring Java POST endpoint that can have a field be different data types

我正在开发 Java Spring 启动 HTTP 服务应用程序。我目前在 @RestController 中定义了一个 POST 端点。这个名为 processRequest 的控制器采用带有 @RequestBody 注释的名为 Info 的对象。

现在,我设置了它,用户可以根据我这样定义的 Info class 发送 JSON:

//Sample JSON Payload
{
   "name": "Bob",
   "age": 26,
   "hobby": biking
}

//Sample Object
@RequiredArgsConstructor
public class Info {
   public final String name;
   public final int age;
   public final String hobby
}

我想知道的是响应其中一个字段作为不同数据类型发送的情况。例如:

//JSON payload with different datatype for a field
{
   "name": "Bob",
   age: 26,
   "hobby": ["biking", "hiking"]   //This is supposed to be a string but it's an array.
}

是否可以保持端点属性相同但处理不同的数据类型?也许我可以创建另一个字段不同的 class 并且 spring 会自动创建与输入匹配的字段?我很好奇解决这个问题的最佳方法是什么。

您可以使用JsonNode 来更改字段。如下:

public class Info {
    public String name;
    public int age;
    public JsonNode hobby;
    
    
    @Schema(description = "")
    @Valid
    @JsonIgnore
    public List<String> getHobbies() {

      // if hobby is array create Java object and return
      // else if hobby is String create List, add the string to it and return it.
      // or some other solution of your choice and requirement
      
    }
}

在这个特定示例中,爱好可以是单个值或多个值,我将依赖 Jackson ACCEPT_SINGLE_VALUE_AS_ARRAY 反序列化功能。

这可以在 application.properties:

的应用程序范围内配置
spring.jackson.deserialization.accept-single-value-as-array=true

或者可以为特定字段启用此功能:

@RequiredArgsConstructor
public class Info {
   public final String name;
   public final int age;
   @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
   public final List<String> hobby
}

对于更复杂的情况,Jackson 建议您编写一个带有特定类型字段的包装器,以提供应反序列化哪种类型的提示。例如:

public class InfoWrapper {
    private String type;

    @JsonTypeInfo(use = Id.NAME, property = "type", include = As.EXTERNAL_PROPERTY)
    @JsonSubTypes(value = { 
        @JsonSubTypes.Type(value = PersonInfo.class, name = "person")
    })
    private Info info;
}

public interface Info {}

@RequiredArgsConstructor
public class PersonInfo implements Info {
   public final String name;
   public final int age;
   public final String hobby
}

所以,如果你想发送一个包含PersonInfo的JSON,你可以使用下面的JSON:

{
  "type": "person",
  "info": {
    "name": "Bob",
    "age": 26,
    "hobby": "biking"
  }
}

如果您需要对要执行的操作进行更高级的控制,您可以编写自定义反序列化程序并使用 @JsonDeserialize 注释应用它。