This tutorial contains notes about NatTableDataSources.
1. NatTable DataSources
Usually data sources for the NatTable are Java objects, which are provided as a list.
Visualizing data from a generic data structure can be very helpful. For example showing data based on a JSON or XML data structure.
2. Exercise - Visualizing JSON data
2.1. Target
The target of this exercise is to visualize a generic JSON data structure in a NatTable.
2.2. Obtaining the dependencies
Reuse the existing example application from the general NatTable tutorial or create a new E4 Sample application.
Adjust the existing target definition or create a new one with the following contents.
-
http://download.eclipse.org/nattable/releases/1.4.0/repository/
-
NatTable Core Feature
-
-
http://download.eclipse.org/eclipse/updates/4.6
-
Eclipse SDK
-
-
https://dl.bintray.com/vogellacompany/codeexamples-javadatamodel/
-
vogella data model feature
-
-
http://download.eclipse.org/tools/orbit/downloads/drops/R20160520211859/repository/
-
Google GSON
-
2.3. The JSON data
In the root of the plugin project a books.json file should be created:
[
{
"id" : "978-0641723445",
"cat" : ["book","hardcover"],
"name" : "The Lightning Thief",
"author" : "Rick Riordan",
"genre" : "fantasy",
"inStock" : true,
"price" : 12.50,
"pages" : 384
}
,
{
"id" : "978-1423103349",
"cat" : ["book","paperback"],
"name" : "The Sea of Monsters",
"author" : "Rick Riordan",
"genre" : "fantasy",
"inStock" : true,
"price" : 6.49,
"pages" : 304
}
,
{
"id" : "978-1857995879",
"cat" : ["book","paperback"],
"name" : "Sophie's World : The Greek Philosophers",
"author" : "Jostein Gaarder",
"genre" : "fantasy",
"inStock" : true,
"price" : 3.07,
"pages" : 64
}
,
{
"id" : "978-1933988177",
"cat" : ["book","paperback"],
"name" : "Lucene in Action, Second Edition",
"author" : "Michael McCandless",
"genre" : "IT",
"inStock" : true,
"price" : 30.50,
"pages" : 475
}
]
2.4. Creating proper NatTable data provider
To provide data for a NatTable different IDataProvider
are necessary.
One for the header and one for the body of the NatTable.
The one for the header takes the keys of the first element of a com.google.gson.JsonArray
and specifies these keys as column header labels.
package com.vogella.nattable.data;
import java.io.Reader;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class JsonColumnHeaderDataProvider implements IDataProvider {
private List<String> colums;
public JsonColumnHeaderDataProvider(Reader reader) {
this(new JsonParser().parse(reader));
}
public JsonColumnHeaderDataProvider(JsonElement jsonArray) {
JsonArray asJsonArray = jsonArray.getAsJsonArray();
JsonObject jsonObject = asJsonArray.get(0).getAsJsonObject();
Set<Entry<String,JsonElement>> entrySet = jsonObject.entrySet();
colums = entrySet.stream().map(entry -> entry.getKey()).collect(Collectors.toList());
}
@Override
public int getColumnCount() {
return this.colums.size();
}
@Override
public int getRowCount() {
return 1;
}
@Override
public Object getDataValue(int columnIndex, int rowIndex) {
return getColumnHeaderLabel(columnIndex);
}
private Object getColumnHeaderLabel(int columnIndex) {
return colums.get(columnIndex);
}
@Override
public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
throw new UnsupportedOperationException();
}
}
For the body a IColumnPropertyAccessor
for JsonElement
objects is used.
package com.vogella.nattable.data;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.nebula.widgets.nattable.data.IColumnPropertyAccessor;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
public class JsonColumnAccessor implements IColumnPropertyAccessor<JsonElement> {
private List<String> colums;
public JsonColumnAccessor(JsonElement jsonElement) {
JsonArray jsonArray = jsonElement.getAsJsonArray();
JsonElement firstJsonEntry = jsonArray.get(0);
JsonObject jsonObject = firstJsonEntry.getAsJsonObject();
Set<Entry<String,JsonElement>> entrySet = jsonObject.entrySet();
colums = entrySet.stream().map(entry -> entry.getKey()).collect(Collectors.toList());
}
@Override
public int getColumnCount() {
return colums.size();
}
@Override
public String getColumnProperty(int columnIndex) {
return colums.get(columnIndex);
}
@Override
public int getColumnIndex(String propertyName) {
return colums.indexOf(propertyName);
}
@Override
public Object getDataValue(JsonElement rowObject, int columnIndex) {
return rowObject.getAsJsonObject().get(getColumnProperty(columnIndex));
}
@Override
public void setDataValue(JsonElement rowObject, int columnIndex, Object newValue) {
// TODO
}
}
A IRowDataProvider
for JsonElement
objects will make use of the JsonColumnAccessor
and manage the underlying data for the NatTable.
package com.vogella.nattable.data;
import java.io.Reader;
import java.util.Iterator;
import org.eclipse.nebula.widgets.nattable.data.IColumnAccessor;
import org.eclipse.nebula.widgets.nattable.data.IRowDataProvider;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
public class JsonDataProvider implements IRowDataProvider<JsonElement> {
private JsonArray jsonArray;
private IColumnAccessor<JsonElement> columnAccessor;
public JsonDataProvider(Reader reader, IColumnAccessor<JsonElement> columnAccessor) {
this(new JsonParser().parse(reader).getAsJsonArray(), columnAccessor);
}
public JsonDataProvider(JsonArray jsonArray, IColumnAccessor<JsonElement> columnAccessor) {
this.jsonArray = jsonArray;
this.columnAccessor = columnAccessor;
}
@Override
public int getColumnCount() {
return this.columnAccessor.getColumnCount();
}
@Override
public int getRowCount() {
return this.jsonArray.size();
}
@Override
public Object getDataValue(int columnIndex, int rowIndex) {
JsonElement rowObj = this.jsonArray.get(rowIndex);
return this.columnAccessor.getDataValue(rowObj, columnIndex);
}
@Override
public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
JsonElement rowObj = this.jsonArray.get(rowIndex);
this.columnAccessor.setDataValue(rowObj, columnIndex, newValue);
}
@Override
public JsonElement getRowObject(int rowIndex) {
return this.jsonArray.get(rowIndex);
}
@Override
public int indexOfRowObject(JsonElement rowObject) {
int index = 0;
for (Iterator<JsonElement> iterator = jsonArray.iterator(); iterator.hasNext();) {
JsonElement element = iterator.next();
index++;
if(rowObject.equals(element)) {
return index;
}
}
return -1;
}
}
2.5. Creating the JSON data part
Now create a new part for the E4 application, which will read the books.json file and visualized this in a NatTable.
package com.vogella.nattable.parts;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import jakarta.annotation.PostConstruct;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
import org.eclipse.nebula.widgets.nattable.grid.GridRegion;
import org.eclipse.nebula.widgets.nattable.grid.layer.ColumnHeaderLayer;
import org.eclipse.nebula.widgets.nattable.layer.CompositeLayer;
import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
import org.eclipse.nebula.widgets.nattable.layer.ILayer;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer;
import org.eclipse.swt.widgets.Composite;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.vogella.nattable.data.JsonColumnAccessor;
import com.vogella.nattable.data.JsonColumnHeaderDataProvider;
import com.vogella.nattable.data.JsonDataProvider;
public class GsonPart {
@PostConstruct
public void postConstruct(Composite parent) throws IOException {
Reader reader = getJsonTestReader();
JsonParser jsonParser = new JsonParser();
JsonElement jsonElement = jsonParser.parse(reader);
JsonDataProvider jsonDataProvider = new JsonDataProvider(jsonElement.getAsJsonArray(),
new JsonColumnAccessor(jsonElement));
DataLayer dataLayer = new DataLayer(jsonDataProvider);
SelectionLayer selectionLayer = new SelectionLayer(dataLayer);
ViewportLayer viewportLayer = new ViewportLayer(selectionLayer);
IDataProvider headerDataProvider = new JsonColumnHeaderDataProvider(jsonElement);
DataLayer headerDataLayer = new DataLayer(headerDataProvider);
ILayer columnHeaderLayer = new ColumnHeaderLayer(headerDataLayer, viewportLayer, selectionLayer);
CompositeLayer compositeLayer = new CompositeLayer(1, 2);
compositeLayer.setChildLayer(GridRegion.COLUMN_HEADER, columnHeaderLayer, 0, 0);
compositeLayer.setChildLayer(GridRegion.BODY, viewportLayer, 0, 1);
new NatTable(parent, compositeLayer);
}
private Reader getJsonTestReader() throws IOException, UnsupportedEncodingException {
Bundle bundle = FrameworkUtil.getBundle(getClass());
URL find = FileLocator.find(bundle, new Path("books.json"), null);
InputStream is = find.openStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
return br;
}
}
3. NatTableDataSources resources
3.1. vogella Java example code
If you need more assistance we offer Online Training and Onsite training as well as consulting