From e240a2d040ccd232900657a6a60927706739ea2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Bl=C3=A4sing?= Date: Sat, 18 Nov 2017 15:53:27 +0100 Subject: [PATCH] Replace addSuppressed with a reflection based variant addSuppressed was added to Throwable in JDK7, to be compatible with Java 6 it can't be called directly. To replace the functionality reflection is used. A helper method "addSuppressedRelfected" was introduced into the only class, that currently uses suppressed exceptions (Win32Exception). --- CHANGES.md | 1 + .../sun/jna/platform/win32/Advapi32Util.java | 4 +-- .../sun/jna/platform/win32/Crypt32Util.java | 4 +-- .../com/sun/jna/platform/win32/GDI32Util.java | 6 ++-- .../sun/jna/platform/win32/Kernel32Util.java | 12 +++---- .../jna/platform/win32/Win32Exception.java | 31 +++++++++++++++++++ .../sun/jna/platform/win32/WininetUtil.java | 2 +- .../sun/jna/platform/win32/WinspoolUtil.java | 2 +- .../sun/jna/platform/win32/Kernel32Test.java | 4 +-- .../com/sun/jna/platform/win32/PsapiTest.java | 6 ++-- .../platform/win32/Win32ExceptionTest.java | 20 ++++++++++++ 11 files changed, 72 insertions(+), 20 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 10394ad1a7..6016125704 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,6 +15,7 @@ Bug Fixes * [#863](https://github.com/java-native-access/jna/pull/863): Fix ARM softfloat/hardfloat detection by modifying armSoftFloat condition in ELFAnalyser. Before this fix a softfloat binary could be misdetected as hardfloat. - [@kunkun26](https://github.com/kunkun26). * [#867](https://github.com/java-native-access/jna/issues/867): Fix memory leak in `COMLateBindingObject#getStringProperty` - [@matthiasblaesing](https://github.com/matthiasblaesing). * [#871](https://github.com/java-native-access/jna/issues/871): Fix mapping of libc function `gethostname`, `sethostname`, `getdomainname` and `setdomainname` and bind `com.sun.jna.platform.win32.Winsock2.gethostname(byte[], int)` - [@matthiasblaesing](https://github.com/matthiasblaesing). +* [#876](https://github.com/java-native-access/jna/pull/876): Restore java 6 compatibility - [@matthiasblaesing](https://github.com/matthiasblaesing). Breaking Changes ---------------- diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java index a405890d88..46407578ab 100755 --- a/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java @@ -544,7 +544,7 @@ public static Account[] getCurrentUserGroups() { if (err == null) { err = e; } else { - err.addSuppressed(e); + err.addSuppressedReflected(e); } } } @@ -2443,7 +2443,7 @@ public static boolean accessCheck(File file, AccessCheckPermission permissionToC if (err == null) { err = e; } else { - err.addSuppressed(e); + err.addSuppressedReflected(e); } } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Crypt32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/Crypt32Util.java index ebf20a4c28..0c73a0d05b 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Crypt32Util.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Crypt32Util.java @@ -150,7 +150,7 @@ public static byte[] cryptUnprotectData(byte[] data, byte[] entropy, int flags, if (err == null) { err = e; } else { - err.addSuppressed(e); + err.addSuppressedReflected(e); } } } @@ -162,7 +162,7 @@ public static byte[] cryptUnprotectData(byte[] data, byte[] entropy, int flags, if (err == null) { err = e; } else { - err.addSuppressed(e); + err.addSuppressedReflected(e); } } } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/GDI32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/GDI32Util.java index 3a807626ed..5bf755217f 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/GDI32Util.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/GDI32Util.java @@ -153,7 +153,7 @@ public static BufferedImage getScreenshot(HWND target) { if (result == null || WinGDI.HGDI_ERROR.equals(result)) { Win32Exception ex = new Win32Exception(Native.getLastError()); if (we != null) { - ex.addSuppressed(we); + ex.addSuppressedReflected(we); } we = ex; } @@ -163,7 +163,7 @@ public static BufferedImage getScreenshot(HWND target) { if (!GDI32.INSTANCE.DeleteObject(hBitmap)) { Win32Exception ex = new Win32Exception(Native.getLastError()); if (we != null) { - ex.addSuppressed(we); + ex.addSuppressedReflected(we); } we = ex; } @@ -174,7 +174,7 @@ public static BufferedImage getScreenshot(HWND target) { if (!GDI32.INSTANCE.DeleteDC(hdcTargetMem)) { Win32Exception ex = new Win32Exception(Native.getLastError()); if (we != null) { - ex.addSuppressed(we); + ex.addSuppressedReflected(we); } we = ex; } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java index 9a7892b884..a06fcb1d8b 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java @@ -110,7 +110,7 @@ public static void closeHandleRefs(HANDLEByReference... refs) { if (err == null) { err = e; } else { - err.addSuppressed(e); + err.addSuppressedReflected(e); } } } @@ -148,7 +148,7 @@ public static void closeHandles(HANDLE... handles) { if (err == null) { err = e; } else { - err.addSuppressed(e); + err.addSuppressedReflected(e); } } } @@ -341,7 +341,7 @@ public static int getFileType(String fileName) throws FileNotFoundException { if (err == null) { err = e; } else { - err.addSuppressed(e); + err.addSuppressedReflected(e); } } @@ -905,7 +905,7 @@ public static byte[] getResource(String path, String type, String name) { if (!Kernel32.INSTANCE.FreeLibrary(target)) { Win32Exception we = new Win32Exception(Kernel32.INSTANCE.GetLastError()); if (err != null) { - we.addSuppressed(err); + we.addSuppressedReflected(err); } throw we; } @@ -1013,7 +1013,7 @@ public boolean invoke(HMODULE module, Pointer type, Pointer name, Pointer lParam if (!Kernel32.INSTANCE.FreeLibrary(target)) { Win32Exception we = new Win32Exception(Kernel32.INSTANCE.GetLastError()); if (err != null) { - we.addSuppressed(err); + we.addSuppressedReflected(err); } throw we; } @@ -1075,7 +1075,7 @@ public static List getModules(int processID) { if (we == null) { we = e; } else { - we.addSuppressed(e); + we.addSuppressedReflected(e); } } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Win32Exception.java b/contrib/platform/src/com/sun/jna/platform/win32/Win32Exception.java index 934ab59ff0..dfc6f5d99f 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Win32Exception.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Win32Exception.java @@ -25,6 +25,10 @@ import com.sun.jna.LastErrorException; import com.sun.jna.platform.win32.WinNT.HRESULT; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Win32 exception. @@ -69,4 +73,31 @@ protected Win32Exception(int code, HRESULT hr, String msg) { super(code, msg); _hr = hr; } + + private static Method addSuppressedMethod = null; + static { + try { + addSuppressedMethod = Throwable.class.getMethod("addSuppressed", Throwable.class); + } catch (NoSuchMethodException ex) { + // This is the case for JDK < 7 + } catch (SecurityException ex) { + Logger.getLogger(Win32Exception.class.getName()).log(Level.SEVERE, "Failed to initialize 'addSuppressed' method", ex); + } + } + + void addSuppressedReflected(Throwable exception) { + if(addSuppressedMethod == null) { + // Make this a NOOP on an unsupported JDK + return; + } + try { + addSuppressedMethod.invoke(this, exception); + } catch (IllegalAccessException ex) { + throw new RuntimeException("Failed to call addSuppressedMethod", ex); + } catch (IllegalArgumentException ex) { + throw new RuntimeException("Failed to call addSuppressedMethod", ex); + } catch (InvocationTargetException ex) { + throw new RuntimeException("Failed to call addSuppressedMethod", ex); + } + } } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WininetUtil.java b/contrib/platform/src/com/sun/jna/platform/win32/WininetUtil.java index 4c64fa8e58..7da5969d10 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/WininetUtil.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/WininetUtil.java @@ -123,7 +123,7 @@ public static Map getCache() { if (!Wininet.INSTANCE.FindCloseUrlCache(cacheHandle)) { if (we != null) { Win32Exception e = new Win32Exception(Native.getLastError()); - e.addSuppressed(we); + e.addSuppressedReflected(we); we = e; } } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinspoolUtil.java b/contrib/platform/src/com/sun/jna/platform/win32/WinspoolUtil.java index ac6e5ce811..e5a0bdc7f1 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/WinspoolUtil.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/WinspoolUtil.java @@ -118,7 +118,7 @@ public static PRINTER_INFO_2 getPrinterInfo2(String printerName) { if (!Winspool.INSTANCE.ClosePrinter(pHandle.getValue())) { Win32Exception ex = new Win32Exception(Kernel32.INSTANCE.GetLastError()); if (we != null) { - ex.addSuppressed(we); + ex.addSuppressedReflected(we); } } } diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java index 7870c9e263..6c35edcb53 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java @@ -1552,7 +1552,7 @@ public void testModule32FirstW() { if (we == null) { we = e; } else { - we.addSuppressed(e); + we.addSuppressedReflected(e); } } @@ -1589,7 +1589,7 @@ public void testModule32NextW() { if (we == null) { we = e; } else { - we.addSuppressed(e); + we.addSuppressedReflected(e); } } diff --git a/contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java b/contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java index 635e1f4749..22e1d0cf39 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java @@ -135,7 +135,7 @@ public void testEnumProcessModules() { if (we == null) { we = e; } else { - we.addSuppressed(e); + we.addSuppressedReflected(e); } } if (we != null) { @@ -186,7 +186,7 @@ public void testGetModuleInformation() { if (we == null) { we = e; } else { - we.addSuppressed(e); + we.addSuppressedReflected(e); } } if (we != null) { @@ -218,7 +218,7 @@ public void testGetProcessImageFileName() { if (we == null) { we = e; } else { - we.addSuppressed(e); + we.addSuppressedReflected(e); } } if (we != null) { diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Win32ExceptionTest.java b/contrib/platform/test/com/sun/jna/platform/win32/Win32ExceptionTest.java index 863f803dae..d703b18372 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Win32ExceptionTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Win32ExceptionTest.java @@ -15,6 +15,7 @@ import com.sun.jna.LastErrorException; import junit.framework.TestCase; +import org.junit.Assume; /** * @author dblock[at]dblock[dot]org @@ -50,8 +51,27 @@ public void testFormatMessageFromHR() { } } + public void testAddSuppressed() { + Assume.assumeTrue(isMethodPresent(Win32Exception.class, "addSuppressed", Throwable.class)); + + Win32Exception demoException = new Win32Exception(WinError.E_FAIL); + demoException.addSuppressed(new RuntimeException("Demo")); + + assertEquals(1, demoException.getSuppressed().length); + assertEquals("Demo", demoException.getSuppressed()[0].getMessage()); + } + private void assertLastErrorValue(LastErrorException e, int code, String msg) { assertEquals("Mismatched error code", code, e.getErrorCode()); assertEquals("Mismatched error message", msg, e.getMessage()); } + + private boolean isMethodPresent(Class baseClass, String methodName, Class... parameters) throws SecurityException { + try { + baseClass.getMethod(methodName, parameters); + return true; + } catch (NoSuchMethodException ex) { + return false; + } + } }