DATAMODEL
package com.foo.bar.baz.model
class Customer {
Integer id
String firstName
String lastName
.....
}
GSP
....
<f:with bean="Customer">
<f:field property="firstName"/>
</f:with>
....
The GSP is not in the views\customer directory but views\customerRegistration.
When I try to view the page I get:
URI
/myApp/customerRegistration/index
Class
org.springframework.beans.NotReadablePropertyException
Message
Invalid property 'firstName' of bean class [java.lang.String]: Bean property 'firstName' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
Why can't it read the firstName field in my data object?
I've tried adding the full package in the tag ("bean="com.foo.bar.baz.model.Customer") that only changes the "bean class" in the above error message from java.lang.String to java.lang.Class
Figured it out.
The fields tag needs a live Customer object, not the reference to the class. To fix it I did the following:
Created a new empty customer object in the controller and gives it to the view:
render(view: "myView", model: [emptyCustomer: new Customer()])
Then changed the view to use this object and everything worked:
<f:with bean="emptyCustomer">
<f:field property="firstName"/>
</f:with>
Related
I am developing a simple struts application. In my JSP I have a dropdown list box (using s:select tag). I need to fill the values with a arraylist values in the action class. How can I do that? what changes needed in the structs.xml file for complete this?
JSP:
<s:select name="department" label="" list="departmentlist" headerKey="-1" headerValue="Select Department">
Action class:
private List<String> departmentlist = new ArrayList<String>();
public String xyz()
{
departmentlist.add("aaa");
departmentlist.add("bbb");
departmentlist.add("ccc");
departmentlist.add("ddd");
return "success";
}
The error
"The requested list key 'departmentlist' could not be resolved as a
collection/array/map/enumeration/iterator type. Example: people or
people.{name} - [unknown location] "
means that the select tag is not able to resolve departmentlist as a collection. It is an OGNL expression which is trying to find the departmentlist in the value stack and if it not found or contains a null reference the select tag will complain. When you render the select tag make sure the list is in the value stack and is initialized. See the example here.
Try to add get and set method for our field departmentlist,in your class
Exple :
in your class controller put this method for your field departmentlist :
public List<String> getDepartmentlist(){
return this.departmentlist();
}
public void setDepartmentlist(List<String> departmentlist){
return this.departmentlist = departmentlist;
}
Let's suppose I have following structure:
1) Managed Bean:
#ViewScoped
#ManagedBean
public class TestBean {
private Test test;
//getters/setters
}
2) Test class:
public class Test {
private String attribute;
//gets/sets
}
3) XHTML
<p:inputText id="test" value="#{testBean.test.atribute}" />
Now, I know there is a way to find and get component instance:
UIComponent c = view.findComponent(s);
From UIComponent, how do I get the type bound to component?
What I need is to get full qualified class name from what is set as "value" attribute in component. Something like: package.Test.attribute.
UIComponent offers getValueExpression("attributeName")
sample :
UIViewRoot viewRoot = Faces.getViewRoot();
UIComponent component= viewRoot.findComponent("x");
ValueExpression value = component.getValueExpression("value");
Class<?> expectedType = value.getType(Faces.getELContext());
NB:Faces here is from Omnifaces, which is a "Collection of utility methods for the JSF API that are mainly shortcuts for obtaining stuff from the thread local FacesContext. "
excepts from getType() javadoc
public abstract Class getType(ELContext context) Evaluates the
expression relative to the provided context, and returns the most
general type that is acceptable for an object to be passed as the
value parameter in a future call to the setValue(javax.el.ELContext. java.lang.Object) method. This is not always the same as
getValue().getClass(). For example, in the case of an expression that
references an array element, the getType method will return the
element type of the array, which might be a superclass of the type of
the actual element that is currently in the specified array element.
For MethodExpression read this.
I have a domain class which contains a Class[] array. I want the contents of that array displayed
using g:select. Although I cannot find how to access those fields. I tried <%#page import="package.path.to.PropertyDefinition" %> and then
<g:select from="${PropertyDefinition.types}" name="cust_prop_type"/>
Although I am getting a very big exception of type org.codehaus.groovy.control.MultipleCompilationErrorsException
Is it possible to access that static Array without making use of a Controller class?
I am using version 2.3.7
class PropertyDefinition {
#Transient
public static final Class[] validTypes = [Integer.getClass(), String.getClass(), RefdataValue.getClass(), BigDecimal.getClass()]
.
.
.
Exception:
Caused by: java.lang.NullPointerException at
org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodGetParameterAnnotations(ReflectiveInterceptor.java:944)
at
org.codehaus.groovy.vmplugin.v5.Java5.configureClassNode(Java5.java:357)
at org.codehaus.groovy.ast.ClassNode.lazyClassInit(ClassNode.java:258)
at org.codehaus.groovy.ast.ClassNode.getInterfaces(ClassNode.java:353)
at
org.codehaus.groovy.ast.ClassNode.declaresInterface(ClassNode.java:945)
at
org.codehaus.groovy.ast.ClassNode.implementsInterface(ClassNode.java:925)
at
org.codehaus.groovy.ast.ClassNode.isDerivedFromGroovyObject(ClassNode.java:915)
at
org.codehaus.groovy.classgen.AsmClassGenerator.isGroovyObject(AsmClassGenerator.java:937)
at
You've declared
public static final Class[] validTypes
in PropertyDefinition but you're accessing PropertyDefinition.types in the GSP...
I have a domain class like this :
class City {
String name;
Country country;
}
In the create view I want to put country as a select box like this :
<g:select id="country" optionKey="id" optionValue="countryName"
from="${Country.list()}" name="country" >
</g:select>
What is the best way to handle the submit, so that the country is sent as an object
(currently i receive a message :
Failed to convert property value of type java.lang.String to required type com.example.Country for property country;
nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.example.Country] for property country:
no matching editors or conversion strategy found
)
note : i found this matching question : Grails select not returning the object but a string but the solution didn't solve my problem.
Thank you.
This is because Grails controller doesn't understand what to do with numeric value of country request parameter. Thus, in your controller you should write:
def country = Country.get(params.getLong('country'))
def city = new City(name: params.name, country: country)
I have the following classes, they are bit simplified for example.
class LineInfo
{
Id,
LineNumber,
SubAccountNumer,
MobileNumber
}
class SuspendLinesVM{
public List<LineInfo> Lines{ get;set; }
}
I receive SuspendLinesVM in my action and all Lines are created dynamicaly from client. Each element that belongs to concrete LineInfo in form has name with template 'lineid{Id}_ElementName'. So they comes to me in form like:
lineid0001_LineNumber
lineid0001_SubAccountNumer
lineid0001_MobileNumber
lineid0021_LineNumber
lineid0021_SubAccountNumer
lineid0021_MobileNumber
When some error occures while validation, I need a way to set the failed property as it came in request to highlight invalid fields in the view.
I left questions where I got confused.
public class LineInfoValidator: AbstractValidator<LineInfo>
{
public LineInfoValidator()
{
RuleFor(m => m.LineNumber)
.NotEmpty().WithMessage("Line # is required").OverridePropertyName( ??? )
.InclusiveBetween(1, 9999).WithMessage("Line # must be in range [1, 9999]").OverridePropertyName( ??? )
...
I need a way to do something like *(instance, propertyName) => return string.format('lineid_{0}_{1}', instance.Id, propertyName)*.
Any ideas ?
Resolved with 'WithState' method. Thanks to Jeremy! His solution is here http://fluentvalidation.codeplex.com/discussions/278892
JeremyS
Nov 10, 2011 at 5:16 PM
Unfortunately this isn't something that is supported.
Property names are resolved only once when the validator is instantiated, as opposed to error messages which are generated when the validator is executed. In this case, you need to inspect the instance being validated to generate the property name, which isn't actually possible - the closest you'd be able to get is to use the WithState method to associate some custom state with the failure:
RuleFor(x => x.LineNumber)
.NotEmpty()
.WithState(instance => string.Format("lineid_{0}_LineNumber", instance.Id));
Once you invoke the validator and get back the ValidationResult, you can retrieve this from the CustomState property on the ValidationFailure.
Jeremy
Given that you're using FluentValidator, you should be able to set the collection validator on the SuspendedLinesVM object like so:
public class SelectedLinesVMValidator : AbstractValidator<SelectedLinesVM>
{
public SelectedLinesVMValidator()
{
RuleFor(x=>x.Lines).SetCollectionValidator(new LineInfoValidator());
}
}
If you do this, then as per the documentation you will get back a collection of errors which relate to the index of the failed property.