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>();
}
Related
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);
}
I apologize in advanced for my lack of knowledge in generics... I am trying to understand how generics work and I am not sure what it is but I am missing a key part that is eluding me so hopefully someone can clarify a little more and get me over this hump.
BaseDtoUtil.mapToDto(map, OcrImageDocDto.class); //OcrImageDocDto extends DtoUtils
//This method is in class BaseDtoUtil
public static <T> List<T> mapToDto(Map<String, Object> map, Class<? extends DtoUtils> klass) throws SparkSQLException{
T obj = (T)klass.newInstance();
//return a list of these
}
So I guess there are two questions I have:
First is why does it complain when I pass in OcrImageDocDto.class when the variable defined for the method call is any class? (I originally had it as (Class<?>) Doesn't that mean any class value? Obviously I am wrong but not sure what it means then.
Second question is if I send in a class value am I actually able to get that instance and return a type value back? <T> List<T>? If I am not mistaken I believe that the generic variables <T> List<T> is used for instantiations of the object. But what do they do if it is a static method?
I am a bit lost and maybe the way I understand generics is wrong... So if someone can clear these two up I think it will help a lot!
Question 1:
public static <T> List<T> mapToDto(
Map<String, Object> map,
Class<? extends DtoUtils> klass) throws SparkSQLException{
T obj = (T)klass.newInstance();
...
You don't know that klass.newInstance() can be cast to a T - all you know is that it is an instance of DtoUtils (or a subclass).
As such, you can either change to use:
DtoUtils obj = klass.newInstance();
or constrain T to extend DtoUtils:
public static <T extends DtoUtils> List<T> mapToDto(
Map<String, Object> map,
Class<? extends T> klass) throws SparkSQLException{
T obj = klass.newInstance();
...
Question 2:
Yes, because you have an actual instance of the class. You would not be able to create an instance without that (or some other object which can provide instances of T), because of type erasure.
This would not work:
public static <T extends DtoUtils> List<T> mapToDto(
Map<String, Object> map) throws SparkSQLException{
T obj = new T(); // Compiler error.
Something like the following works just fine:
T obj = klass.newInstance();
List<T> list = new ArrayList<>();
list.add(obj);
return list;
what I have is a super class
class Geometry{
}
and two classes that extends it:
class ShapeOne extends Geometry{}
class ShapeTwo extends Geometry{}
what I want to achieve is to generate a list(read from the database) of objects of the type ShapeOne or ShapeTwo or any other that is instance of Geometry, but dynamically passing the type as a parameter,
for example like:
public ArrayList< Geometry Object > getList(/**passing typeof generated list**/){
// getting data from Database;
return new ArrayList<typeof generated list>();
}
so the call would be then like:
getList(ShapeTwo);
thanks for any help :)
You cannot do that. Due to type erasure, List<Geometry> is not a super class of List<ShapeOne>. This is better explained here: Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?.
Some alternatives to solve your problem:
Return List<ShapeOne> or List<ShapeTwo> or List<TheExpectedClass> rather than List<Geometry>.
Return <T extends Geometry> List<T> and pass Class<T> clazz as argument. Probably you would need to use an additional parameter to recognize if the data recovered from database belongs to a specific subclass of Geometry.
You can do it by passing Class<T>, like this:
public <T extends GeometryObject> List<T> getList(Class<T> itemClass) throws Exception {
List<T> res = new ArrayList<T>();
for (int i = 0 ; i != 10 ; i++) {
res.add(itemClass.newInstance());
}
return res;
}
Demo.
Note: the above call to newInstance assumes that the class has a parameterless constructor.
Suppose we have the following:
public class Parent{
public void setXXX(String XXX);
public String getXXX();
}
public class Children extends Parent{
....
}
Now I want to create a method called clone List like the following:
public List<Something> cloneList(List<Something> original){
List<Something> newList=new ArrayList<>();
for(Something e:original){
Something newE=new Something();
newE.setXXX(e.getXXX());
newList.add(newE);
}
return newList;
}
The thing is we want cloneList can be applied to both List<Parent> and List<Children>, so is there anyway that applicable for "Something"?
Something cannot be "? extends Parent" or "Parent" due to the Java Collection<Parent> incompatible with Collection<Children>
Assumption:
1. Don't want to use any serialization approach or reflection.
We are unable to modify the Parent and Children class. This is predefined in 3rd party Jar.
SuperParent class is not possible because we cannot modify Parent as stated in 2.
That is not possible in Java. Take a look at Generic syntax for extends or equal to.
You could change your method as follows and make your Parent class extend SuperParent.
public static <T extends SuperParent> List<T> cloneList(List<T> original, Class<T> type) throws IllegalAccessException, InstantiationException {
List<T> newList=new ArrayList<>();
for(T e : original){
T x = type.newInstance();
x.setXXX(e.getXXX());
newList.add(x);
}
return newList;
}
Also, you could choose another cloning approach. For example, using Apache Commons' SerializationUtils:
List<Children> result = (List<Children>) SerializationUtils.clone(originalList);
You cannot use generics this way, only reflection.
For a type variable T, you cannot use new T(). That's because generics are a compile-time mechanism, and new is used in run-time to create a specific-type object, and the compiler cannot create the appropriate reference to the type at compile time. So while this:
new ArrayList<T>();
is legal, because the compiler actually compiles it into the code for creating the raw ArrayList type, this:
new T();
is not, because the compiler does not even know what the actual class will be (even if it was just defined as T extends Parents it could be a class that has not even been written when the program compiled, like Grandchildren or something), and does not even know if it has a parameterless constructor.
In a general sense, you should be able to use a method having this signature:
public <T extends Parent> List<T> cloneList(List<T> original)
That's not your biggest problem, however. THAT would be obtaining copies of the list elements. Your code cannot use
T newE = new T(); // doesn't work
because the existence of a nullary constructor for type argument T cannot be guaranteed. Instead, you need a method that will return a correctly-typed copy. You cannot do this with complete type safety, but you can come close. You can implement these methods:
public Parent Parent.copy();
public Children Children.copy();
... in whatever way is appropriate, and then write your method like so:
public <T extends Parent> List<T> cloneList(List<T> original) {
List<T> newList = new ArrayList<>();
for (T originalItem : original) {
newList.add(original.getClass().cast(original.copy()));
}
return newList;
}
(Note that although the documented return type of Object.getClass() is Class<?>, which would not work for this purpose, the method documentation says that the return type is actually a bit more specific than that, enough so to make this work.)
Change the signature of cloneList to:
public <X extends Parent> List<X> cloneList(final List<X> original)
Then it will work, at least for the method signature. You can internally construct a List<Parent> and then cast it to List<X> and ignore the warnings if you need to; there's no way to find out the runtime type of "X".
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)