I got a class like the following:
public class MyClass {
#Inject
private SomeClass someclass;
//...
}
If I create this class by new MyClass() then someClass is null. If I inject MyClass it is not. But I need the construction with new here. I know I could pass someClass to MyClass via constructor, but I don't want this. What other possibilities do I have here?
I assume you're using CDI or something similar. For injection to work in that case the framework has to "see" the need to inject something (and where to inject that). That's generally done by creating MyClass instances by using the framework as well but there might also be a way to trigger injection manually.
In terms of CDI it would be something like this:
BeanManager bm = ...; //lookup or let it inject
Bean<MyClass> bean = (Bean<MyClass>)bm.getBeans( MyClass.class ).iterator().next();
CreationalContext<T> ctx= bm.createCreationalContext( bean );
MyClass instance = bm.getReference( bean, MyClass.class, ctx);
I found a pretty nice solution. The trick is to inject ´MyClass´ in the following way:
#Inject
private Instance<MyClass> myClass;
Then you can construct the bean via
myClass.get();
This encapsulates the usage of the beanManager.
Related
Basically, I want to make this code work:
#Component
abstract class MyBaseClass(val myArg: MyArgClass) {
#Autowired
private lateinit var myInjectedBean: MyInjectedBean
fun useBothArgAndBean()
}
class MyConcreteClass(myArg: MyArgClass) : MyBaseClass(myArg)
val myConcreteClass = MyConcreteClass(obtainMyArgClass())
myConcreteClass.useBothArgAndBean()
So I have a base class with one argument in the constructor and another argument injected from the Spring context. Currently, such a setup is not possible because Spring tries to inject also MyArgClass from context and because there's no such bean (it's constructed manually) it fails on "no matching bean".
The question is how to make this scenario work. Note that I cannot use the factory-method solution mentioned here https://stackoverflow.com/a/58790893/13015027 because I need to directly call MyBaseClass constructor from MyConcreteClass constructor. Perhaps there's a trick on how to avoid that or how to force Spring not to try to inject into the base constructor or ...?
You have a quite confusing setup there, and I am not sure that you are fully aware how injection by Spring works. You can
either create a class on your own, using its constructor, or
you can let Spring create the class and inject everything, and you don't call the constructor.
When you call the constructor, Spring will not magically inject some parts of your class, just because it has seemingly the right annotations. The variable myInjectedBean will just be null.
If you want to have the ability to create the class on your own using the constructor, you should not use field injection, because you would obviously not have any possibility to initialize the field.
Then your classes MyBaseClass and MyConcreteClass would look like this:
abstract class MyBaseClass(
val myArg: MyArgClass,
private val myInjectedBean: MyInjectedBean
) {
fun useBothArgAndBean()
}
class MyConcreteClass(myArg: MyArgClass, myInjectedBean: MyInjectedBean) : MyBaseClass(myArg, myInjectedBean)
Now, as already suggested by #Sam, you can have myInjectedBean be injected while providing myArg manually by writing another component that can completely be created by Spring, because it will only autowire myInjectedBean while myArg is provided as argument for a factory method:
#Component
class MyFactory(val myInjectedBean: MyInjectedBean) {
fun createMyConcreteClass(myArg: MyArgClass) =
MyConcreteClass(myArg, myInjectedBean)
}
Then in a class, where you have an injected myFactory: MyFactory you can just call myFactory.createMyConcreteClass(myArg) and you obtain a new MyConcreteClass that has an injected myInjectedBean.
I think you still do need some sort of factory. It would pass both the bean and the additional arguments to the MyConcreteClass constructor, and would look like this:
#Component
class MyFactory(val myInjectedBean: MyInjectedBean) {
fun getMyConcreteClass(myArg: MyArgClass) =
MyConcreteClass(myArg, myInjectedBean)
}
If using that approach, none of the other classes except MyInjectedBean would need to be registered with Spring.
In fact, it's a little surprising to me that you currently have MyBaseClass annotated with #Component. What do you expect that to do, and does it work?
I have a class SomeClass and a SomeModule to register it with Guice.
I found out that the constructor SomeClass is only called by SomeModule, and that SomeModule is the only place where binding for SomeClass happens.
This means that the #Inject on SomeClass's constructor is not needed since prop1 and prop2 are injected inside SomeModule and passed to the constructor. And the testing also seems to prove my findings.
My question is that what Guice will do when it sees a #Inject like this?
Also what side effect will there be if I have an excessive #Inject?
public static class SomeModule extends PrivateModule {
#Provides
#Singleton
#Exposed
private SomeClass someClass( SomeObject prop1, String prop2) {
return new SomeClass(prop1, prop2);
}
}
public class SomeClass {
#Inject // unnecessary
public SomeClass(SomeObject prop1, String prop2){
...
}
}
If my understanding is correct, you #Inject a constructor when you want to inject objects managed by Guice into the parameters of the constructor.
e.g. if I have bind(SomeClass.class).in(Singleton.class) and bindings for prop1 and prop2, it makes sense to #Inject SomeClass constructor in order to inject prop1 and prop2 into the constructor.
But since this isn't the case, this makes the #Inject here unnecessary
Cheers
Quoting #Deepak's comment as the answer:
You need #Inject if you were defining a binding in the configure method instead of creating a Provider for this class. When you define a binding in the configure method, you are telling Guice to instantiate the object for you. That is when it looks for a constructor with #Inject to figure out what dependencies it has to Inject to construct that object. In case of Provider, you are creating the object yourself by passing all the dependencies required for that class as arguments. So, #Inject has no meaning at that case
I have a simple situation:
class MyClass #Inject() (configuration: Configuration) {
val port = configuration.get[String]("port")
...
}
and now I want to use MyClass in some other object:
object Toyota extends Car {
val myClass = new MyClass(???)
...
}
but I dont know how when I use MyClass i give it the configuration instance i annotated that will be injected when MyClass is going to be instantiated..
im using play2.6/juice/scala
thanks!
First of all, you should decide if dependency injection is really what you need. Basic idea of DI: instead of factories or objects themselves creating new objects, you externally pass the dependencies, and pass the instantiation problem to someone else.
You suppose to go all in with it if you rely on framework, that is why no way of using new along with DI. You cannot pass/inject a class into the scala object, here is a draft of what you can do:
Play/guice require some preparation.
Injection Module to tell guice how to create objects (if you cannot do this if annotations, or want to do it in one place).
class InjectionModule extends AbstractModule {
override def configure() = {
// ...
bind(classOf[MyClass])
bind(classOf[GlobalContext]).asEagerSingleton()
}
}
Inject the injector to be able to access it.
class GlobalContext #Inject()(playInjector: Injector) {
GlobalContext.injectorRef = playInjector
}
object GlobalContext {
private var injectorRef: Injector = _
def injector: Injector = injectorRef
}
Specify which modules to enable, because there can be more than one.
// application.conf
play.modules.enabled += "modules.InjectionModule"
And finally the client code.
object Toyota extends Car {
import GlobalContext.injector
// at this point Guice figures out how to instantiate MyClass, create and inject all the required dependencies
val myClass = injector.instanceOf[MyClass]
...
}
A simple situation expanded with a frameworks help. So, you should really consider other possibilities. Maybe it would be better to pass the configs as an implicit parameter in your case?
For dependency injection with guice take a look at:
ScalaDependencyInjection with play and Guice wiki
I am trying to figure out how object instantiation works in Java EE. I have noticed that I get a NullPointerException if I try to access a member that is supposed to be injected through #EJB if the Class defining the member has been instantiated explicitly by me rather than the container. My conclusion is that even if a bean is marked to be managed it is not if one doesn't let the container instantiate it. Can we make the container manage such objects?
Let's say that we have the following setup, would it be possible to instantiate (explicitly) ClassB in ClassC and have ClassB invoke a method from ClassA without throwing a NullPointerException?
#Stateless
public class ClassA {
public void bar() {
// Does something fun
}
}
#Stateless
public class ClassB {
#EJB
private ClassA A;
public void foo() {
A.bar(); // throws NullPointerException if ClassB
// is explicitly instantiated works fine
// if injected with #EJB
}
}
public class ClassC {
//#EJB // Only way to go? Can we choose an implementation of ClassB?
private ClassB B;
public ClassC() {
this.B = new ClassB(); // Bad idea? Possible??
this.B.foo();
}
}
The reason I'm looking in to it is because I in my, equivalent of, ClassA need to use an EntityManager to persist some data, at the same time my ClassB is actually an interface so I need to be able to decide at runtime which implementation to instantiate in ClassC. Maybe there are other ways of doing this?
I have noticed that I get a NullPointerException if I try to access a member that is supposed to be injected through #EJB if the Class defining the member has been instantiated explicitly by me rather than the container.
This is obvious as the dependencies are injected by the container. So if you are creating the instance and not setting any value for the dependency, then the dependency will be null. On the other hand, when instances are created by the container, it also sets the values of its dependencies.
My conclusion is that even if a bean is marked to be managed it is not if one doesn't let the container instantiate it.
Yes, that is correct. When you create the instance, the instance is therefore, not managed.
Let's say that we have the following setup, would it be possible to instantiate (explicitly) ClassB in ClassC and have ClassB invoke a method from ClassA without throwing a NullPointerException?
No, when you create the instance, the dependencies will be null.
The reason I'm looking into it is because I in my, equivalent of, ClassA need to use an EntityManager to persist some data, at the same time my ClassB is actually an interface so I need to be able to decide at runtime which implementation to instantiate in ClassC. Maybe there are other ways of doing this?
If you need to inject a specific implementation, the you can do that by specifying bean name.
#EJB(beanName="DefaultService")
private Service defautService;
#EJB(beanName="SpecificService")
private Service specificService;
Refer to this link: http://www.adam-bien.com/roller/abien/entry/injecting_different_implementations_into_an
Alternatively, if you're using CDI you can use #Qualifier
The other way to get an EJB reference if you cannot use injection is to use JNDI to look it up.
Context initialContext = new InitialContext();
ClassB b = (ClassB)initialContext.lookup("java:global/yourappname/ClassB!com.package.containing.ClassB");
Therefore you can use whatever logic you need to determine the JNDI name of the actual ClassB implementation you need and then look it up.
I am using an library which internally has a class
#ImplementedBy(MyClassImpl.class)
public interface MyClassInterface {
....
}
When Guice, how can get the instance of the MyClassImpl?
Do I have to create a binding:
bind(MyClassInterface.class).to(MyClassImpl.class);
in order to use it?
Many thanks
No, you don't have to create a binding, although you can. If you do it will override the #ImplementedBy annotation.
You can get an instance of it via ordinary injection, e.g.
#Inject
public Client(MyClassInterface foo) {
...
}
or (if it's the top-level class):
injector.getInstance(MyClassInterface.class);
You either inject the interface:
#Inject
MyClassInterface myClass;
or you can use an injector to get an instance:
MyClassInterface myClass = injector.getInstance(MyClassInterface.class);
both will be injected with the MyClassImpl type.