I'm trying to understand how DI is used in our codebase (Kotlin). We are using google guice for dependency injection.
Here is a sample class:
class ServiceClass #Inject construct(
private val depA: DepA,
private val depB: DepB
) { ........ }
In Module class:
#Provides
fun provideDepA(): DepA {
//constructs DepA object and returns it
}
DepB class:
class DepB { .... }
As far as I know for the variables annotated with #Inject, Google Guice will look to resolve those dependencies using module class. So it makes sense how DepA object is injected.
But what about DepB? How are we able to inject DepB without specifying it anywhere?
Guice bindings that are not declared in modules are known as Just-in-time Bindings, and by default Guice is willing to call constructors that take zero arguments:
Guice Wiki: JustInTimeBindings
Guice can create bindings for concrete types by using the type's injectable constructor. Guice considers a constructor injectable if:
(recommended) The constructor is explicitly annotated with #Inject (both com.google.inject.Inject and javax.inject.Inject are supported).
or, the constructor takes zero arguments, and
the constructor is non-private and defined in a non-private class (Guice supports private constructor only when it is defined in a private class, however, private constructors are not recommended because they can be slow in Guice due to the cost of reflection).
the injector has not opted in to require explicit #Inject constructor, see explicit #Inject constructors section below.
If you haven't required explicit bindings and you have a public no-arg constructor, Guice will call it as if you had marked it with #Inject. This is in contrast to Dagger, which will only call #Inject-annotated constructors:
Dagger Dev Guide
If your class has #Inject-annotated fields but no #Inject-annotated constructor, Dagger will inject those fields if requested, but will not create new instances. Add a no-argument constructor with the #Inject annotation to indicate that Dagger may create instances as well.
...
Classes that lack #Inject annotations cannot be constructed by Dagger.
In both Guice and Dagger you can construct the objects yourself in #Provides methods, and in Guice you can also use a Module to explicitly bind to a constructor with arguments and without an #Inject constructor.
Related
I am writing a Flink application in Kotlin and data classes (as well as other Kotlin classes) are not identified as valid POJO types.
The Flink documentation states that a data type is recognized as a POJO type (and allows "by-name" field referencing) if the following conditions are fulfilled:
The class is public and standalone
The class has a public no-argument constructor
All non-static, non-transient fields in the class are either public (and non-final) or have public getter and setter methods that follow Java beans naming conventions.
I receive the following when implementing a Kotlin data class, which should meet the aforementioned conditions to be recognized as a POJO:
[main] INFO org.apache.flink.api.java.typeutils.TypeExtractor -
Class class <Class> cannot be used as a POJO type because not all
fields are valid POJO fields, and must be processed as GenericType.
Please read the Flink documentation on "Data Types & Serialization"
for details of the effect on performance.
Investigating further, I reviewed Flink's TypeExtractor.isValidPojoField method # https://github.com/apache/flink/blob/master/flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java
In a separate project, I applied the field checks with java.lang.reflect.Modifier on a simple Kotlin data class in attempt to narrow down the issue.
data class SomeDataClass(
val topic: String = "",
val message: String = ""
)
While Kotlin class fields have public visibility by default, Modifier.isPublic recognizes the fields as private. Additionally, Modifier.isFinal recognizes the fields as final.
val clazz = SomeDataClass::class.java
val fields = clazz.declaredFields
fields.forEach { it ->
println("field: $it")
println(it.genericType)
println("public? " + Modifier.isPublic(it.modifiers))
println("final? " + Modifier.isFinal(it.modifiers))
println("transient? " + Modifier.isTransient(it.modifiers))
println("static? " + Modifier.isStatic(it.modifiers))
}
>
field: private final java.lang.String SomeDataClass.topic
class java.lang.String
public? false
final? true
transient? false
static? false
However, public getter and setter methods are created for these fields, so this object should still meet the POJO criteria.
println(clazz.declaredMethods.toList())
>
[public boolean SomeDataClass.equals(java.lang.Object),
public java.lang.String SomeDataClass.toString(),
public int SomeDataClass.hashCode(),
**public final java.lang.String SomeDataClass.getMessage(),**
public final SomeDataClass SomeDataClass.copy(java.lang.String,java.lang.String),
**public final java.lang.String SomeDataClass.getTopic(),**
public final java.lang.String SomeDataClass.component1(),
public final java.lang.String SomeDataClass.component2(),
public static SomeDataClass SomeDataClass.copy$default(SomeDataClass,java.lang.String,java.lang.String,int,java.lang.Object)]
The getter and setter methods, however, are final, which leads me to believe this is the issue.
I am relatively new to JVM development, so any help would be greatly appreciated. I have reviewed the Flink Jira, Stack Overflow, and Flink mailing list and have not found a similar issue reported.
I see at least two POJO rules violation with provided data class.
1) The class has a public no-argument constructor
By default, Kotlin will not generate overloads to functions with default parameter values (https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#overloads-generation)
So your compiled class will have only one constructor with two-parameter constructor, and no-argument constructor will not be created. To force Kotlin compiler to generate multiple overloads one should use #JvmOverloads annotation. In your case it will be used on constructor so we also need to add constructor keyword:
data class SomeDataClass #JvmOverloads constructor
2) All non-static, non-transient fields in the class are either public (and non-final) or have public getter and setter methods that follow Java beans naming conventions.
Since you are using val keywords the generated fields will be final, and no setter will be generated for them. So you can change vals to vars and the fields will no longer be final and proper getters and setters will be generated too. (Or you could use another annotation to prevent generating getters and setters and expose a field as it is https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#instance-fields)
So final code should be like this:
data class SomeDataClass #JvmOverloads constructor(
var topic: String = "",
var message: String = ""
)
If you wish to use kotlin data classes without any modifications to match a Java POJO (i.e: no default/null values required and keep using val).
You can either:
provide a custom Kryo serializer to serialize it using Protobuf or Avro (or the tool and format of your choice).
use a Kotlin friendly type serializer that will serialize your data class similarly to a case class.
I have this error when clicking a link on a site I'm creating
Error activating IEntityCache using binding from IEntityCache to EntityCache
No constructor was available to create an instance of the implementation type.
Activation path:
4) Injection of dependency IEntityCache into parameter entityCache of constructor of type AlbumRepository
3) Injection of dependency IAlbumRepository into parameter albumRepository of constructor of type AlbumService
2) Injection of dependency IAlbumService into parameter albumService of constructor of type AlbumController
1) Request for AlbumController
Suggestions:
1) Ensure that the implementation type has a public constructor.
2) If you have implemented the Singleton pattern, use a binding with InSingletonScope() instead.
EntityCache is a singleton with no public construction. So this is how I've done my Ninject bindings
kernel.Bind<IAlbumService>().To<AlbumService>();
kernel.Bind<IAlbumRepository>().To<AlbumRepository>();
kernel.Bind<IDbSetWrapper<Album>>().To<DbSetWrapper<Album>>();
kernel.Bind<IEntityCache>().To<EntityCache>().InSingletonScope();
What am I doing wrong?
EDIT
Here's my repository:
public AlbumRepository(DatabaseContext context, IDbSetWrapper<Album> dbSetWrapper, IEntityCache entityCache)
: base(context, dbSetWrapper, entityCache)
How do I pass in an IEntityCache?
EntityCache is a singleton with no public construction.
And how do you expect your DI framework to be able to instantiate this class? This cannot possibly work if your class doesn't have a default public constructor or a constructor taking arguments which are already registered in your DI.
You might need to provide the specific instance yourself if the class doesn't have public constructor:
kernel
.Bind<IEntityCache>()
.ToMethod(context => ...return your specific instance here...)
.InSingletonScope();
for example:
kernel
.Bind<IEntityCache>()
.ToMethod(context => EntityCache.Instance)
.InSingletonScope();
As all private and public attributes and methods are inherited into a child class from its parent class then why would constructors and destructors be inherited into a child class?
Is there a real life scnario?
In most programming languages constructors and descructors are not inherited automatically. Usually base class can provide one set of constructors and child class can provide another set of constructors.
I think that in most cases abstract derived class should provide the same set of constructor as base class do (i.e. "inherit" constructors from the base class), but concrete derived class can resolve some of base class's constructor arguments and provide more usable set of constructors:
Consider following case. Let suppose we have a base class called BaseWCFProxy that requires string as endpoint name:
abstract class BaseWCFProxy
{
public BaseWCFProxy(string endpointName)
{}
}
class ConcreteProxy : BaseWCFProxy
{
public ConcreteProxy() : base("ConcreteProxyEndPoint") {}
}
But you decide to add additional abstract class between BaseProxy and ConcreteProxy than you should provide the same set of constructors as base class:
class DualChannelBaseProxy : BaseWCFProxy
{
public DualChannelBaseProxy(string enpointName) : base(endpointName) {}
}
So the rule of thumb is: if you write a abstract child you should consider to "inherit" all base classes constructors. If you write a concrete child you can provide separate set of constructors that would be appropriate for your clients.
P.S. We don't have the same issue with destructors because there is no such notion like destructors overloading. And they're inherited by default: i.e. descendant can provide some additional logic but it definitely should call base version.
I have a class which needs to use an IRepository for one method in it's class.
Ideally, I would like to avoid having to resolve this dependency into the class's constructor, and so I found method level injection in Ninject and was wondering how this works?
I understand how to set it up. What I'm confused about is how to call it?
Example:
class SomeClassThatUsesRepository
{
[Inject]
public void QueryForSomeStuff(IRepository repository)
{
//do some stuff
}
}
My problem is how do I call this method without specifying an IRepository?
var someClass = Kernel.Resolve<SomeClassThatUsesRepository>();
would work if I was using the constructor, but I want to call a method.
How do I call a method using Ninject method injection?
I'm afraid method injection doesn't work this way - it's just one of the ways to inject dependencies into an object during its construction (you can inject your dependencies through constructor parameters, through properties, fields or methods). Method injection is useful if your class takes its dependencies by Java-style setter methods like
public void SetRepository(IRepository repository) { ... }
If it is marked with [Inject] attribute, you don't need to call this methods directly, it is to be called by Ninject during the initialization to pass the IRepository object into your resolved object.
So I believe your QueryForSomeStuff method is being called when you resove your SomeClassThatUsesRepository.
Confirmed that method injection doesn't work as intended. Got a custom MVC attribute class and wanted to use an injected object inside it. Did not pass it
into the constructor and added method
[Ninject.Inject]
public void ResolveDI(ISettingStore store)
{
ConfigHelper = store;
}
This method was never called and ConfigHelper was null when the attribute's OnActionExecuting was called.
[UPDATE: After discussion on the Glassfish forums/ML at http://forums.java.net/jive/thread.jspa?messageID=480532 a bug was filed against Glassfish https://glassfish.dev.java.net/issues/show_bug.cgi?id=13040 for this issue.]
I'm trying to inject a local no-interface view of a #Stateless EJB into a JSF2 #Named #javax.enterprise.context.SessionScoped backing bean. The EJB is one of several that extend an abstract generic base class. Injection of "#Inject TheEJBClass varName" fails with "Unable to convert ejbRef for ejb TheEJBClass to a business object of type class my.package.name.TheAbstractBase". [edit: Actually, it turns out that injection succeeds, but method resolution in the injected proxy for methods inherited from superclasses fails.] If I use "#EJB TheEJBClass varName" then varName remains null, ie nothing is injected.
Details:
I'm running Glassfish 3.0.1 on Linux (Ubuntu 10.04 in case it matters) and having real problems handling injection of my data model EJBs into my JSF2 session scoped models using CDI (Weld). And yes, before you ask, I have beans.xml in place and CDI is activating to perform injection.
If I inject it with an #EJB annotation, eg:
#EJB TheEJBClass memberName;
... the EJB isn't actually injected, leaving memberName null.
If I inject it with a CDI #Inject annotation:
#Inject TheEJBClass memberName;
... then CDI complains when I call a method of "memberName" that's implemented in a superclass of TheEJBClass and not overridden in TheEJBClass its self, reporting:
java.lang.IllegalStateException: Unable to convert ejbRef for ejb TheEJBClass to a business object of type class my.package.name.TheAbstractBase
at
com.sun.ejb.containers.EjbContainerServicesImpl.getBusinessObject(EjbContainerServicesImpl.java:104)
at
org.glassfish.weld.ejb.SessionObjectReferenceImpl.getBusinessObject(SessionObjectReferenceImpl.java:60)
....
I've tried converting the base to concrete class and de-generifying it, but encounter the same problem, so I don't think I'm hitting the Weld bugs with generic bases (https://jira.jboss.org/browse/WELD-305, https://jira.jboss.org/browse/WELD-381, https://jira.jboss.org/browse/WELD-518).
An outline of the code, with full package qualification on annotations added for clarity, is:
// JSF2 managed backing bean.
//
// Called via #{someJSF2Model.value} in a JSF2 page
//
#javax.inject.Named
#javax.enterprise.context.SessionScoped
public class SomeJSF2Model implements Serializable {
#javax.inject.Inject TheEJBClass member;
public Integer getValue() {
return member.getValue();
}
// blah blah
}
// One of several EJB classes that extend TheAbstractBase
#javax.ejb.Stateless
public class TheEJBClass extends TheAbstractBase {
// blah blah
// does **NOT** override "getValue()"
}
public abstract class TheAbstractBase {
// blah blah
public Integer getValue() {
return 1;
}
}
Note that injection does work if I override TheAbstractBase.getValue() in TheEJBClass, or if I call a method defined in TheEJBClass and not any superclass. It seems like the issue is something to do with inheritance.
Very similar code that used JSF2's built-in lifecycle and injection features worked, but given that this is a new project and CDI is where things are heading in the future, I thought it best to try to go for CDI. Here's what I started out with using JSF2/EJB injection, which worked:
// JSF2 managed backing bean. Using #ManagedBean and JSF2's #SessionScoped
// instead of CDI #Named and CDI #SessionScoped this time.
//
#javax.faces.bean.ManagedBean
#javax.faces.bean.SessionScoped
public class SomeJSF2Model implements Serializable {
#javax.ejb.EJB TheEJBClass member;
public Integer getValue() {
return member.getValue();
}
// blah blah
}
// One of several EJB classes that extend TheAbstractBase
// Unchanged from CDI version
#javax.ejb.Stateless
public class TheEJBClass extends TheAbstractBase {
// blah blah
// does **NOT** override "getValue()"
}
// Unchanged from CDI version
public abstract class TheAbstractBase {
// blah blah
public Integer getValue() {
return 1;
}
}
I'm currently working on putting together a self-contained test case, but thought I'd fire off the question now in case this is something where I'm just doing something silly or there's a well known solution my Google-fu isn't up to finding. Why did it work with JSF2/EJB injection, but fail with CDI injection?
( Since re-posted on the Glassfish forums as http://forums.java.net/jive/thread.jspa?threadID=152567 )
As noted above, it's a Weld/glassfish bug.
Fix: Give up on Glassfish and move to JBoss AS 7, which actually works most of the time.