I have an abstract class Command. The constructor looks like this:
public Command(String cmd, String helpMsg, String... args) {
this.command = cmd;
this.helpMsg = helpMsg;
this.args = args;
}
Whenever a certain condition is met, I want to be able to print out each command, it's help message and arguments.
If I could loop through the instances of the subclasses of Command, I could call the getter functions for these attributes. However, I don't know how I could store instances like this. I've been reading about generics but haven't been able to solve this problem yet.
Right now I have another class with this code:
private static Map<Class<? extends Command>, ? extends Command> instances;
public static <T extends Command> void addInstance(Class<T> tClass, T tInstance) {
instances.put(tClass, tInstance);
}
But it gives me this error:
Required type:
capture of ? extends Command
Provided:
T
It would also be nice if I were able to get instances to individual subclasses with getInstance(subclass.class)
If you want to ensure that the class and object are of the same type, you’re going to need to make your own mapping class which enforces that, or use an existing one like Guava’s ClassToInstanceMap.
If it’s sufficient for you to simply put and get a Command instance out of your map given a class, then I’d recommend simply dropping the second wildcard:
private static Map<Class<? extends Command>, Command> instances;
There are a lot of great existing answers which explain the behavior of the extends wildcard and why you’re getting the warning that you are when attempting to insert one of your command instances. I definitely recommend giving them a read: Difference between <? super T> and <? extends T> in Java
This can be achieved by creating special kind of Map where keys type is bound to values type:
public class BoundMap<T> extends HashMap<Class<? extends T>, T> {
}
Then the code becomes:
private static BoundMap<Command> instances;
public static <T extends Command> void addInstance(Class<T> tClass, T tInstance) {
instances.put(tClass, tInstance);
}
Related
I am using a generic abstract class of a framework AbstractProcessor<T extends CtElement> which is basically a visitor that visits all elements T. There is a method
public void process(T element)
that acts upon all elements of the specified type and does something.
I then have concrete class implementations of this AbstractProcessor that I create using some sort of factory pattern, while holding a list of the common supertype AbstractProcessor to then call the process-method via polymorphism on them. One of these concrete classes might be smth like XYZProcessor<T extends CtElement> extends AbstractProcessor<T>.
I now create these concrete processors like new XYZProcessor<CtNamedElement>() where CtNamedElement is a subtype of CtElement, so the process-method of the XYZProcessor only gets called with CTNamedElements. But the process-method seems to get called for all visisted elements of type CtElement, NOT only for those of the type CtNamedElement as I want to.
Does anyone know what is happening here?
EDIT: relevant code:
creating processors like this
case CLASS:
//CtClass is subtype of CtNamedElement
this.setProcessor(new AnnotatedWithProcessor<CtClass>(targetName, attributeMappings, metapackage));
break;
Class definition:
public class AnnotatedWithProcessor<T extends CtNamedElement> extends AbstractProcessor<T> {
#Override
public void process(T element) {
//do stuff here with elements of correct type
}
And then calling the processors like this:
//this gets set with a concrete case like above
AbstractProcessor<?> processor;
...
//this astModel gets processed with the respective processor,
//where I expect the process method only getting called for the correct types (in this case only when coming over elements of type CtClass),
//but the method gets called for all types of CtNamedElement, not only for those of type CtClass
this.astModel.processWith(processor);
Seems like you're doing so illegal casting somewhere, but it's hard to tell without seeing more of your implementation. Who is calling XYZProcessor::process? Why do you expect defining a generic interface to perform any sort of filtering?
Going to take a shot in the dark here, but it seems like what you probably want is a lookup map for types versus processors. This kind of code can get messy, so it's a good idea to limit access to this mapping using well tested methods:
private final Map<Class, Object> processorMap = new HashMap<Class, Object>();
public <T extends CtElement> void putProcessor(
Class<T> elementClass,
AbstractProcessor<? extends T> processor
) {
processorMap.put(elementClass, processor);
}
#SuppressWarnings("unchecked")
public <T extends CtElement> AbstractProcessor<? extends T> getProcessor(
Class<T> elementClass,
) {
return (AbstractProcessor<? extends T>) processorMap.get(elementClass);
}
Now when you search for a processor, you can use this map to find the correct implementation to call:
public void <T extends CtElement> process(T element) {
getProcessor(element.getClass()).process(element);
}
You may want to extend this to allow multiple implementations for each class, or filter the processorMap for all valid processors for element.getClass() using Class::isInstance and then processing for each valid key.
I have a simple interface like this.
public interface EntityClass
{
public void setId(final Integer id);
public Integer getId();
}
and a class
public Student implements EntityClass
I am trying to code a class which uses a generic type T but still is a instanceof EntityClass a EntityClass subclass something like this.
public abstract class CustomizableQueriesForClazzAndFields<T extends EntityClass>
That's is the project inside that class i want a method like this.
public List<T>getMultipleClazzWithFields(final String ...fields){return of(genericType).retrieve(fields);}
private MyCriteria of(final Class<? extends EntityClass>applyToClazz){........}
MyCriteria is a wrapper over org.hibernate.Criteria.
And in my implementation would do something like this.
public final class TestCustom extends CustomizableQueriesForClazzAndFields<Student>
{
public static void main(String[] args)
{
final TestCustom clazz = new TestCustom();
final List<Student>a=clazz.getMultipleClazzWithFields("id","name","phone");
a.stream().forEach(clazz::consumer);
}
}
Doing this code i would like to be represent it like this using generics.
public List<Student>getMultipleClazzWithFields(final String ...fields){return of(Student.class).retrieve(fields);}
But i dont know how to represent this or if it's possible.
public List<T>getMultipleClazzWithFields(final String ...fields){return of(genericType).retrieve(fields);}
Which genericType should be represent it as Student the same Student as
public final class TestCustom extends CustomizableQueriesForClazzAndFields<Student>
Or represent it as
public final class TestCustom extends CustomizableQueriesForClazzAndFields<School>
And would do something like
public List<School>getMultipleClazzWithFields(final String ...fields){return of(School.class).retrieve(fields);}
Because i was diving like this
public List<T>getMultipleClazzWithFields(final String ...fields){return of(T).retrieve(fields);}
But the compiler kicks me and says.
cannot find symbol
symbol: variable T
location: class CustomizableQueriesForClazzAndFields<T>
where T is a type-variable:
T extends EntityClass declared in class CustomizableQueriesForClazzAndFields
----
(Alt-Enter shows hints)
I also try
public abstract class CustomizableQueriesForClazzAndFields<Class<T extends EntityClass>>
But says.
> expected
----
(Alt-Enter shows hints)
Or how i can accomplish my desire code.. any workaorund.
Because i a kind annoying passing as parameter.
UPDATE
All i wanna to do is pass a SubClass of EntityClass and creates.
session.createCriteria(genericType);
As well gives me the List but i dont know if it's possible to catch or capture the generic type pass CustomizableQueriesForClazzAndFields<Student> and passed to of() method which is who created the org.hibernate.Criteria object i cannot pass only a T value because in my graph would like to be a subclass of EntityClass a not just a raw T value.
I need to catch or capture
CustomizableQueriesForClazzAndFields<Student>
Student generic type.
If this possible or i am dreaming sorry by my poor english.
Thank a lot and best regards from Venezuela..
Approach 1:
I'm not sure I fully understand your question but I have the feeling you want something like this:
public abstract class CustomizableQueriesForClazzAndFields<T extends EntityClass> {
public List<T> getMultipleClazzWithFields(final Class<T> clazz, final String ...fields){
return of(clazz).retrieve(fields);
}
private MyCriteria of(final Class<T> applyToClazz) {
...
}
}
The compiler can't create/retrieve an instance of T at runtime just from inferred data, hence you have to pass that information somehow e.g. as a parameter:
List<Student> l = getMultipleClazzWithFields(Student.class, "field1", "field2");
Approach 2:
Instead of passing Class<T> as a parameter you could also create subclasses for every T, e.g. class StudentQueries extends CustomizableQueriesForClazzAndFields<Student>, and then use reflection to find out the type of T. Please note though, that this would only work for sublcasses that define the concrete type of T.
Which approach is better depends on your needs but if it's just for that query I'd pass the class of the entity as a call parameter and skip all those subclasses that would be needed otherwise.
Update: if you want to implement the second approach (subclasses) have a look here for some code on how to use reflection to look up the type of T: http://www.artima.com/weblogs/viewpost.jsp?thread=208860
Consider this snipped code:
public class MaxSizeHandler extends AbstractValueHandler<Collection> {
}
and I use eclipse, and It warns me to add infer generic arguments type for Collection and the code changes like this:
public class MaxSizeHandler extends AbstractValueHandler<Collection<?>> {
}
My question is what's the problem if I don't put it, or what's the advantage if I put it?
Passing a raw Collection will imply that the Collection is not parametrized, hence you lose the ability to strongly type (i.e. at compile time) what goes in the Collection.
Passing a Collection<?> is not substantially different, as the wildcard will match anything extending Object.
Of course, it will remove the warning.
The best way would be to pass a Collection<MyObject> or a Collection<? extends MyObject>, etc.
you need to mention Collection type before itself in generic format like below :
public class MaxSizeHandler extends AbstractValueHandler<Collection<? extends T>> {
}
T-> type of collections
Otherwise java compiler will take as default type of collection.
Adding the correct type will allow the class to return the correct type of value, is there a specific type of Object your Collection will hold i.e Integer, then use AbstractValueHandler<Collection<Integer>>.
Depending how you're using the MaxSizeHandler class it may make sense to make this class itself generic. For example, if you need to iterate over the collection:
public class MaxSizeHandler<T>
extends AbstractValueHandler<Collection<? extends T>> {
public void handle(Collection<? extends T> coll) {
for(T item : coll) {
// ...
}
}
}
or if you need to add new items to the collection:
public class MaxSizeHandler<T>
extends AbstractValueHandler<Collection<? super T>> {
public void handle(Collection<? super T> coll) {
T item = createAnItem();
coll.add(item);
}
}
(These are just toy examples, as you haven't said what kind of methods AbstractValueHandler declares)
I have the following sets of classes:
public abstract class GSObject<T extends GSObject<T>> {
public abstract boolean matches(String toMatch);
//Other functions
public static <T extends GSObject<T>> T findMatch(List<T> objects, String toMatch){
//Code that iterates through the list, seeing if one matches;
}
}
public abstract class Phrase extends GSObject<Phrase> {
//More code
}
public class Request extends Phrase{
#Override
public boolean matches(String toMatch){
//Implementation of matches()
}
}
Running the following command: Request.findMatch(allRequests,chat); gives the following error:
Bound mismatch: The generic method findMatch(List<T>, String) of type GSObject<T> is not applicable for the arguments (List<Request>, String). The inferred type Request is not a valid substitute for the bounded parameter <T extends GSObject<T>>
If I do Phrase.findMatch(allPhrases, chat); it does not throw an error, meaning that this has to do with double inheritance. Do I have to write another static function that works with a Class that extends a Class that extends GSObject?
I've looked into making GSObject an interface, but it has some classes that I would like to define (not abstractly) in the class.
Is there something I am missing (in any of the three classes), or do I need to create an interface that defines the function matches() (What I am trying to avoid)?
One option is to make Phrase generic in the same way that GSObject is:
public abstract class Phrase<T extends Phrase> extends GSObject<T> {
public class Request extends Phrase<Request> {
This way, Request extends GSObject<Request> (unlike in your code, where Request extends GSObject<Phrase>).
Another option might be to decouple some of these dependent types by using wildcards, e.g. by one of these:
public static <T extends GSObject<T>> T findMatch(List<? extends T> objects, String toMatch){
public static <U extends GSObject<?>> U findMatch(List<U> objects, String toMatch){
though this can be tricky to get right. Note that with this approach, Request will still advertise that it can handle any List<? extends Phrase>, so you lose some of the benefit of the static type system. (In other words, these versions make your classes more permissive than they're really supposed to be.)
A third option is to do both of the above. It does make sense, after all, for Request.findMatch to take a List<? extends Request>.
Without seeing more of your code, it's hard to know which of these makes most sense for your case.
Ok here is what I want to do..
opencsv has following constructor..
CsvToBean<T> csv2Bean=new CsvToBean<T>();
In it's current form, it will take any object. so following works fine for me.
CsvToBean<HoldbackModel> holdbackModelCsv=new CsvToBean<HoldbackModel>();
I would like to write a generic helper which will wrap the opencsv calls. I want to restrict it to any objects of classes which extend my marker class CsvRecord.
public static <T extends CsvRecord> List<T> readCsvRecords(InputStream srcRecords, InputStream templateCsv, Class<? extends T> clazz) {
// here i want to pass the class clazz to the CsvBean.. but don't know how!!
CsvToBean<T> csv2Bean=new CsvToBean<T>();
}
Any help?
You are going the right way, just need a little bit adjustment.
public static <T extends CsvRecord> List<T> readCsvRecords(InputStream srcRecords, InputStream templateCsv) {
CsvToBean<T> csv2Bean = new CsvToBean<T>();
}