Class.forName等效于从String创建ParameterizedType的

时间:2016-09-08 22:25:15

标签: java generics

调用 if (sortCol == "OrderID" && sortDir == "ASC") { _res = l.OrderBy(x => x.OrderId).ThenBy(x => x.AnotherField); } if (sortCol == "OrderID" && sortDir == "DESC") { _res = l.OrderByDescending(x => x.OrderId).ThenByDescending(x => x.AnotherField); } if (sortCol == "AnotherField" && sortDir == "ASC") { _res = l.OrderBy(x => x.AnotherField).ThenBy(x => x.OrderId); } if (sortCol == "AnotherField" && sortDir == "DESC") { _res = l.OrderByDescending(x => x.AnotherField).ThenByDescending(x => x.OrderId); } _res.Skip((page - 1) * rowsPerPage) .Take(rowsPerPage) .Select(o => new Orders { 可以非常好地表示泛型类型:

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

可以通过以下特殊类型的测试:

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");
}

我找不到解决此问题的库或SO问题。

2 个答案:

答案 0 :(得分:3)

嗯......您可以使用例如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 lexer规则可能有点不准确。此解析器也仅适用于非基本类和参数化类型,但您当然也将其扩展为支持通配符类型。

答案 1 :(得分:1)

java.lang.reflect.Type.toString()的输出是特定于实现的 您所看到的行为是Gson ParameterizedTypeImpl的一部分 由于类型擦除,Java中的类在运行时没有类型参数 来自gson的Type不代表实际加载的Class

有关相关信息,请参阅Get Type of ParameterizedType from generic