-
Notifications
You must be signed in to change notification settings - Fork 564
FAQ
Welcome to the Helidon FAQ! If you're reading this, you're a reader, so you might also be interested in our website.
This is a living (somewhat irreverent) document (and Wiki page!) cataloging frequently asked and frequently encountered questions around the Helidon project. It may be updated, edited, reorganized, repaginated, or otherwise generally munged at any time for any reason without prior notice. There may be parts of this document that are incomplete, "to be done", missing, and so on. No guarantees are made about link longevity or content lifespan. We like to keep this document fresh.
You may read it straight through if you wish, though it has been designed to be deeply linkable. As questions come up, we post deep links to the relevant section in this document in response.
Additionally, since Helidon is (among many other things) a careful mix of our own code and repackaged code, some questions that seem like they concern Helidon are actually questions about its constituent technologies. This document tries to balance giving you a useful answer to a question, while not also, say, rewriting the documentation for Jakarta RESTful Web Services, or CDI, or Netty, or one of the other technologies that help make Helidon work. So some topics you may find here are really better addressed by other documentation sites, and we've tried to link to them as appropriate.
No, not at all. For that, you want our documentation site.
If this document says X and the website says Y, which is right?
The website.
Yes. See below. However, if you're looking for code to copy and paste, you're better served by looking at our examples. (Also: copying and pasting code without understanding what it does is almost always the wrong thing to do. You may notice that most of the examples in this FAQ contain comments designed to make copying and pasting without editing as clumsy and awkward as possible. That's on purpose.)
Helidon is a set of Java libraries for writing microservices, oriented around a Netty-based webserver. Helidon comes in two flavors: Helidon SE (reactive and no magic) and Helidon MP (a MicroProfile implementation). It's open source and available under the Apache 2.0 license.
The difference is primarily programming style.
Helidon MP is our implementation of the Eclipse MicroProfile specification. MicroProfile has familiar enterprise Java APIs like Jakarta RESTful Web Services, CDI and JSON-P. MicroProfile also specifies other microservice-focused APIs like MicroProfile Health and MicroProfile Metrics. MicroProfile APIs tend to follow a declarative style with lots of annotations. If you are used to programming in a Jakarta EE- or Spring Boot-like style, then Helidon MP will feel familiar.
Helidon SE is based on our own reactive APIs. It uses a functional style of programming with almost no annotations. You're just calling methods on plain old Java objects (POJOs). No magic!
See the Getting Started section in our documentation!
Helidon's prerequisites are available on our documentation site. (They're not written here because then they'd need to be maintained in two places.)
True MicroProfile Topics (not other topics in disguise)
Please see the Supported APIs page in our Wiki.
What's the difference between the helidon-microprofile
and helidon-microprofile-core
dependency bundles?
- The
io.helidon.microprofile.bundles:helidon-microprofile
bundle contains support for all of the foundational MicroProfile features. It's handy for getting going quickly and experimenting. It probably includes too much for any given single use case, but it is definitely convenient. - The
io.helidon.microprofile.bundles:helidon-microprofile-core
bundle contains support for minimal MicroProfile features. You then add additional dependencies as you need them. Using this core bundle is recommended for production services because it minimizes dependencies and footprint.
The Helidon MicroProfile Multiple Port Example uses the core bundle.
You can also view the contents of the full bundle to see what you might need to add to the core bundle.
When I run my Helidon MP application it complains about providers missing for authentication, tracing, etc. What's going on?
You are likely using the full helidon-microprofile
dependency bundle (see the previous question). That bundle includes Helidon MicroProfile support for most of the MicroProfile features, but not necessarily providers. For example, with tracing you need to add a tracing provider.
On the other hand, if you do not want those features in your application, then you should start with the core dependency bundle and add only what you need. See the previous question.
Helidon MP is not a Servlet implementation, nor does it supply one, so the answer is none. This is deliberate.
You can't.
The short answer is: almost certainly Jakarta RESTful Web Services has an analogous object that will do what you want instead.
Helidon MP is a MicroProfile implementation, which means by definition that it is also a Jakarta RESTful Web Services implementation (formerly JAX-RS)—it packages Jersey. By the time you're talking about requests and responses, you are "in" Jersey, and so you do things the Jersey way; Helidon MP is waiting for your response so it can route it back "through" the webserver and over the wire back to the user. But "inside" Jakarta RESTful Web Services constructs—resource classes, filters—loosely speaking there's very little Helidon MP to see. And no Servlet.
So then: most, if not all, of the things you can do with an HttpServletRequest
you can do with equivalent Jakarta RESTful Web Services constructs. For example, you can @Inject
an instance of HttpHeaders
to get the HTTP headers you need.
Similar useful classes include:
These are arbitrary examples and there are others; a full Jakarta RESTful Web Services tutorial is beyond the scope of this document. You may wish to consult the specification.
Most of the time, this is not a Helidon MP question.
This category of question reduces to: "How do I do {web thing} in Jakarta RESTful Web Services/Jersey?"
(Strictly speaking, this is not a Helidon MP question.)
This question is really: "How do I use Jackson in Jersey?"
As you might expect, the Jersey documentation has the answer.
If you are using Helidon's MicroProfile "bundles" dependency, you'll probably need to exclude some stuff too:
<dependency>
<groupId>io.helidon.microprofile.bundles</groupId>
<artifactId>helidon-microprofile</artifactId>
<exclusions>
<exclusion>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-binding</artifactId>
</exclusion>
<exclusion>
<groupId>jakarta.json.bind</groupId>
<artifactId>jakarta.json.bind-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
Yes and no. You'll note that if you had to do all that, it's because you chose to import one of our opinionated bundles, rather than selecting your dependencies individually according to your preferences.
If you add a JAX-RS exception mapper that re-maps all exceptions then you can disrupt the integration of Jersey (the JAX-RS implementation) and Helidon. For details see 7959
(Strictly speaking, this is not a Helidon MP question. This is a CDI question.)
You'll need to do a few things.
-
First, verify that you have a
src/main/resources/META-INF/beans.xml
file (orsrc/test/resources/META-INF/beans.xml
, or both). AMETA-INF/beans.xml
classpath resource marks that classpath root (usually a jar file) as a bean archive. CDI over the years and versions has changed the micro-level details of exactly what this file means and what its presence and absence mean, but it's best to have one. Now every Java class that ends up under this classpath root (which usually ends up beingtarget/classes
ortarget/test-classes
in a Maven project after compilation) will be potentially discoverable in one way or another as a CDI bean.- You'll need to make sure any dependencies you inject also live in a bean archive on your classpath (or are made visible to CDI using other mechanisms, such as portable extensions).
-
Second, make sure that
beans.xml
file looks like the following. If you're new to CDI and don't understand what you're doing, then make sure it looks exactly like the following:<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd" version="3.0" bean-discovery-mode="annotated"> <!-- This file was copied verbatim from the Helidon MP FAQ. You should probably look at it carefully to make sure it meets your needs and then remove this comment. --> </beans>
Note in particular the
bean-discovery-mode
ofannotated
. You can read more about bean discovery modes in the CDI specification. If you are new to CDI, please leave this asannotated
. -
Because you've now told CDI that it should discover only annotated beans, you need to place a bean-defining annotation on your class (that is under the classpath root that features
META-INF/beans.xml
, so usuallysrc/main/java/your/package/here/YourClass.class
). There are several bean-defining annotations but the easiest thing to do is assign your bean a scope. (If you don't know what a scope is, then this FAQ has to stop somewhere, so go read about scopes and CDI in general.)
Congratulations; you've made a CDI bean.
Assuming src/main/resources/META-INF/beans.xml
is in place with a bean-discovery-mode
of annotated
, here is an example class that is in the @Dependent
scope that is, by virtue of being annotated with @Dependent
—a bean-defining annotation—a CDI bean:
@Dependent
public class ThisClassIsAnExampleFromTheHelidonMPFAQ {
public ThisClassIsAnExampleFromTheHelidonMPFAQ() {
super();
}
}
Helidon MP is fundamentally a CDI container. So the question is really, "How do I run some code when a CDI container starts?"
(Strictly speaking, this is not a Helidon MP question.)
You write a particular kind of observer method in an enabled CDI managed bean somewhere that observes the initialization of the application scope.
The method can be named anything you like, can be public
, package-protected, protected
or private
, returns void
, and must take at least one parameter that is annotated with @Observes @Initialized(ApplicationScoped.class)
. (Usually this parameter is simply an Object
that you can simply ignore since the specification does not mandate what it must be.) Any other parameter is treated as an injection point, so you can also receive dependencies this way for your method to work with.
Here is an application scope initialization observer method. Remember, it must be declared in a class that is an enabled CDI managed bean:
private void thisIsAnExampleMethodFromTheHelidonMPFAQ(@Observes @Initialized(ApplicationScoped.class) final Object ignoredEvent) {
// code you put here will be invoked when the CDI container starts, more specifically
// when CDI's application scope is initialized
}
(Strictly speaking, this is not a Helidon MP question. This is a CDI question.)
Also strictly speaking, you tell an implementation of CDI to log things (CDI is a specification). Helidon MP uses Weld as its CDI implementation.
Using Java logging, set the org.jboss.weld
level to FINE
:
org.jboss.weld.level = FINE
Helidon MP has support for two different connection pools:
You choose one of them, never both.
To use the Universal Connection Pool, ensure the following dependency is in your project's pom.xml
's <dependencies>
stanza:
<dependency>
<groupId>io.helidon.integrations.cdi</groupId>
<artifactId>helidon-integrations-cdi-datasource-ucp</artifactId>
<!--
It's actually best to manage this with Maven's <dependencyManagement> feature.
If you opt for the explicit version here, always check
https://search.maven.org/classic/#search%7Cga%7C1%7Chelidon for up-to-date
available versions.
-->
<!-- <version>2.4.0</version> -->
<scope>runtime</scope>
</dependency>
To use the HikariCP connection pool, ensure the following dependency is in your project's pom.xml
's <dependencies>
stanza:
<dependency>
<groupId>io.helidon.integrations.cdi</groupId>
<artifactId>helidon-integrations-cdi-datasource-hikaricp</artifactId>
<!--
It's actually best to manage this with Maven's <dependencyManagement> feature.
If you opt for the explicit version here, always check
https://search.maven.org/classic/#search%7Cga%7C1%7Chelidon for up-to-date
available versions.
-->
<!-- <version>2.4.0</version> -->
<scope>runtime</scope>
</dependency>
To use connection pool-managed DataSource
instances in your code, you'll also need Maven dependencies corresponding to your database vendor's JDBC database driver. You can use any JDBC driver dependencies you like. Here are two arbitrary examples.
The Oracle Database JDBC driver is available on Maven Central and comes in a variety of flavors for a variety of use cases, all of which are documented, with examples, in the Developers Guide For Oracle JDBC 21c on Maven Central.
Some of the documented use cases include the Universal Connection Pool. You want to avoid those use cases since the Universal Connection Pool integration provided by Helidon already includes it.
Please read Developers Guide For Oracle JDBC 21c on Maven Central and understand it.
As it spells out in detail, to add just the Oracle Database 21c production JDBC driver to your project, put the following in your project's pom.xml
's <dependencies>
stanza, if it is not already there or inherited:
<dependencies>
<dependency>
<!--
See
https://www.oracle.com/database/technologies/maven-central-guide.html
for more details.
-->
<groupId>com.oracle.database.jdbc</groupId>
<!--
Why ojdbc*11*? Why not ojdbc*something else*? Because:
(a) Helidon targets Java 17
(b) Java 17 "includes" JDBC 4.3, not JDBC 4.2
(c) ojdbc11 "includes" JDBC 4.3
(d) ojdbc8 only "includes" JDBC 4.2
Please see
https://www.oracle.com/database/technologies/maven-central-guide.html
for more details.
-->
<artifactId>ojdbc11</artifactId>
<!--
It's actually best to manage this with Maven's <dependencyManagement> feature.
If you opt for the explicit version here, always check
https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22com.oracle.database.jdbc%22
for up-to-date available versions, and see
https://www.oracle.com/database/technologies/maven-central-guide.html
for extremely important information.
-->
<!-- <version>21.3.0.0</version> -->
<scope>runtime</scope>
</dependency>
</dependencies>
This is only one of several possible use cases you may have and so is not universally suitable.
The H2 database is a simple database often used for unit testing.
To add the H2 JDBC driver to your project, put the following in your project's pom.xml
's <dependencies>
stanza, if it is not already there or inherited:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<!--
It's actually best to manage this with Maven's <dependencyManagement> feature.
If you opt for the explicit version here, always check
https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22com.h2database%22%20AND%20a%3A%22h2%22
for up-to-date available versions.
-->
<!-- <version>2.0.202</version> -->
<scope>runtime</scope>
</dependency>
You configure a DataSource
in Helidon MP like you configure everything else: using Helidon's built-in MicroProfile Config implementation.
The general pattern is to tell Helidon that you have a named javax.sql.DataSource
instance you'd like to set up. Because Helidon MP uses MicroProfile Config as its configuration system, you can put this information in a variety of places.
Setting up a javax.sql.DataSource
named yourDataSourceName
isn't really different from the general process setting up other types of Java objects with names. For this reason, the general naming pattern Helidon integrations use is fully.qualified.java.class.name.
followed by theNameYouChoose.
followed by whateverTheActualPropertyIs
. So for various javax.sql.DataSource
configuration properties for a data source named yourDataSourceName
, the properties would all start with javax.sql.DataSource.yourDataSourceName.
.
As mentioned, the canonical answer is in the MicroProfile Config specification. Here are just some of the places you can place configuration information.
Here's how it might look in the src/main/resources/META-INF/microprofile-config.properties
configuration source:
javax.sql.DataSource.yourDataSourceName.somePropertyOfYourConnectionPoolAndDataSource = itsValue
javax.sql.DataSource.yourDataSourceName.someOtherPropertyOfYourConnectionPoolAndDataSource = anotherValue
Here's how it might look as system properties instead:
java \
-Djavax.sql.DataSource.yourDataSourceName.somePropertyOfYourConnectionPoolAndDataSource=itsValue \
-Djavax.sql.DataSource.yourDataSourceName.someOtherPropertyOfYourConnectionPoolAndDataSource=anotherValue \
# ...
Here's how it might look as environment variables as typed directly into a command line shell, taking advantage of MicroProfile Config's mapping rules, since many shells will not understand environment variable names with periods (.
) in them:
JAVAX_SQL_DATASOURCE_YOURDATASOURCENAME_SOMEPROPERTYOFYOURCONNECTIONPOOLANDDATASOURCE=itsValue \
JAVAX_SQL_DATASOURCE_YOURDATASOURCENAME_SOMEOTHERPROPERTYOFYOURCONNECTIONPOOLANDDATASOURCE=anotherValue \
java # ...
Here's how it might look as environment variables as supplied via the env
shell command, thus removing the need for MicroProfile Config's mapping rules and making things more efficient as a result:
env 'javax.sql.DataSource.yourDataSourceName.somePropertyOfYourConnectionPoolAndDataSource=itsValue' \
'javax.sql.DataSource.yourDataSourceName.someOtherPropertyOfYourConnectionPoolAndDataSource=anotherValue' \
java # ...
Here's how it might look as YAML in a src/main/resources/application.yaml
file (assuming the file is registered as a MicroProfile Config configuration source):
javax:
sql:
DataSource:
yourDataSourceName:
somePropertyOfYourConnectionPoolAndDataSource: itsValue
someOtherPropertyOfYourConnectionPoolAndDataSource: anotherValue
Finally of course you can mix and match these approaches, taking advantage of MicroProfile Config's non-deterministic precedence rules, so that, for example, a data source property set as a system property will override one that may appear in src/main/resources/META-INF/microprofile-config.properties
. There is nothing specific to data sources about how all this works.
For more on MicroProfile Config configuration sources, please see the relevant Helidon guide and/or the MicroProfile Config documentation.
No. Specifically, Helidon does not support application.properties
out of the box as a source of external configuration. You can, of course, register a configuration source following the rules of the MicroProfile Config specification.
Not really. The actual property names are those your DataSource
implementation actually supports, and can also vary depending on which connection pool you are using. You'll need to consult the specific examples below tailored to a combination of database driver and connection pool.
Can you give me a specific example of connecting to an Oracle database with a UCP-managed DataSource
?
This example presumes that you have set up the Universal Connection Pool as described earlier in this document.
Here is an example in Java properties file format that configures a Universal Connection Pool-managed data source named main
to connect to an Oracle Database on localhost
port 1521
using the "thin" driver with a service name of XE
with a user
of scott
and a password
of tiger
:
# (Why "connectionFactoryClassName"? See
# https://docs.oracle.com/en/database/oracle/oracle-database/21/jjuar/oracle/ucp/jdbc/PoolDataSourceImpl.html#setConnectionFactoryClassName_java_lang_String_)
javax.sql.DataSource.main.connectionFactoryClassName = oracle.jdbc.pool.OracleDataSource
javax.sql.DataSource.main.url = jdbc:oracle:thin://@localhost:1521/XE # see https://docs.oracle.com/en/database/oracle/oracle-database/21/jjdbc/data-sources-and-URLs.html#GUID-EF07727C-50AB-4DCE-8EDC-57F0927FF61A
javax.sql.DataSource.main.user = scott
javax.sql.DataSource.main.password = tiger
Can you give me a specific example of connecting to an H2 database with a HikariCP-managed DataSource
?
This example presumes that you have set up the HikariCP connection pool as described earlier in this document.
Here is an example that configures a HikariCP-managed data source named test
to connect to an in-memory H2 database named unit-testing
with a user
of sa
and an empty password
:
# Why "dataSourceClassName"? See
# https://github.com/brettwooldridge/HikariCP#essentials
javax.sql.DataSource.test.dataSourceClassName = org.h2.jdbcx.JdbcDataSource
# Why "dataSource."? See
# https://github.com/brettwooldridge/HikariCP/blob/HikariCP-5.0.0/src/main/java/com/zaxxer/hikari/util/PropertyElf.java#L47-L49
javax.sql.DataSource.test.dataSource.url = jdbc:h2:mem:unit-testing;DB_CLOSE_DELAY=-1 # see http://www.h2database.com/html/features.html#database_url
javax.sql.DataSource.test.dataSource.user = sa
javax.sql.DataSource.test.dataSource.password =
Is there a general pattern I can use to figure out how to set other properties on the Universal Connection Pool in particular?
Yes, but with some limitations and a number of problems.
The Universal Connection Pool exposes various properties as Java Bean properties. In general, if its pooling mechanism, the oracle.ucp.jdbc.PoolDataSourceImpl
class (not to be confused with your DataSource
implementation that it wraps!), has a public
method that starts with set
and takes a single String
or int
parameter (and a corresponding get
-prefixed method that returns a value of the same type), you can cause that "setter" method to be invoked by setting an analogous property in your configuration.
For example, to cause the setMinPoolSize(int)
method to be called (corresponding to the Java Beans property named minPoolSize
), you can set the minPoolSize
property for your named data source like so:
javax.sql.DataSource.main.minPoolSize = 1 # for example
One thing that can be confusing when using the Universal Connection Pool in particular is that the DataSource
implementation it uses—oracle.ucp.jdbc.PoolDataSourceImpl
—to wrap your DataSource
implementation (to provide pooling machinery for it)—say, org.h2.jdbcx.JdbcDataSource
—exposes some Java Beans properties that are destined both for your DataSource
implementation and itself! (The description
Java Bean property of oracle.ucp.jdbc.PoolDataSourceImpl
is one such example: setting javax.sql.DataSource.yourDataSourceName.description = someDescription
will cause the setDescription
method of oracle.ucp.jdbc.PoolDataSourceImpl
to be called, as well as the setDescription
method of org.h2.jdbcx.JdbcDataSource
.) Is this confusing? You bet! But it's entirely out of Helidon's control.
It is thus unavoidably hard to figure out which properties affect the pool itself, which affect your DataSource
implementation (that the pool wraps), and which might affect both. So, for example, if you were to set the databaseName
Java Beans property on the pool, it might also "forward" that to your DataSource
implementation (if it supports that Java Bean property). But other Java Bean properties like, for example, maxIdleTime
, are (one hopes!) properties of just the connection pooling mechanism itself, and (probably!) not of your DataSource
implementation. Unfortunately, knowing which is which basically comes down to intuition, trial, and error.
Is there a general pattern I can use to figure out how to set other properties on the HikariCP connection pool in particular?
Yes. The HikariCP connection pool uses properties that are fully documented. Helidon's integration of the HikariCP connection pool prefixes these properties with its usual type-of-object string (javax.sql.DataSource.
), followed by the name of your data source (yourDataSourceName.
). So, for example, to set the HikariCP connection pool dataSourceClassName
Java Bean property, you would set a corresponding MicroProfile Config property like so:
javax.sql.DataSource.yourDataSourceName.dataSourceClassName = org.h2.jdbcx.JdbcDataSource # for example
To set a Java Bean property on your DataSource
implementation itself (for example, the loginTimeout
Java Bean property of org.h2.jdbcx.JdbcDataSource
), you prefix the property name with the usual Helidon prefix (javax.sql.DataSource.yourDataSourceName.
), the HikariCP-reserved word dataSource.
, and the property name itself (loginTimeout
):
javax.sql.DataSource.yourDataSourceName.dataSource.loginTimeout = 100 # for example
Database Vendor |
DataSource class name |
UCP property example | HikariCP property example |
---|---|---|---|
Oracle | oracle.jdbc.pool.OracleDataSource |
javax.sql.DataSource.yourDataSourceName.connectionFactoryClassName = oracle.jdbc.pool.OracleDataSource |
javax.sql.DataSource.yourDataSourceName.dataSourceClassName = oracle.jdbc.pool.OracleDataSource |
H2 | org.h2.jdbcx.JdbcDataSource |
javax.sql.DataSource.yourDataSourceName.connectionFactoryClassName = org.h2.jdbcx.JdbcDataSource |
javax.sql.DataSource.yourDataSourceName.dataSourceClassName = org.h2.jdbcx.JdbcDataSource |
PostgreSQL | org.postgresql.ds.PGSimpleDataSource |
javax.sql.DataSource.yourDataSourceName.connectionFactoryClassName = org.postgresql.ds.PGSimpleDataSource |
javax.sql.DataSource.yourDataSourceName.dataSourceClassName = org.postgresql.ds.PGSimpleDataSource |
Helidon's JTA support is provided by Narayana. Setting Narayana's properties can be tricky.
To change the default transaction timeout by setting a system property, add this to your java
command line:
# Specifies the default timeout for Narayana's transaction coordinator in seconds.
-Dcom.arjuna.ats.arjuna.coordinator.defaultTimeout=120
You probably shouldn't be. Usually this means you haven't added the right indices to your database tables, or that your JPA query is manifesting the n + 1 problem. In any event, increasing the transaction timeout is almost always the wrong thing to do.
Stop right there. This is not a Helidon question. This is a question about application-managed JPA versus container-managed JPA. Helidon provides container-managed JPA integration, which means among many, many other things you don't specify JDBC information in your META-INF/persistence.xml
file. You will want to read the specification for more details. Briefly, the entire point of container-managed JPA is that all of this stuff is taken care of for you, so your META-INF/persistence.xml
classpath resource should mention a JTA-enabled data source name that should be used to connect to the database. See the other topics in this FAQ concerning data sources for some more information.
WebClient is the HTTP client of Helidon SE. It is also used internally by other Helidon modules such as the OIDC and the IDCS Roles Security Providers. For more details about WebClient, please refer to the Helidon WebClient Documentation.
When you set a proxy in WebClient, it will use absolute URI in the request because of changes made in Helidon Issue #2302 and Issue #3438. The use of absolute URI was implemented because of section 5.1.2 Request-URI
in https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html which states:
The absoluteURI form is REQUIRED when the request is being made to a proxy.
The problem is that some hosts have issue processing a request with absolute URI as they expect relative URI instead. As an example, this was encountered when running the testcase in Helidon Issue #4644 where the WebClient is connecting to KeyCloak as an OIDC server via a Proxy. Every time the request is made, KeyCloak will fail with an Http Status 404
response because it cannot handle the absoluteURI.
To resolve this issue, there is a WebClient method called relative-uris(boolean) that can force the request URI to use the relative form rather than absolute and is demonstrated by below source code example:
Proxy proxy = Proxy.builder()
.host("localhost")
.port(8080)
.build();
WebClientConfiguration webConfig = WebClient.builder()
.relativeUris(true)
.proxy(proxy)
.configuration();
As noted above, Helidon modules like (https://helidon.io/docs/v3/#/mp/security/providers#OIDC-Provider) and the IDCS Roles security providers use WebClient internally to communicate with the target server. In Helidon MP, there is a special configuration property called relative-uris
for OidcConfig that is used for this purpose. Hence if Proxy is needed for either or both modules, relative-uris can be set in the Helidon ConfigSource (such as microprofile-config.properties
) like below:
security:
providers:
- oidc:
...
force-https-redirects: true
proxy-host: "www.proxyhost.com"
proxy-port: 80
relative-uris: true
- idcs-role-mapper:
multitenant: false
oidc-config:
...
force-https-redirects: true
proxy-host: "www.proxyhost.com"
proxy-port: 80
relative-uris: true
For more details on the Configuration Options
for OIDC
and IDCS Roles
security providers, they can be found in the Helidon documentation under this section and here, respectively.
OpenAPI is the follow-on standard to Swagger for defining the external interface to REST services. MicroProfile OpenAPI supports OpenAPI via MP annotations, additional APIs, and the /openapi
endpoint which serves the OpenAPI document for the service.
- Read our MP OpenAPI documentation here and SE doc here.
- Do what the doc says: update your
pom.xml
and:-
Add some annotations to your MP app, or
-
Choose a way to provide the OpenAPI information to Helidon for your SE app.
Unlike with MP, which uses annotation processing to find out for itself about your service's endpoints, you have to tell Helidon SE OpenAPI about your service's REST API. The documentation explains how you can do this either by providing a static OpenAPI file or by writing some code that creates the in-memory model for your API.
-
The OpenAPITools project offers a code generator for many languages and platforms. The Helidon team has contributed significant upgrades to the Helidon support in the tool.
See our documentation for full details:
- for SE: https://helidon.io/docs/latest/index.html#/se/openapi/openapi-generator
- for MP: https://helidon.io/docs/latest/index.html#/mp/openapi/openapi-generator
As described above, Helidon can create an OpenAPI document that describes your application as your service starts up.
If you want to generate the document when you build your application, you can try this plug-in from SmallRye. The Helidon team neither supports nor endorses this plug-in but it might work for you.
SmallRye provides a component you can add to your application so it displays a UI based on the OpenAPI document for your service. You can drive the public API of your service using the UI to make sure your service works as you expect.
See our updated documentation:
- for SE: https://helidon.io/docs/latest/index.html#/se/openapi/openapi-ui
- for MP: https://helidon.io/docs/latest/index.html#/mp/openapi/openapi-ui
Please read the documentation--CORS for MP or CORS for SE--very carefully. It describes how to plan the CORS behavior you want and how to use both the @CrossOrigin
annotation (MP only) and configuration (MP and SE) to set up that CORS behavior.
-
Whether you use annotations (in MP) or configuration (MP and SE), you set up CORS behavior by resource, or put another way, by path. Not by Java method. In MP you use the
@CrossOrigin
annotation on the@OPTIONS
methods, but that annotation's settings applies to all methods which share the same@Path
, whether explicit or by default. -
If you are not seeing the CORS behavior you expect:
-
Turn on CORS logging:
io.helidon.webserver.cors.level=FINE
-
Restart the server.
-
If you can, send a single problematic request to the server.
-
Search the log file for relevant messages. For example, if requests you think should work are being refused, search for "CORS denying request" in the log output and read that entire message carefully.
FINE-level logging produces lots of output (which is why you want to send only one request if you can to debug the problem) but Helidon will explain the decisions it makes about CORS processing for each request.
In particular, Helidon announces the CORS type of each request: normal, CORS or CORS pre-flight. For each CORS or CORS pre-flight request, Helidon searches for matching CORS settings from your annotations (MP only) or configuration. If no CORS settings apply to the request Helidon reports "CORS denying request" and dumps the request's CORS-related metadata (path, HTTP method, and headers) and then explains why it denied access.
-
-
For even more detail, set the logging level to
FINER
. Internally, Helidon builds a table of CORS setting instances, basically one row for each CORS annotation or CORS config entry you use.FINER
-level logging tells you, for each incoming request, which of those CORS settings Helidon matched to the request. Knowing this can sometimes help you understand why CORS treats a request the way it does.
This is a dependency problem in your project. Depending on the class that was not found at runtime, you need to figure out which of your dependencies is at fault. StackOverflow can help you here. Sometimes you can accidentally include an older version of a dependency that Helidon itself uses. If you've gummed up the Maven works in this way, you'll want to run mvn dependency:tree
on your project to find how your dependency is being pulled in (or why it's missing). The Maven documentation has several examples.
We Were Using Helidon 2.x And Upgraded To Helidon 3.x And Now It's Not Working In Some Bizarre Way Involving Missing Classes Or Something
Helidon is just fine. Your project's dependency tree, however, is not.
Almost certainly this is because of the great javax
-to-jakarta
switchover, which occurred as part of Jakarta EE's evolution from Jakarta EE 8 to Jakarta EE 9. Helidon 2.x implements parts of Jakarta EE 8, so uses Jakarta EE 8 dependencies; Helidon 3.x implements those parts of Jakarta EE 9 instead, so uses Jakarta EE 9 dependencies. Therefore, your whole stack must also switch from Jakarta EE 8 classes to Jakarta EE 9 classes. You can use mvn dependency:tree
on your project to find how a particular dependency is being pulled in (or why it's missing). The Maven documentation has several examples.
No. This is just where this document currently ends. Enjoy your day!