My Spring CustomCollectionEditor implementation , not binding correctly - spring

I have one select multiple in Spring:
<form:select path="categoryProducts" id="destinationData" itemLabel="product.name" items="${categoryProducts}" itemValue="product.id" multiple="true" ondblclick="moveLeft(document.getElementById('destinationData'), document.getElementById('sourceData'))" size="10" />
In my controller:
#InitBinder
public void initBinder(WebDataBinder binder){
binder.registerCustomEditor(Set.class, "categoryProducts", new CustomCollectionEditor(Set.class)
{
#Override
protected Object convertElement(Object element)
{
Product p = new Product() ;
try {
Short id = new Short(String.valueOf(element));
p = (Product) dataManager.find(Product.class, id);
System.out.println(p.getId() + "\\" +p.getName());
CategoryProduct c = new CategoryProduct ();
c.setProduct(p);
return c;
} catch (Exception e) {
e.printStackTrace();
}
return p;
}
});
When I do submit, receive this log:
136 Product Name
105 Product Name
104 Product Name
211 Product Name
204 Product Name
409 Product Name
30/03/2011 07:32:20 PM org.apache.catalina.core.StandardWrapperValve invoke
GRAVE: Servlet.service() para servlet cms lanzó excepción
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'category' on field 'categoryProducts': rejected value [136,105,104,211,204,409][type
The initiBinder is initialized, but throws exception in the end: (rejected value [136,105,104,211,204,409]) .
Why?

Most likely the field "categoryProducts" of your command class (model attribute) is a
Set<String>
...or a Set of any class other than CategoryProduct. Try to change it to:
Set<CategoryProduct>

Related

GWT & Java EE SessionScoped bean not persisting

I'm playing w/ EE and want to persist a user session state. I have the session bean here:
#Stateful(mappedName = "UserSessionState")
#Named("UserSessionState")
#SessionScoped
#StatefulTimeout(value = 5, unit = TimeUnit.MINUTES)
public class UserSessionState implements Serializable
{
private boolean hasPlayerId = false;
private String playerId = "";
public void setRandomPlayerId()
{
playerId = UUID.uuid();
hasPlayerId = true;
}
public boolean hasPlayerId()
{
return hasPlayerId;
}
public String getPlayerId()
{
return playerId;
}
}
And a servlet here (GameState is an Application Scoped bean that is working as expected, CustomExtendedHttpServlet is just a simple extension of HttpServlet)
public class NewUserJoined extends CustomExtendedHttpServlet
{
#Inject
protected GameState gameState;
#Inject
protected UserSessionState user;
#Override
protected String doGetImpl(HttpServletRequest request, HttpServletResponse response, UserContext userLoginContext)
{
if (!user.hasPlayerId())
{
user.setRandomPlayerId();
}
String userId = user.getPlayerId();
if (!gameState.hasUser(userId))
{
gameState.addUser(userId, user);
return "Hi, your ID is: " + user.getPlayerId() + ", there are " + gameState.getUserCount() + " other players here";
}
else
{
return user.getPlayerId() + " you're already in the game, there are: " + gameState.getUserCount() + " other players here";
}
}
}
I'm not sure what's going on, but whenever I call the New User Joined servlet from the same HTTP session, I get this response on the first call (as expected):
"Hi, your ID is: , there are 1 other players here"
Repeating the same servlet call in the same session gives me the same message:
"Hi, your ID is: , there are 2 other players here"
...
It looks like a new instance of User Session State is getting created over and over. Am I doing this correctly?
EDIT 1: Here the code I use to send a request. It appears I'm getting a new session ID with each request, what could cause that?
RequestCallback callback = new RequestCallback()
{
#Override
public void onResponseReceived(Request request, Response response)
{
log(response.getText());
}
#Override
public void onError(Request request, Throwable exception)
{
log(
"Response Error | "
+ "Exception: " + exception);
}
};
RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, SERVLET_URL);
rb.setCallback(callback);
try
{
rb.send();
}
catch (RequestException e)
{
log("Response Error | "
+ "Exception: " + e);
}
Figured out the issue,
Turns out I had an old workaround in the GWT client that was changing the host to get around a CORS issue. Because the response didn't match up to the origin, the cookie wasn't getting sent with future servlet GET calls.
Have you tried a call to request.getSession(true) to make sure an EE HTTPSession is established here?

Trying to create a dropdown in my jsp page

I am trying to create a dropdown which will have dynamic values in my jsp page but getting an exception, i am trying to use spring form tags here.
WebController.java
#RequestMapping(value="/addAchivement",method=RequestMethod.GET)
public String addAchievements(){
Object object=null;
try {
object = genericAppProcessor.checkLogin(username, password,null,null);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SchoolLoginDetails sld=new SchoolLoginDetails();
sld=(SchoolLoginDetails)object;
List<GroupDetails> list=new ArrayList<GroupDetails>();
list=(List<GroupDetails>) sld.getGroupDetails();
Set<Object> addedClass = new HashSet<Object>();
Set<Object> addedSection = new HashSet<Object>();
Map referenceData = new HashMap();
Map<Object,Object> classs = new LinkedHashMap<Object,Object>();
for(int i=0;i<list.size();i++){
Object obj=list.get(i).getClazz();
Object objj=list.get(i).getSection();
addedClass.add(obj);
addedSection.add(objj);
List<Object> convertTolist=new ArrayList<Object>(addedClass);
classs.put(convertTolist.get(0),convertTolist.get(0));
addedClass.clear();
}
referenceData.put("classList",classs);
return "addAchivement";
}
addAchivement.jsp
<form:form method="POST" role="form" action="/GenericApp/addWebAchievement" enctype="multipart/form-data">
<form:select path="classs">
<form:options items="${classList}" />
</form:select>
Exception :-
org.apache.jasper.JasperException: An exception occurred processing JSP page /WEB-INF/jsp/addAchivement.jsp at line 72
<div class="input-field col s12 m4 l3" >
<!--Line 72 --> <form:select path="classs" class="text-black custom-select">
<form:options items="${classList}" />
</form:select>
you need to return model and view instead of just returning a view Use Below Code :
// Java Code
#RequestMapping(value="/addAchivement",method=RequestMethod.GET)
public ModelAndView addAchievements(){
Object object=null;
try {
object = genericAppProcessor.checkLogin(username, password,null,null);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SchoolLoginDetails sld=new SchoolLoginDetails();
sld=(SchoolLoginDetails)object;
List<GroupDetails> list=new ArrayList<GroupDetails>();
list=(List<GroupDetails>) sld.getGroupDetails();
Set<Object> addedClass = new HashSet<Object>();
Set<Object> addedSection = new HashSet<Object>();
Map referenceData = new HashMap();
Map<Object,Object> classs = new LinkedHashMap<Object,Object>();
for(int i=0;i<list.size();i++){
Object obj=list.get(i).getClazz();
Object objj=list.get(i).getSection();
addedClass.add(obj);
addedSection.add(objj);
List<Object> convertTolist=new ArrayList<Object>(addedClass);
classs.put(convertTolist.get(0),convertTolist.get(0));
addedClass.clear();
}
referenceData.put("classList",classs);
ModelAndView mav = new ModelAndView("addAchivement", referenceData);
return mav;
}
You are assigning a path to classs in your jsp
<!--Line 72 --> <form:select path="classs" class="text-black custom-select">
but you are not sending anything from model on which this class variable can map so you need to use modelAttribute in your spring form so that this class variable can map .
for eg .
: you need to make a class object which has a class as member :
below is java code change :
referenceData.put("classList",classs);
referenceData.put("classObject",class); // Here class is a object that has class attribute by which that value in jsp will bind .
ModelAndView mav = new ModelAndView("addAchivement", referenceData);
Here is Jsp Code change :
<form:form method="POST" role="form" action="/GenericApp/addWebAchievement" enctype="multipart/form-data" modelAttribute="classObject">
<form:select path="classs">
<form:options items="${classList}" />
</form:select>
Sample class object :
public Class{
String classs ;
// getter setter for classs member variable .
}

Mark inputText as invalid in Invoke Applications phase

I am performing some business rule validations in the Invoke Applications phase, and when there is an error, a custom Exception will be thrown. The custom exception is handled in a custom JSF ErrorHandler, where the input component in question will be marked as invalid, FacesMessages created and validation will be failed on the FacesContext.
Bean
public void performAction() {
if ("aaa".equals(input)) {
// custom exception: arg1 - Error Message, arg2 - clientId
throw new ServiceValidationException("Something went wrong", ":f:input");
}
}
XHTML
<h:form id="f">
<p:inputText id="input" value="#{bean.input}" />
<h:commandButton value="Submit" action="#{bean.performAction}"/>
</h:form>
Custom JSF ErrorHandler
#Override
public void handle() throws FacesException {
try {
Iterator<ExceptionQueuedEvent> unhandledExceptionQueuedEvents = getUnhandledExceptionQueuedEvents().iterator();
if (unhandledExceptionQueuedEvents.hasNext()) {
Throwable exception = unhandledExceptionQueuedEvents.next().getContext().getException();
Throwable rootCause = unwrapRootCause(exception);
if (rootCause instanceof ServiceValidationException) {
ServiceValidationException sve = (ServiceValidationException) rootCause;
JSFComponentUtil.markComponentAsInvalid(sve.getClientId());
// create FacesMessage here etc
...
FacesContext.getCurrentInstance().validationFailed();
return;
}
}
} catch (Exception e) {
logger.error("Error encountered while processing exception, allow default error handling to take over", e);
}
// delegate to Omnifaces Ajax exception handler
super.handle();
}
JSFComponentUtil
public static void markComponentAsInvalid(String componentId) {
UIComponent component = findComponent(componentId);
if (component != null && component instanceof EditableValueHolder) {
EditableValueHolder evh = (EditableValueHolder) component;
if (evh.isValid()) {
evh.setValid(false);
}
} else {
LOG.debug("component not found or is not instance of EditableValueHolder");
}
}
public static UIComponent findComponent(String componentId) {
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
if (viewRoot != null) {
return viewRoot.findComponent(componentId);
}
LOG.debug("View Root is null, returning null");
return null;
}
The Problem
The issue I'm running into is that upon submitting the form via the command button, the page redisplays with the input text field marked as red (expected behavior), however the text that was typed into the field is lost. I want the invalid text entered to remain in the field.
In markComponentInvalid, you can try manually setting the component's value:
evh.setSubmittedValue("aaa");
evh.setValue("aaa");
Of course, instead of hard-coding "aaa" you could add an "input" property to your ServiceValidationClass so that you can pass that value from the action method to the error handler and then to the Util class, e.g.
bean:
throw new ServiceValidationClass ("Something went wrong", ":f:input", input);
error handler:
JSFComponentUtil.markComponentAsInvalid(sve.getClientId(), sve.getInput());
etc.

Programmatically created form and validation, unhandled faces messages

I create a form by using Apache MyFaces library. The form is related to the
jsf-page by a binding. Moreover I built a TestValidator-class which implements
Validator-interface. My form got shown, I enter my input, validation gots
triggered successfully. Unfortunately I am not able to display corresponding
FacesMessage. I guess I am not able to tell JSF 'Please rerender h:messages
after throwing the validator-Exception'.
What went wrong? Thanks in advance.
#FacesValidator("TestValidator") // class TestValidator
public class TestValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent uiComponent, Object value) throws ValidatorException {
System.out.println("TestValidator.validate: " + value);
if (((String) value).equals("2")){
FacesMessage fm = new FacesMessage();
fm.setSeverity(FacesMessage.SEVERITY_ERROR);
fm.setSummary("TestValidator FEHLER");
fm.setDetail("TestValidator FEHLER");
throw new ValidatorException(fm);
}
}
}
<!-- JSF-Snippet -->
<t:div id="formContainer" binding="#{formsbuilder.form}" />
private Div createFacesMessagesDiv() { // FormsBuilder-Bean-Snippet for creating the container for the FacesMessage
facesMessagesDiv = new Div(); // CORRESPONDING BEAN PROPERTY
facesMessagesDiv.setId("facesMessagesContainer");
facesMessagesDiv.setStyle("color: blue; border: 3px solid green;");
HtmlOutputText introText = new HtmlOutputText();
introText.setId("facesMessagesIntroText");
introText.setValue("FacesMessages - Start: ");
facesMessagesDiv.getChildren().add(introText);
HtmlMessages fms = new HtmlMessages();
fms.setId("facesMessages");
facesMessagesDiv.getChildren().add(fms);
HtmlOutputText outroText = new HtmlOutputText();
outroText.setId("facesMessagesOutroText");
outroText.setValue("FacesMessages - Ende!");
facesMessagesDiv.getChildren().add(outroText);
return facesMessagesDiv;
}
private HtmlAjaxCommandLink createSaveFormButton() { // saveButton after hitting this button, facesMessages should show up;
HtmlAjaxCommandLink saveFormButton = HtmlRendering.createGeneralButton("saveForm" + currentSubForm.getIdAsString(), /* ID */
"#{resources.labels['formsgenerator_saveForm']}",
"#{formsbuilder.submitForm}",
null, /* action */
null, /* actionReturnType */
null, /* onComplete */
"", /* styleClassValueExpression */
"", /* imageValue */
"modifiedContainerDiv");
saveFormButton.setReRender(facesMessagesDiv); // CORRESPONDING BEAN PROPERTY
saveFormButton.setValueExpression("oncomplete", HtmlRendering.createValueExpression("afterGeneralSavingSubForm()");
return saveFormButton;
}
It does not look like you are setting the message correctly.
You forgot to add the FacesMessage to the FacesContext.
Try this:
public void validate(FacesContext context, UIComponent uiComponent, Object value) throws ValidatorException {
System.out.println("TestValidator.validate: " + value);
if (((String) value).equals("2")){
FacesMessage fm = new FacesMessage();
fm.setSeverity(FacesMessage.SEVERITY_ERROR);
fm.setSummary("TestValidator FEHLER");
fm.setDetail("TestValidator FEHLER");
FacesContext.getCurrentInstance().addMessage(null, fm);
throw new ValidatorException(fm);
}
}
Here's a more concise way to write a FacesMessage:
public void validate(FacesContext context, UIComponent uiComponent, Object value) throws ValidatorException {
System.out.println("TestValidator.validate: " + value);
if (((String) value).equals("2")){
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "TestValidator FEHLER", "TestValidator FEHLER"));
throw new ValidatorException(fm);
}
}

Spring new object Binding Exception: Cannot convert String to long (primitive type)

OS: Windows vista, Framework: Spring (latest), JQuery (latest), Hibernate (latest).
I have a domain class with primary key as long id.
public class domain{
private long id;
....
}
My Controller definition:
#RequestMapping("/domainJqgridData/save")
public #ResponseBody String saveJqgridData(DomainClass domainclass) throws Exception {
return "Saved successfully!";
}
When the JSP form is submitted to add a new DomainClass record, the Spring controller tries to automatically bind the request parameters to domain class. It throws a BindException as follows:
Request processing failed; nested exception is org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'domain' on field 'id': rejected value [_empty]; codes [typeMismatch.domainclass.id,typeMismatch.id,typeMismatch.long,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [domainclass.id,id]; arguments []; default message [id]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'long' for property 'id'; nested exception is org.springframework.core.convert.ConversionFailedException: Unable to convert value "_empty" from type 'java.lang.String' to type 'long'; nested exception is java.lang.NumberFormatException: For input string: "_empty"]
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:656)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
As I am adding a new DomainClass record, the id field is passed as null by the JSP form. Spring converts the null id to empty string value for binding purpose and throws the error. I browsed the net and found that I can register custom editors for such purpose. I changed the DomainClass primitive type definition long id, to Long id and tried to bind a custom editor as follows.
Controller class:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Long.class, new CustomPrimitiveFormat(Long.class, true));
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}
My custom primitive editor class is as follows:
public class CustomPrimitiveFormat extends CustomNumberEditor{
public CustomPrimitiveFormat(Class numberClass, boolean allowEmpty)
throws IllegalArgumentException {
super(numberClass, allowEmpty);
// TODO Auto-generated constructor stub
}
public void setValue(Object value){
System.out.println("Entered CustomPrimitiveFormat setValue");
if (value == null) {
super.setValue(null);
return;
}
if (value.getClass().equals(String.class)){
if (StringUtils.isEmpty((String)value)){
super.setValue(null);
}
}
}
public void setAsText(Object value){
System.out.println("Entered CustomPrimitiveFormat setAsText");
if (value == null) {
super.setValue(null);
return;
}
if (value.getClass().equals(String.class)){
if (StringUtils.isEmpty((String)value)){
super.setValue(null);
}
}
}
}
I still receive the BindingException. Could not find any link that would guide me through how to overcome Spring BindException when adding a new Domain class record. I would like my primary key to remain primitive type, instead of using the Number object type.
Thanks in advance for your help.
As you can see in the error message, jqGrid uses _empty as an id of the new record (also see here), so you need to change your PropertyEditor to convert _empty to null.

Resources