I am working with Java Generic classes (in this example, these are the Collection classes), and Reflection. I would like to be able to use reflection to take in a Class, check if it is an instance of a List, and then invoke the add method to it.
However, I've faced some difficulties in trying to put as the parameters to invoke the method call, and getting the declared method (shown where I put-what???). Both of those method parameter calls, require an object of type Class<?> which is the parameter type of needed for the add methods being invoked, which I don't know, since T itself is a generic.
Any help is appreciated! I apologize if the question is unclear, I tried the best I could to clarify.
static <T> void TestACollection(Class<T> clazz) {
T element=clazz.newInstance();
if(element instanceof List<?>)
Method m=clazz.getDeclaredMethod("add", what??? );
m.invoke(element, what???);
}
I'm guessing what you are trying to do is this:
public static <T> List<T> makeList() {
List<T> list = (List<T>) new ArrayList();
return list;
}
//...
{
List<String> list = makeList();
list.add( "Howdy" );
}
Which works as-is in Java 8. In earlier versions you may have to add #SuppressWarnings("unchecked") to the assignment.
Related
I'm trying to create DI container get method, but struggling with signature. Currently I have this definition:
public Object get(Class<?> key) {
// returns instance of `?`
}
The part of my code which I dont like much is usage of the get method:
IRouter router = (IRouter) container.get(IRouter.class);
where I have to cast return with (IRouter). Any ideas how to change method signature to make usage like this?
IRouter router = container.get(IRouter.class);
Thanks in advance for any ideas!
By using a scoped method parameterized type :
public <T> T get(Class<T> key) {
// ...
return (T) foo;
}
Here I suppose that foo is not typed as T.
If it is already typed as T you can of course return it without cast.
You could so invoke it :
IRouter router = container.get(IRouter.class);
I have a library method, which returns a collection of Objects by class name.
For example
Iterable x = RunState.getInstance().getMasterContext().getObjects(XAgent.class);
would return a list of all Objects in Context which are InstanceOf XAgent.class
If use it in that way, it work very well. How ever I need a method to pass the class-name to.
public Iterable getObjectsFromContext(Class clazz) {
return RunState.getInstance().getMasterContext().getObjects(clazz);
}
getObjectsFromContext(XAgent.class);
And then it does not work any more, it returns All objects of context... so why it does not pass my "clazz" variable into getObjects() ?
here is the linkt ot javadoc of getObjects();
http://repast.sourceforge.net/docs/api/repast_simphony/repast/simphony/context/Context.html#getObjects-java.lang.Class-
IndexedIterable<T> getObjects(java.lang.Class<?> clazz)
update: this works:
public Iterable getObjectsFromContext(Class<?> clazz) {
return RunState.getInstance().getMasterContext().getObjects(clazz);
}
getObjectsFromContext(XAgent.class)
this worked for me:
public Iterable getObjectsFromContext(Class<?> clazz) {
return RunState.getInstance().getMasterContext().getObjects(clazz);
}
getObjectsFromContext(XAgent.class)
There was a right answer suggested, but I do not see it anymore to accept, that's why I post it on my own.
This won't work because your wrapper function, getObjectsFromContext, explicitly takes in a type of "Class".
Whatever you pass in, it will be interpreted as type "Class" and thus get passed into the getObjects() function as "Class". That will explain why the function returns all objects.
You'll need make your wrapper function generic.
public Iterable<T> getObjectsFromContext(T clazz) {
return RunState.getInstance().getMasterContext().getObjects(clazz);
}
I'm having trouble figuring out how to properly cast a generic object in java to a type that extends the generic object.
For example, say I some setup like the following:
public class Parameters extends SomeCustomMap<String, String>
{
...
}
public class SomeCustomMap<K, V> implements Map<K, V>
{
public SomeCustomMap<K, V> getSubSet(...)
{
SomeCustomMap<K, V> subset;
...
return subset;
}
}
class ExampleApp
{
private void someMethod()
{
Parameters params;
Parameters paramsSubSet;
try
{
...
paramsSubSet = (Parameters) params.getSubSet(...);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Running code similar to the above consistently throws a ClassCastException, the likes of which I do not fully understand. Any assitence for how to correctly set up a scenario similar to the above would be appreciated! Namely, how might I properly cast the the SomeCustomMap object that is returned from the params.getSubSet(...) method back to a Parameters object?
Thanks in advance!
Your Problem is that the Subset returned by getSubSet is a of instance SomeCustomMap and not of Parameters.
This problem does not deal with generics. You will get the same problem if you did not use generics.
I don't know how you create an instance of subset but maybe you could use the template desing pattern and some generics to fix your problem.
You can try something like this:
public <T extends SomeCustomMap<K, V>> T getSubSet(...){
T subset = (T)this.clone();
subset.clear();
return subset;
}
creation looks a little funny - feel free to change it to whatever you want :)
As a bonus you will not need to cast :)
paramsSubSet = params.getSubSet(...)
Though I've commented asking for more information, based on what you've posted so far, I think getSubSet is constructing a SomeCustomMap to return (with new SomeCustomMap) somewhere. If you don't override getSubSet in Parameters, then Parameters.getSubset will return a SomeCustomMap (the base class), not a Parameters, so your typecast to Parameters fails.
(Hot tip, if you override getSubSet in the Parameters class, you can change the return type to Parameters and avoid the typecast.)
Generics don't inherently have anything to do with casting (save that due to the nature of erasure, generic parameters cannot be checked during a cast).
If you're getting a ClassCastException in this case, it means that the object returned really is not an instance of Parameters. Just before you cast, try calling
System.out.println(params.getSubSet(...).getClass());
and see what the actual run-time class of the subset is. Chances are the problem lies elsewhere, as your expectation that the subset is a Parameters object is almost certainly not correct at runtime - it's a SomeCustomMap or some other subclass thereof.
As others have explained, the issue is that the actual object you are constructing in getSubSet() is not an instance of Parameters.
Here's one possible workaround. I don't love it, but it is a way to declare the method in SomeCustomMap but have its return value be typed correctly for any subclass.
public static <T extends SomeCustomMap<K, V>> getSubSet(T fullSet)
{
T subset;
... (use fullSet instead of this)
return subset;
}
I've been reading Effective Java and decided to try to put some of what I've learned into action. I'm trying to effectively create a Multimap<?, Condition<?> > where the wild card will be the same type for both the key and the value, but it will be different, distinct types.
Here is the item from the book I'm looking at: Item 29
I'm not trying to fully replicate it. I realize the big difference is the key does not represent the value directly as per the link. In mine, the key represents the generic type of the value.
So I will do mmap.put(Class<Integer>, ConditionMapping<Integer>)
when I do the get I don't have the generic type of the ConditionMapping, so I get the unchecked cast warning.
I have a get method that I want to have the signature <T> List<Condition <T> >(Class<T> type)
Due to type erasure, is my only option to make sure the condition.value is of type T and building a new list of objects?
I could just ignore the unchecked cast warning, but I'm just trying not to. Any suggestions? Tips? Tricks?
There is no way to express that the two wildcards should capture the same type. See this question for a similar situation and a number of possible solutions.
If you make your interface extend Multimap<Void, Condition<?>> it allows your user to call some of the methods that do not rely on type safety (e.g. containsKey) but not to add entries (bypassing your type-checked proxy methods) unless they use unchecked casts.
interface ConditionMapBase<T> extends Multimap<T, Condition<?>> {
}
interface ConditionMap extends ConditionMapBase<Void> {
<T>boolean putCondition(T key, Condition<T> value);
<T>Collection<Condition<T>> getConditions(T key);
}
class ConditionMapImpl
extends ForwardingMultimap<Void, Condition<?>>
implements ConditionMap {
ConditionMapImpl() {
delegate = HashMultimap.create();
}
#SuppressWarnings("unchecked")
#Override
protected Multimap<Void, Condition<?>> delegate() {
return (Multimap<Void, Condition<?>>) (Multimap<?, ?>) delegate;
}
private final Multimap<Object, Condition<?>> delegate;
#SuppressWarnings("unchecked")
#Override
public <T> Collection<Condition<T>> getConditions(T key) {
return (Collection<Condition<T>>) (Collection<?>) ((ConditionMapBase<T>) this).get(key);
}
#SuppressWarnings("unchecked")
#Override
public <T> boolean putCondition(T key, Condition<T> value) {
return ((ConditionMapBase<T>) this).put(key, value);
}
}
You could make a MyClass and then pass your own type to it, and ecapsulate the Multimap inside that. Template impossibilities in Java can often be solved by adding another layer, so to speak, and templating a class around what you really want, since you can get a "T" type that way, which you can then use for Lists or Maps, and guarantee that it is the same for multiple templates from then on.
This might be a step in the right direction.
<Multimap<Class<?>, Condition<?>>
I would like to create an object of Generics Type in java. Please suggest how can I achieve the same.
Note: This may seem a trivial Generics Problem. But I bet.. it isn't. :)
suppose I have the class declaration as:
public class Abc<T> {
public T getInstanceOfT() {
// I want to create an instance of T and return the same.
}
}
public class Abc<T> {
public T getInstanceOfT(Class<T> aClass) {
return aClass.newInstance();
}
}
You'll have to add exception handling.
You have to pass the actual type at runtime, since it is not part of the byte code after compilation, so there is no way to know it without explicitly providing it.
In the code you posted, it's impossible to create an instance of T since you don't know what type that is:
public class Abc<T>
{
public T getInstanceOfT()
{
// There is no way to create an instance of T here
// since we don't know its type
}
}
Of course it is possible if you have a reference to Class<T> and T has a default constructor, just call newInstance() on the Class object.
If you subclass Abc<T> you can even work around the type erasure problem and won't have to pass any Class<T> references around:
import java.lang.reflect.ParameterizedType;
public class Abc<T>
{
T getInstanceOfT()
{
ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass();
Class<T> type = (Class<T>) superClass.getActualTypeArguments()[0];
try
{
return type.newInstance();
}
catch (Exception e)
{
// Oops, no default constructor
throw new RuntimeException(e);
}
}
public static void main(String[] args)
{
String instance = new SubClass().getInstanceOfT();
System.out.println(instance.getClass());
}
}
class SubClass
extends Abc<String>
{
}
What you wrote doesn't make any sense, generics in Java are meant to add the functionality of parametric polymorphism to objects.
What does it mean? It means that you want to keep some type variables of your classes undecided, to be able to use your classes with many different types.
But your type variable T is an attribute that is resolved at run-time, the Java compiler will compile your class proving type safety without trying to know what kind of object is T so it's impossible for it to let your use a type variable in a static method. The type is associated to a run-time instance of the object while public void static main(..) is associated to the class definition and at that scope T doesn't mean anything.
If you want to use a type variable inside a static method you have to declare the method as generic (this because, as explained type variables of a template class are related to its run-time instance), not the class:
class SandBox
{
public static <T> void myMethod()
{
T foobar;
}
}
this works, but of course not with main method since there's no way to call it in a generic way.
EDIT: The problem is that because of type erasure just one generic class is compiled and passed to JVM. Type checker just checks if code is safe, then since it proved it every kind of generic information is discarded.
To instantiate T you need to know the type of T, but it can be many types at the same time, so one solution with requires just the minimum amount of reflection is to use Class<T> to instantiate new objects:
public class SandBox<T>
{
Class<T> reference;
SandBox(Class<T> classRef)
{
reference = classRef;
}
public T getNewInstance()
{
try
{
return reference.newInstance();
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public static void main(String[] args)
{
SandBox<String> t = new SandBox<String>(String.class);
System.out.println(t.getNewInstance().getClass().getName());
}
}
Of course this implies that the type you want to instantiate:
is not a primitive type
it has a default constructor
To operate with different kind of constructors you have to dig deeper into reflection.
You need to get the type information statically. Try this:
public class Abc<T> {
private Class<T> clazz;
public Abc(Class<T> clazz) {
this.clazz = clazz;
}
public T getInstanceOfT()
throws throws InstantiationException,
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException,
NoSuchMethodException,
SecurityException {
return clazz.getDeclaredConstructor().newInstance();
}
}
Use it as such:
Abc<String> abc = new Abc<String>(String.class);
abc.getInstanceOfT();
Depending on your needs, you may want to use Class<? extends T> instead.
The only way to get it to work is to use Reified Generics. And this is not supported in Java (yet? it was planned for Java 7, but has been postponed). In C# for example it is supported assuming that T has a default constructor. You can even get the runtime type by typeof(T) and get the constructors by Type.GetConstructor(). I don't do C# so the syntax may be invalid, but it roughly look like this:
public class Foo<T> where T:new() {
public void foo() {
T t = new T();
}
}
The best "workaround" for this in Java is to pass a Class<T> as method argument instead as several answers already pointed out.
First of all, you can't access the type parameter T in the static main method, only on non-static class members (in this case).
Second, you can't instantiate T because Java implements generics with Type Erasure. Almost all the generic information is erased at compile time.
Basically, you can't do this:
T member = new T();
Here's a nice tutorial on generics.
You don't seem to understand how Generics work.
You may want to look at http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html
Basically what you could do is something like
public class Abc<T>
{
T someGenericThing;
public Abc(){}
public T getSomeGenericThing()
{
return someGenericThing;
}
public static void main(String[] args)
{
// create an instance of "Abc of String"
Abc<String> stringAbc = new Abc<String>();
String test = stringAbc.getSomeGenericThing();
}
}
I was implementing the same using the following approach.
public class Abc<T>
{
T myvar;
public T getInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException
{
return clazz.newInstance();
}
}
I was trying to find a better way to achieve the same.
Isn't it possible?
Type Erasure Workaround
Inspired by #martin's answer, I wrote a helper class that allows me to workaround the type erasure problem. Using this class (and a little ugly trick) I'm able to create a new instance out of a template type:
public abstract class C_TestClass<T > {
T createTemplateInstance() {
return C_GenericsHelper.createTemplateInstance( this, 0 );
}
public static void main( String[] args ) {
ArrayList<String > list =
new C_TestClass<ArrayList<String > >(){}.createTemplateInstance();
}
}
The ugly trick here is to make the class abstract so the user of the class is forced to subtype it. Here I'm subclassing it by appending {} after the call to the constructor. This defines a new anonymous class and creates an instance of it.
Once the generic class is subtyped with concrete template types, I'm able to retrieve the template types.
public class C_GenericsHelper {
/**
* #param object instance of a class that is a subclass of a generic class
* #param index index of the generic type that should be instantiated
* #return new instance of T (created by calling the default constructor)
* #throws RuntimeException if T has no accessible default constructor
*/
#SuppressWarnings( "unchecked" )
public static <T> T createTemplateInstance( Object object, int index ) {
ParameterizedType superClass =
(ParameterizedType )object.getClass().getGenericSuperclass();
Type type = superClass.getActualTypeArguments()[ index ];
Class<T > instanceType;
if( type instanceof ParameterizedType ) {
instanceType = (Class<T > )( (ParameterizedType )type ).getRawType();
}
else {
instanceType = (Class<T > )type;
}
try {
return instanceType.newInstance();
}
catch( Exception e ) {
throw new RuntimeException( e );
}
}
}
There are hacky ways around this when you really have to do it.
Here's an example of a transform method that I find very useful; and provides one way to determine the concrete class of a generic.
This method accepts a collection of objects as input, and returns an array where each element is the result of calling a field getter on each object in the input collection. For example, say you have a List<People> and you want a String[] containing everyone's last name.
The type of the field value returned by the getter is specified by the generic E, and I need to instantiate an array of type E[] to store the return value.
The method itself is a bit ugly, but the code you write that uses it can be so much cleaner.
Note that this technique only works when somewhere in the input arguments there is an object whose type matches the return type, and you can deterministically figure it out. If the concrete classes of your input parameters (or their sub-objects) can tell you nothing about the generics, then this technique won't work.
public <E> E[] array (Collection c) {
if (c == null) return null;
if (c.isEmpty()) return (E[]) EMPTY_OBJECT_ARRAY;
final List<E> collect = (List<E>) CollectionUtils.collect(c, this);
final Class<E> elementType = (Class<E>) ReflectionUtil.getterType(c.iterator().next(), field);
return collect.toArray((E[]) Array.newInstance(elementType, collect.size()));
}
Full code is here: https://github.com/cobbzilla/cobbzilla-utils/blob/master/src/main/java/org/cobbzilla/util/collection/FieldTransformer.java#L28
It looks like you are trying to create the class that serves as the entry point to your application as a generic, and that won't work... The JVM won't know what type it is supposed to be using when it's instantiated as you start the application.
However, if this were the more general case, then something like would be what you're looking for:
public MyGeneric<MyChoiceOfType> getMeAGenericObject(){
return new MyGeneric<MyChoiceOfType>();
}
or perhaps:
MyGeneric<String> objMyObject = new MyGeneric<String>();
Abc<String> abcInstance = new Abc<String> ();
..for example