This question already has answers here:
Validation Error: Value is not valid
(3 answers)
Closed 6 years ago.
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:
The equals() method of the object type in question is broken.
The contents of the list of items is different during the validations phase of the form submit request than as it was during the render response phase of the initial request to display the form.
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.
The validation is failing because after your converter converts the String representation of AssessmentType back to an object, JSF iterates over the existing values (assessmentBean.assessment.type.fields) and compares this recently converted object with all those existing ones.
Since you did not implement Object#equals for AssessmentType, it will default to an object identity comparison (roughly spoken, the memory address of your object) , which will of course fail.
The solution is thus to either implement Object#equals, or let the converter get the object from assessmentBean.assessment.type.fields instead of from AssessmentTypeManager.
I think I've resolved this, at least, I've moved on to the next error!
Despite posting reams of code I'd not posted the full xhtml in which there were multiple and nested form tags. Just the one form seems to allow passing the assessmentId parameter which in turn allows the AssessmentBean to then populate the List of AssessmentFields for the assessment type correctly.
Thanks for all the help.
Related
In my faces-config.xml I have set
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
Thus an arbitrary input component with no input places a null into the bean property bound to the value="#{myBean.someDate}" attribute and renders an empty component when getting null from that bean property.
While this is generally the wanted behavior for the application, I have a particular component where I want to replace null with a custom non null value.
Is there a general good way to achieve this?
I have tried this for the Primefaces (6.2) calendar with Mojarra 2.3.8:
<h:form id="myForm">
<p:calendar value="#{myBean.someDate}" pattern="MM/dd/yyyy"
converter="mySpecialDateConverter" locale="en" />
<p:commandButton value="send" process="#form" update="#form" />
<hr />
<h:outputText value="#{myBean.someDate}" />
</h:form>
I tried it using a converter that while rendering the component returns an empty String in getAsString() when my custom value is received from #{myBean.someDate}, or spits out my custom value in getAsObject() when null or pure emptyness is submitted:
import java.util.Date;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.DateTimeConverter;
import javax.faces.convert.FacesConverter;
#FacesConverter("mySpecialDateConverter")
public class MyConverter extends DateTimeConverter {
private static final Date PAST = new Date(0);
public MyConverter() {
setPattern("MM/dd/yyyy");
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (PAST.equals(value)) {
return "";
}
return super.getAsString(context, component, value);
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (null == value || "".equals(value.trim())) {
return PAST;
}
return super.getAsObject(context, component, value);
}
}
Rendering an empty calendar component when the bean property equals PAST works as expected. But submitting the calender without input sets the property to null because Primefaces CalendarRenderer simply does not consult the Converter on blank value submission:
package org.primefaces.component.calendar;
public class CalendarRenderer extends InputRenderer {
// ...
public Object getConvertedValue(FacesContext context, UIComponent component, Object value) throws ConverterException {
Calendar calendar = (Calendar) component;
String submittedValue = (String) value;
SimpleDateFormat format = null;
if (isValueBlank(submittedValue)) {
return null;
}
//Delegate to user supplied converter if defined
try {
Converter converter = calendar.getConverter();
if (converter != null) {
return converter.getAsObject(context, calendar, submittedValue);
}
}
// ...
}
// ...
}
This is partially ok, as the JavaDoc on Converter.getAsObject() says:
/**
* #return <code>null</code> if the value to convert is <code>null</code>,
* otherwise the result of the conversion
*/
Such there is no reason for Primefaces to resolve the converter on empty input. Would be different imho if we'd set javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL = false. Then I'd consider above behavior not correct as "" is not null.
For completeness this is my bean aka myBean:
import java.io.Serializable;
import java.util.Date;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
#Named
#ViewScoped
public class MyBean implements Serializable {
private static final long serialVersionUID = 1L;
private Date someDate;
public Date getSomeDate() {
return someDate;
}
public void setSomeDate(Date someDate) {
this.someDate = someDate;
}
}
I don't want to make changes to that bean as in real application the Calendars' value is bound to persisted entity property values. I also don't want the persistence layer do the job.
The very background:
I want to prevent null values in some database DATE fields. In case of periods for example I want the start default to some far away past date not relevant in application context, for end of that period I want a date in the far future not relevant in application context and both without to bother the user which dates they are by default. These default dates help filtering entities for which the current Date is in or out of that period, while no input by the user is assumed to be virtually the period for ever.
JSF components will not call the converter on a null value or anything they considers as null - this is true for the default components in JSF as well. So in this regard I guess PrimeFaces is behaving as expected and this is the correct outcome. Here are two ways of circumventing this that instantly come to mind;
Use OmniFaces
As described in JSF converter with null value, OmniFaces o:param will call your converter regardless of a null value - you can use it to pass parameters to components. In your specific case you should be able to do something similar to this;
<h:form id="myForm">
<p:calendar value="#{myBean.someDate}" pattern="MM/dd/yyyy" locale="en" />
<p:commandButton value="send" process="#form" update="#form">
<o:param name="date" value="#{myBean.someDateConversion}"
converter="mySpecialDateConverter" />
</p:commandButton>
<hr />
<h:outputText value="#{myBean.someDate}" />
</h:form>
Use a custom renderer
The second option is to use a custom renderer and just modify the behaviour of the component to always call the converter, as described in this answer - JSF Custom Converter not called on null value.
This question already has answers here:
commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated
(12 answers)
Validation Error: Value is not valid
(3 answers)
How to populate options of h:selectOneMenu from database?
(5 answers)
Closed 5 years ago.
I am trying to perform ajax on selecting any element in selectCheckBoxMenu primefaces.
But ajax event fires only if itemValue is equal to String. If i am passing object then not event is fired. Please have a look.
package com.gsep.utility.bean;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
#ManagedBean
#Entity
#ViewScoped
public class Tool {
#Id #GeneratedValue
#Column(name="tool_id")
private int toolId;
#Column(name="tool_name")
private String toolName;
public int getToolId() {
return toolId;
}
public void setToolId(int toolId) {
this.toolId = toolId;
}
public String getToolName() {
return toolName;
}
public void setToolName(String toolName) {
this.toolName = toolName;
}
}
Above is my bean class which i am iterating to display values in selectCheckboxMenu.
Below is jsf code
<p:selectCheckboxMenu id="multiple" value="#{projectBean.selectedToolList}" label="Tools" multiple="true"
filter="true" filterMatchMode="startsWith" panelStyle="width:250px" >
<f:selectItems value="#{projectBean.toolList}" var="toolObject" itemLabel="#{toolObject.toolName}" itemValue="#{toolObject}" />
<p:ajax update="projectRequestForm:testTabView" listener="#{projectBean.addTab(requestBean,projectBean)}" />
</p:selectCheckboxMenu>
Here if i am changing itemValue attribute to toolObject.toolName then ajax call is happening but i want the selectedToolList as a Tool collection of objects instead of toolName collection of Strings.
#ManagedBean(name = "projectBean")
#ViewScoped
public class ProjectBeanCompUI {
#ManagedProperty(value="#{jiraDao}")
private JiraProjectDAO jiraDao;
private List<Tool> toolList;
private List<String> selectedToolList;
public List<Tool> getToolList() {
toolList = getTools();
return toolList;
}
public void setToolList(List<Tool> toolList) {
this.toolList = toolList;
}
public List<String> getSelectedToolList() {
return selectedToolList;
}
public void setSelectedToolList(List<String> selectedToolList) {
this.selectedToolList = selectedToolList;
public List<Tool> getTools()
{
List<Tool> toolList = new ArrayList<>();
Tool tool = new Tool();
tool.setToolId(1);
tool.setToolName("Eclipse");
Tool tool1 = new Tool();
tool1.setToolId(2);
tool1.setToolName("Jira");
toolList.add(tool);
toolList.add(tool1);
return toolList;
}
}
I use Liferay Tomcat bundle 6.2, and I work with Liferay IDE(eclipse)
How I can invoke a method in Liferay?
I create one Liferay Plugin Project and write in java class this following code. But I don't know, How I can invoke this method?
I can't create a main class in Liferay. But, I think, I can invoke this method in view.jsp with creating an action URL, it this right?
Can you give me a sample example?
Thank you
public class TestLoggerPortlet extends MVCPortlet {
private static final Log logger = LogFactoryUtil.getLog(TestLoggerPortlet.class);
public void addEntry() {
logger.info("This is my message.");
if (logger.isDebugEnabled()) logger.debug("Not always printed.");
}
}
I think you are confusing desktop/mobile application with web application.
In my mind you have to study Java EE basics (how a browser performs a request to an application server and, how to server proceed to understand the request and dispatch it to the right method of the righte class, etc... it is called "servlet lifecycle").
Then should be easy to understand the differences with a portlet lifeycle (and how Liferay MVC portlets work for managing what you need).
I can suggest some interesting reading (in order of learning path):
http://docs.oracle.com/javaee/6/tutorial/doc/bnafd.html (see lifecycle part); basics to have a global idea about what happens behind the stages;
http://www.opensource-techblog.com/2014/12/introduction-to-portlet-phases-and.html an easy comparation to portlet lifecycle;
https://www.liferay.com/it/documentation/liferay-portal/6.0/development/-/ai/portlet-development - Liferay official general introduction to development
https://dev.liferay.com/develop/tutorials/-/knowledge_base/6-2/creating-a-liferay-mvc-portlet-project - THE TUTORIAL YOU NEED to understand how to create a simple LR mvc portlet;
https://www.liferay.com/it/web/meera.success/blog/-/blogs/liferay-mvc-portlet-development-introduction another interesting tutorial.
Hope it helps
See the below code.
view.jsp
<portlet:defineObjects />
<portlet:actionURL var="myAction" name="myAction">
<portlet:param name="someTxt" value="Text Message" />
</portlet:actionURL>
<form action="<%= myAction %> method="post" name="fm">
<input name="<portlet:namespace/>txtName" type="text" />
<input type="submit" name="<portlet:namespace/>submit" value="submit"/>
</form>
Controller Class. TestLoggerPortlet.java
package com.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.upload.UploadPortletRequest;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.model.User;
import com.liferay.portal.service.UserServiceUtil;
import com.liferay.portal.util.PortalUtil;
import com.liferay.util.bridges.mvc.MVCPortlet;
/**
* Portlet implementation class TestLoggerPortlet
*/
public class TestLoggerPortlet extends MVCPortlet {
private static Log _log = LogFactoryUtil.getLog(TestLoggerPortlet.class);
#ProcessAction
public void myAction(ActionRequest actionRequest,
ActionResponse actionResponse) throws IOException, PortletException {
String var1 = actionRequest.getAttribute("someText");//output -> "Text Message"
String var2 = actionRequest.getAttribute("txtName");//output -> Value of Text field.
sendRedirect(actionRequest, actionResponse);
}
}
I have stumbled upon an, at least for me, unexpected behaviour. When using an ui:repeat, it seems I can access the var from outside.
Code - Page:
<f:metadata>
<f:event type="preRenderView" listener="#{xTest.init()}" />
</f:metadata>
<h:form id="xTestForm">
<h:panelGroup layout="block">
Track: #{trk.name}
</h:panelGroup>
<table>
<ui:repeat
value="#{xTest.trackList}"
var="trk">
<tr>
<td>#{trk.name}</td>
<td>
<p:commandLink
actionListener="#{xTest.setTrack(track)}"
value="test"
update=":xTestForm" />
</td>
</tr>
</ui:repeat>
</table>
</h:form>
Code - Bean
package beans;
import dao.DAOFactory;
import dao.track.TrackDAO;
import dto.Track;
import exceptions.DAOException;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import util.MessageUtil;
#ManagedBean
#ViewScoped
public class xTest implements Serializable {
private DAOFactory daoFactory = Config.getInstance().getDAOFactory();
private TrackDAO trackDAO;
private Track track = new Track();
private MessageUtil msg = new MessageUtil();
private List<Track> trackList = new ArrayList();
public xTest() {
trackDAO = daoFactory.getTrackDAO(true);
}
public void init() {
if (!FacesContext.getCurrentInstance().isPostback()) {
try {
trackList = trackDAO.listByAlbumid(241);
} catch (SQLException | DAOException ex) {
msg.setErrorMessage(ex);
}
}
}
public List<Track> getTrackList() {
return trackList;
}
public void setTrack(Track track) {
this.track = track;
}
}
If I click a link in the list of tracks, the track name will be displayed in the panelGroup. How is this possible?
This is a bug in Mojarra. Its UIRepeat component forgets to remove the iteration variable from the request scope by end of iteration during restore view phase. It doesn't work that way in for example MyFaces.
You shouldn't rely your business code on it. Note that <h:dataTable> doesn't have this problem, it properly removes the iteration variable from the request scope by end of iteration by ((UIData) component).setRowIndex(-1) in encodeEnd() method.
8 years later someone reported this to PrimeFaces so I opened a Mojarra issue and a PR to fix the issue.
Mojarra Issue: https://github.com/eclipse-ee4j/mojarra/issues/4830
Mojarra PR: https://github.com/eclipse-ee4j/mojarra/pull/4831
I'm trying to get a composite component working with it's own backing bean,
using the example on p375 from the Core JSF 3 book, but just get an NPE. The problem seems to be at the start of encodeBegin(), Date date = (Date) getValue() returns null.
If I'm honest I don't really understand where the value of the component is supposed to
be getting stored, I specify it as a java.util.Date using cc:attribute type=, but I
don't really understand how this: public Object getSubmittedValue() { return this; } -
which is going to return an instance of an InputDateBean class - results in a Date. I am generally good and confused by how this is supposed to work.
Unlike the book example I am trying to the use backing component for temporary storage,
so when the day is input I try to store it in #{cc.day}, in the book they use an application scoped bean for some reason.
Thanks for any help. I am using Mojarra 2.1.
inputDate.xhtml
<cc:interface componentType="uk.co.myco.jsfbeans.sqcc.InputDateBean">
<cc:attribute name="value" type="java.util.Date"/>
</cc:interface>
<cc:implementation>
<h:panelGrid columns="3">
<h:inputText id="day" value="#{cc.day}"
converter="javax.faces.Integer"/>
<h:inputText id="month" value="#{cc.month}"
converter="javax.faces.Integer"/>
<h:inputText id="year" value="#{cc.year}"
converter="javax.faces.Integer"/>
</h:panelGrid>
</cc:implementation>
InputDateBean.java
package uk.co.myco.jsfbeans.sqcc;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import javax.faces.component.FacesComponent;
import java.util.GregorianCalendar;
import javax.faces.application.FacesMessage;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.convert.ConverterException;
import uk.co.myco.general.SQLog;
import uk.co.myco.jsfbeans.helper.Messages;
#FacesComponent(value = "uk.co.myco.jsfbeans.sqcc.InputDateBean")
public class InputDateBean extends UIInput implements NamingContainer {
private int day = 0, month = 0, year = 0;
public InputDateBean() {
}
#Override
public String getFamily() {
return "javax.faces.NamingContainer";
}
#Override
public void encodeBegin(FacesContext context) throws IOException {
Date date = (Date) getValue();
Calendar cal = new GregorianCalendar();
cal.setTime(date);
UIInput dayComponent = (UIInput) findComponent("day");
UIInput monthComponent = (UIInput) findComponent("month");
UIInput yearComponent = (UIInput) findComponent("year");
dayComponent.setValue(cal.get(Calendar.DATE));
monthComponent.setValue(cal.get(Calendar.MONTH) + 1);
yearComponent.setValue(cal.get(Calendar.YEAR));
super.encodeBegin(context);
}
#Override
public Object getSubmittedValue() {
return this;
}
#Override
protected Object getConvertedValue(FacesContext context, Object newSubmittedValue)
throws ConverterException {
UIInput dayComponent = (UIInput) findComponent("day");
UIInput monthComponent = (UIInput) findComponent("month");
UIInput yearComponent = (UIInput) findComponent("year");
int lday = (Integer) dayComponent.getValue();
int lmonth = (Integer) monthComponent.getValue();
int lyear = (Integer) yearComponent.getValue();
if (isValidDate(lday, lmonth, lyear)) {
return new GregorianCalendar(lyear, lmonth - 1, lday).getTime();
} else {
FacesMessage message = Messages.getMessage("util.messages", "invalidDate", null);
message.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ConverterException(message);
}
}
// getters & setters & isValidDate() removed
}
I now see my mistake. The problem was that the composite component has to be
called with a Date object, i.e. <cclib:inputDate value="#{bean.date}"/>. As the
code stands the date needs to be instantiated, but it wasn't. The more robust
way of doing this is to do a new Date() in encodeBegin() in the event that
getValue() is null. This then works the same a h:inputText/f:convertDateTime
which does not require that the value is instantiated.