Class.forName 相当于从字符串创建参数化类型
Class.forName equivalent for creating ParameterizedType's from String
调用 java.lang.reflect.Type.toString()
提供了非常好的通用类型表示:
@Test
public void typeToStringWithTypeToken() {
assertEquals("java.util.List<java.lang.String>", new TypeToken<List<String>>() {}.getType().toString());
}
我需要的是 Type.toString()
方法的逆向方法,即可以从给定字符串表示创建 Type
s 的方法:
public static Type parseTypeString(String typeString) throws ClassNotFoundException {
if (typeString.indexOf('<') == -1) {
return Class.forName(typeString);
}
// ??? how to implement rest
throw new IllegalStateException("not implemented");
}
可以通过以下特殊类型的测试:
@Test
public void justSimpleClassName() throws Exception {
assertEquals(Integer.class, parseTypeString("java.lang.Integer"));
}
@Test
public void listOfInteger() throws Exception {
assertEquals(new TypeToken<List<Integer>>() {}.getType(), parseTypeString("java.util.List<java.lang.Integer>"));
}
@Test
public void complexType() throws Exception {
assertEquals(new TypeToken<Map<List<Integer>, Set<String>>>() {}.getType(), parseTypeString("java.util.Map<java.util.List<java.lang.Integer>, java.util.Set<java.lang.String>>"));
}
我找不到解决此问题的库或 SO 问题。
java.lang.reflect.Type.toString()
的输出是特定于实现的。
您看到的行为是 Gson ParameterizedTypeImpl
的一部分
由于类型擦除,Java 中的 类 在运行时没有类型参数。
来自 gson 的 Type
并不代表实际加载的 Class
。
相关信息参见。
嗯...你可以自己做,例如 antlr4 使用下面的语法
type returns[ClassBuilder value]
: cls=CLASS { $value = ClassBuilder.parse($cls.text); }
| cls=CLASS { $value = ClassBuilder.parse($cls.text); }
LT head=type { $value.add($head.value); }
(COMMA tail=type { $value.add($tail.value); })* GT
;
GT : '>'
;
LT : '<'
;
COMMA
: ','
;
CLASS
: ('a'..'z'|'A'..'Z') ('a'..'z'|'A'..'Z'|'0'..'9'|'$'|'.'|'_')*
;
ClassBuilder
看起来像
public class ClassBuilder {
private final Class<?> clazz;
private final List<ClassBuilder> parameters = new ArrayList<>();
public ClassBuilder(final Class<?> clazz) {
this.clazz = clazz;
}
public static ClassBuilder parse(String clazz) {
try {
return new ClassBuilder(Class.forName(clazz));
} catch (ClassNotFoundException e) {
// do better handling here
throw new IllegalStateException(e);
}
}
public void add(ClassBuilder builder) {
parameters.add(builder);
}
public Type build() {
// class is not parametrized
if (parameters.isEmpty()) {
return clazz;
}
return ParameterizedTypeImpl.make(
clazz,
parameters.stream()
.map(ClassBuilder::build)
.toArray(Type[]::new),
null);
}
}
然后最后解析字符串
CharStream stream =
new ANTLRInputStream(
"java.util.Map<java.util.List<java.lang.Integer>, java.util.Set<java.lang.String>>"
);
TokenStream tokenStream =
new CommonTokenStream(new ParametrizedTypeLexer(stream));
ParametrizedTypeParser parser =
new ParametrizedTypeParser(tokenStream);
assertEquals(
new TypeToken<Map<List<Integer>, Set<String>>>() {}.getType(),
parser.type().value.build()
);
你可以看到工作示例here。
注意
CLASS
词法分析器规则可能有点不准确。此外,此解析器仅适用于非原始 类 和参数化类型,但您当然可以扩展它以支持通配符类型。
调用 java.lang.reflect.Type.toString()
提供了非常好的通用类型表示:
@Test
public void typeToStringWithTypeToken() {
assertEquals("java.util.List<java.lang.String>", new TypeToken<List<String>>() {}.getType().toString());
}
我需要的是 Type.toString()
方法的逆向方法,即可以从给定字符串表示创建 Type
s 的方法:
public static Type parseTypeString(String typeString) throws ClassNotFoundException {
if (typeString.indexOf('<') == -1) {
return Class.forName(typeString);
}
// ??? how to implement rest
throw new IllegalStateException("not implemented");
}
可以通过以下特殊类型的测试:
@Test
public void justSimpleClassName() throws Exception {
assertEquals(Integer.class, parseTypeString("java.lang.Integer"));
}
@Test
public void listOfInteger() throws Exception {
assertEquals(new TypeToken<List<Integer>>() {}.getType(), parseTypeString("java.util.List<java.lang.Integer>"));
}
@Test
public void complexType() throws Exception {
assertEquals(new TypeToken<Map<List<Integer>, Set<String>>>() {}.getType(), parseTypeString("java.util.Map<java.util.List<java.lang.Integer>, java.util.Set<java.lang.String>>"));
}
我找不到解决此问题的库或 SO 问题。
java.lang.reflect.Type.toString()
的输出是特定于实现的。
您看到的行为是 Gson ParameterizedTypeImpl
的一部分
由于类型擦除,Java 中的 类 在运行时没有类型参数。
来自 gson 的 Type
并不代表实际加载的 Class
。
相关信息参见
嗯...你可以自己做,例如 antlr4 使用下面的语法
type returns[ClassBuilder value]
: cls=CLASS { $value = ClassBuilder.parse($cls.text); }
| cls=CLASS { $value = ClassBuilder.parse($cls.text); }
LT head=type { $value.add($head.value); }
(COMMA tail=type { $value.add($tail.value); })* GT
;
GT : '>'
;
LT : '<'
;
COMMA
: ','
;
CLASS
: ('a'..'z'|'A'..'Z') ('a'..'z'|'A'..'Z'|'0'..'9'|'$'|'.'|'_')*
;
ClassBuilder
看起来像
public class ClassBuilder {
private final Class<?> clazz;
private final List<ClassBuilder> parameters = new ArrayList<>();
public ClassBuilder(final Class<?> clazz) {
this.clazz = clazz;
}
public static ClassBuilder parse(String clazz) {
try {
return new ClassBuilder(Class.forName(clazz));
} catch (ClassNotFoundException e) {
// do better handling here
throw new IllegalStateException(e);
}
}
public void add(ClassBuilder builder) {
parameters.add(builder);
}
public Type build() {
// class is not parametrized
if (parameters.isEmpty()) {
return clazz;
}
return ParameterizedTypeImpl.make(
clazz,
parameters.stream()
.map(ClassBuilder::build)
.toArray(Type[]::new),
null);
}
}
然后最后解析字符串
CharStream stream =
new ANTLRInputStream(
"java.util.Map<java.util.List<java.lang.Integer>, java.util.Set<java.lang.String>>"
);
TokenStream tokenStream =
new CommonTokenStream(new ParametrizedTypeLexer(stream));
ParametrizedTypeParser parser =
new ParametrizedTypeParser(tokenStream);
assertEquals(
new TypeToken<Map<List<Integer>, Set<String>>>() {}.getType(),
parser.type().value.build()
);
你可以看到工作示例here。
注意
CLASS
词法分析器规则可能有点不准确。此外,此解析器仅适用于非原始 类 和参数化类型,但您当然可以扩展它以支持通配符类型。