Java Typed Table for JTable and JXTable.
- Why Dimension-TT?
- Core Philosophy
- Requirements
- Installation
- Usage
- Documentation
- Notice
- Build and Release
- Contact
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#E8F4FD', 'primaryTextColor': '#2C3E50', 'primaryBorderColor': '#85C1E9', 'lineColor': '#5DADE2', 'fontFamily': 'arial'}}}%%
flowchart TD
subgraph DEFINE["📝 Definition"]
A["Java Class + @TTColumn<br/><i>id, name, order, kind...</i>"]
end
subgraph BUILD["🔧 Build-time"]
B["Package Scanning"]
C["JDK Class-File API"]
D["TTScanIndex"]
B --> C --> D
end
subgraph RUNTIME["⚡ Runtime"]
E["TTRegistry"]
F["MethodHandles<br/><i>fast accessors</i>"]
G["TTTableModel<T>"]
E --> F --> G
end
subgraph RESULT["🖥️ Typed Table"]
H["TTTable<T>"]
I["setItems(List<T>)"]
J["addItem(T)"]
K["selectedItem() → T"]
H --- I
H --- J
H --- K
end
subgraph UI["🎨 UI"]
L["JTable / JXTable"]
end
DEFINE ==> BUILD
BUILD ==> RUNTIME
RUNTIME ==> RESULT
RESULT ==> UI
style DEFINE fill:#E8F8F5,stroke:#1ABC9C,stroke-width:2px
style BUILD fill:#FEF9E7,stroke:#F4D03F,stroke-width:2px
style RUNTIME fill:#EBF5FB,stroke:#5DADE2,stroke-width:2px
style RESULT fill:#F5EEF8,stroke:#AF7AC5,stroke-width:2px
style UI fill:#FADBD8,stroke:#E6B0AA,stroke-width:2px
Swing tables are powerful, but the default workflow is usually untyped:
- you manually define columns and their classes;
- you keep writing
addRow(new Object[]{...}); - you duplicate column order/name logic across the codebase;
- you end up coupling UI code to column indices.
Dimension-TT solves this by introducing a simple, typed layer:
- typed rows (
T) instead ofObject[]; - schema from annotations (
@TTColumn) for predictable column order and titles; - typed data operations:
setItems(List<T>),addItem(T),selectedItem(); - row icons driven by row/column data (e.g.,
DataType -> icon); - build-time scan using JDK Class-File API to index schemas without loading classes.
Dimension-TT follows a two-phase approach:
- Build-time indexing (classpath scan)
- Scan packages and read
@TTColumnannotations via the JDK Class-File API - Build an in-memory index (
TTScanIndex) containingTTColumnDef(annotation values)
- Runtime binding (fast accessors)
- When you request a schema for
Class<T>, Dimension-TT:- uses the prebuilt index to create
TTColumnSpec(no annotation reflection needed), - binds getters/setters with
MethodHandles(no reflective invoke in the hot path), - builds a typed table model
TTTableModel<T>.
- uses the prebuilt index to create
The goal is: simple API, minimal overhead, predictable behavior.
- Java 25+ with JDK Class-File API.
To use Dimension-TT in your Maven project, add the following dependency to your pom.xml:
<dependency>
<groupId>ru.dimension</groupId>
<artifactId>tt</artifactId>
<version>${revision}</version>
</dependency>Notes:
- If you use SwingX (
JXTable), add thett-swingxmodule as well (artifact name depends on your final publishing layout).- Current repository is a multi-module build (
tt-core,tt-swingx).
Annotate fields or 0-arg methods with @TTColumn.
import ru.dimension.tt.annotation.ColumnKind;
import ru.dimension.tt.annotation.TTColumn;
public class ColumnRow {
@TTColumn(id = "id", order = 0, name = "ID", kind = ColumnKind.NUMBER, visible = false)
private int id;
@TTColumn(id = "name", order = 1, name = "Name", minWidth = 80, preferredWidth = 180)
private String name;
@TTColumn(id = "type", order = 2, name = "Type", kind = ColumnKind.TEXT)
private DataType type;
private String label;
@TTColumn(id = "label", order = 3, name = "Label", editable = true, setter = "setLabel", maxWidth = 300)
public String getLabel() { return label; }
public void setLabel(String label) { this.label = label; }
public ColumnRow(int id, String name, DataType type, String label) {
this.id = id;
this.name = name;
this.type = type;
this.label = label;
}
public int getId() { return id; }
public String getName() { return name; }
public DataType getType() { return type; }
}TTRegistry stores scan results and schema cache.
import ru.dimension.tt.api.TT;
import ru.dimension.tt.api.TTRegistry;
TTRegistry reg = TT.builder()
.scanPackages("com.myapp.rows")
.build();import javax.swing.JTable;
import ru.dimension.tt.swing.JTableTables;
import ru.dimension.tt.swing.TTTable;
TTTable<ColumnRow, JTable> tt = JTableTables.create(reg, ColumnRow.class);
// typed insert
public void handle() {
tt.setItems(java.util.List.of(
new ColumnRow(1, "CPU", DataType.NUMBER, "L1"),
new ColumnRow(2, "Host", DataType.STRING, "L2")
));
}import org.jdesktop.swingx.JXTable;
import ru.dimension.tt.swing.TTTable;
import ru.dimension.tt.swingx.JXTableTables;
TTTable<ColumnRow, JXTable> tt = JXTableTables.create(reg, ColumnRow.class);Row icons are schema-aware: the icon is derived from a column value by columnId.
import javax.swing.Icon;
import ru.dimension.tt.swing.TableUi;
import ru.dimension.tt.swing.icon.*;
Icon icon123 = new Icon() {};
Icon iconAbc = new Icon() {};
IconMapper<DataType> mapper = new IconMapper<>() {
@Override
public Icon iconFor(DataType value) {
return switch (value) {
case NUMBER -> icon123;
case STRING -> iconAbc;
default -> null;
};
}
@Override
public String tooltipFor(DataType value) {
return "Type: " + value;
}
};
var schema = reg.schema(ColumnRow.class);
RowIconProvider<ColumnRow> icons =
RowIconProviders.byEnumColumn(schema, "type", DataType.class, mapper);
// Put the icon into the "name" column renderer
var tt = JTableTables.create(
reg,
ColumnRow.class,
TableUi.<ColumnRow>builder()
.rowIcon(icons)
.rowIconInColumn("name")
.build()
);public handle() {
tt.selectedItem().ifPresent(row -> {
// row is ColumnRow
System.out.println(row.getId() + " " + row.getName());
});
}| EN | RU |
|---|---|
| README in English | README на русском |
- Build-time scan indexes methods currently by name (getter-style methods are expected). If you need overload-safe matching, extend the index to store method descriptors.
- If a class is not present in the scan index, Dimension-TT can fall back to a reflection-based schema loader (configurable).
Requirements: Java 25 (JDK Class-File API) and Maven 3.9+.
Option 1 — without specifying a version
If you run without -Drevision, the default value from pom.xml will be used (${revision} → 26.2.1-SNAPSHOT):
mvn clean installOption 2 — with an explicit version
To build the project with a specific version, override ${revision} at build time:
mvn clean install -Drevision=26.2.3Use this workflow if publishing/deployment is handled by a CI pipeline on tag push.
Linux / macOS (Bash)
export RELEASE_VERSION=26.2.3
git tag -a v"$RELEASE_VERSION" -m "Release $RELEASE_VERSION"
git push origin v"$RELEASE_VERSION"Windows (PowerShell)
$env:RELEASE_VERSION="26.2.3"
git tag -a v"$env:RELEASE_VERSION" -m "Release $env:RELEASE_VERSION"
git push origin v"$env:RELEASE_VERSION"Windows (CMD)
set RELEASE_VERSION=26.2.3
git tag -a v%RELEASE_VERSION% -m "Release %RELEASE_VERSION%"
git push origin v%RELEASE_VERSION%If you need to publish manually from your machine (requires configured settings.xml credentials and GPG signing):
mvn deploy -Pcentral -DperformRelease=true -Drevision=26.2.3Created by @akardapolov