Adding POJOs to Table using formatting and sorting still works

There has been lots of questions regarding how to add POJOs into a Table when changing the presentation values for Property objects without breaking Table’s sort functionality.

How about doing it the simple way in which you have full control to decide what and how you put into your table’s container.

Below example takes List of POJOs and decides which one of the POJOs fields are displayed and how they are displayed. NumericString class is used to change the presentation to use correct Locale when formatting monetary values, add dollar symbol and two two fractiondigits, but the actual value for the Vaadin Property instances are unchanged, hence sorting works correctly.

About the other options:

  1. Use BeanItemContainer, but with that you lose the possibility to change how Property values are presented or sorting works wrong.
  2. Use Table.addGeneratedColumn but with this you lose sorting capability.
  3. Override Table.getPropertyValue() and table.getType(Object propertyId), haven’t actually tried this one myself but this just feels wrong way to do it

/* 
@ITMillApache2LicenseForJavaFiles@
 */

package com.sandbox;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.List;

import com.sandbox.common.DataMockup;
import com.sandbox.common.User;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.Table;

public class SimpleTableExample extends CustomComponent {

	final static NumberFormat formatter = NumberFormat.getNumberInstance();

	public SimpleTableExample() {

		formatter.setMaximumFractionDigits(2);
		formatter.setMinimumFractionDigits(2);

		final Table table = new Table();

		// Define container properties
		table.addContainerProperty("Full name", String.class, null);
		table.addContainerProperty("email", String.class, null);
		table.addContainerProperty("accountBalance", NumericString.class, null);

		// Get all user POJOs
		List<User> users = DataMockup.getAllUsers();
		// Add POJOs to container
		for (User user : users) {
			String fullname = user.getFirstname() + " " + user.getLastname();
			String email = user.getEmail();
			// Change presentation value without breaking table sorting
			NumericString accountBalance = new NumericString(user
					.getAccountBalance(), formatter);
			// Create item, use user as id
			Object[] row = new Object[]
 { fullname, email, accountBalance };
			table.addItem(row, user);
		}

		// Define visible columns for table
		table.setVisibleColumns(new Object[] { "Full name", "email",
				"accountBalance" });

		table.setSizeFull();
		setCompositionRoot(table);
	}

	/**
	 * Wrapper class for a BigDecimal to be used in Vaadin Table. Presentation
	 * value does not affect the actual value which is used to sort table items.
	 * <p>
	 * Uses {@link Comparable} and equality methods from {@link BigDecimal}, and
	 * toString uses the formatter (or BigDecimal's own if null).
	 * </p>
	 */
	public class NumericString implements Comparable<NumericString> {

		private final BigDecimal value;
		private final NumberFormat formatter;

		public NumericString(final BigDecimal value,
				final NumberFormat formatter) {
			this.value = value;
			this.formatter = formatter;
		}

		public int compareTo(final NumericString o) {
			return value.compareTo(o.value);
		}

		@Override
		public int hashCode() {
			return value.hashCode();
		}

		@Override
		public boolean equals(final Object o) {
			return value.equals(o);
		}

		@Override
		public String toString() {
			if (formatter == null) {
				return value.toString();
			}
			return "$" + formatter.format(value);
		}
	}

}

Ups, there was a bug in my implementation, this fixed it:


table.addContainerProperty("accountBalance", String.class, null);
=>
table.addContainerProperty("accountBalance", NumericString.class, null);

Cheers!

Is this still the prefered / only way to apply sortable custom columns with BigDecimal values? Or are there any updates after 3 years?

BigDecimal implements Comparable so nothing should be needed to make the column sortable as long as the column datatype is correct in the container.

If you want to customize the presentation of the values, use a converter. You can inherit AbstractStringToNumberConverter (if I remember the name correctly) and customize the formatting, and 7.2 will also include a converter specifically for BigDecimal if I remember correctly.

OK thanks, your are right: sorting works for BigDecimal with a member variable behind.
But not for generated columns. How could I add a Converter to a GeneratedColumn??

You seem to be writing about different parts of the same problem in different threads, which usually leads to getting only partial solutions and people who try to answer getting frustrated because they are guessing based on partial information.

You can add a converter for the real values, not generated columns. Normally you use one or the other, not both for the same column.

If I understand correctly, what you want is an Integer (or BigDecimal) column that is shown differently from the default presentation of Integer and that is sortable. In that case, you should probably only use a converter, have Integer values in the container (those are what sorting will be based on) and use a converter to convert Integer values to strings that are shown.

Note that both converters and column generators are a feature of Table, whereas sorting can only happen in the container which does not know anything about them.

See the javadoc for Table.setConverter(propertyId, converter).