jhipster / generator-jhipster

JHipster is a development platform to quickly generate, develop, & deploy modern web applications & microservice architectures.
https://www.jhipster.tech
Apache License 2.0
21.56k stars 4.02k forks source link

Use of Spring Boot Parent may break spring.profiles.active #25979

Closed timothystone closed 6 months ago

timothystone commented 6 months ago
Overview of the issue

The introduction of the Spring Boot Parent POM in #25602—besides messing with side-by-side blueprints that inject a company parent—has introduced conflicting configuration expectations to the Maven Resources Plugin configuration in JHipster 8.3.0.

This appears to stem from root resources definitions introduced by the Spring Boot Parent POM (see below).

This is further complicated when you use any service discovery, e.g., Consul. This adds a boostrap.yml and bootstrap-prod.yml configuration supported by the org.springframework.cloud:spring-cloud-starter-bootstrap dependency added when choosing a Discovery type in the generation of the project.

As the bootstrap*.yml files are not scoped by the root resources definition, but scoped by JHipster's configuration the filtering takes place and the behavior of discovery bootstrapping takes precedence in the application. 😌

Motivation for or Use Case

Use of expected profiles in Maven, e.g, -P prod, fail to start the application, defaulting to dev, api-docs when not using discovery. When discovery is turned on, the behavior is masked and the application appears to behave correctly.

Note: This will generate bundles and other code for the prod profile, but the application will not start because H2 is not found (the dev profile database) with java.lang.ClassNotFoundException: org.h2.server.web.JakartaWebServlet.

Reproduce the error

Generate a common monolith with JHipster 8.3.0 (sse demo project using @mraible's 21-points).

Generate the Maven Effective POM—this is the computed POM that Maven processes, mvn -P prod help:effective-pom. Depending on your IDE it may or may not be easy to resolve how the POM was computed. NetBeans provides this annotation and you can see how and where resolution of elements happen.

Spring defines the application*.yml and application*.properties files with a "deep glob," e.g., **/applications*.yml. This pulls in the JHipster's location of config/application*.yml and thus excludes them by defintion. Yet, Spring Boot defines the Resources Plugin configuration to use the Spring @ ("commercial-at").

When the application has chosen to use Service Discovery, this configuration of resource filtering by the Spring Boot Parent is masked as the bootstrap*.yml are only scoped by JHipster's maven-resource-plugin execution configuration, e.g., config/*.yml.

In all, these conflicting definitions result in JHipster's config-resources definition being effectively ignored or incorrectly computed in the effective POM.

Related issues

See #25602 when the Spring Boot Parent POM was introduced.

Suggest a Fix

See PR #25980 for details, but in summation, edit JHipster's resources configuration deferring to Spring Boot Parent's configuration and use the native syntax, e.g., @spring...@, in the application* and bootstrap* files generated by JHipster.

Workaround:\ Correct the spring.profiles.active values to @spring.profiles.active@, i.e., specifically:

spring:
  profiles:
    active: '@spring.profiles.active@' # quote as '@' is a reserved YAML character
JHipster Version(s)

Detalls below.

JHipster configuration

Welcome to JHipster v8.3.0

21-points@0.0.1-SNAPSHOT /Users/timothystone/NetBeansProjects/21-points
└── generator-jhipster@8.3.0
JHipster configuration, a .yo-rc.json file generated in the root folder
.yo-rc.json file
{
  "generator-jhipster": {
    "applicationType": "monolith",
    "authenticationType": "jwt",
    "baseName": "21Points",
    "buildTool": "maven",
    "cacheProvider": "ehcache",
    "clientFramework": "angular",
    "clientTestFrameworks": [
      "cypress"
    ],
    "clientTheme": "none",
    "creationTimestamp": 1714179890552,
    "cypressAudit": false,
    "cypressCoverage": false,
    "databaseType": "sql",
    "devDatabaseType": "h2Disk",
    "devServerPort": 4200,
    "enableHibernateCache": true,
    "enableSwaggerCodegen": false,
    "enableTranslation": true,
    "entities": [],
    "feignClient": null,
    "jhipsterVersion": "8.3.0",
    "languages": [
      "en",
      "de"
    ],
    "messageBroker": false,
    "microfrontend": null,
    "microfrontends": [],
    "nativeLanguage": "en",
    "packageName": "com.anothercaffeinatedday.demo",
    "prodDatabaseType": "postgresql",
    "reactive": false,
    "searchEngine": "elasticsearch",
    "serverPort": null,
    "serverSideOptions": [
      "searchEngine:elasticsearch"
    ],
    "serviceDiscoveryType": false,
    "syncUserWithIdp": null,
    "testFrameworks": [
      "cypress"
    ],
    "websocket": false,
    "withAdminUi": true
  }
}
Environment and Tools

openjdk version "17.0.9" 2023-10-17 OpenJDK Runtime Environment Temurin-17.0.9+9 (build 17.0.9+9) OpenJDK 64-Bit Server VM Temurin-17.0.9+9 (build 17.0.9+9, mixed mode)

git version 2.39.3 (Apple Git-146)

node: v20.12.2 npm: 10.5.0

Docker version 26.0.0, build 2ae903e

JDL for the Entity configuration(s) entityName.json files generated in the .jhipster directory
JDL entity definitions

Browsers and Operating System
timothystone commented 6 months ago

NetBeans Effective POM "blame" annotation showing the root resources overriding the JHipster's previous behaviors:

image
mraible commented 6 months ago

@timothystone I tested JHipster 8.3.0 and 21-Points using the following technique:

gh repo clone mraible/21-points
cd 21-points
rm -rf *
jhipster
./gradlew -Pprod

The screenshot below shows the prod profile is used correctly:

Screenshot 2024-04-29 at 8 52 02 AM

If I re-create the project with Maven, there is an error on startup.

Screenshot 2024-04-29 at 8 57 22 AM

If I use your fix in #25980, both Gradle and Maven seem to work as expected.

Am I understanding things correctly that this only affects Maven projects?

mraible commented 6 months ago

@mshima While testing this, I noticed the following warning:

WARNING! liquibaseVersion is required by gradle-liquibase-plugin, make sure to add it to your dependencies
timothystone commented 6 months ago

@timothystone I tested JHipster 8.3.0 and 21-Points using the following technique:

gh repo clone mraible/21-points
cd 21-points
rm -rf *
jhipster
./gradlew -Pprod

... snip ... Am I understanding things correctly that this only affects Maven projects?

Yes, mainly a Maven issue, but Gradle does a "brute force" filtering using it.replace(string, string) in the generator. As noted in the narrative of the report, the use of the Spring Boot Parent has cause a configuration shadowing of JHipster's resource filtering in the config directory, e.g,. config/*.yml where the SBP is using "deep globbing" of src/main/resources with **/application*.yml.

The PR does two (2) things: removes JHipster's configuration of the resource plugin's delimiter element, i.e., s/\#/@/g and unfies that in the gradle EJS where it replaces the string #spring.profiles.active# with the now Spring convention form of @spring.profiles.active@, single quoted.

mraible commented 6 months ago

Thanks for the explanation, @timothystone. I appreciate it!

timothystone commented 6 months ago

@mshima While testing this, I noticed the following warning:

WARNING! liquibaseVersion is required by gradle-liquibase-plugin, make sure to add it to your dependencies

I'll admit I was focused on Maven (never really jumped on the Gradle train) and don't have a Gradle environment to play in so I didn't see this. Seems like a key oversight in the gradle.properties, am I right @mraible ?

timothystone commented 6 months ago

@mraible I should write some tests for this. 😞 All the tests passed in the release of 8.3.0 suggesting that a) either they all use -Dspring.profiles.active=... or b) there is an assumption of a discovery provider.

As I noted in the PR, when a discovery provider is provided, the bootstrap*.yml files hide this misconfiguration because the spring-cloud-starter-bootstrap dependency merges this with the application*.yml files and because the Spring Boot Parent is not concerned with the bootstrap*.yml files, the existing (prior to the PR) filtering behavior of JHipster's resources plugin configuration worked as expected.