diff --git a/generators/gradle/internal/needles.ts b/generators/gradle/internal/needles.ts index 68f74084aa90..4c9cff52c98c 100644 --- a/generators/gradle/internal/needles.ts +++ b/generators/gradle/internal/needles.ts @@ -47,20 +47,25 @@ const scopeSortOrder = { testRuntimeOnly: 6, }; -const wrapScope = (scope: string, dependency: string) => - `${scope}${scope === 'implementation platform' ? '(' : ' '}${dependency}${scope === 'implementation platform' ? ')' : ''}`; +const wrapScope = (scope: string, dependency: string, closure?: string[]) => { + if (closure?.length || scope === 'implementation platform') { + return `${scope}(${dependency})${closure?.length ? ` {\n${closure.join('\n')}\n}` : ''}`; + } + return `${scope} ${dependency}`; +}; const serializeDependency = (dependency: GradleDependency) => { if ('libraryName' in dependency) { - return wrapScope(dependency.scope, `libs.${gradleNameToReference(dependency.libraryName)}`); + return wrapScope(dependency.scope, `libs.${gradleNameToReference(dependency.libraryName)}`, dependency.closure); } - const { groupId, artifactId, version, classifier, scope } = dependency; + const { groupId, artifactId, version, classifier, scope, closure } = dependency; return wrapScope( scope, classifier && !version ? `group: "${groupId}", name: "${artifactId}", classifier: "${classifier}"` : `"${groupId}:${artifactId}${version ? `:${version}` : ''}${classifier ? `:${classifier}` : ''}"`, + closure, ); }; @@ -124,10 +129,10 @@ export const addGradleDependenciesCatalogVersionCallback = (versions: GradleToml contentToAdd: versions.map(({ name, version }) => `${name} = "${version}"`), }); -export const addGradleDependencyCatalogLibrariesCallback = (libraries: GradleLibraryDependency[]) => +export const addGradleDependencyCatalogLibrariesCallback = (libraries: (GradleLibraryDependency & { closure?: string[] })[]) => createNeedleCallback({ needle: 'gradle-dependency-catalog-libraries', - contentToAdd: libraries.map(({ libraryName, scope: _scope, ...others }) => + contentToAdd: libraries.map(({ libraryName, scope: _scope, closure: _closure, ...others }) => 'library' in others ? `${libraryName} = "${others.library}"` : `${libraryName} = ${tomlItemToString(others)}`, ), }); diff --git a/generators/gradle/types.d.ts b/generators/gradle/types.d.ts index af391c415c51..e8a8c97094da 100644 --- a/generators/gradle/types.d.ts +++ b/generators/gradle/types.d.ts @@ -6,9 +6,10 @@ export type GradleScript = { script: string }; export type GradleLibraryDependency = { libraryName: string; scope?: string }; -export type GradleDependency = +export type GradleDependency = ( | { groupId: string; artifactId: string; version?: string; scope: string; classifier?: string } - | Required; + | Required +) & { closure?: string[] }; export type GradlePlugin = { id: string; version?: string }; diff --git a/generators/java/generators/build-tool/generator.ts b/generators/java/generators/build-tool/generator.ts index e79b6d64e31d..bc349b9e4f09 100644 --- a/generators/java/generators/build-tool/generator.ts +++ b/generators/java/generators/build-tool/generator.ts @@ -61,30 +61,55 @@ export default class BuildToolGenerator extends BaseApplicationGenerator { prepareJavaApplication({ application, source }) { source.addJavaDependencies = (dependencies, options) => { if (application.buildToolMaven) { - const annotationProcessors = dependencies.filter(dep => dep.scope === 'annotationProcessor'); - const importDependencies = dependencies.filter(dep => dep.scope === 'import'); - const commonDependencies = dependencies.filter(dep => !['annotationProcessor', 'import'].includes(dep.scope!)); - const convertVersionToRef = ({ version, versionRef, ...artifact }: JavaDependency): MavenDependency => - version || versionRef ? { ...artifact, version: `\${${versionRef ?? artifact.artifactId}.version}` } : artifact; - const removeScope = ({ scope: _scope, ...artifact }: MavenDependency) => artifact; + const convertVersionToMavenDependency = ({ versionRef, version, exclusions, ...artifact }: JavaDependency): MavenDependency => { + // If a version is provided, convert to version ref using artifactId + versionRef ??= version ? artifact.artifactId : undefined; + version = versionRef ? `\${${versionRef}.version}` : undefined; + const additionalContent = exclusions?.length + ? `${exclusions.map( + e => ` + + ${e.groupId} + ${e.artifactId} + `, + )} + ` + : ''; + return additionalContent ? { ...artifact, version, additionalContent } : { ...artifact, version }; + }; + const removeScope = ({ scope: _scope, ...artifact }: JavaDependency) => artifact; + + const properties = dependencies + .filter(dep => dep.version) + .map(({ artifactId, version }) => ({ property: `${artifactId}.version`, value: version })); + const annotationProcessors = dependencies + .filter(dep => dep.scope === 'annotationProcessor') + .map(removeScope) + .map(convertVersionToMavenDependency); + const dependencyManagement = dependencies.filter(dep => dep.scope === 'import').map(convertVersionToMavenDependency); + const commonDependencies = dependencies + .filter(dep => !['annotationProcessor', 'import'].includes(dep.scope!)) + .map(convertVersionToMavenDependency); source.addMavenDefinition?.({ - properties: dependencies - .filter(dep => dep.version) - .map(({ artifactId, version }) => ({ property: `${artifactId}.version`, value: version })), + properties, dependencies: [ - ...commonDependencies.map(convertVersionToRef), + ...commonDependencies, // Add a provided scope for annotation processors so that version is not required in annotationProcessor dependencies ...annotationProcessors.filter(dep => !dep.version).map(artifact => ({ ...artifact, scope: 'provided' as const })), ], - dependencyManagement: importDependencies.map(convertVersionToRef), - annotationProcessors: annotationProcessors.map(convertVersionToRef).map(removeScope), + dependencyManagement, + annotationProcessors, }); } if (application.buildToolGradle) { + const gradleDependencies = dependencies.map(({ exclusions, ...dep }) => ({ + ...dep, + closure: exclusions?.map(({ groupId, artifactId }) => ` exclude group: '${groupId}', module: '${artifactId}'`), + })); source.addGradleDependencies?.( - dependencies + gradleDependencies .filter(dep => !dep.version && !dep.versionRef) .map(({ scope, type, ...artifact }) => ({ ...artifact, @@ -93,13 +118,14 @@ export default class BuildToolGenerator extends BaseApplicationGenerator { options, ); source.addGradleDependencyCatalogLibraries?.( - dependencies + gradleDependencies .filter(dep => dep.version || dep.versionRef) - .map(({ scope, type, groupId, artifactId, version, versionRef }) => { + .map(({ scope, type, groupId, artifactId, version, versionRef, closure }) => { const library = { libraryName: artifactId, module: `${groupId}:${artifactId}`, scope: javaScopeToGradleScope({ scope, type }), + closure, }; return version ? { ...library, version } : { ...library, 'version.ref': versionRef! }; }), diff --git a/generators/java/types.d.ts b/generators/java/types.d.ts index 36a27aedcd01..8358fed1c37d 100644 --- a/generators/java/types.d.ts +++ b/generators/java/types.d.ts @@ -28,7 +28,10 @@ export type JavaArtifact = { export type JavaArtifactVersion = RequireOneOrNone<{ version?: string; versionRef?: string }, 'version' | 'versionRef'>; -export type JavaDependency = JavaArtifact & JavaArtifactVersion; +export type JavaDependency = JavaArtifact & + JavaArtifactVersion & { + exclusions?: JavaArtifact[]; + }; export type JavaDefinition = { versions?: JavaDependencyVersion[]; diff --git a/generators/spring-data-relational/generator.ts b/generators/spring-data-relational/generator.ts index 2ac9a6da7587..539a5a828c92 100644 --- a/generators/spring-data-relational/generator.ts +++ b/generators/spring-data-relational/generator.ts @@ -158,7 +158,12 @@ export default class SqlGenerator extends BaseApplicationGenerator { { condition: reactive, dependencies: [ - { groupId: 'commons-beanutils', artifactId: 'commons-beanutils', version: javaDependencies['commons-beanutils'] }, + { + groupId: 'commons-beanutils', + artifactId: 'commons-beanutils', + version: javaDependencies['commons-beanutils'], + exclusions: [{ groupId: 'commons-logging', artifactId: 'commons-logging' }], + }, { groupId: 'jakarta.persistence', artifactId: 'jakarta.persistence-api' }, { groupId: 'org.springframework.boot', artifactId: 'spring-boot-starter-data-r2dbc' }, ],