Skip to content

Commit

Permalink
first pass at adding classmate based resolution. Test suite passing.
Browse files Browse the repository at this point in the history
Old code is still present.
  • Loading branch information
ctrimble committed Jan 20, 2017
1 parent 7662f56 commit 07a9235
Show file tree
Hide file tree
Showing 7 changed files with 336 additions and 8 deletions.
167 changes: 167 additions & 0 deletions src/main/java/org/bridj/StructFieldDeclaration.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,31 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.bridj.ann.Alignment;
import org.bridj.ann.Array;
import org.bridj.ann.Bits;
import org.bridj.ann.Field;
import org.bridj.ann.Union;

import com.fasterxml.classmate.AnnotationConfiguration;
import com.fasterxml.classmate.AnnotationInclusion;
import com.fasterxml.classmate.Filter;
import com.fasterxml.classmate.MemberResolver;
import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.classmate.ResolvedTypeWithMembers;
import com.fasterxml.classmate.TypeResolver;
import com.fasterxml.classmate.members.RawField;
import com.fasterxml.classmate.members.RawMethod;
import com.fasterxml.classmate.members.ResolvedField;
import com.fasterxml.classmate.members.ResolvedMember;
import com.fasterxml.classmate.members.ResolvedMethod;

class StructFieldDeclaration {

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

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

return !Modifier.isStatic(modifiers);
}

protected static boolean acceptFieldGetter(ResolvedMember<?> member, boolean getter) {
if ((member instanceof ResolvedMethod) && ((ResolvedMethod) member).getRawMember().getParameterTypes().length != (getter ? 0 : 1)) {
return false;
}

if (member.get(Field.class) == null) {
return false;
}

return !member.isStatic();
}

/**
* Creates a list of structure fields
*/
@Deprecated
protected static List<StructFieldDeclaration> listFields(Class<?> structClass) {
List<StructFieldDeclaration> list = new ArrayList<StructFieldDeclaration>();
for (Method method : structClass.getMethods()) {
if (acceptFieldGetter(method, true)) {
StructFieldDeclaration io = fromGetter(method);
try {
// this only works when the names are equal, does not support setXXX methods.
Method setter = structClass.getMethod(method.getName(), io.valueClass);
if (acceptFieldGetter(setter, false)) {
io.setter = setter;
Expand Down Expand Up @@ -110,7 +142,81 @@ protected static List<StructFieldDeclaration> listFields(Class<?> structClass) {

return list;
}

protected static List<StructFieldDeclaration> listFields2(Class<?> structClass) {
List<StructFieldDeclaration> list = new ArrayList<StructFieldDeclaration>();
ResolvedTypeWithMembers resolvedStruct = resolveType(structClass);
for (ResolvedMethod method : resolvedStruct.getMemberMethods()) {
if (acceptFieldGetter(method, true)) {
StructFieldDeclaration io = fromGetter(method);
try {
// this only works when the names are equal, does not support setXXX methods.
ResolvedMethod setter = getMethod( resolvedStruct.getMemberMethods(), method.getName(), io.valueClass);
if (acceptFieldGetter(setter, false)) {
io.setter = setter.getRawMember();
}
} catch (Exception ex) {
//assert BridJ.info("No setter for getter " + method);
}
if (io != null) {
list.add(io);
}
}
}

int nFieldFields = 0;
for ( ResolvedField field : resolvedStruct.getMemberFields()) {
if (acceptFieldGetter(field, true)) {
StructFieldDeclaration io = StructFieldDeclaration.fromField(field);
if (io != null) {
list.add(io);
nFieldFields++;
}
}
}
if (nFieldFields > 0 && BridJ.warnStructFields) {
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.");
}

return list;
}

public static ResolvedMethod getMethod( ResolvedMethod[] methods, String name, Class<?>... params ) {
METHODS: for( ResolvedMethod method : methods ) {
if( !name.equals(method.getName()) ) continue METHODS;
if( params.length != method.getArgumentCount()) continue METHODS;
for( int i = 0; i < params.length; i++ ) {
if( !method.getArgumentType(i).isInstanceOf(params[i])) continue METHODS;
}
return method;
}
return null;
}

protected static String nameForMember( ResolvedMember<?> member ) {
String name = member.getName();
if (name.matches("get[A-Z].*")) {
return Character.toLowerCase(name.charAt(3)) + name.substring(4);
} else if ( name.matches("set[A-Z].*")) {
return Character.toLowerCase(name.charAt(3)) + name.substring(4);
} else {
return name;
}
}

protected static ResolvedTypeWithMembers resolveType( Class<?> structClass ) {
TypeResolver resolver = new TypeResolver();
ResolvedType classType = resolver.resolve(structClass);
MemberResolver mr = new MemberResolver(resolver);
mr.setMethodFilter(method->
method.getRawMember().getParameterTypes().length < 2 &&
!method.isStatic());
mr.setFieldFilter(field->!field.isStatic());
AnnotationConfiguration annConfig = new AnnotationConfiguration.StdConfiguration(AnnotationInclusion.INCLUDE_BUT_DONT_INHERIT);
return mr.resolve(classType, annConfig, null);
}

@Deprecated
protected static StructFieldDeclaration fromField(java.lang.reflect.Field getter) {
StructFieldDeclaration field = fromMember((Member) getter);
field.desc.field = getter;
Expand All @@ -119,6 +225,15 @@ protected static StructFieldDeclaration fromField(java.lang.reflect.Field getter
return field;
}

protected static StructFieldDeclaration fromField(ResolvedField getter) {
StructFieldDeclaration field = fromMember((ResolvedField) getter);
field.desc.field = getter.getRawMember();
field.desc.valueType = getter.getType();
field.valueClass = getter.getType().getErasedType();
return field;
}

@Deprecated
protected static StructFieldDeclaration fromGetter(Method getter) {
StructFieldDeclaration field = fromMember((Member) getter);
field.desc.getter = getter;
Expand All @@ -127,6 +242,15 @@ protected static StructFieldDeclaration fromGetter(Method getter) {
return field;
}

protected static StructFieldDeclaration fromGetter(ResolvedMethod getter) {
StructFieldDeclaration field = fromMember((ResolvedMember) getter);
field.desc.getter = getter.getRawMember();
field.desc.valueType = getter.getReturnType();
field.valueClass = getter.getReturnType().getErasedType();
return field;
}

@Deprecated
private static StructFieldDeclaration fromMember(Member member) {
StructFieldDeclaration field = new StructFieldDeclaration();
field.declaringClass = member.getDeclaringClass();
Expand Down Expand Up @@ -170,4 +294,47 @@ private static StructFieldDeclaration fromMember(Member member) {
field.desc.isSizeT = isAnnotationPresent(org.bridj.ann.Ptr.class, getter);
return field;
}

private static StructFieldDeclaration fromMember(ResolvedMember<?> member) {
StructFieldDeclaration field = new StructFieldDeclaration();
field.declaringClass = member.getRawMember().getDeclaringClass();

String name = member.getName();
if (name.matches("get[A-Z].*")) {
name = Character.toLowerCase(name.charAt(3)) + name.substring(4);
}

field.desc.name = name;

Field fil = member.get(Field.class);
Bits bits = member.get(Bits.class);
Alignment alignment = member.get(Alignment.class);
Array arr = member.get(Array.class);
if (fil != null) {
field.index = fil.value();
//field.byteOffset = fil.offset();
field.unionWith = fil.unionWith();
}
if (field.unionWith < 0 && field.declaringClass.getAnnotation(Union.class) != null) {
field.unionWith = 0;
}

if (bits != null) {
field.desc.bitLength = bits.value();
}
if (alignment != null) {
field.desc.alignment = alignment.value();
}
if (arr != null) {
long length = 1;
for (long dim : arr.value()) {
length *= dim;
}
field.desc.arrayLength = length;
field.desc.isArray = true;
}
field.desc.isCLong = member.get(org.bridj.ann.CLong.class) != null;
field.desc.isSizeT = member.get(org.bridj.ann.Ptr.class) != null;
return field;
}
}
23 changes: 20 additions & 3 deletions src/main/java/org/bridj/StructFieldDescription.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
import org.bridj.util.DefaultParameterizedType;
import org.bridj.util.Utils;

import com.fasterxml.classmate.ResolvedType;

/**
* Internal metadata on a struct field
*/
Expand Down Expand Up @@ -90,7 +92,12 @@ static Type resolveType(Type tpe, Type structType) {
}

Type ret;
if (tpe instanceof ParameterizedType) {
if (tpe instanceof ResolvedType ) {
ResolvedType rt = (ResolvedType)tpe;
// TODO: what do we do here?
ret = tpe;
}
else if (tpe instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) tpe;
Type[] actualTypeArguments = pt.getActualTypeArguments();
Type[] resolvedActualTypeArguments = new Type[actualTypeArguments.length];
Expand Down Expand Up @@ -178,8 +185,18 @@ static StructFieldDescription aggregateDeclarations(Type structType, List<Struct
field.desc.byteLength = Pointer.SIZE;
//field.callIO = CallIO.Utils.createPointerCallIO(field.valueClass, field.desc.valueType);
} else if (Pointer.class.isAssignableFrom(field.valueClass)) {
Type tpe = (field.desc.valueType instanceof ParameterizedType) ? ((ParameterizedType) field.desc.valueType).getActualTypeArguments()[0] : null;
field.desc.nativeTypeOrPointerTargetType = resolveType(tpe, structType);
Type tpe = null;
if( field.desc.valueType instanceof ResolvedType ) {
ResolvedType rt = (ResolvedType)field.desc.valueType;
if( !rt.getTypeParameters().isEmpty() ) {
tpe = rt.getTypeParameters().get(0);
field.desc.nativeTypeOrPointerTargetType = tpe;
}
}
else if(field.desc.valueType instanceof ParameterizedType) {
tpe = ((ParameterizedType) field.desc.valueType).getActualTypeArguments()[0];
field.desc.nativeTypeOrPointerTargetType = resolveType(tpe, structType);
}
if (field.desc.isArray) {
field.desc.byteLength = BridJ.sizeOf(field.desc.nativeTypeOrPointerTargetType);
if (field.desc.alignment < 0)
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/bridj/StructUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ static Pointer<?> fixIntegralTypeIOToMatchLength(Pointer<?> ptr, long byteLength

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

customizer.beforeAggregation(desc, fieldDecls);
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/org/bridj/util/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
import java.nio.LongBuffer;
import java.nio.ShortBuffer;

import com.fasterxml.classmate.ResolvedType;

/**
* Miscellaneous utility methods.
*
Expand Down Expand Up @@ -162,6 +164,9 @@ public static <T> Class<T> getClass(Type type) {
if (type instanceof Class<?>) {
return (Class<T>) type;
}
if (type instanceof ResolvedType ) {
return (Class<T>)((ResolvedType) type).getErasedType();
}
if (type instanceof ParameterizedType) {
return getClass(((ParameterizedType) type).getRawType());
}
Expand Down
28 changes: 24 additions & 4 deletions src/main/velocity/org/bridj/PointerIO.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
*/
package org.bridj;

import com.fasterxml.classmate.ResolvedType;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
Expand Down Expand Up @@ -94,6 +96,8 @@ public Type getTargetType() {
static Class<?> getClass(Type type) {
if (type instanceof Class<?>)
return (Class<?>)type;
if (type instanceof ResolvedType)
return ((ResolvedType)type).getErasedType();
if (type instanceof ParameterizedType)
return getClass(((ParameterizedType)type).getRawType());
return null;
Expand Down Expand Up @@ -149,20 +153,36 @@ public static <P> PointerIO<P> getInstance(Type type) {
if (type == null)
return null;

PointerIO io = ios.get(type);
PointerIO io = null;

if( type instanceof ResolvedType ) {
io = ios.get(((ResolvedType) type).getErasedType());
}
if( io == null ) {
io = ios.get(type);
}
if (io == null) {
final Class<?> cl = Utils.getClass(type);
if (cl != null) {
if (cl == Pointer.class)
io = getPointerInstance(((ParameterizedType)type).getActualTypeArguments()[0]);
if (cl == Pointer.class) {
if( type instanceof ResolvedType ) {
io = getPointerInstance(((ResolvedType)type).getTypeParameters().get(0));
} else {
io = getPointerInstance(((ParameterizedType)type).getActualTypeArguments()[0]);
}
}
else if (StructObject.class.isAssignableFrom(cl))
io = getInstance(StructIO.getInstance((Class)cl, type));
else if (Callback.class.isAssignableFrom(cl))
io = new CommonPointerIOs.CallbackPointerIO(cl);
else if (NativeObject.class.isAssignableFrom(cl))
io = new CommonPointerIOs.NativeObjectPointerIO(type);
else if (IntValuedEnum.class.isAssignableFrom(cl)) {
if (type instanceof ParameterizedType) {
if (type instanceof ResolvedType) {
ResolvedType enumType = ((ResolvedType)type).getTypeParameters().get(0);
io = new CommonPointerIOs.IntValuedEnumPointerIO(enumType.getErasedType());
}
else if (type instanceof ParameterizedType) {
Type enumType = ((ParameterizedType)type).getActualTypeArguments()[0];
if (enumType instanceof Class)
io = new CommonPointerIOs.IntValuedEnumPointerIO((Class)enumType);
Expand Down
Loading

0 comments on commit 07a9235

Please sign in to comment.