vendredi 25 janvier 2019

Lookup for private classes

I'm in the process of migrating from Java 7 (yipes) to Java 11 for a web application but am having difficulties in migrating some code due to illegal reflective access warnings (it doesn't prevent things from working, but should they ever actually follow through with their threats to enforce in a future JDK update, I want my code to be ready).

I'm attempting to call registry methods from the WindowsPreferences class (which is a private class in the java.util.prefs package shipped with the 11.0.2 JDK).

I previously had code that would initialize methods in my utility class' constructor like this:

private static Preferences userRoot = Preferences.userRoot();
private static Class<? extends Preferences> userClass = userRoot.getClass();    
private static Method regOpenKey = null;

...

static {
  try {
    regOpenKey = userClass.getDeclaredMethod("WindowsRegOpenKey", new Class[] {int.class, byte[].class, int.class});
    regOpenKey.setAccessible(true);
...
  }
}

I could then invoke them later on like so:

int[] handles = (int[]) regOpenKey.invoke(preferences, new Object[] {
            new Integer(hive), toCstr(keyName), new Integer(KEY_READ | wow64) });

This worked very well for Java 7, but in Java 11 I've had to retool some things.

What I have now is:

private static Preferences userRoot = Preferences.userRoot();
private static Class<? extends Preferences> userClass = userRoot.getClass();    
private static Method regOpenKey = null;

...

static {
  try {
    userRegOpenKey = userClass.getDeclaredMethod("openKey", byte[].class, int.class, int.class);
    userRegOpenKey.setAccessible(true);
...
  }
}

and

long handle = (long) userRegOpenKey.invoke(preferences, toCstr(keyName), hive, wow64));

This works well enough and I can read from the registry just fine, bute whenever I call .setAccessible(true) on a Method from the private class, I get

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.admin.utils.RegistryManager (file://WebRoot/WEB-INF/classes/) to method java.util.prefs.WindowsPreferences.closeKey(long)
WARNING: Please consider reporting this to the maintainers of com.admin.utils.RegistryManager
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

I then tried using Lookup to get MethodHandles using unreflect but the issue persists, as the class is private (this is for a different method, but it's the same basic principle):

Lookup lookup = MethodHandles.lookup();

Method systemRegCloseKeyDeclaredMethod = systemClass.getDeclaredMethod("closeKey", long.class);
systemRegCloseKeyDeclaredMethod.setAccessible(true);

systemRegCloseKey = lookup.unreflect(systemRegCloseKeyDeclaredMethod);

I still get a warning on systemRegCloseKeyDeclaredMethod.setAccessible(true); but if I comment that out then I get a runtime exception:

java.lang.IllegalAccessException: class is not public: java.util.prefs.WindowsPreferences.closeKey[Ljava.lang.Object;@4c6e276e/invokeVirtual, from com.admin.utils.RegistryManager (unnamed module @6ee52dcd)

What should I be doing to properly reflect on the private class (or is this actually something that I shouldn't be doing)?





Aucun commentaire:

Enregistrer un commentaire