how to parse XML in grails - grails

I have object has XML as a string. For example I have a domain which has
class person{
String personId
String personName
String personType
String personDescription
String personDetailsXML
}
I am getting the details and binding to person object. I have to pass this object to another controller which displays the info about each person when he clicks on the profile name. How do i parse the XML string.
I have another domain say eachPerson domian which has
class eachPerson{
String personName
String personDescription
Object personDetails
I want to match the person name and person description and persondetailsXml.How do I do that and how can I parse personDetailsXML to personDetails object. Please suggest. How i can pass the personInstance as object to action show() in eachPerson controller??

I'd check this out for starters. Should be pretty straightforward to work from this example.
http://groovy.codehaus.org/Reading+XML+using+Groovy%27s+XmlParser.
(Upon re-reading, this doesn't entirely answer the question...)

You need to parse the xml (using introduced in the link in the comment above - or with XmlSlurper). This is pretty straightforward and easy to understand.
If you have all the data you can use render(action:'show', controller:'eachPerson', model:[persons:personsData]). See the grails doc for further details how to use render.
This will call the action with the given data. In the show action you can access it with params.persons.

Related

Grails: JSON to beans - custom field name

In my Grails application for POST request I am receiving some data as JSON in with keys in broken English.
{
"emplId": "1234",
"emplyNm": "Priyank Thakkar"
}
I am translating this JSON to a Groovy bean
Employee.groovy
class Employee {
String id
String name
}
Now, Grails is forcing me to use same key names as attributes of my bean class and I don't intend to do that. (This is not a domain class, this is a bean.)
How do I achieve this mapping?
Use Grails Command Object.
http://docs.grails.org/latest/guide/single.html#commandObjects
Whether it is domain or other bean, instead of looking for an workaround to map request param empId into String id, corresponding Command objects are more efficient.
You can use BindUsing annotation, see here http://docs.grails.org/2.3.5/api/org/grails/databinding/BindUsing.html

Grails binding one to one associations

When you generate grails views, grails looks at your relationships and generates the right html for your form data to be automatically binded to the back end domain. For one to one associations grails creates a drop down list.
However, you might not want to present that property as a drop down list but something more custom (for example a text field with autocomplete). As soon as you do that the value that comes to the controller from that field, comes in as a String and you have to first:
Clear errors
Perform a findBy based on a given param and assign it to the property of the domain
I really want to avoid doing findBys in the controller as much as possible because it seems like I am doing logic/things that should not go there. The controller should delegate to the Service layer. It is not clear to me from the grails documentation how would I do that by using bindData which seems to work really well with String, date, Integer properties etc.. but I do not see how bindData is used for properties that are other domains.
I also really want to avoid passing the params object to the Service layer as it seems less reusable (or maybe not, correct me if I am wrong). I guess that I do not like how it looks semantically. I would prefer the first over the second:
#Transactional
class WithdrawService {
def addWithdraw(Withdraw withdraw) {
//perform business logic here
}
def createWithdraw(Map params){
//perform business logic here
}
}
Let's take the following example:
class Withdraw {
Person person
Date withdrawDate
}
and the parent lookup table
class Person {
String name
String lastName
static constraints = {
}
#Override
public String toString() {
return "$name $lastName"
}
}
In order for the bind to happen automatically without any extra work grails passes in the following request params to automatically bind the one to one:
person.id
a person map with the id.
[person.id:2, person:[id:2], withdrawDate:date.struct, withdrawDate_month:11, create:Create, withdrawDate_year:2015, withdrawDate_day:10, action:save, format:null, controller:withdraw]
What is the best way to go about this?
Pass two hidden fields that look exactly like this: person.id:2, person:[id:2] that get populated as a result of the Ajax call that populates the autocomplete?
In the controller do a Person.findBySomeKnownProperty(params.someKnownValue)
Or any other approach?

Operation save in Grails on a POGO

I'm beginner in Grails and I have a problem when I try to save a POGO
I have created 1 domain class
class Book {
String title
}
Then, I have generated the controller and view automatically.
Now, I want to be able to create a book with the code by clicking "create" (I know it is possible directly with the code generated but for my example I want to do it by the code). To do this, I have modified the method 'save(Book bookInstance)' in the controller like this
#Transactional
def save(Book bookInstance) {
def book = new Book(title:"New Grails Book").save()
But, when I go to the URL localhost:8080/myApp/book/create and then I click "Create", I have the error
message -> /myApp/WEB-INF/grails-app/views/book/save.jsp
description -> The requested resource is not available.
When I put this code in bootStrap, it is OK, so I don't understand why it is not in the controller
When you have a hasMany property in a domain class, Grails adds a Set property to the domain class with an AST transformation (so it's actually there in the bytecode, and it's visiable to Java) to represent the collection, and when you add a belongsTo a field of that type is added. So it's as if you had this code:
class Author {
Set<Book> books
static hasMany = [books: Book]
String name
}
and
class Book {
Author author
static belongsTo = [author: Author]
String title
}
The AST xform uses the map key as the field name, so you can use any valid field name, but the convention is to do what you did.
Properties are nullable:false by default, so your code doesn't save the Book instance because you didn't set the author property. When doing this explicitly you typically don't create the Book directly, but instead add it to the Author's collection using the dynamic addToBooks method. This sets the author field back-reference and when you save the author, the book is transitively validated and saved. This is all handled for you when you have code like new Book(params).save(), and you can do it directly, e.g.
Author author = ...
def book = new Book(title:"New Grails Book", author: author).save()
If you're using a generated controller and GSPs, there should be an author id in the params map, it'll likely be author.id, so that first line would be
Author author = Author.get(params['author.id'])
but you can add
println params
at the top of the action method to see all of the submitted params.
In general you don't want to look at the return value of the save call, since it will be null if there's a validation error and there's no way to retrieve the errors. So change
def book = new Book(...).save()
to
def book = new Book(...)
book.save()
and now you can call book.hasErrors(), book.getErrors(), book.errors, etc. to see if it was successful and if not, what went wrong.
But that's not the exact problem you're seeing, just one you will when you fix your problem. There's no save.gsp, and Grails also looks for save.jsp and confusingly includes that name in the not-found message. The save method is accessed via a POST request, typically from the form generated by the create action, and it either re-displays create.gsp with the submitted data and error messages when validation fails, or redirects to the view action when the save succeeds. There's no need for a save.gsp when using the generated code.

Explicit casting doesn't work in default model binding

I am using ASP.NET MVC2 and Entity Framework. I am going to simplify the situation a little; hopefully it will make it clearer, not more confusing!
I have a controller action to create address, and the country is a lookup table (in other words, there is a one-to-many relationship between Country and Address classes). Let's say for clarity that the field in the Address class is called Address.Land. And, for the purposes of the dropdown list, I am getting Country.CountryID and Country.Name.
I am aware of Model vs. Input validation. So, if I call the dropdown field formLand - I can make it work. But if I call the field Land (that is, matching the variable in Address class) - I am getting the following error:
"The parameter conversion from type
'System.String' to type 'App.Country'
failed because no type converter can
convert between these types."
OK, this makes sense. A string (CountryID) comes from the form and the binder doesn't know how to convert it to Country type. So, I wrote the converter:
namespace App {
public partial class Country {
public static explicit operator Country(string countryID) {
AppEntities context = new AppEntities();
Country country = (Country) context.GetObjectByKey(
new EntityKey("AppEntities.Countries", "CountryID", countryID));
return country;
}
}
}
FWIW, I tried both explicit and implicit. I tested it from the controller - Country c = (Country)"fr" - and it works fine. However, it never got invoked when the View is posted. I am getting the same "no type converter" error in the model.
Any ideas how to hint to the model binder that there is a type converter?
Thanks
A type converter is not the same as an explicit or implicit conversion, it's an object that converts values between various types.
I think you need to create a class inherited from TypeConverter that converts between Country and other types, and apply the TypeConverterAttribute to your class to specify the converter to use :
using System.ComponentModel;
public class CountryConverter : TypeConverter
{
// override CanConvertTo, CanConvertFrom, ConvertTo and ConvertFrom
// (not sure about other methods...)
}
[TypeConverter(typeof(CountryConverter))]
public partial class Country
{
...
}

asp.net mvc: What are the advantages of Model Binding over manual assignments?

Aside from there being less code to write, what are the advantages? Is it more secure?
public JsonResult Update (int id, string name)
{
Person person = new Person{
ID=id,
Name=name
}
SavePerson(person);
return Json(...);
}
OR
public JsonResult Update (Person person)
{
SavePerson(person);
return Json(...);
}
I have to disagree with Nick on the notion of values ending up in the URL string. In fact, there is no difference. Try it! Query string parameters can supply the model values with either method.
Another difference which is possibly significant is that when passing ID and name as arguments, those are the only two fields which can ever be updated. When passing a Person as an argument, potentially other fields could be updated. This may or may not be what you want. But UpdateModel will accept a whitelist of properties you'd like it to update (and similarly for binding a Person instance in an argument), so as long as you remember to consider including a whitelist, there is no real difference here.
To me the biggest difference between the two options you show is who is instantiating the Person instance. When you pass ID and name as arguments, it will always be your controller code which instantiates the Person. When you pass a Person as an argument, it will always be the model binder which instantiates the Person. This could be significant if, rather than instantiating a new Person instance, you would like to materialize an existing instance from a repository.
When using the (int id, string name) approach, it is possible these values would end up in the URL string. The other way, it won't. So, that could possibly be considered more secure.
Other than that, if you change the possible properties in your Person class, you wouldn't have to update the values passed in to the (int id, string name) approach. Although, you can get around this by using UpdateMethod(myPersonInstance).

Resources