I know this seems to be a common one, but I'm lost with it. Occurs on clicking the Add button in assessment.jsf. Anyway, I've attached what I think are the relevant sections.
FWIW, AssessmentType.equals() isn't triggered when I debug.
Thanks in advance.
j_idt38:j_idt47:j_idt48: Validation Error: Value is not valid
assessment.xhtml:
<h:form>
<h:selectOneMenu value="#{assessmentBean.assessmentField}">
<f:selectItems value="#{assessmentBean.assessment.type.fields}" />
</h:selectOneMenu>
<h:commandButton value="Add" action="#{assessmentBean.doAddField}">
<f:param name="assessmentId"
value="#{assessmentBean.assessment.id}" />
</h:commandButton>
</h:form>
assessment.jsf:
<form id="j_idt38:j_idt47" name="j_idt38:j_idt47" method="post" action="/jsf-web/edit/assessment.jsf" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="j_idt38:j_idt47" value="j_idt38:j_idt47" />
<select name="j_idt38:j_idt47:j_idt48" size="1"> <option value="1">Presenting Condition</option>
<option value="2">Problem Duration</option>
</select>
<script type="text/javascript" src="/jsf-web/javax.faces.resource/jsf.js.jsf?ln=javax.faces"></script>
<input type="submit" name="j_idt38:j_idt47:j_idt50" value="Add" onclick="mojarra.jsfcljs(document.getElementById('j_idt38:j_idt47'),{'j_idt38:j_idt47:j_idt50':'j_idt38:j_idt47:j_idt50','assessmentId':'1'},'');return false" /><input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="3431661972220941645:6952134510589038883" autocomplete="off" />
</form>
AssessmentType.java:
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.validation.constraints.NotNull;
import lombok.Data;
import org.hibernate.envers.Audited;
@Audited
@Data
@Entity
public class AssessmentType implements Comparable<AssessmentType> {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
private String name;
@OneToMany( fetch=FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity=AssessmentField.class )
private List<AssessmentField> fields;
@Override
public int compareTo(final AssessmentType o) {
return getId().compareTo(o.getId());
}
@Override
public String toString() {
return getName();
}
}
AssessmentFieldConverter.java
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.htu.fizio.api.AssessmentFieldManager;
import com.htu.fizio.domain.AssessmentField;
@FacesConverter(forClass = AssessmentField.class)
public class AssessmentFieldConverter implements Converter {
AssessmentFieldManager<AssessmentField> assessmentFieldManager;
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public Object getAsObject(FacesContext ctx, UIComponent component, String value) {
try {
final InitialContext ic = new InitialContext();
assessmentFieldManager = (AssessmentFieldManager) ic.lookup("fizio/AssessmentFieldManagerImpl/local");
return assessmentFieldManager.find(Long.valueOf(value));
} catch (NamingException e) {
e.printStackTrace();
}
return null;
}
@Override
public String getAsString(FacesContext ctx, UIComponent component, Object value) {
return String.valueOf(((AssessmentField) value).getId());
}
}
AssessmentBean.java
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import lombok.Getter;
import lombok.Setter;
import com.htu.fizio.api.AssessmentManager;
import com.htu.fizio.domain.Assessment;
import com.htu.fizio.domain.AssessmentField;
import com.htu.fizio.domain.AssessmentFieldValue;
import com.htu.fizio.jsf.faces.FacesUtil;
...
@PostConstruct
public void init() {
if (FacesUtil.containsKey("assessmentId")) {
final Long id = Long.parseLong(FacesUtil.get("assessmentId"));
assessment = assessmentManager.find(id);
} else {
assessment = new Assessment();
}
}
public String doAddField() {
final AssessmentFieldValue value = new AssessmentFieldValue();
value.setField(assessmentField);
value.setValue("");
assessment.getFieldValues().add(value);
assessmentManager.save(assessment);
return "/edit/assessment";
}
Edit:
Just noticed this when debugging, is it a likely suspect?:
Daemon Thread [HandshakeCompletedNotify-Thread] (Suspended (exception ConcurrentModificationException))
HashMap$EntryIterator(HashMap$HashIterator<E>).nextEntry() line: 793
HashMap$EntryIterator.next() line: 834
HashMap$EntryIterator.next() line: 832
SSLSocketImpl$NotifyHandshakeThread.run() line: 2214
Validation Error: Value is not valid
To the point, this error means that the selected item does not match any of the items available in the list. I.e. the object represented by the selected item value has never returned true
on its equals()
call with any of the available select items.
There are only two causes for this problem:
equals()
method of the object type in question is broken.Since the first seems to be properly implemented -as per the comments-, the only cause left is the second. Assuming that you're nowhere doing business logic in a getter method, an easy test is to put the #{assessmentBean}
in the session scope. If it works, then the data (pre)loading logic of the list of select items is definitely wrong.