From 68f99f2440e93b1f80b241ea575929ffa79b9513 Mon Sep 17 00:00:00 2001 From: YOUNG CHA Date: Fri, 22 Mar 2019 17:11:11 +0900 Subject: [PATCH 01/10] Make EnumTypeAdapter friendly with obfuscation When enum value was obfuscated by proguard, EnumTypeAdapter raise NoSuchFieldException even if apply SerializedName annotation. Because EnumTypeAdapter cannot find obfuscated enum constant field with its name. --- .../google/gson/internal/bind/TypeAdapters.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java index 354ce5a1fb..f44e056a78 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java +++ b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java @@ -17,6 +17,7 @@ package com.google.gson.internal.bind; import java.io.IOException; +import java.lang.reflect.Field; import java.math.BigDecimal; import java.math.BigInteger; import java.net.InetAddress; @@ -776,9 +777,14 @@ private static final class EnumTypeAdapter> extends TypeAdapte public EnumTypeAdapter(Class classOfT) { try { - for (T constant : classOfT.getEnumConstants()) { + for (Field field : classOfT.getDeclaredFields()) { + if (!field.isEnumConstant()) { + continue; + } + field.setAccessible(true); + T constant = (T)(field.get(null)); String name = constant.name(); - SerializedName annotation = classOfT.getField(name).getAnnotation(SerializedName.class); + SerializedName annotation = field.getAnnotation(SerializedName.class); if (annotation != null) { name = annotation.value(); for (String alternate : annotation.alternate()) { @@ -788,7 +794,11 @@ public EnumTypeAdapter(Class classOfT) { nameToConstant.put(name, constant); constantToName.put(constant, name); } - } catch (NoSuchFieldException e) { + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } catch (NullPointerException e) { + throw new AssertionError(e); + } catch (ExceptionInInitializerError e) { throw new AssertionError(e); } } From 94f894cf44bb908c1dc9b5d7f0a10185a80dc7f8 Mon Sep 17 00:00:00 2001 From: YOUNG CHA Date: Mon, 25 Mar 2019 11:37:09 +0900 Subject: [PATCH 02/10] Add testcase for obfuscated enum class --- gson/pom.xml | 87 +++++++++++++++++++ .../functional/EnumWithObfuscatedTest.java | 60 +++++++++++++ gson/testcases-proguard.conf | 20 +++++ 3 files changed, 167 insertions(+) create mode 100644 gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java create mode 100644 gson/testcases-proguard.conf diff --git a/gson/pom.xml b/gson/pom.xml index 83f52b3a29..bc5e8806a1 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -16,6 +16,12 @@ junit test + + com.github.wvengen + proguard-maven-plugin + 2.0.14 + test + @@ -69,6 +75,87 @@ + + com.coderplus.maven.plugins + copy-rename-maven-plugin + 1.0 + + + pre-obfuscate-class + process-test-classes + + rename + + + + + ${project.build.directory}/test-classes/com/google/gson/functional/EnumWithObfuscatedTest.class + ${project.build.directory}/test-classes-obfuscated-injar/com/google/gson/functional/EnumWithObfuscatedTest.class + + + ${project.build.directory}/test-classes/com/google/gson/functional/EnumWithObfuscatedTest$Gender.class + ${project.build.directory}/test-classes-obfuscated-injar/com/google/gson/functional/EnumWithObfuscatedTest$Gender.class + + + + + + + + com.github.wvengen + proguard-maven-plugin + + + process-test-classes + proguard + + + + 6.0.2 + true + test-classes-obfuscated-injar + test-classes-obfuscated-outjar + **/*.class + ${basedir}/testcases-proguard.conf + + ${project.build.directory}/classes + ${java.home}/jmods/java.base.jmod + + + + + net.sf.proguard + proguard-base + 6.0.2 + runtime + + + + + maven-resources-plugin + 2.7 + + + post-obfuscate-class + process-test-classes + + copy-resources + + + ${project.build.directory}/test-classes/com/google/gson/functional + + + ${project.build.directory}/test-classes-obfuscated-outjar/classes/classes/com/google/gson/functional + + EnumWithObfuscatedTest.class + EnumWithObfuscatedTest$Gender.class + + + + + + + diff --git a/gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java b/gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java new file mode 100644 index 0000000000..a829b07349 --- /dev/null +++ b/gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 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.functional; + +import java.lang.reflect.Field; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import junit.framework.TestCase; + +/** + * Functional tests for enums with Proguard. + * + * @author Young Cha + */ +public class EnumWithObfuscatedTest extends TestCase { + private Gson gson; + + @Override + protected void setUp() throws Exception { + super.setUp(); + gson = new Gson(); + } + + public enum Gender { + @SerializedName("MAIL") + MALE, + + @SerializedName("FEMAIL") + FEMALE + } + + public void testEnumClassWithObfuscated() { + for (Gender enumConstant: Gender.class.getEnumConstants()) { + try { + Gender.class.getField(enumConstant.name()); + fail("Enum is not obfuscated"); + } catch (NoSuchFieldException ignore) { + } + } + + assertEquals(Gender.MALE, gson.fromJson("\"MAIL\"", Gender.class)); + assertEquals("\"MAIL\"", gson.toJson(Gender.MALE, Gender.class)); + } +} diff --git a/gson/testcases-proguard.conf b/gson/testcases-proguard.conf new file mode 100644 index 0000000000..d42da0abef --- /dev/null +++ b/gson/testcases-proguard.conf @@ -0,0 +1,20 @@ +# Options from Android Gradle Plugins +# https://android.googlesource.com/platform/tools/base/+/refs/heads/studio-master-dev/build-system/gradle-core/src/main/resources/com/android/build/gradle +-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/* +-optimizationpasses 5 +-allowaccessmodification +-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep enum com.google.gson.functional.EnumWithObfuscatedTest$Gender +-keep class com.google.gson.functional.EnumWithObfuscatedTest { + public void test*(); + protected void setUp(); +} + +-dontwarn com.google.gson.functional.EnumWithObfuscatedTest +-dontwarn junit.framework.TestCase + From 7988fbfa9047f4373bd382efb1b5add660e28cfd Mon Sep 17 00:00:00 2001 From: YOUNG HO CHA Date: Thu, 10 Sep 2020 20:13:41 +0900 Subject: [PATCH 03/10] Update proguard plugin to support Java 11 compiler --- gson/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gson/pom.xml b/gson/pom.xml index bc5e8806a1..3ecd69a193 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -19,7 +19,7 @@ com.github.wvengen proguard-maven-plugin - 2.0.14 + 2.3.1 test @@ -111,7 +111,7 @@ - 6.0.2 + 6.2.2 true test-classes-obfuscated-injar test-classes-obfuscated-outjar @@ -126,7 +126,7 @@ net.sf.proguard proguard-base - 6.0.2 + 6.2.2 runtime From 1406477d0cd37e8d5d04e619ac349f0a6da614e3 Mon Sep 17 00:00:00 2001 From: YOUNG HO CHA Date: Thu, 10 Sep 2020 20:26:10 +0900 Subject: [PATCH 04/10] Fix post-obfuscate-class task to include obfuscated test classes --- gson/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gson/pom.xml b/gson/pom.xml index 3ecd69a193..baf919e30c 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -145,7 +145,7 @@ ${project.build.directory}/test-classes/com/google/gson/functional - ${project.build.directory}/test-classes-obfuscated-outjar/classes/classes/com/google/gson/functional + ${project.build.directory}/test-classes-obfuscated-outjar/com/google/gson/functional EnumWithObfuscatedTest.class EnumWithObfuscatedTest$Gender.class From e99a4b1cb721d8153c4cf9659571fe7ea352799b Mon Sep 17 00:00:00 2001 From: YOUNG HO CHA Date: Sat, 12 Sep 2020 13:35:15 +0900 Subject: [PATCH 05/10] Move testcases-proguard.conf into gson/src/test/resources --- gson/pom.xml | 2 +- gson/{ => src/test/resources}/testcases-proguard.conf | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename gson/{ => src/test/resources}/testcases-proguard.conf (100%) diff --git a/gson/pom.xml b/gson/pom.xml index baf919e30c..14089475a0 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -116,7 +116,7 @@ test-classes-obfuscated-injar test-classes-obfuscated-outjar **/*.class - ${basedir}/testcases-proguard.conf + ${basedir}/src/test/resources/testcases-proguard.conf ${project.build.directory}/classes ${java.home}/jmods/java.base.jmod diff --git a/gson/testcases-proguard.conf b/gson/src/test/resources/testcases-proguard.conf similarity index 100% rename from gson/testcases-proguard.conf rename to gson/src/test/resources/testcases-proguard.conf From 92a98dab02891af20913c07b4172614ca81b64b6 Mon Sep 17 00:00:00 2001 From: YOUNG HO CHA Date: Sat, 12 Sep 2020 13:36:14 +0900 Subject: [PATCH 06/10] Removed unused import --- .../java/com/google/gson/functional/EnumWithObfuscatedTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java b/gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java index a829b07349..8ad206a23a 100644 --- a/gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java +++ b/gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java @@ -16,8 +16,6 @@ package com.google.gson.functional; -import java.lang.reflect.Field; - import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; From 6ac9f7d8400851fa3d0a136817e880126de9840b Mon Sep 17 00:00:00 2001 From: YOUNG HO CHA Date: Sat, 12 Sep 2020 13:40:09 +0900 Subject: [PATCH 07/10] Suppress unchecked type cast warning --- .../main/java/com/google/gson/internal/bind/TypeAdapters.java | 1 + 1 file changed, 1 insertion(+) diff --git a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java index f44e056a78..f504ad3f8a 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java +++ b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java @@ -782,6 +782,7 @@ public EnumTypeAdapter(Class classOfT) { continue; } field.setAccessible(true); + @SuppressWarnings("unchecked") T constant = (T)(field.get(null)); String name = constant.name(); SerializedName annotation = field.getAnnotation(SerializedName.class); From 20720d6a400eaea63c44f088479daea426e2de99 Mon Sep 17 00:00:00 2001 From: YOUNG HO CHA Date: Sat, 12 Sep 2020 13:57:35 +0900 Subject: [PATCH 08/10] Remove unnecessary catch block --- .../main/java/com/google/gson/internal/bind/TypeAdapters.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java index f504ad3f8a..e8052a708c 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java +++ b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java @@ -797,10 +797,6 @@ public EnumTypeAdapter(Class classOfT) { } } catch (IllegalAccessException e) { throw new AssertionError(e); - } catch (NullPointerException e) { - throw new AssertionError(e); - } catch (ExceptionInInitializerError e) { - throw new AssertionError(e); } } @Override public T read(JsonReader in) throws IOException { From 59a8aedb37ae35d4d2a4306c92efd463fffaaf69 Mon Sep 17 00:00:00 2001 From: YOUNG HO CHA Date: Wed, 4 Aug 2021 12:24:55 +0900 Subject: [PATCH 09/10] Use SecurityManager to read enum fields --- .../com/google/gson/internal/bind/TypeAdapters.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java index e8052a708c..04b13ada81 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java +++ b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java @@ -24,6 +24,8 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.sql.Timestamp; import java.util.ArrayList; import java.util.BitSet; @@ -777,11 +779,16 @@ private static final class EnumTypeAdapter> extends TypeAdapte public EnumTypeAdapter(Class classOfT) { try { - for (Field field : classOfT.getDeclaredFields()) { + for (final Field field : classOfT.getDeclaredFields()) { if (!field.isEnumConstant()) { continue; } - field.setAccessible(true); + AccessController.doPrivileged(new PrivilegedAction() { + @Override public Void run() { + field.setAccessible(true); + return null; + } + }); @SuppressWarnings("unchecked") T constant = (T)(field.get(null)); String name = constant.name(); From d8c5fcf00bdd3170365e92e43880021031c7d005 Mon Sep 17 00:00:00 2001 From: YOUNG HO CHA Date: Wed, 4 Aug 2021 12:30:07 +0900 Subject: [PATCH 10/10] Fix indentation of EnumWithObfuscatedTest --- .../google/gson/functional/EnumWithObfuscatedTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java b/gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java index 8ad206a23a..080b81fa77 100644 --- a/gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java +++ b/gson/src/test/java/com/google/gson/functional/EnumWithObfuscatedTest.java @@ -45,11 +45,11 @@ public enum Gender { public void testEnumClassWithObfuscated() { for (Gender enumConstant: Gender.class.getEnumConstants()) { - try { - Gender.class.getField(enumConstant.name()); - fail("Enum is not obfuscated"); - } catch (NoSuchFieldException ignore) { - } + try { + Gender.class.getField(enumConstant.name()); + fail("Enum is not obfuscated"); + } catch (NoSuchFieldException ignore) { + } } assertEquals(Gender.MALE, gson.fromJson("\"MAIL\"", Gender.class));