I’m not quite sure how to go about reflecting a class that only has package-level access. I know how to reflect any class that has public access, but I cannot figure out how to reflect the following example:
public class Main { public static void main(String[] args) { test t = new test(); Constructor<one.oneimpl> con = one.oneimpl.class.getDeclaredConstructor(test.class); oneimpl o = con.newInstance(t); o.doIt(); } }
======================
package one; // implementation class for mimicking android api class oneimpl extends one { Test mTest; private oneimpl(test t){mTest = t;} public void doIt(){System.out.println("Do It!");} public void dontDoit(){System.out.println("Don't Do It!");} }
======================
package one; // abstract class for mimicking android api abstract class one { public void doIt(); public void dontDoIt(); }
======================
package one; // empty class for mimicking android api public class test {}
As you can see, the class one
only has package-level access. This makes reflecting the class difficult for me. I continue to get compiler errors that states:
Main.java:4: error: oneimpl is not public in one; cannot be accessed from outside package oneimpl o = con.newInstance(t);
I’ve reviewed a few posts, to solve this on my own, but even after reading most of the “similar questions”, reading the AccessibilityObject
api, and reading generic reflection procedures it’s still unclear to me how to achieve this.
Ultimately what I am trying to do is to reflect particular portions of the API to build objects so that soot/spark can build a proper call graph. I’m not actually working inside the android API.
Advertisement
Answer
You’ll need to use reflection at every step in order to do what you’re trying to do.
First, since you can’t directly reference a package-scoped class in package one
from outside that package you’ll need to load that class dynamically (also note the use of ?
instead of directly using oneimpl
):
Class<?> oneImplClass = Class.forName("one.oneimpl");
Then you can get the constructor and the doIt
method (make sure you set both of these as accessible, otherwise you’ll get runtime errors):
Constructor<?> constructor = oneImplClass.getDeclaredConstructor(test.class); constructor.setAccessible(true); Method doIt = oneImplClass.getDeclaredMethod("doIt"); doIt.setAccessible (true);
Next, instantiate the class. You’ll have to cast it to Object
since you can’t reference the class directly):
Object oneImpl = (Object) constructor.newInstance();
Lastly you can invoke the doIt
method:
doIt.invoke(oneImpl);
As one last note: you should follow Java naming conventions when naming your classes: oneimpl
should be OneImpl
and test
should be Test
. Otherwise things like one.oneimpl
end up looking like a package name rather than a fully qualified class name.