diff --git a/pkg/lockfile/fixtures/maven/with-dependency-management-and-duplicates.xml b/pkg/lockfile/fixtures/maven/with-dependency-management-and-duplicates.xml
new file mode 100644
index 00000000..b4d1c76b
--- /dev/null
+++ b/pkg/lockfile/fixtures/maven/with-dependency-management-and-duplicates.xml
@@ -0,0 +1,35 @@
+
+
+ 3.0
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.13.3
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.13.0
+
+
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.13.4
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.13.4.1
+
+
+
+
diff --git a/pkg/lockfile/fixtures/maven/with-duplicate-packages.xml b/pkg/lockfile/fixtures/maven/with-duplicate-packages.xml
new file mode 100644
index 00000000..a77baf0f
--- /dev/null
+++ b/pkg/lockfile/fixtures/maven/with-duplicate-packages.xml
@@ -0,0 +1,25 @@
+
+
+ 3.0
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.13.3
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.13.4
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.13.4.1
+
+
+
diff --git a/pkg/lockfile/parse-maven-lock.go b/pkg/lockfile/parse-maven-lock.go
index 6491b25e..e0445f02 100644
--- a/pkg/lockfile/parse-maven-lock.go
+++ b/pkg/lockfile/parse-maven-lock.go
@@ -64,6 +64,28 @@ type MavenLockFile struct {
ManagedDependencies []MavenLockDependency `xml:"dependencyManagement>dependencies>dependency"`
}
+func (mlf *MavenLockFile) collectPackages(dependencies []MavenLockDependency) map[string]PackageDetails {
+ details := map[string]PackageDetails{}
+
+ for _, lockPackage := range dependencies {
+ finalName := lockPackage.GroupID + ":" + lockPackage.ArtifactID
+
+ // the first declaration of a dependency at a specific depth wins
+ if _, ok := details[finalName]; ok {
+ continue
+ }
+
+ details[finalName] = PackageDetails{
+ Name: finalName,
+ Version: lockPackage.ResolveVersion(*mlf),
+ Ecosystem: MavenEcosystem,
+ CompareAs: MavenEcosystem,
+ }
+ }
+
+ return details
+}
+
const MavenEcosystem Ecosystem = "Maven"
type MavenLockProperties struct {
@@ -113,29 +135,11 @@ func ParseMavenLock(pathToLockfile string) ([]PackageDetails, error) {
return []PackageDetails{}, fmt.Errorf("could not parse %s: %w", pathToLockfile, err)
}
- details := map[string]PackageDetails{}
-
- for _, lockPackage := range parsedLockfile.Dependencies {
- finalName := lockPackage.GroupID + ":" + lockPackage.ArtifactID
-
- details[finalName] = PackageDetails{
- Name: finalName,
- Version: lockPackage.ResolveVersion(*parsedLockfile),
- Ecosystem: MavenEcosystem,
- CompareAs: MavenEcosystem,
- }
- }
+ details := parsedLockfile.collectPackages(parsedLockfile.Dependencies)
// managed dependencies take precedent over standard dependencies
- for _, lockPackage := range parsedLockfile.ManagedDependencies {
- finalName := lockPackage.GroupID + ":" + lockPackage.ArtifactID
-
- details[finalName] = PackageDetails{
- Name: finalName,
- Version: lockPackage.ResolveVersion(*parsedLockfile),
- Ecosystem: MavenEcosystem,
- CompareAs: MavenEcosystem,
- }
+ for k, detail := range parsedLockfile.collectPackages(parsedLockfile.ManagedDependencies) {
+ details[k] = detail
}
return pkgDetailsMapToSlice(details), nil
diff --git a/pkg/lockfile/parse-maven-lock_test.go b/pkg/lockfile/parse-maven-lock_test.go
index d7ef4c87..c3f0ed88 100644
--- a/pkg/lockfile/parse-maven-lock_test.go
+++ b/pkg/lockfile/parse-maven-lock_test.go
@@ -89,6 +89,31 @@ func TestParseMavenLock_TwoPackages(t *testing.T) {
})
}
+func TestParseMavenLock_WithDuplicatePackages(t *testing.T) {
+ t.Parallel()
+
+ packages, err := lockfile.ParseMavenLock("fixtures/maven/with-duplicate-packages.xml")
+
+ if err != nil {
+ t.Errorf("Got unexpected error: %v", err)
+ }
+
+ expectPackages(t, packages, []lockfile.PackageDetails{
+ {
+ Name: "com.fasterxml.jackson.core:jackson-annotations",
+ Version: "2.13.3",
+ Ecosystem: lockfile.MavenEcosystem,
+ CompareAs: lockfile.MavenEcosystem,
+ },
+ {
+ Name: "com.fasterxml.jackson.core:jackson-databind",
+ Version: "2.13.4",
+ Ecosystem: lockfile.MavenEcosystem,
+ CompareAs: lockfile.MavenEcosystem,
+ },
+ })
+}
+
func TestParseMavenLock_WithDependencyManagement(t *testing.T) {
t.Parallel()
@@ -120,6 +145,31 @@ func TestParseMavenLock_WithDependencyManagement(t *testing.T) {
})
}
+func TestParseMavenLock_WithDependencyManagementAndDuplicates(t *testing.T) {
+ t.Parallel()
+
+ packages, err := lockfile.ParseMavenLock("fixtures/maven/with-dependency-management-and-duplicates.xml")
+
+ if err != nil {
+ t.Errorf("Got unexpected error: %v", err)
+ }
+
+ expectPackages(t, packages, []lockfile.PackageDetails{
+ {
+ Name: "com.fasterxml.jackson.core:jackson-annotations",
+ Version: "2.13.3",
+ Ecosystem: lockfile.MavenEcosystem,
+ CompareAs: lockfile.MavenEcosystem,
+ },
+ {
+ Name: "com.fasterxml.jackson.core:jackson-databind",
+ Version: "2.13.4",
+ Ecosystem: lockfile.MavenEcosystem,
+ CompareAs: lockfile.MavenEcosystem,
+ },
+ })
+}
+
func TestParseMavenLock_Interpolation(t *testing.T) {
t.Parallel()