### Context-Less Persistence Service with Transaction Management
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/persistence.adoc
Illustrates a typical setup for a persisting service using `ContextLessDatabase` and `TransactionManager`. This example shows how to inject dependencies and perform context-less write operations within a transaction.
```java
@ApplicationScoped
public class MyPersistingService {
private final TransactionManager txMgr;
private final ContextLessDatabase db;
// constructor to get injections
public void insert(final MyModel model) {
txMgr.write(connection -> db.insert(connection, model));
}
}
```
--------------------------------
### Start Fusion Container
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/examples.adoc
Start the Fusion runtime container in two phases: configuration and launch. This provides a managed environment for your application's beans.
```java
try (
final var container = ConfiguringContainer
.of() <1>
.start() <2>
) {
// use the container or just await for the end of the application
}
```
--------------------------------
### Configuration for ConfigurationDocumentationGenerator
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/documentation.adoc
Example configuration for the ConfigurationDocumentationGenerator when used with Yupiik minisite. This task formats configuration documentation in Asciidoc.
```xml
io.yupiik.fusion.documentation.ConfigurationDocumentationGenerator
```
--------------------------------
### Implement BEFORE Task with Supplier
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/testing.adoc
Example of a BEFORE task implementing Task.Supplier. This task uses a Java Supplier to provide data, suitable for injecting state as parameters.
```java
@DefaultScoped
public class BeforeTask implements Task.Supplier {
private final MyService service;
// constructor...
@Override
public MyData get() {
return service.createData();
}
}
```
--------------------------------
### Declarative Interceptor Example
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/index.adoc
Illustrates a traditional declarative interceptor using an annotation. This approach is not supported by Fusion.
```java
public class MyBean {
@Traced
public void doSomething() {
// ...
}
}
```
--------------------------------
### Custom JUnit 5 Extension for Configuration
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/testing.adoc
Shows how to create a custom JUnit 5 extension to configure the Fusion container before it starts. This is useful for setting system properties or global services.
```java
@Target(TYPE)
@Retention(RUNTIME)
@MonoFusionSupport
@ExtendsWith(MyAppSupport.MyConf.class)
public @interface MyAppSupport {
class MyConf implements Extension {
static {
// do the configuration
System.setProperty("....", "....");
}
}
}
```
--------------------------------
### Configuration for CliDocumentationGenerator
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/documentation.adoc
Example configuration for the CliDocumentationGenerator when used with Yupiik minisite. This task generates Asciidoc documentation for CLI modules.
```xml
io.yupiik.fusion.documentation.CliDocumentationGenerator
```
--------------------------------
### Java Main Class for Fusion Application
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/graalvm.adoc
Example of a main class in a Fusion application that can be converted to a native binary. Ensure your dependencies are GraalVM compatible.
```java
package demo.fusion;
import io.yupiik.fusion.framework.api.ConfiguringContainer;
import io.yupiik.fusion.framework.api.lifecycle.Start;
import io.yupiik.fusion.framework.api.scope.ApplicationScoped;
import io.yupiik.fusion.framework.build.api.event.OnEvent;
import io.yupiik.fusion.framework.build.api.lifecycle.Init;
@ApplicationScoped
public class Greeter {
@Init
protected void init() {
System.out.println("> Init");
}
public void onStart(@OnEvent final Start start) {
System.out.println("> start: " + start);
}
public static void main(final String... args) {
try (final var container = ConfiguringContainer.of().start()) {
// no-op
}
}
}
```
--------------------------------
### Implement a Monitoring Endpoint
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/http-server.adoc
Create a MonitoringEndpoint for health checks or metrics. This example checks transaction manager validity and returns metrics or an OK status.
```java
@DefaultScoped
public class Health implements MonitoringEndpoint {
private final TransactionManager transactionManager;
public Health(final TransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
@Override
public boolean matches(final Request request) {
return "GET".equalsIgnoreCase(request.method()) && "/metrics".equalsIgnoreCase(request.path());
}
@Override
public CompletionStage unsafeHandle(final Request request) {
return transactionManager
.read(c -> {
try {
if (!c.isValid(30_000)) {
return Optional.of(fail("Timeout"));
}
return Optional.>empty();
} catch (final SQLException e) {
return Optional.of(fail(e.getMessage()));
}
})
.orElseGet(() -> completedStage(Response.of().body("OK").build()));
}
}
```
--------------------------------
### Testing a Launcher Application with @FusionCLITest
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/testing.adoc
Example of using @FusionCLITest to test CLI applications. It automatically executes a Launcher with specified arguments and provides Stdout and Stderr for output validation.
```java
@FusionCLITest(args = {"test", "run"})
void run(final Stdout stdout) {
assertEquals("...", stdout.content().strip());
}
```
--------------------------------
### Custom Resource Definition Example (YAML)
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/kubernetes-operator.adoc
An example of a custom resource definition (CRD) for an API kind. Operators use these descriptors to manage custom resources.
```yaml
apiVersion: custom.company.com/v1
kind: MyAPI
metadata:
name: my-api
namespace: my-apps
spec:
path: /api/my
image: company/my-api:1.0
```
--------------------------------
### Implement AFTER Task with Runnable
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/testing.adoc
Example of an AFTER task implementing Task.Supplier. This task uses a Runnable to perform actions, typically for cleanup operations after a process.
```java
@DefaultScoped
public class AfterTask implements Task.Supplier {
private final MyService service;
// constructor...
@Override
public void run() {
service.clean();
}
}
```
--------------------------------
### Kubernetes Operator Manifest Configuration
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/kubernetes-operator.adoc
Example manifest.json file for configuring Kubernetes Operator deployments, including CRD-only, CRD controller, and full-stack alveoli.
```json
{
"$schema": "https://raw.githubusercontent.com/yupiik/bundlebee/gh-pages/generated/jsonschema/manifest.descriptor.json",
"interpolateAlveoli": true,
"alveoli": [
{
"//": "CRD only, no controller",
"name": "api-crd-only",
"descriptors": [
{
"name": "crd.json",
"await": true,
"awaitConditions": [
{
"command": "apply",
"conditions": [
{
"type": "STATUS_CONDITION",
"conditionType": "Established",
"value": "True"
}
]
}
]
}
]
},
{
"//": "CRD controller only registration",
"name": "api-crd-controller",
"descriptors": [
{
"name": "serviceaccount.json"
},
{
"name": "role.json"
},
{
"name": "rolebinding.json"
},
{
"name": "deployment.json"
}
]
},
{
"//": "full stack alveolus",
"name": "api-crd",
"dependencies": [
{
"name": "api-crd-only"
},
{
"name": "api-crd-controller"
}
]
}
]
}
```
--------------------------------
### Configure ExtendedHttpClientConfiguration
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/http-client.adoc
Configure the ExtendedHttpClientConfiguration with a custom SSL context and request listeners. This example shows how to set a custom HttpClient delegate and add listeners for timeouts, user agents, and exchange logging.
```java
final var conf = new ExtendedHttpClientConfiguration();
// (optional) force a custom SSL context
conf.setDelegate(
HttpClient.newBuilder()
.sslContext(getSSLContext())
.build());
// (optional) force custom listeners
conf.setListeners(List.of(
new AutoTimeoutSetter(Duration.ofSeconds(3600)),
new AutoUserAgentSetter(),
new ExchangeLogger(
Logger.getLogger(getClass().getName()),
Clock.systemUTC(),
false)));
```
--------------------------------
### Registering JsonConfigurationSource with @Bean
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/json.adoc
Provides an example of registering a JsonConfigurationSource using a @Bean method. Note the warning about potential singleton cache issues.
```java
public class MyListener {
public void onStart(@OnEvent final ConfigurationRegistration event) {
event.addSource().accept(new JsonConfigurationSource(
ReaderSupplier.from(
event.configuration().get("my.config.path").orElse("config.json"),
"{\"myDefaultPort\": 8080}")));
}
}
```
--------------------------------
### Advanced Maven Configuration for IDE Completion
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/setup.adoc
Configures Maven dependencies and the compiler plugin to avoid exposing the processor in IDE completion, suitable for complex setups.
```xml
io.yupiik.fusion
fusion-api
${fusion.version}
io.yupiik.fusion
fusion-build-api
${fusion.version}
provided
org.apache.maven.plugins
maven-compiler-plugin
3.10.1
io.yupiik.fusion
fusion-processor
${fusion.version}
```
--------------------------------
### Entity Delete Hook
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/persistence.adoc
Implement the @OnDelete hook to perform actions before an entity is deleted from the database. This example is a no-operation.
```java
@OnDelete
private void onDelete() {
// no-op
}
```
--------------------------------
### Yupiik Fusion Core Dependencies for Maven
Source: https://github.com/yupiik/fusion/blob/master/README.adoc
Add these core dependencies to your Maven project to start using Yupiik Fusion. The scope for build-api and processor is provided.
```xml
io.yupiik.fusion
fusion-build-api
${fusion.version}
provided
io.yupiik.fusion
fusion-processor
${fusion.version}
provided
io.yupiik.fusion
fusion-api
${fusion.version}
```
--------------------------------
### Custom Operator Implementation (Java)
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/kubernetes-operator.adoc
An example of a custom operator extending `Operator.Base`. It demonstrates injecting Kubernetes client and JsonMapper, defining the custom resource model, and handling CRD events (add, delete, modify).
```java
@ApplicationScoped
public class APIOperator extends Operator.Base { // <1>
private final Logger logger = Logger.getLogger(getClass().getName());
private final KubernetesClient kubernetes;
private final JsonMapper jsonMapper;
public APIOperator(
// <2>
final KubernetesClient client, final JsonMapper jsonMapper) {
super(
APIResource.class, // <3>
// <4>
new DefaultOperatorConfiguration(true, List.of("default"), "api", "company.com/v1"));
this.kubernetes = client;
this.jsonMapper = jsonMapper;
}
@Override
public CompletionStage> onStart() { // <5>
logger.info(() -> "Starting operator " + getClass().getName());
return super.onStart();
}
@Override // <6>
public void onAdd(final APIResource object) {
logger.info(() -> "[ADD] " + object);
}
@Override // <6>
public void onDelete(final APIResource object) {
logger.info(() -> "[DELETE] " + object);
}
@Override // <6>
public void onModify(final APIResource object) {
logger.info(() -> "[MODIFY] " + object);
}
}
```
--------------------------------
### Maven Shade Plugin Configuration for Fusion
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/examples.adoc
Configure the Maven Shade Plugin to create a fat JAR with custom transformers for Fusion applications. This setup includes transformers for manifest, services, documentation, JSON schema, and OpenRPC.
```xml
org.apache.maven.plugins
maven-shade-plugin
3.5.2
io.yupiik.maven
maven-shade-transformers
0.0.5
shade
true
fat
false
${project.build.directory}/reduced-pom.xml
io.yupiik.fusion.framework.api.main.Launcher
*:*
module-info.class
META-INF/*.SF
META-INF/*.DSA
META-INF/*.RSA
META-INF/LICENSE.txt
META-INF/LICENSE
META-INF/NOTICE.txt
META-INF/NOTICE
META-INF/MANIFEST.MF
META-INF/DEPENDENCIES
```
--------------------------------
### Efficient Functional Interception with Parameters
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/index.adoc
Provides an example of functional interception that efficiently handles parameters without creating Object arrays, suitable for scenarios like transaction management.
```java
public class MyBean {
@Injection
EntityManager em; // assume the application used JPA - not required
@Injection
JpaService jpa; // custom bean to handle transactions for ex
public void store(final Transaction tx) {
tracing(
// no Object[] created for an interceptor
// and no reflection to extract the id
tx.id(),
() -> jpa.tx(() -> em.persist(tx)));
}
}
```
--------------------------------
### Example API Custom Resource Definition (CRD)
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/kubernetes-operator.adoc
Define the Custom Resource Definition (CRD) for your operator. This YAML file specifies the API group, versions, schema, and additional printer columns for your custom resource.
```json
{
"apiVersion": "apiextensions.k8s.io/v1",
"kind": "CustomResourceDefinition",
"metadata": {
"name": "apis.company.com"
},
"spec": {
"group": "company.com",
"versions": [
{
"name": "v1",
"served": true,
"storage": true,
"schema": {
"openAPIV3Schema": {
"type": "object",
"properties": {
"spec": {
"type": "object",
"properties": {
"image": {
"type": "string"
},
"path": {
"type": "string"
}
}
}
}
}
},
"additionalPrinterColumns": [
{
"name": "Path",
"type": "string",
"description": "Path of the endpoint",
"jsonPath": ".spec.path"
},
{
"name": "Image",
"type": "string",
"description": "Image of the main container containing the API",
"jsonPath": ".spec.image"
},
{
"name": "Age",
"type": "date",
"jsonPath": ".metadata.creationTimestamp"
}
]
}
],
"scope": "Namespaced",
"names": {
"plural": "apis",
"singular": "api",
"kind": "API"
}
}
}
```
--------------------------------
### Setting Application Configuration via Environment Variables (Bash)
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/examples.adoc
Demonstrates how to set the complex `AppConfig` using environment variables in a bash script. This includes setting values for lists and maps.
```bash
export APP_NAME="app1"
export APP_HOST="app-1"
export APP_PORT="8380"
export APP_FREQUENCY_INTERVAL="20000L"
export APP_SOURCES_LENGTH="2"
export APP_SOURCES_0_HOST="external-host-1"
export APP_SOURCES_0_PORT="8080"
export APP_SOURCES_1_HOST="external-host-2"
export APP_SOURCES_1_PORT="8080"
export APP_STAMPS="application,server,integration"
export APP_TAGS="
application = app1
env = local
phase = tests
"
```
--------------------------------
### Setting Application Configuration via System Properties (Java)
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/examples.adoc
Illustrates how to set the complex `AppConfig` by programmatically setting Java system properties. This is useful for configuring applications within a Java environment.
```java
public class App{
static {
System.setProperty("app.name", "app1");
System.setProperty("app.host", "app-1");
System.setProperty("app.port", "8380");
System.setProperty("app.frequency.interval", "20000l");
System.setProperty("app.sources.length", "2");
System.setProperty("app.sources.0.host", "ext");
System.setProperty("app.sources.0.port", "808");
System.setProperty("app.sources.1.host", "ext");
System.setProperty("app.sources.1.port", "808");
System.setProperty("app.stamps", "application,server,integration");
System.setProperty("app.tags"," \napplication = app1 \nenv = local \nphase = tests" );
}
}
```
--------------------------------
### Context-Less Database Insert
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/persistence.adoc
Demonstrates how to perform a database insert using `ContextLessDatabase` by explicitly managing the connection. This approach avoids `ThreadLocal` dependencies.
```java
try (final var connection = dataSource.getConnection()) {
database.insert(connection, entity);
}
```
--------------------------------
### Executing Custom SQL Queries
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/persistence.adoc
Demonstrates how to execute custom SQL queries using the database entity model. This allows for dynamic SQL generation based on entity metadata.
```java
import io.yupiik.fusion.persistence.api.Database;
import io.yupiik.fusion.persistence.api.Entity;
import java.util.List;
// Assuming Customer.class and CustomerEntity.class are defined elsewhere
// final var database = ...;
final var customer = database.entity(Customer.class);
final var sql = "SELECT " + String.join(", ",
customer.concatenateColumns(new Entity.ColumnsConcatenationRequest())) +
"FROM " + customer.getTable() +
"WHERE name = ?";
final var lines = database.query(Customer.class, sql, b -> b.bind("the-name"));
```
--------------------------------
### Entity Update Hook
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/persistence.adoc
Implement the @OnUpdate hook to perform actions before an entity is updated in the database. This example simply returns the current entity.
```java
@OnUpdate
private CustomerEntity onUpdate() {
return this;
}
```
--------------------------------
### Setting Application Configuration via Environment Variables (YAML)
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/examples.adoc
Shows how to set the complex `AppConfig` using environment variables in YAML format. This is an alternative to bash scripting for environment variable configuration.
```yaml
APP_NAME: "app1"
APP_HOST: "app-1"
APP_PORT: "8380"
APP_FREQUENCY_INTERVAL: "20000L"
APP_SOURCES_LENGTH: "2"
APP_SOURCES_0_HOST: "external-host-1"
APP_SOURCES_0_PORT: "8080"
APP_SOURCES_1_HOST: "external-host-2"
APP_SOURCES_1_PORT: "8080"
APP_STAMPS: "application,server,integration"
APP_TAGS: |
application = app1
env = local
phase = tests
```
--------------------------------
### Using TestClient for JSON-RPC Requests
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/testing.adoc
Demonstrates how to use the TestClient utility to make JSON-RPC requests. It simplifies HTTP client interactions, logging, and exception handling in tests.
```java
@Test
void myTest(@Fusion final TestClient client) {
final var res = client.jsonRpcRequest(
"my.jsonrpc.method",
Map.of("id", id.value()));
final var order = res
.asJsonRpc()
.success()
.as(Order.class);
assertAll(
() -> assertEquals(200, res.statusCode()),
() -> assertInsertedOrder(order, id, res::body));
}
```
--------------------------------
### HTTP Server Endpoints with Java
Source: https://github.com/yupiik/fusion/blob/master/README.adoc
Defines RESTful endpoints for product retrieval and order creation using annotations. Requires `io.yupiik.fusion.framework.api.scope.ApplicationScoped` and `io.yupiik.fusion.framework.build.api.http.HttpMatcher`.
```java
import io.yupiik.fusion.framework.api.scope.ApplicationScoped;
import io.yupiik.fusion.framework.build.api.http.HttpMatcher;
import io.yupiik.fusion.http.server.api.HttpException;
import io.yupiik.fusion.http.server.api.Request;
import io.yupiik.fusion.http.server.api.Response;
import io.yupiik.fusion.json.JsonMapper;
@ApplicationScoped
public class ProductEndpoint {
private final ProductService productService;
private final JsonMapper jsonMapper;
public ProductEndpoint(final JsonMapper jsonMapper, final ProductService productService) {
this.jsonMapper = jsonMapper;
this.productService = productService;
}
@HttpMatcher(methods = "GET", path = "/product", pathMatching = HttpMatcher.PathMatching.EXACT)
public List findAllProduct(final Request request) {
return productService.findProducts();
}
@HttpMatcher(methods = "GET", path = "/product/", pathMatching = HttpMatcher.PathMatching.STARTS_WITH)
public Product findProduct(final Request request) {
final var id = request.path().split("/")[2];
return productService.findProduct(id);
}
@HttpMatcher(methods = "POST", path = "/order", pathMatching = HttpMatcher.PathMatching.EXACT)
public Response createOrder(final Request request, final Order order) { // custom response crafting
return Response.of()
.status(201)
.header("content-type", "application/json")
.body(jsonMapper.toString(orderService.createOrder(order)))
.build();
}
}
```
--------------------------------
### Validate JSON with Json Schema
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/json.adoc
Use the Json Schema Validator to validate JSON content against a JSON schema. This example shows a service with an injected JsonMapper.
```java
@Bean
public class MyService {
@Injection
JsonMapper mapper;
```
--------------------------------
### Basic Fusion Test Class
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/testing.adoc
Demonstrates how to use @FusionSupport to inject services into a test class. Requires a Fusion support annotation on the test class.
```java
@FusionSupport
class Mytest {
@Test
void run(@Fusion final MyService service) {
// ...
}
}
```
--------------------------------
### Create JsonConfigurationSource from File
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/json.adoc
Initializes a JsonConfigurationSource to read configuration from a JSON file on the filesystem. Uses ReaderSupplier for file path resolution.
```java
import io.yupiik.fusion.framework.api.io.ReaderSupplier;
import io.yupiik.fusion.json.configuration.JsonConfigurationSource;
// from a file
final var source = new JsonConfigurationSource(
ReaderSupplier.fromFile(Path.of("/etc/app/config.json")));
```
--------------------------------
### Read/Write JSON Data with JsonMapper
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/json.adoc
Inject and use the JsonMapper to serialize Java objects to JSON and deserialize JSON to Java objects. This example shows writing data to an HttpServletResponse.
```java
@Bean
public class MyService extends HttpServlet {
@Injection
JsonMapper mapper;
@Override
public void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
try (final var out = resp.getWriter()) {
mapper.write(createMyModelInstance(req), out);
}
}
}
```
--------------------------------
### Injecting Server Configuration
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/examples.adoc
Shows how to inject the `ServerConfiguration` record into a Spring bean. The configuration values are automatically bound.
```java
@Bean
public class MyServer {
private final ServerConfiguration conf;
public MyServer(final ServerConfiguration conf) {
this.conf = conf;
}
// ...
}
```
--------------------------------
### Context-Less Database Write Operation
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/persistence.adoc
Shows how to perform a write operation with `ContextLessDatabase` using a connection provider wrapper. This pattern is useful for encapsulating multiple database operations within a single transaction.
```java
dataSource.write(connection -> {
database.insert(connection, entity);
aServiceDoingAnInsert(connection);
});
```
--------------------------------
### JSON Map Support with $asList
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/json.adoc
Shows how to represent a JSON object as a Map by setting '$asList': true. This allows accessing map entries by index.
```java
final var source = new JsonConfigurationSource(mapper,
() -> new StringReader("{\"config\": {\"$asList\": true,\"key1\": {\"enabled\": true},\"key2\": {\"enabled\": false}}}"));
source.get("config.length"); // "2"
source.get("config.0.key"); // "key1"
source.get("config.0.value.enabled"); // "true"
source.get("config.1.key"); // "key2"
source.get("config.1.value.enabled"); // "false"
```
--------------------------------
### Define a Greeting Endpoint
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/http-server.adoc
Implement the Endpoint interface to create a custom web service endpoint. The matches method determines if the endpoint should handle the request, and the handle method provides the response.
```java
@Bean
public class Greeting implements Endpoint {
@Override
public boolean matches(final Request request) {
return "GET".equals(request.method());
}
@Override
public CompletionStage handle(final Request request) {
return completedFuture(Response.of()
.body("{\"hello\":true}")
.build());
}
}
```
--------------------------------
### Configure Kubernetes Client with Extended HTTP Client
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/http-client.adoc
Configure the Kubernetes client to use an extended HTTP client by setting a client wrapper. This approach avoids manual SSLContext handling.
```java
final var conf = new KubernetesClientConfiguration()
.setClientWrapper(client -> new ExtendedHttpClient(new ExtendedHttpClientConfiguration()
.setDelegate(client)));
final var k8s = new KubernetesClient(conf);
// now call any API you need:
final var response = k8s.send(
HttpRequest.newBuilder()
.GET()
.uri(URI.create(
"https://kubernetes.api/api/v1/namespaces/" + k8s.namespace().orElse("default") + "/configmaps?"
+ "includeUninitialized=false&"
+ "limit=1000&"
+ "timeoutSeconds=600")
.header("Accept", "application/json")
.build(),
HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)));
// handle the response
```
--------------------------------
### Advanced Queries with Virtual Tables and Joins
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/persistence.adoc
Shows how to perform advanced queries involving joins between entities using virtual tables. It demonstrates constructing complex SQL and mapping results to a specific model.
```java
import io.yupiik.fusion.persistence.api.Database;
import io.yupiik.fusion.persistence.api.Entity;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
// Assuming Entity1.class, Entity2.class, JoinModel.class are defined elsewhere
// final var database = ...;
final var entity1 = database.entity(Entity1.class);
final var entity2 = database.entity(Entity2.class);
final var sql = "SELECT DISTINCT " + String.join(", ",
entity1.concatenateColumns(new Entity.ColumnsConcatenationRequest()
.setPrefix("e1.").setAliasPrefix("")),
entity2.concatenateColumns(new Entity.ColumnsConcatenationRequest()
.setPrefix("e2.").setAliasPrefix("e2").setIgnored(Set.of("e1_id"))))
+ " " +
"FROM " + entity1.getTable() + " e1 " +
"LEFT JOIN ENTITY2 admin on e2.e1_id = e1.id " +
"WHERE e1.id = ?";
final var lines = database.query(JoinModel.class, sql, b -> b.bind("the-id"));
```
```java
import io.yupiik.fusion.persistence.api.Database;
import io.yupiik.fusion.persistence.api.Entity;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import io.yupiik.fusion.persistence.api.Tuple2;
// Assuming Entity1.class, Entity2.class are defined elsewhere
// final var database = ...;
final var entity1 = database.entity(Entity1.class);
final var entity2 = database.entity(Entity2.class);
final var e2Alias = "e2";
final var e2Ignored = Set.of("e1Id");
final var sql = "SELECT DISTINCT " + String.join(", ",
entity1.concatenateColumns(new Entity.ColumnsConcatenationRequest()
.setPrefix("e1.").setAliasPrefix("")),
entity2.concatenateColumns(new Entity.ColumnsConcatenationRequest()
.setPrefix(e2Alias + '.').setAliasPrefix(e2Alias).setIgnored(e2Ignored)))
+ " " +
"FROM ENTITY1 e1" +
" LEFT JOIN ENTITY2 admin on e2.e1_id = e1.id " +
"WHERE e1.id = ?";
// precompile the binders
var fields = database.entity(Entity1.class).getOrderedColumns().stream()
.map(Entity.ColumnMetadata::javaName)
.collect(Collectors.toList());
final var e1Binder = database.entity(Entity1.class)
.mapFromPrefix("", fields.toArray(String[]::new));
fields.addAll( // continue to go through the queries fields appending the next entity ones - binder will pick the column indices right this way
database.entity(Entity2.class)
.getOrderedColumns().stream()
.filter(c -> !e2Ignored.contains(c.javaName()))
.map(c -> c.toAliasName(e2Alias))
.collect(Collectors.toList()));
final var e2Binder = database.entity(Entity2.class)
.mapFromPrefix(e2Alias, fields.toArray(String[]::new));
// at runtime
final var lines = database.query(
sql,
b -> b.bind("the-id"),
result -> {
// bind current resultSet and iterate over each line of the resultSet
return result.mapAll(line -> Tuple2.of(e1Binder.apply(line), e2Binder.apply(line)));
});
// lines will get both Entity1 and Entity2 instances, then you can just filter them checking there is an id or not for example
// and join them as needed to create your output model
```
--------------------------------
### Registering a Counter Metric
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/observability.adoc
Demonstrates how to register and increment a counter metric using the MetricsRegistry. This is useful for tracking event counts in your application.
```java
import io.yupiik.fusion.observability.metrics.MetricsRegistry;
import java.util.concurrent.atomic.LongAdder;
@DefaultScoped
public class MyService {
private final LongAdder myCounter;
public MyService(final MetricsRegistry registry) {
this.myCounter = registry.registerCounter("my-service-counter");
}
public void save(final MyEntity entity) {
// do the normal business code
myCounter.increment();
}
}
```
--------------------------------
### Simple Server Configuration Record
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/examples.adoc
Defines a simple configuration record for server settings like port and access log pattern. Values are read from system properties or environment variables.
```java
@RootConfiguration("server")
public record ServerConfiguration(int port, String accessLogPattern) {}
```
--------------------------------
### Map with $asList Serialization
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/json.adoc
Illustrates how Map with '$asList' true serializes primitive values into a Properties-format string.
```java
final var source = new JsonConfigurationSource(mapper,
() -> new StringReader("{\"metadata\": {\"$asList\": true, \"dc\": \"us-east\", \"env\": \"prod\"}}"));
// uses Properties.store() format, readable by Properties.load()
final var value = source.get("metadata"); // contains "dc=us-east" and "env=prod" - 2 lines
```
--------------------------------
### Create JsonConfigurationSource from Classpath
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/json.adoc
Initializes a JsonConfigurationSource to read configuration from a JSON file located on the classpath. Uses ReaderSupplier for resource loading.
```java
import io.yupiik.fusion.framework.api.io.ReaderSupplier;
import io.yupiik.fusion.json.configuration.JsonConfigurationSource;
// from classpath
final var source = new JsonConfigurationSource(
ReaderSupplier.fromClasspath("config.json"));
```
--------------------------------
### JSON-RPC Endpoint Implementation in Java
Source: https://github.com/yupiik/fusion/blob/master/README.adoc
Implements JSON-RPC methods for finding products using the `@JsonRpc` annotation. Requires `io.yupiik.fusion.framework.api.scope.ApplicationScoped` and `io.yupiik.fusion.framework.build.api.jsonrpc.JsonRpc`.
```java
import io.yupiik.fusion.framework.api.scope.ApplicationScoped;
import io.yupiik.fusion.framework.build.api.jsonrpc.JsonRpc;
import io.yupiik.fusion.http.server.api.Request;
import io.yupiik.fusion.json.JsonMapper;
import java.util.Map;
@ApplicationScoped
public class JsonRpcEndpoint {
private final ProductService productService;
public JsonRpcEndpoint(final ProductService productService) {
this.productService = productService;
}
@JsonRpc(value = "fusion.examples.product.findAll", documentation = "Fetch all product available")
public List findAllProduct(final Request request) {
return productService.findProducts();
}
@JsonRpc(value = "fusion.examples.product.findById", documentation = "Find a product by id")
public Product findProduct(final Request request, final String id) {
return productService.findProduct(id);
}
}
```
--------------------------------
### Configure JSON Logging JVM Flags
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/kubernetes-operator.adoc
Add these JVM flags to your configuration to enable JSON formatted logs using Yupiik's logging manager.
```xml
-Djava.util.logging.manager=io.yupiik.logging.jul.YupiikLogManager
-Dio.yupiik.logging.jul.handler.StandardHandler.formatter=json
```
--------------------------------
### Configure TracingListener for HTTP Client
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/http-client.adoc
Integrate tracing capabilities into the HTTP client by configuring a TracingListener. This listener requires a client tracing configuration, an accumulator for spans, an ID generator, a span evaluator, and a clock. The listener is then added to the ExtendedHttpClientConfiguration.
```java
final var listener = new TracingListener(
new ClientTracingConfiguration(), <1>
accumulator, <2>
new IdGenerator(IdGenerator.Type.HEX), <3>
new ServletContextAttributeEvaluator(servletRequest), <4>
systemUTC()); <5>
<6>
final var configuration = new ExtendedHttpClientConfiguration()
.setRequestListeners(List.of(listener));
final var client = new ExtendedHttpClient(configuration);
```
--------------------------------
### Chaining Interceptors with Stream and Function
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/index.adoc
Shows how to chain interceptors using a Stream of Functions. Interceptors are applied in reverse order of stream definition using Function.andThen.
```java
public void storeCustomer(final Customer customer) {
Stream., Supplier>>of(
// reversed chain of interceptor (i1 will be executed before i2)
delegate -> interceptor2(Params.of(customer), delegate),
delegate -> interceptor1("incoming-customer", Map.of("id", customer.id()), delegate)
)
// merge the stream of interceptors as one execution wrapper
.reduce(identity(), Function::andThen)
.apply(() -> { // apply to the actual business logic
System.out.println(">Business");
return null;
})
.get(); // execute it
}
```
--------------------------------
### JSON-RPC Endpoints
Source: https://github.com/yupiik/fusion/blob/master/README.adoc
Provides JSON-RPC methods for interacting with product services.
```APIDOC
## fusion.examples.product.findAll
### Description
Fetch all products available.
### Method
JSON-RPC
### Parameters
None
### Response
#### Success Response
- **List** - A list of product objects.
### Response Example
{
"example": "[{"id": "1", "name": "Example Product"}]"
}
```
```APIDOC
## fusion.examples.product.findById
### Description
Find a product by its ID.
### Method
JSON-RPC
### Parameters
#### Request Parameters
- **id** (string) - Required - The unique identifier of the product.
### Response
#### Success Response
- **Product** - The product object matching the provided ID.
### Response Example
{
"example": "{"id": "1", "name": "Example Product"}"
}
```
--------------------------------
### Add Yupiik Logging Dependency
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/kubernetes-operator.adoc
Include the Yupiik logging dependency for runtime to enable JSON logging.
```xml
io.yupiik.logging
yupiik-logging-jul
${yupiik-logging.version}
runtime
```
--------------------------------
### Add Fusion API and Processor Dependencies (Maven)
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/setup.adoc
Include the fusion-api and fusion-processor dependencies in your Maven project. The API is needed at compile time, and the processor is provided.
```xml
io.yupiik.fusion
fusion-api
${fusion.version}
io.yupiik.fusion
fusion-processor
${fusion.version}
provided
```
--------------------------------
### Configure Jib for Operator Image
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/kubernetes-operator.adoc
Configure the Jib Maven plugin in your pom.xml to build a container image for your operator. Specify the base image, the target image name, and the main class to run.
```xml
com.google.cloud.tools
jib-maven-plugin
3.3.2
packaged
ossyupiik/java:17.0.7@sha256:1a08a09ea4374243f28a48ec5331061d53abcdac70e51c1812b32ac4055a7deb
company/operator-api:latest
io.yupiik.fusion.framework.api.main.Launcher
/opt/company/api-controller
/opt/company/api-controller
-XX:+ExitOnOutOfMemoryError
```
--------------------------------
### Chaining Interceptors with Supplier
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/index.adoc
Demonstrates how to chain multiple interceptors using nested Suppliers. The final .get() call triggers the execution of the entire chain.
```java
public void storeCustomer(final Customer customer) {
interceptor2(
Params.of(customer),
interceptor1(
"incoming-customer", Map.of("id", customer.id()),
() -> {
// business code
}
)
)
.get(); // trigger the actual execution, it is the terminal operation for the chain
}
```
--------------------------------
### Define a Fusion CLI Command
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/cli.adoc
Mark a bean with @Command to make it a command. Ensure it implements Runnable and has a constructor accepting the configuration class. The configuration can be customized with @RootConfiguration.
```java
@Command(name = "my-commands", description = "A super command.")
public class MyCommand implements Runnable {
private final Conf conf;
public MyCommand(final Conf conf) {
this.conf = conf;
}
@Override
public void run() {
// impl what you want
}
@RootConfiguration("my-commands")
public record Conf(String name) {}
}
```
--------------------------------
### Using @Task for Before/After Method Execution
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/testing.adoc
Illustrates the use of the @Task annotation to execute specific code (tasks) before or after a test method. It also shows how to inject the result of a preceding task.
```java
@Test
@Task(phase = BEFORE, value = InsertMyData.class)
@Task(phase = AFTER, value = CleanMyData.class)
void run(@TaskResult(InsertMyData.class) final MyData data) {
// ...
}
```
--------------------------------
### Create JsonConfigurationSource with Default Value
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/json.adoc
Initializes a JsonConfigurationSource, providing a default JSON string if the primary resource is not found. Uses ReaderSupplier for flexible loading.
```java
import io.yupiik.fusion.framework.api.io.ReaderSupplier;
import io.yupiik.fusion.json.configuration.JsonConfigurationSource;
// from a resource or file with a default
final var source = new JsonConfigurationSource(
ReaderSupplier.from("config.json", "{\"myDefaultPort\": 8080}"));
```
--------------------------------
### Listen to an Event
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/examples.adoc
Implement event listeners by annotating methods with `@OnEvent`. The event bus is synchronous and sorted using `@Order`.
```java
public class MyListener {
public void onStart(@OnEvent final Start start) {
System.out.println("Application started");
}
public void onStop(@OnEvent final Stop stop) {
System.out.println("Application stopped");
}
}
```
--------------------------------
### Add HTTP Server Dependency
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/http-server.adoc
Include the fusion-http-server dependency in your project's pom.xml to use the HTTP server module.
```xml
io.yupiik.fusion
fusion-http-server
${fusion.version}
```
--------------------------------
### Product Endpoints
Source: https://github.com/yupiik/fusion/blob/master/README.adoc
Provides endpoints for managing product information.
```APIDOC
## GET /product
### Description
Fetches a list of all available products.
### Method
GET
### Endpoint
/product
### Response
#### Success Response (200)
- **List** - A list of product objects.
### Response Example
{
"example": "[{"id": "1", "name": "Example Product"}]"
}
```
```APIDOC
## GET /product/{id}
### Description
Fetches a specific product by its ID.
### Method
GET
### Endpoint
/product/{id}
### Parameters
#### Path Parameters
- **id** (string) - Required - The unique identifier of the product.
### Response
#### Success Response (200)
- **Product** - The product object matching the provided ID.
### Response Example
{
"example": "{"id": "1", "name": "Example Product"}"
}
```
```APIDOC
## POST /order
### Description
Creates a new order.
### Method
POST
### Endpoint
/order
### Request Body
- **order** (Order) - Required - The order details to be created.
### Response
#### Success Response (201)
- **Response** - A confirmation response, typically including the created order details.
### Response Example
{
"example": "{\"status\": 201, \"header\": {\"content-type\": \"application/json\"}, \"body\": \"{\"orderId\": \"abc-123\"}\"}"
}
```
--------------------------------
### Create JsonConfigurationSource from Inline String
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/json.adoc
Initializes a JsonConfigurationSource to read configuration directly from an inline JSON string. Uses ReaderSupplier for string input.
```java
import io.yupiik.fusion.framework.api.io.ReaderSupplier;
import io.yupiik.fusion.json.configuration.JsonConfigurationSource;
// from a file
final var source = new JsonConfigurationSource(
ReaderSupplier.fromInline("{\"my\":\"content\"}"));
```
--------------------------------
### Basic Interceptor with Supplier
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/index.adoc
Defines a simple interceptor that wraps a Supplier. The interceptor logic executes before the nested task.
```java
public static Supplier interceptor1(String marker, Map data, Supplier nested) {
return () -> {
logger.info(message(marker, data)); // interceptor role
return task.get(); // intercepted business, "ic.proceed()" in jakarta interceptor API
};
}
public static Supplier interceptor12(Params params, Supplier nested) {
// same kind of logic for the impl
}
```
--------------------------------
### Kubernetes Deployment Manifest
Source: https://github.com/yupiik/fusion/blob/master/fusion-documentation/src/main/minisite/content/fusion/kubernetes-operator.adoc
Defines the Deployment for the operator controller. It specifies the container image, service account, and health check probes (readiness and liveness).
```json
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "api-controller",
"namespace": "default",
"labels": {
"app": "api-controller"
}
},
"spec": {
"selector": {
"matchLabels": {
"app": "api-controller"
}
},
"template": {
"metadata": {
"labels": {
"app": "api-controller"
}
},
"spec": {
"serviceAccountName": "api-controller",
"automountServiceAccountToken": true,
"containers": [
{
"name": "operator-controller",
"image": "company/operator-api",
"readinessProbe": {
"initialDelaySeconds": 4,
"periodSeconds": 30,
"failureThreshold": 10,
"timeoutSeconds": 20,
"httpGet": {
"path": "/health",
"port": 8081
}
},
"livenessProbe": {
"initialDelaySeconds": 5,
"periodSeconds": 30,
"failureThreshold": 10,
"timeoutSeconds": 30,
"httpGet": {
"path": "/health",
"port": 8081
}
}
}
]
}
},
"replicas": 1
}
}
```