Skip to content

Commit bc06358

Browse files
committed
first pass at adding classmate based resolution. Most tests passing in suite.
1 parent 8f8db3d commit bc06358

7 files changed

Lines changed: 371 additions & 7 deletions

File tree

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

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,36 @@
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();
5168
Method setter;
69+
ResolvedMember resolvedSetter;
5270
long index = -1, unionWith = -1;//, byteOffset = -1;
5371
Class<?> valueClass;
5472
Class<?> declaringClass;
@@ -58,6 +76,7 @@ public String toString() {
5876
return desc.name + " (index = " + index + (unionWith < 0 ? "" : ", unionWith = " + unionWith) + ", desc = " + desc + ")";
5977
}
6078

79+
@Deprecated
6180
protected static boolean acceptFieldGetter(Member member, boolean getter) {
6281
if ((member instanceof Method) && ((Method) member).getParameterTypes().length != (getter ? 0 : 1)) {
6382
return false;
@@ -71,16 +90,30 @@ protected static boolean acceptFieldGetter(Member member, boolean getter) {
7190

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

75106
/**
76107
* Creates a list of structure fields
77108
*/
109+
@Deprecated
78110
protected static List<StructFieldDeclaration> listFields(Class<?> structClass) {
79111
List<StructFieldDeclaration> list = new ArrayList<StructFieldDeclaration>();
80112
for (Method method : structClass.getMethods()) {
81113
if (acceptFieldGetter(method, true)) {
82114
StructFieldDeclaration io = fromGetter(method);
83115
try {
116+
// this only works when the names are equal, does not support setXXX methods.
84117
Method setter = structClass.getMethod(method.getName(), io.valueClass);
85118
if (acceptFieldGetter(setter, false)) {
86119
io.setter = setter;
@@ -110,7 +143,123 @@ protected static List<StructFieldDeclaration> listFields(Class<?> structClass) {
110143

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

168+
int nFieldFields = 0;
169+
for ( ResolvedField field : resolvedStruct.getMemberFields()) {
170+
if (acceptFieldGetter(field, true)) {
171+
StructFieldDeclaration io = StructFieldDeclaration.fromField(field);
172+
if (io != null) {
173+
list.add(io);
174+
nFieldFields++;
175+
}
176+
}
177+
}
178+
if (nFieldFields > 0 && BridJ.warnStructFields) {
179+
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.");
180+
}
181+
182+
return list;
183+
}
184+
185+
public static ResolvedMethod getMethod( ResolvedMethod[] methods, String name, Class<?>... params ) {
186+
METHODS: for( ResolvedMethod method : methods ) {
187+
if( !name.equals(method.getName()) ) continue METHODS;
188+
if( params.length != method.getArgumentCount()) continue METHODS;
189+
for( int i = 0; i < params.length; i++ ) {
190+
if( !method.getArgumentType(i).isInstanceOf(params[i])) continue METHODS;
191+
}
192+
return method;
193+
}
194+
return null;
195+
}
196+
197+
protected static String nameForMember( ResolvedMember<?> member ) {
198+
String name = member.getName();
199+
if (name.matches("get[A-Z].*")) {
200+
return Character.toLowerCase(name.charAt(3)) + name.substring(4);
201+
} else if ( name.matches("set[A-Z].*")) {
202+
return Character.toLowerCase(name.charAt(3)) + name.substring(4);
203+
} else {
204+
return name;
205+
}
206+
}
207+
208+
protected static ResolvedTypeWithMembers resolveType( Class<?> structClass ) {
209+
TypeResolver resolver = new TypeResolver();
210+
ResolvedType classType = resolver.resolve(structClass);
211+
MemberResolver mr = new MemberResolver(resolver);
212+
mr.setMethodFilter(new Filter<RawMethod>() {
213+
@Override
214+
public boolean include( RawMethod method ) {
215+
return
216+
method.getRawMember().getParameterTypes().length < 2 &&
217+
!method.isStatic();
218+
}
219+
});
220+
mr.setFieldFilter(new Filter<RawField>() {
221+
@Override
222+
public boolean include( RawField field ) {
223+
return !field.isStatic();
224+
}
225+
});
226+
AnnotationConfiguration annConfig = new AnnotationConfiguration.StdConfiguration(AnnotationInclusion.INCLUDE_BUT_DONT_INHERIT);
227+
return mr.resolve(classType, annConfig, null);
228+
}
229+
230+
protected static <T extends Member> void updateDecl(StructFieldDeclaration decl, ResolvedMember<T> member ) {
231+
decl.declaringClass = member.getRawMember().getDeclaringClass();
232+
Field field = member.get(Field.class);
233+
Bits bits = member.get(Bits.class);
234+
Alignment alignment = member.get(Alignment.class);
235+
Array arr = member.get(Array.class);
236+
237+
if( field != null ) {
238+
decl.index = field.value();
239+
decl.unionWith = field.unionWith();
240+
}
241+
if( decl.unionWith < 0 && decl.declaringClass.getAnnotation(Union.class) != null) {
242+
decl.unionWith = 0;
243+
}
244+
if( bits != null ) {
245+
decl.desc.bitLength = bits.value();
246+
}
247+
if( alignment != null ) {
248+
decl.desc.alignment = alignment.value();
249+
}
250+
if( arr != null ) {
251+
long length = 1;
252+
for (long dim : arr.value()) {
253+
length *= dim;
254+
}
255+
decl.desc.arrayLength = length;
256+
decl.desc.isArray = true;
257+
}
258+
decl.desc.isCLong = member.get(org.bridj.ann.CLong.class) != null;
259+
decl.desc.isSizeT = member.get(org.bridj.ann.Ptr.class) != null;
260+
}
261+
262+
@Deprecated
114263
protected static StructFieldDeclaration fromField(java.lang.reflect.Field getter) {
115264
StructFieldDeclaration field = fromMember((Member) getter);
116265
field.desc.field = getter;
@@ -119,6 +268,15 @@ protected static StructFieldDeclaration fromField(java.lang.reflect.Field getter
119268
return field;
120269
}
121270

271+
protected static StructFieldDeclaration fromField(ResolvedField getter) {
272+
StructFieldDeclaration field = fromMember((ResolvedField) getter);
273+
field.desc.field = getter.getRawMember();
274+
field.desc.valueType = getter.getType();
275+
field.valueClass = getter.getType().getErasedType();
276+
return field;
277+
}
278+
279+
@Deprecated
122280
protected static StructFieldDeclaration fromGetter(Method getter) {
123281
StructFieldDeclaration field = fromMember((Member) getter);
124282
field.desc.getter = getter;
@@ -127,6 +285,15 @@ protected static StructFieldDeclaration fromGetter(Method getter) {
127285
return field;
128286
}
129287

288+
protected static StructFieldDeclaration fromGetter(ResolvedMethod getter) {
289+
StructFieldDeclaration field = fromMember((ResolvedMember) getter);
290+
field.desc.getter = getter.getRawMember();
291+
field.desc.valueType = getter.getReturnType();
292+
field.valueClass = getter.getReturnType().getErasedType();
293+
return field;
294+
}
295+
296+
@Deprecated
130297
private static StructFieldDeclaration fromMember(Member member) {
131298
StructFieldDeclaration field = new StructFieldDeclaration();
132299
field.declaringClass = member.getDeclaringClass();
@@ -170,4 +337,47 @@ private static StructFieldDeclaration fromMember(Member member) {
170337
field.desc.isSizeT = isAnnotationPresent(org.bridj.ann.Ptr.class, getter);
171338
return field;
172339
}
340+
341+
private static StructFieldDeclaration fromMember(ResolvedMember<?> member) {
342+
StructFieldDeclaration field = new StructFieldDeclaration();
343+
field.declaringClass = member.getRawMember().getDeclaringClass();
344+
345+
String name = member.getName();
346+
if (name.matches("get[A-Z].*")) {
347+
name = Character.toLowerCase(name.charAt(3)) + name.substring(4);
348+
}
349+
350+
field.desc.name = name;
351+
352+
Field fil = member.get(Field.class);
353+
Bits bits = member.get(Bits.class);
354+
Alignment alignment = member.get(Alignment.class);
355+
Array arr = member.get(Array.class);
356+
if (fil != null) {
357+
field.index = fil.value();
358+
//field.byteOffset = fil.offset();
359+
field.unionWith = fil.unionWith();
360+
}
361+
if (field.unionWith < 0 && field.declaringClass.getAnnotation(Union.class) != null) {
362+
field.unionWith = 0;
363+
}
364+
365+
if (bits != null) {
366+
field.desc.bitLength = bits.value();
367+
}
368+
if (alignment != null) {
369+
field.desc.alignment = alignment.value();
370+
}
371+
if (arr != null) {
372+
long length = 1;
373+
for (long dim : arr.value()) {
374+
length *= dim;
375+
}
376+
field.desc.arrayLength = length;
377+
field.desc.isArray = true;
378+
}
379+
field.desc.isCLong = member.get(org.bridj.ann.CLong.class) != null;
380+
field.desc.isSizeT = member.get(org.bridj.ann.Ptr.class) != null;
381+
return field;
382+
}
173383
}

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: 16 additions & 3 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;
@@ -153,16 +157,25 @@ public static <P> PointerIO<P> getInstance(Type type) {
153157
if (io == null) {
154158
final Class<?> cl = Utils.getClass(type);
155159
if (cl != null) {
156-
if (cl == Pointer.class)
157-
io = getPointerInstance(((ParameterizedType)type).getActualTypeArguments()[0]);
160+
if (cl == Pointer.class) {
161+
if( type instanceof ResolvedType ) {
162+
io = getPointerInstance(((ResolvedType)type).getTypeParameters().get(0));
163+
} else {
164+
io = getPointerInstance(((ParameterizedType)type).getActualTypeArguments()[0]);
165+
}
166+
}
158167
else if (StructObject.class.isAssignableFrom(cl))
159168
io = getInstance(StructIO.getInstance((Class)cl, type));
160169
else if (Callback.class.isAssignableFrom(cl))
161170
io = new CommonPointerIOs.CallbackPointerIO(cl);
162171
else if (NativeObject.class.isAssignableFrom(cl))
163172
io = new CommonPointerIOs.NativeObjectPointerIO(type);
164173
else if (IntValuedEnum.class.isAssignableFrom(cl)) {
165-
if (type instanceof ParameterizedType) {
174+
if (type instanceof ResolvedType) {
175+
ResolvedType enumType = ((ResolvedType)type).getTypeParameters().get(0);
176+
io = new CommonPointerIOs.IntValuedEnumPointerIO(enumType.getErasedType());
177+
}
178+
else if (type instanceof ParameterizedType) {
166179
Type enumType = ((ParameterizedType)type).getActualTypeArguments()[0];
167180
if (enumType instanceof Class)
168181
io = new CommonPointerIOs.IntValuedEnumPointerIO((Class)enumType);

0 commit comments

Comments
 (0)