SwingMetawidget, value not getting bound to JComboBox

108 Views Asked by At

I am using SwingMetawidget. My data structure has a Person class and one of the properties is a Title which is also a class with a Many To One relationship from Person to Title. I am trying to get a JComboBox in the MetaWidget with the value of the Title bound. I am getting the list of values I specify through the lookup, but the value in the inspection object is not getting selected in the Edit Mode. In the Read Only mode, the right value is displayed (I have set up a converter from Title to String).

My code is below. What am I missing?

Read Only Mode where Title is displayed:

enter image description here

Edit Mode, but the value "Mr" not selected:

enter image description here

Edit Mode, All lookup values displayed:

enter image description here

Main Class:

public class MetaWidgetFrame extends JFrame {

    private JPanel contentPane;
    private SwingMetawidget metawidget = new SwingMetawidget();
    private JPanel contentPanel;
    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    MetaWidgetFrame frame = new MetaWidgetFrame();
                    frame.setVisible(true);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public MetaWidgetFrame() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 473, 281);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPane);

        contentPanel = new JPanel();
        contentPane.add(contentPanel, BorderLayout.CENTER);

        JPanel controlsPanel = new JPanel();
        contentPanel.setLayout(new BorderLayout(0, 0));

        contentPane.add(controlsPanel, BorderLayout.SOUTH);

        JButton btnSave = new JButton("Save");
        btnSave.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                savePerson();
            }
        });
        controlsPanel.add(btnSave);


        // Set up the objects 
        Person person = new Person();
        person.setUserID(new Integer(1));
        person.setFirstName("Raman");
        person.setLastName("C V");

        Title title = new Title();
        title.setTitleId(new Integer(1));
        title.setName("Mr");


        // Configure Inspectors 
        CompositeInspectorConfig inspectorConfig = new CompositeInspectorConfig().setInspectors(
                  new JpaInspector()
                , new PropertyTypeInspector()
                ,new MetawidgetAnnotationInspector()
                );

        BeansBindingProcessorConfig bbpc = new BeansBindingProcessorConfig();

        // Set up the converter from Title to String
        bbpc.setConverter(Title.class, String.class, new Converter<Title,String>() {
            @Override
            public String convertForward(Title title) {
                return title.getName();
            }

            @Override
            public Title convertReverse(String title) {
                if ( title == null || "".equals( title ) ) {
                    return null;
                }
                Title titleObj = new Title(title,null,null,1,1);
                return titleObj;
            }

        });

        BeansBindingProcessor bbp = new BeansBindingProcessor(bbpc);        

        metawidget.setInspector( new CompositeInspector( inspectorConfig ) );
        metawidget.addWidgetProcessor(new ReflectionBindingProcessor());
        metawidget.addWidgetProcessor(bbp);

        GridBagLayoutConfig gbc = new GridBagLayoutConfig();
        gbc.setLabelAlignment(SwingConstants.RIGHT);
        gbc.setRequiredText("");
        gbc.setRequiredAlignment(SwingConstants.RIGHT);
        gbc.setLabelSuffix(": ");
        GridBagLayout gbl = new GridBagLayout(gbc);

        metawidget.setMetawidgetLayout(gbl);

        metawidget.setToInspect(person);

        contentPanel.add(metawidget, BorderLayout.CENTER);

        JXLabel hintLabel = new JXLabel("New label");
        contentPanel.add(hintLabel, BorderLayout.NORTH);
        JGoodiesValidatorProcessorIMPL jgProcessor = new JGoodiesValidatorProcessorIMPL().setHintLabel(hintLabel);      
        metawidget.addWidgetProcessor(jgProcessor);

        //add a component to show validation messages
        JComponent validationResultsComponent = jgProcessor.getValidationResultsComponent();

        JPanel errorsPanel = new JPanel(new BorderLayout(0, 0));
        contentPanel.add(errorsPanel, BorderLayout.SOUTH);
        errorsPanel.add(validationResultsComponent,BorderLayout.CENTER);

        pack();
    }

    public void savePerson() {
        JGoodiesValidatorProcessorIMPL validationProcessor = metawidget.getWidgetProcessor(JGoodiesValidatorProcessorIMPL.class);
        ValidationResult result = validationProcessor.showValidationErrors().getValidationResults();
        if (!result.hasErrors()) {
            metawidget.getWidgetProcessor(BeansBindingProcessor.class).save(metawidget );
            Person personSaved = metawidget.getToInspect();
            System.out.println("" + personSaved);
        }
        pack();
    }
    public JPanel getContentPanel() {
        return contentPanel;
    }
}

Person Class:

@Entity
@Table(name = "person", catalog = "mydb")
public class Person {

    private Integer userID;
    private Title title;
    private String firstName;
    private String lastName;

    public Person() {
    }       

    @Id
    @GeneratedValue(strategy = IDENTITY)

    @Column(name = "userID", unique = true, nullable = false)
    public Integer getUserID() {
        return userID;
    }

    @UiLookup (value={"Mr","Ms","Miss","Mrs"})
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "titleID", nullable = false)
    public Title getTitle() {
        return this.title;
    }

    @Column(name = "firstName", nullable = false, length = 10)
    public String getFirstName() {
        return firstName;
    }

    @UiSection ("Others")
    @Column(name = "lastName", nullable = false, length = 45)
    public String getLastName() {
        return lastName;
    }

    public void setUserID(Integer userID) {
        this.userID = userID;
    }

    public void setTitle(Title title) {
        this.title = title;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return "Person: "
                + "\n userID = " + userID  
                + "\n title = " + title
                + "\n titleID = " + title.getTitleId()                  
                + "\n firstName = " + firstName  
                + "\n lastName = " + lastName;
    }


}

Title Class:

@Entity
@Table(name = "title", catalog = "emisdb")
public class Title implements java.io.Serializable {

    private Integer titleId;
    private String name;
    private Date createdDate;
    private Date modifiedDate;
    private int createdBy;
    private int modifiedBy;
    private Set<User> users = new HashSet<User>(0);

    public Title() {
    }

    @Override
    public String toString() {
        return name;
    }
    public Title(String name, Date createdDate, Date modifiedDate, int createdBy, int modifiedBy) {
        this.name = name;
        this.createdDate = createdDate;
        this.modifiedDate = modifiedDate;
        this.createdBy = createdBy;
        this.modifiedBy = modifiedBy;
    }

    public Title(String name, Date createdDate, Date modifiedDate, int createdBy, int modifiedBy, Set<User> users) {
        this.name = name;
        this.createdDate = createdDate;
        this.modifiedDate = modifiedDate;
        this.createdBy = createdBy;
        this.modifiedBy = modifiedBy;
        this.users = users;
    }

    @Id
    @GeneratedValue(strategy = IDENTITY)

    @Column(name = "titleID", unique = true, nullable = false)
    public Integer getTitleId() {
        return this.titleId;
    }

    public void setTitleId(Integer titleId) {
        this.titleId = titleId;
    }

    @Column(name = "name", nullable = false, length = 4)
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @UiHidden
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "createdDate", nullable = false, length = 19)
    public Date getCreatedDate() {
        return this.createdDate;
    }

    public void setCreatedDate(Date createdDate) {
        this.createdDate = createdDate;
    }

    @UiHidden
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "modifiedDate", nullable = false, length = 19)
    public Date getModifiedDate() {
        return this.modifiedDate;
    }

    public void setModifiedDate(Date modifiedDate) {
        this.modifiedDate = modifiedDate;
    }

    @UiHidden
    @Column(name = "createdBy", nullable = false)
    public int getCreatedBy() {
        return this.createdBy;
    }

    public void setCreatedBy(int createdBy) {
        this.createdBy = createdBy;
    }

    @UiHidden
    @Column(name = "modifiedBy", nullable = false)
    public int getModifiedBy() {
        return this.modifiedBy;
    }
    public void setModifiedBy(int modifiedBy) {
        this.modifiedBy = modifiedBy;
    }

    @UiHidden
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "title")
    public Set<User> getUsers() {
        return this.users;
    }
    public void setUsers(Set<User> users) {
        this.users = users;
    }
}
1

There are 1 best solutions below

1
On BEST ANSWER

Thanks for your interest in Metawidget!

There are a number of general problems with your code, ranging from trivial to conceptually important. None of them are Metawidget problems, per se. I'll try to break them down:

Trivial Problems

In MetaWidgetFrame you create person = new Person() and title = new Title() but you forget to do person.setTitle( title ).

Conceptually Important 1

As your code stands, if you try:

Title title1 = new Title();
title1.setTitleId(new Integer(1));
title1.setName("Mr");

Title title2 = new Title();
title2.setTitleId(new Integer(1));
title2.setName("Mr");

System.out.println( title1 == title1 );       // will return true
System.out.println( title1.equals( title2 )); // will return false

You can see two Title objects, with identical fields, will not match using object equivalence (the equals method). BeansBinding, and most Java technologies, rely on object equivalence. So you need to override both the equals and the hashCode method of Title.

Conceptually Important 2

In your Converter, you are trying to convert a String ('Mr') to a Title object by simply doing:

titleObj = new Title(title,null,null,1,1);

This sets the name to title, but the other fields are either not initialized (null) or initialized to an arbitrary value (1). In particular, the id is not initialized. Depending on how you implement the equals and hashCode methods (see above), this means they will never match the record that comes back from the database.

Conclusion

I fixed all 3 of these and the code works as expected. However your particular implementation will vary. In particular you probably need to do a database lookup in your Converter. Or, ideally, do a database lookup once per session and cache the list of title objects.

As an aside, having a OneToMany on Title might be over-normalized (i.e. will result in a lot of database joins). You may be better just storing Title as a String within each Person. You can still have a Title object that is used so that you can configure the list of possible titles in the database.