Skip to content

Commit 2736544

Browse files
committed
first pass at adding classmate based resolution. Test suite passing.
Old code is still present.
1 parent 661fef4 commit 2736544

File tree

7 files changed

+336
-8
lines changed

7 files changed

+336
-8
lines changed

src/main/java/org/bridj/StructFieldDeclaration.java

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,31 @@
3737
import java.lang.reflect.Method;
3838
import java.lang.reflect.Modifier;
3939
import java.util.ArrayList;
40+
import java.util.Arrays;
41+
import java.util.HashMap;
42+
import java.util.LinkedHashMap;
4043
import java.util.List;
44+
import java.util.Map;
4145

4246
import org.bridj.ann.Alignment;
4347
import org.bridj.ann.Array;
4448
import org.bridj.ann.Bits;
4549
import org.bridj.ann.Field;
4650
import org.bridj.ann.Union;
4751

52+
import com.fasterxml.classmate.AnnotationConfiguration;
53+
import com.fasterxml.classmate.AnnotationInclusion;
54+
import com.fasterxml.classmate.Filter;
55+
import com.fasterxml.classmate.MemberResolver;
56+
import com.fasterxml.classmate.ResolvedType;
57+
import com.fasterxml.classmate.ResolvedTypeWithMembers;
58+
import com.fasterxml.classmate.TypeResolver;
59+
import com.fasterxml.classmate.members.RawField;
60+
import com.fasterxml.classmate.members.RawMethod;
61+
import com.fasterxml.classmate.members.ResolvedField;
62+
import com.fasterxml.classmate.members.ResolvedMember;
63+
import com.fasterxml.classmate.members.ResolvedMethod;
64+
4865
class StructFieldDeclaration {
4966

5067
final StructFieldDescription desc = new StructFieldDescription();
@@ -58,6 +75,7 @@ public String toString() {
5875
return desc.name + " (index = " + index + (unionWith < 0 ? "" : ", unionWith = " + unionWith) + ", desc = " + desc + ")";
5976
}
6077

78+
@Deprecated
6179
protected static boolean acceptFieldGetter(Member member, boolean getter) {
6280
if ((member instanceof Method) && ((Method) member).getParameterTypes().length != (getter ? 0 : 1)) {
6381
return false;
@@ -71,16 +89,30 @@ protected static boolean acceptFieldGetter(Member member, boolean getter) {
7189

7290
return !Modifier.isStatic(modifiers);
7391
}
92+
93+
protected static boolean acceptFieldGetter(ResolvedMember<?> member, boolean getter) {
94+
if ((member instanceof ResolvedMethod) && ((ResolvedMethod) member).getRawMember().getParameterTypes().length != (getter ? 0 : 1)) {
95+
return false;
96+
}
97+
98+
if (member.get(Field.class) == null) {
99+
return false;
100+
}
101+
102+
return !member.isStatic();
103+
}
74104

75105
/**
76106
* Creates a list of structure fields
77107
*/
108+
@Deprecated
78109
protected static List<StructFieldDeclaration> listFields(Class<?> structClass) {
79110
List<StructFieldDeclaration> list = new ArrayList<StructFieldDeclaration>();
80111
for (Method method : structClass.getMethods()) {
81112
if (acceptFieldGetter(method, true)) {
82113
StructFieldDeclaration io = fromGetter(method);
83114
try {
115+
// this only works when the names are equal, does not support setXXX methods.
84116
Method setter = structClass.getMethod(method.getName(), io.valueClass);
85117
if (acceptFieldGetter(setter, false)) {
86118
io.setter = setter;
@@ -110,7 +142,81 @@ protected static List<StructFieldDeclaration> listFields(Class<?> structClass) {
110142

111143
return list;
112144
}
145+
146+
protected static List<StructFieldDeclaration> listFields2(Class<?> structClass) {
147+
List<StructFieldDeclaration> list = new ArrayList<StructFieldDeclaration>();
148+
ResolvedTypeWithMembers resolvedStruct = resolveType(structClass);
149+
for (ResolvedMethod method : resolvedStruct.getMemberMethods()) {
150+
if (acceptFieldGetter(method, true)) {
151+
StructFieldDeclaration io = fromGetter(method);
152+
try {
153+
// this only works when the names are equal, does not support setXXX methods.
154+
ResolvedMethod setter = getMethod( resolvedStruct.getMemberMethods(), method.getName(), io.valueClass);
155+
if (acceptFieldGetter(setter, false)) {
156+
io.setter = setter.getRawMember();
157+
}
158+
} catch (Exception ex) {
159+
//assert BridJ.info("No setter for getter " + method);
160+
}
161+
if (io != null) {
162+
list.add(io);
163+
}
164+
}
165+
}
113166

167+
int nFieldFields = 0;
168+
for ( ResolvedField field : resolvedStruct.getMemberFields()) {
169+
if (acceptFieldGetter(field, true)) {
170+
StructFieldDeclaration io = StructFieldDeclaration.fromField(field);
171+
if (io != null) {
172+
list.add(io);
173+
nFieldFields++;
174+
}
175+
}
176+
}
177+
if (nFieldFields > 0 && BridJ.warnStructFields) {
178+
BridJ.warning("Struct " + structClass.getName() + " has " + nFieldFields + " struct fields implemented as Java fields, which won't give the best performance and might require counter-intuitive calls to BridJ.readFromNative / .writeToNative. Please consider using JNAerator to generate your struct instead, or use BRIDJ_WARN_STRUCT_FIELDS=0 or -Dbridj.warnStructFields=false to mute this warning.");
179+
}
180+
181+
return list;
182+
}
183+
184+
public static ResolvedMethod getMethod( ResolvedMethod[] methods, String name, Class<?>... params ) {
185+
METHODS: for( ResolvedMethod method : methods ) {
186+
if( !name.equals(method.getName()) ) continue METHODS;
187+
if( params.length != method.getArgumentCount()) continue METHODS;
188+
for( int i = 0; i < params.length; i++ ) {
189+
if( !method.getArgumentType(i).isInstanceOf(params[i])) continue METHODS;
190+
}
191+
return method;
192+
}
193+
return null;
194+
}
195+
196+
protected static String nameForMember( ResolvedMember<?> member ) {
197+
String name = member.getName();
198+
if (name.matches("get[A-Z].*")) {
199+
return Character.toLowerCase(name.charAt(3)) + name.substring(4);
200+
} else if ( name.matches("set[A-Z].*")) {
201+
return Character.toLowerCase(name.charAt(3)) + name.substring(4);
202+
} else {
203+
return name;
204+
}
205+
}
206+
207+
protected static ResolvedTypeWithMembers resolveType( Class<?> structClass ) {
208+
TypeResolver resolver = new TypeResolver();
209+
ResolvedType classType = resolver.resolve(structClass);
210+
MemberResolver mr = new MemberResolver(resolver);
211+
mr.setMethodFilter(method->
212+
method.getRawMember().getParameterTypes().length < 2 &&
213+
!method.isStatic());
214+
mr.setFieldFilter(field->!field.isStatic());
215+
AnnotationConfiguration annConfig = new AnnotationConfiguration.StdConfiguration(AnnotationInclusion.INCLUDE_BUT_DONT_INHERIT);
216+
return mr.resolve(classType, annConfig, null);
217+
}
218+
219+
@Deprecated
114220
protected static StructFieldDeclaration fromField(java.lang.reflect.Field getter) {
115221
StructFieldDeclaration field = fromMember((Member) getter);
116222
field.desc.field = getter;
@@ -119,6 +225,15 @@ protected static StructFieldDeclaration fromField(java.lang.reflect.Field getter
119225
return field;
120226
}
121227

228+
protected static StructFieldDeclaration fromField(ResolvedField getter) {
229+
StructFieldDeclaration field = fromMember((ResolvedField) getter);
230+
field.desc.field = getter.getRawMember();
231+
field.desc.valueType = getter.getType();
232+
field.valueClass = getter.getType().getErasedType();
233+
return field;
234+
}
235+
236+
@Deprecated
122237
protected static StructFieldDeclaration fromGetter(Method getter) {
123238
StructFieldDeclaration field = fromMember((Member) getter);
124239
field.desc.getter = getter;
@@ -127,6 +242,15 @@ protected static StructFieldDeclaration fromGetter(Method getter) {
127242
return field;
128243
}
129244

245+
protected static StructFieldDeclaration fromGetter(ResolvedMethod getter) {
246+
StructFieldDeclaration field = fromMember((ResolvedMember) getter);
247+
field.desc.getter = getter.getRawMember();
248+
field.desc.valueType = getter.getReturnType();
249+
field.valueClass = getter.getReturnType().getErasedType();
250+
return field;
251+
}
252+
253+
@Deprecated
130254
private static StructFieldDeclaration fromMember(Member member) {
131255
StructFieldDeclaration field = new StructFieldDeclaration();
132256
field.declaringClass = member.getDeclaringClass();
@@ -170,4 +294,47 @@ private static StructFieldDeclaration fromMember(Member member) {
170294
field.desc.isSizeT = isAnnotationPresent(org.bridj.ann.Ptr.class, getter);
171295
return field;
172296
}
297+
298+
private static StructFieldDeclaration fromMember(ResolvedMember<?> member) {
299+
StructFieldDeclaration field = new StructFieldDeclaration();
300+
field.declaringClass = member.getRawMember().getDeclaringClass();
301+
302+
String name = member.getName();
303+
if (name.matches("get[A-Z].*")) {
304+
name = Character.toLowerCase(name.charAt(3)) + name.substring(4);
305+
}
306+
307+
field.desc.name = name;
308+
309+
Field fil = member.get(Field.class);
310+
Bits bits = member.get(Bits.class);
311+
Alignment alignment = member.get(Alignment.class);
312+
Array arr = member.get(Array.class);
313+
if (fil != null) {
314+
field.index = fil.value();
315+
//field.byteOffset = fil.offset();
316+
field.unionWith = fil.unionWith();
317+
}
318+
if (field.unionWith < 0 && field.declaringClass.getAnnotation(Union.class) != null) {
319+
field.unionWith = 0;
320+
}
321+
322+
if (bits != null) {
323+
field.desc.bitLength = bits.value();
324+
}
325+
if (alignment != null) {
326+
field.desc.alignment = alignment.value();
327+
}
328+
if (arr != null) {
329+
long length = 1;
330+
for (long dim : arr.value()) {
331+
length *= dim;
332+
}
333+
field.desc.arrayLength = length;
334+
field.desc.isArray = true;
335+
}
336+
field.desc.isCLong = member.get(org.bridj.ann.CLong.class) != null;
337+
field.desc.isSizeT = member.get(org.bridj.ann.Ptr.class) != null;
338+
return field;
339+
}
173340
}

src/main/java/org/bridj/StructFieldDescription.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
import org.bridj.util.DefaultParameterizedType;
5656
import org.bridj.util.Utils;
5757

58+
import com.fasterxml.classmate.ResolvedType;
59+
5860
/**
5961
* Internal metadata on a struct field
6062
*/
@@ -90,7 +92,12 @@ static Type resolveType(Type tpe, Type structType) {
9092
}
9193

9294
Type ret;
93-
if (tpe instanceof ParameterizedType) {
95+
if (tpe instanceof ResolvedType ) {
96+
ResolvedType rt = (ResolvedType)tpe;
97+
// TODO: what do we do here?
98+
ret = tpe;
99+
}
100+
else if (tpe instanceof ParameterizedType) {
94101
ParameterizedType pt = (ParameterizedType) tpe;
95102
Type[] actualTypeArguments = pt.getActualTypeArguments();
96103
Type[] resolvedActualTypeArguments = new Type[actualTypeArguments.length];
@@ -178,8 +185,18 @@ static StructFieldDescription aggregateDeclarations(Type structType, List<Struct
178185
field.desc.byteLength = Pointer.SIZE;
179186
//field.callIO = CallIO.Utils.createPointerCallIO(field.valueClass, field.desc.valueType);
180187
} else if (Pointer.class.isAssignableFrom(field.valueClass)) {
181-
Type tpe = (field.desc.valueType instanceof ParameterizedType) ? ((ParameterizedType) field.desc.valueType).getActualTypeArguments()[0] : null;
182-
field.desc.nativeTypeOrPointerTargetType = resolveType(tpe, structType);
188+
Type tpe = null;
189+
if( field.desc.valueType instanceof ResolvedType ) {
190+
ResolvedType rt = (ResolvedType)field.desc.valueType;
191+
if( !rt.getTypeParameters().isEmpty() ) {
192+
tpe = rt.getTypeParameters().get(0);
193+
field.desc.nativeTypeOrPointerTargetType = tpe;
194+
}
195+
}
196+
else if(field.desc.valueType instanceof ParameterizedType) {
197+
tpe = ((ParameterizedType) field.desc.valueType).getActualTypeArguments()[0];
198+
field.desc.nativeTypeOrPointerTargetType = resolveType(tpe, structType);
199+
}
183200
if (field.desc.isArray) {
184201
field.desc.byteLength = BridJ.sizeOf(field.desc.nativeTypeOrPointerTargetType);
185202
if (field.desc.alignment < 0)

src/main/java/org/bridj/StructUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ static Pointer<?> fixIntegralTypeIOToMatchLength(Pointer<?> ptr, long byteLength
227227

228228
@SuppressWarnings("deprecation")
229229
protected static void computeStructLayout(StructDescription desc, StructCustomizer customizer) {
230-
List<StructFieldDeclaration> fieldDecls = StructFieldDeclaration.listFields(desc.structClass);
230+
List<StructFieldDeclaration> fieldDecls = StructFieldDeclaration.listFields2(desc.structClass);
231231
orderFields(fieldDecls);
232232

233233
customizer.beforeAggregation(desc, fieldDecls);

src/main/java/org/bridj/util/Utils.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
import java.nio.LongBuffer;
4949
import java.nio.ShortBuffer;
5050

51+
import com.fasterxml.classmate.ResolvedType;
52+
5153
/**
5254
* Miscellaneous utility methods.
5355
*
@@ -162,6 +164,9 @@ public static <T> Class<T> getClass(Type type) {
162164
if (type instanceof Class<?>) {
163165
return (Class<T>) type;
164166
}
167+
if (type instanceof ResolvedType ) {
168+
return (Class<T>)((ResolvedType) type).getErasedType();
169+
}
165170
if (type instanceof ParameterizedType) {
166171
return getClass(((ParameterizedType) type).getRawType());
167172
}

src/main/velocity/org/bridj/PointerIO.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
*/
3131
package org.bridj;
3232

33+
import com.fasterxml.classmate.ResolvedType;
34+
3335
import java.lang.reflect.ParameterizedType;
3436
import java.lang.reflect.Type;
3537
import java.util.*;
@@ -94,6 +96,8 @@ public Type getTargetType() {
9496
static Class<?> getClass(Type type) {
9597
if (type instanceof Class<?>)
9698
return (Class<?>)type;
99+
if (type instanceof ResolvedType)
100+
return ((ResolvedType)type).getErasedType();
97101
if (type instanceof ParameterizedType)
98102
return getClass(((ParameterizedType)type).getRawType());
99103
return null;
@@ -149,20 +153,36 @@ public static <P> PointerIO<P> getInstance(Type type) {
149153
if (type == null)
150154
return null;
151155

152-
PointerIO io = ios.get(type);
156+
PointerIO io = null;
157+
158+
if( type instanceof ResolvedType ) {
159+
io = ios.get(((ResolvedType) type).getErasedType());
160+
}
161+
if( io == null ) {
162+
io = ios.get(type);
163+
}
153164
if (io == null) {
154165
final Class<?> cl = Utils.getClass(type);
155166
if (cl != null) {
156-
if (cl == Pointer.class)
157-
io = getPointerInstance(((ParameterizedType)type).getActualTypeArguments()[0]);
167+
if (cl == Pointer.class) {
168+
if( type instanceof ResolvedType ) {
169+
io = getPointerInstance(((ResolvedType)type).getTypeParameters().get(0));
170+
} else {
171+
io = getPointerInstance(((ParameterizedType)type).getActualTypeArguments()[0]);
172+
}
173+
}
158174
else if (StructObject.class.isAssignableFrom(cl))
159175
io = getInstance(StructIO.getInstance((Class)cl, type));
160176
else if (Callback.class.isAssignableFrom(cl))
161177
io = new CommonPointerIOs.CallbackPointerIO(cl);
162178
else if (NativeObject.class.isAssignableFrom(cl))
163179
io = new CommonPointerIOs.NativeObjectPointerIO(type);
164180
else if (IntValuedEnum.class.isAssignableFrom(cl)) {
165-
if (type instanceof ParameterizedType) {
181+
if (type instanceof ResolvedType) {
182+
ResolvedType enumType = ((ResolvedType)type).getTypeParameters().get(0);
183+
io = new CommonPointerIOs.IntValuedEnumPointerIO(enumType.getErasedType());
184+
}
185+
else if (type instanceof ParameterizedType) {
166186
Type enumType = ((ParameterizedType)type).getActualTypeArguments()[0];
167187
if (enumType instanceof Class)
168188
io = new CommonPointerIOs.IntValuedEnumPointerIO((Class)enumType);

0 commit comments

Comments
 (0)