Why Set doesnt work in web flow and Primefaces - java

I get call in a flow a method which returns a HashSet of Person back. Then i call the Set in my xhtml file with the Primeface-dataTable. Now i want to display the prename of the person, but a error appear and say, he doesn't found "prename"...
Then i put the HashSet in a ArrayList and do the same. And... it works fine! But why?
Set and List use as Superinterfaces Collection & Iterable. So why this don't work with Set?
Here are the parts of the files:
flow.xml
<view-state id="rcpm" view="rc/rcmembers.xhtml">
<on-entry>
<evaluate expression="RCHtmlCache.getCommunityList('rcpm')"
result="flowScope.members" />
</on-entry>
</view-state>
rcmembers.xhtml
<p:dataTable id="table1" var="member" value="#{members}"
sortMode="multiple" rowIndexVar="status"
emptyMessage="The Community is empty.">
<p:column>
<f:facet name="header">
<h:outputText value="Vorname" />
</f:facet>
<h:outputText value="#{member.vorname}" />
</p:column>
RCHtmlCache.java Set Version
public Set<Person> getCommunity(String key) {
return htmlCache.get(key);
}
RCHtmlCache.java List Version
public List<Person> getCommunityList(String key) {
Set<Person> comList = htmlCache.get(key);
ArrayList<Person> result = new ArrayList<Person>();
for (Person person : comList) {
result.add(person);
}
return result;
}
Hope you can explain me this weird incident...

It is just a hint, but I think PrimeFaces only accept the List interface, hence you can't use Set interface, they are not the same.
You may create your own List + Set Adapter class by using the Adapter Pattern. It may suit very well to your problem, since you want to adapt the Set interface to a List interface. If you do so, then you won't need to convert your Set to a List every time.
Take a look at this: http://en.wikipedia.org/wiki/Adapter_pattern
Hope I could help.

DataTable works with DataModels...and DataModels only supports:
* java.util.List
* Array of java.util.Object
* java.sql.ResultSet (which therefore also supports javax.sql.RowSet)
* javax.servlet.jsp.jstl.sql.Result
* Any other Java object is wrapped by a DataModel instance with a single row.
(The above objects are implicitly used to build a DataModel)
See JSF Specification.

Related

JSF: rich datatable filtering, dynamic columns, and passing arguments

I'm working on a rich:datatable on a JSF page. The table can get pretty big and is paged with a rich:datascroller. Most of the columns are hardwired and will always be there, but then there are some optional columns based on additional values that need to be generated for each potential additional value. I've been able to make this happen easily enough. However, I'm running into a problem with filtering.
I'm using a filter on each column. It's placed in the header with the column label and sorting function. That much is working fine on each column, but I'm hitting a snag on filtering due to the way filtermethod works by default. Here's a quick example:
<rich:datatable id="thetable" value=#{backingBean.stuff} var="b">
<!-- First column, standard filter method, works just fine -->
<rich:column sortBy="#{b.field1}" filterMethod="#{filterBean.filterField1}">
<f:facet name="header">
<ui:fragment>
<h:outputText value="Field 1" />
<h:inputText value="#{filterBean.filterMap['Field1']}" />
</ui:fragment>
</f:facet>
#{b.field1}
</rich:column>
<c:forEach items="#{backingBean.extraStuff}" var="e">
<rich:column sortBy="#{b.getExtra(e)}" filterMethod="???">
<f:facet name="header">
<ui:fragment>
<h:outputText value="#{b.getExtra(e).description}" />
<h:inputText value="#{filterBean.filterMap['b.getExtra(e).code']}" />
</ui:fragment>
</f:facet>
#{b.getExtra(e).description}
</rich:column>
</rich:datatable>
The ??? will be covered shortly. As for the filter bean:
public class FilterBean {
public Map<String, String> filterMap = new HashMap<String, String>();
public boolean filterField1(Object current){
return ((BackingBean) current).contains(filterMap.get("Field1"));
}
}
It's fairly straightforward. The filter inputText binds to a preset string in the hashMap, which is retrieved in the method and used to filter so I don't need a separate field for every filter. This is working great, but I still need a separate method for each filter, which brings me to the ??? in the JSF code...
What I'd like to do is pass arguments to the filter method to account for the dynamic columns. In fact, I'd like to simplify the whole class with a single filter method and pass the mapped String in along with the field from the current object. However, this isn't working. I've tried:
filterMethod="#{filterBean.filterStuff(b, 'Field1')}"
but I wind up getting the filter string just fine, but null for the current object. I'm not sure what's going on. If I'm reading the dependencies in the project correctly, I'm using some pretty old versions of EL, JSF, JSP, etc, and I really have no way of changing that. The project does use Seam, though, and I've passed arguments successfully in EL before in this project. Is it just that EL 2.2 supports passing objects while older versions only supported primitives and Strings? Is there any way for me to make this happen or am I stuck without building a ton of extra stuff from the ground up?
Okay, looks like this might be possible with Seam, but it doesn't like iteration variables. I CAN pass the object if I refer to an index in the List from the backing bean, but that doesn't help as I have no way of telling it to search every row...
My use case is a bit different, but basically I had the same problem and found a working solution.
The use case: I have several XHTML-files with their backing-beans all offering a table with a list of entities of different types. In this table there are several columns for some attributes of the entities with the possibility to filter. Since the built-in filter does only a "starts-with" search and I need a more advanced one, I have to use the filterMethod.
But I did not want to mess up my backing-beans with hundreds of simple filter-methods doing all exactly the same (only with different attributes). So I was looking for a more generic way - and this is my approach:
In the backend, I created a new class named FilterMethodWrapper (for easier understanding I put it as nested static class here) and a method to access it:
import org.apache.commons.beanutils.PropertyUtils;
public class BackendBean
{
private String[] filterValues;
// initialize filterValues somewhere, add getter and setter
public static class FilterMethodWrapper
{
private final String fieldName;
private final String filterValue;
public FilterMethodWrapper(final String fieldName, String filterValue)
{
this.fieldName = fieldName;
this.filterValue = filterValue;
}
public boolean doFilter(Object current) throws ...
{
final String stringValue = (String) PropertyUtils.getSimpleProperty(current, fieldName);
// compare stringValue and filterValue somehow (e.g. contains)
// and return result
}
}
public FilterMethodWrapper getFilterMethodWrapper(String fieldName, int filterValueIndex)
{
return new FilterMethodWrapper(fieldName, getFilterValues()[filterValueIndex]);
}
}
And in the XHTMLs use it as follows:
<rich:column filterMethod="#{backendBean.getFilterMethodWrapper('username', 0).doFilter}" filterEvent="onkeyup" >
<f:facet name="header">
<h:panelGrid style="display:inline;">
<h:outputText value="Username"/>
<h:inputText value="#{backendBean.filterValues[0]}" />
</h:panelGrid>
</f:facet>
<h:outputText value="#{_item.username}" />
</rich:column>
Edit: I'm using JSF 1.2 and RichFaces 3.3.3.Final
Edit2: instead of writing the FilterMethodWrapper you could also use some Predicate-implementation and use the apply-method in the frontend (or you write your own Predicate-implementation according to this proposal which is more reusable than this FilterMethodWrapper)

Unable to access property of type java.util.Collections$UnmodifiableSet

I am iterating unmodifiableSet of type EquityStatisticsSet which have instance variable statisticsCurrency. while iterating i am getting following error Property 'statisticsCurrency' not found on type java.util.Collections$UnmodifiableSet.
where i am going wrong? plz help me.
following are xhtml and java file.
.xhtml file:
<p:dataTable id="equityStatisticsTable"
value="#{commonStockController.equityStatistics}"
var="equityStatistics">
<p:column headerText="#{res.business_equity_statistics_statisticsCurrency_Label}">
<gs:textInput
inputName="business_equity_statistics_statisticsCurrency"
inputValue="#{equityStatistics.statisticsCurrency}" />
</p:column>
java code:
public Set<GSEquityStatistics> getEquityStatistics(){
return new HashSet<GSEquityStatistics>(commonStock.getAllStatistics());
}
public Set<GSEquityStatistics> getAllStatistics() {
return Collections.unmodifiableSet(equityStatisticsSet);
}
Exception:
javax.servlet.ServletException: /content/business/security/commonStock.xhtml #166,64
inputValue="#{equityStatistics.statisticsCurrency}": Property 'statisticsCurrency' not found on type java.util.Collections$UnmodifiableSet
javax.faces.webapp.FacesServlet.service(FacesServlet.java:606)
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:147)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
Until the upcoming JSF 2.2, UIData components don't support Set interface. They only support e.g. DataModel, List, Object[], ResultSet, etc. As per JSF 2.2, the Collection will be added, which not only covers List, but also Set.
Your current best bet is to convert the Set to an array via Set#toArray() with help of the new EL 2.2 ability to invoke arbitrary methods:
<p:dataTable ... value="#{commonStockController.equityStatistics.toArray()}">
However, this is fairly expensive as the toArray() is basically invoked on every single iteration. Under the covers, the toArray() iterates over the entire Set and creates an array. There's no "backing array". This ends up in O(n^2) complexity instead of O(1) as in array or ArrayList. If you really can't convert it to an array or List in the model beforehand (not in a getter!), then you'd better use <c:set> to evaluate it once and store it in the request scope.
<c:set var="equityStatistics" value="#{commonStockController.equityStatistics.toArray()}" scope="request" />
<p:dataTable ... value="#{equityStatistics}">

How to sort a Column in a dataTable. JSF 2.0

I'm building a WebApp in jsf 2.0 and it's about storing information and displaying it on the screen. so I've put in some "http://java.sun.com/jsf/html" dataTables to disply some lists. My Java code returns a List and then displays them on screen. but now I have to Sort the columns alphabetically. I believe there's no built in way of doing this, so i'm goign to have to look elsewhere for the task.
I came across This dataTables example, it's pretty awesome but I think I can't give it a List and display the list.
I also came across BalusC's way of incorporating the sorting intot he DataTbal, which is nice, I'm looking for this, but maybe with a jQuery IU.
Is there such an API that can meet my needs? can you point me in the right direction, or do you suggest one? I'd really want one that I just hand over the list in Java, but If I must, I can modify the data to comply with JSON format or some other...
With the native <h:dataTable> you have to do the sorting yourself in your managed bean. You could use existing JSF extension libraries that have them built in such as:
MyFaces Tomahawk - docs
ICEfaces - docs
RichFaces - docs
PrimeFaces - docs
etc, way too many to state.
But if you don't want to use the above toolkits, then in your managed bean, you define your List and sort order (asc or dec). It can be as simple or complex you want.
Change the Ordering library to the SortOrder library, referencing this library: import org.richfaces.component.SortOrder;
The sort order comparator can be defined in a variable programmatically using the <rich:column> attribute:
private SortOrder sorting = SortOrder.unsorted;
This is an example of using SortOrder programmatically using JSF 2.x/RichFaces 4.x. It uses a three-state sort method: unsorted (default), ascending, and descending, and implemented by setting the sortOrder attribute.
Or the comparator default behavior can be overridden in code, as in this example:
#ManagedBean(name="somebean")
#SessionScoped
public class OrderBean implements Serializable {
private static final long serialVersionUID = ....;
private List<Item> items;
private boolean sortAscending;
...
}
In your view, you define the which headers you want to sort with, so add a commandLink to make each header clickable.
<h:dataTable value="#{somebean.items}" var="i">
<h:column>
<f:facet name="header">
<h:commandLink action="#{somebean.sort}"> Sort Column</h:commandLink>
</f:facet>
#{i.name}
</h:column>
</h:dataTable>
Now you have to implement the sort for your bean with basic collections, again, it can be as complex as you can:
private final Comparator NAME_SORT_ASC = new Comparator<Item>() {
#Override
public int compare(Item o1, Item o2) {
return o1.getName().compareTo(o2.getName());
}
}
};
private final Comparator NAME_SORT_DESC = new Comparator<Item>() {
#Override
public int compare(Item o1, Item o2) {
return o2.getName().compareTo(o1.getName());
}
}
};
public String sort() {
Collections.sort(items, sortAscending ? NAME_SORT_ASC : NAME_SORT_DESC );
}
You can make your life easier by reusing stuff instead of doing that for each column, I will let you figure that out. You can use better libraries for Java to help you do the comparator for example with Guava from Google or Collection Commons from Apache.
Instead of doing all that, and reinventing the wheel, use a framework that abstracted all this out for you, they make your life way easier..
There are several component librarys on top of jsf-2.0.
Primefaces for instance has a very powerful datatable component with sorting / filtering options. Primefaces is very easy to integrate into your project and comes with a lot of themes (or you can create your own theme).
Just have a look at the showcase and the documentation.
Other popular component libraries are Richfaces (as per comment datatable sorting not supported) and Icefaces.
You can do it in Richfaces too.
Richfaces 3.3.x supports easy sort:
<rich:column sortable="true" sortBy="#{res.retailerCode}">
<f:facet name="header">
<h:outputText value="#{msg.retailerId}" />
</f:facet>
<h:outputText value="#{res.retailerCode}" />
</rich:column>
In Richfaces 4.x you can sort datatable using Sorting bean:
<rich:column id="cardNumber" sortBy="#{res.instNumber}"
sortOrder="#{cardholderSorting.cardNumberOrder}">
<f:facet name="header">
<a4j:commandLink value="#{msg.cardNumber}"
action="#{cardholderSorting.sortByCardNumber}"
render="cardholderTable" />
</f:facet>
<h:outputText value="#{res.cardNumber}" />
</rich:column>
or your DataModel (extends ExtendedDataModel):
<rich:column id="retailerCode" sortBy="#{rs.retailerCode}" sortOrder="ascending">
<f:facet name="header">
<h:commandLink value="#{msg.retailerId}" style="text-decoration: none; color:black;">
<rich:componentControl target="retailerTable" operation="sort">
<f:param name="column" value="retailerCode" />
<f:param value="" />
<f:param name="reset" value="true" />
</rich:componentControl>
</h:commandLink>
</f:facet>
<h:outputText value="#{rs.retailerCode}" />
</rich:column>
You can add arrows (for sorting order displaying) inside in command link and it will be exact same presentation as in Richfaces 3.3.3.
UPDATE
Starting from RichFaces 4.5 there is support of simple sorting in dataTable (like it was in version 3.3.x).

Radio and Checkbox in primefaces datatable

I have to put radio and chechbox controls in primefaces's 2.2.1 datatable but not as a selection mode controls. I want to bind that controls as a values for the backing bean.
For example:
A have a list of some configurations and in that list only one configuration can be active at one time (radiobox) but every single configuration can be active or not (selectbox).
Datatable doesn't have to be editable, because I will change values in another window. Only controls should be in the datatable.
Is that possible?
Yes, it is definitely possible I do this all the time in my datatables. However, you need to keep in mind that each row will require identification. You can do this with objects or parameters to your listener:
//Backing Bean
#ViewScoped
public class TestBean
{
private ArrayList<Element> elements;
TestBean(){...}
public ArrayList<Element> getElements(){...} //Initialize things here
public class Element
{
/* getter/setter and initialization assumed */
private boolean selected;
private String radioSelection = "one";
private String[] radioChoices = new String[]{"one", "two", "three"};
public void selectMe(ActionEvent evt)
{
System.out.println("Selected -> " + this);
}
}
}
//HTML
<p:dataTable value="testBean.elements" var="element">
<p:column>
<p:commandButton value="Select" actionListener="#{element.selectMe}"
</p:column>
<p:column>
<h:selectBooleanCheckbox value="#{element.selected}" />
</p:column>
<p:column>
<h:selectOneRadio value="#{element.radioSelection}">
<f:selectItems
value="#{element.radioChoices}"
var="item"
itemLabel="#{item}"
itemValue="#{item}"
/>
</h:selectOneRadio>
</p:column>
</p:dataTable>
You can (and might want to) use a parameter using the ID from the element or whatever your preferred pattern is. The key is remembering that each row has its own id and you're creating a set of elements, not a single element. That's where you're most likely to get bound up. Seeing as how each button is a first class citizen you should be able to whatever you want with it.
Edit:
I added a Radio/Checkbox example. It sounds like you're new to JSF so I'd advise reading up on the SelectItem class and run through how combo-boxes etc... work. The key to remember (as I stress above) is that you're rendering a lot of components so if you share a value it can easily lead to behavior you don't want. Encapsulate everything and you're usually in good shape.) You can also look at bindings as a possible solution. It all depends on where you'd rather write your code.

Passing Parameter From One Method To Another

I have a rather silly question, I need to pass a parameter from one method to another method.
I have the following method
public String test(Employees emp)
{
return emp.getempno();
}
I need to pass emp.getempno() to my another method loadDetails();
My problem is I cannot add an argument in loadDetails() method because I am calling this method in couple of other places.
How can I achieve this? I tried putting emp.getempno() in collecion object but problem is test(Employees emp) methood is not being invoked in my second method.
Excuse me for my ignorance, any help is highly appreciable.
Thanks
Update 1
This is how I assign value to test method and getTestValues method is being called from another class when I pass parameter from one page to another.
public void getTestValues(List<Employees> paramList) {
for (Employees dataItem: paramList) {
test(dataItem);
}
}
Update 2
This is my loadDetails() method where I am fetching db values and to display as datatable in jsf page.
private void loadDetails() {
try {
dataDetails = anotherclass.deptDetails(passempno);
} catch (Exception e) {
e.printStackTrace();
logger.error("error from loadDetails" + e.getMessage());
}
}
Basically what I am trying to do is when I click a row in a datatable I would like to pass that row's primary key to second page's bean class so that I could populate datatable in second page.
JSF 1.1 and would like to pass as POST GET with commandlink outputlink in datatable.
Use the following (assuming JSF 1.1):
EmployeeBacking
public class EmployeeBacking {
private List<Employee> list;
public EmployeeBacking() {
list = employeeService.list();
}
// ...
}
employees.jsp
<h:dataTable value="#{employeeBacking.list}" var="employee">
<h:column>
<h:outputText value="#{employee.name}" />
</h:column>
<h:column>
<h:outputLink value="departments.jsp">
<h:outputText value="Show departments" />
<f:param name="employeeId" value="#{employee.id}" />
</h:outputLink>
</h:column>
</h:dataTable>
DepartmentBacking
public class DepartmentBacking {
private Long employeeId;
private List<Department> list;
private void load() {
list = departmentService.list(employeeId);
}
public List<Department> getList() {
if (list == null) load();
return list;
}
// ...
}
(please note the lazy loading in getter, in JSF 1.2 you could better use #PostConstruct method for this)
departments.jsp
<h:dataTable value="#{departmentBacking.list}" var="department">
<h:column>
<h:outputText value="#{department.name}" />
</h:column>
</h:dataTable>
faces-config.xml
<managed-bean>
<managed-bean-name>employeeBacking</managed-bean-name>
<managed-bean-class>com.example.EmployeeBacking</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>departmentBacking</managed-bean-name>
<managed-bean-class>com.example.DepartmentBacking</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>employeeId</property-name>
<value>#{param.employeeId}</value>
</managed-property>
</managed-bean>
What happens here, the outputlink will navigate to departments.jsp with the current employee ID as request parameter and the <managed-property> in faces-config.xml will set it in the department backing and finally the getter on the list will lazily load the right departments based on the employee ID.
OK, I'm still trying to wrap my head around this, but I think it's becoming a bit clearer. In order to make loadDetails() function properly, you need to know an employee number (shown above in passempno). I have two responses:
Best case, it appears that passempno is really a parameter of the loadDetails() method. I.e., the value of passempno is part of the method's behavior. As such, the strongly preferred option is to simply add the employee number as an argument. You state that you don't want to do this because other places are using it -- how are the other clients of the method using it without having an employee number specified?
If this is part of some non-trivial state of the parent class, then possibly you need to sock away the employee number in a field of the object. This is less than desirable because it's hiding (or at least making implicit) important state that loadDetails() needs to function.
If there is a stateful interaction with the backing database, and the employee number here is a piece of that state, I'd recommend factoring out the state of the database interaction into a subsidiary class that holds the employee number and any other state (as suggested in 2 above).
Let me know if this helps; if not... let me know what I missed.
I work on an ERP software for a living. Your LoadDetails method shouldn't take an Employee as a parameter.
I'm assuming loadDetails is on a Load class, and that you have an Employee who scheduled the load, or filled the load. If that's the case, the Load class should have a reference to that Employee from creation time.

Categories