I'm guessing there is absolutely no way I can do something like:
Class c = Class.forName("Processor<Integer, String>");
in Java? (where I defined Processor previously, of course).
Absolutely no way as generic arguments can exist only at compile time. Class object is the same on runtime. It is not class template as in C++. Type parameters are just information for java compiler.
You can try to accomplish something similar by creating a class :
class IntStringProcessor extends Processor<Integer, String> {}
and Class c = Class.forName("IntStringProcessor");
On runtime you can get actual Processor type parameters via c.getGenericSuperclass() but this extends the question I guess.
EDIT: Another idea
Your Processor may keep classess as parameters and then:
Class c1 = Class.forName("java.lang.Integer");
Class c2 = Class.forName("java.lang.String");
Processor = new Processor(c1,c2);
Your processor is now not generic but uses Class instances inside. As I said, there is no way to create generic instance on runtime because generics exist only at compile time.
First let me straighten something. There is no Class object in Java for Processor<Integer, String>. There is only one Class object for Processor, namely Processor.class and all generic instantiations share the same Class object:
Processor<Integer, String> x = new Processor<Integer, String>();
Processor<Character, Byte> y = new Processor<Character, Byte>();
System.out.println(x.getClass() == y.getClass()); // prints true
Having said that, if all you need is to have tokens for generic types to pass around, you can use a third party implementation. Here I use Java ClassMate:
TypeResolver typeResolver = new TypeResolver();
// type token for Processor<Integer, String>
ResolvedType type = typeResolver.resolve(Processor.class, Integer.class, String.class);
System.out.println("type = " + type);
If you read names of Java types as String's from a file, you probably want to use Class.forName() instead of my .class literals.
You'll have to parse <, > brackets yourself, but that should be easy, as those single characters always mean the same thing in Java type names...
You can form nested parameters like this:
// type token for Processor<Processor<Integer, String>, Character>
ResolvedType type = typeResolver.resolve(Processor.class,
typeResolver.resolve(Processor.class, Integer.class, String.class),
typeResolver.resolve(Character.class)
);
System.out.println("type = " + type);
If you want to create type tokens for types you know at compilation time, you can use the so-called super-type-token pattern. Just put any type name you need inside new GenericType<...>() {}:
type = typeResolver.resolve(new GenericType<Processor<Processor<Integer, String>, Character>>() {});
System.out.println("type = " + type);
Related
Specifically, if I return a filled ArrayList do I have to return the type with it such as ArrayList<modNode>? To add onto this, if i'm using a generic typing for a custom link list that uses the <T> tag would I have to return ArrayList<modNode<T>>? Just a little curious on the properties of ArrayLists containing generic objects... Thanks in advance!
Let's say you have a method that returns an ArrayList of String objects:
public ArrayList<String> foo() {
ArrayList<String> list = new ArrayList<>();
// ... fill list ...
return list;
}
This is how you would normally1 declare the method in Java 5+ (since the addition of generics). But you don't have to do this. You could declare the method as:
public ArrayList foo() {
// ... code ...
return list;
}
This would mean you are using raw types. Unless you are interacting with a legacy (pre Java 5) library/application you never want to use raw types. The reason is because a raw type is (nearly?) equivalent to returning ArrayList<Object>. You've just lost all type safety given by generics. The reason for generics is to provide compile-time2 type checks so you don't accidentally use the wrong types. For instance, you could now add a Dog to the ArrayList returned by foo even though you intended it to only contain String objects. Also, code using the returned ArrayList has no guarantee that there will only be String objects inside the ArrayList which can result in all sorts of headaches.
You could get around raw types by casting:
String element = (String) foo().get(0);
However, that's basically what generic code compiles down to anyway; except you no longer have compile-time safety.
If the element type is also generic then yes you would want to return that information as well. Let's say you return an ArrayList of Supplier objects instead. It will be each Supplier that returns the needed String objects.
public ArrayList<Supplier<String>> foo() {
// ... code ...
}
It's important you give the Supplier's generic signature here so you can do things like:
for (Supplier<String> sup : foo()) {
String str = sup.get();
// .. do something with "str" ...
}
If you returned ArrayList<Supplier> then each Supplier.get() would return an Object. You've lost all type safety again.
1. You would actually, in virtually all cases, want to return List rather than ArrayList. It's best to program to an interface.
2. It only works at compile-time due to type erasure. Also see this.
The type parameter <T> depends on the actual Type Parameter you supply to Generic Type. For example:-
List<String> names = new ArrayList<>();
String is the actual type parameter of parameterized type List<String>. Behind the scene compiler did casting on each elements automatically. So you can safely expect get method will return String type.
The modNode class is generic type. Then caller has to declare what is the actual type parameter. It could be String, type that extends Node or whatever. Example below:-
List<modeNode<String>> modeNodes = new ArrayList<>();
However your ArrayList<modNode<T>> actual type parameter is already modeNode. Hence get method will probably returns some kind parameterized type modeNode<T>. Ex:-
List<modeNode<String>> modeNodes = new ArrayList<>();
....
modeNode<String> mn = modeNodes.get(0);
Notes:-
** Rename modNode type class name to ModNode to follow Java convention. Class name must start with Capital letter.
ModeNode<Node> mn = ModeNode.getInstance();
//More readable due to following naming convention.
List<ModeNode<Node>> mns = new ArrayList<>();
** It is preferable to declare as interface type Listthan concrete type ArrayList. Unless if you want to use specific ArrayList behaviour implementation.
Since few days ago I started to work on a webservice project. This project is using Jackson to marshalling and unmarshalling JSON objects. So my question is:
Why always I have to put the {} when I am creating an instance of TypeReference? I know the constructor is protected, but why is protected? I think that it's like a hack to make visible the constructor creating an implementation of the constructor since TypeReference is abstract and you can do it. But what is the point of this?
String jsonString = "{\" firstName\":\"John\",\"lastName\":\"Chen\"}";
ObjectMapper objectMapper = new ObjectMapper();
// properties will store name and value pairs read from jsonString
Map<String, String> properties = objectMapper.readvalue(
jsonString, new TypeReference<Map<String, String>>()
{ //
});
TL;DR
Via subclassing it is possible for TypeReference to extract the actual generic type parameter. E.g:
TypeReference<String> ref = new TypeReference<String>(){};
System.out.println(ref.getType());
Prints:
class java.lang.String
This can be useful when you can't use normal classes. E.g when this doesn't work:
// doesn't work
Type type = ArrayList<String>.class;
You still can get that class by using a TypeReference:
// will yield Class<ArrayList<String>>>
Type type = new TypeReference<ArrayList<String>>(){}.getType();
Detailed
When looking at the source code of TypeReference (using Jackson 2.8.5) you can see that the constructor body contains the following lines:
Type superClass = getClass().getGenericSuperclass();
if (superClass instanceof Class<?>) { // sanity check, should never happen
throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
}
_type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
The interesting lines are the first and last. Let's take a closer look at the first line:
Type superClass = getClass().getGenericSuperclass();
For example when you're creating a subclass, by using an anonymous class:
TypeReference<SomeStype> ref = new TypeReference<SomeType>(){};
Then getClass returns the current Class object (an anonymous class), and getGenericSuperclass() will return the Class object from the class the current implementation extends from, in our case, superClass will equal Class<TypeReference<?>>.
Now when looking at the last line from the constructor body:
_type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
As we know that the superClass is the Class object for TypeReference<?> we know that it has a generic parameter. Hence the cast to ParameterizedType. This specified Type has the method getActualyTypeArguments() which returns an array of all generic parameters specified by that class. In our case it's just 1. So [0] will yield the first element. In the example we will get the actually specified type parameter SomeType.
I have some code which needs to unpick a Jackson TypeReference to find out if it is a Collection. At the moment the best I can come up with is:
// Sample type reference - in reality this is an argument to the method
final TypeReference<List<String>> typeRef = new TypeReference<List<String>>(){};
// Obtain the Java reflection type from the TypeReference
final Type type = typeRef.getType() instanceof ParameterizedType ? ((ParameterizedType)typeRef.getType()).getRawType() : typeRef.getType();
// Obtain the name of the class (or interface)
final String typeName = type.toString().replace("class ", "").replace("interface ", "");
// And find out if it is a Collection
final boolean isCollection = Collection.class.isAssignableFrom(Class.forName(typeName));
But I would hope that there is a way to do this without string manipulation. Is there a better way to go from the Java Type to the Class, or indeed to check assignability directly from either the TypeReference or the Type?
This needs to work on Android so any features added in Java 8 can't be used.
Based on your line of code,
final Type type = typeRef.getType() instanceof ParameterizedType ? ((ParameterizedType)typeRef.getType()).getRawType() : typeRef.getType();
You can safely cast it to a Class like this
final Class clazz = (Class)(typeRef.getType() instanceof ParameterizedType ? ((ParameterizedType)typeRef.getType()).getRawType() : typeRef.getType());
To add a little more explanation -
In the first scenario where ( typeRef is an instance of ParameterizedType), you are retrieving the rawType which would be a Class.
In the second scenario where (typeRef is not an instance of ParameterizedType), it would still be a regular Class because it is not Parameterized.
I am having a data structure (LinkedHashMap) but the problem is that the (second) value should be of variable type since I can put there type String or type int or any primitive type so my question is:
Is there a way to define a variable type for it that can get any value type?
This is what I'm having:
private LinkedHashMap<String, String> keyVal;
I want something like this:
private LinkedHashMap<String, anyValue> keyVal;
private LinkedHashMap<String, Object> keyVal;
You can use Object for that. But do remember that while trying to get data back from this map(sometime later), you may face difficulty in casting the Object to your required data type, as you may not know, what data type is actually present.
Hence, its advisable to avoid such implementations.
You cannot have a generic type be a primitive type. If you want to be able to store anything in your map, you can have the "value" generic type for the map be Object:
private LinkedHashMap<String, Object> keyVal;
You can still store what looks like primitives types due to autoboxing, i.e.
keyVal.put("one", 1);
will place an Integer, even though you specified an int.
No, the closest you can have is Object as a second argument.
Now, I would advise to rethink what you need to accomplish, since this is actually going against what generics were created for.
If you have a bound type and want to maintain some flexibility, then you could use something like <String, ? extends SomeType>.
Mixing several types of Objects in the same data-structure is not advisable in Java (if this is good or bad, is beside the point), but type safety goes a long way in preventing weird errors along the line.
Try to think about how you would deal with this when you actually need to retrieve the objects... will you assume they're Strings? What are you going to do with them?
You say you want to have a Map< String, Primitive type>.
A specified by the JLS, primitives are NumericType or boolean, NumericType are IntegralType or FloatingPointType.
If your need is not primitive but only NumericType, you may use java.lang.Number:
Map< String, Number >
Another way is to define a class Any which hold all the possible attributes:
enum Type {
NULL,
INTEGER,
SHORT,
FLOAT,
...
}
class Any {
private int iValue;
private short sValue;
private float fValue;
...
private Type active = Type.NULL;
public void setInt( int value ) {
iValue = value;
active = Type.INTEGER;
}
public void setFloat( float value ) {
fValue = value;
active = Type.FLOAT;
}
...
public int getInt() {
if( type != Type.INTEGER ) {
throw new ClassCastException( type.name() + " is not an integer" );
}
return iValue;
}
...
}
It's up to you to put some check and throw exception if getInt() is called on a float holder. Everything is possible, transtyping like C language for example.
EDIT
You want String too, and String isn't a primitive.
You have to add the following below private short sValue; into the Any class:
private String sValue;
and the followinf below SHORT, into the Type enum:
STRING,
But, like others says, the best way is to avoid these weak type (fourre-tout in french).
You can use
private LinkedHashMap<String, Object> keyVal;
to leave the second type argument as general as possible.
It allows you to store any object as a value, because every class extends Object.
This leads you to the problem that you don't know what type of things are inside your map - you only know that they are of type Object what means you don't know anything.
So to use these objects again you would have to cast them back to their original type what may cause a runtime exception: ClassCastException.
Generics are about defining data structures for different types with the same code, but if you want to use a generic class you have to parameterize it with its type arguments. This ensures that the type is known at runtime and is the great advantage of generics (avoid ClassCastException).
However, you can still specify a more general type that allows multiple types.
For example, if you define it the following way you can store any object that implements Serializable.
private LinkedHashMap<String, ? extends Serializable> keyVal;
As you can see, this allows you to restrict the permitted types to a common property (i.e., to be a subclass of a more general type). That way, you use the map's values as objects of the more general class, because it's everything you know (and want to know) about the objetcs.
It's better to have a look at:
Generics lesson on Oracle.com.
Care when should use wild cards (?) and you should use Generics.
Using Object in type of LinkedHashMap<String, Object> keyVal; is not recommended.
Like some people said, you could use Object for generic variable type, especially while using generic method or not knowing what data type user would come, like this simple one:
import java.util.Scanner;
public class GenericMethod {
public static void main(String[] args) {
System.out.println("Type something that's yours: ");
Scanner sc = new Scanner(System.in);
Object thing;
thing = sc.next();
isMine(thing);
}
// Generic Method
public static <T> void isMine(T x) {
System.out.println(x + " is mine.");
}
}
I am working on a Configuration Loader class so that I can change the parameters of my program via an external text file (config.txt) rather than having to recompile my code with every change I make.
It has been suggested that I use Java's Reflection to do this, but I'm a little confused as to how I might actually implement this.
I have been able to successfully extract the class name and the arguments for its constructor from my text file, but how do I go from this to an instantiated object?
here's what I have of my method so far:
public void loadObject(String classString, HashMap hm)
{
String className = props.getProperty(classString);
Class c = Class.forName(className);
}
classString is a string containing the name of the class, and hm is a hashmap where the class' constructor parameters map to their intended values.
I.e., for class Foo (int xPos, float yPos), "xPos" would map to a string of the intended int, and "yPos" maps to a string of the intended float. I want to be able to return, new Foo(hm.get"xPos".toInt, hm.get"yPost".toFloat), but I'm unsure how to dynamically use a constructor like that (the issue is, there are multiple possible classes -- perhaps it's a bar instead of a foo, for instance).
I know that its possible to do an if/else based off the classString, and simply call the proper constructor after identifying it that way, but I am looking to create a more extensible code that doesn't have to be rewritten every time I add a new class to the program.
All of the possible objects inherit from a single parent object.
You would use Class.getConstructor(Class<?>... parameterTypes) to get a reference to the constructor followed by Constructor.newInstance(Object... initargs).
However I would suggest taking a look at a dependency injection framework such as Spring or Guice as it sounds like what you are creating is a basic version of what they do.
Upon request for expanding this answer:
Class c = Class.forName(name);
Constructor ctor = c.getConstructor(Integer.class, Integer.class);
Integer param1 = hm.get("xPos") ...;
Integer param2 = hm.get("yPos") ...;
Object instanceOfTheClass = ctor.newInstance(param1, param2);
Of course instead of param1 and param2 you would create an array of arguments based upon what was in the input file (the same goes for the arguments to getConstructor()), etc.
Here's an example of doing it from program arguments:
import java.lang.reflect.Constructor;
import java.util.*;
public class InstantiateWithReflectionIncludingArgs {
public static void main(String[] args) throws Exception {
String className = args[0];
List<Object> argList = new ArrayList<Object>();
if (args.length > 1) {
argList.addAll(Arrays.asList(args).subList(1, args.length));
}
Class c = Class.forName(className);
List<Class<?>> argTypes = new ArrayList<Class<?>>();
for (Object arg : argList) {
argTypes.add(arg.getClass());
}
Constructor constructor = c.getConstructor(
argTypes.toArray(new Class<?>[argTypes.size()]));
Object o = constructor.newInstance(
argList.toArray(new Object[argList.size()]));
System.out.println("Created a " + o.getClass() + ": " + o);
}
}
Naturally, the argList can only ever have Strings in this case because they're pulled from a String[], but you could add args of any type. Note that constructor args are positional, not named, so the names in the map won't do you much good. They need to be in the proper order.
Try running it and passing "java.util.Date" as an argument.
Class<?> clazz = MyClass.class;
Constructor<?> ctor = clazz.getConstructor( /* Array of Classes the constructor takes */);
ctor.newInstance( /* arguments the constructor takes */ );