2

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)?

greg-449
  • 109,219
  • 232
  • 102
  • 145
adamdc78
  • 1,153
  • 8
  • 18
  • 3
    The clean way would be to stop using `java.util.prefs` and switch to a library that provides Windows registry access instead. – Robert Jan 26 '19 at 13:25
  • 1
    Since Java 9, you shouldn't use deep reflection on Java internal classes because in the future it can stop working. You should find a way how to access the Windows registry without reflective hacks. – ZhekaKozlov Jan 26 '19 at 14:46
  • 2
    That last statement (“this [is] actually something that I shouldn't be doing”). Precisely. – Holger Jan 28 '19 at 15:40

0 Answers0