Gson генерирует исключение, когда ожидаемый строковый массив возвращает объект - PullRequest
0 голосов
/ 20 октября 2018

Я использую API, где определенное поле (ниже) обычно содержит строковый массив.Однако, если массив пуст, API возвращает пустой объект в том, что обычно является массивом строк.Вот поле, вызывающее проблемы.

Нормальное.

"a": [
    "str"
    ]

Пусто.

"a": [
    {}
    ]

Во втором случае происходит сбой Gson с JsonSyntaxException.Как мне справиться с этим?

Ответы [ 2 ]

0 голосов
/ 21 октября 2018

Я не знаю, является ли это лучшим способом, но это работает.

Неправильное поле может быть аннотировано @JsonAdapter (MyTypeAdapter.class).TypeAdapter может затем использовать свой метод чтения и проверять, используя peek () weather или нет, следующее значение имеет ожидаемый тип.

0 голосов
/ 20 октября 2018

Предположим, у вас есть класс, представляющий ответ API, например:

public class Response {
    private String[] a;
    private String b;
    private String c;
}

Один из способов получить объект Response, который был проанализирован, является ли JSON для a действительным или нет, это создатьJsonDeserializer, который проверяет, может ли a проанализировать, и исключает синтаксический анализ a в случае сбоя, поэтому оставляет a до null.

public class SkipBadSyntaxDeserializer implements JsonDeserializer<Response> {

    // This strategy is used if parse of field a fails
    private final ExclusionStrategy excludeA = new ExclusionStrategy() {
        @Override
        public boolean shouldSkipField(FieldAttributes f) {
            return "a".equals(f.getName());
        }

        // no need to care of this used only here for the Response class
        @Override
        public boolean shouldSkipClass(Class<?> clazz) {
            return false;
        }
    };

    // one parser for good and another for bad format
    private final Gson gson = new Gson(),
            gsonBadFormat = new GsonBuilder()
                    .addDeserializationExclusionStrategy(excludeA).create();;

    @Override
    public Response deserialize(JsonElement json, Type typeOfT, 
                JsonDeserializationContext context)
            throws JsonParseException {
        try {
            return gson.fromJson(json, Response.class);
        } catch (JsonSyntaxException e) {
            // parse a failed try again without it  
            return gsonBadFormat.fromJson(json, Response.class);
        }

    }

}

Попробуйте:

new GsonBuilder().registerTypeAdapter(Response.class,
            new SkipBadSyntaxDeserializer())
                 .create()
                 .fromJson(JSON, Response.class);

Если JSON будет выглядеть так:

{
    "a": [{}],
    "b": "bval",
    "c": "cval"   
}

, тогда свойства для Response будут:

a=null
b="bval"
c="cval"

Обновление

На основании вашего собственного ответа:если можно изменить DTO для ответа, то использование аннотации @JsonAdapter позволит вам обрабатывать это для каждого поля.Тогда десериализатор будет просто:

public class SkipExceptionAdapter implements JsonDeserializer<String[]> {
    @Override
    public String[] deserialize(JsonElement json, Type typeOfT,
                JsonDeserializationContext context)
            throws JsonParseException {
        try {
            return context.deserialize(json, String[].class);
        } catch (JsonSyntaxException e) {
            return new String[] {}; // or null how you wish
        }
    }
}

, а аннотация в Response.a

@JsonAdapter(SkipExceptionAdapter.class)
private String[] a;

будет обрабатывать его только для этого поля.

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