From 7e4e3c238968f3ed5dc2b29f94f5af8f5c58a9b4 Mon Sep 17 00:00:00 2001 From: Davide Mendolia Date: Fri, 13 Feb 2026 10:48:50 +0100 Subject: [PATCH] feat(java): support postgres URI forms for DATABASE_URL --- src/java/README.md | 8 +- .../openapitools/config/DataSourceConfig.java | 36 ++++++++- .../src/main/resources/application.properties | 4 +- .../config/DataSourceConfigTest.java | 73 ++++++++++++++++++- 4 files changed, 114 insertions(+), 7 deletions(-) diff --git a/src/java/README.md b/src/java/README.md index 4eb0d61b..8d9bc299 100644 --- a/src/java/README.md +++ b/src/java/README.md @@ -168,7 +168,11 @@ Configure database connection using environment variables to enable PostgreSQL m ```bash # Required to enable PostgreSQL mode -export DATABASE_URL=jdbc:postgresql://localhost:5432/lampcontrol +# Accepted formats: jdbc:postgresql://..., postgresql://..., postgres://... +export DATABASE_URL=postgresql://localhost:5432/lampcontrol + +# Optional override (takes precedence and is used as-is without normalization) +# export SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/lampcontrol # Database credentials export DB_USER=lampuser @@ -200,7 +204,7 @@ spring.datasource.hikari.minimum-idle=5 mvn spring-boot:run # Run with PostgreSQL (requires DATABASE_URL) -DATABASE_URL=jdbc:postgresql://localhost:5432/lampcontrol \ +DATABASE_URL=postgresql://localhost:5432/lampcontrol \ FLYWAY_ENABLED=true \ DB_USER=lampuser \ DB_PASSWORD=lamppass \ diff --git a/src/java/src/main/java/org/openapitools/config/DataSourceConfig.java b/src/java/src/main/java/org/openapitools/config/DataSourceConfig.java index 17dda645..632339b6 100644 --- a/src/java/src/main/java/org/openapitools/config/DataSourceConfig.java +++ b/src/java/src/main/java/org/openapitools/config/DataSourceConfig.java @@ -22,8 +22,14 @@ @Conditional(OnDatabaseUrlCondition.class) public class DataSourceConfig { + @Value("${SPRING_DATASOURCE_URL:}") + private String springDatasourceUrl; + + @Value("${DATABASE_URL:}") + private String databaseUrl; + @Value("${spring.datasource.url}") - private String jdbcUrl; + private String fallbackJdbcUrl; @Value("${spring.datasource.username:lampuser}") private String username; @@ -45,7 +51,7 @@ public HikariConfig hikariConfig() { HikariConfig config = new HikariConfig(); // Set core JDBC properties - config.setJdbcUrl(jdbcUrl); + config.setJdbcUrl(resolveJdbcUrl()); config.setUsername(username); config.setPassword(password); config.setDriverClassName(driverClassName); @@ -53,6 +59,32 @@ public HikariConfig hikariConfig() { return config; } + private String resolveJdbcUrl() { + if (isNotBlank(springDatasourceUrl)) { + return springDatasourceUrl; + } + + if (isNotBlank(databaseUrl)) { + return normalizeDatabaseUrl(databaseUrl); + } + + return fallbackJdbcUrl; + } + + private String normalizeDatabaseUrl(String url) { + if (url.startsWith("postgresql://")) { + return "jdbc:" + url; + } + if (url.startsWith("postgres://")) { + return "jdbc:postgresql://" + url.substring("postgres://".length()); + } + return url; + } + + private boolean isNotBlank(String value) { + return value != null && !value.isBlank(); + } + /** * Creates a HikariCP DataSource bean from the configured HikariConfig. * diff --git a/src/java/src/main/resources/application.properties b/src/java/src/main/resources/application.properties index a388e4e2..e7aebdb7 100644 --- a/src/java/src/main/resources/application.properties +++ b/src/java/src/main/resources/application.properties @@ -6,7 +6,9 @@ spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false # Database Configuration (PostgreSQL) # By default, the application uses an in-memory repository # To enable PostgreSQL, set DATABASE_URL environment variable -# Example: DATABASE_URL=jdbc:postgresql://localhost:5432/lampcontrol +# DATABASE_URL supports: jdbc:postgresql://..., postgresql://..., postgres://... +# SPRING_DATASOURCE_URL is used as-is when set (no normalization) +# Example: DATABASE_URL=postgresql://localhost:5432/lampcontrol spring.datasource.url=${SPRING_DATASOURCE_URL:${DATABASE_URL:}} spring.datasource.username=${DB_USER:lampuser} spring.datasource.password=${DB_PASSWORD:lamppass} diff --git a/src/java/src/test/java/org/openapitools/config/DataSourceConfigTest.java b/src/java/src/test/java/org/openapitools/config/DataSourceConfigTest.java index 0ac8dc07..182349be 100644 --- a/src/java/src/test/java/org/openapitools/config/DataSourceConfigTest.java +++ b/src/java/src/test/java/org/openapitools/config/DataSourceConfigTest.java @@ -10,10 +10,31 @@ class DataSourceConfigTest { @Test - void hikariConfig_ShouldReturnConfiguredHikariConfig() throws Exception { + void hikariConfig_ShouldUseSpringDatasourceUrlAsIs() throws Exception { DataSourceConfig config = new DataSourceConfig(); - setField(config, "jdbcUrl", "jdbc:postgresql://localhost:5432/lamp"); + setField(config, "springDatasourceUrl", "postgresql://localhost:5432/lamp"); + setField(config, "databaseUrl", "postgres://ignored:5432/ignored"); + setField(config, "fallbackJdbcUrl", "jdbc:postgresql://localhost:5432/fallback"); + setField(config, "username", "user"); + setField(config, "password", "pass"); + setField(config, "driverClassName", "org.postgresql.Driver"); + + HikariConfig result = config.hikariConfig(); + + assertThat(result.getJdbcUrl()).isEqualTo("postgresql://localhost:5432/lamp"); + assertThat(result.getUsername()).isEqualTo("user"); + assertThat(result.getPassword()).isEqualTo("pass"); + assertThat(result.getDriverClassName()).isEqualTo("org.postgresql.Driver"); + } + + @Test + void hikariConfig_ShouldNormalizeDatabaseUrlPostgresqlScheme() throws Exception { + DataSourceConfig config = new DataSourceConfig(); + + setField(config, "springDatasourceUrl", ""); + setField(config, "databaseUrl", "postgresql://localhost:5432/lamp"); + setField(config, "fallbackJdbcUrl", "jdbc:postgresql://localhost:5432/fallback"); setField(config, "username", "user"); setField(config, "password", "pass"); setField(config, "driverClassName", "org.postgresql.Driver"); @@ -21,6 +42,54 @@ void hikariConfig_ShouldReturnConfiguredHikariConfig() throws Exception { HikariConfig result = config.hikariConfig(); assertThat(result.getJdbcUrl()).isEqualTo("jdbc:postgresql://localhost:5432/lamp"); + } + + @Test + void hikariConfig_ShouldNormalizeDatabaseUrlPostgresScheme() throws Exception { + DataSourceConfig config = new DataSourceConfig(); + + setField(config, "springDatasourceUrl", ""); + setField(config, "databaseUrl", "postgres://localhost:5432/lamp"); + setField(config, "fallbackJdbcUrl", "jdbc:postgresql://localhost:5432/fallback"); + setField(config, "username", "user"); + setField(config, "password", "pass"); + setField(config, "driverClassName", "org.postgresql.Driver"); + + HikariConfig result = config.hikariConfig(); + + assertThat(result.getJdbcUrl()).isEqualTo("jdbc:postgresql://localhost:5432/lamp"); + } + + @Test + void hikariConfig_ShouldKeepJdbcDatabaseUrlUnchanged() throws Exception { + DataSourceConfig config = new DataSourceConfig(); + + setField(config, "springDatasourceUrl", ""); + setField(config, "databaseUrl", "jdbc:postgresql://localhost:5432/lamp"); + setField(config, "fallbackJdbcUrl", "jdbc:postgresql://localhost:5432/fallback"); + setField(config, "username", "user"); + setField(config, "password", "pass"); + setField(config, "driverClassName", "org.postgresql.Driver"); + + HikariConfig result = config.hikariConfig(); + + assertThat(result.getJdbcUrl()).isEqualTo("jdbc:postgresql://localhost:5432/lamp"); + } + + @Test + void hikariConfig_ShouldFallbackToSpringDatasourceProperty() throws Exception { + DataSourceConfig config = new DataSourceConfig(); + + setField(config, "springDatasourceUrl", ""); + setField(config, "databaseUrl", ""); + setField(config, "fallbackJdbcUrl", "jdbc:postgresql://localhost:5432/fallback"); + setField(config, "username", "user"); + setField(config, "password", "pass"); + setField(config, "driverClassName", "org.postgresql.Driver"); + + HikariConfig result = config.hikariConfig(); + + assertThat(result.getJdbcUrl()).isEqualTo("jdbc:postgresql://localhost:5432/fallback"); assertThat(result.getUsername()).isEqualTo("user"); assertThat(result.getPassword()).isEqualTo("pass"); assertThat(result.getDriverClassName()).isEqualTo("org.postgresql.Driver");