Setting a class field array via reflection

Hello once again.

The pipeline I’m developing uses a csv file to drive the animations. I’ve hit a stumbling block: I’d like to be able to parse a string into a class’s float array field using reflection. I feel like I’m close, but I’m not there yet. Here’s the stripped down logic:

import java.lang.reflect.*;
import java.util.Arrays;

String tester = "radii:{1.0, 2.0, 3.0}"; 

Tmp tmp = new Tmp();

void setup(){  

    String[] field_vals = splitTokens(tester, ":");
    
    String attr = field_vals[0];
    String[] vals = splitTokens(field_vals[1], "{}, ");
    println("attr:",attr);
    printArray(vals);
    
    float[] fa = new float[vals.length];
    for (int cnt=0; cnt<vals.length; cnt++){
      fa[cnt] = Float.parseFloat(vals[cnt]);
    }
    printArray(fa);
    
    try {
        Field field = tmp.getClass().getDeclaredField(attr);
        field.set(attr, fa); 
        // or this? ...see link below...
        //field.set(t, values.toArray(Array.newInstance(field.getType().getComponentType(), values.size()));
    } catch (NoSuchFieldException e) { println(tmp.getClass()," has no field ",field_vals[0]);
    } catch (Exception e) { throw new IllegalStateException(e); }

    tmp.printFields();
}

class Tmp {
  float[] radii;
  
  Tmp(){} 
  
  void printFields(){
    println("TMP: radii: ",radii);
  }
}

I came across something that looked like a solution, but I can’t get it to work.

Any help appreciated! Thank you.

1 Like
  final float[] arr;

  try {
    final Field f = tmp.getClass().getDeclaredField(attr);
    f.setAccessible(true);
    arr = (float[]) f.get(tmp);
  } 
  catch (final ReflectiveOperationException e) { 
    throw new RuntimeException(e);
  }

  println(arr);
  exit();
}
1 Like

Thank you for the quick response, GTL!

However, I’m not understanding how this sets tmp.radii to the float array… This just sets arr to null within the local scope of the try block…

B/c the moment it reads the field Tmp::radii it is still null! :roll_eyes:
How about instantiating the array right way inside class Tmp? :bulb:

class Tmp {
  static final int RADII = 3;
  final float[] radii = new float[RADII];
}

B/c the moment it reads the field Tmp:: radii it is still null ! :roll_eyes:

Of course… :face_with_raised_eyebrow: That’s why I don’t understand your solution.

But that’s exactly half of the problem I’m facing: I don’t know how large my array is until I obtain the string from the csv. The other half is setting the array to the values contained in the string.

The goal is to set the radii float array from an external string without knowing its size. The string also contains the name of the class to be instantiated. That’s why I need to use reflection.

  final float[] arr = float(vals);;

  try {
    final Field f = tmp.getClass().getDeclaredField(attr);
    f.setAccessible(true);
    f.set(tmp, arr);
    println(f.get(tmp));
  } 
  catch (final ReflectiveOperationException e) { 
    throw new RuntimeException(e);
  }

  exit();
}
2 Likes

That pretty much replicates my original code, except that I didn’t know I could just assign vals to arr by simply recasting them (instead of going through my original loop). :grinning:

The reason for posting my question is that this doesn’t work for me. When I run this I get the exception java.lang.IllegalArgumentException: Can not set [F field sketch_18209b$Tmp.radii to java.lang.String.

I don’t understand why I get this exception, and I don’t know how to solve it. :confounded:

Actually… it does work!

I read the exception more carefully… how could it think I was trying to assign a string to the float array?

D’OH! Because I was using the wrong parm in field.set()!

I was passing in the attr as the first parm, not the class. :crazy_face: I’ll blame my oversight on tiredness and age.

// wrongBad: field.set(attr, arr);
field.set(tmp, arr); // rightGood

Sorry for distracting you from your other matters. Thank you again, GTL, for your customary willingness to help someone in need!

1 Like