Skip to content

Commit

Permalink
Merge pull request #898 from matthiasblaesing/struct_newinstance_generic
Browse files Browse the repository at this point in the history
Tighten the generic bounds for Structure#newInstance
  • Loading branch information
matthiasblaesing committed Jan 11, 2018
2 parents 398a4bc + a9a2c43 commit 7b66282
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 38 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
---------
Expand Down
14 changes: 7 additions & 7 deletions contrib/platform/src/com/sun/jna/platform/win32/Winevt.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
6 changes: 3 additions & 3 deletions src/com/sun/jna/CallbackReference.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<? extends Structure>)cls);
if (!Structure.ByValue.class.isAssignableFrom(cls))
return Pointer.class;
} else if (NativeMapped.class.isAssignableFrom(cls)) {
Expand Down Expand Up @@ -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<? extends Structure>) 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<? extends Structure>) dstType, (Pointer)value);
s.conditionalAutoRead();
value = s;
}
Expand Down
10 changes: 5 additions & 5 deletions src/com/sun/jna/Function.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<? extends Structure> type = (Class<? extends Structure>) 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<Structure>)type, ss[si], p);
}
}
}
Expand Down Expand Up @@ -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<? extends Structure>)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<? extends Structure>)returnType, (Pointer)result);
s.conditionalAutoRead();
result = s;
}
Expand Down Expand Up @@ -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<? extends Structure>) type).toArray(ss);
return ss[0].getPointer();
} else {
Structure.autoWrite(ss);
Expand Down
4 changes: 2 additions & 2 deletions src/com/sun/jna/Native.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Structure>) type, (Structure)value);
}
try {
return getNativeSize(type);
Expand Down Expand Up @@ -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<? extends Structure>) cls);
}
return POINTER_SIZE;
}
Expand Down
8 changes: 4 additions & 4 deletions src/com/sun/jna/Pointer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Structure>) type, s, getPointer(offset));
} else {
s.useMemory(this, (int)offset, true);
s.read();
Expand Down Expand Up @@ -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<Structure>) cls, sarray[i], parray[i]);
}
}
else {
Structure first = sarray[0];
if (first == null) {
first = Structure.newInstance(cls, share(offset));
first = Structure.newInstance((Class<Structure>) cls, share(offset));
first.conditionalAutoRead();
sarray[0] = first;
}
Expand Down Expand Up @@ -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<Structure>) cls, share(offset));
sbuf[0] = first;
} else {
first.useMemory(this, (int)offset, true);
Expand Down
32 changes: 16 additions & 16 deletions src/com/sun/jna/Structure.java
Original file line number Diff line number Diff line change
Expand Up @@ -662,15 +662,15 @@ private void setFieldValue(Field field, Object value, boolean overrideFinal) {
* @param address the native <code>struct *</code>
* @return Updated <code>Structure.ByReference</code> object
*/
static Structure updateStructureByReference(Class<?> type, Structure s, Pointer address) {
static <T extends Structure> T updateStructureByReference(Class<T> type, T s, Pointer address) {
if (address == null) {
s = null;
}
else {
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 {
Expand Down Expand Up @@ -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<? extends Structure> type) {
return size(type, null);
}

Expand All @@ -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 <T extends Structure> int size(Class<T> type, T value) {
LayoutInfo info;
synchronized(layoutInfo) {
info = layoutInfo.get(type);
Expand Down Expand Up @@ -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<? extends Structure>) type, PLACEHOLDER_MEMORY);
setFieldValue(field, value);
}
catch(IllegalArgumentException e) {
Expand Down Expand Up @@ -1408,7 +1408,7 @@ else if (Structure.class.isAssignableFrom(type)) {
}
else {
if (value == null)
value = newInstance(type, PLACEHOLDER_MEMORY);
value = newInstance((Class<? extends Structure>) type, PLACEHOLDER_MEMORY);
alignment = ((Structure)value).getStructAlignment();
}
}
Expand Down Expand Up @@ -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 extends Structure> T newInstance(Class<T> 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();
}
Expand All @@ -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 extends Structure> T newInstance(Class<T> type, Pointer init) throws IllegalArgumentException {
try {
Constructor<?> ctor = type.getConstructor(Pointer.class);
return (Structure)ctor.newInstance(init);
Constructor<T> ctor = type.getConstructor(Pointer.class);
return ctor.newInstance(init);
}
catch(NoSuchMethodException e) {
// Not defined, fall back to the default
Expand All @@ -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);
}
Expand All @@ -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 extends Structure> T newInstance(Class<T> type) throws IllegalArgumentException {
try {
Structure s = (Structure)type.newInstance();
T s = type.newInstance();
if (s instanceof ByValue) {
s.allocateMemory();
}
Expand Down Expand Up @@ -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<? extends Structure>) cls, PLACEHOLDER_MEMORY);
if (ByReference.class.isAssignableFrom(cls)) {
typeInfoMap.put(cls, FFITypes.ffi_type_pointer);
return FFITypes.ffi_type_pointer;
Expand Down Expand Up @@ -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<? extends Structure> cls) {
Structure.newInstance(cls, PLACEHOLDER_MEMORY);
}
}
2 changes: 1 addition & 1 deletion test/com/sun/jna/StructureTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<? extends Structure> cls = (Class<? extends Structure>) 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());
}
Expand Down

0 comments on commit 7b66282

Please sign in to comment.