- 1. Project Overview
- 2. Features & Status
- 3. Requirements & Compatibility
- 4. Architecture & Modules
- 5. Installation
- 6. Quick Start
- 7. Configuration
- 8. Core Usage / API
- 9. Testing & Build
- 10. Versioning & Branches
- 11. Contributing & License
spring-bytebuddy generates Spring MVC controllers at runtime with ByteBuddy. Instead of writing a @Controller / @RestController class by hand, you describe the endpoint with a fluent builder (EndpointApiBuilder) — class annotations (@Controller, @RestController, Swagger @Api), request mappings, methods, parameters and invocation handlers — and the module produces a loadable class wired for Spring MVC (servlet) or Spring WebFlux (reactive).
It is for dynamic/plugin-style applications that must expose new HTTP endpoints without recompiling — it is not a code generator tool and not a replacement for writing regular Spring controllers.
Typical scenarios:
| Scenario | What this module contributes |
|---|---|
Runtime-generated @RestController |
EndpointApiBuilder (annotations, mappings, methods, parameters) |
| Reactive handler endpoints | ReactiveHandlerBuilder / ReactiveHandler |
| Swagger annotations on generated classes | SwaggerAnnotationUtils |
| Proxy or delegation implementations | EndpointApiBuilder#proxy(...) / #delegate(...) |
| Reusable mapping/param models | MvcMapping, MvcMethod, MvcParam, MvcParamFrom, MvcBound |
Project status: pre-release development line (1.0.x.* snapshots); public API is still stabilizing until the first tagged release.
| Capability | Status | Notes |
|---|---|---|
| Fluent controller builder | Stable | EndpointApiBuilder<T extends EndpointApi> chains api, controller, restController, requestMapping, autowired, newMethod |
| Runtime annotation generation | Stable | @Controller, @RestController, @RequestMapping family, @Autowired, Swagger @Api / @ApiIgnore |
| Method + parameter generation | Stable | newMethod(name, path, method, consumes, bound, params) with MvcParam annotations (@PathVariable, @RequestParam, ... via MvcParamFrom) |
| Implementation strategies | Stable | proxy(InvocationHandler) and delegate(Class) for generated method bodies |
| ByteBuddy interop | Stable | then() exposes the underlying DynamicType.Builder for advanced customization |
| Reactive support | Stable | ReactiveHandlerBuilder / ReactiveHandler for WebFlux-style handlers |
| Annotation utilities | Stable | EndpointApiAnnotationUtils, SwaggerAnnotationUtils |
| Requirement | Version |
|---|---|
| JDK | 17+ |
| Maven | 3.6+ |
| ByteBuddy | declared in the POM |
| Spring Framework | 5.3.x (spring-webmvc, spring-webflux, spring-context) |
| Swagger annotations | springfox-core + swagger-annotations |
| Servlet / validation APIs | jakarta.servlet-api, jakarta.validation-api (declared in the POM) |
Version lines:
| Branch | JDK | Version pattern | Notes |
|---|---|---|---|
feature/1.0.x |
8 | 1.0.x.* |
Current line; Spring 5.x era |
feature/2.0.x |
17 | 2.0.x.* |
Next line |
feature/3.0.x |
21 | 3.0.x.* |
Future line |
Endpoint description (fluent DSL)
|
v
EndpointApiBuilder (ByteBuddy subclass)
controller / requestMapping / newMethod / proxy
|
v
DynamicType.Builder -> make() -> load(ClassLoader)
|
v
Generated Spring MVC Controller class
(@Controller, @RequestMapping, Swagger @Api)
The project is a single jar module. Packages under org.springframework.bytebuddy:
| Package | Responsibility |
|---|---|
bytecode |
EndpointApi, EndpointApiBuilder, ReactiveHandler, ReactiveHandlerBuilder |
bytecode.definition |
MvcBound, MvcMapping, MvcMethod, MvcParam, MvcParamFrom |
utils |
EndpointApiAnnotationUtils, SwaggerAnnotationUtils |
annotation |
WebBound |
Artifacts are published to the easy4j private repository and GitHub Releases; the project is not yet on Maven Central.
Maven:
<dependency>
<groupId>io.github.easy4j</groupId>
<artifactId>spring-bytebuddy</artifactId>
<version>2.0.x.x.20260630-SNAPSHOT</version>
</dependency>Gradle:
implementation 'io.github.easy4j:spring-bytebuddy:2.0.x.x.20260630-SNAPSHOT'Generate a @RestController at runtime and load it:
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import org.springframework.bytebuddy.bytecode.EndpointApi;
import org.springframework.bytebuddy.bytecode.EndpointApiBuilder;
import org.springframework.web.bind.annotation.RequestMethod;
Class<?> controllerClass = new EndpointApiBuilder<EndpointApi>("com.example.DemoApi")
.restController()
.api("Demo API", "demo") // Swagger @Api
.requestMapping("/api/demo") // class-level mapping
.newMethod("sayHello", "/say", RequestMethod.GET,
"application/json", null) // method-level mapping
.then() // underlying ByteBuddy builder
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
System.out.println(controllerClass.getName()); // com.example.DemoApiExpected result: a class named com.example.DemoApi is generated, annotated as a @RestController with the given mappings and Swagger metadata, and is loadable by the class loader — ready to be registered as a Spring bean / handler.
Programmatic library — there are no configuration files or property prefixes. Everything is configured through the builder DSL at runtime.
Describe a method with typed parameters and bind data:
import org.springframework.bytebuddy.bytecode.EndpointApiBuilder;
import org.springframework.bytebuddy.bytecode.definition.MvcBound;
import org.springframework.bytebuddy.bytecode.definition.MvcParam;
import org.springframework.bytebuddy.bytecode.definition.MvcParamFrom;
import org.springframework.web.bind.annotation.RequestMethod;
new EndpointApiBuilder<EndpointApi>("com.example.DemoApi2")
.controller()
.bind(new MvcBound("uid", "{\"name\":\"demo\"}"))
.newMethod("hello", "/hello/{name}", RequestMethod.POST, "application/json",
new MvcBound("uid"),
new MvcParam<>(String.class, "name", MvcParamFrom.PATH_VARIABLE))
.then()
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.INJECTION);Generated methods are stubbed (StubMethod) unless an implementation is attached with proxy(...) or delegate(...):
EndpointApiBuilder<EndpointApi> builder = new EndpointApiBuilder<>("com.example.DemoApi3");
builder.restController().proxy(myInvocationHandler).then();Build and run tests:
./mvnw clean verify- Test suite covers the builder (
Bytebuddy_EndpointApiBuilder_Test), annotations (ByteBuddy_Annotation_Test), naming strategies (ByteBuddy_NamingStrategy_Test), controller generation (ByteBuddy_Controller_Test), reactive handlers (ByteBuddy_ReactiveHandler_Test) and generic subclassing (ByteBuddy_GenericSubclass_Test). - The build is configured with the JaCoCo Maven plugin: a coverage report is generated at
target/site/jacoco/index.htmland a rule checks the bundle line coverage against a 90% minimum (haltOnFailure=false, so the check reports but does not fail the build). - The
centralMaven profile (./mvnw -Pcentral deploy) attaches GPG signatures, sources and Javadoc jars for publishing.
Three parallel version lines are maintained:
| Branch | JDK | Version pattern |
|---|---|---|
feature/1.0.x |
8 | 1.0.x.* |
feature/2.0.x |
17 | 2.0.x.* |
feature/3.0.x |
21 | 3.0.x.* |
Maintenance policy: the 1.0.x line is the actively developed line (current snapshot 2.0.x.x.20260630-SNAPSHOT); 2.0.x and 3.0.x are forward porting lines targeting newer JDKs. Snapshots are built on demand; tagged releases are distributed via GitHub Releases.
- Fork the repository and open a pull request; keep the
1.0.xline compatible with JDK 8. - Bug reports and feature requests are tracked via GitHub Issues.
- Licensed under the Apache License, Version 2.0.