firebase / firebase/firebase-admin-java

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

オープン
#1,231 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
Java
スター
620
フォーク
305
平均マージ
3時間 23分
マージ済み PR(30日)
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

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。