Как десериализовать объект JSON в реализацию интерфейса на основе его пар ключ-значение? - PullRequest
0 голосов
/ 29 декабря 2018

Я настраиваю контроллер для приложения 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;

}

(Примечание: если указан вес, это продуктовый товар, и он не может быть нулевым или "". Если вес не указан, то это предмет одежды).

Контроллер

@Controller
public class Total {

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

JSON body

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

Желаемым результатом было создание экземпляра типа ClothingItem.Когда я попытался сделать это, я получил следующее исключение:

org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Невозможно создать экземпляр com.test.controllers.Models.ShoppableItem:абстрактные типы либо должны быть сопоставлены с конкретными типами, иметь собственный десериализатор или содержать дополнительную информацию о типах;вложенным исключением является com.fasterxml.jackson.databind.JsonMappingException: невозможно создать экземпляр com.test.controllers.Models.ShoppableItem: абстрактные типы либо должны быть сопоставлены с конкретными типами, либо иметь собственный десериализатор, либо содержать дополнительную информацию о типе

Это функция, которую я неправильно реализую?Я понимаю, что это может быть не лучшим подходом, так как было бы проще просто создать 2 конечные точки для обработки каждого случая.

1 Ответ

0 голосов
/ 29 декабря 2018

Этого можно добиться, добавив статический фабричный метод (помеченный @JsonCreator) к вашему ShoppableItem интерфейсу.Обратите внимание, что вам нужно аннотировать все его аргументы с помощью @JsonProperty, чтобы Джексон знал, как сопоставить свойства 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...