Skip to content

enkan/enkan

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

685 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

enkan

Test License: EPL-2.0

Enkan (円環) is a middleware-chain web framework for Java 25, inspired by Ring (Clojure) and Connect (Node.js).

A web application should be explicit, traceable, and operable — not magical.

Why Enkan?

Enkan Spring Boot
Configuration Java code only — no YAML, no classpath scanning YAML + annotations + auto-configuration
Middleware ordering Explicit app.use(...) Implicit (annotation-driven)
Request capabilities Added by middleware — getSession() doesn't exist until SessionMiddleware runs Always present
Component lifecycle Explicit dependency graph @Bean + @Autowired
Live inspection Built-in JShell REPL — inspect objects, toggle features, hot-reload Actuator (HTTP endpoints only)
Startup ~3 seconds (no scanning) 10+ seconds

Read more: Why Enkan?

Features

  • Type-safe middleware composition — four type parameters catch wrong ordering at compile time
  • Capability-based request enrichmentMixinUtils.mixin() adds interfaces to request objects dynamically
  • REPL-driven development — hot-reload in ~1 second, inspect routing, toggle middleware predicates live
  • Component system — explicit lifecycle graph for stateful services (DB pools, HTTP servers, template engines)
  • GraalVM Native Image support — build ahead-of-time compiled binaries via kotowari-graalvm
  • Virtual Thread support — Jetty component runs on virtual threads by default
  • Observability — Micrometer metrics and OpenTelemetry tracing built in

Get Started

The fastest way to scaffold a new Enkan project is the AI-powered /init command in the REPL client. It interactively collects your requirements, lets you review and revise the generated plan, writes a compilable project skeleton (including DevMain, pom.xml, and a SystemFactory), runs mvn compile with an automatic fix loop, and optionally launches the app and connects the REPL.

# Download the standalone client jar from the latest release:
#   https://github.com/enkan/enkan/releases/latest
export ENKAN_AI_API_KEY=sk-...        # any OpenAI-compatible endpoint
java -jar enkan-repl-client.jar
enkan ✗  ❯ /init

See Getting Started for a walkthrough of /init, configuration options, and the manual setup path.

If you prefer to wire everything by hand, add the dependencies to your pom.xml:

<dependency>
  <groupId>net.unit8.enkan</groupId>
  <artifactId>kotowari</artifactId>
  <version>0.15.0</version>
</dependency>
<dependency>
  <groupId>net.unit8.enkan</groupId>
  <artifactId>enkan-component-jetty</artifactId>
  <version>0.15.0</version>
</dependency>

Define your application

public class MyAppFactory implements ApplicationFactory {
    @Override
    public Application create(EnkanSystem system) {
        WebApplication app = new WebApplication();

        Routes routes = Routes.define(r -> {
            r.get("/").to(HomeController.class, "index");
            r.resource(CustomerController.class);
        }).compile();

        app.use(new DefaultCharsetMiddleware());
        app.use(new ContentTypeMiddleware());
        app.use(new ParamsMiddleware());
        app.use(new SessionMiddleware());
        app.use(new RoutingMiddleware(routes));
        app.use(new ControllerInvokerMiddleware(system));
        return app;
    }
}

Write a plain Java controller

public class HomeController {
    @Inject
    private TemplateEngineComponent templateEngine;

    public HttpResponse index() {
        return templateEngine.render("home");
    }
}

Wire the system

EnkanSystem.of(
    "template",   new FreemarkerComponent(),
    "datasource", new HikariCPComponent(OptionMap.of("uri", "jdbc:h2:mem:test")),
    "app",        new ApplicationComponent("com.example.MyAppFactory"),
    "http",       builder(new JettyComponent())
                      .set(JettyComponent::setPort, Env.getInt("PORT", 3000))
                      .build()
).relationships(
    component("http").using("app"),
    component("app").using("template", "datasource")
);

Start via REPL

enkan> /start
enkan> /routes app
GET    /                {controller=HomeController, action=index}
GET    /customers       {controller=CustomerController, action=index}
POST   /customers       {controller=CustomerController, action=create}
...

enkan> /reset           # hot-reload in ~1 second

Components

Component Module
Jetty (virtual threads) enkan-component-jetty
Undertow enkan-component-undertow
HikariCP enkan-component-HikariCP
Flyway enkan-component-flyway
Freemarker enkan-component-freemarker
Thymeleaf enkan-component-thymeleaf
Jackson enkan-component-jackson
Doma2 enkan-component-doma2
JPA / EclipseLink enkan-component-jpa / enkan-component-eclipselink
jOOQ enkan-component-jooq
Micrometer enkan-component-micrometer
OpenTelemetry enkan-component-opentelemetry
Metrics (deprecated) enkan-component-metrics

Requirements

  • Java 25 or higher
  • Maven 3.6.3+

Documentation

License

Copyright © 2016-2026 kawasima

Distributed under the Eclipse Public License, Version 2.0.

About

An explicit and simple Java framework

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors