Десериализация полезной нагрузки JSON в базу объектов на основе целочисленного свойства JSON

#java #json #jackson #deserialization #json-deserialization

#java #json #джексон #десериализация #json-десериализация

Вопрос:

У меня есть следующие классы:

 public class Result<T> {
    public int code;
    public Object meta;
    public T data;
}

public class User {
    public int id;
    public String name;
}

public class Error {
    public String field;
    public String message;
}
  

Я хочу десериализовать JSON полезную нагрузку на основе code поля. Если code >= 10 , верните Result<ArrayList<Error>> , в противном случае верните Result<User>

В настоящее время я сначала сопоставляю JSON с Result<Object> , затем проверяю code поле. На основе этого значения я создаю второе сопоставление с желаемым объектом.

 ObjectMapper mapper = new ObjectMapper();
Result<Object> tempResult = mapper.readValue(json, new TypeReference<Result<Object>>() {});

if (tempResult.code < 10) {    
    Result<User> result = mapper.readValue(json, new TypeReference<Result<User>>() {});
    return resu<
} else {
    Result<ArrayList<Error>> result = mapper.readValue(json, new TypeReference<Result<ArrayList<Error>>>() {});
    return resu<
}
  

Есть ли элегантный способ сделать это без десериализации 2 раза?

Ответ №1:

Вам необходимо реализовать пользовательский TypeIdResolver :

 class UserTypeIdResolverBase extends TypeIdResolverBase {

    @Override
    public String idFromValue(Object value) {
        throw new IllegalStateException("Not implemented!");
    }

    @Override
    public String idFromValueAndType(Object value, Class<?> suggestedType) {
        throw new IllegalStateException("Not implemented!");
    }

    @Override
    public JsonTypeInfo.Id getMechanism() {
        return JsonTypeInfo.Id.CUSTOM;
    }

    @Override
    public JavaType typeFromId(DatabindContext context, String id) {
        if (Integer.parseInt(id) < 10) {
            return context.getTypeFactory().constructType(new TypeReference<Result<User>>() {});
        }
        return context.getTypeFactory().constructType(new TypeReference<Result<List<Error>>>() {});
    }
}
  

и объявите его для Result класса:

 @JsonTypeInfo(property = "code", use = JsonTypeInfo.Id.CUSTOM, visible = true)
@JsonTypeIdResolver(UserTypeIdResolverBase.class)
class Result<T>