diff --git a/generators/gradle/generator.ts b/generators/gradle/generator.ts index e0ae4e8da262..5cba88b3c886 100644 --- a/generators/gradle/generator.ts +++ b/generators/gradle/generator.ts @@ -28,7 +28,7 @@ import { GRADLE_BUILD_SRC_DIR } from '../generator-constants.js'; import cleanupOldServerFilesTask from './cleanup.js'; import { applyFromGradleCallback, - addGradleDependencyCallback, + addGradleDependenciesCallback, addGradleMavenRepositoryCallback, addGradlePluginCallback, addGradlePluginManagementCallback, @@ -76,7 +76,8 @@ export default class GradleGenerator extends BaseApplicationGenerator { }, addSourceNeddles({ source }) { source.applyFromGradle = script => this.editFile('build.gradle', applyFromGradleCallback(script)); - source.addGradleDependency = dependency => this.editFile('build.gradle', addGradleDependencyCallback(dependency)); + source.addGradleDependency = dependency => this.editFile('build.gradle', addGradleDependenciesCallback([dependency])); + source.addGradleDependencies = dependencies => this.editFile('build.gradle', addGradleDependenciesCallback(dependencies)); source.addGradlePlugin = plugin => this.editFile('build.gradle', addGradlePluginCallback(plugin)); source.addGradleMavenRepository = repository => this.editFile('build.gradle', addGradleMavenRepositoryCallback(repository)); source.addGradlePluginManagement = plugin => this.editFile('settings.gradle', addGradlePluginManagementCallback(plugin)); diff --git a/generators/gradle/internal/needles.ts b/generators/gradle/internal/needles.ts index c38863c35616..08e0c3c4c250 100644 --- a/generators/gradle/internal/needles.ts +++ b/generators/gradle/internal/needles.ts @@ -42,10 +42,12 @@ export const applyFromGradleCallback = ({ script }: GradleScript) => contentToAdd: `apply from: "${script}"`, }); -export const addGradleDependencyCallback = ({ groupId, artifactId, version, scope }: GradleDependency) => +export const addGradleDependenciesCallback = (dependencies: GradleDependency[]) => createNeedleCallback({ needle: 'gradle-dependency', - contentToAdd: `${scope} "${groupId}:${artifactId}${version ? `:${version}` : ''}"`, + contentToAdd: dependencies.map( + ({ groupId, artifactId, version, scope }) => `${scope} "${groupId}:${artifactId}${version ? `:${version}` : ''}"`, + ), }); export const addGradleBuildSrcDependencyCallback = ({ groupId, artifactId, version, scope }: GradleDependency) => diff --git a/generators/gradle/types.d.ts b/generators/gradle/types.d.ts index 5be132f4452f..ba13865eee71 100644 --- a/generators/gradle/types.d.ts +++ b/generators/gradle/types.d.ts @@ -27,6 +27,7 @@ export type GradleTomlPlugin = { pluginName: string; addToBuild?: boolean } & ( export type GradleSourceType = { applyFromGradle?(script: GradleScript): void; addGradleDependency?(dependency: GradleDependency): void; + addGradleDependencies?(dependency: GradleDependency[]): void; addGradlePlugin?(plugin: GradlePlugin): void; addGradlePluginManagement?(pluginManagement: GradlePlugin): void; addGradleProperty?(property: GradleProperty): void; diff --git a/generators/java/generator.ts b/generators/java/generator.ts index 73a65c1f2603..6acd2d4896d3 100644 --- a/generators/java/generator.ts +++ b/generators/java/generator.ts @@ -22,10 +22,13 @@ import BaseApplicationGenerator from '../base-application/index.js'; import { GENERATOR_JAVA, GENERATOR_BOOTSTRAP_APPLICATION } from '../generator-list.js'; import writeTask from './files.js'; import cleanupTask from './cleanup.js'; -import { packageInfoTransform, generatedAnnotationTransform, checkJava, isReservedJavaKeyword } from './support/index.js'; -import { JavaApplication } from './types.js'; -import { BaseApplicationGeneratorDefinition, GenericApplicationDefinition } from '../base-application/tasks.js'; -import { GenericSourceTypeDefinition } from '../base/tasks.js'; +import { + packageInfoTransform, + generatedAnnotationTransform, + checkJava, + isReservedJavaKeyword, + mavenScopeToGradleScope, +} from './support/index.js'; import command from './command.js'; import { JAVA_COMPATIBLE_VERSIONS } from '../generator-constants.js'; import { matchMainJavaFiles } from './support/package-info-transform.js'; @@ -34,10 +37,7 @@ import { getEnumInfo } from '../base-application/support/index.js'; import { mutateData } from '../base/support/index.js'; import { javaBeanCase } from '../server/support/index.js'; -export type ApplicationDefinition = GenericApplicationDefinition; -export type GeneratorDefinition = BaseApplicationGeneratorDefinition; - -export default class JavaGenerator extends BaseApplicationGenerator { +export default class JavaGenerator extends BaseApplicationGenerator { packageInfoFile!: boolean; generateEntities!: boolean; useJakartaValidation!: boolean; @@ -88,6 +88,71 @@ export default class JavaGenerator extends BaseApplicationGenerator this.configuring)); } + get preparing() { + return this.asPreparingTaskGroup({ + prepareJavaApplication({ application, source }) { + source.addJavaDependencies = dependencies => { + if (application.buildToolMaven) { + const unversionedAnnotationProcessors = dependencies.filter(dep => !dep.version && dep.scope === 'annotationProcessor'); + const versionedAnnotationProcessors = dependencies.filter(dep => dep.version && dep.scope === 'annotationProcessor'); + const unversionedCommonDependencies = dependencies.filter(dep => !dep.version && dep.scope !== 'annotationProcessor'); + const versionedCommonDependencies = dependencies.filter(dep => dep.version && dep.scope !== 'annotationProcessor'); + + source.addMavenDefinition?.({ + properties: [ + ...versionedCommonDependencies.map(({ artifactId, version }) => ({ property: `${artifactId}.version`, value: version })), + ...versionedAnnotationProcessors.map(({ artifactId, version }) => ({ property: `${artifactId}.version`, value: version })), + ], + dependencies: [ + ...unversionedCommonDependencies, + ...versionedCommonDependencies.map(({ version: _version, artifactId, ...artifact }) => ({ + ...artifact, + artifactId, + version: `\${${artifactId}.version}`, + })), + // Add a provided scope for annotation processors so that version is not required in annotationProcessor dependencies + ...unversionedAnnotationProcessors.map(({ scope: _scope, ...artifact }) => ({ ...artifact, scope: 'provided' })), + ], + annotationProcessors: [ + ...unversionedAnnotationProcessors.map(({ scope: _scope, ...artifact }) => ({ ...artifact })), + ...versionedAnnotationProcessors.map(({ version: _version, artifactId, ...artifact }) => ({ + ...artifact, + artifactId, + version: `\${${artifactId}.version}`, + })), + ], + }); + } + + if (application.buildToolGradle) { + source.addGradleDependencies?.([ + ...dependencies + .filter(dep => !dep.version) + .map(({ scope, type, ...artifact }) => ({ + ...artifact, + scope: mavenScopeToGradleScope({ scope, type }), + })), + ]); + source.addGradleDependencyCatalogLibraries?.([ + ...dependencies + .filter(dep => dep.version) + .map(({ scope, type, groupId, artifactId, version }) => ({ + libraryName: artifactId, + module: `${groupId}:${artifactId}`, + version: version!, + scope: mavenScopeToGradleScope({ scope, type }), + })), + ]); + } + }; + }, + }); + } + + get [BaseApplicationGenerator.PREPARING]() { + return this.delegateTasksToBlueprint(() => this.preparing); + } + get preparingEachEntity() { return this.asPreparingEachEntityTaskGroup({ prepareEntity({ entity }) { @@ -161,7 +226,7 @@ export default class JavaGenerator extends BaseApplicationGenerator [doc.packageName, doc.documentation])), + ...Object.fromEntries(application.packageInfoJavadocs!.map(doc => [doc.packageName, doc.documentation])), [`${application.packageName}`]: 'Application root.', [`${application.packageName}.config`]: 'Application configuration.', [`${application.packageName}.domain`]: 'Domain objects.', diff --git a/generators/java/support/artifacts.ts b/generators/java/support/artifacts.ts new file mode 100644 index 000000000000..e020c7d97572 --- /dev/null +++ b/generators/java/support/artifacts.ts @@ -0,0 +1,30 @@ +import { JavaArtifactType } from '../types.js'; + +export const mavenScopeToGradleScope = (artifactType: JavaArtifactType): string => { + const { scope = 'compile', type = 'jar' } = artifactType; + if (type === 'pom') { + if (scope === 'import') { + return 'implementation platform'; + } + throw new Error(`Unsupported scope for POM artifact: ${scope}`); + } + if (type === 'jar') { + switch (scope) { + case 'compile': + return 'implementation'; + case 'provided': + return 'compileOnly'; + case 'runtime': + return 'runtimeOnly'; + case 'test': + return 'testImplementation'; + case 'system': + return 'system'; + case 'annotationProcessor': + return 'annotationProcessor'; + default: + throw new Error(`Unsupported scope for JAR artifact: ${scope}`); + } + } + throw new Error(`Unsupported type: ${type}`); +}; diff --git a/generators/java/support/index.ts b/generators/java/support/index.ts index 01d74d326c24..d88d7e58b96c 100644 --- a/generators/java/support/index.ts +++ b/generators/java/support/index.ts @@ -17,6 +17,7 @@ * limitations under the License. */ export { default as addJavaAnnotation } from './add-java-annotation.js'; +export * from './artifacts.js'; export * from './checks/index.js'; export * from './doc.js'; export * from './files.js'; diff --git a/generators/java/types.d.ts b/generators/java/types.d.ts index d465846e027f..784fae2e5ab6 100644 --- a/generators/java/types.d.ts +++ b/generators/java/types.d.ts @@ -1,5 +1,16 @@ import { BaseApplication } from '../base-application/types.js'; +export type JavaArtifactType = { + type?: 'jar' | 'pom'; + scope?: 'compile' | 'provided' | 'runtime' | 'test' | 'system' | 'import' | 'annotationProcessor'; +}; + +export type JavaArtifact = { + groupId: string; + artifactId: string; + version?: string; +} & JavaArtifactType; + export type JavaApplication = BaseApplication & { javaVersion: string; @@ -25,3 +36,7 @@ export type JavaApplication = BaseApplication & { imperativeOrReactive: string; }; + +export type JavaSourceType = { + addJavaDependencies?(dependency: JavaArtifact[]): void; +}; diff --git a/generators/maven/types.d.ts b/generators/maven/types.d.ts index d77ef3aac0cb..8435c7f3ebf0 100644 --- a/generators/maven/types.d.ts +++ b/generators/maven/types.d.ts @@ -24,7 +24,7 @@ export type MavenArtifact = { inProfile?: string; }; -export type MavenAnnotationProcessor = MavenArtifact & Required>; +export type MavenAnnotationProcessor = MavenArtifact; export type MavenPlugin = MavenArtifact & { additionalContent?: string; diff --git a/generators/server/templates/build.gradle.ejs b/generators/server/templates/build.gradle.ejs index 9f2116e36093..85f46c6dc86a 100644 --- a/generators/server/templates/build.gradle.ejs +++ b/generators/server/templates/build.gradle.ejs @@ -163,15 +163,12 @@ repositories { } dependencies { + // Allows unversioned annotationProcessor + annotationProcessor platform("tech.jhipster:jhipster-dependencies:<%- jhipsterDependenciesVersion %>") + <%_ if (databaseTypeCouchbase) { _%> implementation "com.couchbase.client:java-client" <%_ } _%> -<%_ if (databaseTypeCassandra) { _%> - annotationProcessor "com.datastax.oss:java-driver-mapper-processor:${cassandraDriverVersion}" -<%_ } _%> -<%_ if (databaseTypeCassandra) { _%> - implementation "com.datastax.oss:java-driver-mapper-runtime" -<%_ } _%> <%_ if (databaseTypeSql && !reactive) { _%> implementation "com.fasterxml.jackson.datatype:jackson-datatype-hibernate6" <%_ } _%> @@ -207,7 +204,7 @@ dependencies { <%_ if (databaseTypeSql && reactive) { _%> implementation "commons-beanutils:commons-beanutils:${commonsBeanutilsVersion}" <%_ } _%> -<%_ if (databaseTypeCassandra || databaseTypeCouchbase) { _%> +<%_ if (databaseTypeCouchbase) { _%> implementation "commons-codec:commons-codec" <%_ } _%> <%_ if (databaseTypeNeo4j && !databaseMigrationLiquibase) { _%> @@ -251,9 +248,6 @@ dependencies { <%_ } _%> <%_ if (reactive) { _%> testRuntimeOnly 'org.junit.platform:junit-platform-launcher:${junitPlatformLauncherVersion}' -<%_ } _%> -<%_ if (databaseTypeCassandra) { _%> - implementation "org.lz4:lz4-java" <%_ } _%> annotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}" implementation "org.mapstruct:mapstruct:${mapstructVersion}" @@ -272,7 +266,7 @@ if (addSpringMilestoneRepository) { _%> runtimeOnly "org.springframework.boot:spring-boot-properties-migrator" <%_ } _%> implementation "org.springframework.boot:spring-boot-starter-actuator" -<%_ if (databaseTypeMongodb || databaseTypeCassandra || databaseTypeCouchbase) { _%> +<%_ if (databaseTypeMongodb || databaseTypeCouchbase) { _%> implementation "org.springframework.boot:spring-boot-starter-data-<%= databaseType %><% if (reactive) { %>-reactive<% } %>" <%_ } _%> <%_ if (searchEngineElasticsearch) { _%> @@ -355,9 +349,6 @@ if (addSpringMilestoneRepository) { _%> implementation "org.springframework.security:spring-security-messaging" <%_ } _%> testImplementation "org.springframework.security:spring-security-test" -<%_ if (databaseTypeCassandra) { _%> - testImplementation "org.testcontainers:cassandra" -<%_ } _%> <%_ if (databaseTypeCouchbase) { _%> testImplementation "org.testcontainers:couchbase" <%_ } _%> @@ -367,7 +358,7 @@ if (addSpringMilestoneRepository) { _%> <%_ if (databaseTypeSql) { _%> testImplementation "org.testcontainers:jdbc" <%_ } _%> -<%_ if (databaseTypeMongodb || databaseTypeCouchbase || databaseTypeNeo4j || databaseTypeCassandra || searchEngineElasticsearch || databaseTypeSql) { _%> +<%_ if (databaseTypeMongodb || databaseTypeCouchbase || databaseTypeNeo4j || searchEngineElasticsearch || databaseTypeSql) { _%> testImplementation "org.testcontainers:junit-jupiter" <%_ } _%> <%_ if (databaseTypeMongodb) { _%> @@ -376,7 +367,7 @@ if (addSpringMilestoneRepository) { _%> <%_ if (databaseTypeNeo4j) { _%> testImplementation "org.testcontainers:neo4j" <%_ } _%> -<%_ if (databaseTypeMongodb || databaseTypeCouchbase || databaseTypeNeo4j || databaseTypeCassandra || searchEngineElasticsearch || databaseTypeSql) { _%> +<%_ if (databaseTypeMongodb || databaseTypeCouchbase || databaseTypeNeo4j || searchEngineElasticsearch || databaseTypeSql) { _%> testImplementation "org.testcontainers:testcontainers" <%_ } _%> <%_ if (reactive) { _%> diff --git a/generators/server/templates/gradle.properties.ejs b/generators/server/templates/gradle.properties.ejs index 1a636c053c54..c7827e34c296 100644 --- a/generators/server/templates/gradle.properties.ejs +++ b/generators/server/templates/gradle.properties.ejs @@ -34,18 +34,11 @@ jacksonDatabindNullableVersion=<%- javaDependencies['jackson-databind-nullable'] <%_ if (databaseTypeSql && reactive) { _%> commonsBeanutilsVersion=<%- javaDependencies['commons-beanutils'] %> <%_ } _%> - <%_ if (reactive) { _%> blockhoundJunitPlatformVersion=<%- javaDependencies['blockhound-junit-platform'] %> junitPlatformLauncherVersion=<%- javaDependencies['junit-platform-launcher'] %> <%_ } _%> -<%_ if (databaseTypeCassandra) { _%> -# The cassandra driver version should match the one managed by -# https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies/<%- javaDependencies['spring-boot'] %> -cassandraDriverVersion=<%- springBootDependencies['cassandra-driver'] %> -<%_ } _%> - # gradle plugin version jibPluginVersion=<%- javaDependencies['jib-maven-plugin'] %> gitPropertiesPluginVersion=<%- javaDependencies['gradle-git-properties'] %> diff --git a/generators/server/types.d.ts b/generators/server/types.d.ts index 5513dd483152..0b8412631f7f 100644 --- a/generators/server/types.d.ts +++ b/generators/server/types.d.ts @@ -1,4 +1,4 @@ -import { JavaApplication } from '../java/types.js'; +import { JavaApplication, JavaSourceType } from '../java/types.js'; import { GradleSourceType } from '../gradle/types.js'; import { MavenSourceType } from '../maven/types.js'; import { LiquibaseSourceType } from '../liquibase/types.js'; @@ -19,7 +19,8 @@ export type SpringEntity = { skipJunitTests?: string; }; -export type SpringBootSourceType = GradleSourceType & +export type SpringBootSourceType = JavaSourceType & + GradleSourceType & MavenSourceType & SpringCacheSourceType & LiquibaseSourceType & { diff --git a/generators/spring-data-cassandra/generator.js b/generators/spring-data-cassandra/generator.js index 792a88ca3fdb..876b12135078 100644 --- a/generators/spring-data-cassandra/generator.js +++ b/generators/spring-data-cassandra/generator.js @@ -89,53 +89,18 @@ export default class CassandraGenerator extends BaseApplicationGenerator { }, addDependencies({ application, source }) { const { reactive } = application; - if (application.buildToolMaven) { - source.addMavenProperty?.({ - property: 'cassandra-driver.version', - value: application.springBootDependencies['cassandra-driver'], - }); - source.addMavenAnnotationProcessor?.({ - groupId: 'com.datastax.oss', - artifactId: 'java-driver-mapper-processor', - // eslint-disable-next-line no-template-curly-in-string - version: '${cassandra-driver.version}', - }); - - source.addMavenDependency?.([ - { - groupId: 'com.datastax.oss', - artifactId: 'java-driver-mapper-runtime', - }, - { - groupId: 'commons-codec', - artifactId: 'commons-codec', - }, - { - groupId: 'org.lz4', - artifactId: 'lz4-java', - }, - { - groupId: 'org.springframework.boot', - artifactId: `spring-boot-starter-data-cassandra${reactive ? '-reactive' : ''}`, - }, - { - groupId: 'org.testcontainers', - artifactId: 'junit-jupiter', - scope: 'test', - }, - { - groupId: 'org.testcontainers', - artifactId: 'testcontainers', - scope: 'test', - }, - { - groupId: 'org.testcontainers', - artifactId: 'cassandra', - scope: 'test', - }, - ]); - } + const cassandraStarter = reactive ? 'spring-boot-starter-data-cassandra-reactive' : 'spring-boot-starter-data-cassandra'; + source.addJavaDependencies?.([ + { groupId: 'com.datastax.oss', artifactId: 'java-driver-mapper-runtime' }, + { groupId: 'commons-codec', artifactId: 'commons-codec' }, + { groupId: 'org.springframework.boot', artifactId: cassandraStarter }, + { groupId: 'org.lz4', artifactId: 'lz4-java' }, + { scope: 'test', groupId: 'org.testcontainers', artifactId: 'junit-jupiter' }, + { scope: 'test', groupId: 'org.testcontainers', artifactId: 'testcontainers' }, + { scope: 'test', groupId: 'org.testcontainers', artifactId: 'cassandra' }, + { scope: 'annotationProcessor', groupId: 'com.datastax.oss', artifactId: 'java-driver-mapper-processor' }, + ]); }, }); }