I have a Bean that is responsible for loading the project settings from a config file, and making them available to any other object that might need them:
#Component
public class ProjectSettings extends Settings{[...]}
Now, I have a bunch of component classes that over multiple steps extend an abstract class where I want to use this bean in:
#Component
public class SomeDataDbEditor extends MongoDbEditor<SomeData> {[...]}
public abstract class MongoDbEditor<T extends MongodbEntryInterface> extends MongoDbTypedAccessor<T>{[...]}
public abstract class MongoDbTypedAccessor<T extends MongodbEntryInterface> extends MongoDbAccessor {[...]}
public abstract class MongoDbAccessor {
#Autowired
protected ProjectSettings projectSettings;
public MongoDbAccessor() throws DatabaseNotConnectedException {
String databaseName = projectSettings.getMongodbDatabaseName();
[...]
}
From my understanding, this should work since the #Autowired field is protected and thus visible from the #Component class SomeDataDbEditor. However, instead I get this exception:
java.lang.IllegalStateException: Failed to load ApplicationContext
[...]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.company.project.module.some_data.database.accessor.SomeDataDbEditor]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:217)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:117)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:310)
... 124 more
Caused by: java.lang.NullPointerException
at io.company.project.module.database.accessor.MongoDbAccessor.<init>(MongoDbAccessor.java:26)
at io.company.project.module.database.accessor.MongoDbTypedAccessor.<init>(MongoDbTypedAccessor.java:20)
at io.company.project.module.database.accessor.MongoDbEditor.<init>(MongoDbEditor.java:19)
at io.company.project.module.some_data.database.accessor.SomeDataDbEditor.<init>(SomeDataDbEditor.java:17)
...where the referenced MongoDbAccessor.<init>(MongoDbAccessor.java:26) line is String databaseName = projectSettings.getMongodbDatabaseName();
Now, I have confirmed that the projectSettings field really is null in that case. However, I was also able to confirm that if I try to access the ProjectSettings bean in the SomeDataDbEditor, that works, and the bean gets correctly instantiated.
I know that one possible solution at this point would be to use that and just manually pass the ProjectSettings bean to the parent classes, but that would kind of defeat the point of using dependency injection in the first place. Also, I would have to adjust, like, really, really many classes for that, and I want to avoid that if at all possible.
So, does anyone have an idea why this happens here, and what I can do against it?
If you use field injection (Autowired on fields), you cannot use those fields in the constructor, since Spring can only inject the dependencies after the object was constructed, i.e. after all constructors have finished.
To circumvent that, you would either have to change to constructor injection, or alternatively do the initialization work, that you do in the constructor, in a separate method annotated with PostConstruct:
#javax.annotation.PostConstruct
public void initialize() {
}
But if you are able to change your code to constructor injection, i (as well as a lot of other people in the Spring universe) highly recommend it, since it prevents exactly such problems.
Related
Tech Stack: Java-11, Spring, SpringBoot
I am trying to re-create a scenario, where Field Injection in Spring would cause Circular Dependency Error
Class A is injected to Class B
Class B is injected to Class A
At Spring Run time, I was expecting the Circular Injection Error to come but it didnt
In class CallingService, I am trying to call class A's method which refers to class B's method. But that also didnt create the Circular Dependency Error.
Class A
#Service
#Data
public class A {
#Autowired B b;
String str = "B";
public void methodA() {
System.out.println(b.str); // referring to B's instance
}
}
Class B
#Service
#Data
public class B {
#Autowired A a;
String str = "B";
public void methodB() {
System.out.println(a.str); // referring to A's instance
}
}
Class CallingService <---- (trying to create Circular Dependency Error in this class)
#Service
#Data
public class CallingService {
#Autowired A a;
public void methodCalled() {
System.out.println(a.str); // This printed successfully as "A"
}
}
My Queries:
Circular Dependency is expected at run-time or while reference-time(when code is referred while running) in Field Injection [This is clear now. It will come at SPRING's]
What changes do I do to my code to create Circular Dependency Error here using Field Injection
I am actually insisting for using Field Type Injection instead of Constructor Type Injection at my office project, as the prior is quick and eliminates verbose code.
Went through few blogs which were recommending Constructor-Dependency but found most of the points lame. Only concerning one was of Circular Dependency Error. So trying to recreate the same as a POC.
Asking your questions:
Circular dependency error is avoided with Setter or Field injection. The reason being that Spring creates the beans, but the dependencies are not injected until they are needed. In Constructor injection it will ever be a runtime error, never compile time.
Use Constructor injection. But you only get the error on runtime.
Constructor injection is way more unit test friendly than Setter or Field injection, so I also recommend you using Constructor injection.
I have a Spring bean (ChildBean extends Parent) which is extending an abstract class (Parent implements Runnable).
public abstract class Parent implements Runnable {
public final void run() {
// some code
}
public int overridenFunct() {
// some code
}
}
Child bean class variant which causes ClassCastException:
#Transactional
#Scope("prototype")
#Service("beanName")
public class ChildBean extends Parent {
#Override
public int overridenFunct() {
// some diff code
}
}
Everything works fine until I override public non-abstract method from parent class in child bean. After that a ClassCastException is thrown when I'm trying to create an instance of that bean.
Parent p = (Parent) appContext.getBean("beanName");
Bean object returned by getBean() is a ChildBean class instance (checked with debugger). Why does casting ChildBean object to its abstract parent class Parent not work?
So, without an overridenFunct() implemented in ChildBean everything works fine.
Could someone please tell what is the problem here?
UPDATE:
Changing method overridingFunct() to protected fixes the issue. But what if I need to override a public method? Is that allowed? I'm using Spring 3.2.8
UPDATE2:
Well, I didn't get to the point why overriding public method in abstract parent causes ClassCastException. As the resolution I did the following: created an interface with all public methods with common logic, an abstract class, which implements that interface and all "common" methods. Then all the child beans are extended from that abstract class, implementing its specific logic.
For anyone that may encounter this error, the following may prove to be useful in debugging this. First and foremost, the problem can be caused by the ClassLoader loading two copies of a particular class due to dependency overinclusion.
Supply the following option to your JVM via IDE or via
java -verbose:class {rest of your args / options}
Then, monitor the console output for the particular Parent class. A chance exists that the class has made it into the ClassLoader twice, perhaps by including a particular dependency more than once. Pay particular attention to the time when the bean is retrieved from lookup.
I was able to solve an issue on 4/22/2022 by using the above strategy to track down an issue in our Gradle build script that caused extra files to make their way into a WAR.
The Problem with your code is, that appContext.getBean("beanName") does not return an object that inherits from the class Parent.
A common mistake regarding classes with names like Parent is a wrong import.
Check if you are importing from the correct package.
If this does not fix the issue, make sure that appContext.getBean("beanName") returns the object you think it does.
It might return a Bean Object, that does not inherit from the Parent class.
The context also might not even contain your ChildBean object yet. Make sure it is added to it beforehand.
I am having problems injecting a generic type interface. Not sure how to do this or google it since I don't know the exact terms to search for. Sorry if i'm completely wrong just getting started with dagger.
Basically I have a use case class
public class LoadConversations<C extends IConversation>
extends UseCase<List<C>, LoadConversations.Type> {
private final IConversationRepository<C> messageRepository;
#Inject LoadConversations(#NonNull IConversationRepository<C> messageRepository) {
this.messageRepository = messageRepository;
}
....
public enum Type {
ALL, NEWER, OLDER
}
}
With IConversationRepository being an interface.
public interface IConversationRepository<C extends IConversation> {
Observable<List<C>> conversations(LoadConversations.Type params);
}
IConversation being a blank interface and ConversationModule where i provide the IConversationRepository.
Im having problems injecting with the following code. Am i missing something or doing something completey wrong. Thanks in advance.
Trying to provide as follows:
#Provides IConversationRepository<Conversation> provideConversationRepository(
ConversationRepository conversationRepository) {
return conversationRepository;
}
And I'm trying to inject this to my presenter as
private final LoadConversations<Conversation> loadConversations;
#Inject public ConversationListPresenter(LoadConversations<Conversation> loadConversations) {
this.loadConversations = loadConversations;
}
Implementation of ConversationRepository
public class ConversationRepository implements IConversationRepository<Conversation> {
#Override public Observable<List<Conversation>> conversations(LoadConversations.Type params) {
....
}
}
Error Log:
Error:(15, 10) error: com.rbttalk.android.data.repository.ConversationRepository cannot be provided without an #Inject constructor or from an #Provides-annotated method.
com.rbttalk.android.data.repository.ConversationRepository is injected at
com.rbttalk.android.di.module.sub_modules.ConversationModule.provideConversationRepository(conversationRepository)
com.rbttalk.android.domain.repository.IConversationRepository<com.rbttalk.android.domain.models.Conversation> is injected at
com.rbttalk.android.domain.usecase.conversation.LoadConversations.<init>(arg0, …)
com.rbttalk.android.domain.usecase.conversation.LoadConversations<com.rbttalk.android.domain.models.Conversation> is injected at
com.rbttalk.android.ui.main.conversation.ConversationListPresenter.<init>(loadConversations)
com.rbttalk.android.ui.main.conversation.ConversationListPresenter is injected at
com.rbttalk.android.ui.main.conversation.ConversationListFragment.userListPresenter
com.rbttalk.android.ui.main.conversation.ConversationListFragment is injected at
com.rbttalk.android.di.component.ConversationComponent.inject(conversationListFragment)
You're very close! The error message says it all:
com.rbttalk.android.data.repository.ConversationRepository cannot be provided without an #Inject constructor or from an #Provides-annotated method.
Note that this is not IConversationRepository; you've provided a binding for that with your #Provides method (which you can eventually consider converting to a #Binds method). However, that #Provides method has a parameter, ConversationRepository, which effectively asks Dagger to create an instance of that concrete ConversationRepository type for you. You've made that binding correctly, but now Dagger needs to instantiate ConversationRepository for you, and it simply doesn't know how.
You'll need to create an #Inject-annotated constructor for ConversationRepository using the annotation type javax.inject.Inject, even if it just looks like this:
#Inject ConversationRepository() {}
This allows Dagger to know that yes, it is safe to call that constructor. (This differs from Guice, which was willing to call a public parameterless constructor including the default constructor provided by Java.) Though you are welcome to accept injector-provided parameters in that annotated constructor (which might be nice if your repository has dependencies, because then you can keep the fields final), you may also choose to simply annotate some fields with #Inject and let the injector populate those after creation.
#Service
public interface DatabaseConnector {
public Model getModel();
}
#Configuration
#Profile({"!test"})
public class DatabaseConnectorT implements DatabaseConnector {
private final Model model;
#Autowired
public DatabaseConnectorT(#Value("${assemblerFile}") String assemblerFile) {
model = TDBFactory.assembleModel(assemblerFile);
}
}
I am getting the error, that this bean class cannot be instantiated and a default constructor should be given. Why should such one be required? I have two different implementations of the interface which should be loaded dependent on the active profile. Configuration should be done with annotations.
Default constructor is a constructor without parameters.
According to the error message I suppose that the class is being created via reflection.
So you must provide a way to create a class via reflection.
I assumed the value of assemblerFile in your constructor can't be determined via reflection and so the default constructor is called instead, which is not provided.
I have an interface I with method m and two concrete implementations A and B.
public interface I{
public void m();
}
public class A implements I{
public void m(){
//
}
}
public class B implements I{
public void m(){
//
}
}
I want to know when I inject I which of the two methods will be executed
#EJB
private I service;
///
service.m();
/////
None of them, it will become into an error since the application server doesn't know which implementation to use. To avoid this, just provide the id of the class implementation, which by default is the same name of the class but starting with lower case:
//uncomment one of these
//#EJB(name="a")
//#EJB(name="b")
private I service;
None of them. The code will compile, but you won't be able to deploy it on your application server. Without specifing type of injected class, you will get an Exception similar to this:
org.jboss.weld.exceptions.DeploymentException:WELD-001409 Ambiguous dependencies
for type [...] with qualifiers [...] at injection point [...]. Possible dependencies
[...] with qualifiers [...], Managed Bean [...] with qualifiers [...]
Container (i.e. your application server) won't be able to recognize which field do you really want to inject (A or B). It cannot just guess it out of thin air. To avoid this kind of errors, provide it with annotation (called qualifier) specifying whether you want to inject class A or class B. If you want an example, you should see this article.