mirror of
https://github.com/google/gson.git
synced 2026-03-13 08:01:59 +08:00
Remove outdated android-proguard-example (#2843)
* Remove outdated android-proguard-example
* Apply suggestions from code review
Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>
* Apply suggestions from code review
Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>
* Apply suggestions from code review
Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>
* Fix typos and revert a review change
* Correct the header to align with refs
* Try out the ref id for ProGuard / R8 header
* Revert "Try out the ref id for ProGuard / R8 header"
This reverts commit e8f52fb490.
* Rearrange
---------
Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -18,5 +18,3 @@ local.properties
|
||||
build
|
||||
|
||||
.DS_Store
|
||||
|
||||
examples/android-proguard-example/gen
|
||||
|
||||
@@ -77,6 +77,10 @@ Older Gson versions may also support lower API levels, however this has not been
|
||||
|
||||
Please use the ['gson' tag on StackOverflow](https://stackoverflow.com/questions/tagged/gson), [GitHub Discussions](https://github.com/google/gson/discussions) or the [google-gson Google group](https://groups.google.com/group/google-gson) to discuss Gson or to post questions.
|
||||
|
||||
### ProGuard / R8
|
||||
|
||||
See the details in the related section in the [Troubleshooting guide](Troubleshooting.md#proguard--r8).
|
||||
|
||||
### Related Content Created by Third Parties
|
||||
* [Gson Tutorial](https://www.studytrails.com/java/json/java-google-json-introduction/) by `StudyTrails`
|
||||
* [Gson Tutorial Series](https://futurestud.io/tutorials/gson-getting-started-with-java-json-serialization-deserialization) by `Future Studio`
|
||||
|
||||
@@ -22,7 +22,8 @@ This guide describes how to troubleshoot common issues when using Gson.
|
||||
The overloads with `Type` parameter do not provide any type-safety guarantees.
|
||||
- When using `TypeToken` make sure you don't capture a type variable. For example avoid something like `new TypeToken<List<T>>()` (where `T` is a type variable). Due to Java [type erasure](https://dev.java/learn/generics/type-erasure/) the actual type of `T` is not available at runtime. Refactor your code to pass around `TypeToken` instances or use [`TypeToken.getParameterized(...)`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/reflect/TypeToken.html#getParameterized(java.lang.reflect.Type,java.lang.reflect.Type...)), for example `TypeToken.getParameterized(List.class, elementType)` where `elementType` is a type you have to provide separately.
|
||||
|
||||
If you are using a code shrinking tool such as ProGuard or R8 (for example when building an Android app), make sure it is correctly configured to keep generic signatures and to keep Gson's `TypeToken` class. See the [Android example](examples/android-proguard-example/README.md) for more information.
|
||||
If you are using a code shrinking tool such as ProGuard / R8 (for example when building an Android app), make sure it is correctly configured to keep generic signatures and to keep Gson's `TypeToken` class.
|
||||
See the [ProGuard / R8](#proguard--r8) section for more information.
|
||||
|
||||
## <a id="reflection-inaccessible"></a> `InaccessibleObjectException`: 'module ... does not "opens ..." to unnamed module'
|
||||
|
||||
@@ -67,7 +68,8 @@ Or in case this occurs for a field in one of your classes which you did not actu
|
||||
|
||||
**Reason:** You probably have not configured ProGuard / R8 correctly
|
||||
|
||||
**Solution:** Make sure you have configured ProGuard / R8 correctly to preserve the names of your fields. See the [Android example](examples/android-proguard-example/README.md) for more information.
|
||||
**Solution:** Make sure you have configured ProGuard / R8 correctly to preserve the names of your fields.
|
||||
See the section below, it's related to this issue.
|
||||
|
||||
## <a id="android-app-broken-after-app-update"></a> Android app unable to parse JSON after app update
|
||||
|
||||
@@ -75,7 +77,8 @@ Or in case this occurs for a field in one of your classes which you did not actu
|
||||
|
||||
**Reason:** You probably have not configured ProGuard / R8 correctly; probably the field names are being obfuscated and their naming changed between the versions of your app
|
||||
|
||||
**Solution:** Make sure you have configured ProGuard / R8 correctly to preserve the names of your fields. See the [Android example](examples/android-proguard-example/README.md) for more information.
|
||||
**Solution:** Make sure you have configured ProGuard / R8 correctly to preserve the names of your fields.
|
||||
See the [ProGuard / R8](#proguard--r8) section for more information.
|
||||
|
||||
If you want to preserve backward compatibility for you app you can use [`@SerializedName`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/annotations/SerializedName.html) on the fields to specify the obfuscated name as alternate, for example: `@SerializedName(value = "myprop", alternate = "a")`
|
||||
|
||||
@@ -346,7 +349,7 @@ For older Gson versions a `RuntimeException` with message 'Missing type paramete
|
||||
-keep class * extends com.google.gson.reflect.TypeToken
|
||||
```
|
||||
|
||||
See also the [Android example](examples/android-proguard-example/README.md) for more information.
|
||||
See the [ProGuard / R8](#proguard--r8) section for more information.
|
||||
|
||||
Note: For newer Gson versions these rules might be applied automatically; make sure you are using the latest Gson version and the latest version of the code shrinking tool.
|
||||
|
||||
@@ -393,3 +396,11 @@ For backward compatibility it is possible to restore Gson's old behavior of allo
|
||||
|
||||
- This does not solve any of the type-safety problems mentioned above; in the long term you should prefer one of the other solutions listed above. This system property might be removed in future Gson versions.
|
||||
- You should only ever set the property to `"true"`, but never to any other value or manually clear it. Otherwise this might counteract any libraries you are using which might have deliberately set the system property because they rely on its behavior.
|
||||
|
||||
## ProGuard / R8
|
||||
|
||||
If you use Gson as a dependency in an Android project which uses R8 or ProGuard as code shrinking and obfuscation tool you don't have to do anything.
|
||||
The specific rules are [already bundled](gson/src/main/resources/META-INF/proguard/gson.pro) (from Gson 2.11.0) into
|
||||
the JAR which can be interpreted by R8 automatically. For users who still use older Gson versions, you may need to
|
||||
copy the rules from the [`gson.pro`](gson/src/main/resources/META-INF/proguard/gson.pro) file into your own ProGuard
|
||||
configuration file.
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.gson.examples.android"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<uses-sdk android:minSdkVersion="3"/>
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name">
|
||||
<activity android:name=".GsonProguardExampleActivity"
|
||||
android:label="@string/app_name"
|
||||
android:exported="true"
|
||||
android:icon="@drawable/icon"
|
||||
android:configChanges="keyboardHidden|orientation"
|
||||
android:enabled="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
</manifest>
|
||||
@@ -1,20 +0,0 @@
|
||||
# android-proguard-example
|
||||
|
||||
Example Android project showing how to properly configure [ProGuard](https://www.guardsquare.com/proguard).
|
||||
ProGuard is a tool for 'shrinking' and obfuscating compiled classes. It can rename methods and fields,
|
||||
or remove them if they appear to be unused. This can cause issues for Gson which uses Java reflection to
|
||||
access the fields of a class. It is necessary to configure ProGuard to make sure that Gson works correctly.
|
||||
|
||||
Also have a look at the [ProGuard manual](https://www.guardsquare.com/manual/configuration/usage#keepoverview)
|
||||
and the [ProGuard Gson examples](https://www.guardsquare.com/manual/configuration/examples#gson) for more
|
||||
details on how ProGuard can be configured.
|
||||
|
||||
The R8 code shrinker uses the same rule format as ProGuard, but there are differences between these two
|
||||
tools. Have a look at R8's Compatibility FAQ, and especially at the [Gson section](https://r8.googlesource.com/r8/+/refs/heads/main/compatibility-faq.md#gson).
|
||||
|
||||
Note that the latest Gson versions (> 2.10.1) apply some of the rules shown in `proguard.cfg` automatically by default,
|
||||
see the file [`gson/META-INF/proguard/gson.pro`](/gson/src/main/resources/META-INF/proguard/gson.pro) for
|
||||
the Gson version you are using. In general if your classes are top-level classes or are `static`, have a no-args constructor and their fields are annotated with Gson's [`@SerializedName`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/annotations/SerializedName.html), you might not have to perform any additional ProGuard or R8 configuration.
|
||||
|
||||
An alternative to writing custom keep rules for your classes in the ProGuard configuration can be to use
|
||||
Android's [`@Keep` annotation](https://developer.android.com/studio/write/annotations#keep).
|
||||
@@ -1,12 +0,0 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system use,
|
||||
# "build.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-3
|
||||
proguard.config=proguard.cfg
|
||||
@@ -1,32 +0,0 @@
|
||||
##---------------Begin: proguard configuration for Gson ----------
|
||||
# Gson uses generic type information stored in a class file when working with fields. Proguard
|
||||
# removes such information by default, so configure it to keep all of it.
|
||||
-keepattributes Signature
|
||||
|
||||
# For using GSON @Expose annotation
|
||||
-keepattributes *Annotation*
|
||||
|
||||
# Gson specific classes
|
||||
-dontwarn sun.misc.**
|
||||
#-keep class com.google.gson.stream.** { *; }
|
||||
|
||||
# Application classes that will be serialized/deserialized over Gson
|
||||
-keep class com.google.gson.examples.android.model.** { <fields>; }
|
||||
|
||||
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
|
||||
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
|
||||
-keep class * extends com.google.gson.TypeAdapter
|
||||
-keep class * implements com.google.gson.TypeAdapterFactory
|
||||
-keep class * implements com.google.gson.JsonSerializer
|
||||
-keep class * implements com.google.gson.JsonDeserializer
|
||||
|
||||
# Prevent R8 from leaving Data object members always null
|
||||
-keepclassmembers,allowobfuscation class * {
|
||||
@com.google.gson.annotations.SerializedName <fields>;
|
||||
}
|
||||
|
||||
# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
|
||||
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
|
||||
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
|
||||
|
||||
##---------------End: proguard configuration for Gson ----------
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 KiB |
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<TextView android:id="@+id/tv"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Gson Proguard Example</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.gson.examples.android;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.examples.android.model.Cart;
|
||||
import com.google.gson.examples.android.model.LineItem;
|
||||
|
||||
/**
|
||||
* Activity class illustrating how to use proguard with Gson
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
*/
|
||||
public class GsonProguardExampleActivity extends Activity {
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
setContentView(R.layout.main);
|
||||
TextView tv = (TextView) findViewById(R.id.tv);
|
||||
Gson gson = new Gson();
|
||||
Cart cart = buildCart();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Gson.toJson() example: \n");
|
||||
sb.append(" Cart Object: ").append(cart).append('\n');
|
||||
sb.append(" Cart JSON: ").append(gson.toJson(cart)).append('\n');
|
||||
sb.append("\n\nGson.fromJson() example: \n");
|
||||
String json = "{buyer:'Happy Camper',creditCard:'4111-1111-1111-1111',"
|
||||
+ "lineItems:[{name:'nails',priceInMicros:100000,quantity:100,currencyCode:'USD'}]}";
|
||||
sb.append("Cart JSON: ").append(json).append('\n');
|
||||
sb.append("Cart Object: ").append(gson.fromJson(json, Cart.class)).append('\n');
|
||||
tv.setText(sb.toString());
|
||||
tv.invalidate();
|
||||
}
|
||||
|
||||
private Cart buildCart() {
|
||||
List<LineItem> lineItems = new ArrayList<>();
|
||||
lineItems.add(new LineItem("hammer", 1, 12000000, "USD"));
|
||||
return new Cart(lineItems, "Happy Buyer", "4111-1111-1111-1111");
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.gson.examples.android.model;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* A model object representing a cart that can be posted to an order-processing server
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
*/
|
||||
public class Cart {
|
||||
public final List<LineItem> lineItems;
|
||||
|
||||
@SerializedName("buyer")
|
||||
private final String buyerName;
|
||||
|
||||
private final String creditCard;
|
||||
|
||||
public Cart(List<LineItem> lineItems, String buyerName, String creditCard) {
|
||||
this.lineItems = lineItems;
|
||||
this.buyerName = buyerName;
|
||||
this.creditCard = creditCard;
|
||||
}
|
||||
|
||||
public List<LineItem> getLineItems() {
|
||||
return lineItems;
|
||||
}
|
||||
|
||||
public String getBuyerName() {
|
||||
return buyerName;
|
||||
}
|
||||
|
||||
public String getCreditCard() {
|
||||
return creditCard;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder itemsText = new StringBuilder();
|
||||
boolean first = true;
|
||||
if (lineItems != null) {
|
||||
try {
|
||||
Class<?> fieldType = Cart.class.getField("lineItems").getType();
|
||||
System.out.println("LineItems CLASS: " + getSimpleTypeName(fieldType));
|
||||
} catch (SecurityException e) {
|
||||
} catch (NoSuchFieldException e) {
|
||||
}
|
||||
for (LineItem item : lineItems) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
itemsText.append("; ");
|
||||
}
|
||||
itemsText.append(item);
|
||||
}
|
||||
}
|
||||
return "[BUYER: " + buyerName + "; CC: " + creditCard + "; "
|
||||
+ "LINE_ITEMS: " + itemsText.toString() + "]";
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static String getSimpleTypeName(Type type) {
|
||||
if (type == null) {
|
||||
return "null";
|
||||
}
|
||||
if (type instanceof Class) {
|
||||
return ((Class)type).getSimpleName();
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
ParameterizedType pType = (ParameterizedType) type;
|
||||
StringBuilder sb = new StringBuilder(getSimpleTypeName(pType.getRawType()));
|
||||
sb.append('<');
|
||||
boolean first = true;
|
||||
for (Type argumentType : pType.getActualTypeArguments()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(getSimpleTypeName(argumentType));
|
||||
}
|
||||
sb.append('>');
|
||||
return sb.toString();
|
||||
} else if (type instanceof WildcardType) {
|
||||
return "?";
|
||||
}
|
||||
return type.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.gson.examples.android.model;
|
||||
|
||||
/**
|
||||
* A line item in a cart. This is not a rest resource, just a dependent object
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
*/
|
||||
public class LineItem {
|
||||
private final String name;
|
||||
private final int quantity;
|
||||
private final long priceInMicros;
|
||||
private final String currencyCode;
|
||||
|
||||
public LineItem(String name, int quantity, long priceInMicros, String currencyCode) {
|
||||
this.name = name;
|
||||
this.quantity = quantity;
|
||||
this.priceInMicros = priceInMicros;
|
||||
this.currencyCode = currencyCode;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public long getPriceInMicros() {
|
||||
return priceInMicros;
|
||||
}
|
||||
|
||||
public String getCurrencyCode() {
|
||||
return currencyCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("(item: %s, qty: %s, price: %.2f %s)",
|
||||
name, quantity, priceInMicros / 1000000d, currencyCode);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user