Десериализация JSON при наличии нескольких реализаций интерфейса

Имеются две реализации dto наследуемые от одного интерфейса с одинаковыми названиями полей, но с разными @JsonProperty. В интерфейсе прописаны геттеры и сеттеры.

@Data
@ToString
@JsonIgnoreProperties(ignoreUnknown = true)
public class ResponseOldImpl implements Response {
@JsonProperty("phone")
private String phone;
@JsonProperty("name")
private String name;
}



@Data
@ToString
@JsonIgnoreProperties(ignoreUnknown = true)
public class ResponseActualImpl implements Response {
@JsonProperty("mobile_phone")
private String phone;
@JsonProperty("first_name")
private String name;
}


public interface Response {
public String getPhone();
public String getName();
public void setPhone(String Phone);
public void setName(String Name);
}

В тестах падает erxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of Response (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information

Как в данном случае можно указать какую конкретно реализацию нужно десериализовать?


Ответы (1 шт):

Автор решения: Seryozha

Решение вышло таким:

public class ResponseDeserializer extends StdDeserializer<Response> {
    
        protected ResponseDeserializer() {
            super(Response.class);
        }
    
        @Override
        public Response deserialize(JsonParser jp, DeserializationContext context)
            throws IOException {
    
            ObjectMapper mapper = new ObjectMapper();
    
            JsonNode node = jp.getCodec().readTree(jp);
    
            String text = node.toString();
    
            if (text.contains("mobile_phone") || text.contains("first_name")) {
                return mapper.readValue(text, ResponseActualImpl.class);
            } else {
                return mapper.readValue(text, ResponseOldImpl.class);
            }
        }
    }


@Data
@ToString
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonDeserialize(as = ResponseOldImpl.class)
public class ResponseOldImpl implements Response {
@JsonProperty("phone")
private String phone;
@JsonProperty("name")
private String name;
}



@Data
@ToString
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonDeserialize(as = ResponseActualImpl.class)
public class ResponseActualImpl implements Response {
@JsonProperty("mobile_phone")
private String phone;
@JsonProperty("first_name")
private String name;
}

@JsonDeserialize(using = ResponseDeserializer.class)
public interface Response {
public String getPhone();
public String getName();
public void setPhone(String Phone);
public void setName(String Name);
}

Помогла эта статья. На имплементации нужно отдельно указать:

@JsonDeserialize(as = {имя имплементации}.class)
→ Ссылка