firebase / firebase/firebase-admin-java
google-http-client-jackson2 cannot be excluded even when a JsonFactory is configured via FirebaseOptions
- 主要語言
- Java
- 星號
- 620
- 分支
- 305
- 平均合併
- 3 小時 23 分鐘
- 30 天內合併 PR
- 1
描述
### Describe your environment
* Operating System version: Amazon Linux 2023 (AWS ECS Fargate), also reproduced on macOS 15
* Firebase SDK version: 9.7.1 (the code in question is unchanged on `v9.10.0`)
* Library version: `com.google.firebase:firebase-admin:9.7.1`, Java 25, Spring Boot 4.1
* Firebase Product: messaging (FCM only — no Firestore, Storage, Realtime Database or FirebaseAuth)
### Describe the problem
`google-http-client-jackson2` is a hard runtime requirement, and `FirebaseOptions.setJsonFactory(...)` is not sufficient to avoid it. Excluding the artifact still throws `ClassNotFoundException` on the first FCM send, which forces ~580 KB of Jackson 2 into deployments whose Firebase usage is otherwise entirely Gson-based.
#### Steps to reproduce:
1. Configure `FirebaseOptions` with an explicit transport **and** JSON factory (see code below).
2. Exclude `com.google.http-client:google-http-client-jackson2` from the build.
3. Start the application — startup succeeds, both `FirebaseApp` instances initialize fine.
4. Send a message via `FirebaseMessaging.sendEachForMulticast(...)` — fails:
```
java.lang.ClassNotFoundException: com.google.api.client.json.jackson2.JacksonFactory
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:490)
at com.google.firebase.messaging.FirebaseMessagingClientImpl.fromApp(FirebaseMessagingClientImpl.java:193)
at com.google.firebase.messaging.FirebaseMessaging$7.get(FirebaseMessaging.java:637)
at com.google.firebase.messaging.FirebaseMessaging$7.get(FirebaseMessaging.java:634)
at com.google.common.base.Suppliers$NonSerializableMemoizingSupplier.get(Suppliers.java:201)
at com.google.firebase.messaging.FirebaseMessaging.getMessagingClient(FirebaseMessaging.java:519)
at com.google.firebase.messaging.FirebaseMessaging.sendOpForSendResponse(FirebaseMessaging.java:253)
```
The failure only surfaces on the first send, because `getMessagingClient()` is lazy and memoized — so a startup smoke test does not catch it.
The configured factory does appear to be honoured for messaging itself; something in the request-factory / credentials initialization path loads `JacksonFactory` regardless of configuration.
#### Relevant Code:
```java
FirebaseOptions.builder()
.setHttpTransport(new NetHttpTransport())
.setJsonFactory(GsonFactory.getDefaultInstance())
.setCredentials(GoogleCredentials.fromStream(serviceAccountJson))
.build();
```
We use FCM only, and prune the parts of the SDK we do not need:
```xml
com.google.firebase
firebase-admin
com.google.cloud
*
io.netty
*
```
### Why this matters
After that pruning, everything remaining is Gson-based. Credentials come from `GoogleCredentials`, and `google-auth-library-oauth2-http` uses `GsonFactory` (`OAuth2Utils.JSON_FACTORY`), which brings `google-http-client-gson` + `gson` 2.13.2 (283 KB) in at compile scope. Despite that, we must also ship:
```
+- com.google.http-client:google-http-client-jackson2:jar:runtime
| \- com.fasterxml.jackson.core:jackson-core:jar:2.21.4:runtime <- 580 KB, sole consumer
```
Jackson 2 is roughly twice the size of the Gson stack it duplicates, and nothing else on our classpath requires it.
This is amplified on Spring Boot 4.x, which moved to Jackson 3 (`tools.jackson`). Applications now carry **both** Jackson generations side by side, with Jackson 2 present solely to satisfy firebase-admin.
### The blocker cited in the code may be stale
```java
public static JsonFactory getDefaultJsonFactory() {
// Force using the Jackson2 parser for this project for now. Eventually we should switch
// to Gson, but there are some issues that are preventing this migration at the moment.
// See https://github.com/googleapis/google-api-java-client/issues/1779 for details.
return JacksonFactory.getDefaultInstance();
}
```
googleapis/google-api-java-client#1779 was closed on 2021-04-29 as triage rather than fixed, splitting into three sub-bugs. Per a 2023-03-03 comment on that issue from a Gson maintainer:
* floating-point serialization — **fixed**
* parser leniency — **addressed** by Gson's strict-parsing API
* exception handling — tracked in googleapis/google-http-java-client#1353, which is a *documentation* issue
`ApiClientUtils.java` does not appear to have been revisited on this point since (subsequent commits touch transports and copyright headers).
### Ask
Any of these would help:
1. Make the Jackson2 dependency genuinely optional when a `JsonFactory` is supplied via `FirebaseOptions`.
2. Switch the default to `GsonFactory`, if the 2021 blockers no longer apply.
3. Failing both, document that `google-http-client-jackson2` is a hard requirement — that alone would save others the investigation.
貢獻指南
研究方向
從 ApiClientUtils.java 和堆疊追蹤中顯示的 FirebaseMessagingClientImpl.fromApp 路徑開始,然後使用 issue 中的 FirebaseOptions 設定重現 Maven 排除和首次傳送失敗。確認設定的 JsonFactory 是否在 request-factory 或 credentials 初始化期間遭到繞過。完成的標準是:此設定不再需要 Jackson2,或已記錄該硬性要求。
由索引模型根據 Issue 內容生成。
評估
- 技術堆疊
- java
- 領域
- api, backend
- Issue 類型
- 缺陷
- 難度
- 4/5
- 預估耗時
- 3-5 天
- 活躍度
- 冷清
- 描述清晰度
- 基本清楚
- 新手友好度
- 48/100