--- name: tinystruct-patterns description: Expert guidance for developing with the tinystruct Java framework. Use when working on the tinystruct codebase or any project built on tinystruct — including creating Application classes, @Action-mapped routes, unit tests, ActionRegistry, HTTP/CLI dual-mode handling, the built-in HTTP server, the event system, JSON with Builder/Builders, database persistence with AbstractData, POJO generation, Server-Sent Events (SSE), file uploads, and outbound HTTP networking. origin: ECC --- # tinystruct Development Patterns Architecture and implementation patterns for building modules with the **tinystruct** Java framework – a lightweight, high-performance framework that treats CLI and HTTP as equal citizens, requiring no `main()` method and minimal configuration. ## Core Principle **CLI and HTTP are equal citizens.** Every method annotated with `@Action` should ideally be runnable from both a terminal and a web browser without modification. This "dual-mode" capability is the core design philosophy of tinystruct. ## When to Activate ### When to Use - Creating new `Application` modules by extending `AbstractApplication`. - Defining routes and command-line actions using `@Action`. - Handling per-request state via `Context`. - Performing JSON serialization using the native `Builder` and `Builders` components. - Working with database persistence via `AbstractData` POJOs. - Generating POJOs from database tables using the `generate` command. - Implementing Server-Sent Events (SSE) for real-time push. - Handling file uploads via multipart data. - Making outbound HTTP requests with `URLRequest` and `HTTPHandler`. - Configuring database connections or system settings in `application.properties`. - Debugging routing conflicts (Actions) or CLI argument parsing. ## How It Works The tinystruct framework treats any method annotated with `@Action` as a routable endpoint for both terminal and web environments. Applications are created by extending `AbstractApplication`, which provides core lifecycle hooks like `init()` and access to the request `Context`. Routing is handled by the `ActionRegistry`, which automatically maps path segments to method arguments and injects dependencies. For data-only services, the native `Builder` and `Builders` components should be used for JSON serialization to maintain a zero-dependency footprint. The database layer uses `AbstractData` POJOs paired with XML mapping files for CRUD operations without external ORM libraries. ## Examples ### Basic Application (MyService) ```java public class MyService extends AbstractApplication { @Override public void init() { this.setTemplateRequired(false); // Disable .view lookup for data/API apps } @Override public String version() { return "1.0.0"; } @Action("greet") public String greet() { return "Hello from tinystruct!"; } // Path parameter: GET /?q=greet/James OR bin/dispatcher greet/James @Action("greet") public String greet(String name) { return "Hello, " + name + "!"; } } ``` ### HTTP Mode Disambiguation (login) ```java @Action(value = "login", mode = Mode.HTTP_POST) public String doLogin(Request request) throws ApplicationException { request.getSession().setAttribute("userId", "42"); return "Logged in"; } ``` ### Native JSON Data Handling (Builder + Builders) ```java import org.tinystruct.data.component.Builder; import org.tinystruct.data.component.Builders; @Action("api/data") public String getData() throws ApplicationException { Builders dataList = new Builders(); Builder item = new Builder(); item.put("id", 1); item.put("name", "James"); dataList.add(item); Builder response = new Builder(); response.put("status", "success"); response.put("data", dataList); return response.toString(); // {"status":"success","data":[{"id":1,"name":"James"}]} } ``` ### SSE (Server-Sent Events) ```java import org.tinystruct.http.SSEPushManager; @Action("sse/connect") public String connect() { return "{\"type\":\"connect\",\"message\":\"Connected to SSE\"}"; } // Push to a specific client String sessionId = getContext().getId(); Builder msg = new Builder(); msg.put("text", "Hello, user!"); SSEPushManager.getInstance().push(sessionId, msg); // Broadcast to all // Broadcast to all SSEPushManager.getInstance().broadcast(msg); ``` ### File Upload ```java import org.tinystruct.data.FileEntity; @Action(value = "upload", mode = Mode.HTTP_POST) public String upload(Request request) throws ApplicationException { List files = request.getAttachments(); if (files != null) { for (FileEntity file : files) { System.out.println("Uploaded: " + file.getFilename()); } } return "Upload OK"; } ``` ## Configuration Settings are managed in `src/main/resources/application.properties`. ```properties # Database driver=org.h2.Driver database.url=jdbc:h2:~/mydb database.user=sa database.password= # Server default.home.page=hello server.port=8080 # Locale default.language=en_US # Session (Redis for clustered environments) # default.session.repository=org.tinystruct.http.RedisSessionRepository # redis.host=127.0.0.1 # redis.port=6379 ``` Access config values in your application: ```java String port = this.getConfiguration("server.port"); ``` ## Red Flags & Anti-patterns | Symptom | Correct Pattern | |---|---| | Importing `com.google.gson` or `com.fasterxml.jackson` | Use `org.tinystruct.data.component.Builder` / `Builders`. | | Using `List` for JSON arrays | Use `Builders` to avoid generic type erasure issues. | | `ApplicationRuntimeException: template not found` | Call `setTemplateRequired(false)` in `init()` for API-only apps. | | Annotating `private` methods with `@Action` | Actions must be `public` to be registered by the framework. | | Hardcoding `main(String[] args)` in apps | Use `bin/dispatcher` as the entry point for all modules. | | Manual `ActionRegistry` registration | Prefer the `@Action` annotation for automatic discovery. | | Action not found at runtime | Ensure class is imported via `--import` or listed in `application.properties`. | | CLI arg not visible | Pass with `--key value`; access via `getContext().getAttribute("--key")`. | | Two methods same path, wrong one fires | Set explicit `mode` (e.g., `HTTP_GET` vs `HTTP_POST`) to disambiguate. | ## Best Practices 1. **Granular Applications**: Break logic into smaller, focused applications rather than one monolithic class. 2. **Setup in `init()`**: Leverage `init()` for setup (config, DB) rather than the constructor. Do NOT call `setAction()` — use `@Action` annotation. 3. **Mode Awareness**: Use the `Mode` parameter in `@Action` to restrict sensitive operations to `CLI` only or specific HTTP methods. 4. **Context over Params**: For optional CLI flags, use `getContext().getAttribute("--flag")` rather than adding parameters to the method signature. 5. **Asynchronous Events**: For heavy tasks triggered by events, use `CompletableFuture.runAsync()` inside the event handler. ## Technical Reference Detailed guides are available in the `references/` directory: - [Architecture & Config](references/architecture.md) — Abstractions, Package Map, Properties - [Routing & @Action](references/routing.md) — Annotation details, Modes, Parameters - [Data Handling](references/data-handling.md) — Builder, Builders, JSON serialization & parsing - [Database Persistence](references/database.md) — AbstractData POJOs, CRUD, mapping XML, POJO generation - [System & Usage](references/system-usage.md) — Context, Sessions, SSE, File Uploads, Events, Networking - [Testing Patterns](references/testing.md) — JUnit 5 unit and HTTP integration testing ## Reference Source Files (Internal) - `src/main/java/org/tinystruct/AbstractApplication.java` — Core base class with lifecycle hooks - `src/main/java/org/tinystruct/system/annotation/Action.java` — Annotation & Modes - `src/main/java/org/tinystruct/application/ActionRegistry.java` — Routing Engine - `src/main/java/org/tinystruct/data/component/Builder.java` — JSON object serializer - `src/main/java/org/tinystruct/data/component/Builders.java` — JSON array serializer - `src/main/java/org/tinystruct/data/component/AbstractData.java` — Base POJO class with CRUD - `src/main/java/org/tinystruct/data/Mapping.java` — Mapping XML parser - `src/main/java/org/tinystruct/data/tools/MySQLGenerator.java` — POJO generator reference - `src/main/java/org/tinystruct/data/component/FieldType.java` — SQL-to-Java type mappings - `src/main/java/org/tinystruct/data/component/Condition.java` — Fluent SQL query builder - `src/main/java/org/tinystruct/http/SSEPushManager.java` — SSE connection management - `src/test/java/org/tinystruct/application/ActionRegistryTest.java` — Registry test examples - `src/test/java/org/tinystruct/system/HttpServerHttpModeTest.java` — HTTP integration test patterns