Spring webflow 2 binding: nested object do not follow flow rule - binding

I have an object that has a nested one that is binded in the same view:
class MyForm{
private String var1;
private String var2;
private MyNestedForm nested;
}
class MyNestedForm{
private String var3;
}
and in my jsp:
<form:input path="var1" />
<form:input path="var2" />
<form:input path="nested.var3"/>
As I enter some value in var1 and var2 in my form everything goes well (validations, prev/back buttons...)
But var3 maintain always the last value inserted! Even if I restart the flow from the beginning
Do I missing something?
Many thanks for your help.

Try in both clases implementing java.io.Serializable and adding a generated serial version ID.
Hope this helps.

Related

java struts2 very strange behaviour while using iterator

public class UserAction{
private UserData user;
//getter, setter
public String Load() {
user = UserDao.getInstance().getItem(getUserContext().getId());
request.getSession().setAttribute("item", user);
return super.Load();
}
}
public class PropertyAction {
private List <PropertyData> propertyList;
//getter, setter
#Override
public String execute() throws Exception {
propertyList=PropertyDao.getInstance().getItems();
return "list";
}
}
jsp:
<s:iterator value="propertyList" var="item">
${item.name}
${item.thema}
${item.desc}
</s:iterator>
I want to show very strange behaviour of Struts2.
I click property link -> then run PropertyAction.execute() and it display above jsp.
I click user link -> then run UserAction.Load()
I click property link -> then run PropertyAction.execute() and error has been shown "UserData has no property thema".
I spy what happened and I notice that I set setAttribute with name "item". So if I use var="item" in my iterator in jsp, it doesn not use value from propertyList but from session !
My question is it is correct behaviour ?
This is defined behavior; whether or not it's "correct" is debatable.
Because you're using JSP EL, the Struts request wrapper is responsible for resolving JSP EL expressions. The normal application scopes are searched first (e.g., application, session, request). If nothing is found, only then will the value stack be queried for matching expressions.
If you accessed item via non-JSP EL means, e.g., the <s:property> tag, only the value stack would be queried, and you'd get the expected behavior.
When you mix ELs results are not always what you'd expect, so you must be aware how the frameworks in question relate to each other.

Custom component attribute types

I was wondering if i can pass other types of arguments than int, String to custom components explained here.
My problem is that i want to make a component and i want to pass data of type List, especially List<Map<String, String>> to the component itself. How can i achive this functionality? In other words, how can i pass other arguments to a component in angulardart than int or String?
My related code looks like this:
#NgComponent(
...
)
class MyComponent {
List<Map<String, String>> myList;
...
#NgAttr('myAttr')
set setMyAttribute(List<Map<String, String>> myList) {
this.myList = myList;
}
...
}
Where i use the component:
<div>
...
<mycomponent myAttr="ctrl.returnsAListOfMaps"></mycomponent>
...
</div>
Any idea? Is it possible?
Cheers
With #NgAttr the literal value of the attribute is assigned to the fild.
With #NgOneWay, #NgTwoWay, #NgOneWayOneTime the attribute value is evaluated and the result gets assigned.
#NgCallback is for assigning callback functions.
It is possible to use many kind of types with component attributes (map, list and even object/class).
Here you can find a couple of examples: https://stackoverflow.com/a/21961449/2777805

Calling Methods and Functions

in jsf2 if we have some function like
public String greeting(String gtr) {
return "Hello " + gtr;
}
then from jsf page we can call this function as
<h:outputLabel value="#{greetingBean.greeting['some-name']}"
now my question is i want to pass the dynamic parameter from the same bean class instead of 'some-name' something like value="#{greetingBean.greeting[greetingBean.name]} is it possible ?
i required this because i have value in Map<String, ArrayList> and want to edit particular ArrayList value ?
any suggestions ?
Brackets are used to replace the dot notation. That is,
#{greetingBean.greeting['some-name']}
is the same as
#{greetingBean.greeting.some-name}
So, the greeting method will not be called. Instead, JSF will try to access a greeting property, and then try to access a some-name property of the object returned by greeting property. That is, your code above is already generating an error.
If you are using EL 2.2 and want to call an action, simply put:
#{greetingBean.greeting('some-name')}
or
#{greetingBean.greetingThatReceivesAMap(greetingBean.name)}

How to access nested elements in struts2 with foreach tag?

I have the following problem in Struts 2.
Let's assume i have a class like this
class User {
private String name;
private String address;
public String getName() { return name;}
public String getAddress() { return address;}
}
and a list of users available on ValueStack named : users
and a list of user propertiesavailable also on ValueStack as: userProps.
In this case userProps would be {name, address}.
Now I want to iterate over the users list and dinamycally access one user properties via userProps.
Here is how:
<s:iterator value="#users" var="user">
<s:iterator value="#userProps" var="prop">
**<%--- HOW to get user.name, user.address ???%>**
<s:property value="#user.%{#prop}"/>
</s:iterator>
</s:iterator>
I dont know how to evaluate #user.#data to obtain the value for #user.name or #user.address ??
Thank you.
First, is the line in your example correct? Shouldn't you be trying:
<s:property value="#user.%{#prop}"/>
Second, have you tried using parens? Something like:
<s:property value="#user.(#prop)"/>
According to the OGNL docs it might do what you want (I haven't tried it myself).
http://www.opensymphony.com/ognl/html/LanguageGuide/paren.html
http://www.opensymphony.com/ognl/html/LanguageGuide/chainedSubexpressions.html
If that doesn't help, maybe OGNL's indexed property support would help. See the OGNL Object Indexed Properties section at the end.
http://www.opensymphony.com/ognl/html/LanguageGuide/indexing.html
It seems that Struts2 does not support double evaluation... just what I have tried to do.
But here is my workaround!
<%
ValueStack vs = ActionContext.getContext.getValueStack();
%>
<s:iterator value="#users" var="user">
<s:iterator value="#userProps" var="prop">
<%
String userProp =(String) vs.findValue("#prop");
Object userPropVal = vs.findValue("#users."+userProp);
vs.getContext().put("userPropValKey", userPropVal);
%>
<s:property value="#userPropValKey"/>
</s:iterator>
</s:iterator>
Tadaaa.. and it works!
Great,double evaluation should have been provided. Anyways, what I did is:
Created method that takes params in Action class, Bec action is in Valustack, you can call methods directly passing values for which you need double validation.
And you can call from anywhere..
public Object findValueFromValueStack(String objectRef,String expression){
//get valuStack
//Get value for expression
//Then pass the value and scoped object reference to get the final value..
}
The simplest solution is this:
You need to wrap ActionSupport and implement a method, i.e. eval
public class ActionSupportWrapper extends ActionSupport {
...
public Object eval(String name) {
return ActionContext.getContext().getValueStack().findValue(name);
}
}
Then, you can do what you asked for in your jsp
<s:iterator value="#users" var="user">
<s:iterator value="#userProps" var="prop">
<s:property value="eval('#user.'+#prop)"/>
</s:iterator>
</s:iterator>
Another way is to implement your own tag extending ComponentTagSupport, giving it a name in a tld so you can call it from your jsp
<myPrefix:eval value="'#user.'+#prop" />

ASP.NET MVC: dealing with Version field

I have a versioned model:
public class VersionedModel
{
public Binary Version { get; set; }
}
Rendered using
<%= Html.Hidden("Version") %>
it gives:
<input id="Version" name="Version" type="hidden" value=""AQID"" />
that looks a bit strange. Any way, when the form submitted, the Version field is always null.
public ActionResult VersionedUpdate(VersionedModel data)
{
...
}
How can I pass Version over the wire?
EDIT:
A naive solution is:
public ActionResult VersionedUpdate(VersionedModel data)
{
data.Version = GetBinaryValue("Version");
}
private Binary GetBinaryValue(string name)
{
return new Binary(Convert.FromBase64String(this.Request[name].Replace("\"", "")));
}
Related posts I found.
Link
Suggests to turn 'Binary Version' into 'byte[] Version', but some commenter noticed:
The problem with this approach is that
it doesn't work if you want to use the
Table.Attach(modified, original)
overload, such as when you are using a
disconnected data context.
Link
Suggests a solution similar to my 'naive solution'
public static string TimestampToString(this System.Data.Linq.Binary binary)
{ ... }
public static System.Data.Linq.Binary StringToTimestamp(this string s)
{ ... }
http://msdn.microsoft.com/en-us/library/system.data.linq.binary.aspx
If you are using ASP.Net and use the
SQL Server "timestamp" datatype for
concurrency, you may want to convert
the "timestamp" value into a string so
you can store it (e.g., on a web
page). When LINQ to SQL retrieves a
"timestamp" from SQL Server, it stores
it in a Binary class instance. So you
essentially need to convert the Binary
instance to a string and then be able
to convert the string to an equivalent
Binary instance.
The code below provides two extension
methods to do this. You can remove the
"this" before the first parameter if
you prefer them to be ordinary static
methods. The conversion to base 64 is
a precaution to ensure that the
resultant string contains only
displayable characters and no escape
characters.
public static string ConvertRowVersionToString(this Binary rowVersion) {
return Convert.ToBase64String(rowVersion.ToArray());
}
public static Binary ConvertStringToRowVersion(this string rowVersion) {
return new Binary(Convert.FromBase64String(rowVersion));
}
I think the problem with not seeing it in the bound model on form submission is that there is no Convert.ToBinary() method available to the model binary to restructure the data from a string to it's binary representation. If you want to do this, I think that you'll need to convert the value by hand. I'm going to guess that the value you are seeing is the Base64 encoding of the binary value -- the output of Binary.ToString(). In that case, you'll need to convert it back from Base64 to a byte array and pass that to the Binary() constructor to reconstitute the value.
Have you thought about caching the object server-side, instead? This could be a little tricky as well as you have to detach the object from the data context (I'm assuming LINQ) or you wouldn't be able to reattach it to a different data context. This blog entry may be helpful if you decide to go that route.
You may need to use binding to get a strongly-typed parameter to your action method.
Try rendering using:
<%=Html.Hidden("VersionModel.Version")%>
And defining your action method signature as:
public ActionResult VersionedUpdate([Bind(Prefix="VersionModel")] VersionedModel data)
{
...
}
This post http://forums.asp.net/p/1401113/3032737.aspx#3032737 suggests to use
LinqBinaryModelBinder from http://aspnet.codeplex.com/SourceControl/changeset/view/21528#338524.
Once registered
protected void Application_Start()
{
ModelBinders.Binders.Add(typeof(Binary), new LinqBinaryModelBinder());
}
the binder will automatically deserialize Version field
public ActionResult VersionedUpdate(VersionedModel data)
{ ... }
rendered this way:
<%= Html.Hidden("Version") %>
(See also http://stephenwalther.com/blog/archive/2009/02/25/asp.net-mvc-tip-49-use-the-linqbinarymodelbinder-in-your.aspx)
There are many ways like here
byte[] b = BitConverter.GetBytes(DateTime.Now.Ticks);//new byte [(DateTime.Now).Ticks];
_store.Version = new System.Data.Linq.Binary(b)
(make sure you bind exclude your version),
But the best way is to let the DB handle it...
There are many ways like here
byte[] b = BitConverter.GetBytes(DateTime.Now.Ticks);//new byte [(DateTime.Now).Ticks]; _store.Version = new System.Data.Linq.Binary(b)
(make sure you bind exclude your version),
But the best way is to let the DB handle it...

Resources