
import java.awt.*;
import java.awt.image.BufferedImage;
import java.beans.*;
import java.lang.reflect.Method;
import javax.swing.*;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.tree.DefaultTreeCellRenderer;


public class BoundTest {

    private static class Listener implements PropertyChangeListener {

        @Override
        public void propertyChange(PropertyChangeEvent e) {
            System.out.println(">>> LISTENER: " + e.getPropertyName() + " changed");
        }
    }

    private final Listener LISTENER = new Listener();

    private Icon getIcon() {

        Image img = new BufferedImage(20, 20, BufferedImage.TYPE_INT_RGB);
        Graphics g = img.getGraphics();
        g.setColor(Color.red);
        g.fillRect(0, 0, 20, 20);
        g.dispose();
        return new ImageIcon(img);
    }

    private void checkIfBound(Class<?> c) throws NoSuchMethodException {

        Method m = c.getMethod("setIcon", Icon.class);
        if (m.isAnnotationPresent(BeanProperty.class)) {
            BeanProperty p = (BeanProperty) m.getAnnotation(BeanProperty.class);
            System.out.println("\n" + c.getSimpleName() + ": bound = " + p.bound());
        }
    }

    private void test1() throws NoSuchMethodException {

        JLabel l = new JLabel();
        checkIfBound(l.getClass());
        l.addPropertyChangeListener(LISTENER);
        l.setIcon(getIcon());
    }


    private void test2() throws NoSuchMethodException {

        JLabel l = new BasicComboBoxRenderer();
        checkIfBound(l.getClass());
        l.addPropertyChangeListener(LISTENER);
        l.setIcon(getIcon());
    }

    private void test3() throws NoSuchMethodException {

        JLabel l = new DefaultListCellRenderer();
        checkIfBound(l.getClass());
        l.addPropertyChangeListener(LISTENER);
        l.setIcon(getIcon());
    }

    private void test4() throws NoSuchMethodException {

        JLabel l = new DefaultTableCellRenderer();
        checkIfBound(l.getClass());
        l.addPropertyChangeListener(LISTENER);
        l.setIcon(getIcon());
    }

    private void test5() throws NoSuchMethodException {

        JLabel l = new DefaultTreeCellRenderer();
        checkIfBound(l.getClass());
        l.addPropertyChangeListener(LISTENER);
        l.setIcon(getIcon());
    }

    public static void main(String[] args) throws NoSuchMethodException {

        BoundTest test = new BoundTest();
        test.test1();
        test.test2();
        test.test3();
        test.test4();
        test.test5();
    }
}
