diff --git a/build.gradle b/build.gradle
index b7828fba2de..379d45f67e6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -46,6 +46,7 @@ configure(allprojects) {
}
configure(subprojects) { subproject ->
+ apply plugin: MergePlugin
apply from: "${gradleScriptDir}/publish-maven.gradle"
jar {
@@ -432,10 +433,8 @@ project("spring-orm") {
project("spring-orm-hibernate4") {
description = "Spring Object/Relational Mapping - Hibernate 4 support"
- ext.mergeIntoProject = project(":spring-orm")
- apply from: "${gradleScriptDir}/merge-artifacts.gradle"
+ merge.into = project(":spring-orm")
dependencies {
- compile(project(":spring-orm").sourceSets.main.output)
compile(project(":spring-tx"))
compile(project(":spring-jdbc"))
optional("org.hibernate:hibernate-core:4.1.0.Final")
@@ -506,11 +505,9 @@ project("spring-webmvc") {
project("spring-webmvc-tiles3") {
description = "Spring Framework Tiles3 Integration"
- ext.mergeIntoProject = project(":spring-webmvc")
- apply from: "${gradleScriptDir}/merge-artifacts.gradle"
+ merge.into = project(":spring-webmvc")
dependencies {
compile(project(":spring-context"))
- compile(project(":spring-webmvc").sourceSets.main.output)
provided("javax.el:el-api:1.0")
provided("javax.servlet:jstl:1.2")
provided("javax.servlet.jsp:jsp-api:2.1")
@@ -581,13 +578,10 @@ project("spring-test") {
project("spring-test-mvc") {
description = "Spring Test MVC Framework"
- ext.mergeIntoProject = project(":spring-test")
- apply from: "${gradleScriptDir}/merge-artifacts.gradle"
- apply from: "ide.gradle"
+ merge.into = project(":spring-test")
dependencies {
optional(project(":spring-context"))
compile(project(":spring-webmvc"))
- compile(project(":spring-test").sourceSets.main.output)
provided("javax.servlet:javax.servlet-api:3.0.1")
optional("org.hamcrest:hamcrest-core:1.3")
optional("com.jayway.jsonpath:json-path:0.8.1")
@@ -663,6 +657,7 @@ configure(rootProject) {
description = "Spring Framework"
apply plugin: "docbook-reference"
+ apply plugin: "groovy"
apply from: "${gradleScriptDir}/jdiff.gradle"
reference {
@@ -674,6 +669,8 @@ configure(rootProject) {
configurations.archives.artifacts.clear()
dependencies { // for integration tests
+ compile gradleApi()
+ groovy localGroovy()
testCompile(project(":spring-core"))
testCompile(project(":spring-beans"))
testCompile(project(":spring-aop"))
diff --git a/buildsrc/src/main/groovy/MergePlugin.groovy b/buildsrc/src/main/groovy/MergePlugin.groovy
new file mode 100644
index 00000000000..2f49938c053
--- /dev/null
+++ b/buildsrc/src/main/groovy/MergePlugin.groovy
@@ -0,0 +1,130 @@
+import org.gradle.api.*
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.artifacts.ProjectDependency;
+import org.gradle.api.artifacts.maven.Conf2ScopeMapping
+import org.gradle.api.plugins.MavenPlugin
+import org.gradle.api.tasks.*
+import org.gradle.plugins.ide.eclipse.EclipsePlugin
+import org.gradle.plugins.ide.eclipse.model.EclipseClasspath;
+import org.gradle.plugins.ide.idea.IdeaPlugin
+import org.gradle.api.invocation.*
+
+/**
+ * Gradle plugin that allows projects to merged together. Primarily developed to
+ * allow Spring to support multiple multiple incompatible versions of third-party
+ * dependencies (for example Hibernate v3 and v4).
+ *
+ * The 'merge' extension should be used to define how projects are merged, for example:
+ *
+ * configure(subprojects) {
+ * apply plugin: MergePlugin
+ * }
+ *
+ * project("myproject") {
+ * }
+ *
+ * project("myproject-extra") {
+ * merge.into = project("myproject")
+ * }
+ *
+ *
+ * This plugin adds two new configurations:
+ *
+ * - merging - Contains the projects being merged into this project
-
+ *
- runtimeMerge - Contains all dependencies that are merge projects. These are used
+ * to allow an IDE to reference merge projects.
+ *
+ *
+ * @author Rob Winch
+ * @author Phillip Webb
+ */
+class MergePlugin implements Plugin {
+
+ private static boolean attachedProjectsEvaluated;
+
+ public void apply(Project project) {
+ project.plugins.apply(MavenPlugin)
+ project.plugins.apply(EclipsePlugin)
+ project.plugins.apply(IdeaPlugin)
+
+ MergeModel model = project.extensions.create("merge", MergeModel)
+ project.configurations.add("merging")
+ Configuration runtimeMerge = project.configurations.add("runtimeMerge")
+
+ // Ensure the IDE can reference merged projects
+ project.eclipse.classpath.plusConfigurations += [runtimeMerge]
+ project.idea.module.scopes.PROVIDED.plus += runtimeMerge
+
+ // Hook to perform the actual merge logic
+ project.afterEvaluate{
+ if(it.merge.into != null) {
+ setup(it)
+ }
+ }
+
+ // Hook to build runtimeMerge dependencies
+ if(!attachedProjectsEvaluated) {
+ project.gradle.projectsEvaluated{
+ postProcessProjects(it)
+ }
+ attachedProjectsEvaluated = true;
+ }
+ }
+
+ private void setup(Project project) {
+ project.merge.into.dependencies.add("merging", project)
+ project.dependencies.add("provided", project.merge.into.sourceSets.main.output)
+ project.dependencies.add("runtimeMerge", project.merge.into)
+ setupTaskDependencies(project)
+ setupMaven(project)
+ }
+
+ private void setupTaskDependencies(Project project) {
+ // invoking a task will invoke the task with the same name on 'into' project
+ ["sourcesJar", "jar", "javadocJar", "javadoc", "install", "artifactoryPublish"].each {
+ def task = project.tasks.findByPath(it)
+ if(task) {
+ task.enabled = false
+ task.dependsOn(project.merge.into.tasks.findByPath(it))
+ }
+ }
+
+ // update 'into' project artifacts to contain the source artifact contents
+ project.merge.into.sourcesJar.from(project.sourcesJar.source)
+ project.merge.into.jar.from(project.jar.source)
+ project.merge.into.javadoc {
+ source += project.javadoc.source
+ classpath += project.javadoc.classpath
+ }
+ }
+
+ private void setupMaven(Project project) {
+ project.configurations.each { configuration ->
+ Conf2ScopeMapping mapping = project.conf2ScopeMappings.getMapping([configuration])
+ if(mapping.scope) {
+ Configuration intoConfiguration = project.merge.into.configurations.add(
+ project.name + "-" + configuration.name)
+ intoConfiguration.dependencies.addAll(configuration.dependencies)
+ project.merge.into.install.repositories.mavenInstaller.pom.scopeMappings.addMapping(
+ mapping.priority + 100, intoConfiguration, mapping.scope)
+ }
+ }
+ }
+
+ private postProcessProjects(Gradle gradle) {
+ gradle.allprojects(new Action() {
+ public void execute(Project project) {
+ project.configurations.getByName("runtime").allDependencies.withType(ProjectDependency).each{
+ Configuration dependsOnMergedFrom = it.dependencyProject.configurations.getByName("merging");
+ dependsOnMergedFrom.dependencies.each{ dep ->
+ project.dependencies.add("runtimeMerge", dep.dependencyProject)
+ }
+ }
+ }
+ });
+ }
+}
+
+class MergeModel {
+ Project into;
+}
diff --git a/gradle/merge-artifacts.gradle b/gradle/merge-artifacts.gradle
deleted file mode 100644
index 5f139c593a8..00000000000
--- a/gradle/merge-artifacts.gradle
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * Will merge the artifacts of the current project into mergeIntoProject. For example, to
- * bundle spring-test-mvc in spring-test"s jars. This script will perform the following
- * steps:
- *
- * - Ensure that jar tasks of the project being merged from will execute the tasks of the
- * project being merged into
- *
- * - Add the project being merged into to the classpath of the project being merged from
- *
- * - Update the pom.xml of the project being merged into to contain the entries from the
- * project being merged from
- *
- * Example Usage:
- *
- * ext.mergeIntoProject = project(":spring-test")
- * apply from: "${rootProject.projectDir}/gradle/merge-artifacts.gradle"
- */
-
-def mergeFromProject = project
-
-// invoking a task on mergeFromProject will invoke the task with the same name on mergeIntoProject
-def taskNamesToMerge = ["sourcesJar","jar","javadocJar","javadoc","install","artifactoryPublish"]
-taskNamesToMerge.each { taskName ->
- def taskToRemove = mergeFromProject.tasks.findByPath(taskName)
- if(taskToRemove) {
- taskToRemove.enabled = false
- taskToRemove.dependsOn mergeIntoProject."$taskName"
- }
-}
-
-// update mergeIntoProject artifacts to contain the mergeFromProject artifact contents
-mergeIntoProject."sourcesJar" {
- from mergeFromProject.sourcesJar.source
-}
-mergeIntoProject."jar" {
- from mergeFromProject.jar.source
-}
-mergeIntoProject."javadoc" {
- source += mergeFromProject.javadoc.source
- classpath += mergeFromProject.javadoc.classpath
-}
-
-// Update mergeIntoProject to contain additional configurations that contains all the dependencies from mergeFromProject
-// so that Maven pom generation works
-gradle.taskGraph.whenReady {
- mergeFromProject.configurations.archives.artifacts.clear()
-
- mergeFromProject.configurations.each { config->
- def mapping = mergeFromProject.conf2ScopeMappings.getMapping([config])
- if(mapping.scope) {
- def newConfigName = mergeFromProject.name + "-"+ config.name
- mergeIntoProject.configurations.add(newConfigName)
- config.dependencies.each { dependency ->
- mergeIntoProject.dependencies.add(newConfigName, dependency)
- }
- configure(mergeIntoProject.install.repositories.mavenInstaller.pom.scopeMappings) {
- addMapping(mapping.priority + 100, mergeIntoProject.configurations."$newConfigName", mapping.scope)
- }
- }
- }
-}
diff --git a/spring-test-mvc/ide.gradle b/spring-test-mvc/ide.gradle
deleted file mode 100644
index 3410525b775..00000000000
--- a/spring-test-mvc/ide.gradle
+++ /dev/null
@@ -1,7 +0,0 @@
-import org.gradle.plugins.ide.eclipse.model.ProjectDependency
-
-// SPR-10042
-eclipse.classpath.file.whenMerged { classpath ->
- def projectName = "spring-webmvc-tiles3"
- classpath.entries.add(0, new ProjectDependency("/${projectName}", project(":${projectName}").path))
-}