Add some reflection with generics experiments
This commit is contained in:
parent
5c7e822b53
commit
35cc5abdf0
@ -9,7 +9,7 @@
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>core</artifactId>
|
||||
<artifactId>lang</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
2
pom.xml
2
pom.xml
@ -10,7 +10,7 @@
|
||||
<module>reflection</module>
|
||||
<module>gui</module>
|
||||
<module>async</module>
|
||||
<module>core</module>
|
||||
<module>lang</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
@ -1,4 +1,4 @@
|
||||
package fr.gasser.reflection.dynamicload;
|
||||
package fr.gasser.reflection;
|
||||
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.ToolProvider;
|
||||
@ -18,7 +18,7 @@ public class DynamicLoadDemo {
|
||||
*/
|
||||
private static final String SOURCE =
|
||||
"package test;"
|
||||
+ "import static fr.gasser.reflection.dynamicload.DynamicLoadDemo.*;"
|
||||
+ "import static DynamicLoadDemo.*;"
|
||||
+ "public class Test implements IDynamicLoad {"
|
||||
+ " static { System.out.println(\"Test\"); }"
|
||||
+ " @Override public String doSomething() {"
|
@ -0,0 +1,26 @@
|
||||
package fr.gasser.reflection;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
|
||||
/**
|
||||
* Shows how to access generic type parameter type at runtime.
|
||||
*/
|
||||
public abstract class GenericClass<T> {
|
||||
|
||||
private Class<T> clazz;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private GenericClass() {
|
||||
ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
|
||||
this.clazz = (Class<T>) genericSuperclass.getActualTypeArguments()[0];
|
||||
}
|
||||
|
||||
Class<T> getClazz() {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(new GenericClass<Long>() {}.getClazz());
|
||||
System.out.println(new GenericClass<Integer>() {}.getClazz());
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package fr.gasser.reflection;
|
||||
|
||||
public class GenericsTest<T> {
|
||||
|
||||
private TypeToken<T> typeToken;
|
||||
private T data;
|
||||
|
||||
|
||||
public GenericsTest(T data) {
|
||||
this.data = data;
|
||||
this.typeToken = new TypeToken<T>() {};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GenericsTest{" +
|
||||
"type=" + typeToken.type +
|
||||
", data=" + data +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
GenericsTest<Long> g = new GenericsTest<>(5L);
|
||||
System.out.println(g);
|
||||
}
|
||||
}
|
102
reflection/src/main/java/fr/gasser/reflection/TypeToken.java
Normal file
102
reflection/src/main/java/fr/gasser/reflection/TypeToken.java
Normal file
@ -0,0 +1,102 @@
|
||||
package fr.gasser.reflection;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* {@code TypeToken<List<String>> list = new TypeToken<List<String>>() {};}
|
||||
*/
|
||||
public class TypeToken<T> {
|
||||
private final Class<? super T> rawType;
|
||||
final Type type;
|
||||
private final int hashCode;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
TypeToken() {
|
||||
this.type = getSuperclassTypeParameter(getClass());
|
||||
this.rawType = (Class<? super T>) getRawType(type);
|
||||
this.hashCode = type.hashCode();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unsafe. Constructs a type literal manually.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private TypeToken(Type type) {
|
||||
this.type = checkNotNull(type);
|
||||
this.rawType = (Class<? super T>) getRawType(this.type);
|
||||
this.hashCode = this.type.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type from super class's type parameter
|
||||
*/
|
||||
private static Type getSuperclassTypeParameter(Class<?> subclass) {
|
||||
Type superclass = subclass.getGenericSuperclass();
|
||||
if (superclass instanceof Class) {
|
||||
throw new RuntimeException("Missing type parameter.");
|
||||
}
|
||||
ParameterizedType parameterized = (ParameterizedType) superclass;
|
||||
return parameterized.getActualTypeArguments()[0];
|
||||
}
|
||||
|
||||
public static Class<?> getRawType(Type type) {
|
||||
if (type instanceof Class<?>) {
|
||||
// type is a normal class.
|
||||
return (Class<?>) type;
|
||||
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
|
||||
// I'm not exactly sure why getRawType() returns Type instead of Class.
|
||||
// Neal isn't either but suspects some pathological case related
|
||||
// to nested classes exists.
|
||||
Type rawType = parameterizedType.getRawType();
|
||||
checkArgument(rawType instanceof Class);
|
||||
return (Class<?>) rawType;
|
||||
|
||||
} else if (type instanceof GenericArrayType) {
|
||||
Type componentType = ((GenericArrayType)type).getGenericComponentType();
|
||||
return Array.newInstance(getRawType(componentType), 0).getClass();
|
||||
|
||||
} else if (type instanceof TypeVariable) {
|
||||
// we could use the variable's bounds, but that won't work if there are multiple.
|
||||
// having a raw type that's more general than necessary is okay
|
||||
return Object.class;
|
||||
|
||||
} else if (type instanceof WildcardType) {
|
||||
return getRawType(((WildcardType) type).getUpperBounds()[0]);
|
||||
|
||||
} else {
|
||||
String className = type == null ? "null" : type.getClass().getName();
|
||||
throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
|
||||
+ "GenericArrayType, but <" + type + "> is of type " + className);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkArgument(boolean condition) {
|
||||
if (!condition) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T checkNotNull(T obj) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets type literal for the given {@code Class} instance.
|
||||
*/
|
||||
public static <T> TypeToken<T> get(Class<T> type) {
|
||||
return new TypeToken<T>(type);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
TypeToken<List<String>> token = new TypeToken<List<String>>() {};
|
||||
System.out.println(token);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user