Skip to content

Commit

Permalink
Merge branch 'main' into hql-escape-columns-in-order-by-with-backtick
Browse files Browse the repository at this point in the history
  • Loading branch information
ifeelgood authored Nov 23, 2023
2 parents 0161a5d + 63ff7b0 commit 8cb3db3
Show file tree
Hide file tree
Showing 68 changed files with 2,560 additions and 531 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ public interface Capability {
String LRA_PARTICIPANT = QUARKUS_PREFIX + ".lra.participant";

String JACKSON = QUARKUS_PREFIX + ".jackson";
String JSONB = QUARKUS_PREFIX + ".jsonb";

String KOTLIN = QUARKUS_PREFIX + ".kotlin";
String JAXB = QUARKUS_PREFIX + ".jaxb";
String JAXP = QUARKUS_PREFIX + ".jaxp";

String JSONB = QUARKUS_PREFIX + ".jsonb";
String KOTLIN = QUARKUS_PREFIX + ".kotlin";

String HAL = QUARKUS_PREFIX + ".hal";

Expand Down
42 changes: 42 additions & 0 deletions docs/src/main/asciidoc/config-yaml.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,45 @@ quarkus:
----

YAML `null` keys are not included in the assembly of the configuration property name, allowing them to be used at any level for disambiguating configuration keys.

Although Quarkus primarily uses `.properties` file extension for configuration, the snakeyaml library, which is used for parsing YAML in Quarkus, can also parse JSON structures. This means you can use YAML files with JSON content inside.

YAML and JSON structures can be read in an application.yaml file.

Certainly, here's a step-by-step guide on how to use complex configuration structures with Quarkus:

* Define Your Configuration Interface.

[source,java]
----
@ConfigMapping(prefix = "server")
public interface ServiceConfig {
List<Environment> environments();
interface Environment {
String name();
String services();
}
}
----

* Create the appropriate JSON structure and store it in a YAML file.

[source,yaml]
----
{
"server": {
"environments": [
{
"name": "dev",
"services": "bookstore"
},
{
"name": "batch",
"services": "warehouse"
}
]
}
}
----
79 changes: 79 additions & 0 deletions docs/src/main/asciidoc/hibernate-orm.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1242,3 +1242,82 @@ to tell Quarkus it should be used in the default persistence unit.
+
For <<multiple-persistence-units,named persistence units>>, use `@PersistenceUnitExtension("nameOfYourPU")`
<2> Implement `org.hibernate.engine.jdbc.spi.StatementInspector`.

[[json_xml_serialization_deserialization]]
== Customizing JSON/XML serialization/deserialization

By default, Quarkus will try to automatically configure format mappers depending on available extensions.
Globally configured `ObjectMapper` (or `Jsonb`) will be used for serialization/deserialization operations when Jackson (or JSON-B) is available.
Jackson will take precedence if both Jackson and JSON-B are available at the same time.

JSON and XML serialization/deserialization in Hibernate ORM can be customized by implementing a `org.hibernate.type.format.FormatMapper`
and annotating the implementation with the appropriate qualifiers:

[source,java]
----
@JsonFormat // <1>
@PersistenceUnitExtension // <2>
public class MyJsonFormatMapper implements FormatMapper { // <3>
@Override
public String inspect(String sql) {
// ...
return sql;
}
@Override
public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
// ...
}
@Override
public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
// ...
}
}
----
<1> Annotate the format mapper implementation with the `@JsonFormat` qualifier
to tell Quarkus that this mapper is specific to JSON serialization/deserialization.
+
<2> Annotate the format mapper implementation with the `@PersistenceUnitExtension` qualifier
to tell Quarkus it should be used in the default persistence unit.
+
For <<multiple-persistence-units,named persistence units>>, use `@PersistenceUnitExtension("nameOfYourPU")`
<3> Implement `org.hibernate.type.format.FormatMapper`.

In case of a custom XML format mapper, a different CDI qualifier must be applied:

[source,java]
----
@XmlFormat // <1>
@PersistenceUnitExtension // <2>
public class MyJsonFormatMapper implements FormatMapper { // <3>
@Override
public String inspect(String sql) {
// ...
return sql;
}
@Override
public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
// ...
}
@Override
public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
// ...
}
}
----
<1> Annotate the format mapper implementation with the `@XmlFormat` qualifier
to tell Quarkus that this mapper is specific to XML serialization/deserialization.
+
<2> Annotate the format mapper implementation with the `@PersistenceUnitExtension` qualifier
to tell Quarkus it should be used in the default persistence unit.
+
For <<multiple-persistence-units,named persistence units>>, use `@PersistenceUnitExtension("nameOfYourPU")`
<3> Implement `org.hibernate.type.format.FormatMapper`.

[NOTE]
====
Format mappers *must* have both `@PersistenceUnitExtension` and either `@JsonFormat` or `@XmlFormat` CDI qualifiers applied.
Having multiple JSON (or XML) format mappers registered for the same persistence unit will result in an exception, because of the ambiguity.
====
12 changes: 8 additions & 4 deletions docs/src/main/asciidoc/qute-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2425,7 +2425,11 @@ TIP: Quarkus detects possible namespace collisions and fails the build if a spec
=== Global Variables

The `io.quarkus.qute.TemplateGlobal` annotation can be used to denote static fields and methods that supply _global variables_ which are accessible in any template.
Internally, each global variable is added to the data map of any `TemplateInstance` via the `TemplateInstance#data(String, Object)` method.

Global variables are:

* added to the data map of any `TemplateInstance` during initialization,
* accessible with the `global:` namespace.

.Global Variables Definition
[source,java]
Expand Down Expand Up @@ -2454,11 +2458,11 @@ public class Globals {
[source,html]
----
User: {currentUser} <1>
Age: {age} <2>
Age: {global:age} <2>
Colors: {#each myColors}{it}{#if it_hasNext}, {/if}{/each} <3>
----
<1> `currentUser` resolves to `Globals#user()`.
<2> `age` resolves to `Globals#age`.
<2> The `global:` namespace is used; `age` resolves to `Globals#age`.
<3> `myColors` resolves to `Globals#myColors()`.

NOTE: Note that global variables implicitly add <<typesafe_expressions,parameter declarations>> to all templates and so any expression that references a global variable is validated during build.
Expand All @@ -2473,7 +2477,7 @@ Colors: RED, BLUE

==== Resolving Conflicts

Global variables may conflict with regular data objects.
If not accessed via the `global:` namespace the global variables may conflict with regular data objects.
<<typesafe_templates,Type-safe templates>> override the global variables automatically.
For example, the following definition overrides the global variable supplied by the `Globals#user()` method:

Expand Down
1 change: 1 addition & 0 deletions docs/src/main/asciidoc/reactive-event-bus.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc
= Using the event bus
include::_attributes.adoc[]
:categories: messaging
:keywords: vertx vert.x
:summary: This guide explains how different beans can interact using the event bus.
:topics: messaging,event-bus,vert.x
:extensions: io.quarkus:quarkus-vertx
Expand Down
18 changes: 18 additions & 0 deletions docs/src/main/asciidoc/redis-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,24 @@ We recommend the latter, and if possible, using secrets or an environment variab

The associated environment variable is `QUARKUS_REDIS_PASSWORD`, or `QUARKUS_REDIS_<NAME>_PASSWORD` for named clients.

=== Connection pooling

Connections to Redis are always pooled.
By default, maximum number of connections in the pool is 6.
This can be configured using `quarkus.redis.max-pool-size`.

When the connection pool is depleted, attempts to obtain a connection are put into a queue.
By default, maximum number of attempts waiting in the queue to obtain a Redis connection is 24.
This can be configured using `quarkus.redis.max-pool-waiting`.

Executing certain commands modifies the server-side state and the behavior of the connection.
Such connections cannot be reused and when closed, they are not put back into the pool; instead, they are truly closed.
The commands that cause this behavior are:

* subscription commands (`SUBSCRIBE`, `UNSUBSCRIBE` etc.)
* `SELECT`
* `AUTH`

== Use Redis data sources

Quarkus exposes a high-level API on top of Redis.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ It is an exact path match because it does not end with `*`.
<3> This permission set references the previously defined policy.
`roles1` is an example name; you can call the permission sets whatever you want.

WARNING: The `/forbidden` exact path in the example above will not secure the `/forbidden/` path. Don't forget to add new exact path for the `/forbidden/` path.

=== Custom HttpSecurityPolicy

Sometimes it might be useful to register your own named policy. You can get it done by creating application scoped CDI
Expand Down Expand Up @@ -123,10 +125,12 @@ Otherwise, it queries for an exact match and only matches that specific path:

[source,properties]
----
quarkus.http.auth.permission.permit1.paths=/public/*,/css/*,/js/*,/robots.txt
quarkus.http.auth.permission.permit1.paths=/public*,/css/*,/js/*,/robots.txt <1>
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD
----
<1> The `$$*$$` wildcard at the end of the path matches zero or more path segments, but never any word starting from the `/public` path.
For that reason, a path like `/public-info` is not matched by this pattern.

=== Matching a path but not a method

Expand Down Expand Up @@ -170,6 +174,59 @@ quarkus.http.auth.permission.public.policy=permit
----
====

=== Matching multiple sub-paths: longest path to the `*` wildcard wins

Previous examples shown how you can match all sub-paths when a path ends with the `$$*$$` wildcard.
The `$$*$$` wildcard can also be used in the middle of the path, in which case it represents exactly one path segment.
You can't combine this wildcard with any other path segment character, therefore the `$$*$$` wildcard will always be
enclosed with path separators as in the `/public/$$*$$/about-us` path.

What happens if multiple path patterns matches same request path?
Matching is always done on the "longest sub-path to the `$$*$$` wildcard wins" basis.
Every path segment character is considered more specific than the `$$*$$` wildcard.

Here is a simple example:

[source,properties]
----
quarkus.http.auth.permission.secured.paths=/api/*/detail <1>
quarkus.http.auth.permission.secured.policy=authenticated
quarkus.http.auth.permission.public.paths=/api/public-product/detail <2>
quarkus.http.auth.permission.public.policy=permit
----
<1> Request paths like `/api/product/detail` can only be accessed by authenticated users.
<2> The path `/api/public-product/detail` is more specific, therefore accessible by anyone.

[IMPORTANT]
====
All paths secured with the authorization using configuration should be tested.
Writing path patterns with multiple wildcards can be cumbersome.
Please make sure paths are authorized as you intended.
====

In the following example, paths are ordered from the most specific to the least specific one:

.Request path `/one/two/three/four/five` matches ordered from the most specific to the least specific path

[source, text]
----
/one/two/three/four/five
/one/two/three/four/*
/one/two/three/*/five
/one/two/three/*/*
/one/two/*/four/five
/one/*/three/four/five
/*/two/three/four/five
/*/two/three/*/five
/*
----

[IMPORTANT]
====
The `$$*$$` wildcard at the end of the path matches zero or more path segments.
The `$$*$$` wildcard placed anywhere else matches exactly one path segment.
====

=== Matching multiple paths: most specific method wins

When a path is registered with multiple permission sets, the permission sets explicitly specifying an HTTP method that matches the request take precedence.
Expand Down
1 change: 1 addition & 0 deletions docs/src/main/asciidoc/vertx-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc
= Vert.x Reference Guide
include::_attributes.adoc[]
:categories: miscellaneous
:keywords: vertx event verticle
:summary: This reference guide provides advanced details about the usage and the configuration of the Vert.x instance used by Quarkus.

https://vertx.io[Vert.x] is a toolkit for building reactive applications.
Expand Down
1 change: 1 addition & 0 deletions docs/src/main/asciidoc/vertx.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc
= Using Eclipse Vert.x API from a Quarkus Application
include::_attributes.adoc[]
:categories: miscellaneous
:keywords: vertx event verticle
:summary: This guide explains how to use Vert.x in Quarkus to build reactive applications.

https://vertx.io[Vert.x] is a toolkit for building reactive applications.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ private static DotName createConstant(String fqcn) {

public static final DotName INTERCEPTOR = createConstant("org.hibernate.Interceptor");
public static final DotName STATEMENT_INSPECTOR = createConstant("org.hibernate.resource.jdbc.spi.StatementInspector");
public static final DotName FORMAT_MAPPER = createConstant("org.hibernate.type.format.FormatMapper");
public static final DotName JSON_FORMAT = createConstant("io.quarkus.hibernate.orm.JsonFormat");
public static final DotName XML_FORMAT = createConstant("io.quarkus.hibernate.orm.XmlFormat");

public static final List<DotName> GENERATORS = List.of(
createConstant("org.hibernate.generator.internal.CurrentTimestampGeneration"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public class HibernateOrmCdiProcessor {
ClassNames.TENANT_RESOLVER,
ClassNames.TENANT_CONNECTION_RESOLVER,
ClassNames.INTERCEPTOR,
ClassNames.STATEMENT_INSPECTOR);
ClassNames.STATEMENT_INSPECTOR,
ClassNames.FORMAT_MAPPER);

@BuildStep
AnnotationsTransformerBuildItem convertJpaResourceAnnotationsToQualifier(
Expand Down Expand Up @@ -247,11 +248,13 @@ void generateDataSourceBeans(HibernateOrmRecorder recorder,
@BuildStep
void registerAnnotations(BuildProducer<AdditionalBeanBuildItem> additionalBeans,
BuildProducer<BeanDefiningAnnotationBuildItem> beanDefiningAnnotations) {
// add the @PersistenceUnit and @PersistenceUnitExtension classes
// add the @PersistenceUnit, @PersistenceUnitExtension, @JsonFormat and @XmlFormat classes
// otherwise they won't be registered as qualifiers
additionalBeans.produce(AdditionalBeanBuildItem.builder()
.addBeanClasses(ClassNames.QUARKUS_PERSISTENCE_UNIT.toString(),
ClassNames.PERSISTENCE_UNIT_EXTENSION.toString())
ClassNames.PERSISTENCE_UNIT_EXTENSION.toString(),
ClassNames.JSON_FORMAT.toString(),
ClassNames.XML_FORMAT.toString())
.build());

// Register the default scope for @PersistenceUnitExtension and make such beans unremovable by default
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ public void configurationDescriptorBuilding(
hibernateOrmConfig.database.ormCompatibilityVersion, Collections.emptyMap()),
null,
jpaModel.getXmlMappings(persistenceXmlDescriptorBuildItem.getDescriptor().getName()),
false, true));
false, true, capabilities));
}

if (impliedPU.shouldGenerateImpliedBlockingPersistenceUnit()) {
Expand Down Expand Up @@ -1124,7 +1124,7 @@ private static void producePersistenceUnitDescriptorFromConfig(
persistenceUnitConfig.unsupportedProperties),
persistenceUnitConfig.multitenantSchemaDatasource.orElse(null),
xmlMappings,
false, false));
false, false, capabilities));
}

private static void collectDialectConfig(String persistenceUnitName,
Expand Down
Loading

0 comments on commit 8cb3db3

Please sign in to comment.