google / google/guice

Custom provider should not be used when its fields were not injected correctly

Open
#1,116 0 comments 3 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
12.7k
Forks
1.7k
Avg merge
11m
Merged PRs (30d)
2

Description

I have a custom provider, which needs an `@Injected` field. When the injection of this fields fails due to exception being thrown, the provider's `get()` method should not be called, as referencing the field results in `NullPointerException`.

The result is very misleading and log polluting (see also #676 and #728) provisioning errors:

```
1) Error in custom provider, java.lang.NullPointerException
at guice.NPEInjectionTest$1.configure(NPEInjectionTest.java:26)
while locating guice.NPEInjectionTest$B
for field at guice.NPEInjectionTest$2$1.b(NPEInjectionTest.java:1)
at guice.NPEInjectionTest$2.configure(NPEInjectionTest.java:37)
Caused by: java.lang.NullPointerException
at guice.NPEInjectionTest$1$1.get(NPEInjectionTest.java:30)
at guice.NPEInjectionTest$1$1.get(NPEInjectionTest.java:1)
at com.google.inject.internal.ProviderInternalFactory.provision(ProviderInternalFactory.java:81)
at com.google.inject.internal.InternalFactoryToInitializableAdapter.provision(InternalFactoryToInitializableAdapter.java:53)
at com.google.inject.internal.ProviderInternalFactory.circularGet(ProviderInternalFactory.java:61)
at com.google.inject.internal.InternalFactoryToInitializableAdapter.get(InternalFactoryToInitializableAdapter.java:45)
at com.google.inject.internal.SingleFieldInjector.inject(SingleFieldInjector.java:54)
at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:132)
at com.google.inject.internal.MembersInjectorImpl$1.call(MembersInjectorImpl.java:93)
at com.google.inject.internal.MembersInjectorImpl$1.call(MembersInjectorImpl.java:80)
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1085)
at com.google.inject.internal.MembersInjectorImpl.injectAndNotify(MembersInjectorImpl.java:80)
at com.google.inject.internal.Initializer$InjectableReference.get(Initializer.java:223)
at com.google.inject.internal.Initializer.injectAll(Initializer.java:132)
at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:174)
at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:110)
at com.google.inject.Guice.createInjector(Guice.java:99)
at com.google.inject.Guice.createInjector(Guice.java:73)
at com.google.inject.Guice.createInjector(Guice.java:62)
at guice.NPEInjectionTest.test(NPEInjectionTest.java:23)
```
The test case:

```java
import static org.assertj.core.api.Assertions.assertThat;

import org.junit.Test;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Provider;
import com.google.inject.Provides;
import com.google.inject.Singleton;

public class NPEInjectionTest {

interface A { B getB(); }
interface B { }
interface Service { B getB(); }

@Test
public void test() {
Injector inj = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(B.class).toProvider(new Provider() {
@Inject Service service;
@Override
public B get() {
return service.getB();
}
});
}
}, new AbstractModule() {
@Override
protected void configure() {
bind(A.class).toProvider(new Provider() {
@Inject(optional=true) B b;
@Override
public A get() {
return () -> b;
}
});
}
@Provides @Singleton Service getService() {
throw new RuntimeException("Service producing C is not available");
// return () -> new B() { };
}
});

A a = inj.getInstance(A.class);
assertThat(a.getB()).isNotNull();
}
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.