Java:リフレクションで得たjava.lang.reflect.Typeから型文字列を復帰
何の因果か、こんなことをやる必要に迫られた。
以下を実行すると、
package test;
import java.util.*;
public class Foo {
static class Bar {
}
public List<String>foo(ArrayList<? extends Bar> a, Set<String>b, Bar[][]array, int[]test) {
return null;
}
public void foo(Map<String, ? extends Class<?>>map, Class<Bar>[]aaa) {
}
public static void main(String[]args) throws Exception {
TypeString typeString = new TypeString();
Arrays.stream(Foo.class.getDeclaredMethods()).forEach(m-> {
System.out.println("" + typeString.constructMethod(m));
});
}
}
以下が出力される。
void main(String[] args)
void foo(java.util.Map<String, ? extends Class<?>> map, Class<test.Foo.Bar>[] aaa)
java.util.List foo(java.util.ArrayList<? extends test.Foo.Bar> a, java.util.Set<String> b, test.Foo.Bar[][] array, int[] test)
void lambda$0(test.TypeString arg0, java.lang.reflect.Method arg1)
メソッドの定義が必要だったので、他の部分は省略している。
※lambda$0というのは勝手にできているメソッドのようだ。
ここで使用しているTypeStringは以下である。
package test;
import java.lang.reflect.*;
import java.util.*;
import java.util.stream.*;
/**
* リフレクションで取得したJavaのメソッドの返り値や引数の型オブジェクトから
* 元の定義文字列を取得する。
*
* @author ysugimura
*/
public class TypeString {
/** 省略するパッケージ */
Set<String>omitPackages = new HashSet<String>() {{
add("java.lang");
}};
/** メソッドの定義を作成する */
String constructMethod(Method method) {
return
constructType(method.getReturnType()) + " " +
method.getName() + "(" +
Arrays.stream(method.getParameters()).map(p->
constructType(p.getParameterizedType()) + " " + p.getName()
).collect(Collectors.joining(", ")) +
")";
}
/** 型の定義を作成する */
String constructType(Type type) {
// TypeがClass
if (type instanceof Class) {
Class<?>clazz = (Class<?>)type;
if (clazz.isArray()) return arrayType(clazz);
return simpleClass((Class<?>)type);
}
// WildcardType
if (type instanceof WildcardType) {
return wildcardType((WildcardType)type);
}
// GenericArrayType
if (type instanceof GenericArrayType) {
return genericArrayType((GenericArrayType)type);
}
// ParameterizedType
return parameterizedType((ParameterizedType)type);
}
/**
* パラメータ付型
* @param type
* @return
*/
String parameterizedType(ParameterizedType type) {
StringBuilder s = new StringBuilder();
Type ownerType = type.getOwnerType();
if (ownerType != null) s.append(constructType(ownerType) + ".");
Type rawType = type.getRawType();
s.append(
constructType(rawType) +
"<" +
Arrays.stream(type.getActualTypeArguments())
.map(a->constructType(a)).collect(Collectors.joining(", ")) +
">"
);
return s.toString();
}
/**
* ワイルドカード型
* @param type
* @return
*/
String wildcardType(WildcardType type) {
StringBuilder s = new StringBuilder();
Type[]upperBounds = type.getUpperBounds();
Type[]lowerBounds = type.getLowerBounds();
// extends
if (upperBounds.length > 0) {
String extendsObjects =
Arrays.stream(upperBounds).map(b->constructType(b)).collect(Collectors.joining(","));
if (extendsObjects.equals("Object")) {
// "? extends Object" --> "?"
s.append("?");
} else {
s.append("? extends " + extendsObjects);
}
}
// super
if (lowerBounds.length > 0) {
s.append("? super " +
Arrays.stream(lowerBounds).map(b->constructType(b)).collect(Collectors.joining(",")));
}
return s.toString();
}
/**
* 要素がジェネリックタイプの配列
* @param type
* @return
*/
String genericArrayType(GenericArrayType type) {
return constructType(type.getGenericComponentType()) + "[]";
}
/**
* 要素が単純クラスの配列
* @param clazz
* @return
*/
String arrayType(Class<?>clazz) {
return constructType(clazz.getComponentType()) + "[]";
}
/**
* 単純なクラスbの場合
* パッケージ省略対象であれば、省略する。
* '$'は'.'に変更する。
* @param clazz
* @return
*/
String simpleClass(Class<?>clazz) {
String className = clazz.getName();
int lastDot = className.lastIndexOf('.');
if (lastDot < 0) return className;
String pkg = className.substring(0, lastDot);
className = className.replace('$', '.');
if (omitPackages.contains(pkg)) return className.substring(lastDot + 1);
return className;
}
}
ディスカッション
コメント一覧
まだ、コメントがありません