Вам не нужна карта. Вы можете написать свой собственный десериализатор JSON. Скажем, у вас есть следующие JSON, где вам не нужно корневой объект один ключ:
{
"idontcareaboutthis": {
"foo": 1,
"bar": 2
}
}
Тогда JSON десериализатор может выглядеть следующим образом:
final class ResponseJsonDeserializer<T>
implements JsonDeserializer<T> {
private final Gson backingGson;
private ResponseJsonDeserializer(final Gson backingGson) {
this.backingGson = backingGson;
}
static <T> JsonDeserializer<T> getResponseJsonDeserializer(final Gson backingGson) {
return new ResponseJsonDeserializer<>(backingGson);
}
@Override
public T deserialize(final JsonElement json, final Type type, final JsonDeserializationContext context)
throws JsonParseException {
final JsonObject root = json.getAsJsonObject();
final Set<Entry<String, JsonElement>> entries = root.entrySet();
final int propertyCount = entries.size();
if (propertyCount != 1) {
throw new JsonParseException("Expected a single property root object, but got an object with " + propertyCount + " properties");
}
final Entry<String, JsonElement> inner = entries.iterator().next();
// Can't use context.deserialize here due to recursion
return backingGson.fromJson(inner.getValue(), type);
}
}
Обратите внимание, как выше десериализатор извлекает root и как он делегирует процесс десериализации на другой экземпляр Gson. Теперь вам нужно создать экземпляр Gson, который знает о свойстве idontcareaboutthis
.
private static final Gson registryBackingGson = new GsonBuilder()
// whatever necessary here
.create();
private static final Gson registryGson = new GsonBuilder()
.registerTypeAdapter(FooBarResponse.class, getResponseJsonDeserializer(registryBackingGson))
// add another response classes here like the above, but do not register other types - they must be registered in registryBackingGson
.create();
registryGson
требует либо перечисления всех классов ответа или регистрацию определенной иерархии типов. Если первый случай вам не очень удобен, и вы можете изменить исходный код классов ответов, вы можете добавить специальный интерфейс маркера, чтобы зарегистрировать всю иерархию типов. Скажем, что-то вроде этого:
private static final Gson registryBackingGson = new GsonBuilder()
// whatever necessary here
.create();
private static final Gson registryGson = new GsonBuilder()
.registerTypeHierarchyAdapter(IResponse.class, getResponseJsonDeserializer(registryBackingGson))
// no need to add another "response" classes here - they just must implement the marker interface
.create();
Объект передачи данных:
final class FooBarResponse {
// The `final` modifier is a reasonable habit for incoming DTO classes, but primitive constants are inlined by the compiler.
// Suppressing the inlining can be done be a simple workaround to make javac think that it's not a real constant.
// However, it's a matter of your code style, and this is just an example.
private final int foo = constOf(0);
private final int bar = constOf(0);
int getFoo() {
return foo;
}
int getBar() {
return bar;
}
// We're cheating...
private static int constOf(final int i) {
return i;
}
}
А если вы предпочитаете интерфейс маркеров и регистрацию иерархии
interface IResponse {
}
final class FooBarResponse
implements IResponse {
...
всего типа А как это работает :
final FooBarResponse fooBar = registryGson.fromJson(JSON, FooBarResponse.class)
out.println(fooBar.getFoo()); // 1
out.println(fooBar.getBar()); // 2
дооснащения адаптер:
final Retrofit retrofit = new Retrofit.Builder()
// ...
.addConverterFactory(GsonConverterFactory.create(registryGson))
.build();
Таким образом, ваши методы дооснащения-базовый интерфейс может вернуть FooBar
/и т.д. экземпляров класса, а не карты.
Использование преобразователей. 1. http://square.github.io/retrofit/#restadapter-configuration 2. «Retrofit.Builder.addConverterFactory (фабрика Converter.Factory)' 3. (При использовании Gson) Создайте файл, похожий на GsonConverterFactory. java добавляет вашу пользовательскую логику. – Sangharsh