o Added dependencyDefaults section to POM.

The nested <dependencyDefault> element closely mirrors the <dependency> element specification.
  It provides the ability to set url, artifact, properties, version for a dependency that matches on
  {groupId, artifactId, type}. Url, artifact, and version will only override the dependency's values if
  the dependency doesn't provide the value, and (in the case of url and artifact) the dependency
  doesn't provide a version (url and artifact are assumed to be version-specific).

  Properties will only be overwritten, and only in the case where the dependency
  doesn't specify them.

  Dependencies are validated after merging with defaults, since version is not required
  on either <dependency> or <dependencyDefault> but is required between the two.

o Added component interface/default impl for injecting project defaults.
o Added unit and integration tests.


git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@163323 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
John Dennis Casey 2005-02-01 22:43:03 +00:00
parent a404ffd7d7
commit e687cfed61
15 changed files with 498 additions and 1 deletions

View File

@ -37,6 +37,8 @@ it0010: Since the artifact resolution does not use the project builder, we must
will check this, by depending on classworlds, which is a dependency of
maven-component, which is the parent of maven-plugin, which is an
explicit dependency of this test.
it0011: Test specification of dependency versions via <dependencyDefaults/>.
-------------------------------------------------------------------------------

View File

@ -9,3 +9,4 @@ it0007
it0008
it0009
it0010
it0011

View File

@ -0,0 +1,10 @@
*~
*.log
target
*.ipr
*.iws
dist
target
.classpath
.project
log.txt

View File

@ -0,0 +1 @@
target/classes/org/apache/maven/it0011/PersonFinder.class

View File

@ -0,0 +1 @@
compiler:compile

View File

@ -0,0 +1,30 @@
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>maven</groupId>
<artifactId>maven-core-it0011</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>maven</groupId>
<artifactId>maven-plugin</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
<dependencyDefaults>
<dependencyDefault>
<groupId>maven</groupId>
<artifactId>maven-plugin</artifactId>
<version>2.0-SNAPSHOT</version>
</dependencyDefault>
<dependencyDefault>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
</dependencyDefault>
</dependencyDefaults>
</project>

View File

@ -0,0 +1 @@
rm ${localRepository}/maven/plugins/maven-core-it-plugin-1.0-SNAPSHOT.jar

View File

@ -0,0 +1,8 @@
package org.apache.maven.it0011;
import org.codehaus.classworlds.ClassRealm;
public class PersonFinder
{
private ClassRealm classRealm;
}

View File

@ -70,6 +70,8 @@ public class DefaultMavenProjectBuilder
private MavenXpp3Reader modelReader;
private PathTranslator pathTranslator;
private ProjectDefaultsInjector projectDefaultsInjector;
public void initialize()
throws Exception
@ -111,6 +113,8 @@ public class DefaultMavenProjectBuilder
previous = current;
}
projectDefaultsInjector.injectDefaults(project);
project.setLocalRepository( localRepository );

View File

@ -0,0 +1,91 @@
// TODO Attach license header here.
package org.apache.maven.project;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyDefault;
import org.codehaus.plexus.util.StringUtils;
/**
* @author jdcasey
*
* Created on Feb 1, 2005
*/
public class DefaultProjectDefaultsInjector implements ProjectDefaultsInjector
{
public void injectDefaults(MavenProject project)
{
injectDependencyDefaults(project.getDependencies(), project.getDependencyDefaults());
}
/** Added: Feb 1, 2005 by jdcasey
*/
private void injectDependencyDefaults( List dependencies, List dependencyDefaults )
{
// a given project's dependencies should be smaller than the group-defined defaults set...
// in other words, the project's deps will probably be a subset of those specified in defaults.
Map depsMap = new TreeMap();
for ( Iterator it = dependencies.iterator(); it.hasNext(); )
{
Dependency dep = (Dependency) it.next();
depsMap.put(dep.getGroupId() + ":" + dep.getArtifactId() + ":" + dep.getType(), dep);
}
for ( Iterator it = dependencyDefaults.iterator(); it.hasNext(); )
{
DependencyDefault depdef = (DependencyDefault) it.next();
String key = depdef.getGroupId() + ":" + depdef.getArtifactId() + ":" + depdef.getType();
Dependency dep = (Dependency) depsMap.get(key);
if(dep != null)
{
mergeWithDefaults(dep, depdef);
validateDependency(dep);
}
}
}
/** Added: Feb 1, 2005 by jdcasey
*/
private void mergeWithDefaults( Dependency dep, DependencyDefault depdef )
{
if(dep.getVersion() == null && depdef.getVersion() != null)
{
dep.setVersion(depdef.getVersion());
if(dep.getArtifact() == null && depdef.getArtifact() != null)
{
dep.setArtifact(depdef.getArtifact());
}
if(dep.getUrl() == null && depdef.getUrl() != null)
{
dep.setUrl(depdef.getUrl());
}
}
Properties depProps = dep.getProperties();
Properties depdefProps = depdef.getProperties();
if((depProps == null || depProps.isEmpty()) && depdefProps != null)
{
dep.setProperties(depdefProps);
}
}
/** Added: Feb 1, 2005 by jdcasey
*/
private void validateDependency( Dependency dep )
{
if(StringUtils.isEmpty(dep.getVersion()))
{
throw new IllegalStateException("Dependency version is null for: " + dep.getId());
}
}
}

View File

@ -118,6 +118,11 @@ public class MavenProject
{
return model.getDependencies();
}
public List getDependencyDefaults()
{
return model.getDependencyDefaults();
}
// ----------------------------------------------------------------------
// Test and compile sourceroots.

View File

@ -0,0 +1,14 @@
// TODO Attach license header here.
package org.apache.maven.project;
/**
* @author jdcasey
*
* Created on Feb 1, 2005
*/
public interface ProjectDefaultsInjector
{
public static final String ROLE = DefaultProjectDefaultsInjector.class.getName();
void injectDefaults( MavenProject project );
}

View File

@ -134,6 +134,15 @@
</lifecycle-phases>
</configuration>
</component>
<!--
|
|
|
-->
<component>
<role>org.apache.maven.project.ProjectDefaultsInjector</role>
<implementation>org.apache.maven.project.DefaultProjectDefaultsInjector</implementation>
</component>
<!--
|
|
@ -143,6 +152,9 @@
<role>org.apache.maven.project.MavenProjectBuilder</role>
<implementation>org.apache.maven.project.DefaultMavenProjectBuilder</implementation>
<requirements>
<requirement>
<role>org.apache.maven.project.ProjectDefaultsInjector</role>
</requirement>
<requirement>
<role>org.apache.maven.project.inheritance.ModelInheritanceAssembler</role>
</requirement>

View File

@ -0,0 +1,219 @@
// TODO Attach license header here.
package org.apache.maven.project;
import java.util.List;
import java.util.Properties;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyDefault;
import org.apache.maven.model.Model;
import junit.framework.TestCase;
/**
* @author jdcasey
*
* Created on Feb 1, 2005
*/
public class DefaultProjectDefaultsInjectorTest
extends TestCase
{
public void testShouldConstructWithNoParams()
{
new DefaultProjectDefaultsInjector();
}
public void testShouldSucceedInMergingDependencyWithDependencyDefault()
{
Model model = new Model();
Dependency dep = new Dependency();
dep.setGroupId("myGroup");
dep.setArtifactId("myArtifact");
model.addDependency(dep);
DependencyDefault def = new DependencyDefault();
def.setGroupId(dep.getGroupId());
def.setArtifactId(dep.getArtifactId());
def.setVersion("1.0.1");
model.addDependencyDefault(def);
MavenProject project = new MavenProject(model);
new DefaultProjectDefaultsInjector().injectDefaults(project);
List deps = project.getDependencies();
assertEquals(1, deps.size());
Dependency result = (Dependency)deps.get(0);
assertEquals(def.getVersion(), result.getVersion());
}
public void testShouldMergeDefaultUrlAndArtifactWhenDependencyDoesntSupplyVersion()
{
Model model = new Model();
Dependency dep = new Dependency();
dep.setGroupId("myGroup");
dep.setArtifactId("myArtifact");
model.addDependency(dep);
DependencyDefault def = new DependencyDefault();
def.setGroupId(dep.getGroupId());
def.setArtifactId(dep.getArtifactId());
def.setArtifact("myArtifact");
def.setUrl("http://www.google.com");
def.setVersion("1.0.1");
model.addDependencyDefault(def);
MavenProject project = new MavenProject(model);
new DefaultProjectDefaultsInjector().injectDefaults(project);
List deps = project.getDependencies();
assertEquals(1, deps.size());
Dependency result = (Dependency)deps.get(0);
assertEquals(def.getVersion(), result.getVersion());
assertEquals(def.getArtifact(), result.getArtifact());
assertEquals(def.getUrl(), result.getUrl());
}
public void testShouldNotMergeDefaultUrlOrArtifactWhenDependencySuppliesVersion()
{
Model model = new Model();
Dependency dep = new Dependency();
dep.setGroupId("myGroup");
dep.setArtifactId("myArtifact");
dep.setVersion("1.0.1");
model.addDependency(dep);
DependencyDefault def = new DependencyDefault();
def.setGroupId(dep.getGroupId());
def.setArtifactId(dep.getArtifactId());
def.setArtifact("myArtifact");
def.setUrl("http://www.google.com");
model.addDependencyDefault(def);
MavenProject project = new MavenProject(model);
new DefaultProjectDefaultsInjector().injectDefaults(project);
List deps = project.getDependencies();
assertEquals(1, deps.size());
Dependency result = (Dependency)deps.get(0);
assertEquals(dep.getVersion(), result.getVersion());
assertNull(result.getArtifact());
assertNull(result.getUrl());
}
public void testShouldMergeDefaultPropertiesWhenDependencyDoesntSupplyProperties()
{
Model model = new Model();
Dependency dep = new Dependency();
dep.setGroupId("myGroup");
dep.setArtifactId("myArtifact");
dep.setVersion("1.0.1");
model.addDependency(dep);
DependencyDefault def = new DependencyDefault();
def.setGroupId(dep.getGroupId());
def.setArtifactId(dep.getArtifactId());
Properties props = new Properties();
props.setProperty("test", "value");
def.setProperties(props);
model.addDependencyDefault(def);
MavenProject project = new MavenProject(model);
new DefaultProjectDefaultsInjector().injectDefaults(project);
List deps = project.getDependencies();
assertEquals(1, deps.size());
Dependency result = (Dependency)deps.get(0);
assertEquals("value", result.getProperties().getProperty("test"));
}
public void testShouldNotMergeDefaultPropertiesWhenDependencySuppliesProperties()
{
Model model = new Model();
Dependency dep = new Dependency();
dep.setGroupId("myGroup");
dep.setArtifactId("myArtifact");
dep.setVersion("1.0.1");
Properties props = new Properties();
props.setProperty("test", "value");
dep.setProperties(props);
model.addDependency(dep);
DependencyDefault def = new DependencyDefault();
def.setGroupId(dep.getGroupId());
def.setArtifactId(dep.getArtifactId());
Properties props2 = new Properties();
props2.setProperty("test", "value2");
def.setProperties(props2);
model.addDependencyDefault(def);
MavenProject project = new MavenProject(model);
new DefaultProjectDefaultsInjector().injectDefaults(project);
List deps = project.getDependencies();
assertEquals(1, deps.size());
Dependency result = (Dependency)deps.get(0);
assertEquals("value", result.getProperties().getProperty("test"));
}
public void testShouldRejectDependencyWhereNoVersionIsFoundAfterDefaultsInjection()
{
Model model = new Model();
Dependency dep = new Dependency();
dep.setGroupId("myGroup");
dep.setArtifactId("myArtifact");
model.addDependency(dep);
DependencyDefault def = new DependencyDefault();
def.setGroupId(dep.getGroupId());
def.setArtifactId(dep.getArtifactId());
model.addDependencyDefault(def);
MavenProject project = new MavenProject(model);
try
{
new DefaultProjectDefaultsInjector().injectDefaults( project );
fail("Should fail to validate dependency without a version.");
}
catch ( IllegalStateException e )
{
// should throw when it detects a missing version in the test dependency.
}
}
}

View File

@ -407,6 +407,18 @@
<association>
<type>DistributionManagement</type>
</association>
</field>
<!-- [ jdcasey:01-Feb-2005 ] Added to handle version management for
| dependencies to be used in sub-projects. -->
<field>
<name>dependencyDefaults</name>
<version>4.0.0</version>
<required>false</required>
<description><![CDATA[Default dependency information for grouped projects inheriting from this one.]]></description>
<association>
<type>DependencyDefault</type>
<multiplicity>*</multiplicity>
</association>
</field>
<field>
<name>local</name>
@ -804,7 +816,8 @@
<field>
<name>version</name>
<version>3.0.0+</version>
<required>true</required>
<!-- [ jdcasey:01-Feb-2005 ] No longer required. We'll validate after injecting defaults. -->
<!-- required>true</required -->
<description><![CDATA[
The version of the dependency., e.g.
<code>3.2.1</code>
@ -1754,6 +1767,91 @@
</field>
</fields>
</class>
<!-- [ jdcasey:01-Feb-2005 ] Added to handle version management for
| dependencies to be used in sub-projects. -->
<class>
<name>DependencyDefault</name>
<version>4.0.0</version>
<description><![CDATA[
Default information for a dependency to be used in a sub-project. The
required fields here will be used to match dependency references.
]]></description>
<fields>
<field>
<name>groupId</name>
<version>4.0.0</version>
<required>true</required>
<description><![CDATA[
The project group that produced the dependency, e.g.
<code>geronimo</code>.
]]></description>
<type>String</type>
</field>
<field>
<name>artifactId</name>
<version>4.0.0</version>
<required>true</required>
<description><![CDATA[
The unique id for an artifact produced by the project group, e.g.
<code>germonimo-jms</code>
]]></description>
<type>String</type>
</field>
<field>
<name>version</name>
<version>4.0.0</version>
<description><![CDATA[
The version of the dependency., e.g.
<code>3.2.1</code>
]]></description>
<type>String</type>
</field>
<field>
<name>url</name>
<version>4.0.0</version>
<description><![CDATA[
This url will be provided to the user if the jar file cannot be downloaded
from the central repository.
]]></description>
<type>String</type>
<comment>The URL should really be gleaned from a shared database of dependency information.</comment>
</field>
<field>
<name>artifact</name>
<version>4.0.0</version>
<description><![CDATA[Literal name of the artifact]]></description>
<type>String</type>
</field>
<field>
<name>type</name>
<version>4.0.0</version>
<description><![CDATA[
Other known recognised dependency types are:
<code>ejb</code> and
<code>plugin</code>.
]]></description>
<type>String</type>
<defaultValue>jar</defaultValue>
</field>
<field>
<name>properties</name>
<version>4.0.0</version>
<description><![CDATA[
Properties about the dependency. Various plugins allow you to
<code>mark</code> dependencies with properties. For example the
<a href="plugins/war/index.html">war</a> plugin looks for a
<code>war.bundle</code> property, and if found will include the dependency
in
<code>WEB-INF/lib</code>. For example syntax, check the war plugin docs.
]]></description>
<type>Properties</type>
<association xml.mapStyle="inline">
<type>String</type>
<multiplicity>*</multiplicity>
</association>
</field>
</fields>
</class>
</classes>
</model>