firebase / firebase/firebase-admin-java

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

Aberta
#1,231 0 comentários 0 reações 0 responsáveis Ver no GitHub
Linguagem predominante
Java
Estrelas
620
Forks
305
Merge médio
3h 23min
PRs com merge (30d)
1

Descrição

### 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.

Guia de contribuição

Abrir o guia de contribuição

Direção de pesquisa

Comece por ApiClientUtils.java e pelo caminho FirebaseMessagingClientImpl.fromApp mostrado no stack trace; em seguida, reproduza a exclusão do Maven e a falha no primeiro envio usando a configuração de FirebaseOptions da issue. Determine se o JsonFactory configurado é ignorado durante a inicialização de request-factory ou das credenciais. Está concluído quando Jackson2 não for mais necessário para essa configuração ou quando o requisito obrigatório estiver documentado.

Escrita pelo modelo de indexação a partir do texto da issue.

Avaliação

Stack de tecnologia
java
Domínio
api, backend
Tipo de issue
Bug
Dificuldade
4/5
Tempo estimado
3-5 dias
Status de atividade
Pouca atividade
Clareza
Razoavelmente clara
Facilidade para iniciantes
48/100

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.