如何基于键值对将JSON对象反序列化到接口的实现上?

时间:2018-12-29 08:41:04

标签: java json spring-boot jackson

我正在为Spring Boot应用程序设置一个控制器。我希望控制器根据传入的JSON字符串的键值对生成接口实现的实例。

界面:

public interface ShoppableItem {}

实现1:

public class GroceryItem implements ShoppableItem {

@JsonProperty("transactionId")
private Long transactionId;

@JsonProperty
@NotNull
private String itemName;

@JsonProperty
@NotNull
private Float weight;
}

实施2:

public class ClothingItem implements ShoppableItem {

@JsonProperty("transactionId")
private Long transactionId;

@JsonProperty
@NotNull
private String itemName;

}

(注意:如果提供了重量,则为杂货,并且不能为null或“”。如果没有提供重量,则为服装)。

控制器

@Controller
public class Total {

  @PostMapping(value = "total")
  @ResponseStatus(HttpStatus.ACCEPTED)
  public String tester(@Valid @RequestBody ShoppableItem shoppableItem) {
    return shoppableItem.toString();
  }
}

JSON正文

{
"transactionId" : "123",
"itemName" : "whatever"
}

所需结果是创建一个ClothingItem类型的实例。当我尝试执行此操作时,出现以下异常:

  

org.springframework.http.converter.HttpMessageNotReadableException:JSON解析错误:无法构造com.test.controllers.Models.ShoppableItem的实例:抽象类型要么需要映射到具体类型,要么具有自定义反序列化器,或者包含其他类型类型信息;嵌套异常是com.fasterxml.jackson.databind.JsonMappingException:无法构造com.test.controllers.Models.ShoppableItem的实例:抽象类型要么需要映射到具体类型,要么具有自定义反序列化器,或者包含其他类型信息

这是我执行不正确的功能吗?我知道这可能不是最好的方法,因为仅创建2个端点来处理每种情况会更容易。

1 个答案:

答案 0 :(得分:0)

您可以通过添加静态工厂方法来实现 (用@JsonCreator注释)到ShoppableItem界面。 请注意,您需要使用@JsonProperty注释其所有参数。 这样Jackson就会知道如何将JSON属性映射到方法参数。

public interface ShoppableItem {

    @JsonCreator
    public static ShoppableItem create(@JsonProperty("transactionId") Long transactionId,
                                       @JsonProperty("itemName") String itemName,
                                       @JsonProperty("weight") Float weight) {
        if (weight == null)
            return new ClothingItem(transactionId, itemName);
        else
            return new GroceryItem(transactionId, itemName, weight);
    }
}

然后,杰克逊在反序列化ShoppableItem时将使用该方法。