12 messages in net.java.dev.jna.usersRe: [jna-users] Generics...
FromSent OnAttachments
Paul LoyJul 2, 2008 5:23 am 
Timothy WallJul 2, 2008 7:13 am 
Timothy WallJul 2, 2008 7:16 am 
Paul LoyJul 2, 2008 7:18 am 
Paul LoyAug 7, 2008 8:26 am 
Timothy WallAug 7, 2008 10:21 am 
Paul LoyAug 14, 2008 3:18 am 
Timothy WallAug 19, 2008 7:29 am 
Paul LoyAug 19, 2008 7:53 am 
Timothy WallAug 19, 2008 8:01 am 
Alex Lam S.L.Aug 19, 2008 10:03 am 
Wayne MeissnerAug 19, 2008 5:32 pm 
Actions with this message:
Paste this link in email or IM:
Paste this link in email or IM:
Atom feed for this thread
Paste this URL into your reader:
Subject:Re: [jna-users] Generics...Actions...
From:Paul Loy (kete@gmail.com)
Date:Aug 14, 2008 3:18:59 am
List:net.java.dev.jna.users

Sorry, I was talking about something similar to this:

public class GProperty<T> extends Structure implements ByReference {

public String propertyName; public T propertyData;

... }

I would like to propose a small refactor of Structure to allow us to override certain defaults. For this generic case I would like to refactor calculateSize(boolean force) as such:

int calculateSize(boolean force) { // TODO: maybe cache this information on a per-class basis // so that we don't have to re-analyze this static information each // time a struct is allocated.

structAlignment = 1; int calculatedSize = 0; Field[] fields = getClass().getFields(); // Restrict to valid fields List flist = new ArrayList(); for (int i=0;i < fields.length;i++) { int modifiers = fields[i].getModifiers(); if (Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) continue; flist.add(fields[i]); } fields = (Field[])flist.toArray(new Field[flist.size()]);

if (REVERSE_FIELDS) { for (int i=0;i < fields.length/2;i++) { int idx = fields.length-1-i; Field tmp = fields[i]; fields[i] = fields[idx]; fields[idx] = tmp; } } else if (REQUIRES_FIELD_ORDER) { List fieldOrder = getFieldOrder(); if (fieldOrder.size() < fields.length) { if (force) { throw new Error("This VM does not store fields in a predictable order; you must use setFieldOrder: " + System.getProperty("java.vendor") + ", " + System.getProperty("java.version")); } return CALCULATE_SIZE; } sortFields(fields, (String[])fieldOrder.toArray(new String[fieldOrder.size()])); }

for (int i=0; i<fields.length; i++) { Field field = fields[i]; int modifiers = field.getModifiers();

Class type = field.getType(); StructField structField = new StructField(); structField.isVolatile = Modifier.isVolatile(modifiers); structField.field = field; if (Modifier.isFinal(modifiers)) { field.setAccessible(true); } structField.name = field.getName(); structField.type = type;

// Check for illegal field types if (Callback.class.isAssignableFrom(type) && !type.isInterface()) { throw new IllegalArgumentException("Structure Callback field '" + field.getName() + "' must be an interface"); } if (type.isArray() && Structure.class.equals(type.getComponentType())) { String msg = "Nested Structure arrays must use a " + "derived Structure type so that the size of " + "the elements can be determined"; throw new IllegalArgumentException(msg); }

int fieldAlignment = 1; if (!Modifier.isPublic(field.getModifiers())) continue;

Object value = getField(structField); if (value == null) { if (Structure.class.isAssignableFrom(type) && !(ByReference.class.isAssignableFrom(type))) { try { value = newInstance(type); setField(structField, value); } catch(IllegalArgumentException e) { String msg = "Can't determine size of nested structure: " + e.getMessage(); throw new IllegalArgumentException(msg); } } else if (type.isArray()) { // can't calculate size yet, defer until later if (force) { throw new IllegalStateException("Array fields must be initialized"); } return CALCULATE_SIZE; } } Class nativeType = assignNativeMapper(type, value, field, structField);

structField.size = getNativeSize(nativeType, value); fieldAlignment = getNativeAlignment(nativeType, value, i==0);

// Align fields as appropriate structAlignment = Math.max(structAlignment, fieldAlignment); if ((calculatedSize % fieldAlignment) != 0) { calculatedSize += fieldAlignment - (calculatedSize % fieldAlignment); } structField.offset = calculatedSize; calculatedSize += structField.size;

// Save the field in our list structFields.put(structField.name, structField); }

if (calculatedSize > 0) { return calculateAlignedSize(calculatedSize); }

throw new IllegalArgumentException("Structure " + getClass() + " has unknown size (ensure " + "all fields are public)"); }

protected Class assignNativeMapper(Class type, Object value, Field field, StructField structField) { Class nativeType = type;

if (NativeMapped.class.isAssignableFrom(type)) { NativeMappedConverter tc = NativeMappedConverter.getInstance(type); if (value == null) { value = tc.defaultValue(); setField(structField, value); } nativeType = tc.nativeType(); structField.writeConverter = tc; structField.readConverter = tc; structField.context = new StructureReadContext(this, field); } else if (typeMapper != null) { ToNativeConverter writeConverter = typeMapper.getToNativeConverter(type); FromNativeConverter readConverter = typeMapper.getFromNativeConverter(type); if (writeConverter != null && readConverter != null) { value = writeConverter.toNative(value, new StructureWriteContext(this, structField.field)); nativeType = value != null ? value.getClass() : Pointer.class; structField.writeConverter = writeConverter; structField.readConverter = readConverter; structField.context = new StructureReadContext(this, field); } else if (writeConverter != null || readConverter != null) { String msg = "Structures require bidirectional type conversion for " + type; throw new IllegalArgumentException(msg); } } return nativeType; }

this would then allow me to create a generic superclass of Structure that could handle generics by overriding assignNativeMapper. I would be happy to put that back in to JNA if any one else would find it useful.

Paul.

On Thu, Aug 7, 2008 at 6:22 PM, Timothy Wall <twal@dev.java.net> wrote:

On Aug 7, 2008, at 11:26 AM, Paul Loy wrote:

Hi Timothy,

Except... because a 'vanilla' instance of the nativemapped class is created by Structure (well by NativeMappedConverter.getInstance(type)). This means that we do not have the generic type applied so it tries to map to Object rather than Integer (for example if GProperty<Integer> were used). I guess I don't understand why when the data type extends NativeMapped does it then create a new instance? Why not use the instance we now have?

Can you be more specific about what code you're referring to?