Add some reflection with generics experiments
This commit is contained in:
parent
5c7e822b53
commit
35cc5abdf0
@ -9,7 +9,7 @@
|
|||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>core</artifactId>
|
<artifactId>lang</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
|
2
pom.xml
2
pom.xml
@ -10,7 +10,7 @@
|
|||||||
<module>reflection</module>
|
<module>reflection</module>
|
||||||
<module>gui</module>
|
<module>gui</module>
|
||||||
<module>async</module>
|
<module>async</module>
|
||||||
<module>core</module>
|
<module>lang</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package fr.gasser.reflection.dynamicload;
|
package fr.gasser.reflection;
|
||||||
|
|
||||||
import javax.tools.JavaCompiler;
|
import javax.tools.JavaCompiler;
|
||||||
import javax.tools.ToolProvider;
|
import javax.tools.ToolProvider;
|
||||||
@ -18,7 +18,7 @@ public class DynamicLoadDemo {
|
|||||||
*/
|
*/
|
||||||
private static final String SOURCE =
|
private static final String SOURCE =
|
||||||
"package test;"
|
"package test;"
|
||||||
+ "import static fr.gasser.reflection.dynamicload.DynamicLoadDemo.*;"
|
+ "import static DynamicLoadDemo.*;"
|
||||||
+ "public class Test implements IDynamicLoad {"
|
+ "public class Test implements IDynamicLoad {"
|
||||||
+ " static { System.out.println(\"Test\"); }"
|
+ " static { System.out.println(\"Test\"); }"
|
||||||
+ " @Override public String doSomething() {"
|
+ " @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