Reputation: 333
I'm using the Google Guice IoC container. I have two packages, one containing interfaces and one containing implementations for those interfaces.
The ClassFinder class returns a list of classes from a package.
When I try to bind the interface to an implementation, I receive the following compile error: Cannot resolve method to <java.lang.Class<capture<?>>
from the to method.
The API specifies that to can take as a parameter Class and packageClass is Class. What should be the problem?
public void autoMatch(String basePackageName)
{
String interfacesPackage = basePackageName + "." + interfacesPackageName;
String implementationPackage = basePackageName + "." + implementationPackageName;
List<Class<?>> interfaces = ClassFinder.find(interfacesPackage);
List<Class<?>> implementations = ClassFinder.find(implementationPackage);
for(Class<?> packageClass : implementations)
{
String name = packageClass.getSimpleName();
try
{
Class<?> foundInterface
= interfaces.stream()
.filter(packageInterface -> packageInterface.getSimpleName().equals(name + "Interface"))
.findFirst().get();
bind(foundInterface).to(packageClass);
}
catch (NoSuchElementException exception)
{
Log.error("IoC", "Could not match interface to implementation", exception);
}
}
}
EDIT
Managed to solve the issue by casting to (Class). The class is found, but it throws a java.lang.NullPointerException when binding.
Upvotes: 0
Views: 1335
Reputation: 75376
The problem is that you loose the information at compile-time the class implements the interface. From the compilers point of view you end up with two unrelated Class<?>
objects and as Guice is written with generics there is no method for binding them to each other.
Untested: Consider using Class
instead of Class<?>
so generics are not used.
That said, I would suggest you write the 20-30 bindings out by hand. The idea with Dependency Injection is to decouple interfaces from their implementation and your approach will introduce a subtle, hard to debug runtime dependency between them which I do not think is a good thing.
Upvotes: 1
Reputation: 333
Fixed the issue by no longer using ClassFinder to find the classes and by using the Reflections library.
public void autoMatch(String basePackageName)
{
String interfacesPackage = basePackageName + "." + interfacesPackageName;
String implementationPackage = basePackageName + "." + implementationPackageName;
Reflections interfacesReflections = new Reflections(interfacesPackage);
Reflections implementationsReflections = new Reflections(implementationPackage);
Set<Class<? extends Object>> interfaces = interfacesReflections.getSubTypesOf(Object.class);
Set<Class<? extends Object>> implementations = implementationsReflections.getSubTypesOf(Object.class);
for(Class<?> packageClass : implementations)
{
String name = packageClass.getSimpleName();
try
{
Class<?> foundInterface
= interfaces.stream()
.filter(packageInterface -> packageInterface.getSimpleName().equals(name + "Interface"))
.findFirst().get();
bind(foundInterface).to((Class)packageClass);
}
catch (NoSuchElementException exception)
{
Log.error("IoC", "Could not match interface to implementation", exception);
}
}
}
Upvotes: 1