Java Generics - way around instantiating wildcard type
Clash Royale CLAN TAG#URR8PPP
Java Generics - way around instantiating wildcard type
I am trying to build a lib that supports deployment of custom implementations of a specific object.
When the user is setting things up with Class A, I want them to be able to do something like this:
/* this code will not be part of the lib */
ClassA a = new ClassA()
a.setClassCImpl(ClassD.class)
Now when Class B gets instantiated it needs to know to use the custom implementation Class D
/* this code will be part of the lib */
Class<? extends ClassC> classCImpl;
ClassB()
classCImpl = new ??? // this needs to be an instance of Class D
There will be many instances of Class B. I'd rather not need Class B to hold onto an instance of Class A, but I'm not sure this will be possible without using static stuff in Class A.
Class
a.setClassCImpl()
newInstance()
Class
getDeclaredConstructor().newInstance()
This will require me to change
Class<? extends ClassC> classCImpl;
to ClassC classCImpl;
What's the difference?– vaps
Aug 10 at 3:09
Class<? extends ClassC> classCImpl;
ClassC classCImpl;
Why are you trying to create a new
Class
object inside the ClassB()
constructor? Shouldn't you just be passing the Class
object injected into the configuration (the ClassA
instance)?– Ted Hopp
Aug 10 at 3:13
Class
ClassB()
Class
ClassA
Why mess around with classes like this? Just injecting a Supplier to supply you an instance of the class. Then the user can instantiate the class however they want and your class B will have a fully functioning instance.
– Hangman4358
Aug 10 at 3:14
Having to pass the custom implementation type through
Class B
's constructor isn't nice. I currently have it set up like @TedHopp's original comment. But like I said I had to switch it from ? extends ClassC
to just ClassC
. I think this might be the best way to do it. I'm just not sure the difference.– vaps
Aug 10 at 3:20
Class B
? extends ClassC
ClassC
2 Answers
2
This sort of pattern is a good use case for using annotations. Some frameworks implement this kind of behavior but you can quite easily achieve it.
If you can allow users to extend B annotations are really convenient.
For example declare your annotation like that :
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MeaningfulName
public Class<? extends ClassC> value(); // you can define a default
Now when your users extend B they can add this annotation
@MeaningfulName(ClassD.class)
public class CustomB extends ClassB
// whatever your class does
Then you can extract this at runtime using getAnnotation() and setup some caching maybe to avoid frequent lookups. After obtaining the Class attribute you can get the appropriate instance using your desired strategy (singleton, factory, straight up reflection etc.).
If you just want to stick to a single B class, you can specify various combinations of locations users could use it using @Target
and other ElementTypes, although with different ways to extract the annotation.
@Target
This is interesting. I will look into this, thanks! If you could edit your answer though, it is kinda throwing me off because you have it set up so that
ClassB
is the one that will be extended but it is not - ClassC
is the abstract class. Being able to define a default implementation is perfect because it is not required for my users to provide their own implementation.– vaps
Aug 10 at 6:17
ClassB
ClassC
I corrected the class definition using ClassD to mitigate confusion. There's no real benefit to a type annotation honestly if your classes are gonna be final. You're better off with a Supplier<ClassC> or a factory pattern in that case.
– GDF
Aug 10 at 14:19
ClassA:
ClassA
static Class<? extends ClassC> impl = ClassD.class
ClassB:
ClassC classCImpl;
ClassB()
classCImpl = ClassA.impl.getDeclaredConstructor().newInstance();
I think this will work.
Please use answers to just post the solution to your problem. If you have any further questions, ask a new Question instead.
– Bhargav Rao♦
Aug 10 at 7:13
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Store the
Class
object passed ina.setClassCImpl()
and use thenewInstance()
method defined inClass
. (Or usegetDeclaredConstructor().newInstance()
for Java 9+.)– Ted Hopp
Aug 10 at 3:01