Performance Optimization of JSON Serialization on Android: Replacing Gson with JSONObject and Mson
The article shows that replacing reflection‑heavy Gson with lightweight JSONObject for manual serialization and a compile‑time annotation‑processor generated library called Mson can cut JSON parsing and writing time to about one‑tenth, while maintaining compatibility and eliminating ProGuard rules for performance‑critical Android apps.
When Android applications need to read configuration files or cache data on the main thread, developers often serialize objects to JSON strings and store them using SharedPreferences. While this approach is simple, the widely used Gson library can become a performance bottleneck during serialization and deserialization, leading to noticeable UI jank and slower startup.
Profiling with Android Studio shows that Gson.fromJson consumes about 61% of the time in Activity.onCreate. The root cause is heavy reliance on reflection for every field, getter, and setter.
To eliminate the reflection overhead, the article replaces Gson with Android's lightweight JSONObject for manual serialization. The following class demonstrates a manual implementation:
public class Bean {
public String key;
public String title;
public String[] values;
public String defaultValue;
public static Bean fromJsonString(String json) {
try {
JSONObject jsonObject = new JSONObject(json);
Bean bean = new Bean();
bean.key = jsonObject.optString("key");
bean.title = jsonObject.optString("title");
JSONArray jsonArray = jsonObject.optJSONArray("values");
if (jsonArray != null && jsonArray.length() > 0) {
int len = jsonArray.length();
bean.values = new String[len];
for (int i = 0; i < len; ++i) {
bean.values[i] = jsonArray.getString(i);
}
}
bean.defaultValue = jsonObject.optString("defaultValue");
return bean;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
public static String toJsonString(Bean bean) {
if (bean == null) return null;
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("key", bean.key);
jsonObject.put("title", bean.title);
if (bean.values != null) {
JSONArray array = new JSONArray();
for (String str : bean.values) {
array.put(str);
}
jsonObject.put("values", array);
}
jsonObject.put("defaultValue", bean.defaultValue);
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObject.toString();
}
}A benchmark runs each method 1,000 times. The results show that JSONObject is roughly one‑tenth the time of Gson for both parsing and serialization.
Because many existing codebases already use Gson, rewriting everything is impractical. The article therefore proposes an annotation‑processor solution that generates serialization code at compile time for beans annotated with @JsonType. The processor extends AbstractProcessor and emits Java source files containing toJson and fromJson methods.
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(JsonType.class);
for (Element element : elements) {
if (element instanceof TypeElement) {
processTypeElement((TypeElement) element);
}
}
return false;
}The generated code uses custom interfaces IJSONObject and IJsonArray so that different high‑performance JSON back‑ends can be swapped in later.
When dealing with large JSON payloads, the article further optimizes by switching to Gson's streaming API, reading token by token and skipping unknown fields with reader.skipValue() to avoid allocating large intermediate objects.
Friend object = new Friend();
reader.beginObject();
while (reader.hasNext()) {
String field = reader.nextName();
if ("id".equals(field)) {
object.id = reader.nextInt();
} else if ("name".equals(field)) {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
object.name = null;
} else {
object.name = reader.nextString();
}
} else {
reader.skipValue();
}
}
reader.endObject();The tool, named Mson , supports a wide range of data types (primitives, wrappers, arrays, collections, maps, Sparse* arrays, and nested structures). Compatibility tests with a complex bean show that Gson has the best compatibility, Mson follows, while fastjson lags on nested types. Performance tests indicate that Mson is the fastest, with Gson and fastjson comparable.
Mson consists of only about 60 methods. For each @JsonType bean, the processor generates two methods: String toJson(Bean bean) and Bean fromJson(String data). No ProGuard keep rules are required.
Usage is straightforward:
@JsonType
public class Bean {
public String name;
public int age;
@JsonField("_desc")
public String description; // custom key
public transient boolean state; // not serialized
@JsonIgnore
public int state2; // not serialized
}Then call:
Mson.fromJson(json, Bean.class); // deserialize
Mson.toJson(bean); // serializeThe article concludes that Mson provides a high‑performance JSON serialization solution suitable for performance‑critical Android components. It also includes a recruitment notice for Meituan’s client‑side technology team.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Meituan Technology Team
Over 10,000 engineers powering China’s leading lifestyle services e‑commerce platform. Supporting hundreds of millions of consumers, millions of merchants across 2,000+ industries. This is the public channel for the tech teams behind Meituan, Dianping, Meituan Waimai, Meituan Select, and related services.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
