diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/dependencies/ManagedDependenciesArtifactCoordinatesResolver.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/dependencies/ManagedDependenciesArtifactCoordinatesResolver.java index 5903a4f40f..5b3243222a 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/dependencies/ManagedDependenciesArtifactCoordinatesResolver.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/dependencies/ManagedDependenciesArtifactCoordinatesResolver.java @@ -18,6 +18,7 @@ package org.springframework.boot.cli.compiler.dependencies; import org.springframework.boot.dependency.tools.Dependency; import org.springframework.boot.dependency.tools.ManagedDependencies; +import org.springframework.boot.dependency.tools.VersionManagedDependencies; /** * {@link ArtifactCoordinatesResolver} backed by {@link ManagedDependencies}. @@ -30,7 +31,7 @@ public class ManagedDependenciesArtifactCoordinatesResolver implements private final ManagedDependencies dependencies; public ManagedDependenciesArtifactCoordinatesResolver() { - this(ManagedDependencies.get()); + this(new VersionManagedDependencies()); } ManagedDependenciesArtifactCoordinatesResolver(ManagedDependencies dependencies) { @@ -53,7 +54,7 @@ public class ManagedDependenciesArtifactCoordinatesResolver implements if (artifactId != null) { if (artifactId.startsWith("spring-boot")) { return new Dependency("org.springframework.boot", artifactId, - this.dependencies.getVersion()); + this.dependencies.getSpringBootVersion()); } return this.dependencies.find(artifactId); } diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/ManagedDependenciesFactory.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/ManagedDependenciesFactory.java index 546e737747..e7c9c41a88 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/ManagedDependenciesFactory.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/ManagedDependenciesFactory.java @@ -24,10 +24,12 @@ import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.util.artifact.JavaScopes; import org.springframework.boot.dependency.tools.ManagedDependencies; +import org.springframework.boot.dependency.tools.PomManagedDependencies; +import org.springframework.boot.dependency.tools.VersionManagedDependencies; /** * Factory to create Maven {@link Dependency} objects from Boot - * {@link ManagedDependencies}. + * {@link PomManagedDependencies}. * * @author Phillip Webb */ @@ -36,7 +38,7 @@ public class ManagedDependenciesFactory { private final ManagedDependencies dependencies; ManagedDependenciesFactory() { - this(ManagedDependencies.get()); + this(new VersionManagedDependencies()); } ManagedDependenciesFactory(ManagedDependencies dependencies) { diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/dependencies/ManagedDependenciesArtifactCoordinatesResolverTests.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/dependencies/ManagedDependenciesArtifactCoordinatesResolverTests.java index 7dc472355a..830138b7c5 100644 --- a/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/dependencies/ManagedDependenciesArtifactCoordinatesResolverTests.java +++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/dependencies/ManagedDependenciesArtifactCoordinatesResolverTests.java @@ -45,7 +45,7 @@ public class ManagedDependenciesArtifactCoordinatesResolverTests { public void setup() { this.dependencies = mock(ManagedDependencies.class); given(this.dependencies.find("a1")).willReturn(new Dependency("g1", "a1", "0")); - given(this.dependencies.getVersion()).willReturn("1"); + given(this.dependencies.getSpringBootVersion()).willReturn("1"); this.resolver = new ManagedDependenciesArtifactCoordinatesResolver( this.dependencies); } diff --git a/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc b/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc index aa0106522a..7aad4a0d58 100644 --- a/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc +++ b/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc @@ -225,6 +225,33 @@ actual Spring Boot version that you wish to use. +[[build-tool-plugins-gradle-custom-version-management]] +==== Custom version management +If is possible to customize the versions used by the `ResolutionStrategy` if you need +to deviate from Spring Boot's ``blessed'' dependencies. Alternative version meta-data +is consulted using the `versionManagement` configuration. For example: + +[source,groovy,indent=0,subs="verbatim,attributes"] +---- + dependencies { + versionManagement("com.mycorp:mycorp-versions:1.0.0.RELEASE@properties") + compile("org.springframework.data:spring-data-hadoop") + } +---- + +Version information needs to be published to a repository as a `.properties` file. For +the above example `mycorp-versions.properties` file might contain the following: + +[source,properties,indent=0,subs="verbatim,attributes"] +---- + org.springframework.data\:spring-data-hadoop=2.0.0.RELEASE +---- + +The properties file takes precedence over Spring Boot's defaults, and can be used +to override version numbers if necessary. + + + [[build-tool-plugins-gradle-packaging]] === Packaging executable jar and war files Once the `spring-boot` plugin has been applied to your project it will automatically diff --git a/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/AbstractManagedDependencies.java b/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/AbstractManagedDependencies.java new file mode 100644 index 0000000000..099adbcbda --- /dev/null +++ b/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/AbstractManagedDependencies.java @@ -0,0 +1,115 @@ +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.dependency.tools; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Abstract base implementation for {@link ManagedDependencies}. + * + * @author Phillip Webb + * @since 1.1.0 + */ +abstract class AbstractManagedDependencies implements ManagedDependencies { + + private final Map byArtifactAndGroupId; + + private final Map byArtifactId; + + public AbstractManagedDependencies() { + this.byArtifactAndGroupId = new LinkedHashMap(); + this.byArtifactId = new LinkedHashMap(); + } + + @Override + public Dependency find(String groupId, String artifactId) { + return this.byArtifactAndGroupId.get(new ArtifactAndGroupId(groupId, artifactId)); + } + + @Override + public Dependency find(String artifactId) { + return this.byArtifactId.get(artifactId); + } + + @Override + public Iterator iterator() { + return this.byArtifactAndGroupId.values().iterator(); + } + + @Override + public String getSpringBootVersion() { + Dependency dependency = find("org.springframework.boot", "spring-boot"); + return (dependency == null ? null : dependency.getVersion()); + } + + protected void add(ArtifactAndGroupId artifactAndGroupId, Dependency dependency) { + this.byArtifactAndGroupId.put(artifactAndGroupId, dependency); + this.byArtifactId.put(dependency.getArtifactId(), dependency); + } + + /** + * Simple holder for an artifact+group ID. + */ + protected static class ArtifactAndGroupId { + + private final String groupId; + + private final String artifactId; + + public ArtifactAndGroupId(Dependency dependency) { + this(dependency.getGroupId(), dependency.getArtifactId()); + } + + public ArtifactAndGroupId(String groupId, String artifactId) { + Assert.notNull(groupId, "GroupId must not be null"); + Assert.notNull(artifactId, "ArtifactId must not be null"); + this.groupId = groupId; + this.artifactId = artifactId; + } + + public Dependency newDependency(String version) { + return new Dependency(this.groupId, this.artifactId, version); + } + + @Override + public int hashCode() { + return this.groupId.hashCode() * 31 + this.artifactId.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() == obj.getClass()) { + ArtifactAndGroupId other = (ArtifactAndGroupId) obj; + boolean result = true; + result &= this.groupId.equals(other.groupId); + result &= this.artifactId.equals(other.artifactId); + return result; + } + return false; + } + + } + +} diff --git a/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/ManagedDependencies.java b/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/ManagedDependencies.java index c44faa15ea..ad288c5cf9 100644 --- a/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/ManagedDependencies.java +++ b/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/ManagedDependencies.java @@ -16,104 +16,20 @@ package org.springframework.boot.dependency.tools; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; /** - * Provides access to the managed dependencies declared in - * {@literal spring-boot-dependencies}. + * Interface for accessing a known managed set of dependencies. * * @author Phillip Webb * @see Dependency */ -public class ManagedDependencies implements Iterable { - - private static ManagedDependencies instance; - - private final String version; - - private final Map byArtifactAndGroupId; - - private final Map byArtifactId; - - ManagedDependencies(String dependenciesPomResource, String effectivePomResource) { - try { - Document dependenciesPomDocument = readDocument(dependenciesPomResource); - this.version = dependenciesPomDocument.getElementsByTagName("version") - .item(0).getTextContent(); - - // Parse all dependencies from the effective POM (with resolved properties) - Document effectivePomDocument = readDocument(effectivePomResource); - Map all = new HashMap(); - for (Dependency dependency : readDependencies(effectivePomDocument)) { - all.put(new ArtifactAndGroupId(dependency), dependency); - } - - // But only add those from the dependencies POM - this.byArtifactAndGroupId = new LinkedHashMap(); - this.byArtifactId = new LinkedHashMap(); - for (Dependency dependency : readDependencies(dependenciesPomDocument)) { - ArtifactAndGroupId artifactAndGroupId = new ArtifactAndGroupId(dependency); - Dependency effectiveDependency = all.get(artifactAndGroupId); - if (effectiveDependency != null) { - this.byArtifactAndGroupId - .put(artifactAndGroupId, effectiveDependency); - this.byArtifactId.put(effectiveDependency.getArtifactId(), - effectiveDependency); - } - } - } - catch (Exception ex) { - throw new IllegalStateException(ex); - } - } - - private Document readDocument(String resource) throws Exception { - InputStream stream = getClass().getResourceAsStream(resource); - if (stream == null) { - throw new IllegalStateException("Unable to open resource " + resource); - } - DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance() - .newDocumentBuilder(); - Document document = documentBuilder.parse(stream); - document.getDocumentElement().normalize(); - return document; - } - - private List readDependencies(Document document) throws Exception { - Element element = (Element) document.getElementsByTagName("project").item(0); - element = (Element) element.getElementsByTagName("dependencyManagement").item(0); - element = (Element) element.getElementsByTagName("dependencies").item(0); - NodeList nodes = element.getChildNodes(); - List dependencies = new ArrayList(); - for (int i = 0; i < nodes.getLength(); i++) { - Node node = nodes.item(i); - if (node instanceof Element) { - dependencies.add(Dependency.fromDependenciesXml((Element) node)); - } - } - return dependencies; - } +public interface ManagedDependencies extends Iterable { /** - * Return the 'spring-boot-dependencies' POM version. + * @return The Spring Boot version being managed. */ - public String getVersion() { - return this.version; - } + public String getSpringBootVersion(); /** * Find a single dependency for the given group and artifact IDs. @@ -121,79 +37,19 @@ public class ManagedDependencies implements Iterable { * @param artifactId the artifact ID * @return a {@link Dependency} or {@code null} */ - public Dependency find(String groupId, String artifactId) { - return this.byArtifactAndGroupId.get(new ArtifactAndGroupId(groupId, artifactId)); - } + public Dependency find(String groupId, String artifactId); /** * Find a single dependency for the artifact IDs. * @param artifactId the artifact ID * @return a {@link Dependency} or {@code null} */ - public Dependency find(String artifactId) { - return this.byArtifactId.get(artifactId); - } + public Dependency find(String artifactId); /** * Provide an {@link Iterator} over all managed {@link Dependency Dependencies}. */ @Override - public Iterator iterator() { - return this.byArtifactAndGroupId.values().iterator(); - } + public Iterator iterator(); - /** - * @return The Spring Boot managed dependencies. - */ - public static ManagedDependencies get() { - if (instance == null) { - return new ManagedDependencies("dependencies-pom.xml", "effective-pom.xml"); - } - return instance; - } - - /** - * Simple holder for an artifact+group ID. - */ - private static class ArtifactAndGroupId { - - private final String groupId; - - private final String artifactId; - - public ArtifactAndGroupId(Dependency dependency) { - this(dependency.getGroupId(), dependency.getArtifactId()); - } - - public ArtifactAndGroupId(String groupId, String artifactId) { - Assert.notNull(groupId, "GroupId must not be null"); - Assert.notNull(artifactId, "ArtifactId must not be null"); - this.groupId = groupId; - this.artifactId = artifactId; - } - - @Override - public int hashCode() { - return this.groupId.hashCode() * 31 + this.artifactId.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() == obj.getClass()) { - ArtifactAndGroupId other = (ArtifactAndGroupId) obj; - boolean result = true; - result &= this.groupId.equals(other.groupId); - result &= this.artifactId.equals(other.artifactId); - return result; - } - return false; - } - - } } diff --git a/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/PomManagedDependencies.java b/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/PomManagedDependencies.java new file mode 100644 index 0000000000..45d1ebe4e0 --- /dev/null +++ b/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/PomManagedDependencies.java @@ -0,0 +1,113 @@ +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.dependency.tools; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * {@link ManagedDependencies} implementation backed a maven POM. + * + * @author Phillip Webb + * @since 1.1.0 + */ +public class PomManagedDependencies extends AbstractManagedDependencies { + + /** + * Create a new {@link PomManagedDependencies} instance. + * @param effectivePomInputStream the effective POM containing resolved versions. The + * input stream will be closed once content has been loaded. + * @param dependenciesInputStream and optional POM used to limit the dependencies. The + * input stream will be closed once content has been loaded. which will be added from + * the effective POM + */ + public PomManagedDependencies(InputStream effectivePomInputStream, + InputStream dependenciesInputStream) { + try { + Document effectivePom = readDocument(effectivePomInputStream); + Document dependenciesPom = readDocument(dependenciesInputStream); + + if (dependenciesPom == null) { + // No dependencies POM, add all items + for (Dependency dependency : readDependencies(effectivePom)) { + add(new ArtifactAndGroupId(dependency), dependency); + } + } + else { + // Only add items that are also in the dependencies POM + Map all = new HashMap(); + for (Dependency dependency : readDependencies(effectivePom)) { + all.put(new ArtifactAndGroupId(dependency), dependency); + } + for (Dependency dependency : readDependencies(dependenciesPom)) { + ArtifactAndGroupId artifactAndGroupId = new ArtifactAndGroupId( + dependency); + Dependency effectiveDependency = all.get(artifactAndGroupId); + if (effectiveDependency != null) { + add(artifactAndGroupId, effectiveDependency); + } + } + } + } + catch (Exception ex) { + throw new IllegalStateException(ex); + } + } + + private Document readDocument(InputStream inputStream) throws Exception { + if (inputStream == null) { + return null; + } + try { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + Document document = builder.parse(inputStream); + document.getDocumentElement().normalize(); + return document; + } + finally { + inputStream.close(); + } + } + + private List readDependencies(Document document) throws Exception { + Element element = (Element) document.getElementsByTagName("project").item(0); + element = (Element) element.getElementsByTagName("dependencyManagement").item(0); + element = (Element) element.getElementsByTagName("dependencies").item(0); + NodeList nodes = element.getChildNodes(); + List dependencies = new ArrayList(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node instanceof Element) { + dependencies.add(Dependency.fromDependenciesXml((Element) node)); + } + } + return dependencies; + } + +} diff --git a/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/PropertiesFileManagedDependencies.java b/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/PropertiesFileManagedDependencies.java new file mode 100644 index 0000000000..7369f639ca --- /dev/null +++ b/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/PropertiesFileManagedDependencies.java @@ -0,0 +1,73 @@ +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.dependency.tools; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; + +/** + * {@link ManagedDependencies} backed by an external properties file (of the form created + * by the Spring IO platform). The property key should be the groupID and versionId (in + * the form {@literal group:version}) and the value should be the version. + * + * @author Phillip Webb + * @since 1.1.0 + */ +public class PropertiesFileManagedDependencies extends AbstractManagedDependencies { + + /** + * Create a new {@link PropertiesFileManagedDependencies} instance from the specified + * input stream. + * @param inputStream source input stream (will be closed when properties have been + * loaded) + * @throws IOException + */ + public PropertiesFileManagedDependencies(InputStream inputStream) throws IOException { + try { + Properties properties = new Properties(); + properties.load(inputStream); + initialize(properties); + } + finally { + inputStream.close(); + } + } + + private void initialize(Properties properties) { + Map sortedMap = new TreeMap(); + for (Map.Entry entry : properties.entrySet()) { + sortedMap.put(entry.getKey().toString(), entry.getValue().toString()); + } + for (Map.Entry entry : sortedMap.entrySet()) { + ArtifactAndGroupId artifactAndGroupId = parse(entry.getKey()); + Dependency dependency = artifactAndGroupId.newDependency(entry.getValue()); + add(artifactAndGroupId, dependency); + } + } + + private ArtifactAndGroupId parse(String value) { + String[] parts = value.split("\\:"); + if (parts.length != 2) { + throw new IllegalStateException("Unable to parse " + value); + } + return new ArtifactAndGroupId(parts[0], parts[1]); + } + +} diff --git a/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/VersionManagedDependencies.java b/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/VersionManagedDependencies.java new file mode 100644 index 0000000000..4128b8b4f2 --- /dev/null +++ b/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/VersionManagedDependencies.java @@ -0,0 +1,85 @@ +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.dependency.tools; + +import java.io.InputStream; +import java.util.Collection; +import java.util.Collections; + +/** + * {@link ManagedDependencies} used by various spring boot tools. Provides programmatic + * access to 'spring-boot-dependencies' and can also support user defined version managed + * dependencies. + * + * @author Phillip Webb + * @since 1.1.0 + */ +public class VersionManagedDependencies extends AbstractManagedDependencies { + + private static ManagedDependencies springBootDependencies; + + /** + * Create a new {@link VersionManagedDependencies} instance for + * 'spring-boot-dependencies'. + */ + public VersionManagedDependencies() { + this(Collections. emptySet()); + } + + /** + * Create a new {@link VersionManagedDependencies} instance with optional version + * managed dependencies. + * @param versionManagedDependencies a collection of {@link ManagedDependencies} that + * take precedence over the `spring-boot-dependencies`. + */ + public VersionManagedDependencies( + Collection versionManagedDependencies) { + this(getSpringBootDependencies(), versionManagedDependencies); + } + + VersionManagedDependencies(ManagedDependencies rootDependencies, + Collection versionManagedDependencies) { + addAll(rootDependencies); + if (versionManagedDependencies != null) { + for (ManagedDependencies managedDependencies : versionManagedDependencies) { + addAll(managedDependencies); + } + } + } + + private void addAll(ManagedDependencies dependencies) { + for (Dependency dependency : dependencies) { + add(new ArtifactAndGroupId(dependency), dependency); + } + } + + private static ManagedDependencies getSpringBootDependencies() { + if (springBootDependencies == null) { + springBootDependencies = new PomManagedDependencies( + getResource("effective-pom.xml"), getResource("dependencies-pom.xml")); + } + return springBootDependencies; + } + + private static InputStream getResource(String name) { + InputStream inputStream = VersionManagedDependencies.class + .getResourceAsStream(name); + Assert.notNull(inputStream, "Unable to load " + name); + return inputStream; + } + +} diff --git a/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/package-info.java b/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/package-info.java index 9271ab60ae..fd8846f8dd 100644 --- a/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/package-info.java +++ b/spring-boot-tools/spring-boot-dependency-tools/src/main/java/org/springframework/boot/dependency/tools/package-info.java @@ -18,7 +18,7 @@ * Utilities for working with the managed dependencies declared in the * {@literal spring-boot-dependencies} project. * - * @see org.springframework.boot.dependency.tools.ManagedDependencies + * @see org.springframework.boot.dependency.tools.VersionManagedDependencies */ package org.springframework.boot.dependency.tools; diff --git a/spring-boot-tools/spring-boot-dependency-tools/src/test/java/org/springframework/boot/dependency/tools/PomManagedDependenciesTests.java b/spring-boot-tools/spring-boot-dependency-tools/src/test/java/org/springframework/boot/dependency/tools/PomManagedDependenciesTests.java new file mode 100644 index 0000000000..09f1f00985 --- /dev/null +++ b/spring-boot-tools/spring-boot-dependency-tools/src/test/java/org/springframework/boot/dependency/tools/PomManagedDependenciesTests.java @@ -0,0 +1,102 @@ +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.dependency.tools; + +import java.io.InputStream; +import java.util.Iterator; + +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +/** + * Tests for {@link PomManagedDependencies}. + * + * @author Phillip Webb + */ +public class PomManagedDependenciesTests { + + private PomManagedDependencies dependencies; + + @Before + public void setup() { + InputStream x = getResource("test-effective-pom.xml"); + InputStream y = getResource("test-dependencies-pom.xml"); + this.dependencies = new PomManagedDependencies(x, y); + } + + private InputStream getResource(String name) { + InputStream inputStream = getClass().getResourceAsStream(name); + assertNotNull("Unable to read " + name, inputStream); + return inputStream; + } + + @Test + public void springBootVersion() throws Exception { + assertThat(this.dependencies.getSpringBootVersion(), + equalTo("1.0.0.BUILD-SNAPSHOT")); + } + + @Test + public void iterate() throws Exception { + Iterator iterator = this.dependencies.iterator(); + assertThat(iterator.next().toString(), equalTo("org.sample:sample01:1.0.0")); + assertThat(iterator.next().toString(), equalTo("org.sample:sample02:1.0.0")); + assertThat(iterator.next().toString(), + equalTo("org.springframework.boot:spring-boot:1.0.0.BUILD-SNAPSHOT")); + assertThat(iterator.hasNext(), equalTo(false)); + } + + @Test + public void findByArtifactAndGroupId() throws Exception { + assertThat(this.dependencies.find("org.sample", "sample02").toString(), + equalTo("org.sample:sample02:1.0.0")); + } + + @Test + public void findByArtifactAndGroupIdMissing() throws Exception { + assertThat(this.dependencies.find("org.sample", "missing"), nullValue()); + } + + @Test + public void findByArtifactAndGroupIdOnlyInEffectivePom() throws Exception { + assertThat(this.dependencies.find("org.extra", "extra01"), nullValue()); + } + + @Test + public void findByArtifactId() throws Exception { + assertThat(this.dependencies.find("sample02").toString(), + equalTo("org.sample:sample02:1.0.0")); + } + + @Test + public void findByArtifactIdMissing() throws Exception { + assertThat(this.dependencies.find("missing"), nullValue()); + } + + @Test + public void exludes() throws Exception { + Dependency dependency = this.dependencies.find("org.sample", "sample01"); + assertThat(dependency.getExclusions().toString(), + equalTo("[org.exclude:exclude01]")); + } + +} diff --git a/spring-boot-tools/spring-boot-dependency-tools/src/test/java/org/springframework/boot/dependency/tools/ManagedDependenciesTests.java b/spring-boot-tools/spring-boot-dependency-tools/src/test/java/org/springframework/boot/dependency/tools/PropertiesFileManagedDependenciesTests.java similarity index 73% rename from spring-boot-tools/spring-boot-dependency-tools/src/test/java/org/springframework/boot/dependency/tools/ManagedDependenciesTests.java rename to spring-boot-tools/spring-boot-dependency-tools/src/test/java/org/springframework/boot/dependency/tools/PropertiesFileManagedDependenciesTests.java index 33cba815ad..996af35b1f 100644 --- a/spring-boot-tools/spring-boot-dependency-tools/src/test/java/org/springframework/boot/dependency/tools/ManagedDependenciesTests.java +++ b/spring-boot-tools/spring-boot-dependency-tools/src/test/java/org/springframework/boot/dependency/tools/PropertiesFileManagedDependenciesTests.java @@ -22,28 +22,28 @@ import org.junit.Before; import org.junit.Test; import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; /** - * Tests for {@link ManagedDependencies}. + * Tests for {@link PropertiesFileManagedDependencies}. * * @author Phillip Webb */ -public class ManagedDependenciesTests { +public class PropertiesFileManagedDependenciesTests { - private ManagedDependencies dependencies; + private PropertiesFileManagedDependencies dependencies; @Before - public void setup() { - this.dependencies = new ManagedDependencies("test-dependencies-pom.xml", - "test-effective-pom.xml"); + public void setup() throws Exception { + this.dependencies = new PropertiesFileManagedDependencies(getClass() + .getResourceAsStream("external.properties")); } @Test - public void version() throws Exception { - assertThat(this.dependencies.getVersion(), equalTo("1.0.0.BUILD-SNAPSHOT")); + public void springBootVersion() throws Exception { + assertThat(this.dependencies.getSpringBootVersion(), + equalTo("1.0.0.BUILD-SNAPSHOT")); } @Test @@ -51,6 +51,8 @@ public class ManagedDependenciesTests { Iterator iterator = this.dependencies.iterator(); assertThat(iterator.next().toString(), equalTo("org.sample:sample01:1.0.0")); assertThat(iterator.next().toString(), equalTo("org.sample:sample02:1.0.0")); + assertThat(iterator.next().toString(), + equalTo("org.springframework.boot:spring-boot:1.0.0.BUILD-SNAPSHOT")); assertThat(iterator.hasNext(), equalTo(false)); } @@ -83,17 +85,9 @@ public class ManagedDependenciesTests { @Test public void exludes() throws Exception { + // No Support for exclusion Dependency dependency = this.dependencies.find("org.sample", "sample01"); - assertThat(dependency.getExclusions().toString(), - equalTo("[org.exclude:exclude01]")); - } - - @Test - public void get() throws Exception { - ManagedDependencies dependencies = ManagedDependencies.get(); - assertThat(dependencies.iterator().hasNext(), equalTo(true)); - assertThat(dependencies.find("org.springframework", "spring-core"), - notNullValue()); + assertThat(dependency.getExclusions().size(), equalTo(0)); } } diff --git a/spring-boot-tools/spring-boot-dependency-tools/src/test/java/org/springframework/boot/dependency/tools/VersionManagedDependenciesTests.java b/spring-boot-tools/spring-boot-dependency-tools/src/test/java/org/springframework/boot/dependency/tools/VersionManagedDependenciesTests.java new file mode 100644 index 0000000000..fb8724f2f5 --- /dev/null +++ b/spring-boot-tools/spring-boot-dependency-tools/src/test/java/org/springframework/boot/dependency/tools/VersionManagedDependenciesTests.java @@ -0,0 +1,76 @@ +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.dependency.tools; + +import java.util.Collections; +import java.util.Iterator; + +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; + +/** + * Tests for {@link VersionManagedDependencies}. + * + * @author Phillip Webb + */ +public class VersionManagedDependenciesTests { + + private VersionManagedDependencies dependencies; + + @Before + public void setup() throws Exception { + PropertiesFileManagedDependencies root = new PropertiesFileManagedDependencies( + getClass().getResourceAsStream("external.properties")); + PropertiesFileManagedDependencies extra = new PropertiesFileManagedDependencies( + getClass().getResourceAsStream("additional-external.properties")); + this.dependencies = new VersionManagedDependencies(root, + Collections. singleton(extra)); + } + + @Test + public void extra() throws Exception { + assertThat(this.dependencies.find("org.sample", "sample03").toString(), + equalTo("org.sample:sample03:2.0.0")); + } + + @Test + public void override() throws Exception { + assertThat(this.dependencies.find("org.sample", "sample02").toString(), + equalTo("org.sample:sample02:2.0.0")); + } + + @Test + public void getSpringBootVersion() throws Exception { + assertThat(this.dependencies.getSpringBootVersion(), + equalTo("1.0.0.BUILD-SNAPSHOT")); + } + + @Test + public void iterator() throws Exception { + Iterator iterator = this.dependencies.iterator(); + assertThat(iterator.next().toString(), equalTo("org.sample:sample01:1.0.0")); + assertThat(iterator.next().toString(), equalTo("org.sample:sample02:2.0.0")); + assertThat(iterator.next().toString(), + equalTo("org.springframework.boot:spring-boot:1.0.0.BUILD-SNAPSHOT")); + assertThat(iterator.next().toString(), equalTo("org.sample:sample03:2.0.0")); + assertThat(iterator.hasNext(), equalTo(false)); + } + +} diff --git a/spring-boot-tools/spring-boot-dependency-tools/src/test/resources/org/springframework/boot/dependency/tools/additional-external.properties b/spring-boot-tools/spring-boot-dependency-tools/src/test/resources/org/springframework/boot/dependency/tools/additional-external.properties new file mode 100644 index 0000000000..a16bf51a33 --- /dev/null +++ b/spring-boot-tools/spring-boot-dependency-tools/src/test/resources/org/springframework/boot/dependency/tools/additional-external.properties @@ -0,0 +1,2 @@ +org.sample\:sample03=2.0.0 +org.sample\:sample02=2.0.0 diff --git a/spring-boot-tools/spring-boot-dependency-tools/src/test/resources/org/springframework/boot/dependency/tools/external.properties b/spring-boot-tools/spring-boot-dependency-tools/src/test/resources/org/springframework/boot/dependency/tools/external.properties new file mode 100644 index 0000000000..b31616844c --- /dev/null +++ b/spring-boot-tools/spring-boot-dependency-tools/src/test/resources/org/springframework/boot/dependency/tools/external.properties @@ -0,0 +1,3 @@ +org.sample\:sample01=1.0.0 +org.sample\:sample02=1.0.0 +org.springframework.boot\:spring-boot=1.0.0.BUILD-SNAPSHOT diff --git a/spring-boot-tools/spring-boot-dependency-tools/src/test/resources/org/springframework/boot/dependency/tools/test-dependencies-pom.xml b/spring-boot-tools/spring-boot-dependency-tools/src/test/resources/org/springframework/boot/dependency/tools/test-dependencies-pom.xml index 2bf7cf04b2..d41d9ce8de 100644 --- a/spring-boot-tools/spring-boot-dependency-tools/src/test/resources/org/springframework/boot/dependency/tools/test-dependencies-pom.xml +++ b/spring-boot-tools/spring-boot-dependency-tools/src/test/resources/org/springframework/boot/dependency/tools/test-dependencies-pom.xml @@ -15,10 +15,10 @@ sample01 ${sample.version} - - org.exclude - exclude01 - + + org.exclude + exclude01 + @@ -26,6 +26,11 @@ sample02 ${sample.version} + + org.springframework.boot + spring-boot + 1.0.0.BUILD-SNAPSHOT + diff --git a/spring-boot-tools/spring-boot-dependency-tools/src/test/resources/org/springframework/boot/dependency/tools/test-effective-pom.xml b/spring-boot-tools/spring-boot-dependency-tools/src/test/resources/org/springframework/boot/dependency/tools/test-effective-pom.xml index f24b636687..5cdad4fdbc 100644 --- a/spring-boot-tools/spring-boot-dependency-tools/src/test/resources/org/springframework/boot/dependency/tools/test-effective-pom.xml +++ b/spring-boot-tools/spring-boot-dependency-tools/src/test/resources/org/springframework/boot/dependency/tools/test-effective-pom.xml @@ -24,6 +24,11 @@ sample02 1.0.0 + + org.springframework.boot + spring-boot + 1.0.0.BUILD-SNAPSHOT + org.extra extra01 diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPlugin.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPlugin.java index 240fc85bb7..53ec8d3ab5 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPlugin.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPlugin.java @@ -32,7 +32,7 @@ import org.springframework.boot.gradle.task.RunWithAgent; /** * Gradle 'Spring Boot' {@link Plugin}. - * + * * @author Phillip Webb * @author Dave Syer */ @@ -45,6 +45,9 @@ public class SpringBootPlugin implements Plugin { @Override public void apply(Project project) { + project.getConfigurations().create( + SpringBootResolutionStrategy.VERSION_MANAGEMENT_CONFIGURATION); + applyRepackage(project); applyRun(project); @@ -80,12 +83,12 @@ public class SpringBootPlugin implements Plugin { project.getTasks().whenTaskAdded(new ComputeMain(project)); } - private void applyResolutionStrategy(Project project) { + private void applyResolutionStrategy(final Project project) { project.getConfigurations().all(new Action() { @Override public void execute(Configuration configuration) { - SpringBootResolutionStrategy.apply(configuration.getResolutionStrategy()); + SpringBootResolutionStrategy.apply(project, configuration); } }); diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootResolutionStrategy.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootResolutionStrategy.java index 2f92c8b6ed..ce6753185e 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootResolutionStrategy.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootResolutionStrategy.java @@ -1,50 +1,99 @@ + package org.springframework.boot.gradle; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + import org.gradle.api.Action; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.DependencyResolveDetails; import org.gradle.api.artifacts.ModuleVersionSelector; -import org.gradle.api.artifacts.ResolutionStrategy; import org.springframework.boot.dependency.tools.Dependency; import org.springframework.boot.dependency.tools.ManagedDependencies; +import org.springframework.boot.dependency.tools.PropertiesFileManagedDependencies; +import org.springframework.boot.dependency.tools.VersionManagedDependencies; /** * A resolution strategy to resolve missing version numbers using the * 'spring-boot-dependencies' POM. - * + * * @author Phillip Webb */ public class SpringBootResolutionStrategy { + public static final String VERSION_MANAGEMENT_CONFIGURATION = "versionManagement"; + private static final String SPRING_BOOT_GROUP = "org.springframework.boot"; - public static void apply(ResolutionStrategy resolutionStrategy) { - resolutionStrategy.eachDependency(new Action() { - - @Override - public void execute(DependencyResolveDetails resolveDetails) { - String version = resolveDetails.getTarget().getVersion(); - if (version == null || version.trim().length() == 0) { - resolve(resolveDetails); - } - } - - }); - } - - protected static void resolve(DependencyResolveDetails resolveDetails) { - - ManagedDependencies dependencies = ManagedDependencies.get(); - ModuleVersionSelector target = resolveDetails.getTarget(); - - if (SPRING_BOOT_GROUP.equals(target.getGroup())) { - resolveDetails.useVersion(dependencies.getVersion()); + public static void apply(final Project project, Configuration configuration) { + if (VERSION_MANAGEMENT_CONFIGURATION.equals(configuration.getName())) { return; } - - Dependency dependency = dependencies.find(target.getGroup(), target.getName()); - if (dependency != null) { - resolveDetails.useVersion(dependency.getVersion()); - } + VersionResolver versionResolver = new VersionResolver(project); + configuration.getResolutionStrategy().eachDependency(versionResolver); } + private static class VersionResolver implements Action { + + private Configuration versionManagementConfiguration; + + private Collection versionManagedDependencies; + + public VersionResolver(Project project) { + this.versionManagementConfiguration = project.getConfigurations().getByName( + VERSION_MANAGEMENT_CONFIGURATION); + } + + @Override + public void execute(DependencyResolveDetails resolveDetails) { + String version = resolveDetails.getTarget().getVersion(); + if (version == null || version.trim().length() == 0) { + resolve(resolveDetails); + } + } + + private void resolve(DependencyResolveDetails resolveDetails) { + ManagedDependencies dependencies = new VersionManagedDependencies( + getVersionManagedDependencies()); + ModuleVersionSelector target = resolveDetails.getTarget(); + if (SPRING_BOOT_GROUP.equals(target.getGroup())) { + resolveDetails.useVersion(dependencies.getSpringBootVersion()); + return; + } + Dependency dependency = dependencies.find(target.getGroup(), target.getName()); + if (dependency != null) { + resolveDetails.useVersion(dependency.getVersion()); + } + } + + private Collection getVersionManagedDependencies() { + if (versionManagedDependencies == null) { + Set files = versionManagementConfiguration.resolve(); + List dependencies = new ArrayList( + files.size()); + for (File file : files) { + dependencies.add(getPropertiesFileManagedDependencies(file)); + } + this.versionManagedDependencies = dependencies; + } + return versionManagedDependencies; + } + + private ManagedDependencies getPropertiesFileManagedDependencies(File file) { + if (!file.getName().toLowerCase().endsWith(".properties")) { + throw new IllegalStateException(file + " is not a version property file"); + } + try { + return new PropertiesFileManagedDependencies(new FileInputStream(file)); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + } } diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/manual-test/versionManagement/.gradletasknamecache b/spring-boot-tools/spring-boot-gradle-plugin/src/manual-test/versionManagement/.gradletasknamecache new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/manual-test/versionManagement/build.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/manual-test/versionManagement/build.gradle new file mode 100644 index 0000000000..d5d58e98a9 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/manual-test/versionManagement/build.gradle @@ -0,0 +1,29 @@ +buildscript { + ext { + springBootVersion = '1.1.0.BUILD-SNAPSHOT' + } + repositories { + mavenLocal() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") + } +} + +apply plugin: 'java' +apply plugin: 'spring-boot' + +repositories { + mavenLocal() + mavenCentral() + maven { url "http://repo.spring.io/release" } + maven { url "http://repo.spring.io/milestone" } + maven { url "http://repo.spring.io/snapshot" } +} + +dependencies { + versionManagement("io.spring.platform:platform-versions:1.0.0.BUILD-SNAPSHOT@properties") + compile("org.springframework.boot:spring-boot-starter") + compile("org.springframework.data:spring-data-hadoop") + testCompile("org.springframework.boot:spring-boot-starter-test") +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/manual-test/versionManagement/readme.txt b/spring-boot-tools/spring-boot-gradle-plugin/src/manual-test/versionManagement/readme.txt new file mode 100644 index 0000000000..60d8ea04cc --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/manual-test/versionManagement/readme.txt @@ -0,0 +1,3 @@ +simple manual test to show how versionManagement dependencies can be used + +run gradle dependencies and check that there are no failures diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/manual-test/versionManagement/src/main/java/VersionManagementApplication.java b/spring-boot-tools/spring-boot-gradle-plugin/src/manual-test/versionManagement/src/main/java/VersionManagementApplication.java new file mode 100644 index 0000000000..cb3e3c33c5 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/manual-test/versionManagement/src/main/java/VersionManagementApplication.java @@ -0,0 +1,6 @@ +public class VersionManagementApplication { + + public static void main(String[] args) { + } + +}