0

Presume we have two different packages... one package can't be accessed but we like to know the value of a complex field called b.

public class A {
    private String  whatever;
    private B       b;

    private static class B {
         final ArrayList<Z> c   = new ArrayList<Z>();

         private void addItem(Z z) {
                this.c.add(z);
         }

         private Z getItem(int nr) {
                return this.c.get(nr);
          }
     }
}

public class Reflect extends A {
      public static void main(String[] args) throws NoSuchFieldException, SecurityException {
            Reflect ref = new Reflect();
            Class getA = ref.getClass().getSuperclass();
            Field getB = getDeclaredField("b");
            getB.setAccessible(true);
            Class bInst = getB.getClass();
            Method bMeth = bInst.getMethod("getItem", Integer.TYPE);
            Object zInst = bMeth.invoke(new Integer(123));
      }
}

How can I get the value if I don't get the complex type B from the package ? Still get java.lang.NoSuchMethodException: stackOver.A.getItem(int) even I set the field gstB accessible ....

Fendrix
  • 556
  • 2
  • 11
  • 34

3 Answers3

2

How can I get the value if I don't get the complex type B from the package ?

You can get it as an Object, and then use reflection to further discover the methods that it exposes.

Object bInst = ... // Get b through reflection
Class bClass = bInst.getClass();
Method[] bMeth = bClass.getMethod("getItem", Integer.TYPE);
Object zInst = bMeth.invoke(new Integer(123));
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • which means I have to loop through B to get the full object... thus if I have heaps of complex objects I have to run through all objects ... – Fendrix Jan 27 '13 at 17:11
  • @Fendrix This is correct: if you do not have access to a type at compile time, you need to loop through objects, potentially even recursing down the object hierarchy. – Sergey Kalinichenko Jan 27 '13 at 17:12
  • I thought I could somehow get the Object directly... thanks anyway ...:) – Fendrix Jan 27 '13 at 17:14
  • 1
    @Fendrix Ah, I thought you already found a link on how to get private variables through reflection. Here is [a link](http://stackoverflow.com/q/1196192/335858) to a very good answer. – Sergey Kalinichenko Jan 27 '13 at 17:42
2

The only thing you are missing is that getField only gives you public accessible fields.

 Field getB = getA.getDeclaredField("b");

will give you any field of that class.


A longer example

class Main {
    public static class A {
        private String whatever;
        private B b = new B();

        private static class B {
            final ArrayList<String> c = new ArrayList<String>();

            private void addItem(String z) {
                this.c.add(z);
            }

            private String getItem(int nr) {
                return this.c.get(nr);
            }
        }
    }

    public static class Reflect extends A {
        public static void main(String... ignored) throws Exception {
            Reflect ref = new Reflect();
            Class getA = ref.getClass().getSuperclass();
            Field getB = getA.getDeclaredField("b");
            getB.setAccessible(true);
            Object b = getB.get(ref);

            Method addItem = b.getClass().getDeclaredMethod("addItem", String.class);
            addItem.setAccessible(true);
            addItem.invoke(b, "Hello");

            Method getItem = b.getClass().getDeclaredMethod("getItem", int.class);
            getItem.setAccessible(true);
            String hi = (String) getItem.invoke(b, 0);
            System.out.println(hi);
        }
    }
}

prints

Hello
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • this is not working as B is private and therefor it s not visible... even with getB.setAccessible(true); I don't know how I can access a method of B... – Fendrix Jan 27 '13 at 19:21
  • 1
    To access an instance method of B you need to have an instance of B. Reflection doesn't change this fact in any way. – Peter Lawrey Jan 27 '13 at 19:30
1

Use commons beanutils library and use following method, it is much cleaner than doing it yourself

PropertyUtils.getNestedProperty(ref, "b.propertyOfClassB");

replace propertyOfClassB with actual property name.

Deniz
  • 1,575
  • 1
  • 16
  • 27