lysine-dev/retrofit · error · NullPointerException
mapper == null
Error message
mapper == null
What it means
Thrown by JacksonConverterFactory.create(ObjectMapper, MediaType) as an explicit NullPointerException when the supplied ObjectMapper is null. The factory holds the mapper for all subsequent conversions; failing at construction surfaces the misconfiguration immediately rather than as an obscure NPE during the first request.
Source
Thrown at retrofit-converters/jackson/src/main/java/retrofit2/converter/jackson/JacksonConverterFactory.java:56
*/
public final class JacksonConverterFactory extends Converter.Factory {
private static final MediaType DEFAULT_MEDIA_TYPE =
MediaType.get("application/json; charset=UTF-8");
/** Create an instance using a default {@link ObjectMapper} instance for conversion. */
public static JacksonConverterFactory create() {
return new JacksonConverterFactory(new ObjectMapper(), DEFAULT_MEDIA_TYPE, false);
}
/** Create an instance using {@code mapper} for conversion. */
public static JacksonConverterFactory create(ObjectMapper mapper) {
return create(mapper, DEFAULT_MEDIA_TYPE);
}
/** Create an instance using {@code mapper} and {@code mediaType} for conversion. */
@SuppressWarnings("ConstantConditions") // Guarding public API nullability.
public static JacksonConverterFactory create(ObjectMapper mapper, MediaType mediaType) {
if (mapper == null) throw new NullPointerException("mapper == null");
if (mediaType == null) throw new NullPointerException("mediaType == null");
return new JacksonConverterFactory(mapper, mediaType, false);
}
private final ObjectMapper mapper;
private final MediaType mediaType;
private final boolean streaming;
private JacksonConverterFactory(ObjectMapper mapper, MediaType mediaType, boolean streaming) {
this.mapper = mapper;
this.mediaType = mediaType;
this.streaming = streaming;
}
/**
* Return a new factory which streams serialization of request messages to bytes on the HTTP thread
* This is either the calling thread for {@link Call#execute()}, or one of OkHttp's background
* threads for {@link Call#enqueue}. Response bytes are always converted to message instances onView on GitHub (pinned to d0b112dad0)
Solutions
- Pass a non-null ObjectMapper: use JacksonConverterFactory.create() for a default instance, or create(new ObjectMapper()) / create(objectMapper, mediaType).
- If using DI, ensure the ObjectMapper @Provides/@Bean binding is present and returns non-null.
- Initialize the ObjectMapper field before constructing the factory.
- In tests, pass a real ObjectMapper or a properly stubbed non-null mock.
Example fix
// before
ObjectMapper mapper = diContainer.get(ObjectMapper.class); // null when unbound
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(JacksonConverterFactory.create(mapper))
.build();
// after
ObjectMapper mapper = diContainer.get(ObjectMapper.class);
if (mapper == null) mapper = new ObjectMapper();
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(JacksonConverterFactory.create(mapper))
.build(); Defensive patterns
Strategy: validation
Validate before calling
ObjectMapper mapper = resolveObjectMapper();
if (mapper == null) {
throw new IllegalStateException("ObjectMapper must not be null before building JacksonConverterFactory");
}
JacksonConverterFactory factory = JacksonConverterFactory.create(mapper); Type guard
// Kotlin: non-nullable parameter forces the compiler to reject null at the call site.
fun converterFactory(mapper: ObjectMapper): JacksonConverterFactory =
JacksonConverterFactory.create(mapper) Try / catch
JacksonConverterFactory factory;
try {
factory = JacksonConverterFactory.create(resolveObjectMapper());
} catch (NullPointerException e) {
if ("mapper == null".equals(e.getMessage())) {
factory = JacksonConverterFactory.create(); // fall back to default ObjectMapper
} else {
throw e;
}
} Prevention
- Prefer JacksonConverterFactory.create() (no-arg) unless you need a customized mapper.
- Make ObjectMapper fields final and assign them in the constructor.
- In DI, ensure the ObjectMapper @Provides/@Bean binding exists and is covered by a test.
When it happens
Trigger: Calling JacksonConverterFactory.create(null) or create(null, mediaType) directly, or passing a null reference from an unbound DI provider, an uninitialized field, or a test mock that returned null.
Common situations: A Spring/Dagger bean that injects an ObjectMapper which was never provided, a Kotlin lateinit ObjectMapper field read before initialization, or a test wiring the factory with a null value by accident.
Related errors
- gson == null
- context == null
- Response must be parameterized as Response<Foo> or Response<
- Result must be parameterized as Result<Foo> or Result<? exte
- Future return type must be parameterized as Future<Foo> or F
AI-assisted analysis of lysine-dev/retrofit@d0b112dad0 (2026-08-13).
Data as JSON: /api/errors/388c590410526a14.
Report an issue: GitHub.