简体   繁体   English

Java反射,有没有一种简单的方法可以通过“字段路径”获取字段值?

[英]Java reflection, is there an easy way to get field value by 'field path'?

I have a pretty complex class, like,我有一个非常复杂的课程,比如,

classA {
  public classB b;
}

classB {
  public classC c;
}

classC {
  public List<classD> d;
}
...

Now, given an instance of classA, and a field path like 'bcdefg', is there an easy way to get the target field value via reflection?现在,给定一个 classA 实例和一个像“bcdefg”这样的字段路径,是否有一种简单的方法可以通过反射获取目标字段值? Any existing library or something?任何现有的图书馆或其他东西?

Many thanks.非常感谢。

There is not an "easy" way (and there is definitely not an easy way to navigate into a List of classD elements by using a field path like bcdef , as (at some point) you would need to specify which element in the list you are looking at.没有一种“简单”的方法(并且绝对没有一种简单的方法可以使用bcdef之类的字段路径导航到classD元素列表,因为(在某些时候)您需要指定列表中的哪个元素正在看。

Nevertheless, you can use reflection to navigate down a queue of fields, like so:不过,您可以使用反射向下导航字段队列,如下所示:

public static void main(final String args[]) throws Exception
{
    // Initialize all variables
    final ClassA a = new ClassA();
    a.b = new ClassB();
    a.b.c = new ClassC();
    a.b.c.d = new ArrayList<>();
    a.b.c.d.add(new ClassD("Success!"));

    final String fieldPath = "b.c.d";

    final Queue<String> fieldPaths = buildFieldPaths(fieldPath);

    System.out.println(((List<ClassD>) discover(a, fieldPaths)).get(0).s);
}

public static Object discover(final Object o, final Queue<String> fieldPaths) throws Exception
{
    // End of the queue, return the object found most recently
    if (null == fieldPaths.peek())
    {
        return o;
    }

    final String nextFieldPath = fieldPaths.remove();

    final Field f[] = o.getClass().getDeclaredFields();
    for (final Field next : f)
    {
        final String nextName = next.getName();
        System.out.println("Checking " + o.getClass().getName() + ": " + nextName);
        if (nextName.equals(nextFieldPath))
        {
            System.out.println("Found: " + nextName);
            return discover(next.get(o), fieldPaths);
        }
    }

    throw new RuntimeException("Field not found: " + nextFieldPath);
}

public static Queue<String> buildFieldPaths(final String s)
{
    final Queue<String> fieldPaths = new PriorityQueue<>();
    for (final String next : s.split("\\."))
    {
        fieldPaths.add(next);
    }
    return fieldPaths;
}

protected static class ClassA
{
    public ClassB b;
}

protected static class ClassB
{
    public ClassC c;
}

protected static class ClassC
{
    public List<ClassD> d;
}

protected static class ClassD
{
    public String s;

    public ClassD(final String s)
    {
        this.s = s;
    }
}

Running this program should output运行这个程序应该输出

Checking ClassA: b
Found: b
Checking ClassB: c
Found: c
Checking ClassC: d
Found: d
Success!

Take note: the final Success!注意:最后Success! string is being retrieved from inside the List<ClassD> using some extra code, and is not actually part the field path recursion of discovery.字符串是使用一些额外的代码从List<ClassD>内部检索的,实际上并不是发现的字段路径递归的一部分。

Thank you all for the post.谢谢大家的帖子。

Thanks Tim, commons-beanutils helps a lot when handling pojo classes, it works pretty fine for List/Map field.感谢 Tim,commons-beanutils 在处理 pojo 类时有很大帮助,它对于 List/Map 字段工作得非常好。

This is almost what I need, except a few edge cases, for example, when giving a List with no index provided.这几乎是我需要的,除了一些边缘情况,例如,当给出一个没有提供索引的 List 时。

I think the way to go is to write my own tool with the help of commons-beanutils.我认为要走的路是在 commons-beanutils 的帮助下编写我自己的工具。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM