samedi 17 juin 2017

Field.set throws IllegalArgumentException

I'm trying to do one-way data binding in java for swing objects, just as an exercise. Currently for swing objects that extend JTextComponent, I add a document listener that also updates the backing data storage.

public class Binder {

Map<JComponent, Map.Entry<WeakReference, Field>> map = new WeakHashMap<>();
AutoDocumentListener adl;

public Binder() {
    adl = new AutoDocumentListener();
}

public void bind(Object instance, String varName, JComponent element, String property) {
    Field field;
    try {
        field = instance.getClass().getDeclaredField(varName);
        field.setAccessible(true);
        map.put(element,
                new AbstractMap.SimpleEntry<WeakReference, Field>(new WeakReference(instance), field));

        if (element instanceof JTextComponent) {
            element = (JTextComponent) element;
            Document eldoc = ((JTextComponent) element).getDocument();
            eldoc.putProperty("origin", element);

            eldoc.addDocumentListener(adl);
        } else {  }
    } catch (NoSuchFieldException | SecurityException ex) {
        Logger.getLogger(Binder.class.getName()).log(Level.SEVERE, null, ex);
    }
 }

 class AutoDocumentListener implements DocumentListener {

    @Override
    public void insertUpdate(DocumentEvent evt) {
        JTextComponent jc = (JTextComponent) evt.getDocument().getProperty("origin");
        Map.Entry<WeakReference, Field> dataToUpdate = map.get(jc);
        if (dataToUpdate != null) {
            try {
                Object data = jc.getText();
                dataToUpdate.getValue().set(dataToUpdate.getKey(), data);
            } catch (IllegalArgumentException | IllegalAccessException ex) {
                Logger.getLogger(Binder.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    @Override
    public void removeUpdate(DocumentEvent evt) {
    }
    @Override
    public void changedUpdate(DocumentEvent e) {
    }
  }
}

The problem is, at the following line I get a IllegalArgumentException:

dataToUpdate.getValue().set(dataToUpdate.getKey(), data);

java.lang.IllegalArgumentException: Can not set java.lang.String field org.jbind.test.TestClass.data to java.lang.ref.WeakReference

As far as I can see in the docs, the call to Field.set is correct. So, I don't understand what's going wrong.

I call the function with the following code:

public class TestClass {
public String data = "Text1";

public void init() {
    Binder binder = new Binder();

    JTextField jtf = new JTextField(data);
    binder.bind(this, "data", jtf, "");
    jtf.setText("Text2");
    System.out.println(data);
}

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            new TestClass().init();
        }
    });

  }
}





Aucun commentaire:

Enregistrer un commentaire