[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6ADR00QFR0TKQYQBPV7CCNK":3,"skill-same:01M6ADR00QFR0TKQYQBPV7CCNK":73},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":49,"commitSha":50,"skillDirectory":51,"forksCount":52,"repositoryHtmlUrl":53,"repositoryHomepageUrl":54,"ownerHtmlUrl":55,"ownerBlogUrl":56,"ownerDescription":57,"updatedAt":58,"install":59,"resources":72},"01M6ADR00QFR0TKQYQBPV7CCNK","java-helidon",null,"Get best practices for developing applications with Helidon 4 (SE and MP). Use when working with Helidon SE or Helidon MP, HttpService routing, Helidon DB Client, MicroProfile Config, Helidon Security, or Helidon testing in Java 21+ projects.","github\u002Fawesome-copilot","github","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F9919?v=4","01M6AC83DS133TPXFSP1DHNCC6","GitHub","01M6AD3PBDYPK7NVFJNJ66Y8RS",41156,"MIT","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fawesome-copilot\u002Fblob\u002Fmain\u002Fskills\u002Fjava-helidon\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"java","java helidon","use","when","microprofile","for","with","java 21","client","db","get","se","testing","projects","applications","best practices","mp","routing","config","security","2026-11-10 10:12:30",false,"---\nname: java-helidon\ndescription: 'Get best practices for developing applications with Helidon 4 (SE and MP). Use when working with Helidon SE or Helidon MP, HttpService routing, Helidon DB Client, MicroProfile Config, Helidon Security, or Helidon testing in Java 21+ projects.'\n---\n\n# Helidon Best Practices\n\nYour goal is to help me write high-quality Helidon applications by following established best practices.\n\n## Helidon 3 → 4 API changes\n\nHelidon 4 renamed or resignatured APIs that appear widely in their Helidon 3 form.\nThe left column does not compile on Helidon 4. Check generated code against this table\nbefore returning it.\n\n| Do not use (Helidon 3)                                     | Use (Helidon 4)                                                    |\n| ---------------------------------------------------------- | ------------------------------------------------------------------ |\n| `io.helidon.common.http.Http.Status`                       | `io.helidon.http.Status`                                           |\n| `io.helidon.webserver.Service`                             | `io.helidon.webserver.http.HttpService`                            |\n| `Routing.Rules`, `update(Routing.Rules)`                   | `HttpRules`, `routing(HttpRules)`                                  |\n| `request.path().param(\"id\")`                               | `request.path().pathParameters().get(\"id\")`                        |\n| `String s = column.as(String.class)`                       | `column.getString()` or `column.get(String.class)`                 |\n| `dbClient.execute(exec -> ...)` returning `Single`\u002F`Multi` | `dbClient.execute()` returning `Optional\u003CDbRow>` \u002F `Stream\u003CDbRow>` |\n| `javax.*`                                                  | `jakarta.*`                                                        |\n| `helidon-microprofile-tests-junit5`                        | `helidon-microprofile-testing-junit5`                              |\n\n`Value.as(Class)` in Helidon 4 returns `OptionalValue\u003CT>`, not `T`. This is the single\nmost common Helidon 4 compile error in generated code.\n\n## Project Setup & Structure\n\n- **Programming Model:** Determine whether the project uses Helidon SE or Helidon MP before generating code. Do not mix the two programming models unless explicitly required.\n- **Java Version:** Use Java 21 or later for Helidon 4 applications.\n- **Build Tool:** Use Maven (`pom.xml`) or Gradle (`build.gradle`) for dependency management.\n- **Dependency Management:** Use the Helidon BOM or platform to keep Helidon module versions aligned.\n- **Package Structure:** Organize code by feature or domain, such as `com.example.app.order` and `com.example.app.customer`, rather than only by technical layer.\n\n## Helidon SE\n\n- **Explicit Composition:** Construct services and dependencies explicitly in the application bootstrap layer.\n- **Constructor Injection:** Pass required dependencies through constructors and declare dependency fields as `private final`.\n- **HTTP Services:** Group related routes in focused `HttpService` implementations.\n- **Business Logic:** Keep business logic outside route handlers.\n- **Virtual Threads:** Prefer straightforward blocking code with Helidon 4 virtual-thread-based request handling. Do not introduce reactive complexity without a clear reason. Helidon 4 is not reactive; do not generate `Single`, `Multi`, or `CompletionStage` chains.\n\n## Helidon MP\n\n- **Jakarta and MicroProfile:** Prefer standard Jakarta EE and Eclipse MicroProfile APIs when available.\n- **Dependency Injection:** Use CDI with constructor injection for required dependencies.\n- **Bean Scopes:** Use CDI scopes such as `@ApplicationScoped` and `@RequestScoped` intentionally.\n- **Normal-Scoped Beans:** Add a non-private no-argument constructor to normal-scoped beans that use constructor injection, so the CDI client proxy can be created portably.\n- **Business Logic:** Keep Jakarta REST resource classes thin and delegate business operations to service classes.\n- **Portability:** Prefer portable Jakarta and MicroProfile APIs over Helidon-specific APIs when portability is important.\n\n## Configuration\n\n- **Externalized Configuration:** Store non-secret configuration in `application.yaml` or `application.properties`.\n- **Helidon SE Configuration:** Use Helidon Config and pass configuration values or typed configuration objects to components.\n- **Helidon MP Configuration:** Use MicroProfile Config for injected application settings.\n- **Environment Overrides:** Use environment variables or deployment-specific configuration sources for environment-dependent values.\n- **Secrets Management:** Never hardcode credentials, API keys, tokens, or private certificates.\n\n## Web Layer\n\n- **DTOs:** Use dedicated request and response models. Do not expose persistence entities directly through APIs.\n- **Validation:** Validate path parameters, query parameters, headers, and request bodies before invoking business logic.\n- **Status Codes:** Return appropriate HTTP status codes for successful, invalid, unauthorized, forbidden, missing, and failed requests. On `PUT` and `DELETE`, return 404 when the target does not exist rather than succeeding unconditionally.\n- **Error Handling:** Use centralized error handling in Helidon SE and Jakarta REST `ExceptionMapper` implementations in Helidon MP.\n- **Sensitive Information:** Do not expose stack traces, database details, filesystem paths, or internal exception messages to clients.\n\n### Helidon SE Example\n\nUse an `HttpService` to register routes programmatically. Keep request handlers small and delegate business logic to a service.\n\n```java\nimport io.helidon.http.Status;\nimport io.helidon.webserver.http.HttpRules;\nimport io.helidon.webserver.http.HttpService;\nimport io.helidon.webserver.http.ServerRequest;\nimport io.helidon.webserver.http.ServerResponse;\n\npublic final class CustomerHttpService implements HttpService {\n\n    private final CustomerService customerService;\n\n    public CustomerHttpService(CustomerService customerService) {\n        this.customerService = customerService;\n    }\n\n    @Override\n    public void routing(HttpRules rules) {\n        rules.get(\"\u002F{id}\", this::findById);\n    }\n\n    private void findById(ServerRequest request, ServerResponse response) {\n        var id = request.path().pathParameters().get(\"id\");\n\n        customerService.findById(id)\n                .ifPresentOrElse(\n                        response::send,\n                        () -> response.status(Status.NOT_FOUND_404).send()\n                );\n    }\n}\n```\n\nRegister the HTTP service when constructing the server:\n\n```java\nimport io.helidon.webserver.WebServer;\n\nWebServer server = WebServer.builder()\n        .routing(routing -> routing.register(\"\u002Fcustomers\", customerHttpService))\n        .build()\n        .start();\n```\n\n### Helidon MP Example\n\nUse Jakarta REST annotations for endpoints and CDI for dependency injection.\n\n```java\nimport jakarta.enterprise.context.RequestScoped;\nimport jakarta.inject.Inject;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.PathParam;\nimport jakarta.ws.rs.Produces;\nimport jakarta.ws.rs.core.MediaType;\nimport jakarta.ws.rs.core.Response;\n\n@Path(\"\u002Fcustomers\")\n@RequestScoped\n@Produces(MediaType.APPLICATION_JSON)\npublic class CustomerResource {\n\n    private final CustomerService customerService;\n\n    protected CustomerResource() {\n        this.customerService = null;\n    }\n\n    @Inject\n    public CustomerResource(CustomerService customerService) {\n        this.customerService = customerService;\n    }\n\n    @GET\n    @Path(\"\u002F{id}\")\n    public Response findById(@PathParam(\"id\") String id) {\n        return customerService.findById(id)\n                .map(customer -> Response.ok(customer).build())\n                .orElseGet(() -> Response.status(Response.Status.NOT_FOUND).build());\n    }\n}\n```\n\n## Service Layer\n\n- **Transactions:** Define transaction boundaries around complete business operations.\n- **Entity Mapping:** Map persistence entities to API models at the service boundary so that service method signatures expose only API models. A service returning `Optional\u003CCustomerEntity>` where the caller expects `Optional\u003CCustomer>` is a common generated-code compile error.\n- **Concurrency:** Avoid mutable shared state in application-scoped components unless access is properly coordinated.\n\n### Helidon SE Example\n\nHelidon SE services are normally plain Java classes with explicitly supplied dependencies.\n\n```java\npublic final class CustomerService {\n\n    private final CustomerRepository customerRepository;\n\n    public CustomerService(CustomerRepository customerRepository) {\n        this.customerRepository = customerRepository;\n    }\n\n    public Optional\u003CCustomer> findById(String id) {\n        if (id == null || id.isBlank()) {\n            throw new IllegalArgumentException(\"Customer ID is required\");\n        }\n\n        return customerRepository.findById(id);\n    }\n\n    public Customer create(CreateCustomerRequest request) {\n        if (request.name() == null || request.name().isBlank()) {\n            throw new IllegalArgumentException(\"Customer name is required\");\n        }\n\n        var customer = new Customer(request.id(), request.name().trim());\n\n        customerRepository.save(customer);\n        return customer;\n    }\n}\n```\n\nConstruct the dependency graph explicitly:\n\n```java\nvar repository = new DbCustomerRepository(dbClient);\nvar service = new CustomerService(repository);\nvar httpService = new CustomerHttpService(service);\n```\n\n### Helidon MP Example\n\nUse CDI scopes and constructor injection. Apply transactions at the service layer when a business operation changes persistent state. Map the persistence entity to the API model here, so the service never leaks `CustomerEntity` to callers.\n\n```java\nimport jakarta.enterprise.context.ApplicationScoped;\nimport jakarta.inject.Inject;\nimport jakarta.transaction.Transactional;\n\n@ApplicationScoped\npublic class CustomerService {\n\n    private final JpaCustomerRepository customerRepository;\n\n    protected CustomerService() {\n        this.customerRepository = null;\n    }\n\n    @Inject\n    public CustomerService(JpaCustomerRepository customerRepository) {\n        this.customerRepository = customerRepository;\n    }\n\n    public Optional\u003CCustomer> findById(String id) {\n        if (id == null || id.isBlank()) {\n            throw new IllegalArgumentException(\"Customer ID is required\");\n        }\n\n        return customerRepository.findById(id)\n                .map(Customer::fromEntity);\n    }\n\n    @Transactional\n    public Customer create(CreateCustomerRequest request) {\n        if (request.name() == null || request.name().isBlank()) {\n            throw new IllegalArgumentException(\"Customer name is required\");\n        }\n\n        var entity = new CustomerEntity(request.id(), request.name().trim());\n\n        customerRepository.save(entity);\n        return Customer.fromEntity(entity);\n    }\n}\n```\n\n## Data Layer\n\n- **Database Access:** Use Helidon DB Client, Jakarta Persistence, or another persistence mechanism already established by the project.\n- **Parameterized Queries:** Always use parameter binding or prepared statements. Never concatenate untrusted input into SQL.\n- **Column Accessors:** Read a typed column value with `column(\"name\").getString()` (or `getInt()`, `getLong()`, and so on) or with `column(\"name\").get(String.class)`. `DbColumn.as(String.class)` returns an `OptionalValue\u003CString>` in Helidon 4, not a `String`.\n- **Nullable Columns:** Read nullable columns through `asOptional()` or another optional-aware accessor. Direct `getString()` and similar accessors throw when the column value is null.\n- **Row Mapping:** For whole-row mapping, `DbRow.as(Customer.class)` returns the mapped instance directly, but requires a `DbMapper` registered through a `DbMapperProvider` service-loader entry. Prefer explicit column reads for a small number of simple repositories, and introduce a `DbMapper` when the same row shape is mapped in several places.\n- **Migrations:** Use a database migration tool for schema changes rather than automatic destructive schema updates.\n- **Entity Separation:** Do not expose database entities directly as API contracts.\n\n### Helidon SE Example\n\nUse Helidon DB Client with parameterized statements. Map database rows into application models inside the repository.\n\n```java\nimport io.helidon.dbclient.DbClient;\n\npublic final class DbCustomerRepository implements CustomerRepository {\n\n    private static final String FIND_BY_ID =\n            \"SELECT id, name FROM customers WHERE id = :id\";\n\n    private static final String INSERT =\n            \"INSERT INTO customers (id, name) VALUES (:id, :name)\";\n\n    private final DbClient dbClient;\n\n    public DbCustomerRepository(DbClient dbClient) {\n        this.dbClient = dbClient;\n    }\n\n    @Override\n    public Optional\u003CCustomer> findById(String id) {\n        return dbClient.execute()\n                .createGet(FIND_BY_ID)\n                .addParam(\"id\", id)\n                .execute()\n                .map(row -> new Customer(\n                        row.column(\"id\").getString(),\n                        row.column(\"name\").getString()\n                ));\n    }\n\n    @Override\n    public void save(Customer customer) {\n        dbClient.execute()\n                .createInsert(INSERT)\n                .addParam(\"id\", customer.id())\n                .addParam(\"name\", customer.name())\n                .execute();\n    }\n}\n```\n\nNamed statements can also be stored in configuration instead of embedding SQL in Java:\n\n```yaml\ndb:\n  source: \"jdbc\"\n  connection:\n    url: \"jdbc:postgresql:\u002F\u002Flocalhost:5432\u002Fcustomers\"\n    username: ${DB_USERNAME}\n    password: ${DB_PASSWORD}\n  statements:\n    find-customer-by-id: >\n      SELECT id, name\n      FROM customers\n      WHERE id = :id\n```\n\nReference the named statement by name instead of passing SQL text:\n\n```java\nreturn dbClient.execute()\n        .createNamedGet(\"find-customer-by-id\")\n        .addParam(\"id\", id)\n        .execute()\n        .map(row -> new Customer(\n                row.column(\"id\").getString(),\n                row.column(\"name\").getString()\n        ));\n```\n\n### Helidon MP Example\n\nUse Jakarta Persistence in a CDI-managed repository. Keep transaction boundaries in the service layer. The repository works in entities; the service maps them to API models.\n\n```java\nimport jakarta.enterprise.context.ApplicationScoped;\nimport jakarta.persistence.EntityManager;\nimport jakarta.persistence.PersistenceContext;\n\n@ApplicationScoped\npublic class JpaCustomerRepository {\n\n    @PersistenceContext\n    private EntityManager entityManager;\n\n    public Optional\u003CCustomerEntity> findById(String id) {\n        return Optional.ofNullable(entityManager.find(CustomerEntity.class, id));\n    }\n\n    public void save(CustomerEntity customer) {\n        entityManager.persist(customer);\n    }\n}\n```\n\nDefine the persistence entity separately from the public API model:\n\n```java\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.Table;\n\n@Entity\n@Table(name = \"customers\")\npublic class CustomerEntity {\n\n    @Id\n    private String id;\n\n    @Column(nullable = false)\n    private String name;\n\n    protected CustomerEntity() {\n    }\n\n    public CustomerEntity(String id, String name) {\n        this.id = id;\n        this.name = name;\n    }\n\n    public String id() {\n        return id;\n    }\n\n    public String name() {\n        return name;\n    }\n}\n```\n\nThe API model stays free of persistence annotations and owns the mapping:\n\n```java\npublic record Customer(String id, String name) {\n\n    public static Customer fromEntity(CustomerEntity entity) {\n        return new Customer(entity.id(), entity.name());\n    }\n}\n```\n\n## Observability\n\n- **Health:** Use Helidon Health in SE or MicroProfile Health in MP for liveness and readiness checks.\n- **Metrics:** Use Helidon Metrics or MicroProfile Metrics for operational and business measurements.\n- **Tracing:** Propagate tracing context across inbound and outbound service calls.\n- **Cardinality:** Avoid user IDs, request IDs, email addresses, and raw URLs as metric tags.\n\n## Logging\n\n- **Logging API:** Use the logging API and implementation configured by the project.\n- **Sensitive Information:** Never log passwords, access tokens, authorization headers, cookies, or complete sensitive request bodies. Do not place secrets or personal information in metrics or trace attributes either.\n\n## Testing\n\n- **Unit Tests:** Write unit tests for business services using JUnit 5.\n- **Helidon SE Tests:** Use `helidon-webserver-testing-junit5` with `@ServerTest` for full server tests and `@RoutingTest` for routing-only tests. These start the server on a dynamically selected port and inject a `Http1Client` bound to it. Never hardcode a port.\n- **Helidon MP Tests:** Use `helidon-microprofile-testing-junit5` with `@HelidonTest`, which starts the CDI container and server for the test class. Confirm the artifact coordinates against the Helidon version in use, since this module was renamed across 4.x releases.\n- **Testcontainers:** Consider Testcontainers for integration tests using real databases, message brokers, or other infrastructure.\n- **Failure Paths:** Test validation failures, missing resources, external-service failures, and authorization failures.\n\n## Security\n\n- **Helidon Security:** Use Helidon Security or supported Jakarta and MicroProfile security APIs for authentication and authorization.\n- **Authorization:** Enforce permissions at a clear application boundary and deny protected operations by default.\n- **JWT and OIDC:** Validate token signatures, issuers, audiences, and expiration times.\n- **TLS:** Use TLS for production traffic and verify certificates for outbound connections.\n- **CORS:** Configure allowed origins explicitly. Do not combine wildcard origins with credentials.\n- **Secrets:** Store secrets in protected environment configuration or a dedicated secret-management system.\n- **Outbound Requests:** Validate outbound destinations to reduce server-side request forgery risks.\n","# Helidon Best Practices\n\nYour goal is to help me write high-quality Helidon applications by following established best practices.\n\n## Helidon 3 → 4 API changes\n\nHelidon 4 renamed or resignatured APIs that appear widely in their Helidon 3 form.\nThe left column does not compile on Helidon 4. Check generated code against this table\nbefore returning it.\n\n| Do not use (Helidon 3)                                     | Use (Helidon 4)                                                    |\n| ---------------------------------------------------------- | ------------------------------------------------------------------ |\n| `io.helidon.common.http.Http.Status`                       | `io.helidon.http.Status`                                           |\n| `io.helidon.webserver.Service`                             | `io.helidon.webserver.http.HttpService`                            |\n| `Routing.Rules`, `update(Routing.Rules)`                   | `HttpRules`, `routing(HttpRules)`                                  |\n| `request.path().param(\"id\")`                               | `request.path().pathParameters().get(\"id\")`                        |\n| `String s = column.as(String.class)`                       | `column.getString()` or `column.get(String.class)`                 |\n| `dbClient.execute(exec -> ...)` returning `Single`\u002F`Multi` | `dbClient.execute()` returning `Optional\u003CDbRow>` \u002F `Stream\u003CDbRow>` |\n| `javax.*`                                                  | `jakarta.*`                                                        |\n| `helidon-microprofile-tests-junit5`                        | `helidon-microprofile-testing-junit5`                              |\n\n`Value.as(Class)` in Helidon 4 returns `OptionalValue\u003CT>`, not `T`. This is the single\nmost common Helidon 4 compile error in generated code.\n\n## Project Setup & Structure\n\n- **Programming Model:** Determine whether the project uses Helidon SE or Helidon MP before generating code. Do not mix the two programming models unless explicitly required.\n- **Java Version:** Use Java 21 or later for Helidon 4 applications.\n- **Build Tool:** Use Maven (`pom.xml`) or Gradle (`build.gradle`) for dependency management.\n- **Dependency Management:** Use the Helidon BOM or platform to keep Helidon module versions aligned.\n- **Package Structure:** Organize code by feature or domain, such as `com.example.app.order` and `com.example.app.customer`, rather than only by technical layer.\n\n## Helidon SE\n\n- **Explicit Composition:** Construct services and dependencies explicitly in the application bootstrap layer.\n- **Constructor Injection:** Pass required dependencies through constructors and declare dependency fields as `private final`.\n- **HTTP Services:** Group related routes in focused `HttpService` implementations.\n- **Business Logic:** Keep business logic outside route handlers.\n- **Virtual Threads:** Prefer straightforward blocking code with Helidon 4 virtual-thread-based request handling. Do not introduce reactive complexity without a clear reason. Helidon 4 is not reactive; do not generate `Single`, `Multi`, or `CompletionStage` chains.\n\n## Helidon MP\n\n- **Jakarta and MicroProfile:** Prefer standard Jakarta EE and Eclipse MicroProfile APIs when available.\n- **Dependency Injection:** Use CDI with constructor injection for required dependencies.\n- **Bean Scopes:** Use CDI scopes such as `@ApplicationScoped` and `@RequestScoped` intentionally.\n- **Normal-Scoped Beans:** Add a non-private no-argument constructor to normal-scoped beans that use constructor injection, so the CDI client proxy can be created portably.\n- **Business Logic:** Keep Jakarta REST resource classes thin and delegate business operations to service classes.\n- **Portability:** Prefer portable Jakarta and MicroProfile APIs over Helidon-specific APIs when portability is important.\n\n## Configuration\n\n- **Externalized Configuration:** Store non-secret configuration in `application.yaml` or `application.properties`.\n- **Helidon SE Configuration:** Use Helidon Config and pass configuration values or typed configuration objects to components.\n- **Helidon MP Configuration:** Use MicroProfile Config for injected application settings.\n- **Environment Overrides:** Use environment variables or deployment-specific configuration sources for environment-dependent values.\n- **Secrets Management:** Never hardcode credentials, API keys, tokens, or private certificates.\n\n## Web Layer\n\n- **DTOs:** Use dedicated request and response models. Do not expose persistence entities directly through APIs.\n- **Validation:** Validate path parameters, query parameters, headers, and request bodies before invoking business logic.\n- **Status Codes:** Return appropriate HTTP status codes for successful, invalid, unauthorized, forbidden, missing, and failed requests. On `PUT` and `DELETE`, return 404 when the target does not exist rather than succeeding unconditionally.\n- **Error Handling:** Use centralized error handling in Helidon SE and Jakarta REST `ExceptionMapper` implementations in Helidon MP.\n- **Sensitive Information:** Do not expose stack traces, database details, filesystem paths, or internal exception messages to clients.\n\n### Helidon SE Example\n\nUse an `HttpService` to register routes programmatically. Keep request handlers small and delegate business logic to a service.\n\n```java\nimport io.helidon.http.Status;\nimport io.helidon.webserver.http.HttpRules;\nimport io.helidon.webserver.http.HttpService;\nimport io.helidon.webserver.http.ServerRequest;\nimport io.helidon.webserver.http.ServerResponse;\n\npublic final class CustomerHttpService implements HttpService {\n\n    private final CustomerService customerService;\n\n    public CustomerHttpService(CustomerService customerService) {\n        this.customerService = customerService;\n    }\n\n    @Override\n    public void routing(HttpRules rules) {\n        rules.get(\"\u002F{id}\", this::findById);\n    }\n\n    private void findById(ServerRequest request, ServerResponse response) {\n        var id = request.path().pathParameters().get(\"id\");\n\n        customerService.findById(id)\n                .ifPresentOrElse(\n                        response::send,\n                        () -> response.status(Status.NOT_FOUND_404).send()\n                );\n    }\n}\n```\n\nRegister the HTTP service when constructing the server:\n\n```java\nimport io.helidon.webserver.WebServer;\n\nWebServer server = WebServer.builder()\n        .routing(routing -> routing.register(\"\u002Fcustomers\", customerHttpService))\n        .build()\n        .start();\n```\n\n### Helidon MP Example\n\nUse Jakarta REST annotations for endpoints and CDI for dependency injection.\n\n```java\nimport jakarta.enterprise.context.RequestScoped;\nimport jakarta.inject.Inject;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.PathParam;\nimport jakarta.ws.rs.Produces;\nimport jakarta.ws.rs.core.MediaType;\nimport jakarta.ws.rs.core.Response;\n\n@Path(\"\u002Fcustomers\")\n@RequestScoped\n@Produces(MediaType.APPLICATION_JSON)\npublic class CustomerResource {\n\n    private final CustomerService customerService;\n\n    protected CustomerResource() {\n        this.customerService = null;\n    }\n\n    @Inject\n    public CustomerResource(CustomerService customerService) {\n        this.customerService = customerService;\n    }\n\n    @GET\n    @Path(\"\u002F{id}\")\n    public Response findById(@PathParam(\"id\") String id) {\n        return customerService.findById(id)\n                .map(customer -> Response.ok(customer).build())\n                .orElseGet(() -> Response.status(Response.Status.NOT_FOUND).build());\n    }\n}\n```\n\n## Service Layer\n\n- **Transactions:** Define transaction boundaries around complete business operations.\n- **Entity Mapping:** Map persistence entities to API models at the service boundary so that service method signatures expose only API models. A service returning `Optional\u003CCustomerEntity>` where the caller expects `Optional\u003CCustomer>` is a common generated-code compile error.\n- **Concurrency:** Avoid mutable shared state in application-scoped components unless access is properly coordinated.\n\n### Helidon SE Example\n\nHelidon SE services are normally plain Java classes with explicitly supplied dependencies.\n\n```java\npublic final class CustomerService {\n\n    private final CustomerRepository customerRepository;\n\n    public CustomerService(CustomerRepository customerRepository) {\n        this.customerRepository = customerRepository;\n    }\n\n    public Optional\u003CCustomer> findById(String id) {\n        if (id == null || id.isBlank()) {\n            throw new IllegalArgumentException(\"Customer ID is required\");\n        }\n\n        return customerRepository.findById(id);\n    }\n\n    public Customer create(CreateCustomerRequest request) {\n        if (request.name() == null || request.name().isBlank()) {\n            throw new IllegalArgumentException(\"Customer name is required\");\n        }\n\n        var customer = new Customer(request.id(), request.name().trim());\n\n        customerRepository.save(customer);\n        return customer;\n    }\n}\n```\n\nConstruct the dependency graph explicitly:\n\n```java\nvar repository = new DbCustomerRepository(dbClient);\nvar service = new CustomerService(repository);\nvar httpService = new CustomerHttpService(service);\n```\n\n### Helidon MP Example\n\nUse CDI scopes and constructor injection. Apply transactions at the service layer when a business operation changes persistent state. Map the persistence entity to the API model here, so the service never leaks `CustomerEntity` to callers.\n\n```java\nimport jakarta.enterprise.context.ApplicationScoped;\nimport jakarta.inject.Inject;\nimport jakarta.transaction.Transactional;\n\n@ApplicationScoped\npublic class CustomerService {\n\n    private final JpaCustomerRepository customerRepository;\n\n    protected CustomerService() {\n        this.customerRepository = null;\n    }\n\n    @Inject\n    public CustomerService(JpaCustomerRepository customerRepository) {\n        this.customerRepository = customerRepository;\n    }\n\n    public Optional\u003CCustomer> findById(String id) {\n        if (id == null || id.isBlank()) {\n            throw new IllegalArgumentException(\"Customer ID is required\");\n        }\n\n        return customerRepository.findById(id)\n                .map(Customer::fromEntity);\n    }\n\n    @Transactional\n    public Customer create(CreateCustomerRequest request) {\n        if (request.name() == null || request.name().isBlank()) {\n            throw new IllegalArgumentException(\"Customer name is required\");\n        }\n\n        var entity = new CustomerEntity(request.id(), request.name().trim());\n\n        customerRepository.save(entity);\n        return Customer.fromEntity(entity);\n    }\n}\n```\n\n## Data Layer\n\n- **Database Access:** Use Helidon DB Client, Jakarta Persistence, or another persistence mechanism already established by the project.\n- **Parameterized Queries:** Always use parameter binding or prepared statements. Never concatenate untrusted input into SQL.\n- **Column Accessors:** Read a typed column value with `column(\"name\").getString()` (or `getInt()`, `getLong()`, and so on) or with `column(\"name\").get(String.class)`. `DbColumn.as(String.class)` returns an `OptionalValue\u003CString>` in Helidon 4, not a `String`.\n- **Nullable Columns:** Read nullable columns through `asOptional()` or another optional-aware accessor. Direct `getString()` and similar accessors throw when the column value is null.\n- **Row Mapping:** For whole-row mapping, `DbRow.as(Customer.class)` returns the mapped instance directly, but requires a `DbMapper` registered through a `DbMapperProvider` service-loader entry. Prefer explicit column reads for a small number of simple repositories, and introduce a `DbMapper` when the same row shape is mapped in several places.\n- **Migrations:** Use a database migration tool for schema changes rather than automatic destructive schema updates.\n- **Entity Separation:** Do not expose database entities directly as API contracts.\n\n### Helidon SE Example\n\nUse Helidon DB Client with parameterized statements. Map database rows into application models inside the repository.\n\n```java\nimport io.helidon.dbclient.DbClient;\n\npublic final class DbCustomerRepository implements CustomerRepository {\n\n    private static final String FIND_BY_ID =\n            \"SELECT id, name FROM customers WHERE id = :id\";\n\n    private static final String INSERT =\n            \"INSERT INTO customers (id, name) VALUES (:id, :name)\";\n\n    private final DbClient dbClient;\n\n    public DbCustomerRepository(DbClient dbClient) {\n        this.dbClient = dbClient;\n    }\n\n    @Override\n    public Optional\u003CCustomer> findById(String id) {\n        return dbClient.execute()\n                .createGet(FIND_BY_ID)\n                .addParam(\"id\", id)\n                .execute()\n                .map(row -> new Customer(\n                        row.column(\"id\").getString(),\n                        row.column(\"name\").getString()\n                ));\n    }\n\n    @Override\n    public void save(Customer customer) {\n        dbClient.execute()\n                .createInsert(INSERT)\n                .addParam(\"id\", customer.id())\n                .addParam(\"name\", customer.name())\n                .execute();\n    }\n}\n```\n\nNamed statements can also be stored in configuration instead of embedding SQL in Java:\n\n```yaml\ndb:\n  source: \"jdbc\"\n  connection:\n    url: \"jdbc:postgresql:\u002F\u002Flocalhost:5432\u002Fcustomers\"\n    username: ${DB_USERNAME}\n    password: ${DB_PASSWORD}\n  statements:\n    find-customer-by-id: >\n      SELECT id, name\n      FROM customers\n      WHERE id = :id\n```\n\nReference the named statement by name instead of passing SQL text:\n\n```java\nreturn dbClient.execute()\n        .createNamedGet(\"find-customer-by-id\")\n        .addParam(\"id\", id)\n        .execute()\n        .map(row -> new Customer(\n                row.column(\"id\").getString(),\n                row.column(\"name\").getString()\n        ));\n```\n\n### Helidon MP Example\n\nUse Jakarta Persistence in a CDI-managed repository. Keep transaction boundaries in the service layer. The repository works in entities; the service maps them to API models.\n\n```java\nimport jakarta.enterprise.context.ApplicationScoped;\nimport jakarta.persistence.EntityManager;\nimport jakarta.persistence.PersistenceContext;\n\n@ApplicationScoped\npublic class JpaCustomerRepository {\n\n    @PersistenceContext\n    private EntityManager entityManager;\n\n    public Optional\u003CCustomerEntity> findById(String id) {\n        return Optional.ofNullable(entityManager.find(CustomerEntity.class, id));\n    }\n\n    public void save(CustomerEntity customer) {\n        entityManager.persist(customer);\n    }\n}\n```\n\nDefine the persistence entity separately from the public API model:\n\n```java\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.Table;\n\n@Entity\n@Table(name = \"customers\")\npublic class CustomerEntity {\n\n    @Id\n    private String id;\n\n    @Column(nullable = false)\n    private String name;\n\n    protected CustomerEntity() {\n    }\n\n    public CustomerEntity(String id, String name) {\n        this.id = id;\n        this.name = name;\n    }\n\n    public String id() {\n        return id;\n    }\n\n    public String name() {\n        return name;\n    }\n}\n```\n\nThe API model stays free of persistence annotations and owns the mapping:\n\n```java\npublic record Customer(String id, String name) {\n\n    public static Customer fromEntity(CustomerEntity entity) {\n        return new Customer(entity.id(), entity.name());\n    }\n}\n```\n\n## Observability\n\n- **Health:** Use Helidon Health in SE or MicroProfile Health in MP for liveness and readiness checks.\n- **Metrics:** Use Helidon Metrics or MicroProfile Metrics for operational and business measurements.\n- **Tracing:** Propagate tracing context across inbound and outbound service calls.\n- **Cardinality:** Avoid user IDs, request IDs, email addresses, and raw URLs as metric tags.\n\n## Logging\n\n- **Logging API:** Use the logging API and implementation configured by the project.\n- **Sensitive Information:** Never log passwords, access tokens, authorization headers, cookies, or complete sensitive request bodies. Do not place secrets or personal information in metrics or trace attributes either.\n\n## Testing\n\n- **Unit Tests:** Write unit tests for business services using JUnit 5.\n- **Helidon SE Tests:** Use `helidon-webserver-testing-junit5` with `@ServerTest` for full server tests and `@RoutingTest` for routing-only tests. These start the server on a dynamically selected port and inject a `Http1Client` bound to it. Never hardcode a port.\n- **Helidon MP Tests:** Use `helidon-microprofile-testing-junit5` with `@HelidonTest`, which starts the CDI container and server for the test class. Confirm the artifact coordinates against the Helidon version in use, since this module was renamed across 4.x releases.\n- **Testcontainers:** Consider Testcontainers for integration tests using real databases, message brokers, or other infrastructure.\n- **Failure Paths:** Test validation failures, missing resources, external-service failures, and authorization failures.\n\n## Security\n\n- **Helidon Security:** Use Helidon Security or supported Jakarta and MicroProfile security APIs for authentication and authorization.\n- **Authorization:** Enforce permissions at a clear application boundary and deny protected operations by default.\n- **JWT and OIDC:** Validate token signatures, issuers, audiences, and expiration times.\n- **TLS:** Use TLS for production traffic and verify certificates for outbound connections.\n- **CORS:** Configure allowed origins explicitly. Do not combine wildcard origins with credentials.\n- **Secrets:** Store secrets in protected environment configuration or a dedicated secret-management system.\n- **Outbound Requests:** Validate outbound destinations to reduce server-side request forgery risks.\n",{"name":5,"description":7},"main","5269f7ea2d6c3a9bfda5ed878b6726cf509121fd","skills\u002Fjava-helidon",5360,"https:\u002F\u002Fgithub.com\u002Fgithub\u002Fawesome-copilot","https:\u002F\u002Fawesome-copilot.github.com\u002F","https:\u002F\u002Fgithub.com\u002Fgithub","https:\u002F\u002Fgithub.com\u002Fabout","How people build software.","2026-11-14 05:37:52",{"source":8,"skillName":5,"commands":60,"prompt":70,"zipAvailable":71},[61,64,67],{"tool":62,"command":63},"npx","npx skills add github\u002Fawesome-copilot --skill java-helidon",{"tool":65,"command":66},"bunx","bunx skills add github\u002Fawesome-copilot --skill java-helidon",{"tool":68,"command":69},"pnpm","pnpm dlx skills add github\u002Fawesome-copilot --skill java-helidon","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fgithub\u002Fawesome-copilot\u002Fblob\u002Fmain\u002Fskills\u002Fjava-helidon\u002FSKILL.md",true,[],[74,101,128,156,190,207],{"skillNo":75,"name":76,"nameZh":6,"description":77,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":84,"publishedAt":44},"01M70KXZNX9ES38N2A8M58ZZMZ","supabase-rls-policies","Write, review, and test Supabase Row Level Security (RLS) policies so that one user cannot read or change another user's rows. Use when creating or changing tables, policies, views, or security definer functions in a Supabase project, when reviewing a migration that touches RLS, or when asked to prove user isolation with pgTAP tests that sign in as two users.","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fawesome-copilot\u002Fblob\u002Fmain\u002Fskills\u002Fsupabase-rls-policies\u002FSKILL.md",[80,81],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":82,"categoryName":83,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[85,86,87,88,89,27,90,91,92,93,43,94,95,96,97,98,26,99,100,30],"supabase","rls","supabase rls","supabase rls policies","project","review","change","read","write","isolation","tables","as","tests","prove","users","functions",{"skillNo":102,"name":103,"nameZh":6,"description":104,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":105,"categories":106,"keywords":108,"publishedAt":44},"01M70KWA5YWXDV6V8DZ19E3T2Y","skill-distribution-audit","Audit a skill collection before release or investigate installer omissions, archived\u002Ftemplate leakage, duplicate identities, and manifest drift. Reconcile the intended public source set, distribution manifest, and actual discovery output for a specified consumer version. Includes a deterministic set-comparison helper.","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fawesome-copilot\u002Fblob\u002Fmain\u002Fskills\u002Fskill-distribution-audit\u002FSKILL.md",[107],{"categoryNo":82,"categoryName":83,"taxonomyType":21,"taxonomyTypeDesc":22},[109,110,111,112,113,114,29,115,116,117,118,119,120,121,122,123,124,125,126,127],"distribution","skill distribution audit","audit","SET","deterministic","installer","discovery","comparison","helper","manifest","version","collection","drift","output","investigate","duplicate","template","release","reconcile",{"skillNo":129,"name":130,"nameZh":6,"description":131,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":132,"sourceHtmlUrl":133,"categories":134,"keywords":140,"publishedAt":44},"01M70KCJPFVW7PPQ49CC5R8JGK","logicapps-custom-code-net10-migration","Migrate Azure Logic Apps Standard local-function custom-code projects from .NET 8 to .NET 10. Use for legacy Logic Apps custom-code workspace upgrades, project\u002Fpackage configuration, custom-worker settings, publication, and integrated VS Code debugging. Not for ordinary .NET applications, standalone Azure Functions, Consumption workflows, or cloud deployment.","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fawesome-copilot\u002Fblob\u002Fmain\u002Fskills\u002Flogicapps-custom-code-net10-migration\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fawesome-copilot\u002Fblob\u002Fmain\u002Fskills\u002Flogicapps-custom-code-net10-migration\u002FSKILL.md",[135],{"categoryNo":136,"categoryName":137,"taxonomyType":138,"taxonomyTypeDesc":139},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[141,142,143,144,37,145,29,89,146,38,147,148,149,150,151,26,152,153,154,155],"custom","code","logicapps custom code net10 migration","migration","standalone","deployment","local","azure","worker","upgrades","package","apps","Legacy","debugging","workflows",{"skillNo":157,"name":158,"nameZh":6,"description":159,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":160,"sourceHtmlUrl":161,"categories":162,"keywords":167,"publishedAt":44},"01M6AEBN37RQMXJ3298PEY7PG1","winmd-api-search","Find and explore Windows desktop APIs. Use when building features that need platform capabilities — camera, file access, notifications, UI controls, AI\u002FML, sensors, networking, etc. Discovers the right API for a task and retrieves full type details (methods, properties, events, enumeration values).","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fawesome-copilot\u002Fblob\u002Fmain\u002Fskills\u002Fwinmd-api-search\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fawesome-copilot\u002Fblob\u002Fmain\u002Fskills\u002Fwinmd-api-search\u002FSKILL.md",[163,166],{"categoryNo":164,"categoryName":165,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":136,"categoryName":137,"taxonomyType":138,"taxonomyTypeDesc":139},[168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,27,183,184,185,186,187,29,188,189],"winmd api search","search","api","windows","desktop","file access","enumeration","ui","ml","file","networking","capabilities","notifications","explore","access","features","full","camera","events","platform","methods","controls",{"skillNo":191,"name":192,"nameZh":6,"description":193,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":194,"licenseFileUrl":195,"sourceHtmlUrl":196,"categories":197,"keywords":203,"publishedAt":44},"01M6AE571R3SC1ZGE202B3NB5S","resemble-detect","Deepfake detection and media safety — detect AI-generated audio, images, video, and text, trace synthesis sources, apply watermarks, verify speaker identity, and analyze media intelligence using Resemble AI","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fawesome-copilot\u002Fblob\u002Fmain\u002Fskills\u002Fresemble-detect\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fawesome-copilot\u002Fblob\u002Fmain\u002Fskills\u002Fresemble-detect\u002FSKILL.md",[198,199,202],{"categoryNo":164,"categoryName":165,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":200,"categoryName":201,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000016","图像与多媒体",{"categoryNo":82,"categoryName":83,"taxonomyType":21,"taxonomyTypeDesc":22},[204,112,177,205,206],"resemble detect","https","identity",{"skillNo":208,"name":209,"nameZh":6,"description":210,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":194,"licenseFileUrl":211,"sourceHtmlUrl":212,"categories":213,"keywords":218,"publishedAt":44},"01M6AE30BSK2HCY4TQQ22Z8JRD","quality-playbook","Run a complete quality engineering audit on any codebase. Derives behavioral requirements from the code, generates spec-traced functional tests, runs a three-pass code review with regression tests, executes a multi-model spec audit (Council of Three), and produces a consolidated bug report with TDD-verified patches. Finds the 35% of real defects that structural code review alone cannot catch. Works with any language. Trigger on 'quality playbook', 'spec audit', 'Council of Three', 'fitness-to-purpose', or 'coverage theater'.","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fawesome-copilot\u002Fblob\u002Fmain\u002Fskills\u002Fquality-playbook\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fawesome-copilot\u002Fblob\u002Fmain\u002Fskills\u002Fquality-playbook\u002FSKILL.md",[214,217],{"categoryNo":215,"categoryName":216,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000007","代码审查",{"categoryNo":82,"categoryName":83,"taxonomyType":21,"taxonomyTypeDesc":22},[219,220,221,222,142,90,9,111,223,224,205,225,226,227,228,229,230,231,232,233,234,235,97,236,237,238,239],"playbook","quality playbook","quality","code review","tdd","run","report","spec","bug report","council","engineering","functional","spec audit","bug","verified","multi-model","three","coverage","model","regression","structural"]