Access Processing PConstants dynamically using reflection

Processing has a large collection of constants defined in the interface PConstants (API) (code). For people trying to read a list of available constants and their values, this can be done by simply reading the API and the source code above.

Recently I have seen several discussions of how to access these constants programmatically (e.g. request a list at runtime, rather than hand-code constants explicitly by name). Examples of these discussions have included the Processing.r mode project @gaocegege and in a recent Processing github issue @Stanlepunk.

If you need to retrieve constants dynamically for some reason, you can do this using Java reflection and the Field object (tutorial) (API).

In order to print out console output like this...:

...
float MAX_FLOAT = 3.4028235E38;
float MIN_FLOAT = -3.4028235E38;
int MAX_INT = 2147483647;
int MIN_INT = -2147483648;
int VERTEX = 0;
int BEZIER_VERTEX = 1;
int QUADRATIC_VERTEX = 2;
...

...here is a sketch that iterates over all the Fields in PConstants, using reflection and an array of Field objects:

import java.lang.reflect.Field;

ClassList pcList = new ClassList(PConstants.class);

void setup() {
  for(String s: pcList.list()){
    println(s);
  }
 exit();
}

class ClassList {
  Field[] classFields; 
  ClassList(Class c){
    classFields = c.getFields();
  }
  ArrayList<String> list() {
    ArrayList<String> slist = new ArrayList();
    // for each constant
    for (Field f : classFields) {
      String s = "";
      // object type
      s = s + "(" + f.getType() + ")";
      // field name
      s = s + " " + f.getName();
      // value
      try {
        s = s + ": " + f.get(null);
      } 
      catch (IllegalAccessException e) {
      }
      // Optional special handling for field types:
      if (f.getType().equals(int.class)) {
        // ...
      }
      if (f.getType().equals(float.class)) {
        // ...
      }
      slist.add(s);
    }
    return(slist);
  }
}

Rather than mapping each constant manually (which will break if Processing updates the PConstants interface), the sketch requests a list of fields with getFields() and then iterates over them to retrieve the type, name, and value of each.

This sketch will work with other interfaces as well. For example, changing the declaration line to PSurface...:

ClassList pcList = new ClassList(PSurface.class);

...outputs:

int MIN_WINDOW_WIDTH = 128;
int MIN_WINDOW_HEIGHT = 128;

A "gotcha" for me in writing the sketch was that retrieving the value with Field.get() must be wrapped in a try/catch block in order to handle a potential IllegalAccessException.

For more background on this, see:

Sign In or Register to comment.