Skip to content

Commit 59f285d

Browse files
authored
Hikari to UCP Recipe (#183)
Version 0.1
1 parent a60dd57 commit 59f285d

File tree

7 files changed

+635
-0
lines changed

7 files changed

+635
-0
lines changed

recipes/hikariucp/.gitignore

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
target/
2+
!.mvn/wrapper/maven-wrapper.jar
3+
!**/src/main/**/target/
4+
!**/src/test/**/target/
5+
*.log
6+
7+
### IntelliJ IDEA ###
8+
.idea/modules.xml
9+
.idea/jarRepositories.xml
10+
.idea/compiler.xml
11+
.idea/libraries/
12+
*.iws
13+
*.iml
14+
*.ipr
15+
.idea
16+
.idea/**
17+
18+
### Eclipse ###
19+
.apt_generated
20+
.classpath
21+
.factorypath
22+
.project
23+
.settings
24+
.springBeans
25+
.sts4-cache
26+
27+
### NetBeans ###
28+
/nbproject/private/
29+
/nbbuild/
30+
/dist/
31+
/nbdist/
32+
/.nb-gradle/
33+
build/
34+
!**/src/main/**/build/
35+
!**/src/test/**/build/
36+
37+
### VS Code ###
38+
.vscode/
39+
/.jpb/**
40+
41+
### Mac OS ###
42+
.DS_Store

recipes/hikariucp/README.md

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Hikari to UCP Open Rewrite Recipe
2+
3+
Current Version is `0.0.1-SNAPSHOT` and is under development. Please file GitHub issues for issues, enhancements and more.
4+
5+
## Hikari to UCP rewrite Recipe
6+
7+
> **_NOTE:_** In the pre release the rewrite works best with `properties` files. `YAML` files works too but the formatting of the outcome isn't pretty.
8+
9+
This recipe will change the Hikare connection pool parameters and dependency from Hikari to Oracle Universal Connection Pooling (UCP). The [UCP documentation](https://docs.oracle.com/en/database/oracle/oracle-database/23/jjucp/index.html).
10+
11+
The following properties are rewritten:
12+
13+
### Maven dependencies `pom.xml`
14+
15+
The Hikari dependency is removed and replaced with SPring Boot starters for Oracle UCP and Oracle Wallet (commonly used to connect to an autonomous database (ADB)).
16+
17+
```xml
18+
<dependency>
19+
<groupId>com.zaxxer</groupId>
20+
<artifactId>HikariCP</artifactId>
21+
</dependency>
22+
```
23+
24+
is changed to:
25+
26+
```xml
27+
<dependency>
28+
<groupId>com.oracle.database.spring</groupId>
29+
<artifactId>oracle-spring-boot-starter-ucp</artifactId>
30+
<version>25.1.0</version>
31+
</dependency>
32+
```
33+
34+
The following dependency is removed (all ojdbc* variants) and replaced by the UCP Starter:
35+
36+
```xml
37+
<dependency>
38+
<groupId>com.oracle.database.jdbc</groupId>
39+
<artifactId>ojdbc*</artifactId>
40+
</dependency>
41+
```
42+
43+
And the following dependency is added, as it is commonly used to connect to an autonomous database (ADB):
44+
45+
```xml
46+
<dependency>
47+
<groupId>com.oracle.database.spring</groupId>
48+
<artifactId>oracle-spring-boot-starter-wallet</artifactId>
49+
<version>25.1.0</version>
50+
</dependency>
51+
```
52+
53+
### Spring Boot Connection Pooling configuration `application.properties`
54+
55+
> **_NOTE:_** The recipe will change Hikari's milliseconds to seconds.
56+
57+
The following properties are rewritten. [UCP documentation](https://docs.oracle.com/en/database/oracle/oracle-database/23/jjucp/index.html)
58+
59+
| Hikari Property | Oracle UCP Property | Notes |
60+
|-----------------|---------------------|-------|
61+
| N/A | `spring.datasource.driver-class-name` | Will be set to `oracle.jdbc.OracleDriver` |
62+
| N/A | `spring.datasource.type` | Will be set to `oracle.ucp.jdbc.PoolDataSource` |
63+
| `spring.datasource.hikari.pool-name` | `spring.datasource.oracleucp.connection-pool-name` | |
64+
| `spring.datasource.hikari.maximum-pool-size` | `spring.datasource.oracleucp.max-pool-size` | |
65+
| `spring.datasource.hikari.minimum-idle` | `spring.datasource.oracleucp.min-pool-size` | |
66+
| `spring.datasource.hikari.connection-timeout` | `spring.datasource.oracleucp.connection-wait-timeout` | |
67+
| `spring.datasource.hikari.idle-timeout` | `spring.datasource.oracleucp.inactive-connection-timeout` | |
68+
| `spring.datasource.hikari.connection-test-query` | `spring.datasource.oracleucp.s-q-l-for-validate-connection` | |
69+
| `spring.datasource.hikari.max-lifetime` | `spring.datasource.oracleucp.max-connection-reuse-time` | |
70+
| `spring.datasource.hikari.validation-timeout` | `spring.datasource.oracleucp.connection-validation-timeout` | |
71+
72+
The following UCP properties are added:
73+
74+
| Oracle UCP Property | Value | Notes |
75+
|---------------------|-------|-------|
76+
| `spring.datasource.oracleucp.initial-pool-size` | 5 | [UCP documentation](https://docs.oracle.com/en/database/oracle/oracle-database/23/jjucp/index.html) |
77+
78+
The following Hikari Properties do not have identical UCP properties and will be commented out in the rewritten properties file. [UCP documentation](https://docs.oracle.com/en/database/oracle/oracle-database/23/jjucp/index.html)
79+
80+
| Hikari UCP Property | Notes |
81+
|---------------------|-------|
82+
| `spring.datasource.hikari.auto-commit` | Use Oracle JDBC driver connection property autoCommit |
83+
| `spring.datasource.hikari.register-mbeans` | UCP always attempts registration |
84+
| `spring.datasource.hikari.thread-factory` | UCP supports setTaskManager instead |
85+
| `spring.datasource.hikari.scheduled-executor` | UCP supports setTaskManager instead |
86+
| `spring.datasource.hikari.keepalive-time` | Closest is to use driver connection properties oracle.net.keepAlive + oracle.net.TCP_KEEPIDLE |
87+
88+
## Build the Open Rewrite Recipe
89+
90+
The repo is using maven. To build the recipe run the following command:
91+
92+
```shell
93+
mvn install
94+
```
95+
96+
## To use the Recipe
97+
98+
In the repository you want to test your recipe against, update the `pom.xml` to include the following:
99+
100+
```xml
101+
<project>
102+
<build>
103+
<plugins>
104+
<plugin>
105+
<groupId>org.openrewrite.maven</groupId>
106+
<artifactId>rewrite-maven-plugin</artifactId>
107+
<version>6.3.2</version> <!-- Verify the version, March 2025 -->
108+
<configuration>
109+
<activeRecipes>
110+
<recipe>ConvertHikariToUCP </recipe>
111+
</activeRecipes>
112+
</configuration>
113+
<dependencies>
114+
<dependency>
115+
<groupId>com.oracle.cloud.recipes</groupId>
116+
<artifactId>hikariucp</artifactId>
117+
<version>0.0.1-SNAPSHOT</version>
118+
</dependency>
119+
</dependencies>
120+
</plugin>
121+
</plugins>
122+
</build>
123+
</project>
124+
```

recipes/hikariucp/pom.xml

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!-- Copyright (c) 2025, Oracle and/or its affiliates. -->
3+
<!-- Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. -->
4+
<project xmlns="http://maven.apache.org/POM/4.0.0"
5+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
7+
<modelVersion>4.0.0</modelVersion>
8+
9+
<groupId>com.oracle.cloud.recipes</groupId>
10+
<artifactId>hikariucp</artifactId>
11+
<version>0.0.1-SNAPSHOT</version>
12+
<name>hikari-ucp</name>
13+
<description>Openrewrite Recipe to convert Hikari Connection Pool to Oracle UCP</description>
14+
15+
<url>https://github.com/oracle/spring-cloud-oracle/tree/hikari-ucp-recipe/recipes/hikari-ucp</url>
16+
17+
<organization>
18+
<name>Oracle America, Inc.</name>
19+
<url>https://www.oracle.com</url>
20+
</organization>
21+
<licenses>
22+
<license>
23+
<name>The Universal Permissive License (UPL), Version 1.0</name>
24+
<url>https://oss.oracle.com/licenses/upl/</url>
25+
<distribution>repo</distribution>
26+
</license>
27+
</licenses>
28+
<developers>
29+
<developer>
30+
<name>Oracle</name>
31+
<email>obaas_ww at oracle.com</email>
32+
<organization>Oracle America, Inc.</organization>
33+
<organizationUrl>https://www.oracle.com</organizationUrl>
34+
</developer>
35+
</developers>
36+
<scm>
37+
<url>https://github.com/oracle/spring-cloud-oracle</url>
38+
<connection>scm:git:https://github.com/oracle/spring-cloud-oracle.git</connection>
39+
<developerConnection>scm:git:[email protected]:oracle/spring-cloud-oracle.git</developerConnection>
40+
</scm>
41+
42+
<properties>
43+
<java.version>17</java.version>
44+
<maven.compiler.source>17</maven.compiler.source>
45+
<maven.compiler.target>17</maven.compiler.target>
46+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
47+
<rewrite.version>8.48.1</rewrite.version> <!-- Latest as of Mar 2025 -->
48+
<rewrite.recipe.version>3.3.0</rewrite.recipe.version> <!-- Latest as of Mar 2025 -->
49+
<maven.rewrite.plugin.version>6.3.2</maven.rewrite.plugin.version> <!-- Latest as of Mar 2025 -->
50+
<junit.version>5.12.1</junit.version> <!-- Latest as of Mar 2025 -->
51+
</properties>
52+
53+
<dependencies>
54+
<dependency>
55+
<groupId>org.openrewrite</groupId>
56+
<artifactId>rewrite-java</artifactId>
57+
<version>${rewrite.version}</version>
58+
</dependency>
59+
60+
<dependency>
61+
<groupId>org.openrewrite</groupId>
62+
<artifactId>rewrite-properties</artifactId>
63+
<version>${rewrite.version}</version>
64+
</dependency>
65+
66+
<dependency>
67+
<groupId>org.openrewrite</groupId>
68+
<artifactId>rewrite-yaml</artifactId>
69+
<version>${rewrite.version}</version>
70+
</dependency>
71+
72+
<dependency>
73+
<groupId>org.openrewrite</groupId>
74+
<artifactId>rewrite-maven</artifactId>
75+
<version>${rewrite.version}</version>
76+
</dependency>
77+
78+
<dependency>
79+
<groupId>org.junit.jupiter</groupId>
80+
<artifactId>junit-jupiter</artifactId>
81+
<scope>test</scope>
82+
</dependency>
83+
84+
<dependency>
85+
<groupId>org.openrewrite</groupId>
86+
<artifactId>rewrite-test</artifactId>
87+
<scope>test</scope>
88+
</dependency>
89+
</dependencies>
90+
91+
<dependencyManagement>
92+
<dependencies>
93+
<dependency>
94+
<groupId>org.openrewrite.recipe</groupId>
95+
<artifactId>rewrite-recipe-bom</artifactId>
96+
<version>${rewrite.recipe.version}</version>
97+
<type>pom</type>
98+
<scope>import</scope>
99+
</dependency>
100+
<dependency>
101+
<groupId>org.junit</groupId>
102+
<artifactId>junit-bom</artifactId>
103+
<version>${junit.version}</version>
104+
<type>pom</type>
105+
<scope>import</scope>
106+
</dependency>
107+
</dependencies>
108+
</dependencyManagement>
109+
110+
<build>
111+
<plugins>
112+
<plugin>
113+
<groupId>org.openrewrite.maven</groupId>
114+
<artifactId>rewrite-maven-plugin</artifactId>
115+
<version>${maven.rewrite.plugin.version}</version>
116+
<!-- <configuration>-->
117+
<!-- <exportDatatables>true</exportDatatables>-->
118+
<!-- <activeRecipes>-->
119+
<!-- <recipe>ConvertHikariToUCP</recipe>-->
120+
<!-- </activeRecipes>-->
121+
<!-- </configuration>-->
122+
<dependencies>
123+
<dependency>
124+
<groupId>org.openrewrite.recipe</groupId>
125+
<artifactId>rewrite-spring</artifactId>
126+
<version>5.24.1</version>
127+
</dependency>
128+
</dependencies>
129+
</plugin>
130+
131+
</plugins>
132+
</build>
133+
134+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) 2025, Oracle and/or its affiliates.
2+
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
3+
4+
package com.oracle.cloud.recipes.hikariucp;
5+
6+
import org.openrewrite.NlsRewrite;
7+
import org.openrewrite.ExecutionContext;
8+
import org.openrewrite.Recipe;
9+
import org.openrewrite.TreeVisitor;
10+
import org.openrewrite.properties.PropertiesVisitor;
11+
import org.openrewrite.properties.tree.Properties;
12+
13+
public class ConvertMsToSecondsInPropertiesRecipe extends Recipe {
14+
15+
private final String keyRegex;
16+
17+
// Takes a keyRegex parameter to specify which property keys to target (e.g., Hikari timeout properties).
18+
public ConvertMsToSecondsInPropertiesRecipe(String keyRegex) {
19+
this.keyRegex = keyRegex;
20+
}
21+
22+
// Extends PropertiesVisitor to process each Properties.Entry (key-value pair) in application.properties.
23+
@Override
24+
public TreeVisitor<?, ExecutionContext> getVisitor() {
25+
26+
return new PropertiesVisitor<ExecutionContext>() {
27+
28+
@Override
29+
public Properties visitEntry(Properties.Entry entry, ExecutionContext ctx) {
30+
if (entry.getKey().matches(keyRegex)) {
31+
String value = entry.getValue().getText().trim();
32+
try {
33+
long ms = Long.parseLong(value);
34+
double seconds = ms / 1000.0;
35+
String newValue = String.valueOf(seconds);
36+
Properties.Value updatedValue = entry.getValue().withText(newValue);
37+
return entry.withValue(updatedValue);
38+
} catch (NumberFormatException e) {
39+
// If the value isn't a valid number, ignore it.
40+
}
41+
}
42+
return super.visitEntry(entry, ctx);
43+
}
44+
45+
};
46+
}
47+
48+
@Override
49+
public @NlsRewrite.DisplayName String getDisplayName() {
50+
return "Convert milliseconds to seconds for Hikari properties";
51+
}
52+
53+
@Override
54+
public @NlsRewrite.Description String getDescription() {
55+
return "Transforms millisecond values to seconds for Hikari connection pool properties matching the given regex.";
56+
}
57+
}

0 commit comments

Comments
 (0)