From a9a2c4393ff00059808585e2c814b2313a1ab029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Bl=C3=A4sing?= Date: Sat, 16 Dec 2017 22:42:57 +0100 Subject: [PATCH] Tighten the generic bounds for Structure#newInstance The signature was: `Structure newInstance(Class type)` requiring an explicit cast after the call. The the new signature introduces a type parameter `T` with an upper bound of `com.sun.jna.Structure`: T newInstance(Class type)` The companion, that takes an init pointer was also updated: T newInstance(Class type, Pointer init) Closes: #889 --- CHANGES.md | 2 ++ .../com/sun/jna/platform/win32/Winevt.java | 14 ++++---- src/com/sun/jna/CallbackReference.java | 6 ++-- src/com/sun/jna/Function.java | 10 +++--- src/com/sun/jna/Native.java | 4 +-- src/com/sun/jna/Pointer.java | 8 ++--- src/com/sun/jna/Structure.java | 32 +++++++++---------- test/com/sun/jna/StructureTest.java | 2 +- 8 files changed, 40 insertions(+), 38 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a8d0f9858c..7be58366a2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,8 @@ Release 5.0.0 (Next release) Features -------- +* [#822](https://github.com/java-native-access/jna/issues/822): `Native#loadLibrary` requires that the interface class passed in is an instance of Library. The runtime check can be enhanced by using a constraint generic. This breaks binary compatibility (see notes below) - [@d-noll](https://github.com/d-noll). +* [#889](https://github.com/java-native-access/jna/issues/889): The `Structure#newInstance` receive the target type as a parameter. This adds a limited generic type, so that the return type ist the target type and not a generic structure, removing the necessity to do an explizit cast - [@matthiasblaesing](https://github.com/matthiasblaesing). Bug Fixes --------- diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Winevt.java b/contrib/platform/src/com/sun/jna/platform/win32/Winevt.java index 9ce7d5cebc..71a46e0ec2 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Winevt.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Winevt.java @@ -488,7 +488,7 @@ public Object getValue() { return isArray() ? field1.getPointer().getPointer(0).getWideStringArray(0, Count) : field1.getPointer().getPointer(0).getWideString(0); case EvtVarTypeFileTime: if (isArray()) { - WinBase.FILETIME resultFirst = (WinBase.FILETIME) Structure.newInstance(WinBase.FILETIME.class, field1.getPointer().getPointer(0)); + WinBase.FILETIME resultFirst = Structure.newInstance(WinBase.FILETIME.class, field1.getPointer().getPointer(0)); resultFirst.read(); return resultFirst.toArray(Count); } else { @@ -498,11 +498,11 @@ public Object getValue() { } case EvtVarTypeSysTime: if (isArray()) { - WinBase.SYSTEMTIME resultFirst = (WinBase.SYSTEMTIME) Structure.newInstance(WinBase.SYSTEMTIME.class, field1.getPointer().getPointer(0)); + WinBase.SYSTEMTIME resultFirst = Structure.newInstance(WinBase.SYSTEMTIME.class, field1.getPointer().getPointer(0)); resultFirst.read(); return resultFirst.toArray(Count); } else { - WinBase.SYSTEMTIME result = (WinBase.SYSTEMTIME) Structure.newInstance(WinBase.SYSTEMTIME.class, field1.getPointer().getPointer(0)); + WinBase.SYSTEMTIME result = Structure.newInstance(WinBase.SYSTEMTIME.class, field1.getPointer().getPointer(0)); result.read(); return result; } @@ -531,21 +531,21 @@ public Object getValue() { return null; case EvtVarTypeGuid: if (isArray()) { - Guid.GUID resultFirst = (Guid.GUID) Structure.newInstance(Guid.GUID.class, field1.getPointer().getPointer(0)); + Guid.GUID resultFirst = Structure.newInstance(Guid.GUID.class, field1.getPointer().getPointer(0)); resultFirst.read(); return resultFirst.toArray(Count); } else { - Guid.GUID result = (Guid.GUID) Structure.newInstance(Guid.GUID.class, field1.getPointer().getPointer(0)); + Guid.GUID result = Structure.newInstance(Guid.GUID.class, field1.getPointer().getPointer(0)); result.read(); return result; } case EvtVarTypeSid: if (isArray()) { - WinNT.PSID resultFirst = (WinNT.PSID) Structure.newInstance(WinNT.PSID.class, field1.getPointer().getPointer(0)); + WinNT.PSID resultFirst = Structure.newInstance(WinNT.PSID.class, field1.getPointer().getPointer(0)); resultFirst.read(); return resultFirst.toArray(Count); } else { - WinNT.PSID result = (WinNT.PSID) Structure.newInstance(WinNT.PSID.class, field1.getPointer().getPointer(0)); + WinNT.PSID result = Structure.newInstance(WinNT.PSID.class, field1.getPointer().getPointer(0)); result.read(); return result; } diff --git a/src/com/sun/jna/CallbackReference.java b/src/com/sun/jna/CallbackReference.java index 5c9d62cd7d..8fcb34773d 100644 --- a/src/com/sun/jna/CallbackReference.java +++ b/src/com/sun/jna/CallbackReference.java @@ -272,7 +272,7 @@ private CallbackReference(Callback callback, int callingConvention, boolean dire private Class getNativeType(Class cls) { if (Structure.class.isAssignableFrom(cls)) { // Make sure we can instantiate an argument of this type - Structure.validate(cls); + Structure.validate((Class)cls); if (!Structure.ByValue.class.isAssignableFrom(cls)) return Pointer.class; } else if (NativeMapped.class.isAssignableFrom(cls)) { @@ -580,14 +580,14 @@ else if (Structure.class.isAssignableFrom(dstType)) { // If passed by value, don't hold onto the pointer, which // is only valid for the duration of the callback call if (Structure.ByValue.class.isAssignableFrom(dstType)) { - Structure s = Structure.newInstance(dstType); + Structure s = Structure.newInstance((Class) dstType); byte[] buf = new byte[s.size()]; ((Pointer)value).read(0, buf, 0, buf.length); s.getPointer().write(0, buf, 0, buf.length); s.read(); value = s; } else { - Structure s = Structure.newInstance(dstType, (Pointer)value); + Structure s = Structure.newInstance((Class) dstType, (Pointer)value); s.conditionalAutoRead(); value = s; } diff --git a/src/com/sun/jna/Function.java b/src/com/sun/jna/Function.java index 795901d44b..2d31827f02 100644 --- a/src/com/sun/jna/Function.java +++ b/src/com/sun/jna/Function.java @@ -378,11 +378,11 @@ Object invoke(Method invokingMethod, Class[] paramTypes, Class returnType, if (args[i] instanceof PointerArray) { PointerArray array = (PointerArray)args[i]; if (Structure.ByReference[].class.isAssignableFrom(inArg.getClass())) { - Class type = inArg.getClass().getComponentType(); + Class type = (Class) inArg.getClass().getComponentType(); Structure[] ss = (Structure[])inArg; for (int si=0;si < ss.length;si++) { Pointer p = array.getPointer(Native.POINTER_SIZE * si); - ss[si] = Structure.updateStructureByReference(type, ss[si], p); + ss[si] = Structure.updateStructureByReference((Class)type, ss[si], p); } } } @@ -436,13 +436,13 @@ Object invoke(Object[] args, Class returnType, boolean allowObjects, int fixe if (Structure.ByValue.class.isAssignableFrom(returnType)) { Structure s = Native.invokeStructure(this, this.peer, callFlags, args, - Structure.newInstance(returnType)); + Structure.newInstance((Class)returnType)); s.autoRead(); result = s; } else { result = invokePointer(callFlags, args); if (result != null) { - Structure s = Structure.newInstance(returnType, (Pointer)result); + Structure s = Structure.newInstance((Class)returnType, (Pointer)result); s.conditionalAutoRead(); result = s; } @@ -604,7 +604,7 @@ private Object convertArgument(Object[] args, int index, } else if (ss.length == 0) { throw new IllegalArgumentException("Structure array must have non-zero length"); } else if (ss[0] == null) { - Structure.newInstance(type).toArray(ss); + Structure.newInstance((Class) type).toArray(ss); return ss[0].getPointer(); } else { Structure.autoWrite(ss); diff --git a/src/com/sun/jna/Native.java b/src/com/sun/jna/Native.java index 33e8e56008..ae80566609 100644 --- a/src/com/sun/jna/Native.java +++ b/src/com/sun/jna/Native.java @@ -1241,7 +1241,7 @@ public static int getNativeSize(Class type, Object value) { } if (Structure.class.isAssignableFrom(type) && !Structure.ByReference.class.isAssignableFrom(type)) { - return Structure.size(type, (Structure)value); + return Structure.size((Class) type, (Structure)value); } try { return getNativeSize(type); @@ -1276,7 +1276,7 @@ public static int getNativeSize(Class cls) { if (cls == double.class || cls == Double.class) return 8; if (Structure.class.isAssignableFrom(cls)) { if (Structure.ByValue.class.isAssignableFrom(cls)) { - return Structure.size(cls); + return Structure.size((Class) cls); } return POINTER_SIZE; } diff --git a/src/com/sun/jna/Pointer.java b/src/com/sun/jna/Pointer.java index 16ad03fd80..c111f9a7a6 100644 --- a/src/com/sun/jna/Pointer.java +++ b/src/com/sun/jna/Pointer.java @@ -363,7 +363,7 @@ Object getValue(long offset, Class type, Object currentValue) { if (Structure.class.isAssignableFrom(type)) { Structure s = (Structure)currentValue; if (Structure.ByReference.class.isAssignableFrom(type)) { - s = Structure.updateStructureByReference(type, s, getPointer(offset)); + s = Structure.updateStructureByReference((Class) type, s, getPointer(offset)); } else { s.useMemory(this, (int)offset, true); s.read(); @@ -488,13 +488,13 @@ else if (Structure.class.isAssignableFrom(cls)) { if (Structure.ByReference.class.isAssignableFrom(cls)) { Pointer[] parray = getPointerArray(offset, sarray.length); for (int i=0;i < sarray.length;i++) { - sarray[i] = Structure.updateStructureByReference(cls, sarray[i], parray[i]); + sarray[i] = Structure.updateStructureByReference((Class) cls, sarray[i], parray[i]); } } else { Structure first = sarray[0]; if (first == null) { - first = Structure.newInstance(cls, share(offset)); + first = Structure.newInstance((Class) cls, share(offset)); first.conditionalAutoRead(); sarray[0] = first; } @@ -940,7 +940,7 @@ private void writeArray(long offset, Object value, Class cls) { } else { Structure first = sbuf[0]; if (first == null) { - first = Structure.newInstance(cls, share(offset)); + first = Structure.newInstance((Class) cls, share(offset)); sbuf[0] = first; } else { first.useMemory(this, (int)offset, true); diff --git a/src/com/sun/jna/Structure.java b/src/com/sun/jna/Structure.java index 5e4b7f7dfb..13f3c14a83 100644 --- a/src/com/sun/jna/Structure.java +++ b/src/com/sun/jna/Structure.java @@ -662,7 +662,7 @@ private void setFieldValue(Field field, Object value, boolean overrideFinal) { * @param address the native struct * * @return Updated Structure.ByReference object */ - static Structure updateStructureByReference(Class type, Structure s, Pointer address) { + static T updateStructureByReference(Class type, T s, Pointer address) { if (address == null) { s = null; } @@ -670,7 +670,7 @@ static Structure updateStructureByReference(Class type, Structure s, Pointer if (s == null || !address.equals(s.getPointer())) { Structure s1 = reading().get(address); if (s1 != null && type.equals(s1.getClass())) { - s = s1; + s = (T) s1; s.autoRead(); } else { @@ -1042,7 +1042,7 @@ protected int calculateSize(boolean force) { * @param type Structure subclass to check * @return native size of the given Structure subclass */ - static int size(Class type) { + static int size(Class type) { return size(type, null); } @@ -1051,7 +1051,7 @@ static int size(Class type) { * @param value optional instance of the given class * @return native size of the Structure subclass */ - static int size(Class type, Structure value) { + static int size(Class type, T value) { LayoutInfo info; synchronized(layoutInfo) { info = layoutInfo.get(type); @@ -1329,7 +1329,7 @@ private Object initializeField(Field field, Class type) { if (Structure.class.isAssignableFrom(type) && !(ByReference.class.isAssignableFrom(type))) { try { - value = newInstance(type, PLACEHOLDER_MEMORY); + value = newInstance((Class) type, PLACEHOLDER_MEMORY); setFieldValue(field, value); } catch(IllegalArgumentException e) { @@ -1408,7 +1408,7 @@ else if (Structure.class.isAssignableFrom(type)) { } else { if (value == null) - value = newInstance(type, PLACEHOLDER_MEMORY); + value = newInstance((Class) type, PLACEHOLDER_MEMORY); alignment = ((Structure)value).getStructAlignment(); } } @@ -1744,9 +1744,9 @@ static Pointer getTypeInfo(Object obj) { * #newInstance(Class,Pointer)}, except that it additionally calls * {@link #conditionalAutoRead()}. */ - private static Structure newInstance(Class type, long init) { + private static T newInstance(Class type, long init) { try { - Structure s = newInstance(type, init == 0 ? PLACEHOLDER_MEMORY : new Pointer(init)); + T s = newInstance(type, init == 0 ? PLACEHOLDER_MEMORY : new Pointer(init)); if (init != 0) { s.conditionalAutoRead(); } @@ -1765,10 +1765,10 @@ private static Structure newInstance(Class type, long init) { * @return the new instance * @throws IllegalArgumentException if the instantiation fails */ - public static Structure newInstance(Class type, Pointer init) throws IllegalArgumentException { + public static T newInstance(Class type, Pointer init) throws IllegalArgumentException { try { - Constructor ctor = type.getConstructor(Pointer.class); - return (Structure)ctor.newInstance(init); + Constructor ctor = type.getConstructor(Pointer.class); + return ctor.newInstance(init); } catch(NoSuchMethodException e) { // Not defined, fall back to the default @@ -1789,7 +1789,7 @@ public static Structure newInstance(Class type, Pointer init) throws IllegalA e.printStackTrace(); throw new IllegalArgumentException(msg, e); } - Structure s = newInstance(type); + T s = newInstance(type); if (init != PLACEHOLDER_MEMORY) { s.useMemory(init); } @@ -1801,9 +1801,9 @@ public static Structure newInstance(Class type, Pointer init) throws IllegalA * @return the new instance * @throws IllegalArgumentException if the instantiation fails */ - public static Structure newInstance(Class type) throws IllegalArgumentException { + public static T newInstance(Class type) throws IllegalArgumentException { try { - Structure s = (Structure)type.newInstance(); + T s = type.newInstance(); if (s instanceof ByValue) { s.allocateMemory(); } @@ -1993,7 +1993,7 @@ private static Pointer get(Object obj, Class cls) { return FFITypes.ffi_type_pointer; } if (Structure.class.isAssignableFrom(cls)) { - if (obj == null) obj = newInstance(cls, PLACEHOLDER_MEMORY); + if (obj == null) obj = newInstance((Class) cls, PLACEHOLDER_MEMORY); if (ByReference.class.isAssignableFrom(cls)) { typeInfoMap.put(cls, FFITypes.ffi_type_pointer); return FFITypes.ffi_type_pointer; @@ -2124,7 +2124,7 @@ protected int getNativeSize(Class nativeType, Object value) { /** Indicate whether the given Structure class can be created by JNA. * @param cls Structure subclass to check */ - static void validate(Class cls) { + static void validate(Class cls) { Structure.newInstance(cls, PLACEHOLDER_MEMORY); } } diff --git a/test/com/sun/jna/StructureTest.java b/test/com/sun/jna/StructureTest.java index 21f80f620e..1752672fbe 100644 --- a/test/com/sun/jna/StructureTest.java +++ b/test/com/sun/jna/StructureTest.java @@ -281,7 +281,7 @@ public interface SizeTest extends Library { private void testStructureSize(int index) { try { SizeTest lib = Native.loadLibrary("testlib", SizeTest.class); - Class cls = Class.forName(getClass().getName() + "$TestStructure" + index); + Class cls = (Class) Class.forName(getClass().getName() + "$TestStructure" + index); Structure s = Structure.newInstance(cls); assertEquals("Incorrect size for structure " + index + "=>" + s.toString(true), lib.getStructureSize(index), s.size()); }