Java:将未知规范的嵌套 JSON 反序列化为多态哈希表
Java: Deserialize nested JSON of unknown spec to a polymorphic Hashtable
我想将具有 unknown/varied 字段名称和结构的嵌套 JSON 映射转换为通用和多态 Java 数据结构。我相信 HashMap<String,Object>
包含我的案例的这个要求。
澄清:多态仅指 String、HashMap 或 ArrayList。
这是一个例子JSON,请注意键名和结构是可变的:
{"k1":{"k2":["1","2"], "k3":{"k4":"v4","k5":"v5"}, "k6":"v6"}
我已经用 Gson 实现了它,它在创建嵌套的 Java 哈希映射时起作用,但它试图将值转换为 Java 基本 类,例如Double、Integer 等,它不仅做得非常糟糕(例如时间戳长到 Double),而且没有必要,因为我需要的只是将所有值转换为 String,除非它们是映射或数组。我猜 Object
被拿得太大方了。我用过这个:
@SerializedName("data")
HashMap<String,Object> data;
我在这里问过一个问题Retrofit2, Gson, Java: Parse received JSON values as String, only,它收集了反对票,但没有一点智慧。
现在我正在尝试使用 Moshi,例如:
@JsonClass(generateAdapter = true)
public HashMap<String, Object> data;
但仍然没有快乐,因为它抱怨 java.lang.IllegalArgumentException: Unable to create converter ...
所以,我正在寻找有关此问题的指导。我很简单,我不需要将 JSON 转换为 POJO。对于此实例,将 JSON 转换为 HashMap<String,Object>
就足够了。我在工具上很容易使用:Gson,Moshi 或者我自己定制的JSON -> 嵌套多态HashMap。有任何指示或想法吗?
在 Gson 中,无法覆盖 Object
类型适配器,因此没有直接的方法来反序列化通用类型下的字符串、列表和映射。但是,您可以假装它们三个可以有一个共同的超类型,通过引入标记类型来欺骗类型系统,例如仅标记某些共同点的注释。伪造的通用类型标记仅适用于顶级 fromJson
调用,不适用于真正强类型的字段,但是您不需要它们,正如您在问题中提到的那样。
@Target({})
@Retention(RetentionPolicy.RUNTIME)
public @interface Poly {
}
public final class PolyTypeAdapterFactory
implements TypeAdapterFactory {
private static final TypeAdapterFactory defaultInstance = new PolyTypeAdapterFactory(ArrayList::new, LinkedHashMap::new);
private final Supplier<? extends List<? super Object>> createList;
private final Supplier<? extends Map<String, ? super Object>> createMap;
private PolyTypeAdapterFactory(final Supplier<? extends List<? super Object>> createList, final Supplier<? extends Map<String, ? super Object>> createMap) {
this.createList = createList;
this.createMap = createMap;
}
public static TypeAdapterFactory getDefaultInstance() {
return defaultInstance;
}
@Override
@Nullable
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
if ( typeToken.getRawType() != Poly.class ) {
return null;
}
final TypeAdapter<Object> polyTypeAdapter = new TypeAdapter<Object>() {
@Override
public void write(final JsonWriter out, final Object o) {
throw new UnsupportedOperationException();
}
@Override
public Object read(final JsonReader in)
throws IOException {
final JsonToken token = in.peek();
switch ( token ) {
case BEGIN_ARRAY:
return readList(in);
case BEGIN_OBJECT:
return readMap(in);
case STRING:
case NUMBER:
case BOOLEAN:
return readString(in);
case NULL:
return readNull(in);
case NAME:
case END_ARRAY:
case END_OBJECT:
throw new AssertionError("Unexpected token: " + token + " at " + in);
case END_DOCUMENT:
throw new UnsupportedOperationException();
default:
throw new AssertionError(token);
}
}
@Nullable
private Object readNull(final JsonReader in)
throws IOException {
in.nextNull();
return null;
}
private String readString(final JsonReader in)
throws IOException {
return in.nextString();
}
private Map<String, Object> readMap(final JsonReader in)
throws IOException {
in.beginObject();
final Map<String, Object> map = createMap.get();
while ( in.hasNext() ) {
final String key = in.nextName();
if ( map.containsKey(key) ) {
throw new IllegalStateException("Duplicate key: " + key);
}
@Nullable
final Object value = read(in);
if ( value != null ) {
map.put(key, value);
}
}
in.endObject();
return map;
}
private List<Object> readList(final JsonReader in)
throws IOException {
in.beginArray();
final List<Object> list = createList.get();
while ( in.hasNext() ) {
final Object element = read(in);
list.add(element);
}
in.endArray();
return list;
}
}
.nullSafe();
@SuppressWarnings("unchecked")
final TypeAdapter<T> typeAdapter = (TypeAdapter<T>) polyTypeAdapter;
return typeAdapter;
}
}
上面的类型适配器检查给定的类型是否是伪超级类型,然后根据实际的 JSON 标记反序列化为三种类型:
- 每个简单文字的原始字符串(Gson
nextString
强制数字和布尔值);
- 容器的映射和列表,递归。
我稍微修改了你的 JSON 以表明数字将被强制转换为字符串:
{
"k1": {
"k2": [
"1",
2
],
"k3": {
"k4": "v4",
"k5": "v5"
},
"k6": "v6"
}
}
以下测试将通过:
public final class PolyTypeAdapterFactoryTest {
private static final Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.disableInnerClassSerialization()
.registerTypeAdapterFactory(PolyTypeAdapterFactory.getDefaultInstance())
.create();
@Test
public void test()
throws IOException {
try ( final JsonReader jsonReader = new JsonReader(...) ) {
// This is where cheating happens: we tell Gson to apply the Poly handler,
// but it returns a Map. Well, let it be for the top-most level...
final Map<String, ?> actual = gson.fromJson(jsonReader, Poly.class);
final Map<String, ?> expected = ImmutableMap.of(
"k1", ImmutableMap.of(
"k2", ImmutableList.of("1", "2"),
"k3", ImmutableMap.of(
"k4", "v4",
"k5", "v5"
),
"k6", "v6"
)
);
Assertions.assertEquals(expected, actual);
}
}
}
没有 Gson 但 org.json
解决方案
正如我在评论中提到的,您可以避免使用 Gson de/serialization 工具,并完全手动反序列化给定的 JSON:
public final class OrgJsonPolyReader {
private OrgJsonPolyReader() {
}
@Nullable
public static Object read(final JSONTokener jsonTokener) {
return read(jsonTokener, ArrayList::new, LinkedHashMap::new);
}
@Nullable
public static Object read(final JSONTokener jsonTokener, final Supplier<? extends List<? super Object>> createList,
final Supplier<? extends Map<? super String, ? super Object>> createMap) {
while ( jsonTokener.more() ) {
final char token = jsonTokener.nextClean();
switch ( token ) {
case 'n':
jsonTokener.back();
return readNull(jsonTokener);
case 'f':
case 't':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
jsonTokener.back();
return readLiteral(jsonTokener);
case '"':
jsonTokener.back();
return readString(jsonTokener);
case '[':
jsonTokener.back();
return readList(jsonTokener, createList, createMap);
case '{':
jsonTokener.back();
return readMap(jsonTokener, createList, createMap);
default:
throw new IllegalStateException("Unexpected token: " + token);
}
}
throw new AssertionError();
}
@Nullable
private static <T> T readNull(final JSONTokener jsonTokener) {
final Object value = jsonTokener.nextValue();
assert value.equals(JSONObject.NULL);
return null;
}
private static String readLiteral(final JSONTokener jsonTokener) {
return jsonTokener.nextValue().toString();
}
private static String readString(final JSONTokener jsonTokener) {
jsonTokener.next('"');
return jsonTokener.nextString('"');
}
private static List<Object> readList(final JSONTokener jsonTokener, final Supplier<? extends List<? super Object>> createList,
final Supplier<? extends Map<? super String, ? super Object>> createMap) {
jsonTokener.next('[');
final List<? super Object> list = createList.get();
for ( ; ; ) {
final char token = jsonTokener.nextClean();
switch ( token ) {
case ']':
return list;
case ',':
break;
default:
jsonTokener.back();
final Object value = read(jsonTokener, createList, createMap);
list.add(value);
break;
}
}
}
private static Map<? super String, Object> readMap(final JSONTokener jsonTokener, final Supplier<? extends List<? super Object>> createList,
final Supplier<? extends Map<? super String, ? super Object>> createMap) {
jsonTokener.next('{');
final Map<? super String, ? super Object> map = createMap.get();
for ( ; ; ) {
final char token = jsonTokener.nextClean();
switch ( token ) {
case '}':
return map;
case ',':
break;
case '"':
final String key = jsonTokener.nextString(token);
if ( map.containsKey(key) ) {
throw new IllegalStateException("Duplicate key: " + key);
}
jsonTokener.next(':');
final Object value = read(jsonTokener, createList, createMap);
map.put(key, value);
break;
default:
throw new IllegalStateException("Unexpected token: " + token);
}
}
}
}
这就是它可以添加到 Retrofit 而不是 Gson 转换器工厂的方式:
.addConverterFactory(new Converter.Factory() {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(final Type type, final Annotation[] annotations, final Retrofit retrofit) {
return responseBody -> {
try ( final Reader reader = new InputStreamReader(responseBody.byteStream()) ) {
return OrgJsonPolyReader.read(new JSONTokener(reader));
}
};
}
})
呼,这是一个漫长的旅程。希望这将帮助那些想要避免使用 Gson
或 Moshi
并有一个简单的 JSON 解析器将 JSON 字符串转换为多态(多类型?)LinkedHashMap
。多态性是指它仅包含 String
、Array
和 Map
。我个人更喜欢它而不是大量的 POJO。上面的@Fluffy 演示了如何使用 Gson
创建所述多态 Map。但同时删除 Gson
并使用 org.json
也很诱人。 @Fluffy 也提供了解决方案。
所以,同样,这个解决方案基于@Fluffy 上面的回答,但我还添加了创建一个在返回的 Map 上构造的自定义对象(这样我就不会继续对某些字段进行类型转换)。我刚刚修改了这个方法(BaseResponse3
是我的容器class):
public static Object read(final JSONTokener jsonTokener) {
Log.d(TAG, "read()/1 : called ...");
Map<? super String, ? super Object> ret = (Map) (read(
jsonTokener, ArrayList::new, LinkedHashMap::new
));
BaseResponse3 br = new BaseResponse3(
Integer.parseInt((String )(ret.get("status"))),
(String )(ret.get("message")),
(HashMap)(ret.get("data"))
);
Log.d(TAG, "EOF reached: " + br);
return br;
}
我处理的第二件事是在... android 中使用此代码。哎哟。似乎 android 内置 json.org
支持相同的命名空间。它有所修改。例如,它没有 JSONTokener(Reader ...)
构造函数。这是我发布的一个问题:org.json.JSONTokener : no constructor from Reader
所以我不得不使用一个“真实的”org.json
(在我的例子中是 https://github.com/stleary/JSON-java),我不得不将它的命名空间修改为 org.json.XYZ
并创建一个 JAR(带有我的 linux 朋友几乎没有帮助我实现一切自动化)。该 JAR 包含在 Android Studio 中,方法是将其添加到 build.gradle
(项目):
flatDir {
dirs '../../3rdparty/jars'
}
并将此添加到 build.gradle
(应用程序):
implementation fileTree(include: ['*.jar'], dir: '../../3rdparty/jars')
我现在按照@Fluffy 的说明将此 JSON 解析器合并到 Retrofit 中,使用:
Retrofit myRetrofitWithJsonOrg = new Retrofit.Builder()
.baseUrl(base_url)
.client(myOkHttpClient)
.addConverterFactory(
new Converter.Factory() {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(final Type type, final Annotation[] annotations, final Retrofit retrofit) {
return responseBody -> {
try (final Reader reader = new InputStreamReader(responseBody.byteStream())) {
return OrgJsonDeserializer.read(new org.json.XYZ.JSONTokener(reader));
}
};
}
})
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.build();
一切正常。
尽管很可能存在性能问题(到目前为止我还没有注意到)因为 Android 的 org.json
可能会以某种方式被修改比香草 org.json
更有效地处理 JSON 数据流。或 Gson
以更有效地与 OkHttp 交互。我很高兴我已经摆脱了另一个依赖的魔爪,我很难告诉它我希望它如何表现。例如,我没能告诉它 ^&^%& 停止将每个 JSON 字符串转换为 Java 基本类型。我结束了将整数转换为浮点数和时间戳(长)的荒谬状态...... Double!!!!!使用 org.json
我完全可以控制。谢谢@Fluffy。
我想将具有 unknown/varied 字段名称和结构的嵌套 JSON 映射转换为通用和多态 Java 数据结构。我相信 HashMap<String,Object>
包含我的案例的这个要求。
澄清:多态仅指 String、HashMap 或 ArrayList。
这是一个例子JSON,请注意键名和结构是可变的:
{"k1":{"k2":["1","2"], "k3":{"k4":"v4","k5":"v5"}, "k6":"v6"}
我已经用 Gson 实现了它,它在创建嵌套的 Java 哈希映射时起作用,但它试图将值转换为 Java 基本 类,例如Double、Integer 等,它不仅做得非常糟糕(例如时间戳长到 Double),而且没有必要,因为我需要的只是将所有值转换为 String,除非它们是映射或数组。我猜 Object
被拿得太大方了。我用过这个:
@SerializedName("data")
HashMap<String,Object> data;
我在这里问过一个问题Retrofit2, Gson, Java: Parse received JSON values as String, only,它收集了反对票,但没有一点智慧。
现在我正在尝试使用 Moshi,例如:
@JsonClass(generateAdapter = true)
public HashMap<String, Object> data;
但仍然没有快乐,因为它抱怨 java.lang.IllegalArgumentException: Unable to create converter ...
所以,我正在寻找有关此问题的指导。我很简单,我不需要将 JSON 转换为 POJO。对于此实例,将 JSON 转换为 HashMap<String,Object>
就足够了。我在工具上很容易使用:Gson,Moshi 或者我自己定制的JSON -> 嵌套多态HashMap。有任何指示或想法吗?
在 Gson 中,无法覆盖 Object
类型适配器,因此没有直接的方法来反序列化通用类型下的字符串、列表和映射。但是,您可以假装它们三个可以有一个共同的超类型,通过引入标记类型来欺骗类型系统,例如仅标记某些共同点的注释。伪造的通用类型标记仅适用于顶级 fromJson
调用,不适用于真正强类型的字段,但是您不需要它们,正如您在问题中提到的那样。
@Target({})
@Retention(RetentionPolicy.RUNTIME)
public @interface Poly {
}
public final class PolyTypeAdapterFactory
implements TypeAdapterFactory {
private static final TypeAdapterFactory defaultInstance = new PolyTypeAdapterFactory(ArrayList::new, LinkedHashMap::new);
private final Supplier<? extends List<? super Object>> createList;
private final Supplier<? extends Map<String, ? super Object>> createMap;
private PolyTypeAdapterFactory(final Supplier<? extends List<? super Object>> createList, final Supplier<? extends Map<String, ? super Object>> createMap) {
this.createList = createList;
this.createMap = createMap;
}
public static TypeAdapterFactory getDefaultInstance() {
return defaultInstance;
}
@Override
@Nullable
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
if ( typeToken.getRawType() != Poly.class ) {
return null;
}
final TypeAdapter<Object> polyTypeAdapter = new TypeAdapter<Object>() {
@Override
public void write(final JsonWriter out, final Object o) {
throw new UnsupportedOperationException();
}
@Override
public Object read(final JsonReader in)
throws IOException {
final JsonToken token = in.peek();
switch ( token ) {
case BEGIN_ARRAY:
return readList(in);
case BEGIN_OBJECT:
return readMap(in);
case STRING:
case NUMBER:
case BOOLEAN:
return readString(in);
case NULL:
return readNull(in);
case NAME:
case END_ARRAY:
case END_OBJECT:
throw new AssertionError("Unexpected token: " + token + " at " + in);
case END_DOCUMENT:
throw new UnsupportedOperationException();
default:
throw new AssertionError(token);
}
}
@Nullable
private Object readNull(final JsonReader in)
throws IOException {
in.nextNull();
return null;
}
private String readString(final JsonReader in)
throws IOException {
return in.nextString();
}
private Map<String, Object> readMap(final JsonReader in)
throws IOException {
in.beginObject();
final Map<String, Object> map = createMap.get();
while ( in.hasNext() ) {
final String key = in.nextName();
if ( map.containsKey(key) ) {
throw new IllegalStateException("Duplicate key: " + key);
}
@Nullable
final Object value = read(in);
if ( value != null ) {
map.put(key, value);
}
}
in.endObject();
return map;
}
private List<Object> readList(final JsonReader in)
throws IOException {
in.beginArray();
final List<Object> list = createList.get();
while ( in.hasNext() ) {
final Object element = read(in);
list.add(element);
}
in.endArray();
return list;
}
}
.nullSafe();
@SuppressWarnings("unchecked")
final TypeAdapter<T> typeAdapter = (TypeAdapter<T>) polyTypeAdapter;
return typeAdapter;
}
}
上面的类型适配器检查给定的类型是否是伪超级类型,然后根据实际的 JSON 标记反序列化为三种类型:
- 每个简单文字的原始字符串(Gson
nextString
强制数字和布尔值); - 容器的映射和列表,递归。
我稍微修改了你的 JSON 以表明数字将被强制转换为字符串:
{
"k1": {
"k2": [
"1",
2
],
"k3": {
"k4": "v4",
"k5": "v5"
},
"k6": "v6"
}
}
以下测试将通过:
public final class PolyTypeAdapterFactoryTest {
private static final Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.disableInnerClassSerialization()
.registerTypeAdapterFactory(PolyTypeAdapterFactory.getDefaultInstance())
.create();
@Test
public void test()
throws IOException {
try ( final JsonReader jsonReader = new JsonReader(...) ) {
// This is where cheating happens: we tell Gson to apply the Poly handler,
// but it returns a Map. Well, let it be for the top-most level...
final Map<String, ?> actual = gson.fromJson(jsonReader, Poly.class);
final Map<String, ?> expected = ImmutableMap.of(
"k1", ImmutableMap.of(
"k2", ImmutableList.of("1", "2"),
"k3", ImmutableMap.of(
"k4", "v4",
"k5", "v5"
),
"k6", "v6"
)
);
Assertions.assertEquals(expected, actual);
}
}
}
没有 Gson 但 org.json
解决方案
正如我在评论中提到的,您可以避免使用 Gson de/serialization 工具,并完全手动反序列化给定的 JSON:
public final class OrgJsonPolyReader {
private OrgJsonPolyReader() {
}
@Nullable
public static Object read(final JSONTokener jsonTokener) {
return read(jsonTokener, ArrayList::new, LinkedHashMap::new);
}
@Nullable
public static Object read(final JSONTokener jsonTokener, final Supplier<? extends List<? super Object>> createList,
final Supplier<? extends Map<? super String, ? super Object>> createMap) {
while ( jsonTokener.more() ) {
final char token = jsonTokener.nextClean();
switch ( token ) {
case 'n':
jsonTokener.back();
return readNull(jsonTokener);
case 'f':
case 't':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
jsonTokener.back();
return readLiteral(jsonTokener);
case '"':
jsonTokener.back();
return readString(jsonTokener);
case '[':
jsonTokener.back();
return readList(jsonTokener, createList, createMap);
case '{':
jsonTokener.back();
return readMap(jsonTokener, createList, createMap);
default:
throw new IllegalStateException("Unexpected token: " + token);
}
}
throw new AssertionError();
}
@Nullable
private static <T> T readNull(final JSONTokener jsonTokener) {
final Object value = jsonTokener.nextValue();
assert value.equals(JSONObject.NULL);
return null;
}
private static String readLiteral(final JSONTokener jsonTokener) {
return jsonTokener.nextValue().toString();
}
private static String readString(final JSONTokener jsonTokener) {
jsonTokener.next('"');
return jsonTokener.nextString('"');
}
private static List<Object> readList(final JSONTokener jsonTokener, final Supplier<? extends List<? super Object>> createList,
final Supplier<? extends Map<? super String, ? super Object>> createMap) {
jsonTokener.next('[');
final List<? super Object> list = createList.get();
for ( ; ; ) {
final char token = jsonTokener.nextClean();
switch ( token ) {
case ']':
return list;
case ',':
break;
default:
jsonTokener.back();
final Object value = read(jsonTokener, createList, createMap);
list.add(value);
break;
}
}
}
private static Map<? super String, Object> readMap(final JSONTokener jsonTokener, final Supplier<? extends List<? super Object>> createList,
final Supplier<? extends Map<? super String, ? super Object>> createMap) {
jsonTokener.next('{');
final Map<? super String, ? super Object> map = createMap.get();
for ( ; ; ) {
final char token = jsonTokener.nextClean();
switch ( token ) {
case '}':
return map;
case ',':
break;
case '"':
final String key = jsonTokener.nextString(token);
if ( map.containsKey(key) ) {
throw new IllegalStateException("Duplicate key: " + key);
}
jsonTokener.next(':');
final Object value = read(jsonTokener, createList, createMap);
map.put(key, value);
break;
default:
throw new IllegalStateException("Unexpected token: " + token);
}
}
}
}
这就是它可以添加到 Retrofit 而不是 Gson 转换器工厂的方式:
.addConverterFactory(new Converter.Factory() {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(final Type type, final Annotation[] annotations, final Retrofit retrofit) {
return responseBody -> {
try ( final Reader reader = new InputStreamReader(responseBody.byteStream()) ) {
return OrgJsonPolyReader.read(new JSONTokener(reader));
}
};
}
})
呼,这是一个漫长的旅程。希望这将帮助那些想要避免使用 Gson
或 Moshi
并有一个简单的 JSON 解析器将 JSON 字符串转换为多态(多类型?)LinkedHashMap
。多态性是指它仅包含 String
、Array
和 Map
。我个人更喜欢它而不是大量的 POJO。上面的@Fluffy 演示了如何使用 Gson
创建所述多态 Map。但同时删除 Gson
并使用 org.json
也很诱人。 @Fluffy 也提供了解决方案。
所以,同样,这个解决方案基于@Fluffy 上面的回答,但我还添加了创建一个在返回的 Map 上构造的自定义对象(这样我就不会继续对某些字段进行类型转换)。我刚刚修改了这个方法(BaseResponse3
是我的容器class):
public static Object read(final JSONTokener jsonTokener) {
Log.d(TAG, "read()/1 : called ...");
Map<? super String, ? super Object> ret = (Map) (read(
jsonTokener, ArrayList::new, LinkedHashMap::new
));
BaseResponse3 br = new BaseResponse3(
Integer.parseInt((String )(ret.get("status"))),
(String )(ret.get("message")),
(HashMap)(ret.get("data"))
);
Log.d(TAG, "EOF reached: " + br);
return br;
}
我处理的第二件事是在... android 中使用此代码。哎哟。似乎 android 内置 json.org
支持相同的命名空间。它有所修改。例如,它没有 JSONTokener(Reader ...)
构造函数。这是我发布的一个问题:org.json.JSONTokener : no constructor from Reader
所以我不得不使用一个“真实的”org.json
(在我的例子中是 https://github.com/stleary/JSON-java),我不得不将它的命名空间修改为 org.json.XYZ
并创建一个 JAR(带有我的 linux 朋友几乎没有帮助我实现一切自动化)。该 JAR 包含在 Android Studio 中,方法是将其添加到 build.gradle
(项目):
flatDir {
dirs '../../3rdparty/jars'
}
并将此添加到 build.gradle
(应用程序):
implementation fileTree(include: ['*.jar'], dir: '../../3rdparty/jars')
我现在按照@Fluffy 的说明将此 JSON 解析器合并到 Retrofit 中,使用:
Retrofit myRetrofitWithJsonOrg = new Retrofit.Builder()
.baseUrl(base_url)
.client(myOkHttpClient)
.addConverterFactory(
new Converter.Factory() {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(final Type type, final Annotation[] annotations, final Retrofit retrofit) {
return responseBody -> {
try (final Reader reader = new InputStreamReader(responseBody.byteStream())) {
return OrgJsonDeserializer.read(new org.json.XYZ.JSONTokener(reader));
}
};
}
})
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.build();
一切正常。
尽管很可能存在性能问题(到目前为止我还没有注意到)因为 Android 的 org.json
可能会以某种方式被修改比香草 org.json
更有效地处理 JSON 数据流。或 Gson
以更有效地与 OkHttp 交互。我很高兴我已经摆脱了另一个依赖的魔爪,我很难告诉它我希望它如何表现。例如,我没能告诉它 ^&^%& 停止将每个 JSON 字符串转换为 Java 基本类型。我结束了将整数转换为浮点数和时间戳(长)的荒谬状态...... Double!!!!!使用 org.json
我完全可以控制。谢谢@Fluffy。