generic signature to accept Map<String,Object> or Map<String,String> - java

I currently have a method like this:
public static Report createReport(Map<String,Object> parameters) {...}
I'm trying to figure out if there is a way I can change the generic specification so that it will accept both Map<String,Object>s and Map<String,String>s for parameters.
Note that createReport needs to be able to add entries to parameters. Is this possible?

Please see:
Difference between <? super T> and <? extends T> in Java
Specifically this answer. The PECS (producer extends, consumer supers) rule is ingenious.
Try:
public static Report createReport(Map<String,? super String> parameters) {...}
You'll be able to add Strings and read Objects:
parameters.put("a,", "b");
Object object = parameters.get("c");

If you were only reading the values out of the Map you could have done something like this:
public static Report createReport(Map<String,?> parameters) {...}
However, since you also want to add enteries, you need to know the type, or at least be able to know that the type in the Map is the same as the type you are adding.
If it is variable, then I would suggest having another parameter that does the conversion to the type you need.
interface Converter<T>{
T convert(Object o);
}
Then add that parameter to your createReport method like this:
public static <T> Report createReport(Map<String,T> parameters, Converter<T> converter) {...}
Then inside your method you can do something like this:
T value = converter.convert(foo);
parameters.put(key, value);
It would then be up to the caller of createReport to provide the correct converter.

No it is not possible. There is no type-union in Java. You have to revert to the lowest common superclass, which is in your case Object. In some cases you could use an Interface instead, like for example a collection type or a -able style (Closeable) interface.

Related

when to use java generic wildCard?

It was stated in comments that, question was creating confusion. So, i have edited the question, let me know, if it is still creating confusion.
Consider below code:
class Employee{}
class ContractEmployee extends Employee{
}
class PermanentEmployee extends Employee{
}
...
Can any one provide the basic difference between below two cases and
when to use which one
Case:1
public <T extends Employee> void empTest(ArrayList<T> list)
public <? extends Employee> void empTest(ArrayList<?> list)
Case:2
public void empTest(ArrayList<? extends Employee> list)
public void empTest(ArrayList<T extends Employee> list)
Not full explanation but you will get starting over here. We need to follow PECS pattern in generics.
PECS stands for Producer Extends and Consumer Super.
in your line below,
public void empTest(ArrayList list)
You are basically giving list which will act as a producer in further use inside that method. Now as you might know, generic is just compile time illusion and will get erased at runtime, your code in mrthod empTest is expecting the List of particular Employee. for example, if you have Fruit as superclass for Orange and Apple, you should not give list of both Orange and Apple to consumer and restrict it to either Apple or Orange. Does it make sense? I guess yes.
First of all, your question is quite legitimate, although with your examples, it's hard to explain / understand the differences.
In all the variants, you want to define a method empTest() that accepts an ArrayList of Employees or subclasses of Employee. You do this with
public void empTest(ArrayList<? extends Employee> list) { ... }
So, what are the other syntax variants meant for? Let's use a different example, as your empTest() method doesn't need anything else.
Say, we want to add an employee to a list using something like addEmp(list, emp);. First idea might be:
public void addEmp(ArrayList<Employee> list, Employee emp) { ... }
But that won't do the job, as you won't be able to pass an ArrayList<ContractEmployee> into the method. Next attempt:
public void addEmp(ArrayList<? extends Employee> list, Employee emp) { ... }
Now it accepts the list, but it also allows you to pass an ArrayList<ContractEmployee> in combination with a PermanentEmployee, and adding a PermanentEmployee to an ArrayList<ContractEmployee> isn't allowed. The compiler will flag the line in the method body where you add the employee, as illegal.
So, what we need here, is to check for using the same type of employee in both places, and that's what the named type parameters can be used for.
public <T extends Employee> void addEmp(ArrayList<T> list, T emp) { ... }
This says: it's ok to pass in an ArrayList of any subtype of Employee, and we call that subtype T. Then the emp argument must also come from the same subtype T (or from a sub-subtype because of normal class inheritance).
If being an Employee or not doesn't make a difference to the method, you can even write
public <T> void addEmp(ArrayList<T> list, T emp) { ... }
To summarize it:
Use the <... extends SomeClass> constructs if need more variability than the plain <SomeClass> construct.
If it's just one place where you need that variability, there's often no need to introduce a name for the subclass, so <? extends SomeClass> in the method's parameter list does the job.
If you need the same subclass in multiple places, you need to give it a name, so use something like <T extends SomeClass> in front of the return-type declaration and use T without the angle brackets in the parameters list.
Regarding syntax:
- If you need to introduce a name for the type parameter, this is done before the return type.
- In the method return type or the method parameter list, you can only use names that already exist, or use unnamed wildcard constructs.

Assign a generic type to a variable of Class type

// I would like to create a variable of Class type and assign a pattern into it like that:
Class clazz = HashMap<Long,HashMap<String, Semaphore>>.class; // does not work!
// I need it in order to be able later use it in .isInstance() expression, like:
if (clazz.isInstance(myVariable)) {
// do something
}
, because the usual "instanceof" does not work either on pattern types.
With a simple types (non-pattern types) it works:
Class clazz = Long.class; // this works fine
How can I achieve what I want that is to assign a pattern and not a simple type?
If it is not allowed in Java, is there another proper way to test if the variable is an instance of a type defined as a pattern?
You can't check if you have an instance of HashMap<Long,HashMap<String, Semaphore>>.
Despite the syntax implying that HashMap<Long,HashMap<String, Semaphore>> is a single thing, that type actually means:
A variable of this type will hold a HashMap (or null) at runtime
And I want the compiler to stop me if I try to put in or take out a key which isn't a Long, and to stop me if I try to put in or take out anything which isn't a HashMap whose keys and values are of that specific type.
The bit between the <>s is purely a compile time hint. There is nothing there to test at runtime.
Provided the map isn't empty, you can check if it contains any keys or values which violate the type constraints.
But, aside from you only being able to do this if the map is non-empty, and contains non-null keys and values, it doesn't tell you if it is a HashMap<Long,HashMap<String, Semaphore>>, but rather that it is a HashMap<? extends Long, ? extends HashMap<? extends String, ? extends Semaphore>>.
You can safely consume things held in such a map, but you couldn't safely add to it, other than by re-adding keys and values which were already contained in that map, or null.
Generics are erased after compilation.
So even this code that is valid will not help you further :
HashMap<Long, HashMap<String, Semaphore>> map = new HashMap<>();
Class<?> clazz = map.getClass();
clazz would refer java.util.HashMap "only" and not its generics.
About your requirement, if it happens that you have to write such a code and besides by checking the types of the generics :
if (clazz.isInstance(myVariable)) {
// do something
}
I think that should rethink your logic.
Generics are mainly designed to improve the type safety that mechanically reduces the requirement to instanceof test and downcasts.
If it is not allowed in Java, is there another proper way to test if
the variable is an instance of a type defined as a pattern?
You could store the types specified in the generic instance by adding class fields in the generic class. But as you use a built in type, you are stuck.
With your own class you could capture the information in this way for example :
public class Foo<T, U, V> {
private Map<T, HashMap<U, V>> map = new HashMap<>();
private Class<T> tClass;
private Class<U> uClass;
private Class<V> vClass;
public Foo(Class<T> t, Class<U> u, Class<V> v) {
this.tClass = t;
this.uClass = u;
this.vClass = v;
}
}
So you can use tClass, uClass, vClass to perform the required checks.
But as said, going on into this way is probably not the best thing to do.

Single method to return an instance of different generic type of a class

I have a generic class as follows:
MyClass<T>
{
....
}
Now, what I want create a single generic method,say for example public MyClass<T> getMyClassInstance(Type t){...}, in which I pass a type and this method gives an instance of MyClass with that type.
See the following examples.
If I call this method as follows, getMyClassInstance(Integer_type), then it returns the MyClass<Integer> instance.
Similarly, if I call this method as follows, getMyClassInstance(String_type), then it returns the MyClass<String> instance.
How shall I write this method? If it can't be done, is there any alternative way or another better way to do something like this?
For simple applications of this, you don't even need to pass in a Type or Class argument. Consider the following:
public <T> List<T> getList() {
return new ArrayList<>();
}
To use this is as simple as:
List<Integer> lst = getList();
The compiler will infer the type of the list desired.
Do note that you will get more flexibility from passing in a Type parameter, especially in cases where you may not know in advance what sort of List you want to get back. But this sort of syntax, IMHO, reads more naturally and may be suited to what you want to do. (I say "may" since you haven't provided a ton of details ...)
The Type class must carry the type parameter on it: Type<T>, so you can declare
<T> MyClass<T> getMyClassInstance(Type<T> t);
If you can't make that happen, then the compiler is blind.

Why is it necessary to extend in case of read and super in write in generics wildcards?

I am having a hard time to understand the concept of generics wild cards.
As per my understanding <?> type unknown is introduced to resolve the co-variance not supported in generics and it should fit any type of collection and <?extends T> means that you can have collection of types T or the class which extends T.<?super T> means you can have collection of types T or super(s) of T.
Please correct me, if the above is wrong.
When I try to write it like this:
import java.util.*;
public class Gclass {
static Gclass t;
public void write(List< ?super String > lw){
lw.add("b");
}
public void read(List< ? extends String> lr){
String s=lr.get(2);
System.out.println(s);
}
public static void main(String[] args) {
t=new Gclass();
List<String> l=new ArrayList<String>();
l.add("a");
l.add("");
System.out.println(l);
t.write(l);
System.out.println(l);
t.read(l);
System.out.println(l);
}
}
It works but my places of doubt are:
As per my understanding both (extends and super) includes the type declared, so in this particular case as my List is of type String. I could interchange the extends and super, but I get compilation error?
In case of write ? super Object is not working? It should work as it is super of String?
I did not check for read as String can not be extended, but I think I'm also missing a concept here.
I've read all answers on SO related to this problem, but am still not able to have a good understanding about it.
String is indeed a bit of a bad example as it is a final class, but consider something like Number instead.
If a method takes a parameter of type List<? extends Number> then you can pass it a List<Number> or a List<Integer> or a List<BigDecimal> etc. Within the method body it is therefore fine to take things out of the list (as you know they must be instances of Number) but you can't put anything in because you don't know whether or not it's safe (the compiler can't let you risk putting an Integer into a List<Float>, for example).
Conversely if the method takes List<? super Number> then you can pass it a List<Number> or List<Object> - you can't take anything out of this list because you don't know what type it is*, but you do know that it'll definitely be safe to put a Number in.
* technically you can take things out but the only type you can assign them to is Object
As per my understanding both(extends and super) includes the type declared(String here), so in this particular case as my List is of type String... I could interchange the extends and super but i get compilation error?
You're right that both ? extends String and ? super String includes String. But you are missing the point that, ? super String also includes CharSequence, Object, which is not in bounds of ? extends String. You can add a String to a List<? super String>, b'coz whatever type that list is of, it can definitely refer to a String. But, you cannot add say an Integer to a List<? extends Number>, because the list can be a List<Float> actually.
In case of write ? super Object is not working? It should work as it is super of String?
Object is a super class of String will fit in where you have ? super String, and use Object for that. So, ? super String can capture Object, but ? super Object cannot capture String, as String is not a super type of Object. Think of it like this: "Actual type replaces the ?, and it must satisfy the rules attached to that ?.
List<? super String> means that lw holds a value of List with type argument which is String or it's superclass, so you can add a String value "b" (because it can be casted to list's type argument).
List<? extends String> means that lw holds a value of List with type argument which is String or it's subclasses, so values from lw can be casted to String.

How can we describe T<S> as return type for a method using generics in java

How can we describe T<S> as return type for a method
<T,S> T<S> getResult(Class<T> tClass, Class<S> sClass)
You can't, basically. There's no way of describing "a generic type with one type parameter" and using it like this.
Jon's right in that you can't do this in the general case. But if we think of a more specific case, say returning a specific type of List of a specific type of elements, we can do something like this:
<T, L extends List<T>> L getResult(Class<T> tClass, Class<L> lClass)
But then there's the problem of calling it. Classes are parameterized by raw types only. So if we wanted to call it like this:
ArrayList<String> result = getResult(String.class, ArrayList.class);
It wouldn't work, because ArrayList.class has type Class<ArrayList>, not Class<ArrayList<String>>.
But then we could use the super type token pattern, which Guava makes really easy with its TypeToken class:
<T, L extends List<T>> L getResult(Class<T> tClass, TypeToken<L> lType) {
// use lType.getRawType()...
}
ArrayList<String> result =
getResult(String.class, new TypeToken<ArrayList<String>>(){});
Of course, this is only going to be of use if L represents a concrete class. It's also possible to create a TypeToken using type parameters, which won't help you at runtime.

Categories