Groovy/Grails validations and hasFieldErrors issue - spring

I have created a custom tag that looks like this:
def textField = { attrs ->
def field = attrs.name.split('\\.')[-1]
log.error("--------- Field is ${field}")
if (attrs.bean && attrs.bean.errors.hasFieldErrors(field)) {
def className = attrs.remove('class')
def classStr = 'errors '
if (className) {
classStr += className
}
attrs.put('class', classStr)
attrs.put('value', attrs.bean[field])
attrs.remove('bean')
}
out << g.textField(attrs)
}
I'm calling it in my GSP like this:
<my:textField bean="${client}" name="client.firstName"/>
<my:textField bean="${client}" name="client.lastName"/>
...
<my:textField bean="${client}" name="client.workPhone"/>
And here is my domain-class
class Client {
String email
String address
String city
String state
String zip
String firstName
String lastName
String phone
String workPhone
String mobilePhone
String birthCountry
String citizenshipCountry
String emergencyContactName
String emergencyPhone
String disabilities
String experience
static constraints = {
email(email:true, unique:true, blank:false)
address(blank:false)
city(blank:false)
state(blank:false)
zip(blank:false)
firstName(blank:false)
lastName(blank:false)
phone(blank:false)
emergencyContactName(blank:false)
emergencyPhone(blank:false)
workPhone(blank:true, nullable:true)
mobilePhone(blank:true, nullable:true)
birthCountry(blank:true, nullable:true)
citizenshipCountry(blank:true, nullable:true)
disabilities(blank:true, nullable:true)
experience(blank:true, nullable:true)
}
static mapping = {
disabilities type: 'text'
experience type: 'text'
}
static hasMany = [courses:ClientCourseMap]
}
The page loads fine except when I actually have a "client" bean. It loads all the way up to the last tag "client.workPhone". Then I get the following exception:
2010-03-06 18:32:35,329 [http-8080-2] ERROR view.GroovyPageView - Error processing GroovyPageView: Error executing tag : org.codehaus.groovy.grails.web.taglib.exceptions.GrailsTagException: Error executing tag : groovy.lang.MissingPropertyException: No such property: client for class: com.personal.Client at /Users/dean/Projects/PersonalGrails/grails-app/views/registration/index.gsp:98 at /Users/dean/Projects/PersonalGrails/grails-app/views/registration/index.gsp:145
The problem is when hasFieldErrors is called on the bean. It passes in "field" which should be "workPhone". Stepping through a debugger shows that field is exactly "workPhone". However, with further inspection into the field variable, it shows that the internal value of field is "client.workPhone" and offset = 7, count = 9, hash = 0. However, if you call toString(), you get back "workPhone" as you'd expect.
I'm wondering of Grails or maybe even Spring is not using this string correctly? It looks like it's trying to use the real value of that string instead of paying attention to the offset/count of that string and getting back what is intended.
Does anyone see something I'm doing wrong? Or do you know of a workaround? I can give whatever info is needed, just ask... This is driving me nuts!

It looks like the intention of your tag is to reduce the amount of boilerplate GSP code needed when rendering a form. Have you considered using the bean-fields plugin instead?

Related

How to pass 2 or more variables using #PathParam in spring mvc? and suppose if I want to test it out using postman how to do that?

I'm trying to fetch value from db using JPA repository method
product findByIdNumberOrCifNumber(String idNumber , String cifNumber);
service class logic:-
public ResponseModel FindByCivIDOrCifNumber(String idNumber,String cifNumber) {
ResponseModel responseModel = new ResponseModel();
Optional<product> civId = Optional.ofNullable(productRepos.findByIdNumber(idNumber));
if (civId.isPresent()) {
responseModel.setResponse(productRepos.findByIdNumberOrCifNumber(idNumber,cifNumber));
} else {
errorModel errorModel1 = new errorModel();
enter image description here errorModel1.setErrorCode(productConstant.INVALID_REQUEST);
errorModel1.setErrorDescription("Requested Civil Id or CifNUmber is not present");
responseModel.setErrorModel(errorModel1);
}
return responseModel;
}
controller class:-
#GetMapping("/getByCifNoOrGetByIdNo")
public ResponseModel getProductByCifNoOrGetByIdNo(#RequestParam String idNumber,#RequestParam String cifNumber ) {
return productService.FindByCivIDOrCifNumber(idNumber,cifNumber);
}
post man:-
kindly help me out how to make it work:)
If you are looking for an answer to pass two or more path variables and test it with postman, you can try this.
#GetMapping("/api/mapping-name/{variable1}/{variable2}")
Here you will be getting two path variables which you can access by the syntax
#PathVariable("variable1") datatype variableName
Now in postman request url you can simply give the respective url, lets say:
https://localhost8080/api/mapping-name/:variable1/:variable2
which automaticaly will give you a key value section in the path variables section in the params with prepopulated key names as per the name you have given. In this case variable1 & variable2.
Give the respective value and it should work.

Spring boot: mockMvc testing controller: Expected: Entity, Actuall: null

How looks my json:
event object
{
...
"game": {
//game fields
}
}
...
}
I am trying to do:
event.setGame(new Game());
And check if there is my value by mockMvc
.andExpect(jsonPath("$.game").value(event.getGame()))
But i am getting error:
java.lang.AssertionError: JSON path "$.game"
Expected : Event(id= null, name= null, ...)
Actual :null
Why i am getting null, if i should get just empty game?
P.S. even if i set fields to game, i will get null
I make .andDo(print), and get :
Body = // event
{
"id":"5f087eec-8bf0-11eb-8dcd-0242ac130003",
"game":
{
"id":null,
"team1":null,
"team2":null,
"gameDate":null,
},
"user":
{
//user fields
}
}
How looks controller:
#GetMapping("/{id}")
public ResponseEntity<GetEventById> getEventById #PathVariable("id") String id) {
GetEventByIResponse dto= service.getEventById(id);
return ResponseEntity
.status(HttpStatus.OK)
.body(dto);
}
In my test i am creating GetEventByIResponse, how it looks:
public class Event {
private String id;
private Game game;
...
}
The JsonPath assert works as follows:
It first parses the path result into a Map/List/Object, to see if the origin was an array/object/simple type.
Then, if it's a Map (like in your case) it tries to parse the path result into the same type as the expected object.
Finally it compare the created object to the expected object using equals().
In your case I see several problems:
The AssertionError talks about an Event although you seem to hand in a Game.
We do not know if the serialization/deserialization works at all
Maybe you should try one of the following:
Place a breakpoint right here to watch the assert steps in your debugger:
Start with simple type comparisons:
.andExpect(jsonPath("$.id").value("foo"))
.andExpect(jsonPath("$.game.id").value("bar"))
Seems like the json path referencing the game child object is incorrect, try below:
.andExpect(jsonPath("$.event.game").value(event.getGame()))

How do I store a comma-separated list in Orchard CMS?

Using Orchard CMS, I am dealing with a record and a part proxy, but cannot figure out how to save it into the DB. In fact, I confess I don't even know how to get the items I'm trying to save into this paradigm. I was originally using enum's for choices:
MyEmum.cs:
public enum Choices { Choice1, Choice2, Choice3, Choice4 }
MyRecord.cs:
public virtual string MyProperty { get; set; }
MyPart.cs:
public IEnumerable<string> MyProperty
{
get
{
if (String.IsNullOrWhiteSpace(Record.MyProperty)) return new string[] { };
return Record
.MyProperty
.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries)
.Select(r => r.Trim())
.Where(r => !String.IsNullOrEmpty(r));
}
set { Record.MyProperty = value == null ? null : String.Join(",", value); }
}
Now, in my service class, I tried something like:
public MyPart Create(MyPartRecord record)
{
MyPart part = Services.ContentManager.Create<MyPart>("My");
...
part.MyProperty = record.MyProperty; //getting error here
...
return part;
}
However, I am getting the following error: Cannot implicitly convert 'string' to System.Collections.Generic.IEnumerable<string>'
Essentially, I am trying to save choices from a checkboxlist (one or more selections) as a comma-separated list in the DB.
And this doesn't even get me over the problem of how do I use the enum. Any thoughts?
For some background:
I understand that the appropriate way to handle this relationship would be to create a separate table and use IList<MyEnum>. However, this is a simple list that I do not intend to manipulate with edits (in fact, no driver is used in this scenario as I handle this on the front-end with a controller and routes). I am just capturing data and redisplaying it in the Admin view for statistical/historical purposes. I may even consider getting rid of the Part (considering the following post: Bertrand's Blog Post.
It should be:
part.MyProperty = new[] {"foo", "bar"};
for example. The part's setter will store the value on the record's property as a comma-separated string, which will get persisted into the DB.
If you want to use enum values, you should use the Parse and ToString APIs that .NET provide on Enum.

Sitecore 6 WFFM: ListField value?

I am building a complex WFFM user control that extends BaseUserControl. This control has multiple fields that get prepopulated based on some business logic. One of the fields is supposed to be a drop down which shows values from a series of Sitecore items. Here is the definition of my ListField property:
private string myListField;
[VisualProperty("My List Field:", 100),
VisualCategory("Appearance"), VisualFieldType(typeof(ListField))]
public string MyListField{
get { return myListField; }
set { myListField= value; }
}
When I debug this, the content of titleFieldList is a string that contains the following XML in URL encoded format:
%3Cquery%20t%3D%22root%22%20vf%3D%22__ID%22%20tf%3D%22Value%22%3E%3Cvalue%3E%7B814FC177-2750-48D6-B7B7-4EE87012C637%7D%3C%2Fvalue%3E%3C%2Fquery%3E
which, decode, is:
<query t="root" vf="__ID" tf="Value">
<value>{814FC177-2750-48D6-B7B7-4EE87012C637}</value>
</query>
I understand the meaning of this XML. It says that all the children of the item whose ID is that Guid are supposed to be used to populate my list, using the template field "__ID" for the value and the template field "value" for the text.
Can someone help me understand what am I supposed to do to bind an asp:DropDownList to this? Is this a particular sitecore object that has been serialized and encoded?
Is there an sc:control that can handle this?
Thanks!
** EDIT **
So I tried the following piece of code
string encodedQuery = TitleFieldList;
string query = HttpUtility.UrlDecode(encodedQuery);
XDocument xmlQuery = XDocument.Parse(query);
if (xmlQuery.Element("query") != null)
{
Dictionary<string, string> nodesDictionary = new Dictionary<string, string>();
string root = xmlQuery.Element("query").Element("value").Value;
string value = xmlQuery.Element("query").Attribute("vf").Value;
string text = xmlQuery.Element("query").Attribute("tf").Value;
Item rootItem = SitecoreUtility.GetItemWithoutSecurity(new ID(root));
ChildList childList = rootItem.GetChildren();
foreach (Item child in childList)
{
string theValue = (value == "__ID") ? child.ID.ToString() : child.Fields[value].ToString();
string theText = child.Fields[text].ToString();
nodesDictionary.Add(theText, theValue);
}
titleDropDownList.DataSource = nodesDictionary;
titleDropDownList.DataTextField = "key";
titleDropDownList.DataValueField = "value";
titleDropDownList.DataBind();
}
and it works. The dropdownlist is populated with the correct data coming from the fields that were selected in the editor. I just can't believe that there is no easier way to do this. Plus how am I supposed to honor the MultipleSelectedValueField and the EmptyChoiceField if present?
Try to change the return type of your property and add attribute TypeConverter. The type specified in TypeConverter is responsible for converting raw string value to a property's return type.
ListItemCollectionConverter - is a converter provided by WFFM
[VisualProperty("My List Field:", 100)]
[VisualCategory("Appearance")]
[VisualFieldType(typeof(ListField))]
[TypeConverter(typeof(Sitecore.Form.Web.UI.Controls.ListItemCollectionConverter.ListItemCollectionConverter))]
public Sitecore.Form.Web.UI.Controls.ListItemCollection MyListField{
get { return myListField; }
set { myListField= value; }
}

linq NullReferenceException question

I have a linq query to a XML dataset, which when executed is generating a NullReferenceException.
XDocument dataDoc = XDocument.Load(new StringReader(e.Result));
var Genres = from genre in dataDoc.Descendants("genres")
where (!genre.Element("ID").IsEmpty)
select (string)genre.Element("id").Value + ',' + (string)genre.Attribute("name").Value + ',' + (string)genre.Attribute("url").Value;
foreach (string myGenre in Genres)
{
}
When executed, the Linq query works fine, but when the code attempts to iterate through the foreach loop, the NullReferenceException occurs.
Now, i think that the issue has to do with the XML data I am reading, which looks like the following:
<genres>
<translated>true</translated>
<genre name="1">
<id>28</id>
<url>http://url1</url>
</genre>
<genre name="2">
<id>12</id>
<url>http://url2</url>
</genre>
</genres>
Is the first child node, which is different in structure, causing the issue?
My class behind this shouldn't be an issue, but is the following (just in case):
public class Genre
{
public string ID { get; set; }
public string Name { get; set; }
public string URL { get; set; }
}
genre.Attribute("url") returns null, since there is no url attribute.
You need to call Element, not Attribute.
EDIT: Calling dataDoc.Descendants("genres") returns the single <genres> element, which is not what you want.
You need to call Descendants("genre") (singular) to get the individual <genre ...> elements.
You could also call dataDoc.Descendants("genres").Elements to get the elements inside the <genres> element.
SLaks has pointed out the mistake in using Attribute rather than Element, but there's another improvement you can make in your code. Currently you're using the Value property and then redundantly casting to string. If you just cast an XAttribute or XElement to string, then if the original reference is null, the result will be null as well, rather than an exception being thrown. There's no point in using Value and casting.

Resources