how to find Collection type? - java

I have two variables
Collection<Service> services = new ArrayList<Service>();
Collection<Subscription> subscriptions = new ArrayList<Subscription>();
and I have the following method, I was wondering how can I find the value of "?" in this method, or how can I find if services was passed or subscriptions was passed?
myMethod(Collection<?> myCollection) {
if (myCollection is of type Service) {
// process service
}
else if (myCollection is of type Subscription) {
// process subscription
}
}
Thanks.

You cannot. Java has erasure-based generics, which means that the type parameters are not available at runtime.
If your collection is not empty, you can do an instanceof on the first element or something, of course.

Using that if-else construct in a generic method defeats the purpose of generics. If you need to know the type of what is being passed in at runtime, it really shouldn't be generic and you should write a separate method for each type.

You can't (except by using reflection), since the generic type parameter gets erased during compilation.
And I would recommend you rethink your design rather than trying to solve it with generics. Passing arbitrary types of collections into the same method is a recipe for problems in the long run.

There is no Java way of doing exactly that. Type erasure gets in the way. And if you need to do so, it is also probably a design issue.
But if you must, there is horrible way to do almost that:
Change your variables to
Collection<Service> services = new ArrayList<Service>(){};
Collection<Subscription> subscriptions = new ArrayList<Subscription>(){};
Note the {} after the (). You are not creating an ArrayList, but a anonymous class that inherits from ArrayList. And type erasure does not apply there. So you can tell the real type by doing something like
private static Class<?> detectType(Collection<?> col) {
return (Class<?>) ((ParameterizedType) col.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
That method will return the actual class. It does work, it is disgusting. It is up to you.

Related

When is it acceptable to pass a Class<T> argument to a generic method?

Methods that are generic using the T parameter can for sure be handy. However, I am curious what the use of a generic method would be if you pass an argument such as Class<T> clazz to the method. I've come up with a case that maybe could be an possible use. Perhaps you only want to run a part of the method based on the type of class. For example:
/** load(File, Collection<T>, Class<T>)
* Creates an object T from an xml. It also prints the contents of the collection if T is a House object.
* #return T
* Throws Exception
*/
private static <T> T void load(File xml, Collection<T> t, Class<T> clazz) throws Exception{
T type = (T) Jaxb.unmarshalFile(xml.getAbsolutePath(), clazz); // This method accepts a class argument. Is there an alternative to passing the class here without "clazz"? How can I put "T" in replace of "clazz" here?
if (clazz == House.class) {
System.out.println(t.toString());
} else {
t.clear();
}
return T;
}
Is this an accepted practice? When is the Class<T> clazz argument useful with generic methods?
Is this an accepted practice?
Well, to me.. no not really. To me, it seems somewhat pointless when you can simply define some boundaries on the type of T. For example:
private static <T extends House> void load(Collection<T> t)
This will guarantee that either the object is of type House or of a subclass of House, but then again if you only want an instance of type House or it's subclasses, it should really just be:
private static void load(Collection<House> houses)
The idea of generics is to make a method or a class more malleable and extensible, so to me it seems counter-intuitive to start comparing class types in the method body, when the very notion of generics is to abstract away from such details.
I'd only pass class objects if the generic type could not be derived otherwise. In your case, the compiler should be able to infer T from the collection. To treat specific objects differently, I'd use polymorphism - e.g. House#something() and Other#something(), and just call anyObject.something().
I think it is acceptable but if it can be avoided then you should. Typically, if you can have different methods which accepts different type, then do it instead of one method which uses if clauses to do something different depending on the type of the parameter. You could also delegates to the class the operation you want to make specific for a given type.
In your case, you could simply test the type of each element of the collection using instanceof, to do what you need for the specific type. But it won't work if the list is empty.
A typical use is if you need to get the type to create it and you can find it from another way. For instance, Spring uses it to load a bean from its name:
<T> T getBean(Class<T> requiredType)
In that case, it cannot be avoided (without having to cast).
If the returned value or other parameters types are dependent or need to be equal, generics will add compile time checks, so that there's no need to cast to T.
Examples
<T> T createNewInstanceOfType(Class<T> type);
<T> void addValueToCollection(Collection<T> collection,T value);
<T> List<Class<? extends T>> findSubClassesInClasspath(Class<T> superType);
Raw types
It is still possible to defer a casting error until runtime (ClassCastException) with some casts, e.g. with implicit casts from non-generic (raw) types to generic ones:
List nonGenericList = new ArrayList();
nonGenericList.add(new Integer(42));
List<String> wreckedList = nonGenericList;
The compiler will generate a bunch of warnings, unless you suppress them with annotations or compiler settings.
Compiler Settings (Eclipse):
For example, the usage of raw types generates a warning per default, one can treat warnings as errors and even as fatal errors:
You would pass a Class<T> argument in generics if, and only if, you would pass a Class argument before generics. In other words, only if the Class object is used in some way. Generics serves as a compile-time type checking tool. However, what arguments you pass should be determined by the runtime logic of the program, and should be irrelevant of generics.
I haven't seen passing a Class object in order to check the runtime type of an object as a common use case for generics. If you're doing that, there's a good chance that there's a better way to set up your class structure.
What I have seen is if you need to create a new instance of the class in question, or otherwise use reflection. In that case you do have to pass the Class object, because Java cannot derive it at runtime thanks to type erasure.
In your case actually having the Generic parameter is not strictly needed.
Since the output of the function you are describing does not depend on the type of the input you might as well use wild cards.
private static void stuff(Collection<?> t){
Object next = t.iterator().next(); //this is ugly and inefficient though
if(next instanceof House){
System.out.print(next.toString());
}else{
t.clear();
}
}
The only time you should use generic parameter is when the type of the result of a function will be dependent of the type of the parameters.
You will need to pass the Class corresponding to the type when your code will need it; most of the time this happens when:
- You need to cast/type check objects to T
- There is serialization/deserialization involved.
- You cannot access any instance of T in your function and you cannot call the getClass() method when you need it.
Passing a Class on every generic function will result in you passing an unnecessary parameter most of the time, which is regarded as bad practice.
I answered a similar discussion in the past:
When to use generic methods and when to use wild-card?

Creating a list from generic type in Java

I have an interface of the form:
public interface Tester<K1, V1> {
...
}
A client will implement this interface, then pass me the .class file for their subclass. I then parse out the K1, V1 from the interface in the following manner:
// Assume only Tester<K1, V1> is implemented for now:
Type genericInterface = ClientClass.class.getGenericInterfaces()[0];
if(genericInterface instanceof ParameterizedType){
Type[] genericTypes = ((ParameterizedType) genericInterface).getActualTypeArguments();
List<?> myList = new ArrayList<genericTypes[1]>(); // THIS DOES NOT WORK!
}
I'm trying to instantiate a list based on the generic type declared in their interface. What is the correct way to do this in java? Is this possible? The way that I'm going about it doesn't seem to work.
Instead of List<?> myList say List<Object> myList or even older style: List myList. The latter will give you compiler warning, it was the style before generics helped. I cannot fully understand what you want to do though. Do you basically try to determine the type of the generic at runtime?
Generics were introduced so you'd be able to get compile type error checks. Unless there's a really good reason, try to avoid generics (I can only think of that if you build some caching framework, where you really have to handle everything, I've seen that). Try to find the most common denominator base class among those objects what you'll try to handle/store.
In your case this is possible to do. However, the way you create the ArrayList is illegal, syntactically, since the generic type argument must be known in compile time. Use new ArrayList<Object> instead (both in constructor call and declaration).
I don't think using a dynamic value, such as genericTypes[1] in your example, is possible in Java. Generics in Java are basically syntactic sugar which is applied at compile time. The type information is, for the most part, erased at runtime. Some additional information is available in the Java tutorial at http://docs.oracle.com/javase/tutorial/java/generics/erasure.html

How to do `MyClass<String>.class` in Java?

How can call public <T> T doit(Class<T> clazz); using MyClass<String>.class as clazz where I can not instantiate or extend MyClass.
EDIT: 'David Winslow' and 'bmargulies' responses are correct (MyClass<String>) doit(MyClass.class); works for the original question BUT surprisingly when the method returns say MyClass<T> instead of T casting will not compile any more.
Edit: I have replaced List with MyClass and added the condition to my original question.
Use List.class. Because of type erasure type parameters to Java classes are entirely a compile-time construct - even if List<String>.class was valid syntax, it would be the exact same class as List<Date>.class, etc. Since reflection is by nature a runtime thing, it doesn't deal well with type parameters (as implemented in Java).
If you want to use the Class object to (for example) instantiate a new List instance, you can cast the result of that operation to have the appropriate type parameter.
List<String> list = (List<String>)(ArrayList.class.newInstance());
I've seen similar questions asked several times, for example
Acquiring generic class type
There are legitimate reasons to construct static generic types. In op' case, he would probably like to
MyClass<String> result = doit(MyClass<String>.class);
Without language syntax support, casting is the correct way to go. If this is needed quite often, the casting should be put in a method, as
public class MyClass<T>
{
#SuppressWarnings("unchecked")
// may need a better method name
static public <T2> Class<MyClass<T2>> of(Class<T2> tClass)
{
return (Class<MyClass<T2>>)(Class<?>)(MyClass.class);
}
}
MyClass<String> result = doit(MyClass.of(String.class)); // no warning
We can supress the warning on that method alone, after making sure the cast is safe. Any call site will not see the warning.
This is all compile time casting game. At runtime all the type parameters are erased, and really only the naked class object is passed around. The of method will most likely be optimized off, so to JVM the last line is nothing but
MyClass result = doit(MyClass.class)
There are also times when at runtime we need a complete MyClass<String> type. A ParameterizedType object needs to be obtained to represent MyClass<String>.
When the two requirements are combined together, that is, we need a compile time expression regarding MyClass and String that will evaluate at runtime to a ParameterizedType
ParameterizedType type_MyClass_String = ???? MyClass ?? String ???
There is a technique involving an anonymous subclass of MyClass<String>
ParameterizedType type_MyClass_String = superTypeOf( new MyClass<String>(){} );
which I find quite disturbing.
See http://jackson.codehaus.org/1.7.0/javadoc/org/codehaus/jackson/type/TypeReference.html and the references that it references for a comprehensive discussion of the issues around generics.
the bottom line is that, if you really want to work with generic types in this way, you have to stop using Class and start using Type and its subclasses.
Contrary to your comment on another answer, you can write List<List<String>> obj = (List<List<String>>) doit(List.class);, you just can't avoid a warning when you write it.
Since after your update your question does not appear to be an exact duplicate:
You would need to call getClass() on an instance of MyClass. Better have a dummy static final instance somewhere:
public static final MyClass INSTANCE = new MyClass();
...
return (Class<MyClass<String>>) instance.getClass();
T corresponds to List, so any reference to String as the generic paramter of List is irrelevant.
How to do MyClass<String>.class in
Java?
You can't.
Generics in Java use type erasure; the type of the parametrized argument is enforced during compilation, but it is lost after compilation. The resulting byte code for an instance of a generic class does not contain any run-time meta-data on its arguments whatsoever.
As it is now, it is just not possible, a major language design blunder IMO.

Creating parameterized type object using anonymous class

This might be a stupid question, but I just saw a question asking how to create a Type variable for a generic type. The consensus seemed to be that you should have a dummy method returning that type, and then use reflection to get it (in this case he wanted Map<String, String>). Something like this :
public Map<String, String> dummy() { throw new Error(); }
Type mapStringString = Class.forName("ThisClass").getMethod("dummy").getGenericReturnType();
My question is, not having used reflection that much, couldn't you just do something like:
Type mapStringString = new ParameterizedType() {
public Type getRawType() {
return Map.class;
}
public Type getOwnerType() {
return null;
}
public Type[] getActualTypeArguments() {
return new Type[] { String.class, String.class };
}
};
Would this work? If not, why not? And what are some of the dangers/problems if it does (besides being able to return some Type like Integer<String> which is obviously not possible.
Sure you could, and for most applications it would probably be sufficient.
However, using the first method, you get a more refined object. Let's say for instance that you create an object type1 using the first method, and type2 using the second method. Then type1.equals(type2) would return true (since the first method returns an object that properly implements the equals-method) but type2.equals(type1) would return false (since in the second method, you haven't overridden the equals-method, and are using the implementation from Object).
Same reasoning applies to other (sometimes useful methods) such as toString, hashCode etc. The second method does not provide useful implementations of these.
If you include Google's Guava library in your project (you should; it's great), use its TypeToken to get a type. Google's Gson library (for interacting with JSON) has a similar version. Both are used like this (to get a Type representing List<String>:
Type t = new TypeToken<List<String>>(){}.getType();
If you don't want to rely on any third-party libraries, you can still use anonymous types to get a generic concrete type with one line of code (this technique will not work with interfaces and could be more trouble than it's worth for Abstract Types). To get a Type representing HashMap<String, String>, do this:
Type t = new HashMap<String, String>(){}.getClass().getGenericSuperclass();
I have verified that resulting Type instance .equals() the Type instances created by Gson's TypeToken, though have not verified the same for Guava's version of TypeToken, which I do not have access to at the moment. (Guava is a more general-purpose library that is so handy for all sorts of things, you should probably be using it anyways.)
In addition to the mentioned libs from Google there is also a lib from Apache that does the job.
import org.apache.commons.lang3.reflect.TypeUtils;
...
ParameterizedType type = TypeUtils.parameterize(List.class, Double.class);
...
Finde code on GitHub here and Maven artifacts here.
Actually, I think the simplest way (== least code) to do this would be a dummy interface extending the type your interested in, and then getGenericInterfaces()[0] from its class (use getGenericSuperclass() if you're interested in a class):
private interface MapStringString extends Map<String, String> {}
private static ParameterizedType mapStringString(){
return (ParameterizedType) MapStringString.class.getGenericInterfaces()[0];
}
It doen't scale well, though, as you have to create a new class for every ParameterizedType you want to represent. I don't see why your implementation wouldn't do (unless there are narrowing casts somewhere), and it does have the appealing benefit that you can make it reusable.

Java: getting inner type in nested parameterized types (reflection)

Most of the documentation regarding type erasure handling in Java assumes that the use case is handling a type like SomeType<ParamType>.
I am trying to process method parameter for the following method:
public void setOtherReferenceRanges(List<ReferenceRange<T>> referenceRanges)
When the container class is instantiated with a type DvQuantity, this signature should become
public void setOtherReferenceRanges(List<ReferenceRange<DvQuanitity>> referenceRanges) in runtime.
Using reflection one can see that the List has an actualTypeArgument which is ReferenceRange<T>. Since reflection uses class information, I would not expect it to give me ReferenceRange<DvQuantity>.
However, when I created the class containing this method, I passed the DvQuantity type as T. So the type filling in T should be available to Java runtime, but I could not find a way of getting it. I end up with a TypeVariableImpl object accessed via reflection, which does not seem to contain any useful data.
Can you think of any ways to discover this information in runtime?
When you say
when I created the class containing this method
I guess you mean when you create an object of that type, for example:
foo = new ContainerClass<DvQuantity>();
In that case, because of erasure, there is no way to recover the type DvQuantity.
However, if you create a class passing a type parameter to the superclass, like this
class DvQuantityContainerClass extends ContainerClass<DvQuantity> {...}
...
foo = new DvQuantityContainerClass();
Or, shorter, an inline anonymous subclass (which looks almost like the first example but with a subtle but important difference):
foo = new ContainerClass<DvQuantity>(){};
Then you can recover the type parameter, because you recover the type parameter used to extend a superclass at runtime. Unfortunately, Java itself doesn't provide an easy way to now get the type of the DvQuantityContainerClass.setOtherReferenceRanges method with the T filled in. For that, I've written gentyref, to do advanced reflection on generic types:
Method m = DvQuantityContainerClass.class.getMethod("setOtherReferenceRanges", List.class);
// this will return List<ReferenceRange<DvQuanity>>, like you are lookingn for
return GenericTypeReflector.getExactParameterTypes(m, DvQuantityContainerClass.class)
Generic type information is erased by the compiler and is not available at runtime. When I need to ensure a certain type at runtime I pass in a class argument:
public <T> void doSomething(T t, Class<T> c);
This is not always convenient or even possible, but for many cases it is possible.
So the type filling in T should be available to Java runtime, but I could not find a way of getting it.
Perhaps it's not entirely correct, but the way I think about it is that at runtime there is no actual class - just an object without a specific type which meets the interface of T. In other words, erasure happens not with objects, but instead with these nebulous (in the OOP world at least) type-things.
http://java.sun.com/docs/books/tutorial/java/generics/erasure.html
There are ways of capturing the type information inside the class itself (T types would need a method getUnderlyingType()... or something), but that's a bad idea. If you truly need to raw type of the object, I'd reconsider using generics.

Categories

Resources