Поскольку информация type
хранится в классе Dto
, пользовательский JsonDeserializer
должен быть реализован для класса 'Dto' вместо интерфейса 'Power', чтобы получить доступ к информации type
.Важной частью реализации пользовательского JsonDeserializer
в приведенном ниже коде является строка
config.powers.add (parser.readValueAs (getPowerClass (dto.type)));;
, где getPowerClass
метод определяет класс (FirstPower
или SecondPower
), требуемый с помощью type
из dto
.Как только класс известен, мы можем десериализовать объект power
, просто вызвав метод readValueAs
.Следующие классы (должны быть помещены в один и тот же пакет) демонстрируют, как реализовать пользовательский JsonDeserializer
.
Основной класс
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class PolymorphicDeserialize {
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
ObjectMapper mapper = new ObjectMapper();
Dto type1 = mapper.readValue(getType1Json(), Dto.class);
Dto type2 = mapper.readValue(getType2Json(), Dto.class);
printDto(type1);
printDto(type2);
}
private static void printDto(Dto dto) {
System.out.println("type :" + dto.type);
for (Config config : dto.configs) {
System.out.println("itemLevel:" + config.itemLevel);
System.out.println("powers:" + config.powers);
}
}
private static String getType1Json() {
return " { "
+ " \"type\": \"first_type\", "
+ " \"configs\": [ "
+ " { "
+ " \"itemLevel\": 1, "
+ " \"power\": { "
+ " \"firstTypeParam\": \"xxxx\" "
+ " } "
+ " }, "
+ " { "
+ " \"itemLevel\": 2, "
+ " \"power\": { "
+ " \"firstTypeParam\": \"yyy\" "
+ " } "
+ " } "
+ " ] "
+ " } ";
}
private static String getType2Json() {
return " { "
+ " \"type\": \"second_type\", "
+ " \"configs\": [ "
+ " { "
+ " \"itemLevel\": 11, "
+ " \"power\": { "
+ " \"anotherParam\": true "
+ " } "
+ " }, "
+ " { "
+ " \"itemLevel\": 12, "
+ " \"power\": { "
+ " \"anotherParam\": false "
+ " } "
+ " } "
+ " ] "
+ " } ";
}
}
Класс Dto
import java.util.Collection;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@JsonDeserialize(using = DtoDeserializer.class)
public class Dto {
String type;
Collection<Config> configs;
}
Класс DtoDeserializer
import java.io.IOException;
import java.util.ArrayList;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
public class DtoDeserializer extends JsonDeserializer<Dto> {
@Override
public Dto deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Dto dto = new Dto();
dto.configs = new ArrayList<Config>();
while (parser.nextToken() == JsonToken.FIELD_NAME) {
deserializeType(parser, dto);
deserializeConfigs(parser, dto);
}
return dto;
}
private void deserializeType(JsonParser parser, Dto dto) throws IOException, JsonProcessingException {
if (!"type".equals(parser.getCurrentName())) {
return;
}
parser.nextToken();
dto.type = parser.getValueAsString();
}
private void deserializeConfigs(JsonParser parser, Dto dto) throws IOException, JsonProcessingException {
if (!"configs".equals(parser.getCurrentName())) {
return;
}
if (parser.nextToken() != JsonToken.START_ARRAY) {
return;
}
while (parser.nextValue() != null) {
if (parser.getCurrentToken() != JsonToken.START_OBJECT) {
continue;
}
Config config = new Config();
config.powers = new ArrayList<Power>();
while (parser.nextToken() != JsonToken.END_OBJECT) {
if ("itemLevel".equals(parser.getCurrentName())) {
parser.nextToken();
config.itemLevel = parser.getValueAsInt();
} else if ("power".equals(parser.getCurrentName())) {
parser.nextToken();
config.powers.add(parser.readValueAs(getPowerClass(dto.type)));
}
}
dto.configs.add(config);
}
}
private Class<? extends Power> getPowerClass(String type) {
if ("first_type".equals(type)) {
return FirstPower.class;
} else if ("second_type".equals(type)) {
return SecondPower.class;
}
throw new IllegalArgumentException("Not known type" + type);
}
}
Интерфейс питания
public interface Power {}
FirstPower класс
public class FirstPower implements Power {
String firstTypeParam;
String getFirstTypeParam() {
return firstTypeParam;
}
void setFirstTypeParam(String firstTypeParam) {
this.firstTypeParam = firstTypeParam;
}
@Override
public String toString() {
return "firstTypeParam:" + firstTypeParam;
}
}
SecondPower класс
public class SecondPower implements Power {
boolean anotherParam;
boolean isAnotherParam() {
return anotherParam;
}
void setAnotherParam(boolean anotherParam) {
this.anotherParam = anotherParam;
}
@Override
public String toString() {
return "anotherParam:" + String.valueOf(anotherParam);
}
}