Skip to content

Commit

Permalink
Account for different internal field names for JSON-java and Android
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcono1234 committed Jul 29, 2023
1 parent 002e249 commit f358319
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 8 deletions.
48 changes: 43 additions & 5 deletions Troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ If you cannot switch the classes you are using, see the library-specific solutio
*/
public class JsonOrgBackwardCompatibleAdapterFactory implements TypeAdapterFactory {
private abstract static class JsonOrgBackwardCompatibleAdapter<W, T> extends TypeAdapter<T> {
/** Internal field name used by JSON-java for the respective JSON value class */
/** Internal field name used by JSON-java / Android for the respective JSON value class */
private final String fieldName;
private final TypeAdapter<W> wrappedTypeAdapter;
Expand Down Expand Up @@ -228,6 +228,24 @@ If you cannot switch the classes you are using, see the library-specific solutio
}
}

/**
* For multiple alternative field names, tries to find the first which exists on the class.
*/
private static String getFieldName(Class<?> c, String... names) throws NoSuchFieldException {
NoSuchFieldException exception = null;

for (String name : names) {
try {
Field unused = c.getDeclaredField(name);
return name;
} catch (NoSuchFieldException e) {
exception = e;
}
}

throw exception;
}

@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Class<?> rawType = type.getRawType();
Expand Down Expand Up @@ -255,8 +273,18 @@ If you cannot switch the classes you are using, see the library-specific solutio

TypeAdapter<?> adapter;
if (rawType == JSONArray.class) {
// Choose correct field name depending on whether JSON-java or Android is used
String fieldName;
try {
String jsonJavaName = "myArrayList";
String androidName = "values";
fieldName = getFieldName(JSONArray.class, jsonJavaName, androidName);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Unable to get internal field name for JSONArray", e);
}

TypeAdapter<List<Object>> wrappedAdapter = gson.getAdapter(new TypeToken<List<Object>> () {});
adapter = new JsonOrgBackwardCompatibleAdapter<List<Object>, JSONArray>("myArrayList", wrappedAdapter) {
adapter = new JsonOrgBackwardCompatibleAdapter<List<Object>, JSONArray>(fieldName, wrappedAdapter) {
@Override
protected JSONArray createJsonOrgValue(List<Object> wrapped) throws JSONException {
JSONArray jsonArray = new JSONArray();
Expand All @@ -283,8 +311,18 @@ If you cannot switch the classes you are using, see the library-specific solutio
}
};
} else {
// Choose correct field name depending on whether JSON-java or Android is used
String fieldName;
try {
String jsonJavaName = "map";
String androidName = "nameValuePairs";
fieldName = getFieldName(JSONObject.class, jsonJavaName, androidName);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Unable to get internal field name for JSONObject", e);
}

TypeAdapter<Map<String, Object>> wrappedAdapter = gson.getAdapter(new TypeToken<Map<String, Object>> () {});
adapter = new JsonOrgBackwardCompatibleAdapter<Map<String, Object>, JSONObject>("map", wrappedAdapter) {
adapter = new JsonOrgBackwardCompatibleAdapter<Map<String, Object>, JSONObject>(fieldName, wrappedAdapter) {
@Override
protected JSONObject createJsonOrgValue(Map<String, Object> map) throws JSONException {
// JSONObject(Map) constructor wraps elements, so instead put elements separately to be closer
Expand Down Expand Up @@ -323,10 +361,10 @@ If you cannot switch the classes you are using, see the library-specific solutio
}
```

**Important:** Verify carefully that these `TypeAdapterFactory` classes work as expected for your use case and produce the desired JSON data or parse the JSON data without issues. There might be corner cases where they behave slightly differently than Gson's reflection-based adapter, respectively behave differently than the other JSON library would behave.
</details>

**Important:** Verify carefully that these `TypeAdapterFactory` classes work as expected for your use case and produce the desired JSON data or parse the JSON data without issues. There might be corner cases where they behave slightly differently than Gson's reflection-based adapter, respectively behave differently than the other JSON library would behave.
## <a id="android-app-random-names"></a> Android app not working in Release mode; random property names
**Symptom:** Your Android app is working fine in Debug mode but fails in Release mode and the JSON properties have seemingly random names such as `a`, `b`, ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -388,7 +389,7 @@ public void testCustomAdapters() throws JSONException {
*/
private static class JsonOrgBackwardCompatibleAdapterFactory implements TypeAdapterFactory {
private abstract static class JsonOrgBackwardCompatibleAdapter<W, T> extends TypeAdapter<T> {
/** Internal field name used by JSON-java for the respective JSON value class */
/** Internal field name used by JSON-java / Android for the respective JSON value class */
private final String fieldName;
private final TypeAdapter<W> wrappedTypeAdapter;

Expand Down Expand Up @@ -440,6 +441,24 @@ public void write(JsonWriter out, T value) throws IOException {
}
}

/**
* For multiple alternative field names, tries to find the first which exists on the class.
*/
private static String getFieldName(Class<?> c, String... names) throws NoSuchFieldException {
NoSuchFieldException exception = null;

for (String name : names) {
try {
Field unused = c.getDeclaredField(name);
return name;
} catch (NoSuchFieldException e) {
exception = e;
}
}

throw exception;
}

@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Class<?> rawType = type.getRawType();
Expand Down Expand Up @@ -467,8 +486,18 @@ public void write(JsonWriter out, T value) throws IOException {

TypeAdapter<?> adapter;
if (rawType == JSONArray.class) {
// Choose correct field name depending on whether JSON-java or Android is used
String fieldName;
try {
String jsonJavaName = "myArrayList";
String androidName = "values";
fieldName = getFieldName(JSONArray.class, jsonJavaName, androidName);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Unable to get internal field name for JSONArray", e);
}

TypeAdapter<List<Object>> wrappedAdapter = gson.getAdapter(new TypeToken<List<Object>> () {});
adapter = new JsonOrgBackwardCompatibleAdapter<List<Object>, JSONArray>("myArrayList", wrappedAdapter) {
adapter = new JsonOrgBackwardCompatibleAdapter<List<Object>, JSONArray>(fieldName, wrappedAdapter) {
@Override
protected JSONArray createJsonOrgValue(List<Object> wrapped) throws JSONException {
JSONArray jsonArray = new JSONArray();
Expand All @@ -495,8 +524,18 @@ protected List<Object> getWrapped(JSONArray jsonArray) {
}
};
} else {
// Choose correct field name depending on whether JSON-java or Android is used
String fieldName;
try {
String jsonJavaName = "map";
String androidName = "nameValuePairs";
fieldName = getFieldName(JSONObject.class, jsonJavaName, androidName);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Unable to get internal field name for JSONObject", e);
}

TypeAdapter<Map<String, Object>> wrappedAdapter = gson.getAdapter(new TypeToken<Map<String, Object>> () {});
adapter = new JsonOrgBackwardCompatibleAdapter<Map<String, Object>, JSONObject>("map", wrappedAdapter) {
adapter = new JsonOrgBackwardCompatibleAdapter<Map<String, Object>, JSONObject>(fieldName, wrappedAdapter) {
@Override
protected JSONObject createJsonOrgValue(Map<String, Object> map) throws JSONException {
// JSONObject(Map) constructor wraps elements, so instead put elements separately to be closer
Expand Down

0 comments on commit f358319

Please sign in to comment.