Java Generics - way around instantiating wildcard type

The name of the pictureThe name of the pictureThe name of the pictureClash 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.





Store the Class object passed in a.setClassCImpl() and use the newInstance() method defined in Class. (Or use getDeclaredConstructor().newInstance() for Java 9+.)
– Ted Hopp
Aug 10 at 3:01


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.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

Creating a leaderboard in HTML/JS