java struts2 very strange behaviour while using iterator - struts2

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.

Related

How to get the list in jsp present in reques using s:select tag struts2 [duplicate]

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;
}

How to Dispatch Action types in Struts 2

I am trying to find the replacement for org.apache.struts.actions.DispatchAction.types in Struts2.
Below code snippet:
if(types != null)
{
if(types.length == forward.length)
{
select.add(type[0]);
}
}
The forward is a string type object and select is a list type array.
The documentation for DispatchAction.types:
types
protected java.lang.Class[] types
The set of argument type classes for the reflected method call. These are the same for all calls, so calculate them only once.
There's not the same thing in Struts2. You should refresh your mind to understand that struts2 works differently than struts-1.
For example you can map your actions directly to the method. You can use SMI for method call like in this answer
You should place the annotation directly on the method. Because if you put it on the class the default method execute() is used for the mapping.
#ParentPackage("basePackage")
#Namespace("/")
#AllowedMethods("test")
public class UserAction {
#Action(value = "userAction")
public String test() {
// your code
rerurn Action.SUCCESS;
}
}
or use wildcard mapping like this answer.
The action name is overridden if used in the same package. The action name maps to a specific method or execute.
You can use wildcard mapping to put a method name in the action.
<action name="*product" class="com.DispatchAction" method="{1}">

Setter of h:selectOneMenu is not invoked [duplicate]

This question already has answers here:
Conversion Error setting value for 'null Converter' - Why do I need a Converter in JSF?
(2 answers)
Closed 6 years ago.
I just tried to change a value of a select input box. Loading the page runs into my breakpoint for the getter method of the pubcategory property. Good so far. Changing the value, does NOT invoke the setter method. I trigger an Richfaces ajax processing. I confirm, that all JSF phases are walked through (I also see the JPA-SQL select queries, where I would expect an update statement for changing the value - well, can't be, if the setter method is not triggered). This is my selectOneMenu code
<h:selectOneMenu id="pubCategoryId" converter="#{pubCategoryConverter}" value="#{pubController.pubCategory}">
<f:selectItems value="#{listPubCategoryController.pubCategories}" var="category" itemLabel="#{category.name}" itemValue="#{category}" />
<a4j:ajax event="change" execute="#this" />
</h:selectOneMenu>
<h:message for="pubCategoryId" style="color:red" />
My converter is invoked on both times. the getAsString method, when I load the page and the getAsObject when the on-change action is triggered. From this I concluse, the change really goes back to the server. But - again - it never triggers the setter method.
#ManagedBean(name = "pubCategoryConverterController")
#FacesConverter(value = "pubCategoryConverter")
//#Named
public class PubCategoryConverter implements Converter {
#Inject
private PubCategoryRepository pubCategoryRepository;
public PubCategoryConverter() {
}
// from page to backing bean
#Override
public Object getAsObject(FacesContext ctx, UIComponent component,
String value) {
PubCategory pubCat = pubCategoryRepository.getPubCategoryById(new Long(
value));
return pubCat;
}
// from backing bean to page
#Override
public String getAsString(FacesContext fc, UIComponent uic, Object o) {
PubCategory pubCat = ((PubCategory) o);
return pubCat.getId().toString();
}
}
Same story if I annotate the converter with #Named instead of #FacesConverter/#ManagedBean. Any clue or hints anyone?
Using JBoss 7.1.1, Richfaces 4.3.3, JSF 2.0
The converter is called in the "Process Validations" phase of the JSF lifecycle whereas the setter is called later, during the "Update Model Values" phase. Each phase goes through the entire page which means a validation error in any component will prevent all model updates. If you're not seeing validation errors on the page try checking your message tags.
The skipping of lifecycle phases is done by calling FacesContext.renderResponse(). See UIInput.executeValidate() and LifeCycleImpl.execute() for details.
I hooked up the phase listener and printed the event.getFacesContext().getMessageList(). And, there is an error although not printed to the <h:Message for="pubCategoryId"/>. The error is msg j_idt18:pubFormE:pubCategoryId: Validation Error: Value is not valid
package com.foo;
import java.util.List;
import java.util.logging.Logger;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseListener;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
public class PhaseTracker implements PhaseListener {
private static final Logger logger = Logger.getLogger("org.exadel.helper");
public void beforePhase(PhaseEvent e) {
List<FacesMessage> msgs = e.getFacesContext().getMessageList();
for (FacesMessage msg : msgs) {
logger.info("before msg " + msg.getSummary() + " :: " + msg.getDetail());
}
logger.info("BEFORE " + e.getPhaseId());
}
public void afterPhase(PhaseEvent e) {
logger.info("AFTER " + e.getPhaseId());
}
}
The issue is with the equals(Object o) method within of the model object (some call that DTO). As stated in many forums, the values that you compare within this method must not look like e.g. this.id == o.id, because it compares instances not the inner state. Use equals instead this.id.equals(o.id). Once that is fixed the error Value is not valid will go away.
After all, I noticed the following. If you want to use the selectOneMenu with the tag attribute converter instead of <f:converter ../>, e.g. ...
<h:selectOneMenu value="#{pubController.pubCategory}" converter="#{pubCategoryConverterController}">
... you need to annotate your converter also as a #ManagedBean instance in addition to #FacesConverter, e.g.
#ManagedBean(name="pubCategoryConverterController")
#FacesConverter(value = "pubCategoryConverter")
On the other hand, if you want to use <f:converter converterId="pubCategoryConverter"> tag, you need to reference the faces converter name - NOT an instance of a managed bean. Notice, there is no EL #{...} around the converter name. However, in this case, you CANNOT inject a bean into your converter. As a consequence, in your converter bean, you need to instantiate a controller from the application context in order to use EJB services. e.g.
PubCategoryController pubCategoryController = ctx.getApplication().evaluateExpressionGet(ctx, "#{pubCategoryController}", PubCategoryController.class);

How to use the selected values from the s:inputtransferselect struts tag

I am unable to find the attribute which holds the selected value in the case of <s:inputtransferselect/> Struts Tag. I referred to the documentation but I'm still unable to figure out which attribute exactly holds the selected values.
In the case of <s:optiontransferselect/>, I was able to get the selected values from the doubleId attribute. I am looking for a similar attribute for <s:inputtransferselect/>.
Inputtransferselect creates an input field, a multi option select list and some buttons to add and remove from the select list. When you submit your form this triggers some javascript to select all of the options in the select list, these options then appear in the list on the java side.
Here is an example.
Your .jsp file:
<s:inputtransferselect
key="cartoonCharacters"
addLabel="Add element"
removeLabel="Remove element"
removeAllLabel="Remove all elements"
upLabel="Move up"
downLabel="Move down"
leftTitle="Add Character"
rightTitle="Existing Characters"
list="cartoonCharacters"
/>
Make sure that your .jsp includes a <s:head/> tag else the javascript required for the inputtransferselect to work won't be available to your page.
To see all available attribute parameters of this tag refer to the documentation.
Your action .java file should contain a list which corisponds to the key and list of your inputtransferselect. To get hold of the values, use the list's getter:
public abstract class MyAction extends AbstractAction
{
private List<String> cartoonCharacters = new ArrayList<>();
public MyAction()
{
cartoonCharacters.add("Popeye");
cartoonCharacters.add("Superman");
cartoonCharacters.add("Scoobydoo");
}
public List<String> getCartoonCharacters()
{
return this.cartoonCharacters;
}
public void setCartoonCharacters(List pCartoonCharacters)
{
this.cartoonCharacters = pCartoonCharacters;
}
public String execute() throws Exception
{
return SUCCESS;
}
}
I should also note that in my implementation I haven't got this to work properly - the javascript to automatically select all options on form submit isn't firing so I had to write my own event for this, it's probably something to do with my other on submit events clashing.

Silverlight DataGridColumn AttachedProperties

I am attempting to create an AttachedProperty for a DataGridColumn within Silverlight 3.0 and I am having some issues.
Here is the AttachedProperty:
public class DataGridColumnHelper
{
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.RegisterAttached("Header", typeof(string), typeof(DataGridColumnHelper),
new PropertyMetadata(OnHeaderPropertyChanged));
private static void OnHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
string header = GetHeader(d);
var dataGridColumn = d as DataGridColumn;
if (dataGridColumn == null)
{
return;
}
dataGridColumn.Header = GetHeader(dataGridColumn);
}
public static string GetHeader(DependencyObject obj)
{
return (string)obj.GetValue(HeaderProperty);
}
public static void SetHeader(DependencyObject obj, string value)
{
obj.SetValue(HeaderProperty, value);
}
}
As you can see it is really simple, I am trying to overcome the limitation that the Header Property in the DataGridColumn class cannot be bound.
This XAML works as expected...
<Controls:DataGridTextColumn Binding="{Binding OwnerName}"
HeaderStyle="{StaticResource DataGridColumnHeaderStyle}"
Behaviors:DataGridColumnHelper.Header="User Name"/>
However this XAML throws an error...(Specifically: {System.Windows.Markup.XamlParseException: AG_E_PARSER_PROPERTY_NOT_FOUND [Line: 224 Position: 112]
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
....})
<Controls:DataGridTextColumn Binding="{Binding OwnerName}"
HeaderStyle="{StaticResource DataGridColumnHeaderStyle}"
Behaviors:DataGridColumnHelper.Header="{Binding Resources.UserNameListViewHeading, Source={StaticResource Labels}}"/>
Just for experimentation I attached this property (with the binding syntax above) to a DataGrid and checked the DataGridColumnHelper.Header property in the OnHeaderPropertyChanged method and the value was correct (and an exception wasn't thrown)
It is my understanding that the object that the AttachedProperty is attached to must be a DependencyProperty. Looking through Reflector, DataGridColumn (from which DataGridTextColumn derives) derives from DependencyProperty.
Can somebody please shed some light on this? I am trying to Localize our application, and I am having trouble with the DataGrid. I am sure I can do this in code-behind, but I am trying to avoid that.
Chris, the problem is very simple, this won't work because the DataGridTextColumn is "detached" from the Visual Tree. Your DataGridTextColumn object is rooted in the Columns collection of the DataGrid - see the indirection. So even attached properties will not work as you expect. Now there is a way to make all this work using something I'm calling Attached Bindings, see:
http://www.orktane.com/Blog/post/2009/09/29/Introducing-nRouteToolkit-for-Silverlight-(Part-I).aspx
Just remember to attach the binding properties using something that is in the VisualTree (so the Grid holding the column would do just fine.)
Hope this helps.
Try using this, im assuming UserName is a property in your viewmodel
<Controls:DataGridTextColumn Binding="{Binding OwnerName}"
HeaderStyle="{StaticResource DataGridColumnHeaderStyle}"
Behaviors:DataGridColumnHelper.Header="{Binding UserName}"/>
I cant test your scenario so my post is just an idea. Might work, might not.

Resources