Java Джексон десериализуется с наследованием по шаблону компоновщика - PullRequest
0 голосов
/ 25 августа 2018

У меня есть базовый класс (Foo) с 2 детьми (A и B).Они выглядят так:

public abstract class Foo {
  private String fooString;
  public Foo(String fooString) {
    this.fooString = fooString;
  }
  //getter
}

@JsonDeserialize(builder = A.ABuilder.class)
public class A extends Foo {
  private int amount;
  public A(String fooString, int amount) {
    super(fooString);
    this.amount = amount;
  }
  //getter

  @JsonPOJOBuilder
  public static class ABuilder {
    private String fooString;
    private int amount;

    public ABuilder withFooString(final String fooString) {
        this.fooString = fooString;
        return this;
    }

    public ABuilder withAmount(final int amount) {
        this.amount = amount;
        return this;
    }

    public A build() {
      return new A(fooString, amount);
    }
  }
}

@JsonDeserialize(builder = B.BBuilder.class)
public class B extends Foo {
  private String type;
  public B(String fooString, String type) {
    super(fooString);
    this.type = type;
  }
  //getter

  @JsonPOJOBuilder
  public static class BBuilder {
    private String fooString;
    private String type;

    public BBuilder withFooString(final String fooString) {
        this.fooString = fooString;
        return this;
    }

    public BBuilder withType(final String type) {
        this.type = type;
        return this;
    }

    public B build() {
      return new B(fooString, type);
    }
  }
}

В моем контроллере у меня есть конечная точка:

@PutMapping
private ResponseEntity<Foo> doSomething(@RequestBody Foo dto) {
    //stuff
}

Но всякий раз, когда я пытаюсь отправить через свою полезную нагрузку json:

{
   "fooString":"test",
   "amount":1
}

Я получаю сообщение об ошибке:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.test.Foo` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
 at [Source: (String)"{"fooString":"test","amount":1}; line: 1, column: 1]
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
    at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1451)
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1027)
    at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:265)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)
    at AbstractJackson.main(AbstractJackson.java:11)

Как заставить Джексона десериализовать JSON в соответствующий дочерний класс?Что я делаю не так?

1 Ответ

0 голосов
/ 25 августа 2018

Базовый класс не получит конструкторы подклассов, а наоборот. Вы не можете установить специфические свойства подкласса в базовом классе, вместо этого вам нужно использовать определенный подкласс для вызова или использовать пользовательский десериализатор длябазовый класс при правильном использовании intanceOf Самый простой способ заставить его работать - это изменить метод контроллера.

@PutMapping
private ResponseEntity<Foo> doSomething(@RequestBody A dto) {
    //stuff
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...