Реализация собственного GsonCoverterFactory / Deserializer для динамических типов - PullRequest
0 голосов
/ 25 апреля 2018

Как реализовать пользовательский GsonConverterFactor или JsonDeserializer для типов, имеющих динамические значения?

Например:

Если объект Tags имеет контент, он выглядит следующим образом:

"tags": [
                {
                    "content_id": "13",
                    "tag_id": "3",
                    "created": "2018-03-26 11:09:08",
                    "tag_name": "FICTION"
                },
                {
                    "content_id": "13",
                    "tag_id": "7",
                    "created": "2018-03-26 11:09:08",
                    "tag_name": "JUVENILE FICTION"
                }
            ]

Однако, если он пуст, он вернет это:

            "tags": false

По сути, я хочу создать список тегов null, если десериализатор читает его значение как false.

РЕДАКТИРОВАТЬ: я использую Retrofit и GSON.

Ответы [ 3 ]

0 голосов
/ 25 апреля 2018

Вы можете создать десериализатор, подобный этому

public class UserResponseDeserializer implements 
JsonDeserializer<ResponseWrapper> {
@Override
public ResponseWrapper deserialize(JsonElement json, Type typeOfT, 
JsonDeserializationContext context) throws JsonParseException {


    if (((JsonObject) json).get("tags") instanceof JsonArray){
        return new Gson().fromJson(json, ResponseArray.class);
    } else {
        return new Gson().fromJson(json, ResponseBoolean.class);
    }

}
}

, где ResponseArray и ResponseBoolean расширяются ResponseWrapper, как упоминалось здесь

0 голосов
/ 25 апреля 2018

Адаптеры типа, самое сердце сериализации / десериализации Gson, могут помочь практически во всех случаях. Все, что вам нужно, это просто реализовать один.

final class CollectionFalseAsNullTypeAdapterFactory
        implements TypeAdapterFactory {

    private static final TypeAdapterFactory instance = new CollectionFalseAsNullTypeAdapterFactory();

    private CollectionFalseAsNullTypeAdapterFactory() {
    }

    static TypeAdapterFactory get() {
        return instance;
    }

    @Override
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
        if ( !Collection.class.isAssignableFrom(typeToken.getRawType()) ) {
            return null;
        }
        @SuppressWarnings("unchecked")
        final TypeAdapter<Collection<Object>> delegateTypeAdapter = (TypeAdapter<Collection<Object>>) gson.getDelegateAdapter(this, typeToken);
        @SuppressWarnings("unchecked")
        final TypeAdapter<T> typeAdapter = (TypeAdapter<T>) new CollectionFalseAsNullTypeAdapter<>(delegateTypeAdapter);
        return typeAdapter;
    }

    private static final class CollectionFalseAsNullTypeAdapter<E>
            extends TypeAdapter<Collection<E>> {

        private final TypeAdapter<Collection<E>> delegateTypeAdapter;

        private CollectionFalseAsNullTypeAdapter(final TypeAdapter<Collection<E>> delegateTypeAdapter) {
            this.delegateTypeAdapter = delegateTypeAdapter;
        }

        @Override
        public void write(final JsonWriter out, final Collection<E> value)
                throws IOException {
            delegateTypeAdapter.write(out, value);
        }

        @Override
        public Collection<E> read(final JsonReader in)
                throws IOException {
            // Let's just make sure it's a boolean
            if ( in.peek() == JsonToken.BOOLEAN ) {
                // If yes, then just return a null skipping the boolean
                in.skipValue();
                return null;
            }
            return delegateTypeAdapter.read(in);
        }

    }

}

Пример использования:

private static final Gson gson = new GsonBuilder()
        .setDateFormat("yyyy-MM-dd HH:mm:ss")
        .registerTypeAdapterFactory(CollectionFalseAsNullTypeAdapterFactory.get())
        .create();

public static void main(final String... args)
        throws IOException {
    for ( final String resourceName : ImmutableList.of("non-null.json", "null.json") ) {
        try ( final JsonReader jsonReader = Resources.getPackageResourceJsonReader(Q50013856.class, resourceName) ) {
            final Entity entity = gson.fromJson(jsonReader, Entity.class);
            System.out.println(entity);
        }
    }
}

Пример вывода (при условии, что toString переопределено):

Entity {tags = [Tag {contentId = 13, tagId = 3, создан = понедельник, 26 марта 11:09:08 EEST 2018, tagName = FICTION}, Tag {contentId = 13, tagId = 7, создан = понедельник 26 11:09:08 EEST 2018, tagName = ФУНКЦИЯ ЮВЕНИЛЯ}]}
Entity {tags = null}

Обратите внимание, что вы можете аннотировать поле tags, чтобы оно было более точным, чем глобальная регистрация завода:

@JsonAdapter(CollectionFalseAsNullTypeAdapterFactory.class)
final List<Tag> tags = null;
0 голосов
/ 25 апреля 2018
public class Example implements Serializable
{
@JsonProperty("tags")
private Map<String, Object> tags = new HashMap<String, Object>();
}

Использовать вышеуказанный класс для разбора json:

Object object = tags.get("tags");

if (object instanceof JSONArray){
            JSONArray jsonArray = (JSONArray) tags.get("tags");
        }else {
            boolean booleanValue = (boolean) tags.get("tags");
        }
...