Подтвердить что ты не робот

Регистрация нескольких адаптеров с помощью GSON не работает

У меня проблема с регистрацией нескольких типов адаптеров с помощью моего GsonBuilder. Похоже, только один выстрелит, и он никогда не принимает во внимание второй. Если я делаю это с каждым из них, он, похоже, работает нормально. Но мне нужно, чтобы они работали с обоими, и кажется, что я делаю что-то неправильно. Также в настоящее время я использую GSON v2.2.4.

Простая форма объекта Zip:

public class Zip {

  private String zipCode;
  private String city;
  private String state;

  public Zip(){}                                            
}

ZipSerializer:

public class ZipSerializer implements JsonSerializer<Zip>{

    @Override
    public JsonElement serialize(Zip obj, Type type, JsonSerializationContext jsc) {
        Gson gson = new Gson();
        JsonObject jObj = (JsonObject)gson.toJsonTree(obj);
        jObj.remove("state");        
        return jObj;
    }

}

Простая форма объекта JsonResponse:

public class JsonResponse {

    private String jsonrpc = "2.0"; 
    private Object result = null;
    private String id = null;

    public JsonResponse(){}

}

JsonResponseSerializer:

public class JsonResponseSerializer implements JsonSerializer<JsonResponse> {

    @Override
    public JsonElement serialize(JsonResponse obj, Type type, JsonSerializationContext jsc) {
        Gson gson = new Gson();
        JsonObject jObj = (JsonObject)gson.toJsonTree(obj);
        jObj.remove("id");

        return jObj;
    }

}

Пример теста:

public class Test {

    public static void main(String[] args) {
        Zip zip = new Zip();
        zip.setCity("testcity");
        zip.setState("OH");
        zip.setZipCode("12345");

        JsonResponse resp = new JsonResponse();
        resp.setId("1");
        resp.setResult(zip);
        resp.setJsonrpc("2.0");

        Gson gson1 = new GsonBuilder()
        .registerTypeAdapter(JsonResponse.class, new JsonResponseSerializer())
        .registerTypeAdapter(Zip.class, new ZipSerializer())
        .setPrettyPrinting()
        .create();


        String json = gson1.toJson(resp);
        System.out.println(json);               

    }

}

Вывод:

{
  "jsonrpc": "2.0",
  "result": {
    "zipCode": "12345",
    "city": "testcity",
    "state": "OH"
  }
}

Ожидаемый результат: (уведомление ZipSerializer не срабатывает)

{
  "jsonrpc": "2.0",
  "result": {
    "zipCode": "12345",
    "city": "testcity"
  }
}

Я попробовал тест для этого. Я знаю, что я могу использовать exclusionStrategy в этом примере для достижения результатов, но реальная проблема намного сложнее, и это был лучший способ показать и воспроизвести мою проблему.

Спасибо

< ---------------------------- РЕШЕНИЕ ---------------- --------------- >

Мне удалось прочитать настраиваемый серализатор Gson для одной переменной (из многих) в объекте с использованием TypeAdapter, и это очень помогло мне.

Я создал базу customTypeAdapterFactory, а затем расширил ее для каждого класса, который нуждался в специальной сериализации.

CustomizedTypeAdapterFactory

public abstract class CustomizedTypeAdapterFactory<C> implements TypeAdapterFactory {

    private final Class<C> customizedClass;

    public CustomizedTypeAdapterFactory(Class<C> customizedClass) {
        this.customizedClass = customizedClass;
    }

    @SuppressWarnings("unchecked") // we use a runtime check to guarantee that 'C' and 'T' are equal
    public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        return type.getRawType() == customizedClass
                ? (TypeAdapter<T>) customizeMyClassAdapter(gson, (TypeToken<C>) type)
                : null;
    }

    private TypeAdapter<C> customizeMyClassAdapter(Gson gson, TypeToken<C> type) {
        final TypeAdapter<C> delegate = gson.getDelegateAdapter(this, type);
        final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);

        return new TypeAdapter<C>() {

            @Override public void write(JsonWriter out, C value) throws IOException {               
                JsonElement tree = delegate.toJsonTree(value);
                beforeWrite(value, tree);
                elementAdapter.write(out, tree);
            }


            @Override public C read(JsonReader in) throws IOException {
                JsonElement tree = elementAdapter.read(in);
                afterRead(tree);
                return delegate.fromJsonTree(tree);
            }
        };
    }

    /**
    * Override this to muck with {@code toSerialize} before it is written to
    * the outgoing JSON stream.
    */
    protected void beforeWrite(C source, JsonElement toSerialize) {
    }

    /**
    * Override this to muck with {@code deserialized} before it parsed into
    * the application type.
    */
    protected void afterRead(JsonElement deserialized) {
    }
}

ZipTypeAdapterFactory (это было с JsonResponseTypeAdapterFactory)

public class ZipTypeAdapterFactory  extends CustomizedTypeAdapterFactory<Zip> {

    ZipTypeAdapterFactory() {
        super(Zip.class);
    }

    @Override
    protected void beforeWrite(Zip source, JsonElement toSerialize) {
        JsonObject obj = (JsonObject) toSerialize;
        obj.remove("state");
    }

}

Тестовый код:

Gson gson1 = new GsonBuilder()
        .registerTypeAdapterFactory(new JsonResponseTypeAdapterFactory())       
        .registerTypeAdapterFactory(new ZipTypeAdapterFactory())
        .setPrettyPrinting()
        .create();


        String json = gson1.toJson(resp);
        System.out.println(json);

Спасибо всем за помощь.

4b9b3361

Ответ 1

Проблема в вашем JsonResponseSerializer. Вы создаете новый экземпляр Gson, а затем в этом новом экземпляре ZipSerializer не регистрируется. Вот почему ваш второй сериализатор никогда не вызывается.

Если вы хотите добиться делегирования и сложной сериализации, посмотрите TypeAdapterFactory.

Как вы сказали, если вы просто хотите фильтровать поля из сериализации, определите ExclusionStrategy.