Consider that I've a excel sheet in below format:
person
age
Foo
29
Bar
27
Now I want to read these values (using POI HSSF) and have to process them. What's the best way to do that?
Note that I do not have a Object Person in my application, becasue the values that may come in excel sheet is arbitrary (i.e. it may not be the person name and age). So, I need to use some kinda HashMap to store these values. In case multiple rows, is it good to have a List !?
public class Grid {
private Row headerColumns;
private List<Row> dataRows;
public Grid() {
dataRows = new LinkedList<Row>();
}
public Grid(int rowCount) {
dataRows = new ArrayList<Row>(rowCount);
}
public void addHeaderRow(List<String> headers) {
this.headerColumns = new Row(headers);
}
public void addDataRow(List<String> data) {
this.dataRows.add( new Row(data) );
}
public List<Row> getAllData() {
List<Row> data = new ArrayList<Row>(1+dataRows.size());
data.add(this.headerColumns);
data.addAll(dataRows);
return data;
}
public Row getHeaderColumns() {
return headerColumns;
}
public List<Row> getDataRows() {
return dataRows;
}
}
class Row {
private List<String> data;
public Row(List<String> data) {
this.data = data;
}
public void addColumn(String columnData) {
data.add(columnData);
}
public List<String> getData() {
return data;
}
}
If the format is defined, make a class that accomodates all those fields.
If the format isn't defined, pass Row-s around, or Lists, or even DOM from excel-to-dom transformation. You have no choice. I'd recommend just stick to POI's native Row and Cell objects.
Yes, you cannot use map if you have multiple key values. And i didn't find some build-in class for this issue. You can try write some kind of wrapper.
If you don't care of speed use simple 2D array like this:
String[][] filter = new String[initial width][initial height];
it can be Object instead of String;
Related
I'm trying to create a custom Itemreader using a HashMap, here is an eaxmple i find it of an itemReader using a list instead of HashMap
public class InMemoryStudentReader implements ItemReader<StudentDTO> {
private int nextStudentIndex;
private List<StudentDTO> studentData;
InMemoryStudentReader() {
initialize();
}
private void initialize() {
StudentDTO tony = new StudentDTO();
tony.setEmailAddress("tony.tester#gmail.com");
tony.setName("Tony Tester");
tony.setPurchasedPackage("master");
StudentDTO nick = new StudentDTO();
nick.setEmailAddress("nick.newbie#gmail.com");
nick.setName("Nick Newbie");
nick.setPurchasedPackage("starter");
StudentDTO ian = new StudentDTO();
ian.setEmailAddress("ian.intermediate#gmail.com");
ian.setName("Ian Intermediate");
ian.setPurchasedPackage("intermediate");
studentData = Collections.unmodifiableList(Arrays.asList(tony, nick, ian));
nextStudentIndex = 0;
}
#Override
public StudentDTO read() throws Exception {
StudentDTO nextStudent = null;
if (nextStudentIndex < studentData.size()) {
nextStudent = studentData.get(nextStudentIndex);
nextStudentIndex++;
}
return nextStudent;
}
}
As you can see here we can iterate on a list by it's position (index), so when we call next time the method read() we garantie that we get the next elment.
But in my case the is no notion of index, as HashMap has no concept of position so there is no way to get an object by position.
haw can update this code to work with my case:
public class InMemoryMouvementReader implements ItemReader<MouvementFileRow> {
#Autowired
private MouvementToMap mvts;
#Override
public MouvementFileRow read() throws Exception {
MouvementFileRow nextMouvement = null;
// the Map
// public Map<Long, MouvementFileRow> getMouvmentFileRowMap() {
// return mouvmentFileRowMap;
// }
mvts.getMouvmentFileRowMap()
return nextMouvement;
}
}
do i need to change the hashMap to LinkedHashMap instead or to convert map to List ?
There are no indexes like 0, 1, ... n but you can use the keys in an specific order (e.g. alphabetic sort). Another approach is to get a Iterator object by calling yourHashMap.keySet().iterator() and use that object as class-attribute instead of the nextStudentIndex-attribute. Then use a code snippet like:
if (yourIterator.hasNext()) return yourHashMap.get(youtIterator.next());
else return null;
If you don't want to use any kind of index in your implementation, then read(idx) can be written in the loop, where read() is going to be called idx times.
I have a problem trying to sort specific columns from a cell table, whcih is populated from the DB, using RPC. Basically I'm trying to sort the family name column alphabetically, and it's just not working. Table gets fully populated, but sorting does not work.
Any ideas why ?
Thanks in advance
// Create the family name column.
final TextColumn<ContactInfo> familyNameColumn = new TextColumn<ContactInfo>() {
#Override
public String getValue(ContactInfo object) {
return object.getFamilyName();
}
};
table.setColumnWidth(familyNameColumn, 20, Unit.PCT);
// Make the family name sortable
familyNameColumn.setSortable(true);
// Add the columns
table.addColumn(familyNameColumn, UserMenuConstants.FAMILY_NAME_COLUMN);
table.addColumn(familyAdministratorColumn, UserMenuConstants.FAMILY_ADMINISTRATOR_COLUMN);
table.addColumn(apartmentNuberColumn, UserMenuConstants.FAMILY_APARTMENT_NUMBER_COLUMN);
table.addColumn(emailColumn, UserMenuConstants.EMAIL_ADDRESS_COLUMN);
table.addColumn(phoneNumberColumn, UserMenuConstants.PHONE_NUMBER_COLUMN);
DBGetContactInfoAsync rpcService = (DBGetContactInfoAsync) GWT.create(DBGetContactInfo.class);
ServiceDefTarget target = (ServiceDefTarget) rpcService;
String moduleRelativeURL = GWT.getModuleBaseURL() + "DBGetContactInfoImpl";
target.setServiceEntryPoint(moduleRelativeURL);
rpcService.getContacts(new AsyncCallback<List<ContactInfo>>() {
#Override
public void onSuccess(List<ContactInfo> result) {
table.setRowCount(result.size());
ListDataProvider<ContactInfo> dataProvider = new ListDataProvider<ContactInfo>();
dataProvider.addDataDisplay(table);
List<ContactInfo> list = dataProvider.getList();
for (ContactInfo contactInfo : result) {
list.add(contactInfo);
}
ListHandler<ContactInfo> listHandler = new ListHandler<ContactInfo>(result);
listHandler.setComparator(familyNameColumn, new Comparator<ContactInfo>() {
#Override
public int compare(ContactInfo o1, ContactInfo o2) {
return o1.getFamilyName().compareTo(o2.getFamilyName());
}
});
table.addColumnSortHandler(listHandler);
}
#Override
public void onFailure(Throwable caught) {
...
}
});
You are making two copies of your data: result and list. The list is connected with dataProvider:
List<ContactInfo> list = dataProvider.getList();
and the listListener is connected with result:
ListHandler<ContactInfo> listHandler = new ListHandler<ContactInfo>(result);
so you are displaying list but sorting the result.
Just replace
new ListHandler<ContactInfo>(result);
with
new ListHandler<ContactInfo>(list);
and it works.
EDIT:
You can make it even easier and pass the result to the ListDataProvider constructor:
new ListDataProvider<ContactInfo>(result);
Then, you don't need to copy values to the list and just do
new ListHandler<ContactInfo>(dataProvider.getList());
Move most of the code in your onSuccess method out of there - there is no reason to call it each time a data is loaded. For example, you can/should set a Comparator only once, etc.
Tell your table which column to use for sorting:
table.getColumnSortList().push(familyNameColumn);
When you finish loading new data, tell your table to sort it:
ColumnSortEvent.fire(table, table.getColumnSortList());
I need to dinamically add columns to GXT grid. I can do that, but problem occurs, when I want to input data for rows. Thing is, that not all rows have specific column. So what I want to achieve is to check if given row has specific column and return proper value.
Problem is, that ValueProvider for my column doesn't allow to use arguments in it's methods. So I can't pass column name to ValueProvider, so it could check if given column exists in specific row and return proper data.
Here is my column:
ColumnConfig<SomeClass, String> column = new ColumnConfig<SomeClass, String> (props.attributeValue(name), 150, name);
Here is my ValueProvider
ValueProvider<LimitDTO, String> attributeValue(String name);
And here is my implementation (simplified):
public String getAttributeValue(String name) {
if(this.attributes.get(name) == null) {
return "";
} else {
return this.attributes.get(name);
}
}
But I get build error:
Method public abstract com.sencha.gxt.core.client.ValueProvider<com.example.SomeClass, java.lang.String> attributeValue(java.lang.String s) must not have parameters
SOLUTION
Thanks to your answers I was able to do it. This is my implementation of ValueProvider in case someone will look for solution. It wasn't so hard after all :)
public class CustomValueProvider implements ValueProvider<SomeClass, String> {
public String column;
public CustomValueProvider(String column) {
this.column = column;
}
#Override
public String getValue(SomeClass object) {
if(object.getAttributes().get(column) == null) {
return "";
} else {
return object.getAttributes().get(column);
}
}
#Override
public void setValue(SomeClass object, String value) {
}
#Override
public String getPath() {
return column.getName();
}
}
And here is how I used it
LimitsValueProvider lvp = new LimitsValueProvider(name);
ColumnConfig<SomeClass, String> newColumn = new ColumnConfig<>(lvp, 150, name);
Thanks a lot!
I would suggest, do not use
props.attributeValue(name)
Instead, you can follow the post Dynamic charts in GXT 3 and you can create your own dynamic value providers (See the section value providers), which will take columnId (path) as input and peform the same functionality.
Remember ValueProvider is just an interface and using GWT.create you provides its default implementation.
I have a JTable that loads data from a database and then generates a summary row at the bottom of the table. I want the user to be able to sort the table, but I'd like the summary row to always remain at the bottom of the table.
I've been trying to create a custom TableRowSorter, but I'm having some trouble figuring it out and getting it to do what I want.
Anyone know how to do this?
Thanks
You need a class which holds whether the value is a summary or not.
Something like this
public class SummarizedValue {
public Integer value;
public boolean summarized;
public String toString() {
return null == value? "" : value.toString();
}
}
public class SummaryComparator implements Comparator<SummarizedValue> {
public int compare(SummarizedValue v1, SummarizedValue v2) {
if (v1.summarized) return 1;
if (v2.summarized) return -1;
return v1.value.compareTo(v2.value);
}
}
public class SummaryBackComparator implements Comparator<SummarizedValue> {
public int compare(SummarizedValue v1, SummarizedValue v2) {
if (v1.summarized) return 1;
if (v2.summarized) return -1;
return v2.value.compareTo(v1.value);
}
}
You need to display the objects of class SummarizedValue in your column and your row sorter should return SummaryComparator. Also your need to override toggle behaviour in RowSorter to use SummaryBackComparator.
Is there any way to add clickHandlers (or any type of handler) to the headers of the columns in a CellTable? I want to add some sorting functionality to my CellTable and I dont see any methods in the Column or Header classes that will allow this. I used this post to figure out how to use the CellTable.
Workaround for click events:
Header<String> columnHeader = new Header<String>(new ClickableTextCell()) {
#Override
public String getValue() {
return columnName;
}
};
columnHeader.setUpdater(new ValueUpdater<String>() {
#Override
public void update(String value) {
Window.alert("Header clicked!");
}
});
table.addColumn(column, columnHeader);
There is no out of the box way of supporting sort as yet on the CellTable. However there is a manual workaround involving a lot of code drudgery. Refer the classes SortableHeader and SortableColumn in the bike shed under expenses sample. You will find the usage in com.google.gwt.sample.expenses.gwt.client.ExpenseDetails. You can use this until something concrete comes out in the next release.
check out directory: http://google-web-toolkit.googlecode.com/svn/trunk/bikeshed
With the final release of GWT 2.1, has there been any support for sortable columns added to the CellTable? Or is it still a roll your own solution after looking at the bikeshed example?
CellTable<Contact> table = new CellTable<Contact>();
// Create name column.
final TextColumn<Contact> nameColumn = new TextColumn<Contact>() {
#Override
public String getValue(Contact contact) {
return contact.name;
}
};
// Create a data provider.
ListDataProvider<Contact> dataProvider = new ListDataProvider<Contact>();
// Connect the table to the data provider.
dataProvider.addDataDisplay(table);
final List<Contact> list = dataProvider.getList();
for (Contact contact : CONTACTS) {
list.add(contact);
}
final ListHandler<Contact> columnSortHandler = new ListHandler<Contact>(
list);
Header<String> columnHeader = new Header<String>(new ClickableTextCell()) {
#Override
public String getValue() {
return "Name";
}
};
columnHeader.setUpdater(new ValueUpdater<String>() {
#Override
public void update(String value) {
if (Window.confirm("Want to do?")){
nameColumn.setSortable(true);
columnSortHandler.setComparator(nameColumn,
new Comparator<Contact>() {
public int compare(Contact o1, Contact o2) {
if (o1 == o2) {
return 0;
}
// Compare the name columns.
if (o1 != null) {
return (o2 != null) ? o1.name.compareTo(o2.name) : 1;
}
return -1;
}
});
} else nameColumn.setSortable(false);
}
});
// Make the name column sortable.
nameColumn.setSortable(false);
// Create address column.
TextColumn<Contact> addressColumn = new TextColumn<Contact>() {
#Override
public String getValue(Contact contact) {
return contact.address;
}
};
// Add the columns.
table.addColumn(nameColumn, columnHeader);
table.addColumn(addressColumn, "Address");
// Add the data to the data provider, which automatically pushes it to the
// widget.
// Add a ColumnSortEvent.ListHandler to connect sorting to the
// java.util.List.
//------------------ Code to add --------------------------------//
VerticalPanel vp = new VerticalPanel();
table.addColumnSortHandler(columnSortHandler);
//------------------ Code end --------------------------------//
// We know that the data is sorted alphabetically by default.
table.getColumnSortList().push(nameColumn);
// Add it to the root panel.
vp.add(table);
RootPanel.get().add(vp);