Where is the SequenceRange from the walk-method from ExtendedDataModel defined? - ajax4jsf

The ExtendedDataModel from ajax4jsf uses a method called walk, looking like this:
public void walk(FacesContext ctx, DataVisitor dv, Range range, Object argument){}
This method is called several times in my application. Some topics on internet seem to say that it the latter is defined by the rows="x" in the xhtml. However, for me range is always defined as 0 (firstRow) - -1 (getRows).
So I was wondering where this range is defined, so I can figure out why the wrong parameters are passed to it. Debugging and googling hasn't helped me so far.

Range represents visible part of data displayed in table. If you have paginator, then paginator display which page (= from which row to which row) data is presented.
Problem can be in incorrect value of rows attribute of data table (for example rows attribute is missing).
Other place can be in incorrect implementation of data model. Object of data model class can be used as storage for data displayed in rich:dataTable.
Real example:
public class VSDataModel<RecordType> extends ExtendedDataModel<RecordType> implements Arrangeable {
private final FetchList<RecordType> list;
#Override
public void walk(FacesContext ctx, DataVisitor visitor, Range range, Object obj) {
try {
int firstRow = ((SequenceRange) range).getFirstRow();
int numberOfRows = ((SequenceRange) range).getRows();
if(list == null) {
throw new RuntimeException("Underlying list is null!");
}
if(list.getList() == null || firstRow != list.getFirstRow()) {
list.fetch(firstRow, numberOfRows);
}
for (RecordType elem : list.getList()) {
visitor.process(ctx, list.getPK(elem), obj);
}
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}
It is used in Java private VSDataModel<Record> dependentList; and html
<rich:dataTable value="#{bean.dependentList}" rows="#{referenceData.recordsPerPage}">

Related

How to clean up EPStatement#iterator() whose underlying statement is "INSERT INTO"

I'm investigating an issue with Esper 5.5.0. In the code base which I'm working on, an "INSERT INTO" statement is used and it pulls out data with EPStatement#iterator() from the "INSERT INTO" statement. It does return a non-empty Iterator (which looks weird to me though).
The issue is that the Iterator keeps accumulating data and never gets cleaned up. I'm trying to find a way to clean up the data in the Iterator but I don't know how I can do that. Its remove() method throws an Exception and deleting data from the derived window doesn't have any effect on the EPStatement object which corresponds to the "INSERT INTO" statement. How can I clean up the data in the Iterator which corresponds to the "INSERT INTO" statement? (EDIT: Not the one corresponds to the derived window, the one for the "INSERT INTO" statement itself)
Unfortunately I'm even unable to create a simple reproducer. They do something like the following but the Iterator is always empty when I try to replicate that behavior in new code. I would also like to know what is missing to replicate the behavior.
public class MyTest {
#Test
void eplStatementReturningNonEmptyIterator() {
EPServiceProvider engine = EPServiceProviderManager.getDefaultProvider();
EPRuntime rt = engine.getEPRuntime();
EPAdministrator adm = engine.getEPAdministrator();
adm.getConfiguration().addEventType(PersonEvent.class);
adm.createEPL("create window PersonEventWindow.win:keepall() as PersonEvent");
EPStatement epl = adm.createEPL("insert into PersonEventWindow select irstream * from PersonEvent");
rt.sendEvent(new PersonEvent("foo", 1));
rt.sendEvent(new PersonEvent("bar", 2));
// passes, but this question is not about this one
assert count(rt.executeQuery("select * from PersonEventWindow").iterator()) == 2;
// This question is about this one, I want to clean up the Iterator which epl.iterator() returns
assert count(epl.iterator()) == 2;
// (this assertion ^ fails actually; I cannot even replicate the issue)
}
private static int count(Iterator<?> it) {
int count = 0;
while (it.hasNext()) {
it.next();
count++;
}
return count;
}
public static class PersonEvent {
private String name;
private int age;
public PersonEvent(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
}
This code creates named window PersonEventWindow#keepall that keeps all events that ever arrived (its what keepall means). The code executes a fire-and=forget query rt.executeQuery that selects all events from the named window and the iterator returned provides each event. Iterators I don't think allow remove. One option, use a time window that automatically removes data from the named window like for example PersonEventWindow#time(10) which keeps only the last 10 seconds. Another option, execute a fire-and-forget query like rt.executeQuery("delete from PersonEventWindow") and that deletes all events from the named window.
It turned out that the Iterator for "insert into..." returns elements if it selects from a window. In order to clean up the Iterator, we can delete data from the window which the "insert into" query selects data from.
The following code verifies my explanation I believe:
public class MyTest3 {
EPServiceProvider engine;
EPAdministrator epa;
EPRuntime epr;
#BeforeEach
void setUp() {
engine = EPServiceProviderManager.getDefaultProvider();
epa = engine.getEPAdministrator();
epr = engine.getEPRuntime();
}
#Test
#DisplayName("The Iterator gets cleaned up by delete from MyWindow")
void cleanUpIterator() {
epa.getConfiguration().addEventType(MyEvent.class);
epa.createEPL("create window MyWindow.std:unique(id) as MyEvent");
epa.createEPL("insert into MyWindow select id from MyEvent");
epr.sendEvent(new MyEvent(1));
epr.sendEvent(new MyEvent(2));
EPStatement insertIntoAnotherWindow = epa.createEPL("insert into AnotherWindow select id from MyWindow");
assertThat(count(insertIntoAnotherWindow.iterator())).isEqualTo(2); // this returns the events surprisingly
epr.executeQuery("delete from MyWindow");
assertThat(count(insertIntoAnotherWindow.iterator())).isEqualTo(0); // now it's empty
}
public static class MyEvent {
private final int id;
public MyEvent(int id) {
this.id = id;
}
public int getId() {
return id;
}
}
#AfterEach
void tearDown() {
engine.destroy();
}
private static int count(Iterator<?> it) {
int count = 0;
while (it.hasNext()) {
it.next();
count++;
}
return count;
}
}

How to get Parse.com object count in class

I want to get the object count from 5 classes in Parse.com (to check if all objects were fetched successfully).
Because I'm using findObjectsInBackgroundWithBlock: sometimes not all the objects are fetched before I'm using it, that's why I want to check.
How can I do that?
Update 2: just noticed you were asking about iOS. its basically the same principle, use fetchAllIfNeeded like so:
https://parse.com/docs/ios/api/Categories/PFObject(Synchronous).html#/c:objc(cs)PFObject(cm)fetchAllIfNeeded:
Update: a better way than the naive one (below) would probably be using fetchAllIfNeededInBackground:
ArrayList<ParseObject> objectsToFetch = new ArrayList<>();
objectsToFetch.add(object1);
objectsToFetch.add(object2);
objectsToFetch.add(object3);
ParseObject.fetchAllIfNeededInBackground(objectsToFetch, new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
//all are fetched, do stuff
}
});
My native way of doing this is adding an outer boolean array where each boolean is responsible for one of the classes.
When a findObjectsInBackgroundWithBlock's 'done' function runs, I set that boolean to "true" and run a function that checks whether all array is true, if so -> all classes have been fetched and I can continue.
example from my code:
boolean[] itemFetched;
protected void getAllClassesAndDoStuffWithThem() {
itemFetched= new boolean[NUM_OF_CLASSES];
for (int i=0;i<NUM_OF_CLASSES;i++){
final int finalI = i;
itemFetched[i] = false;
parseObjectArray[i].fetchIfNeededInBackground(new GetCallback<ParseObject>() {
#Override
public void done(ParseObject object, ParseException e) {
itemFetched[finalI] = true;
finishInitIfPossible();
}
});
}
}
private void finishInitIfPossible() {
for (int i=0;i<NUM_OF_CLASSES;i++){
if (!itemFetched[i])
return;
}
//all classes fetched
finishInit();
}
private void finishInit() {
//do stuff with all 5 classes
}

Mutable vs. Immutable

What should be considered to make a mutable class immutable? For example: Can we still have push and pop methods in an immutable stack class? Or we should simply remove any method that changes the state of the instantiated object?
The bottom line is: You'd be better to remove the method modifying the state of the instantiated object from the class. But if you want to keep it, then it should create a new object with a different state from the original one and return the new object back.
Here is a more specific answer:
There shouldn't be any methods changing the object state in an immutable class.
There are a lot of void methods which change the state of this object in a mutable class. So we should change the signature of them in a way the return a new object instead of changing "this" object's state.
Also there are a lot of non-void methods which change the state of "this" object and return the value they changed in "this". The signature of these methods should also be changed in a way that they return a new object instead of changing the state of "this". Talking about lists, usually another method (like "peek") is also needed to get a certain value. Check the sample bellow to get what do I mean:
Check out these "push" and "pop" methods for a mutable stack class:
public class Stack <E> {
…
public void push (E e) {
ensureCapacity(); // This method checks for capacity
elements[size++] = e;
}
This method adds a new element at the top of the stack and changes the state of "this" object in this way.
public E pop () {
if (size == 0) throw new IllegalStateException("Stack.pop");
E result = elements[--size];
elements[size] = null;
return result;
}
…
}
This method removes the element at the top of the stack and returns it back and changes the state of "this" object by removing the element.
Now, suppose that we need to change these methods to make this stack immutable. Let's deal with "push" method first:
"push" is a void method which changes the state of "this" object by adding a new element to it. To make the stack immutable we will create a new stack similar to "this" and add the new element to this new stack and return it back:
public class ImmStack <E> {
...
/**
* this method pushes the item to a new object and keeps the original object unchanged
* #param e The item to be pushed
* #return A new list
* #PRE An original list object is required as well as an item to be pushed
* #POST A new list would be returned
*/
#SuppressWarnings({ "unchecked", "rawtypes" }) // All items in this.elements[] are of type E
public ImmStack<E> push (E e) {
ImmStack<E> stc = new ImmStack(getNewElements());
stc.elements=ensureCapacity(stc.elements);
stc.elements[size] = e;
stc.size = size +1;
return stc;
}
"pop" method changes the state of "this" object by removing an element. To make the class immutable we will reate a new stack similar to "this" and remove the element from this new stack and return it back:
/**
* This pop method returns a new stack without the element at the top of the original list
* #return The new stack
* #POST The new stack would be returned
*/
#SuppressWarnings({ "unchecked", "rawtypes" }) // All items in this.elements[] are of type E
public ImmStack<E> pop () {
if (size == 0) throw new IllegalStateException("Stack.pop");
ImmStack<E> stc = new ImmStack(getNewElements());
stc.elements=ensureCapacity(stc.elements);
stc.elements[size-1] = null;
stc.size=size-1;
return stc;
}
The old "pop" method was returning the element at the top. We also need a new method which returns the element at the top to cover this feature:
/**
* Returns item at front of queue without removing.
* #return item at front
* #throws java.util.NoSuchElementException if empty
*/
public E top()
{
if (this.isEmpty())
{
throw new NoSuchElementException("Queue underflow");
}
return elements[size-1];
}
This was just an example. You might have more methods to change in your class to make it immutable.
If your stack is immutable, then by definition it cannot be changed. The push() and pop() methods cannot be completed.
When a method cannot be completed successfully, you can throw an exception. When a method can never be completed successfully, the standard exception to throw is UnsupportedOperationException.
For example:
public E[] push (E e) {
throw new UnsupportedOperationException();
}
EDIT:
You note in a comment that your push() method is just returning a deep copy of the stack with the new element. It looks like you're representing the immutable stack as an instance of a class, and the pushed stack as an array.
You can get the size of one of the two arrays referenced by newElements with newElements.length. So you could write code like this:
public E[] push (E e) {
E[] newElements=getNewElements();
int oldLength = newElements.length;
newElements=ensureCapacity(newElements);
int lastIndexInNewArray = oldLength;
newElements[ lastIndexInNewArray ] = e;
return newElements;
}
Below is an implementation of immutable stack in C#.
Pushing and popping give you back an entirely new stack, and Peek lets you look at the top of the stack without popping it.
Note that copying the entire stack is not necessary.
That is how immutable structures are implemented in any nontrivial cases. Nontrivial immutable structures are very useful in certain cases. Posters saying that this cannot be done are much misinformed.
The original code and more information can be found here:
https://blogs.msdn.microsoft.com/ericlippert/2007/12/04/immutability-in-c-part-two-a-simple-immutable-stack/
public interface IStack<T> : IEnumerable<T>
{
IStack<T> Push(T value);
IStack<T> Pop();
T Peek();
bool IsEmpty { get; }
}
public sealed class Stack<T> : IStack<T>
{
private sealed class EmptyStack : IStack<T>
{
public bool IsEmpty { get { return true; } }
public T Peek() { throw new Exception("Empty stack"); }
public IStack<T> Push(T value) { return new Stack<T>(value, this); }
public IStack<T> Pop() { throw new Exception("Empty stack"); }
public IEnumerator<T> GetEnumerator() { yield break; }
IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
}
private static readonly EmptyStack empty = new EmptyStack();
public static IStack<T> Empty { get { return empty; } }
private readonly T head;
private readonly IStack<T> tail;
private Stack(T head, IStack<T> tail)
{
this.head = head;
this.tail = tail;
}
public bool IsEmpty { get { return false; } }
public T Peek() { return head; }
public IStack<T> Pop() { return tail; }
public IStack<T> Push(T value) { return new Stack<T>(value, this); }
public IEnumerator<T> GetEnumerator()
{
for(IStack<T> stack = this; !stack.IsEmpty ; stack = stack.Pop())
yield return stack.Peek();
}
IEnumerator IEnumerable.GetEnumerator() {return this.GetEnumerator();}
}

Facing Critical Performance issue in Primefaces 4 & 5

I am working on a project which deal with heavy data sets. I am using Primefaces 4 & 5, spring and hibernate. I have to to display a very huge datasets such as min 3000 rows with 100 columns with various features such as sorting, filtering, row-expansion etc. My problem is, my applications took 8 to 10 mins to show the whole page as well as other functionalities(sorting, filtering ) also takes a lot time. My client is not happy at all. However I can use pagination for this but again My client do not want paging. So I decided to use livescroll but unfortunately I failed to implement livescroll with lazyload or without lazyload as there were bugs in PF regarding livescroll. also i have posted this question here earlier but no solution found.
This performance issue is very critical and show stopper for me. To show 3000 rows with 100 columns, the size of the page which is getting loaded is ~10MB.
I have calculated the time consumed by various life-cycles of of JSF, using Phase-listener I figure out that its Browser who is taking time to parse the response rendered by jsf. To complete the all phases my application took only 25 sec.
At minimal I want to increase the performance of my project. Please share any idea, suggestion and anything which could help to overcome this problem
Note: There is no database manipulations in getters and setters as well as no complex business logic.
UPDATE :
This is my datatable without lazyload:
<p:dataTable
style="width:100%"
id="cdTable"
selection="#{controller.selectedArray}"
resizableColumns="true"
draggableColumns="true"
var="cd"
value="#{controller.cdDataModel}"
editable="true"
editMode="cell"
selectionMode="multiple"
rowSelectMode="add"
scrollable="true"
scrollHeight="650"
rowKey="#{cd.id}"
rowIndexVar="rowIndex"
styleClass="screenScrollStyle"
liveScroll="true"
scrollRows="50"
filterEvent="enter"
widgetVar="dt4"
>
Here everything is working except filtering. Once I filter then first page is displayed but unable to sort or livescroll on datatable. Note this I have tested in Primefaces5.
2nd Approch
With lazyload with same datatable
1) When I add rows="100" livescroll happens but problem with row-editing, row-expansion but filter & sorting works.
2) When I remove rows livescroll works with row-editing, row-expansion etc but filter & sorting dont work.
My LazyLoadModel is as follows
public class MyDataModel extends LazyDataModel<YData>
{
#Override
public List<YData> load(int first, int pageSize,
List<SortMeta> multiSortMeta, Map<String, Object> filters) {
System.out.println("multisort wala load");
return super.load(first, pageSize, multiSortMeta, filters);
}
/**
*
*/
private static final long serialVersionUID = 1L;
private List<YData> datasource;
public YieldRecBondDataModel() {
}
public YieldRecBondDataModel(List<YData> datasource) {
this.datasource = datasource;
}
#Override
public YData getRowData(String rowKey) {
// In a real app, a more efficient way like a query by rowKey should be
// implemented to deal with huge data
// List<YData> yList = (List<YData>) getWrappedData();
for (YData y : datasource)
{
System.out.println("datasource :"+datasource.size());
if(y.getId()!=null)
{
if (y.getId()==(new Long(rowKey)))
{
return y;
}
}
}
return null;
}
#Override
public Object getRowKey(YData y) {
return y.getId();
}
#Override
public void setRowIndex(int rowIndex) {
/*
* The following is in ancestor (LazyDataModel):
* this.rowIndex = rowIndex == -1 ? rowIndex : (rowIndex % pageSize);
*/
if (rowIndex == -1 || getPageSize() == 0) {
super.setRowIndex(-1);
}
else
super.setRowIndex(rowIndex % getPageSize());
}
#Override
public List<YData> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String,Object> filters) {
List<YData> data = new ArrayList<YData>();
System.out.println("sort order : "+sortOrder);
//filter
for(YData yInfo : datasource) {
boolean match = true;
for(Iterator<String> it = filters.keySet().iterator(); it.hasNext();) {
try {
String filterProperty = it.next();
String filterValue = String.valueOf(filters.get(filterProperty));
Field yField = yInfo.getClass().getDeclaredField(filterProperty);
yField.setAccessible(true);
String fieldValue = String.valueOf(yField.get(yInfo));
if(filterValue == null || fieldValue.startsWith(filterValue)) {
match = true;
}
else {
match = false;
break;
}
} catch(Exception e) {
e.printStackTrace();
match = false;
}
}
if(match) {
data.add(yInfo);
}
}
//sort
if(sortField != null) {
Collections.sort(data, new LazySorter(sortField, sortOrder));
}
int dataSize = data.size();
this.setRowCount(dataSize);
//paginate
if(dataSize > pageSize) {
try {
List<YData> subList = data.subList(first, first + pageSize);
return subList;
}
catch(IndexOutOfBoundsException e) {
return data.subList(first, first + (dataSize % pageSize));
}
}
else
return data;
}
#Override
public int getRowCount() {
// TODO Auto-generated method stub
return super.getRowCount();
}
}
I am fade up with these issues and becomes show stopper for me. Even i tried Primefaces 5
If your data is loaded from db i suggest you to do a better LazyDataModel like:
public class ElementiLazyDataModel extends LazyDataModel<T> implements Serializable {
private Service<T> abstractFacade;
public ElementiLazyDataModel(Service<T> abstractFacade) {
this.abstractFacade = abstractFacade;
}
public Service<T> getAbstractFacade() {
return abstractFacade;
}
public void setAbstractFacade(Service<T> abstractFacade) {
this.abstractFacade = abstractFacade;
}
#Override
public List<T> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
PaginatedResult<T> pr = abstractFacade.findRange(new int[]{first, first + pageSize}, sortField, sortOrder, filters);
setRowCount(new Long(pr.getTotalItems()).intValue());
return pr.getItems();
}
}
The service is some kind of backend communication (like an EJB) injected in the ManagedBean that use this model.
The service for pagination may be like this:
#Override
public PaginatedResult<T> findRange(int[] range, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
final Query query = getEntityManager().createQuery("select x from " + entityClass.getSimpleName() + " x")
.setFirstResult(range[0]).setMaxResults(range[1] - range[0] + 1);
// Add filter sort etc.
final Query queryCount = getEntityManager().createQuery("select count(x) from " + entityClass.getSimpleName() + " x");
// Add filter sort etc.
Long rowCount = (Long) queryCount.getSingleResult();
List<T> resultList = query.getResultList();
return new PaginatedResult<T>(resultList, rowCount);
}
Note that you have to do the paginated query (with jpa like this the orm do the query for you, but if you don't use orm have to do paginated query, for oracle look at TOP-N query, for example: http://oracle-base.com/articles/misc/top-n-queries.php)
Remember your return obj must be contains also the total record as a fast count:
public class PaginatedResult<T> implements Serializable {
private List<T> items;
private long totalItems;
public PaginatedResult() {
}
public PaginatedResult(List<T> items, long totalItems) {
this.items = items;
this.totalItems = totalItems;
}
public List<T> getItems() {
return items;
}
public void setItems(List<T> items) {
this.items = items;
}
public long getTotalItems() {
return totalItems;
}
public void setTotalItems(long totalItems) {
this.totalItems = totalItems;
}
}
All this is useful if your database table is correctly setup, pay aptention to the execution plan of the possible query and add the right index.
Hope to give some hint to improve you performance
In the end, remember to your final user that the human eyes can't see more that 10-20 record at once, so it is very useless to have thousand record in a page.
You have used the default load implementation which is used in the showcases of Primefaces. This is not the correct implementation for your case where you load your data from a database.
The load method should use the correct query with consideration of :
1) the filter fields that are used, example:
String query = "select e from Entity e where lower(e.f1) like lower('" + filters.get(key) + "'%) and..., etc. for the other fields
2) the sorting columns that are used, example:
query.append("order by ").append(sortField).append(" ").append(SortOrder.ASCENDING.name() ? "" : sortOrder.substring(0, 4)),..., etc. for the other columns.
3) The total count of your query WITH 1) attached to it. Example:
Long totalCount = (Long) entityManager.createQuery("select count(*) from Entity e where lower(e.f1) like lower('filterKey1%') and lower(e.f2) like lower('filterKey2%') ...").getSingleResult();

Show distinct values from IndexedContainers in comboboxes in a table in editing mode

In short: The comboboxes in each field of my table in editing mode is giving me a conversion error when selecting an item, but the same logic and containers are working perfectly well outside of the TableFieldFactory (createField()). What am I doing wrong?
Longer explanation:
I have a container with multiple properties (columns) and items (rows). When I edit the table that is connected to this container, I want comboboxes on some of the column fields. I'm using a TableFieldFactory for that, and it is working like a charm.
I want the combobox in each field to contain the distinct elements from its respective property. My solution to this was to implement a method in my Container class that iterate through all properties in the container and for each property creates a new IndexedContainer with unique values from that property. The method returns a map with PropertyIds/Containers, so that I, in createField(), can pick each container from each property I want to have comboboxes for.
Example
So, say I have three propertyId's, Foo, Bar and Baz which each "contains" several items of which some are the same, like so:
Foo
Chris
Chris
Meg
Meg
Meg
Stewie
Stewie
... and the same for Bar and Baz, only other values...
The getDistinctContainers() method returns a Map, looking like this:
Key: PropertyId: Foo
Value: Container: contains propertyId [Foo] and the unique values of Foo, ie. [Chris, Meg, Stewie]
Key: PropertyId: Bar
Value: ... and so forth...
When I am about to set the container datasource in createField(), the container looks like this (for property Foo):
allItemIds: [0, 1, 2]
items: {2={Foo=Stewie}, 1={Foo=Meg}, 0={Foo=Chris}}
propertyIds: [Foo]
... which seems alright to me...
Now, the table shows the comboboxes in each field as intended. But when I click an item in a combobox, it gives me the following conversion error:
com.vaadin.data.util.converter.Converter$ConversionException: Unable to convert value of type java.lang.Integer to model type class java.lang.String. No converter is set and the types are not compatible.
at com.vaadin.data.util.converter.ConverterUtil.convertToModel(ConverterUtil.java:181)
at com.vaadin.ui.AbstractField.convertToModel(AbstractField.java:745)
Note:
I tried creating the same scenario outside of the table, and it worked just fine. So it seems that the comboboxes, with the same logic and the same containers, works fine outside the TableFieldFactory and the createFields() method. I can't put my finger on why they shouldn't work in a TableFieldFactory...
Question:
What do I do to get the comboboxes to set the correct values?
Here's my Container class:
public class SomeContainer extends IndexedContainer {
private static final long serialVersionUID = 1L;
public void addContainerProperties() {
addContainerProperty("Foo", String.class, null);
addContainerProperty("Bar", String.class, null);
addContainerProperty("Baz", String.class, null);
}
public Map<String, Container> getDistinctContainers() {
Map<String, Container> m = new HashMap<String, Container>();
ArrayList<Object> filter = new ArrayList<Object>();
int id = 0;
for (Object propertyId : this.getContainerPropertyIds()) {
Container cont = new IndexedContainer();
cont.addContainerProperty(propertyId, propertyId.getClass(), null);
for (Object itemId : this.getItemIds()) {
Object ob = ((Item) this.getItem(itemId)).getItemProperty(propertyId).getValue();
if ((!filter.contains(ob.toString())) && (ob != null)) {
filter.add(ob.toString());
Item item = cont.addItem(id);
item.getItemProperty(propertyId).setValue(ob);
id++;
}
}
m.put(propertyId.toString(), cont);
}
return m;
}
}
... and here is the relevant code for createField:
#Override
public Field<?> createField(Container container, Object itemId, Object propertyId, com.vaadin.ui.Component uiContext) {
TextField tField = (TextField) DefaultFieldFactory.get().createField(container, itemId, propertyId, uiContext);
tField.setImmediate(true);
// ...some code here that uses the TextField
if (propertyId.equals("Foo")) {
ComboBox select = new ComboBox();
for (Map.Entry<String, Container> entry : distinctContainers.entrySet()) {
if (entry.getKey().equals(propertyId)) {
select.setContainerDataSource(entry.getValue());
}
}
select.setImmediate(true);
select.setItemCaptionPropertyId(propertyId);
select.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
return select;
}
// ... if statements for Bar and Baz left out for brevity...
return tField;
}
Please help me understand what I'm missing!
Thanks in advance!
From the above exception and code snippets we can see that a conversion between Integer (presentation type) and String (model) is required. In this particular case:
presentation type: ItemId = {0,1,2}
model: value of PropertyId = {"Chris", "Meg", "Stewie"}
Since Vaadin has no no built-in IntegerToStringConverter you would need a custom converter:
...
select.setContainerDataSource(entry.getValue());
select.setConverter(new Converter<Object, String>() {
#Override
public String convertToModel(Object itemId, Class<? extends String> paramClass, Locale paramLocale) throws ConversionException {
if (itemId != null) {
IndexedContainer c = (IndexedContainer) entry.getValue();
Object propertyId = c.getContainerPropertyIds().iterator().next();
Object name = c.getItem(itemId).getItemProperty(propertyId).getValue();
return (String) name;
}
return null;
}
#Override
public Object convertToPresentation(String value, Class<? extends Object> paramClass, Locale paramLocale) throws ConversionException {
if (value != null) {
IndexedContainer c = (IndexedContainer) entry.getValue();
Object propertyId = c.getContainerPropertyIds().iterator().next();
for (Object itemId : container.getItemIds()) {
Object name = c.getContainerProperty(itemId, propertyId).getValue();
if (value.equals(name)) {
return itemId;
}
}
}
return null;
}
#Override
public Class<String> getModelType() {
return String.class;
}
#Override
public Class<Object> getPresentationType() {
return Object.class;
}
});
Please notice that is not possible to use explicit Integer<-->String conversion
select.setConverter(new Converter<Integer, String>());
as compiler rejects it. The problem has been described here.
More about Vaadin's converters can be found at:
Book of Vaadin, Chapter 9.2.3: Converting Between Property Type and Representation
Changing the default converters for an application
Creating your own converter for String - MyType conversion
I hope it helps.

Resources