JPAContainer: ManytoOne relation with EmbeddedID

There are questions similar but not quite. In those cases (and in the JPAContainer examples) the Entity part of the ManyToOne relationship has a single key. In my case it is an embedded id.

My code is based on the Address Book example.

Here are the two entities:

@Entity
@Table(name = "tutorial")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "Tutorial.findAll", query = "SELECT t FROM Tutorial t"),
@NamedQuery(name = "Tutorial.findById", query = "SELECT t FROM Tutorial t WHERE t.tutorialPK.id = :id"),
@NamedQuery(name = "Tutorial.findByTutorialTypeId", query = "SELECT t FROM Tutorial t WHERE t.tutorialPK.tutorialTypeId = :tutorialTypeId"),
@NamedQuery(name = "Tutorial.findByMessage", query = "SELECT t FROM Tutorial t WHERE t.message = :message")})
public class Tutorial implements Serializable {

private static final long serialVersionUID = 1L;
@EmbeddedId
protected TutorialPK tutorialPK;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 245)
@Column(name = "message")
private String message;
@JoinColumn(name = "tutorial_type_id", referencedColumnName = "id", insertable = false, updatable = false)
@ManyToOne(optional = false)
private TutorialType tutorialType;

public Tutorial() {
}

public Tutorial(TutorialPK tutorialPK) {
this.tutorialPK = tutorialPK;
}

public Tutorial(TutorialPK tutorialPK, String message) {
this.tutorialPK = tutorialPK;
this.message = message;
}

public Tutorial(int id, int tutorialTypeId) {
this.tutorialPK = new TutorialPK(id, tutorialTypeId);
}

public TutorialPK getTutorialPK() {
return tutorialPK;
}

public void setTutorialPK(TutorialPK tutorialPK) {
this.tutorialPK = tutorialPK;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public TutorialType getTutorialType() {
return tutorialType;
}

public void setTutorialType(TutorialType tutorialType) {
this.tutorialType = tutorialType;
}

@Override
public int hashCode() {
int hash = 0;
hash += (tutorialPK != null ? tutorialPK.hashCode() : 0);
return hash;
}

@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Tutorial)) {
return false;
}
Tutorial other = (Tutorial) object;
if ((this.tutorialPK == null && other.tutorialPK != null) || (this.tutorialPK != null && !this.tutorialPK.equals(other.tutorialPK))) {
return false;
}
return true;
}

@Override
public String toString() {
return "games.jwrestling.server.game.db.persistence.Tutorial[ tutorialPK=" + tutorialPK + " ]
";
}

}

And the EmbeddedId class:

@Embeddable
public class TutorialPK implements Serializable {

@Basic(optional = false)
@NotNull
@Column(name = "id")
private int id;
@Basic(optional = false)
@NotNull
@Column(name = "tutorial_type_id")
private int tutorialTypeId;

public TutorialPK() {
}

public TutorialPK(int id, int tutorialTypeId) {
this.id = id;
this.tutorialTypeId = tutorialTypeId;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public int getTutorialTypeId() {
return tutorialTypeId;
}

public void setTutorialTypeId(int tutorialTypeId) {
this.tutorialTypeId = tutorialTypeId;
}

@Override
public int hashCode() {
int hash = 0;
hash += (int) id;
hash += (int) tutorialTypeId;
return hash;
}

@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof TutorialPK)) {
return false;
}
TutorialPK other = (TutorialPK) object;
if (this.id != other.id) {
return false;
}
if (this.tutorialTypeId != other.tutorialTypeId) {
return false;
}
return true;
}

@Override
public String toString() {
return "games.jwrestling.server.game.db.persistence.TutorialPK[ id=" + id + ", tutorialTypeId=" + tutorialTypeId + " ]
";
}

}

I got the form set up and it works fine when I edit the items, but creating I get errors because the TutorialPK is null:

Caused by: Exception [EclipseLink-4002]
 (Eclipse Persistence Services - 2.6.2.v20151217-774c696): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'tutorial_type_id' cannot be null

Here are the related Vaadin code:

public final class TutorialEditor extends Window implements Button.ClickListener,
FormFieldFactory {

private final Item tutorialItem;
private final Form editorForm;
private final Button saveButton;
private final Button cancelButton;

public TutorialEditor(Item tutorialItem) {
this.tutorialItem = tutorialItem;
editorForm = new Form();
editorForm.setFormFieldFactory(this);
editorForm.setBuffered(true);
editorForm.setImmediate(true);
editorForm.setItemDataSource(tutorialItem, Arrays.asList("message",
"tutorialType"));

saveButton = new Button("Save", this);
cancelButton = new Button("Cancel", this);

editorForm.getFooter().addComponent(saveButton);
editorForm.getFooter().addComponent(cancelButton);
setSizeUndefined();
setContent(editorForm);
setCaption("New Tutorial");
}

@Override
public void buttonClick(Button.ClickEvent event) {
if (event.getButton() == saveButton) {
editorForm.commit();
fireEvent(new EditorSavedEvent(this, tutorialItem));
} else if (event.getButton() == cancelButton) {
editorForm.discard();
}
close();
}

@Override
public Field<?> createField(Item item, Object propertyId, Component uiContext) {
Field field = DefaultFieldFactory.get().createField(item, propertyId,
uiContext);
if ("tutorialType".equals(propertyId)) {
field = new TutorialTypeSelector();
} else if (field instanceof TextField) {
((TextField) field).setNullRepresentation("");
}

field.addValidator(new BeanValidator(Tutorial.class, propertyId
.toString()));

return field;
}

public void addListener(EditorSavedListener listener) {
try {
Method method = EditorSavedListener.class.getDeclaredMethod(
"editorSaved", new Class{EditorSavedEvent.class});
addListener(EditorSavedEvent.class, listener, method);
} catch (final java.lang.NoSuchMethodException e) {
// This should never happen
throw new java.lang.RuntimeException(
"Internal error, editor saved method not found");
}
}

public void removeListener(EditorSavedListener listener) {
removeListener(EditorSavedEvent.class, listener);
}

public static class EditorSavedEvent extends Component.Event {

private final Item savedItem;

public EditorSavedEvent(Component source, Item savedItem) {
super(source);
this.savedItem = savedItem;
}

public Item getSavedItem() {
return savedItem;
}
}

public interface EditorSavedListener extends Serializable {

public void editorSaved(EditorSavedEvent event);
}

And another one:

class TutorialTypeSelector extends CustomField<TutorialType> {

private final JPAContainer<TutorialType> container;
private final ComboBox type = new ComboBox();

public TutorialTypeSelector() {
container = JPAContainerFactory.make(TutorialType.class,
"JWPUJNDI");
setCaption("Type");
type.setContainerDataSource(container);
type.setItemCaptionPropertyId("type");
type.addListener(new Property.ValueChangeListener() {
@Override
public void valueChange(
com.vaadin.data.Property.ValueChangeEvent event) {
/*
* Modify the actual value of the custom field.
*/
if (type.getValue() == null) {
setValue(null, false);
} else {
TutorialType entity = container
.getItem(type.getValue()).getEntity();
setValue(entity, false);
}
}
});
}

@Override
protected Component initContent() {
CssLayout cssLayout = new CssLayout();
cssLayout.addComponent(type);
return cssLayout;
}

@Override
public void setPropertyDataSource(Property newDataSource) {
super.setPropertyDataSource(newDataSource);
setTutorialType((TutorialType) newDataSource.getValue());
}

@Override
public void setValue(TutorialType newValue) throws ReadOnlyException,
Converter.ConversionException {
super.setValue(newValue);
setTutorialType(newValue);
}

private void setTutorialType(TutorialType type) {
this.type.setValue(type != null ? type.getId() : null);
}

@Override
public Class<? extends TutorialType> getType() {
return TutorialType.class;
}
}

Any idea on how to populate this field? See related Stackoverflow question
here
.