firebase / firebase/firebase-admin-java

google-http-client-jackson2 cannot be excluded even when a JsonFactory is configured via FirebaseOptions

未关闭
#1,231 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
主要语言
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.

贡献指南

打开贡献指南

调研方向

Start with ApiClientUtils.java and the FirebaseMessagingClientImpl.fromApp path shown in the stack trace, then reproduce the Maven exclusion and first-send failure using the FirebaseOptions configuration in the issue. Determine whether the configured JsonFactory is bypassed during request-factory or credentials initialization. Done means Jackson2 is no longer required for this configuration, or the hard requirement is documented.

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

评估

技术栈
java
领域
api, backend
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
冷清
描述清晰度
基本清楚
新手友好度
48/100

把新 issue 发到你的邮箱

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