avaje-inject
avaje-inject copied to clipboard
Support Generic Auto Provides/Requires
- Changes the
Module
interface to useType[]
instead ofClass<?>[]
- Updates generator to allow generic types to be added to auto provides/requires via
GenericType
- updates the maven/gradle plugin to use
Type[]
instead ofClass<?>[]
Now we can have a generic (factory) bean in Module A:
@Component
public class OtherComponentGeneric implements Supplier<String> {
@Override
public String get() {
return "hello";
}
}
The generated Avaje Module class will have:
public final class ModuleClass implements Module {
// ...rest of the module class
@Override
public Type[] autoProvides() {
return autoProvides;
}
private static final Type[] autoProvides = {
new GenericType<java.util.function.Supplier<java.lang.String>>(){},
OtherComponentGeneric.class,
};
// ...rest of the module class
and in Module B we can reference via:
@Component
public class HasExternalDependencies {
public final Supplier<String> stringSupplier;
public HasExternalDependencies(
Supplier<String> stringSupplier) {
this.stringSupplier = stringSupplier;
}
}
Did somebody hit a limitation here / was there a requirement for this?
The autoProvides is for wiring across modules. I tend to believe that cross-module dependencies should be interfaces and I tend to think they shouldn't use generic types. Has someone hit an issue here?
Is it so inconceivable that a module would provide generic types? I've got a mongo common library that handles authentication and provides some common MongoCollection
beans. Currently, I have to wrap the generic types in a non-generic wrapper class to wire across modules.
Factory beans that return Map
s are also not uncommon. Overall, wrapping generic types to get them to wire across modules is quite a hassle.
Currently, I have to wrap the generic types in a non-generic wrapper class to wire across modules.
That sounds like a concrete class being used across a module boundary - so yeah I'm really surprised as that sounds like relatively tight coupling between modules. Can you share an example? [so that I can get a sense of the coupling, I'm also wondering if this is changing with the java module system in terms of tight coupling]
Noting that this is a breaking change - it would need a bump to the major version.
Noting that this is a breaking change - it would need a bump to the major version
Surprisingly, it doesn't break anything except the plugins. Class<?>
extends Type
so modules generated before this change will load and work as expected.
Can you share an example?
an example of wrapping? In module A:
@Singleton
public record WrapperClass(Map<String, String> map){}
Then you can inject WrapperClass into a bean in some module B.
an example of wrapping?
I meant a real world example - as in, we are using tight coupling between 2 modules with a concrete class (and not an interface). What is real world example where this is a good idea (versus a bad idea because that is tight coupling between modules that uses an implementation - a non-abstract implementation class to coupling 2 modules together ... and I'm going "Really??").
modules with a concrete class (and not an interface)
I don't follow, the point of this PR is that we can avoid concrete wrapper classes and use the generic interface/super classes directly
modules with a concrete class (and not an interface)
I did think of an example though. Some time ago I was helping out a guy on discord with avaje and he was quite confused about the current behavior, he had a common library that would configure a Jackson ObjectMapper
for his other applications.
The problem was that ObjectMapper is auto provided as Versioned
, which nobody recognizes.
public final class ModuleClass implements Module {
// ...rest of the module class
@Override
public Class<?>[] autoProvides() {
return autoProvides;
}
private static final Class<?>[] autoProvides = {
Versioned.class,
};
so naturally his compilation would fail. I ended up telling him he had to manually use @InjectModule(provides=ObjectMapper.class)
to get it to work.
Honestly, any sort of avaje-based configuration library that configures third-party classes would appreciate #501