Struts2 Iteration of ArrayList with JavaBean - struts2

This Question may be asked in several threads...but could not fine the correct answer
a Java Bean
package com.example;
public class Document {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
An ArrayList creation of JavaBean as displayed below
package com.example;
import java.util.ArrayList;
public class classdocs {
public ArrayList getData() {
ArrayList docsmx = new ArrayList();
Document d1 = new Document();
d1.setName("user.doc");
Document d2 = new Document();
d2.setName("office.doc");
Document d3 = new Document();
d3.setName("transactions.doc");
docsmx.add(d1);
docsmx.add(d2);
docsmx.add(d3);
return docsmx;
}
}
an Action Class
package com.example;
import java.util.ArrayList;
import com.opensymphony.xwork2.ActionSupport;
public class FetchAction extends ActionSupport {
private String username;
private String message;
private ArrayList docsmx = new ArrayList();
public ArrayList getDocuments() {
return docsmx;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String execute() {
classdocs cx = new classdocs();
if( username != null) {
docsmx = cx.getData();
return "success";
} else {
message="Unable to fetch";
return "failure";
}
}
}
Jsp with Struts2 Iterator Tag
Documents uploaded by the user are:</br>
<s:iterator value="docsmx">
<s:property value="name" /></br>
</s:iterator>
Question Why the ArrayList of Bucket containing JavaBean not displayed when Iterated ...
Am I doing some thing wrong ???
with regards
karthik

Depending your version, you should either provide a getter for docsmx (preferred, pre-S2.1.mumble), or make docsmx public (not as preferred, S2.1+).
Or, based on your code, use the correct getter:
<s:iterator value="documents">
<s:property value="name" /></br>
</s:iterator>
A couple of notes: documents should likely be declared a List, not ArrayList, although in this case it almost certainly doesn't matter. It's a good habit to get in to, though, coding to an interface when the implementation doesn't matter.
I'd also consider tightening up the code a little bit:
public String execute() {
if (username == null) {
message = "Unable to fetch";
return "failure";
}
docsmx = cs.getData();
return "success";
}
This allows a more natural reading, makes it more clear what the two states are (success and failure), keeps them very distinct, and slightly shorter.

Related

selectOneMenu with complex objects, is a converter necessary? [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 7 years ago.
Is a Converter necessary for a <h:selectOneMenu> or <p:selectOneMenu> with arbitrary user-created classes as its values? I mean, is the following code supposed to work without a converter?
<p:selectOneMenu value="#{bean.language}">
<f:selectItems value="#{bean.allLanguages}" />
</p:selectOneMenu>
and
#Named(value = "bean")
#ConversationScoped
public class Bean {
private Language language; // appropriate getter and setter are present
public List<SelectItem> getAllLanguages() {
// populates a list of select items with Strings as item labels and Languages as item values
}
}
I have a similar code with an enum as the type (Language) and it works perfectly. But when I replace the type with a normal java class, I get a conversion error.
You need a converter here, as JSF will assume strings by default, that is the way you coded it. JSF has no idea how to convert your pseudo entities to strings and vice versa.
Some notes:
1 . Your getAsString method defines your identifier for your entities/POJOs, not what the JSF (or whatever) select gets as itemLabel.
2 . Your converter can dig into the DB for real entities using this infamous article:
http://balusc.blogspot.de/2011/09/communication-in-jsf-20.html#ConvertingAndValidatingGETRequestParameters
You can also use CDI annotations with that "pattern".
3 . Your value = "bean"is redundant and the CDI scope of choice is usually #ViewScoped. However, you have to keep in mind that CDI #Named + JSF #ViewScoped isn't working together without using Seam 3 or Apache MyFaces CODI.
You do not need a converter, if you use this little class that I wrote :-) It can back selectOne and selecteMany components. It requires that your class's toString() provides a one-to-one unique representation of your object. If you like, you could substitute a method name other than toString(), like toIDString()
To use ListBacker in your ManagedBean, use ListBacker<Type> wherever you would have used List<Type>
#ManagedBean
#RequestScoped
public class BackingBean {
private ListBacker<User> users; // +getter +setter
#PostConstruct
public void init() {
// fill it up from your DAO
users = new ListBacker<User>(userDAO.find());
}
// Here's the payoff! When you want to use the selected object,
// it is just available to you, with no extra database hits:
User thisOneIsSelected = users.getSelectedItemAsObject();
// or for multi-select components:
List<User> theseAreSelected = users.getSelectedItemsAsObjects();
}
In your xhtml file:
<p:selectOneMenu value="#{backingBean.users.selectedItem}">
<f:selectItems value="#{backingBean.users.contents}" var="item" itemValue="#{item.value}" itemLabel="#{item.label}" />
</p:selectOneMenu>
The ListBacker class:
public class ListBacker<T extends AbstractEntityBase> {
// Contains the String representation of an Entity's ID (a.k.a.
// primary key) and the associated Entity object
Map<String, T> contents = new LinkedHashMap<String, T>(); // LinkedHashMap defaults to insertion-order iteration.
// These hold values (IDs), not labels (descriptions).
String selectedItem; // for SelectOne list
List<String> selectedItems; // for SelectMany list
public class ListItem {
private String value;
private String label;
public ListItem(String value, String label) {
this.value = value;
this.label = label;
}
public String getValue() {
return value;
}
public String getLabel() {
return label;
}
}
public ListBacker() {}
public ListBacker(List<T> lst) {
put(lst);
}
public void clear() {
contents.clear();
selectedItem = null;
if(selectedItems != null) {
selectedItems.clear();
}
}
public List<ListItem> getContents() {
return convert(contents);
}
public String getSelectedItem() {
return selectedItem;
}
public void setSelectedItem(String selectedItem) {
this.selectedItem = selectedItem;
}
public List<String> getSelectedItems() {
return selectedItems;
}
public void setSelectedItems(List<String> selectedItems) {
this.selectedItems = selectedItems;
}
public T getSelectedItemAsObject() {
return convert(selectedItem);
}
public List<T> getSelectedItemsAsObjects() {
return convert(selectedItems);
}
public void put(T newItem) {
contents.put(newItem.toString(), newItem);
}
public void put(List<T> newItems) {
for (T t : newItems) {
put(t);
}
}
// PROTECTED (UTILITY) METHODS
protected List<ListItem> convert(Map<String, T> maps) {
List<ListItem> lst = new ArrayList<ListItem>();
for (Entry<String, T> e : maps.entrySet()) {
lst.add(new ListItem(e.getKey(), e.getValue().desc()));
}
return lst;
}
protected List<T> convert(List<String> ids) {
List<T> lst = new ArrayList<T>();
for (String id : ids) {
lst.add(convert(id));
}
return lst;
}
protected T convert(String id) {
return contents.get(id);
}
}
I have two toString() implementations, one for JPA entities:
public abstract class AbstractEntityBase {
#Override
public final String toString() {
return String.format("%s[id=%s]", getClass().getSimpleName(), getIdForToString().toString());
}
/**
* Return the entity's ID, whether it is a field or an embedded ID class..
* #return ID Object
*/
protected abstract Object getIdForToString();
}
and one for JPA EmbeddedId's:
public abstract class CompositeKeyBase {
#Override
public final String toString() {
return String.format("%s[id=%s]", getClass().getSimpleName(), getIdForToString());
}
/**
* Supports the class's toString() method, which is required for ListBacker.
* Compile a string of all ID fields, with this format:
* fieldName=StringVALUE,field2=STRINGvAlUE2,...,fieldx=stringvalue <br />
* Recommended: start with Eclipse's "generate toString()" utility and move it to getIdForToString()
* #return a 1-to-1 String representation of the composite key
*/
public abstract String getIdForToString();
}
An example implementation of getIdForToString(), for an entity that has one Id field:
#Override
public Object getIdForToString() {
return userID;
}
An example implementation of getIdForToString(), for an EmbeddedId that has two fields:
#Override
public String getIdForToString() {
return "userID=" + userID + ",roleID=" + roleID;
}

struts2 taglib Object access in jsp

HI i have created one action, that contain one Document Object. I want to display those properties in jsp. i used to struts tag i am not able to get it , i am able to get string property of action , but not Object can you please help me... se my code below. i went all suport. i am not able to fix it. i am using tomcat7 .
public class SearchResultAction extends ActionSupport{
private static Logger log = Logger.getLogger(SearchResultAction.class);
private String name;
private DocumentData documentData;
public String execute() throws Exception {
documentData=new DocumentData();
documentData.setdocName("docName");
documentData.setdDocTitle("docTitle");
if (documentData!=null)
{
return SUCCESS;
}else{
return ERROR;
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public DocumentData getDocumentData() {
return documentData;
}
public void setDocumentData(DocumentData documentData) {
this.documentData = documentData;
}
}
My jsp code is:
<s:property value="documentData.docName" default="object is null"/>
My pojo class is:
public class DocumentData {
String docName;
String dDocTitle;
String dDocDate;
String dDocAuther;
// setters and getters for all property
}
Your docName setter doesn't follow JavaBean conventions; does your getter?
E.g., setdocName should be setDocName, the getter getDocName.
OGNL is going to call getDocName(), if the method doesn't exist, you won't get data.

ENTITY object in the JSF SelectOneMenu is not working

I want to get the instance of the Entity from SelectOneMenu so i can assign the entity variables to some other method. But it is pointing to null.
xhtml code
<h:selectOneMenu value="#{statusReport.projectDetID}" converter="ObjectStringConv" onchange="#{statusReport.retrieveReport()}" >
<f:selectItems value="#{statusReport.listOfProjectDetail}"
var="projectDetail" itemLabel="#{projectDetail.project} #{projectDetail.startDate} - #{projectDetail.endDate}"
itemValue="#{projectDetail}" noSelectionValue="Select the Saved Project"/>
</h:selectOneMenu>
statusReport bean
public class StatusReport implements Serializable {
private ProjectDetail projectDetID;
private List<ProjectDetail> listOfProjectDetail;
public List<ProjectDetail> getListOfProjectDetail() {
listOfProjectDetail = projectDetailFacade.findAll();
return listOfProjectDetail;
}
public void setListOfProjectDetail(List<ProjectDetail> listOfProjectDetail) {
this.listOfProjectDetail = listOfProjectDetail;
}
public ProjectDetail getProjectDetID() {
return projectDetID;
}
public void setProjectDetID(ProjectDetail projectDetID) {
this.projectDetID = projectDetID;
}
public void retrieveReport(){
System.out.println(" Processing .....");
if ( projectDetID == null )
{
System.out.println("The object from Select null");
}
else
{
System.out.println("The object from Select menu" + projectDetID.toString());
}
System.out.println("Generated Data:Completed");
}}
ProjectDetail Entity Bean
package com.jira.entity;
import java.io.Serializable;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
/**
* The persistent class for the PROJECT_DETAIL database table.
*
*/
#Entity
#Table(name="PROJECT_DETAIL",schema="weeklyrep")
public class ProjectDetail implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="projectdetail_seq")
#SequenceGenerator(name="projectdetail_seq",schema="weeklyrep",sequenceName="projectdetail_seq", allocationSize=1)
#Column(name="PDETAIL_ID")
private long pdetailId;
private Boolean completed;
#Temporal( TemporalType.DATE)
#Column(name="END_DATE")
private Date endDate;
private Long project;
#Temporal( TemporalType.DATE)
#Column(name="START_DATE")
private Date startDate;
//bi-directional many-to-one association to MajorEvent
#OneToMany(mappedBy="projectDetail",cascade=CascadeType.ALL)
private List<MajorEvent> majorEvents;
//bi-directional one-to-one association to ExecSummary
#OneToOne(mappedBy="projectDetailExec",cascade=CascadeType.ALL)
private ExecSummary execSummary;
public ProjectDetail() {
}
public long getPdetailId() {
return this.pdetailId;
}
public void setPdetailId(Long pdetailId) {
this.pdetailId = pdetailId;
}
public Boolean getCompleted() {
return this.completed;
}
public void setCompleted(Boolean completed) {
this.completed = completed;
}
public Date getEndDate() {
return this.endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
public long getProject() {
return this.project;
}
public void setProject(long project) {
this.project = project;
}
public Date getStartDate() {
return this.startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public List<MajorEvent> getMajorEvents() {
return this.majorEvents;
}
public void setMajorEvents(List<MajorEvent> majorEvents) {
this.majorEvents = majorEvents;
}
public ExecSummary getExecSummary() {
return execSummary;
}
public void setExecSummary(ExecSummary execSummary) {
this.execSummary = execSummary;
}
}
Converter
I don't know if it needs converter, however i don't know how code it.
package com.weeklyreport.converters;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import com.jira.entity.ProjectDetail;
#FacesConverter(value="ObjectStringConv")
public class ObjectStringConv implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String svalue) {
System.out.print("String version of object is:" + svalue);
return "test";
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object ovalue) {
return ovalue.toString();
}
}
Please help me figure this out. Is there a way we get instance of the entity object like this?
Your converter needs to be written that way so that it can convert between ProjectDetail and String based on an unique identifier of ProjectDetail. Usually entities have an id. You need to use this as String value. Here's a kickoff example without any trivial checks like null and instanceof:
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
// Convert ProjectDetail to its unique String representation.
ProjectDetail projectDetail = (ProjectDetail) value;
String idAsString = String.valueOf(projectDetail.getId())
return idAsString;
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
// Convert unique String representation of ProjectDetail back to ProjectDetail object.
Long id = Long.valueOf(value);
ProjectDetail projectDetail = someProjectDetailService.find(id);
return projectDetail;
}
Note that using EJBs in JSF converters (and validators) needs some hackery. See also How to inject #EJB, #PersistenceContext, #Inject, #Autowired, etc in #FacesConverter?

db4o Transparent Persistence Not Working

Using db4o client/server, updates are not working for collection properties of an object. I'm using transparent persistence, but that's not helping. Then, I changed my Collection property to ActivatableCollection, but no luck.
This is the server setup:
private void StartDatabase()
{
IServerConfiguration serverConfiguration = Db4oClientServer.NewServerConfiguration();
serverConfiguration.Networking.MessageRecipient = this;
serverConfiguration.Common.Add(new TransparentActivationSupport());
serverConfiguration.Common.Add(new TransparentPersistenceSupport());
string db4oDatabasePath = AppDomain.CurrentDomain.BaseDirectory;
string db4oDatabaseFileName = ConfigurationManager.AppSettings["db4oDatabaseFileName"];
int databaseServerPort = Convert.ToInt32(ConfigurationManager.AppSettings["databaseServerPort"], CultureInfo.InvariantCulture);
_db4oServer = Db4oClientServer.OpenServer(serverConfiguration, db4oDatabasePath + db4oDatabaseFileName, databaseServerPort);
string databaseUser = ConfigurationManager.AppSettings["databaseUser"];
string databasePassword = ConfigurationManager.AppSettings["databasePassword"];
_db4oServer.GrantAccess(databaseUser, databasePassword);
}
This is the entity that I want to save:
public class Application : ActivatableEntity
And this is the property within the Application entity:
public ActivatableCollection<TaskBase> Tasks { get; private set; }
This is the client code to update each object within the collection:
Application application = (from Application app in db
where app.Name == "Foo"
select app).FirstOrDefault();
foreach (TaskBase task in application.Tasks)
{
task.Description += ".";
}
db.Store(application);
Curiously, db.Commit() didn't work either.
There are two work-arounds, but I'd rather do this the "right" way.
Work-around 1: Call db.Store(task) on each task as the change is made.
Work-around 2: Before calling db.Store(), do this:
db.Ext().Configure().UpdateDepth(5);
Can anyone tell me why the list isn't updating?
If it helps, here is the ActivatableCollection class:
public class ActivatableCollection<T> : Collection<T>, IActivatable
{
[Transient]
private IActivator _activator;
/// <summary>
/// Activates the specified purpose.
/// </summary>
/// <param name="purpose">The purpose.</param>
public void Activate(ActivationPurpose purpose)
{
if (this._activator != null)
{
this._activator.Activate(purpose);
}
}
/// <summary>
/// Binds the specified activator.
/// </summary>
/// <param name="activator">The activator.</param>
public void Bind(IActivator activator)
{
if (_activator == activator) { return; }
if (activator != null && null != _activator) { throw new System.InvalidOperationException(); }
_activator = activator;
}
}
Indeed, transparent persistence needs a call to it's activator before every field access. However the intentions is that you do this with the enhancer-tool instead of implementing manually.
Another note: When you're using CascadeOnUpdate(true) everywhere db4o will end up storing every reachable activated object. If the object-graph is huge, this can be a major performance bottle-neck.
I was able to get transparent activation and persistence to work. I decided not to go with the approach for the reasons mentioned in my comment above. I think the easiest way to handle cascading updates is to simply use a client config like this:
IClientConfiguration clientConfig = Db4oClientServer.NewClientConfiguration();
And then either a bunch of these (this isn't so bad because we can add an attribute to every domain entity, then reflectively do this on each one):
clientConfig.Common.ObjectClass(typeof(Application)).CascadeOnUpdate(true);
Or this:
clientConfig.Common.UpdateDepth = 10;
return Db4oClientServer.OpenClient(clientConfig, databaseServerName, databaseServerPort, databaseUser, databasePassword);
Now, here is the server config that allowed me to get transparent persistence working.
private void StartDatabase()
{
IServerConfiguration serverConfiguration = Db4oClientServer.NewServerConfiguration();
serverConfiguration.Networking.MessageRecipient = this;
serverConfiguration.Common.Add(new TransparentActivationSupport());
serverConfiguration.Common.Add(new TransparentPersistenceSupport());
string db4oDatabasePath = AppDomain.CurrentDomain.BaseDirectory;
string db4oDatabaseFileName = ConfigurationManager.AppSettings["db4oDatabaseFileName"];
int databaseServerPort = Convert.ToInt32(ConfigurationManager.AppSettings["databaseServerPort"], CultureInfo.InvariantCulture);
_db4oServer = Db4oClientServer.OpenServer(serverConfiguration, db4oDatabasePath + db4oDatabaseFileName, databaseServerPort);
string databaseUser = ConfigurationManager.AppSettings["databaseUser"];
string databasePassword = ConfigurationManager.AppSettings["databasePassword"];
_db4oServer.GrantAccess(databaseUser, databasePassword);
}
Hope this helps someone.
I had the same problem with Transparent Activation and Persistence in java. I managed to get it to work cleaning the database and starting from scratch. However, no works by calling commit() after changing the object graph. You must call store() on the root object.
This is a simple example:
/*************** Item.java ******************************************/
import com.db4o.activation.ActivationPurpose;
import com.db4o.activation.Activator;
import com.db4o.collections.ActivatableSupport;
import com.db4o.ta.Activatable;
public class Item implements Activatable {
private String name;
private transient Activator activator;
public Item(String name) {
this.name = name;
}
public String getName() {
activate(ActivationPurpose.READ);
return name;
}
public void setName(String name) {
activate(ActivationPurpose.WRITE);
this.name = name;
}
#Override
public String toString() {
activate(ActivationPurpose.READ);
return "Item [name=" + name + "]";
}
public void activate(ActivationPurpose purpose) {
ActivatableSupport.activate(this.activator, purpose);
}
public void bind(Activator activator) {
this.activator = ActivatableSupport.validateForBind(this.activator, activator);
}
}
/******************* Container.java *********************************/
import java.util.Set;
import com.db4o.activation.ActivationPurpose;
import com.db4o.activation.Activator;
import com.db4o.collections.ActivatableHashSet;
import com.db4o.collections.ActivatableSupport;
import com.db4o.ta.Activatable;
public class Container implements Activatable {
private String name;
private Set<Item> items;
private transient Activator activator;
public Container() {
items = new ActivatableHashSet<Item>();
}
public String getName() {
activate(ActivationPurpose.READ);
return name;
}
public void setName(String name) {
activate(ActivationPurpose.WRITE);
this.name = name;
}
public void addItem(Item item) {
activate(ActivationPurpose.WRITE);
items.add(item);
}
public Set<Item> getItems() {
activate(ActivationPurpose.READ);
return items;
}
#Override
public String toString() {
activate(ActivationPurpose.READ);
return "Container [items=" + items + "]";
}
public void activate(ActivationPurpose purpose) {
ActivatableSupport.activate(this.activator, purpose);
}
public void bind(Activator activator) {
this.activator = ctivatableSupport.validateForBind(this.activator, activator);
}
}
/************* Main.java ********************************************/
import com.db4o.Db4oEmbedded;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.config.EmbeddedConfiguration;
import com.db4o.ta.TransparentActivationSupport;
import com.db4o.ta.TransparentPersistenceSupport;
public class Main {
public static void main() {
EmbeddedConfiguration config = Db4oEmbedded.newConfiguration();
config.common().add(new TransparentActivationSupport());
config.common().add(new TransparentPersistenceSupport());
ObjectContainer db = Db4oEmbedded.openFile(config, System.getProperty("user.home") + "/testTP.db4o");
Container c = new Container();
c.setName("Container0");
ObjectSet<Container> result = db.queryByExample(c);
if(result.hasNext()) {
c = result.next();
System.out.println(c);
}
c.addItem(new Item("Item" + c.getItems().size()));
db.store(c);
System.out.println(c);
db.close();
}
}

Access ApplicationResource.properties file from Action Class in Struts 2

can i access ApplicationResource.properties file keys from Action Class in Struts 2
and update the values of the key ?
I don't think you can update the values of those keys directly, that would kind of defeat the purpose of it being (static) resources.
You can however use placeholders.
ApplicationResources.properties
property.key=Hi {0}, there's a problem with {1}
MyAction.java
public ActionForward execute(ActionMapping mapping,
ActionForm form,
javax.servlet.ServletRequest request,
javax.servlet.ServletResponse response)
throws java.lang.Exception {
MessageResources msgResource = getResources(request);
String msg = msgResource.getMessage("property.key", "Sankar", "updating values in the resources.");
}
Yes its possible.
Lets say if you have a property error.login in applicationResources.properties file.
eg : error.login= Invalid Username/Password. Please try again.
then in the Action class you can access it like this : getText("error.login")
Complete example:
applicationResources.properties
error.login= Invalid Username/Password
LoginAction.java
package net.sumitknath.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport {
private String username;
private String password;
public String execute() {
if (this.username.equals("admin") && this.password.equals("admin123")) {
return "success";
} else {
addActionError(getText("error.login"));
return "error";
}
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

Resources