Spring POST 将 class 从 2 参数更改为 1 参数时出现 400 Bad Request Postman
Spring POST 400 Bad Request Postman when changing class from 2 to 1 parameter
我的@RestController 中有以下代码class:
@RequestMapping("api/")
@RestController
public class RecommendationsController {
@PostMapping(path = "cart")
public List<RecommendationDTO> getCartRecommendations(@NonNull @RequestBody List<CartItemDTO> cart){
System.out.println(cart);
return null;
}
}
这是我的 CartItemDTO 中的代码 class:
public class CartItemDTO {
private String productId;
private Double quantity;
public CartItemDTO(String productId, Double quantity) {
this.productId = productId;
this.quantity = quantity;
}
public String getProductId() {
return productId;
}
public Double getQuantity(){
return quantity;
}
这是我用邮递员发送的请求:
[
{
"productId": "20000010",
"quantity": 5.0;
},
{
"productId": "20000011",
"quantity": 7.0;
}
]
这是有效的,但是当我像下面这样更改我的代码时,我收到了错误的请求:
语法错误
public class CartItemDTO {
private String productId;
public CartItemDTO(String productId) {
this.productId = productId;
}
public String getProductId() {
return productId;
}
}
请求:
[
{
"productId": "20000010"
},
{
"productId": "20000011"
}
]
有人知道哪里出了问题吗?
fasterxml jackson 似乎有问题,当它在构造函数只有 1 个参数时尝试自动猜测 JsonCreator。
我找到的最佳解决方案是将 @JsonCreator 注释添加到构造函数中,这样 jackson 就不必猜测它应该使用哪个创建者。
像这样:
import com.fasterxml.jackson.annotation.JsonCreator;
public class CartItemDTO {
private String productId;
@JsonCreator
public CartItemDTO( String productId) {
this.productId = productId;
}
public String getProductId() {
return productId;
}
}
更新:
显然这是 fasterxml jackson 中的一个已知限制:
https://github.com/FasterXML/jackson-modules-java8/issues/8
主要问题是 Jackson 无法构建 DTO 实例。
解决这个问题的两种方法:
1.指定默认构造函数:
- 当您指定参数化构造函数时,Java 编译器将不会添加 default constructor.
现在您的第一个请求:
curl --location --request POST 'localhost:8080/cart' \
--header 'Content-Type: application/json' \
--data-raw '[
{
"productId": "20000010",
"quantity": 5.0
},
{
"productId": "20000011",
"quantity": 7.0
}
]'
抛出错误:
"timestamp": "2020-04-27T12:08:28.497+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Type definition error: [simple type, class hello.dto.CartItemDTO]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `hello.dto.CartItemDTO` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)\n at [Source: (PushbackInputStream); line: 3, column: 9] (through reference chain: java.util.ArrayList[0])",
"path": "/cart"
将默认构造函数添加到 DTO 后,一切都按预期正常工作。
public class CartItemDTO {
private String productId;
private Double quantity;
public CartItemDTO() {
}
public CartItemDTO(String productId, Double quantity) {
this.productId = productId;
this.quantity = quantity;
}
public String getProductId() {
return productId;
}
public Double getQuantity() {
return quantity;
}
}
由于 OP 没有 RecommendationDTO
对象,因此只添加 System.out.println 作为输出:
[hello.dto.CartItemDTO@145e35d6, hello.dto.CartItemDTO@25df553f]
- DTO 中只有 ProductId
public class CartItemDTO {
private String productId;
public CartItemDTO() {
}
public CartItemDTO(String productId, Double quantity) {
this.productId = productId;
}
public String getProductId() {
return productId;
}
}
要求:
curl --location --request POST 'localhost:8080/cart' \
--header 'Content-Type: application/json' \
--data-raw '[
{
"productId": "20000010"
},
{
"productId": "20000011"
}
]'
输出:
[hello.dto.CartItemDTO@42ad1f23, hello.dto.CartItemDTO@777d8eb3]
- 解决方案二:需要指示 Jackson 使用具有实例字段的构造函数创建一个 dto 对象,如下所示:
将 DTO 更改为
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class CartItemDTO {
private String productId;
private Double quantity;
@JsonCreator
public CartItemDTO(@JsonProperty(value = "productId", required = true) String productId,
@JsonProperty(value = "quantity", required = true) Double quantity) {
this.productId = productId;
this.quantity = quantity;
}
public String getProductId() {
return productId;
}
public Double getQuantity() {
return quantity;
}
}
或只有 productId
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class CartItemDTO {
private String productId;
@JsonCreator
public CartItemDTO(@JsonProperty(value = "productId", required = true) String productId) {
this.productId = productId;
}
public String getProductId() {
return productId;
}
}
我的@RestController 中有以下代码class:
@RequestMapping("api/")
@RestController
public class RecommendationsController {
@PostMapping(path = "cart")
public List<RecommendationDTO> getCartRecommendations(@NonNull @RequestBody List<CartItemDTO> cart){
System.out.println(cart);
return null;
}
}
这是我的 CartItemDTO 中的代码 class:
public class CartItemDTO {
private String productId;
private Double quantity;
public CartItemDTO(String productId, Double quantity) {
this.productId = productId;
this.quantity = quantity;
}
public String getProductId() {
return productId;
}
public Double getQuantity(){
return quantity;
}
这是我用邮递员发送的请求:
[
{
"productId": "20000010",
"quantity": 5.0;
},
{
"productId": "20000011",
"quantity": 7.0;
}
]
这是有效的,但是当我像下面这样更改我的代码时,我收到了错误的请求: 语法错误
public class CartItemDTO {
private String productId;
public CartItemDTO(String productId) {
this.productId = productId;
}
public String getProductId() {
return productId;
}
}
请求:
[
{
"productId": "20000010"
},
{
"productId": "20000011"
}
]
有人知道哪里出了问题吗?
fasterxml jackson 似乎有问题,当它在构造函数只有 1 个参数时尝试自动猜测 JsonCreator。
我找到的最佳解决方案是将 @JsonCreator 注释添加到构造函数中,这样 jackson 就不必猜测它应该使用哪个创建者。
像这样:
import com.fasterxml.jackson.annotation.JsonCreator;
public class CartItemDTO {
private String productId;
@JsonCreator
public CartItemDTO( String productId) {
this.productId = productId;
}
public String getProductId() {
return productId;
}
}
更新:
显然这是 fasterxml jackson 中的一个已知限制: https://github.com/FasterXML/jackson-modules-java8/issues/8
主要问题是 Jackson 无法构建 DTO 实例。
解决这个问题的两种方法:
1.指定默认构造函数:
- 当您指定参数化构造函数时,Java 编译器将不会添加 default constructor.
现在您的第一个请求:
curl --location --request POST 'localhost:8080/cart' \
--header 'Content-Type: application/json' \
--data-raw '[
{
"productId": "20000010",
"quantity": 5.0
},
{
"productId": "20000011",
"quantity": 7.0
}
]'
抛出错误:
"timestamp": "2020-04-27T12:08:28.497+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Type definition error: [simple type, class hello.dto.CartItemDTO]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `hello.dto.CartItemDTO` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)\n at [Source: (PushbackInputStream); line: 3, column: 9] (through reference chain: java.util.ArrayList[0])",
"path": "/cart"
将默认构造函数添加到 DTO 后,一切都按预期正常工作。
public class CartItemDTO {
private String productId;
private Double quantity;
public CartItemDTO() {
}
public CartItemDTO(String productId, Double quantity) {
this.productId = productId;
this.quantity = quantity;
}
public String getProductId() {
return productId;
}
public Double getQuantity() {
return quantity;
}
}
由于 OP 没有 RecommendationDTO
对象,因此只添加 System.out.println 作为输出:
[hello.dto.CartItemDTO@145e35d6, hello.dto.CartItemDTO@25df553f]
- DTO 中只有 ProductId
public class CartItemDTO {
private String productId;
public CartItemDTO() {
}
public CartItemDTO(String productId, Double quantity) {
this.productId = productId;
}
public String getProductId() {
return productId;
}
}
要求:
curl --location --request POST 'localhost:8080/cart' \
--header 'Content-Type: application/json' \
--data-raw '[
{
"productId": "20000010"
},
{
"productId": "20000011"
}
]'
输出:
[hello.dto.CartItemDTO@42ad1f23, hello.dto.CartItemDTO@777d8eb3]
- 解决方案二:需要指示 Jackson 使用具有实例字段的构造函数创建一个 dto 对象,如下所示:
将 DTO 更改为
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class CartItemDTO {
private String productId;
private Double quantity;
@JsonCreator
public CartItemDTO(@JsonProperty(value = "productId", required = true) String productId,
@JsonProperty(value = "quantity", required = true) Double quantity) {
this.productId = productId;
this.quantity = quantity;
}
public String getProductId() {
return productId;
}
public Double getQuantity() {
return quantity;
}
}
或只有 productId
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class CartItemDTO {
private String productId;
@JsonCreator
public CartItemDTO(@JsonProperty(value = "productId", required = true) String productId) {
this.productId = productId;
}
public String getProductId() {
return productId;
}
}