Padrões de Desenvolvimento com tinystruct
Padrões de arquitetura e implementação para construir módulos com o tinystruct framework Java – um framework leve e de alto desempenho que trata CLI e HTTP como cidadãos iguais, exigindo nenhum método main() e configuração mínima.
Princípio Central
CLI e HTTP são cidadãos iguais. Todo método anotado com @Action deve, idealmente, ser executável tanto de um terminal quanto de um navegador web sem modificação. Essa capacidade de "modo duplo" é a filosofia central de design do tinystruct.
Quando Ativar
Quando Usar
- Criando novos módulos
ApplicationestendendoAbstractApplication. - Definindo rotas e ações de linha de comando usando
@Action. - Manipulando estado por requisição via
Context. - Realizando serialização JSON usando os componentes nativos
BuildereBuilders. - Trabalhando com persistência de banco de dados via POJOs
AbstractData. - Gerando POJOs a partir de tabelas de banco de dados usando o comando
generate. - Implementando Server-Sent Events (SSE) para push em tempo real.
- Manipulando upload de arquivos via dados multipartes.
- Fazendo requisições HTTP de saída com
URLRequesteHTTPHandler. - Configurando conexões de banco de dados ou configurações do sistema em
application.properties. - Depurando conflitos de roteamento (Actions) ou análise de argumentos CLI.
Como Funciona
O framework tinystruct trata qualquer método anotado com @Action como um endpoint roteável tanto para terminal quanto para ambiente web. As aplicações são criadas estendendo AbstractApplication, que fornece hooks de ciclo de vida centrais como init() e acesso ao Context da requisição.
O roteamento é tratado pelo ActionRegistry, que automaticamente mapeia segmentos de caminho para argumentos de método e injeta dependências. Para serviços apenas de dados, os componentes nativos Builder e Builders devem ser usados para serialização JSON a fim de manter uma pegada de zero dependências. A camada de banco de dados usa POJOs AbstractData emparelhados com arquivos de mapeamento XML para operações CRUD sem bibliotecas ORM externas.
Exemplos
Aplicação Básica (MyService)
public class MyService extends AbstractApplication {
@Override
public void init() {
this.setTemplateRequired(false); // Desabilita busca de .view para apps de dados/API
}
@Override public String version() { return "1.0.0"; }
@Action("greet")
public String greet() {
return "Olá do tinystruct!";
}
// Parâmetro de caminho: GET /?q=greet/James OU bin/dispatcher greet/James
@Action("greet")
public String greet(String name) {
return "Olá, " + name + "!";
}
}
Desambiguação de Modo HTTP (login)
@Action(value = "login", mode = Mode.HTTP_POST)
public String doLogin(Request<?, ?> request) throws ApplicationException {
request.getSession().setAttribute("userId", "42");
return "Logado";
}
Manipulação de Dados JSON Nativa (Builder + Builders)
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)
import org.tinystruct.http.SSEPushManager;
@Action("sse/connect")
public String connect() {
return "{\"type\":\"connect\",\"message\":\"Conectado ao SSE\"}";
}
// Enviar para um cliente específico
String sessionId = getContext().getId();
Builder msg = new Builder();
msg.put("text", "Olá, usuário!");
SSEPushManager.getInstance().push(sessionId, msg);
// Transmitir para todos
SSEPushManager.getInstance().broadcast(msg);
Upload de Arquivo
import org.tinystruct.data.FileEntity;
@Action(value = "upload", mode = Mode.HTTP_POST)
public String upload(Request<?, ?> request) throws ApplicationException {
List<FileEntity> files = request.getAttachments();
if (files != null) {
for (FileEntity file : files) {
System.out.println("Enviado: " + file.getFilename());
}
}
return "Upload OK";
}
Integração com Servidor e Ferramentas MCP
tinystruct fornece suporte nativo ao Model Context Protocol (MCP) a partir da versão 1.7.26 do SDK.
As APIs MCP (ex.: org.tinystruct.mcp.MCPTool, org.tinystruct.mcp.MCPServer, org.tinystruct.mcp.MCPException) estão incluídas diretamente na dependência principal:
<dependency>
<groupId>org.tinystruct</groupId>
<artifactId>tinystruct</artifactId>
<version>1.7.26</version>
</dependency>
AVISO DE SEGURANÇA (Injeção de Prompt): Os valores de retorno das ferramentas são alimentados diretamente de volta no contexto do modelo de IA. Você DEVE validar e higienizar todos os argumentos fornecidos pelo chamador antes de incluí-los na string de retorno da ferramenta. A não higienização das entradas pode permitir que um invasor injete instruções adversárias (Injeção de Prompt) que sobrescrevem o comportamento do modelo. Sempre valide comprimento, conjuntos de caracteres e nulidade.
Para criar uma Ferramenta MCP:
- Estenda
org.tinystruct.mcp.MCPTool. - Anote operações com
@Actione declare parâmetros usando@Argumentno arrayarguments. - Aceite parâmetros como argumentos de método explícitos correspondentes às chaves em
@Argument. (Não usegetContext().getAttribute(...)para argumentos de ferramenta).
import org.tinystruct.mcp.MCPTool;
import org.tinystruct.mcp.MCPException;
import org.tinystruct.system.annotation.Action;
import org.tinystruct.system.annotation.Argument;
public class MyCustomTool extends MCPTool {
public MyCustomTool() {
super("custom", "Uma ferramenta personalizada para demonstrar MCP");
}
@Action(
value = "custom/hello",
description = "Diga olá para alguém",
arguments = {
@Argument(key = "name", description = "O nome para cumprimentar", type = "string", optional = false)
}
)
public String hello(String name) throws MCPException {
// SEGURANÇA: Validar/higienizar entradas da ferramenta antes de retornar ao modelo
// para prevenir vulnerabilidades de injeção de prompt.
if (name == null || name.length() > 50 || !name.matches("^[a-zA-Z0-9 ]+$")) {
throw new MCPException("Nome inválido fornecido");
}
return "Olá, " + name + "!";
}
}
Para implantar um Servidor MCP:
- Estenda
org.tinystruct.mcp.MCPServer. - Sobrescreva
init()e registre suas ferramentas usandothis.registerTool(). O framework automaticamente escaneia e mapeia os métodos@Action.
import org.tinystruct.mcp.MCPServer;
public class MyMCPServer extends MCPServer {
@Override
public void init() {
super.init();
this.registerTool(new MyCustomTool());
}
@Override
public String version() {
return "1.0.0";
}
}
Execute o servidor via o dispatcher:
bin/dispatcher start --import org.tinystruct.system.HttpServer --import com.example.MyMCPServer
Configuração
As configurações são gerenciadas em src/main/resources/application.properties.
# Banco de Dados
driver=org.h2.Driver
database.url=jdbc:h2:~/mydb
database.user=sa
database.password=
# Servidor
default.home.page=hello
server.port=8080
# Localidade
default.language=en_US
# Sessão (Redis para ambientes clusterizados)
# default.session.repository=org.tinystruct.http.RedisSessionRepository
# redis.host=127.0.0.1
# redis.port=6379
Acesse valores de configuração em sua aplicação:
String port = this.getConfiguration("server.port");
Bandeiras Vermelhas e Anti-padrões
| Sintoma | Padrão Correto |
|---|---|
Importar com.google.gson ou com.fasterxml.jackson | Use org.tinystruct.data.component.Builder / Builders. |
Usar List<Builder> para arrays JSON | Use Builders para evitar problemas de apagamento de tipo genérico. |
ApplicationRuntimeException: template not found | Chame setTemplateRequired(false) em init() para aplicações apenas de API. |
Anotar métodos private com @Action | Actions devem ser public para serem registradas pelo framework. |
Codificar main(String[] args) manualmente em aplicações | Use bin/dispatcher como ponto de entrada para todos os módulos. |
Registro manual de ActionRegistry | Prefira a anotação @Action para descoberta automática. |
| Action não encontrada em tempo de execução | Garanta que a classe seja importada via --import ou listada em application.properties. |
| Argumento CLI não visível | Passe com --key value; acesse via getContext().getAttribute("--key"). |
| Dois métodos no mesmo caminho, o errado é disparado | Defina mode explícito (ex.: HTTP_GET vs HTTP_POST) para desambiguar. |
Melhores Práticas
- Aplicações Granulares: Divida a lógica em aplicações menores e focadas em vez de uma única classe monolítica.
- Configuração em
init(): Utilizeinit()para configuração (config, banco de dados) em vez do construtor. NÃO chamesetAction()— use a anotação@Action. - Consciência de Modo: Use o parâmetro
Modeem@Actionpara restringir operações sensíveis apenas aCLIou métodos HTTP específicos. - Contexto sobre Parâmetros: Para flags CLI opcionais, use
getContext().getAttribute("--flag")em vez de adicionar parâmetros à assinatura do método. - Eventos Assíncronos: Para tarefas pesadas disparadas por eventos, use
CompletableFuture.runAsync()dentro do manipulador de eventos.
Referência Técnica
Guias detalhados estão disponíveis no diretório references/:
- Arquitetura e Config — Abstrações, Mapa de Pacotes, Propriedades
- Roteamento e @Action — Detalhes da anotação, Modos, Parâmetros
- Manipulação de Dados — Builder, Builders, serialização e análise JSON
- Persistência de Banco de Dados — POJOs AbstractData, CRUD, XML de mapeamento, geração de POJOs
- Sistema e Uso — Contexto, Sessões, SSE, Uploads de Arquivos, Eventos, Rede
- Padrões de Teste — Testes unitários e de integração HTTP com JUnit 5
Arquivos de Fonte de Referência (Internos)
src/main/java/org/tinystruct/AbstractApplication.java— Classe base central com hooks de ciclo de vidasrc/main/java/org/tinystruct/system/annotation/Action.java— Anotação e Modossrc/main/java/org/tinystruct/application/ActionRegistry.java— Motor de Roteamentosrc/main/java/org/tinystruct/data/component/Builder.java— Serializador de objeto JSONsrc/main/java/org/tinystruct/data/component/Builders.java— Serializador de array JSONsrc/main/java/org/tinystruct/data/component/AbstractData.java— Classe base POJO com CRUDsrc/main/java/org/tinystruct/data/Mapping.java— Analisador de XML de mapeamentosrc/main/java/org/tinystruct/data/tools/MySQLGenerator.java— Referência do gerador de POJOssrc/main/java/org/tinystruct/data/component/FieldType.java— Mapeamentos SQL-para-Javasrc/main/java/org/tinystruct/data/component/Condition.java— Construtor fluente de consulta SQLsrc/main/java/org/tinystruct/http/SSEPushManager.java— Gerenciamento de conexões SSEsrc/test/java/org/tinystruct/application/ActionRegistryTest.java— Exemplos de teste do Registrysrc/test/java/org/tinystruct/system/HttpServerHttpModeTest.java— Padrões de teste de integração HTTP