Skip to content

Commit a9a2c43

Browse files
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 extends Structure> T newInstance(Class<T> type)` The companion, that takes an init pointer was also updated: <T extends Structure> T newInstance(Class<T> type, Pointer init) Closes: #889
1 parent 327e41a commit a9a2c43

File tree

8 files changed

+40
-38
lines changed

8 files changed

+40
-38
lines changed

CHANGES.md

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Release 5.0.0 (Next release)
77

88
Features
99
--------
10+
* [#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).
11+
* [#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).
1012

1113
Bug Fixes
1214
---------

contrib/platform/src/com/sun/jna/platform/win32/Winevt.java

+7-7
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ public Object getValue() {
488488
return isArray() ? field1.getPointer().getPointer(0).getWideStringArray(0, Count) : field1.getPointer().getPointer(0).getWideString(0);
489489
case EvtVarTypeFileTime:
490490
if (isArray()) {
491-
WinBase.FILETIME resultFirst = (WinBase.FILETIME) Structure.newInstance(WinBase.FILETIME.class, field1.getPointer().getPointer(0));
491+
WinBase.FILETIME resultFirst = Structure.newInstance(WinBase.FILETIME.class, field1.getPointer().getPointer(0));
492492
resultFirst.read();
493493
return resultFirst.toArray(Count);
494494
} else {
@@ -498,11 +498,11 @@ public Object getValue() {
498498
}
499499
case EvtVarTypeSysTime:
500500
if (isArray()) {
501-
WinBase.SYSTEMTIME resultFirst = (WinBase.SYSTEMTIME) Structure.newInstance(WinBase.SYSTEMTIME.class, field1.getPointer().getPointer(0));
501+
WinBase.SYSTEMTIME resultFirst = Structure.newInstance(WinBase.SYSTEMTIME.class, field1.getPointer().getPointer(0));
502502
resultFirst.read();
503503
return resultFirst.toArray(Count);
504504
} else {
505-
WinBase.SYSTEMTIME result = (WinBase.SYSTEMTIME) Structure.newInstance(WinBase.SYSTEMTIME.class, field1.getPointer().getPointer(0));
505+
WinBase.SYSTEMTIME result = Structure.newInstance(WinBase.SYSTEMTIME.class, field1.getPointer().getPointer(0));
506506
result.read();
507507
return result;
508508
}
@@ -531,21 +531,21 @@ public Object getValue() {
531531
return null;
532532
case EvtVarTypeGuid:
533533
if (isArray()) {
534-
Guid.GUID resultFirst = (Guid.GUID) Structure.newInstance(Guid.GUID.class, field1.getPointer().getPointer(0));
534+
Guid.GUID resultFirst = Structure.newInstance(Guid.GUID.class, field1.getPointer().getPointer(0));
535535
resultFirst.read();
536536
return resultFirst.toArray(Count);
537537
} else {
538-
Guid.GUID result = (Guid.GUID) Structure.newInstance(Guid.GUID.class, field1.getPointer().getPointer(0));
538+
Guid.GUID result = Structure.newInstance(Guid.GUID.class, field1.getPointer().getPointer(0));
539539
result.read();
540540
return result;
541541
}
542542
case EvtVarTypeSid:
543543
if (isArray()) {
544-
WinNT.PSID resultFirst = (WinNT.PSID) Structure.newInstance(WinNT.PSID.class, field1.getPointer().getPointer(0));
544+
WinNT.PSID resultFirst = Structure.newInstance(WinNT.PSID.class, field1.getPointer().getPointer(0));
545545
resultFirst.read();
546546
return resultFirst.toArray(Count);
547547
} else {
548-
WinNT.PSID result = (WinNT.PSID) Structure.newInstance(WinNT.PSID.class, field1.getPointer().getPointer(0));
548+
WinNT.PSID result = Structure.newInstance(WinNT.PSID.class, field1.getPointer().getPointer(0));
549549
result.read();
550550
return result;
551551
}

src/com/sun/jna/CallbackReference.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ private CallbackReference(Callback callback, int callingConvention, boolean dire
272272
private Class<?> getNativeType(Class<?> cls) {
273273
if (Structure.class.isAssignableFrom(cls)) {
274274
// Make sure we can instantiate an argument of this type
275-
Structure.validate(cls);
275+
Structure.validate((Class<? extends Structure>)cls);
276276
if (!Structure.ByValue.class.isAssignableFrom(cls))
277277
return Pointer.class;
278278
} else if (NativeMapped.class.isAssignableFrom(cls)) {
@@ -580,14 +580,14 @@ else if (Structure.class.isAssignableFrom(dstType)) {
580580
// If passed by value, don't hold onto the pointer, which
581581
// is only valid for the duration of the callback call
582582
if (Structure.ByValue.class.isAssignableFrom(dstType)) {
583-
Structure s = Structure.newInstance(dstType);
583+
Structure s = Structure.newInstance((Class<? extends Structure>) dstType);
584584
byte[] buf = new byte[s.size()];
585585
((Pointer)value).read(0, buf, 0, buf.length);
586586
s.getPointer().write(0, buf, 0, buf.length);
587587
s.read();
588588
value = s;
589589
} else {
590-
Structure s = Structure.newInstance(dstType, (Pointer)value);
590+
Structure s = Structure.newInstance((Class<? extends Structure>) dstType, (Pointer)value);
591591
s.conditionalAutoRead();
592592
value = s;
593593
}

src/com/sun/jna/Function.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -378,11 +378,11 @@ Object invoke(Method invokingMethod, Class<?>[] paramTypes, Class<?> returnType,
378378
if (args[i] instanceof PointerArray) {
379379
PointerArray array = (PointerArray)args[i];
380380
if (Structure.ByReference[].class.isAssignableFrom(inArg.getClass())) {
381-
Class<?> type = inArg.getClass().getComponentType();
381+
Class<? extends Structure> type = (Class<? extends Structure>) inArg.getClass().getComponentType();
382382
Structure[] ss = (Structure[])inArg;
383383
for (int si=0;si < ss.length;si++) {
384384
Pointer p = array.getPointer(Native.POINTER_SIZE * si);
385-
ss[si] = Structure.updateStructureByReference(type, ss[si], p);
385+
ss[si] = Structure.updateStructureByReference((Class<Structure>)type, ss[si], p);
386386
}
387387
}
388388
}
@@ -436,13 +436,13 @@ Object invoke(Object[] args, Class<?> returnType, boolean allowObjects, int fixe
436436
if (Structure.ByValue.class.isAssignableFrom(returnType)) {
437437
Structure s =
438438
Native.invokeStructure(this, this.peer, callFlags, args,
439-
Structure.newInstance(returnType));
439+
Structure.newInstance((Class<? extends Structure>)returnType));
440440
s.autoRead();
441441
result = s;
442442
} else {
443443
result = invokePointer(callFlags, args);
444444
if (result != null) {
445-
Structure s = Structure.newInstance(returnType, (Pointer)result);
445+
Structure s = Structure.newInstance((Class<? extends Structure>)returnType, (Pointer)result);
446446
s.conditionalAutoRead();
447447
result = s;
448448
}
@@ -604,7 +604,7 @@ private Object convertArgument(Object[] args, int index,
604604
} else if (ss.length == 0) {
605605
throw new IllegalArgumentException("Structure array must have non-zero length");
606606
} else if (ss[0] == null) {
607-
Structure.newInstance(type).toArray(ss);
607+
Structure.newInstance((Class<? extends Structure>) type).toArray(ss);
608608
return ss[0].getPointer();
609609
} else {
610610
Structure.autoWrite(ss);

src/com/sun/jna/Native.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1241,7 +1241,7 @@ public static int getNativeSize(Class<?> type, Object value) {
12411241
}
12421242
if (Structure.class.isAssignableFrom(type)
12431243
&& !Structure.ByReference.class.isAssignableFrom(type)) {
1244-
return Structure.size(type, (Structure)value);
1244+
return Structure.size((Class<Structure>) type, (Structure)value);
12451245
}
12461246
try {
12471247
return getNativeSize(type);
@@ -1276,7 +1276,7 @@ public static int getNativeSize(Class<?> cls) {
12761276
if (cls == double.class || cls == Double.class) return 8;
12771277
if (Structure.class.isAssignableFrom(cls)) {
12781278
if (Structure.ByValue.class.isAssignableFrom(cls)) {
1279-
return Structure.size(cls);
1279+
return Structure.size((Class<? extends Structure>) cls);
12801280
}
12811281
return POINTER_SIZE;
12821282
}

src/com/sun/jna/Pointer.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ Object getValue(long offset, Class<?> type, Object currentValue) {
363363
if (Structure.class.isAssignableFrom(type)) {
364364
Structure s = (Structure)currentValue;
365365
if (Structure.ByReference.class.isAssignableFrom(type)) {
366-
s = Structure.updateStructureByReference(type, s, getPointer(offset));
366+
s = Structure.updateStructureByReference((Class<Structure>) type, s, getPointer(offset));
367367
} else {
368368
s.useMemory(this, (int)offset, true);
369369
s.read();
@@ -488,13 +488,13 @@ else if (Structure.class.isAssignableFrom(cls)) {
488488
if (Structure.ByReference.class.isAssignableFrom(cls)) {
489489
Pointer[] parray = getPointerArray(offset, sarray.length);
490490
for (int i=0;i < sarray.length;i++) {
491-
sarray[i] = Structure.updateStructureByReference(cls, sarray[i], parray[i]);
491+
sarray[i] = Structure.updateStructureByReference((Class<Structure>) cls, sarray[i], parray[i]);
492492
}
493493
}
494494
else {
495495
Structure first = sarray[0];
496496
if (first == null) {
497-
first = Structure.newInstance(cls, share(offset));
497+
first = Structure.newInstance((Class<Structure>) cls, share(offset));
498498
first.conditionalAutoRead();
499499
sarray[0] = first;
500500
}
@@ -940,7 +940,7 @@ private void writeArray(long offset, Object value, Class<?> cls) {
940940
} else {
941941
Structure first = sbuf[0];
942942
if (first == null) {
943-
first = Structure.newInstance(cls, share(offset));
943+
first = Structure.newInstance((Class<Structure>) cls, share(offset));
944944
sbuf[0] = first;
945945
} else {
946946
first.useMemory(this, (int)offset, true);

src/com/sun/jna/Structure.java

+16-16
Original file line numberDiff line numberDiff line change
@@ -662,15 +662,15 @@ private void setFieldValue(Field field, Object value, boolean overrideFinal) {
662662
* @param address the native <code>struct *</code>
663663
* @return Updated <code>Structure.ByReference</code> object
664664
*/
665-
static Structure updateStructureByReference(Class<?> type, Structure s, Pointer address) {
665+
static <T extends Structure> T updateStructureByReference(Class<T> type, T s, Pointer address) {
666666
if (address == null) {
667667
s = null;
668668
}
669669
else {
670670
if (s == null || !address.equals(s.getPointer())) {
671671
Structure s1 = reading().get(address);
672672
if (s1 != null && type.equals(s1.getClass())) {
673-
s = s1;
673+
s = (T) s1;
674674
s.autoRead();
675675
}
676676
else {
@@ -1042,7 +1042,7 @@ protected int calculateSize(boolean force) {
10421042
* @param type Structure subclass to check
10431043
* @return native size of the given Structure subclass
10441044
*/
1045-
static int size(Class<?> type) {
1045+
static int size(Class<? extends Structure> type) {
10461046
return size(type, null);
10471047
}
10481048

@@ -1051,7 +1051,7 @@ static int size(Class<?> type) {
10511051
* @param value optional instance of the given class
10521052
* @return native size of the Structure subclass
10531053
*/
1054-
static int size(Class<?> type, Structure value) {
1054+
static <T extends Structure> int size(Class<T> type, T value) {
10551055
LayoutInfo info;
10561056
synchronized(layoutInfo) {
10571057
info = layoutInfo.get(type);
@@ -1329,7 +1329,7 @@ private Object initializeField(Field field, Class<?> type) {
13291329
if (Structure.class.isAssignableFrom(type)
13301330
&& !(ByReference.class.isAssignableFrom(type))) {
13311331
try {
1332-
value = newInstance(type, PLACEHOLDER_MEMORY);
1332+
value = newInstance((Class<? extends Structure>) type, PLACEHOLDER_MEMORY);
13331333
setFieldValue(field, value);
13341334
}
13351335
catch(IllegalArgumentException e) {
@@ -1408,7 +1408,7 @@ else if (Structure.class.isAssignableFrom(type)) {
14081408
}
14091409
else {
14101410
if (value == null)
1411-
value = newInstance(type, PLACEHOLDER_MEMORY);
1411+
value = newInstance((Class<? extends Structure>) type, PLACEHOLDER_MEMORY);
14121412
alignment = ((Structure)value).getStructAlignment();
14131413
}
14141414
}
@@ -1744,9 +1744,9 @@ static Pointer getTypeInfo(Object obj) {
17441744
* #newInstance(Class,Pointer)}, except that it additionally calls
17451745
* {@link #conditionalAutoRead()}.
17461746
*/
1747-
private static Structure newInstance(Class<?> type, long init) {
1747+
private static <T extends Structure> T newInstance(Class<T> type, long init) {
17481748
try {
1749-
Structure s = newInstance(type, init == 0 ? PLACEHOLDER_MEMORY : new Pointer(init));
1749+
T s = newInstance(type, init == 0 ? PLACEHOLDER_MEMORY : new Pointer(init));
17501750
if (init != 0) {
17511751
s.conditionalAutoRead();
17521752
}
@@ -1765,10 +1765,10 @@ private static Structure newInstance(Class<?> type, long init) {
17651765
* @return the new instance
17661766
* @throws IllegalArgumentException if the instantiation fails
17671767
*/
1768-
public static Structure newInstance(Class<?> type, Pointer init) throws IllegalArgumentException {
1768+
public static <T extends Structure> T newInstance(Class<T> type, Pointer init) throws IllegalArgumentException {
17691769
try {
1770-
Constructor<?> ctor = type.getConstructor(Pointer.class);
1771-
return (Structure)ctor.newInstance(init);
1770+
Constructor<T> ctor = type.getConstructor(Pointer.class);
1771+
return ctor.newInstance(init);
17721772
}
17731773
catch(NoSuchMethodException e) {
17741774
// Not defined, fall back to the default
@@ -1789,7 +1789,7 @@ public static Structure newInstance(Class<?> type, Pointer init) throws IllegalA
17891789
e.printStackTrace();
17901790
throw new IllegalArgumentException(msg, e);
17911791
}
1792-
Structure s = newInstance(type);
1792+
T s = newInstance(type);
17931793
if (init != PLACEHOLDER_MEMORY) {
17941794
s.useMemory(init);
17951795
}
@@ -1801,9 +1801,9 @@ public static Structure newInstance(Class<?> type, Pointer init) throws IllegalA
18011801
* @return the new instance
18021802
* @throws IllegalArgumentException if the instantiation fails
18031803
*/
1804-
public static Structure newInstance(Class<?> type) throws IllegalArgumentException {
1804+
public static <T extends Structure> T newInstance(Class<T> type) throws IllegalArgumentException {
18051805
try {
1806-
Structure s = (Structure)type.newInstance();
1806+
T s = type.newInstance();
18071807
if (s instanceof ByValue) {
18081808
s.allocateMemory();
18091809
}
@@ -1993,7 +1993,7 @@ private static Pointer get(Object obj, Class<?> cls) {
19931993
return FFITypes.ffi_type_pointer;
19941994
}
19951995
if (Structure.class.isAssignableFrom(cls)) {
1996-
if (obj == null) obj = newInstance(cls, PLACEHOLDER_MEMORY);
1996+
if (obj == null) obj = newInstance((Class<? extends Structure>) cls, PLACEHOLDER_MEMORY);
19971997
if (ByReference.class.isAssignableFrom(cls)) {
19981998
typeInfoMap.put(cls, FFITypes.ffi_type_pointer);
19991999
return FFITypes.ffi_type_pointer;
@@ -2124,7 +2124,7 @@ protected int getNativeSize(Class<?> nativeType, Object value) {
21242124
/** Indicate whether the given Structure class can be created by JNA.
21252125
* @param cls Structure subclass to check
21262126
*/
2127-
static void validate(Class<?> cls) {
2127+
static void validate(Class<? extends Structure> cls) {
21282128
Structure.newInstance(cls, PLACEHOLDER_MEMORY);
21292129
}
21302130
}

test/com/sun/jna/StructureTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ public interface SizeTest extends Library {
281281
private void testStructureSize(int index) {
282282
try {
283283
SizeTest lib = Native.loadLibrary("testlib", SizeTest.class);
284-
Class<?> cls = Class.forName(getClass().getName() + "$TestStructure" + index);
284+
Class<? extends Structure> cls = (Class<? extends Structure>) Class.forName(getClass().getName() + "$TestStructure" + index);
285285
Structure s = Structure.newInstance(cls);
286286
assertEquals("Incorrect size for structure " + index + "=>" + s.toString(true), lib.getStructureSize(index), s.size());
287287
}

0 commit comments

Comments
 (0)