Why Is My Field 'Null' After Injection? How to Inject My Object

Why is my field `null` after injection? How do I inject my object?

The above includes both constructor and field injection, but neither done right. The example would behave the same if we removed all the @Inject annotations from MyPresenter since we're not using any of them.

@Provides
MyPresenter provideMyPresenter(MyView view) {
// no constructor injection, we create the object ourselves!
return new MyPresenter(view);
}

// also no mention anywhere of component.inject(presenter)
// so the fields won't be injected either

Make sure to use either constructor injection or field injection. Mixing both will usually indicate an error in your setup or understanding.

  • @Inject on a field is a marker for field injection
  • @Inject on a constructor is a marker for constructor injection

This means your class should have either of

  • a single @Inject on the constructor, or
  • a @Inject on all the fields to initialize, but none on the constructor!

Don't sprinkle @Inject everywhere and expect things to work! Make sure to place the annotation where needed. Don't mix field and constructor injection!

Constructor injection should be favored over field injection as it creates an initialized and usable object. Field injection is to be used with Framework components where the Framework creates the objects. You have to manually call component.inject(object) for field injection to be performed, or any annotated fields will be null when you try to use them.

Constructor Injection

As the name suggests you put your dependencies as parameters in the constructor. The annotation on the constructor tells Dagger about the object and it can then create the object for you by calling it with all the required dependencies. Dagger will also inject any annotated fields or methods after creating the object, but plain constructor injection should usually be favored as it doesn't hide any dependencies.

Dagger creating the object also means there is no need for a @Provides method in your module that creates the object. All you need to do is add @Inject to the constructor and declare the dependencies.

class MyPresenter {

private Context context;
private MyView view;

@Inject
MyPresenter(MyView view, Context context) {
this.view = view;
this.context = context
}
}

If you want to bind your implementation to an interface, there is still no need to create the object yourself.

@Module class MyModule {

@Provides
MyPresenter providePresenter(MyPresenterImpl presenter) {
// Dagger creates the object, we return it as a binding for the interface!
return presenter;
}
}

And there is even a shorter (and more performant) version of the above use-case:

@Module interface MyModule {

@Binds
MyPresenter providePresenter(MyPresenterImpl presenter)
}

Constructor injection should be your default way of using Dagger. Make sure that you don't call new yourself or you misunderstood the concept.

Field Injection

There are times when you can't use constructor injection, e.g. an Activity in Android gets created by the Framework and you shouldn't override the constructor. In this case we can use field injection.

To use field injection you annotate all the fields that you want initialized with @Inject and add a void inject(MyActivity activity) method to the component that should handle the injection.

@Component
interface MyComponent {
void inject(MyActivity activity);
}

And somewhere in your code you have to call component.inject(myActivity) or the fields will not be initialized. e.g. in onCreate(..)

void onCreate(..) {
// fields still null / uninitialized
myComponent.inject(this);
// fields are now injected!

// ...
}

Field injection is not transitive. Just because you inject an Activity this does not mean that Dagger will also inject the fields of the presenter it injected. You have to inject every object manually, which is one reason why you should favor constructor injection.

There are tools that help mitigate the boilerplate of creating components and injecting your objects like AndroidInjection.inject() which will do this for you, but it still has to be done. Another example is AppInjector which adds various lifecycle listeners to inject your Activities and Fragments, but it will still call AndroidInjection which then creates your component and injects the object.

Make sure that you inject the object before using it and that there is no constructor annotated with @Inject to avoid confusion.

What else?

There is also the lesser used method injection and of course Dagger can't inject third party libraries, which you have to construct and provide in your modules.

CDI - @Injected field null

Here

@Inject
private KwetterApp kwetterApp;
private UserService userService = kwetterApp.getService();

I do not think the kwetterApp field is going to be set before userService.

CDI will set that field after the object has been constructed.

An alternative, which should be used anyway, is constructor injection

@RequestScoped
@Path("/user")
public class UserRest {
private KwetterApp kwetterApp;
private UserService userService;

protected UserRest() {}

@Inject
public UserRest(final KwetterApp kwetterApp) {
this.kwetterApp = kwetterApp;
this.userService = kwetterApp.getService();
}

@GET
@Produces({"application/json"})
@Override
public List<User> get() throws UserException {
return userService.getAll();
}
}

A protected constructor is needed because @RequestScoped is a normal-scoped bean, and it must be proxiable, as described in the specification.

The only annotation that doesn't require an empty constructor is @Singleton (from javax.inject).

@Inject field is always null

During the construction of the DataController, it's normal the dataProvider is null. Injection happens after that.

You should add a @PostConstruct method to check for nullity of the field:

@PostConstruct
void init() {
// dataProvider should not be null here.
}

Aditionally, error reporting on Weld is pretty well done. So you should have an explicit and detailed error message if the injection fails, and not only a null field.

Why is my Spring @Autowired field null?

The field annotated @Autowired is null because Spring doesn't know about the copy of MileageFeeCalculator that you created with new and didn't know to autowire it.

The Spring Inversion of Control (IoC) container has three main logical components: a registry (called the ApplicationContext) of components (beans) that are available to be used by the application, a configurer system that injects objects' dependencies into them by matching up the dependencies with beans in the context, and a dependency solver that can look at a configuration of many different beans and determine how to instantiate and configure them in the necessary order.

The IoC container isn't magic, and it has no way of knowing about Java objects unless you somehow inform it of them. When you call new, the JVM instantiates a copy of the new object and hands it straight to you--it never goes through the configuration process. There are three ways that you can get your beans configured.

I have posted all of this code, using Spring Boot to launch, at this GitHub project; you can look at a full running project for each approach to see everything you need to make it work. Tag with the NullPointerException: nonworking

Inject your beans

The most preferable option is to let Spring autowire all of your beans; this requires the least amount of code and is the most maintainable. To make the autowiring work like you wanted, also autowire the MileageFeeCalculator like this:

@Controller
public class MileageFeeController {

@Autowired
private MileageFeeCalculator calc;

@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}

If you need to create a new instance of your service object for different requests, you can still use injection by using the Spring bean scopes.

Tag that works by injecting the @MileageFeeCalculator service object: working-inject-bean

Use @Configurable

If you really need objects created with new to be autowired, you can use the Spring @Configurable annotation along with AspectJ compile-time weaving to inject your objects. This approach inserts code into your object's constructor that alerts Spring that it's being created so that Spring can configure the new instance. This requires a bit of configuration in your build (such as compiling with ajc) and turning on Spring's runtime configuration handlers (@EnableSpringConfigured with the JavaConfig syntax). This approach is used by the Roo Active Record system to allow new instances of your entities to get the necessary persistence information injected.

@Service
@Configurable
public class MileageFeeCalculator {

@Autowired
private MileageRateService rateService;

public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}

Tag that works by using @Configurable on the service object: working-configurable

Manual bean lookup: not recommended

This approach is suitable only for interfacing with legacy code in special situations. It is nearly always preferable to create a singleton adapter class that Spring can autowire and the legacy code can call, but it is possible to directly ask the Spring application context for a bean.

To do this, you need a class to which Spring can give a reference to the ApplicationContext object:

@Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext context;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}

public static ApplicationContext getContext() {
return context;
}
}

Then your legacy code can call getContext() and retrieve the beans it needs:

@Controller
public class MileageFeeController {
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
MileageFeeCalculator calc = ApplicationContextHolder.getContext().getBean(MileageFeeCalculator.class);
return calc.mileageCharge(miles);
}
}

Tag that works by manually looking up the service object in the Spring context: working-manual-lookup

@inject-ed attribute remains null

The error message could be a hint, that the JVM wasn't able to create an instance of UserBean. The following is some guessing and would have to be proven:

Dependecy Injection requires a dependency injector, a tool that injects an instance of UserService into a UserBean. In your code you're already using this injected instance during instantiation of the bean: you call the injected service in the constructor.

If the dependency injector starts it's work after the bean is created, then the call to the service inside the constructor will raise a NullPointerException (because service is still null at that time). It's worth checking that by trying to catch NPEs in the UserBean constructor for a moment. If you catch one - voilà - the dependency injector starts runnning after the bean has been created and, as a consequence, we can't use injected services during class instantiation (= in the constructor)


Workaround idea: implement a small service provider helper class - inner class could work:

public class UserBean implements Serializable {
static class UserServiceProvider {
@Inject static UserService service;
}

// ...

public UserBean() {
this.user = UserServiceProvider.service.findUser("kaas");
}

// ...
}

Untested but could work - the service should be injected in the provider class before you use it in the beans constructor.

Dagger2 injection not happening - injected field is turning out to be null

You're not injecting the Context to your MainHelper. I suggest you refactor your MainHelper class to obtain the Context via Constructor injection (you should do this for all classes you own):

@Singleton
public class MainHelper {

private final Context context;

@Inject
public MainHelper(Context context) {
this.context = context;
}

}

The @Inject annotation on the constructor should be enough so that Dagger knows to instantiate/create MainHelper for you. And then in order for this MainHelper class to be injected to your MainActivity, you first need to tell Dagger that you need to inject dependencies to your MainActivity. You already did something similar for your MainApplication class:

@Singleton
@Component(modules = MainModule.class)
public interface MainComponent {
void inject(MainApplication application);
void inject(MainActivity activity);
}

Then on your MainActivity, you inject MainHelper by calling the inject method that Dagger generates for you:

public class MainActivity extends AppCompatActivity {

@Inject
MainHelper helper;

@Override
protected void onCreate(Bundle savedInstanceState) {
((CustomApplication) getApplication()).getComponent().inject(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

TextView tvAppName = findViewById(R.id.main_app_name);
tvAppName.setText(helper.getApplicationName());
}
}

Spring injection via Qualifier inject null instead of object

@Qualifier doesn't enable the autowiring for the fields.

It is specified as :

This annotation may be used on a field or parameter as a qualifier for
candidate beans when autowiring

So these :

@Qualifier("Male")
Human Male;

@Qualifier("Female")
Human female;

should be :

@Autowired
@Qualifier("Male")
Human Male;

@Autowired
@Qualifier("Female")
Human female;

Guice field injection not working (returns null)

This is what's throwing you off:

@Provides
C getC(){
return new C();
}

Delete it. Delete the whole module, in fact—none of the methods you've defined are helping your injection.


When you create a @Provides C method, Guice assumes that you're creating C just the way you'd like it, and will not populate @Inject-annotated fields or call @Inject-annotated methods. However, when C has an @Inject-annotated or public argumentless constructor, Guice will inspect the object and create it according to its @Inject fields and methods, which is the behavior you're looking for.



Related Topics



Leave a reply



Submit