Java 解析泛型类型描述

Java 解析泛型类型描述,java,regex,parsing,Java,Regex,Parsing,我正在尝试编写一个实用程序方法,它允许我获取字段的定义,包括所有泛型参数。为此,我通过检索字段的泛型类型,并解析具有以下语法的类型名称(in): generictype=classname['] classname=package'.'(字母|'.'''{字母|数字|'.'} package=(packagepart{.'packagepart})| packagepart=(字母|'124;'{字母|数字|'124;'} 我第一次尝试解析它是使用正则表达式 (?。这个正则表达式正是我所需要的

我正在尝试编写一个实用程序方法,它允许我获取字段的定义,包括所有泛型参数。为此,我通过检索字段的泛型类型,并解析具有以下语法的类型名称(in):

generictype=classname[']
classname=package'.'(字母|'.'''{字母|数字|'.'}
package=(packagepart{.'packagepart})|
packagepart=(字母|'124;'{字母|数字|'124;'}
我第一次尝试解析它是使用正则表达式

(?。这个正则表达式正是我所需要的。现在,Java正则表达式不支持
\g
构造,所以如果我想支持参数深度未知的泛型类型,就不能使用这种方法

我还可以使用其他方法吗?如果可以,我如何才能实现我的目标


编辑:我之所以要实现这一点,是因为我有一个配置,并且希望将其内容传输到对象的各个字段中。如果您想这样调用它,则需要某种反序列化。现在,配置只支持基元类型,
java.lang.String
java.util.List
de>java.util.Map
java.util.Map.Entry
。要检索这些类的值,客户端必须提供一个类作为参数,用于反序列化保存在配置中的字符串。因此,我必须确定类的字段使用了哪些泛型参数,以及
class
e在一个问题上,我找到了一个解决方案,这个问题正试图做完全相同的事情,唯一的区别是它是在C#中。由于这个区别,我不得不稍微重写代码,最终得到了这个解决方案:

public类ClassUtil{
// https://stackoverflow.com/questions/20532691/how-to-parse-c-sharp-generic-type-names?rq=1
静态列表splitByComma(字符串类型ArgumentList){
列表字符串=新的LinkedList();
StringBuilder sb=新的StringBuilder();
智力水平=0;
对于(int i=0;i如果(!description.contains(“),则可以执行以下操作:

Type type = Field.getGenericType();
if (type instanceof ParameterizedType) {
    ParameterizedType pt = (ParameterizedType) type;
    Class<?> genericType  = (Class<?>) pt.getActualTypeArguments()[0];
}
Type Type=Field.getGenericType();
if(类型instanceof ParameterizedType){
ParameteredType pt=(ParameteredType)类型;
类genericType=(类)pt.getActualTypeArguments()[0];
}

如果这还不够,只需使用google reflections库:

如果您真的需要解析(高赌注的方法看起来更优雅,但解析是问题所要求的),我会使用递归下降解析,类似这样:

class GenericType {
  String baseName;
  List<GenericType> params;

  GenericType(String baseName, List<GenericType> params) {
    this.baseName = baseName;
    this.params = params;
  }

  static GenericType parse(String s) {
    StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(s));
    tokenizer.wordChars('.', '.');  // Make dots part of the name
    try {
      tokenizer.nextToken();  // Skip "BOF" token
      return parse(tokenizer);
    } catch (IOException e) {
      throw new RuntimeException();
    }
  }

  static GenericType parse(StreamTokenizer tokenizer) throws IOException {
    String baseName = tokenizer.sval;
    tokenizer.nextToken();
    List<GenericType> params = new ArrayList<>();
    if (tokenizer.ttype == '<') {
      do {
        tokenizer.nextToken();  // Skip '<' or ','
        params.add(parse(tokenizer));
      } while (tokenizer.ttype == ',');
      tokenizer.nextToken();  // skip '>'
    }
    return new GenericType(baseName, params);
  }
}
类GenericType{
字符串基名称;
列出参数;
GenericType(字符串baseName,列表参数){
this.baseName=baseName;
this.params=params;
}
静态GenericType解析(字符串s){
StreamTokenizer tokenizer=新的StreamTokenizer(新的StringReader);
tokenizer.wordChars('.','.');//使点成为名称的一部分
试一试{
tokenizer.nextToken();//跳过“BOF”标记
返回解析(标记器);
}捕获(IOE异常){
抛出新的RuntimeException();
}
}
静态GenericType解析(StreamTokenizer标记器)引发IOException{
字符串baseName=tokenizer.sval;
tokenizer.nextToken();
List params=new ArrayList();

如果(tokenizer.ttype==“Java的编译器在解析Java语法方面已经做得相当好了——为什么要重新发明轮子?@Boristeider如果你也能告诉我如何让Java编译器给我泛型类型的参数,那么使用它就没有问题了。我会的。有一个完整的API来检查Jav生成的AST一个编译器…你想做什么真的让人困惑:你想在运行时解析它吗?为什么你要用regexp而不是反射api来解析它?@IraBaxter泛型存在于字节码中,只是JVM没有使用。事实上你可以。是的,Java泛型被类型擦除,但声明本身不是rei您发布的代码无效,因为
ParameterizedType.getActualTypeArguments()返回的值
不是
Class
类型,因此会导致
ClassCastException
。不过,我没有尝试Guava。如果在ParameterizedType中嵌入ParameterizedType,则必须继续递归,反复检查实例,直到得到一个类。我不知道如何
解析(字符串)
应该可以工作。它创建了一个新的
StreamTokenizer
,但从未向其分配任何内容。我想您应该想编写
StreamTokenizer tokenizer=new StreamTokenizer(new StringReader));
?@mezzodrinker谢谢,修复了(包括其他一些打字错误)。请注意,这实际上以简洁的方式回答了原始问题——我同意对于您的实际用例,接受的答案是一个更好的解决方案,但对于寻求类似问题解决方案的人来说,这可能是,也可能不是。我只是在等待一些(或多或少)明显的问题得到解决:)