Core: documented keep rules do not preserve reflective model construction under strict R8

未关闭
#2,193 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
3/5
预计耗时
半天
新手友好度
40/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
java
领域
build-system, data

调研方向

Start with the standalone rules in google-http-client-assembly/proguard-google-http-client.txt and the reflective path in google-http-client/src/main/java/com/google/api/client/util/Types.java (newInstance, around lines 101-119). Run the reproducer's run.py against the documented and workaround rule sets to see the three parsing cases fail and pass. Done when the documented rules keep public no-argument constructors for model classes, those cases pass, and an R8 regression test covers reflective model construction.

由索引模型根据 Issue 内容生成。

描述

JSON parsing can fail under strict R8 full mode even when using the library’s documented ProGuard rules. I reproduced this with the latest published google-http-client and google-http-client-gson 2.2.0.

The documented rules preserve generic signatures, annotations, and @Key fields, but do not explicitly preserve model classes and their public no-argument constructors. In the reproducer, R8 makes a GenericJson response model abstract and removes its constructor. Parsing then fails when the library attempts to construct that model reflectively.

Environment

  • macOS 26.5
  • OpenJDK/JBR 25.0.3
  • google-http-client and google-http-client-gson 2.2.0
  • Gson 2.11.0 and Guava 33.4.8-android
  • R8 9.4.24, bundled with AGP 9.4.1
  • R8 release mode, with setProguardCompatibility(false) and enableLegacyFullModeForKeepRules(false)

Reproduction

The attached reproducer.zip contains synthetic model fixtures, both rule configurations, and a runner. Extract it and run:

cd reproducer
python3 run.py --r8-jar /path/to/builder-9.4.1.jar

The runner downloads the pinned parsing dependencies, compiles an unminified control, and runs R8 with the documented rules and with the workaround below. R8 processes the fixture and both Google HTTP Client JARs together. Gson and Guava are supplied as library dependencies.

The runner checks these results automatically:

Test Unminified Documented rules With workaround
Plain model with typed nested list Pass Fail Pass
GenericJson model with typed nested list Pass Fail Pass
Supplied root with reflected nested model Pass Fail Pass
Parameterized request serialization Pass Pass Pass

The parsing tests assert scalar values and nested model types. The runner exits successfully only when the expected failures and successes are observed.

Representative failure

The retraced GenericJson failure includes:

Caused by: java.lang.IllegalArgumentException: unable to create new instance of class repro.a because it is abstract and because it has no accessible default constructor
    at com.google.api.client.util.Types.handleExceptionForNewInstance(Types.java:162)
    at com.google.api.client.util.Types.newInstance(Types.java:117)
    at com.google.api.client.util.Data.newMapInstance(Data.java:550)
    at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:766)
...
Caused by: java.lang.NoSuchMethodException: repro.a.<init>()

The mapping identifies repro.a as the fixture’s GenericRoot model. The other two parsing failures are ClassCastException failures associated with lost reflected model/type retention; they are not separate demonstrations of missing constructors.

Workaround

Keep the existing attribute and annotated-field rules, and additionally use:

-keepclasseswithmembers,allowobfuscation class * {
    @com.google.api.client.util.Key <fields>;
    public <init>();
}

This fixes all three parsing cases in the reproducer.

The original annotated-field rule remains necessary for models that do not match this constructor rule, including request classes with only parameterized constructors. It also preserves field names when @Key uses its default name, while the additional rule permits class-name obfuscation.

Reflective construction in 2.2.0

In 2.2.0, JSON model construction reaches Types.newInstance(), which calls Class.newInstance() and requires a public no-argument constructor.

The release’s standalone ProGuard configuration preserves attributes and annotated fields but omits constructor protection. The core JAR also does not bundle Android consumer keep rules.

Could the project update the documented rules, ship appropriate consumer rules, and add an R8 regression test for reflective model construction?

Related: #1843 reports missing documentation and a similar full-mode construction failure. PR #2171 restores the documentation using the existing rules.

For simplicity, this reproducer uses JVM classfile output. It does not test an Android APK using 2.2.0.

主要语言
Java
星标
1.4k
派生
476
平均合并
10 小时 47 分钟
30 天内合并 PR
3

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

googleapis/google-http-java-client 的其他 Issue

查看 googleapis/google-http-java-client 的全部 Issue

相似的 Issue

更多 Java Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。