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)
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;
}
Setup: Grails 2.5.6 with Hibernate 4.3.10
I have a table with a string id. Thing is, its values are numeric strings, and this seems to mess up get() when I pass in a value such as "000000".
Domain class:
class Term
{
static mapping = {
id name: 'code', generator: 'assigned'
version false
code column: 'CODE'
description column: 'DESC'
}
String code
String description
}
Data looks like:
CODE || DESC
-------++---------------------------
000000 || The Beginning of Time
201715 || Post Secondary Winter 2017
201815 || Post Secondary Winter 2018
999999 || The End of Time
And then in testing I found the following:
assert Term.list() // works fine
assert !Term.get('foo') // works fine
//assert Term.get('000000') // throws exception
The exception thrown is:
Method threw 'org.springframework.orm.hibernate4.HibernateSystemException' exception.
Provided id of the wrong type for class Term. Expected: class java.lang.String, got class java.lang.Long
org.hibernate.TypeMismatchException: Provided id of the wrong type for class Term. Expected: class java.lang.String, got class java.lang.Long
So it looks like at some point the '000000' and the '201715' and whatever else are being inconveniently converted into Long objects. Using as String doesn't help either. Can anyone help me tell Hibernate that this String should be treated as a String?
This seems like a Grails bug and I'm guessing it is because you have not declared id to be of type String in your domain class because it is mapped to a different field (which makes sense).
You could try adding
String id
to your domain class although that may not caused desired behaviour with column generation.
I would suggest rather than using get() you could use findByCode() as you have mapped your id to the code field and the result should be the same.
Assuming a domain class with a simple association:
class User {
Country country
}
Grails by default allows binding it by id:
new User(country: 1).country
≫ Country: 1
I'm trying to use the BindUsing annotation to bind it by another property:
class User {
#BindUsing({ obj, src ->
Country.findByCode(src['country'])
})
Country country
}
But it fails, even though the country exists:
Country.findByCode('US')
≫ Country: 1
new User(country: 'US').country
≫ null
Moreover, I can't seem to be able to debug the closure, because if I try to print anything coming from the src object, I get this error:
java.lang.IncompatibleClassChangeError: Expected static method
java.io.PrintStream.println(Ljava/lang/Object;)V
Printing constant values works.
I have the following combobox:
<g:select name="ticketType" from="${app.domain.enums.TicketType?.values()}"
keys="${app.domain.enums.TicketType.values() }"
value="${ticketInstance?.ticketType}"
noSelection="${['null': 'Select One...']}"
/>
I've setup the following constraint for ticketType in command object
ticketType nullable: true, blank:true
TicketType is a very simple enum:
public enum TicketType {
QUESTION, SUPPORT, MAINTENANCE, NEW_FUNCTIONALITY, MALFUNCTION
}
And every time I don't setup some value for ticketType in my GSP I get the following error:
Failed to convert property value of type 'java.lang.String' to required type 'com.coming.enums.TicketPriority'
It's like in case of no selection g:select sets the value for "null" (string).
What am I missing?
Rather than using the 'null' literal, have you tried using an empty string as your noSelection attribute? e.g. noSelection="${['':'Select One...']}"? This may do a proper conversion to a true null value during data binding.
As your error says - you do have a string in your noSelection. This can't be converted to any of your enum values.
Remove the quotation marks of your null and it should work (it works for me with grails 2.0):
<g:select name="ticketType" from="${app.domain.enums.TicketType?.values()}"
keys="${app.domain.enums.TicketType.values() }"
value="${ticketInstance?.ticketType}"
noSelection="${[null: 'Select One...']}"/>
Under Rails 3.3.x, no variation of providing the "null" value worked. In the end, I resolved it by adding this line in to the controller+action before doing any use of the params:
// convert "null" strings to REAL nulls
params.account.each { it.value = (it.value == 'null' ? null : it.value) }
After that, the following worked fine:
account.properties = params.account
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>