diff --git a/main/src/main/scala/sbt/internal/PomGenerator.scala b/main/src/main/scala/sbt/internal/PomGenerator.scala
index b7036799e..99816eb16 100644
--- a/main/src/main/scala/sbt/internal/PomGenerator.scala
+++ b/main/src/main/scala/sbt/internal/PomGenerator.scala
@@ -221,7 +221,7 @@ private[sbt] object PomGenerator:
{versionNode}
{scopeElem(scope)}
{optionalElem(optional)}
- {classifierElem(dep)}
+ {typeAndClassifierElems(dep)}
{exclusions(dep)}
result
@@ -265,10 +265,19 @@ private[sbt] object PomGenerator:
private def optionalElem(opt: Boolean): NodeSeq =
if opt then true else NodeSeq.Empty
- private def classifierElem(dep: ModuleID): NodeSeq =
- dep.explicitArtifacts.headOption.flatMap(_.classifier) match
- case Some(c) => {c}
- case None => NodeSeq.Empty
+ private def typeAndClassifierElems(dep: ModuleID): NodeSeq =
+ dep.explicitArtifacts.headOption match
+ case None => NodeSeq.Empty
+ case Some(art) =>
+ val classifier = art.classifier
+ val baseType = Option(art.`type`).filter(_ != Artifact.DefaultType)
+ val tpe = (classifier, baseType) match
+ case (Some(c), Some(t)) if Artifact.classifierType(c) == t => None
+ case _ => baseType
+ val typeNode = tpe.map(t => {t}).getOrElse(NodeSeq.Empty)
+ val classifierNode =
+ classifier.map(c => {c}).getOrElse(NodeSeq.Empty)
+ typeNode ++ classifierNode
private def exclusions(dep: ModuleID): NodeSeq =
if dep.exclusions.isEmpty then NodeSeq.Empty
diff --git a/sbt-app/src/sbt-test/dependency-management/pom-artifact-type/build.sbt b/sbt-app/src/sbt-test/dependency-management/pom-artifact-type/build.sbt
new file mode 100644
index 000000000..07570f4c5
--- /dev/null
+++ b/sbt-app/src/sbt-test/dependency-management/pom-artifact-type/build.sbt
@@ -0,0 +1,38 @@
+lazy val checkPom = taskKey[Unit]("check pom emits for non-jar explicit artifacts")
+
+lazy val root = (project in file("."))
+ .settings(
+ scalaVersion := "2.13.16",
+ autoScalaLibrary := false,
+ libraryDependencies += "org.eclipse.jetty" % "jetty-webapp" % "11.0.15" artifacts (Artifact("jetty-webapp", "war", "war")),
+ libraryDependencies += "com.typesafe" % "config" % "1.4.3",
+ // classified artifact with non-default type: both and must appear
+ libraryDependencies += ("com.example" % "classified-war" % "1.0")
+ .artifacts(Artifact("classified-war", "war", "war").withClassifier(Some("client"))),
+ checkPom := {
+ val converter = fileConverter.value
+ val pomFile = makePom.value
+ val pom = xml.XML.loadFile(converter.toPath(pomFile).toFile)
+ val deps = pom \ "dependencies" \ "dependency"
+
+ // WAR dependency should be present with war
+ val warDep = deps.find(d => (d \ "artifactId").text == "jetty-webapp")
+ assert(warDep.isDefined, s"jetty-webapp dependency missing from POM.\nDeps: ${deps.map(d => (d \ "artifactId").text)}")
+ val warType = (warDep.get \ "type").text
+ assert(warType == "war", s"Expected war for jetty-webapp, got: '$warType'")
+
+ // JAR dependency should NOT have (jar is the Maven default)
+ val jarDep = deps.find(d => (d \ "artifactId").text == "config")
+ assert(jarDep.isDefined, "config dependency missing from POM")
+ val jarType = (jarDep.get \ "type").text
+ assert(jarType == "", s"Expected no for config (jar is default), got: '$jarType'")
+
+ // Classified WAR: must have both war and client
+ val cwDep = deps.find(d => (d \ "artifactId").text == "classified-war")
+ assert(cwDep.isDefined, s"classified-war dependency missing from POM.\nDeps: ${deps.map(d => (d \ "artifactId").text)}")
+ val cwType = (cwDep.get \ "type").text
+ assert(cwType == "war", s"Expected war for classified-war, got: '$cwType'")
+ val cwClassifier = (cwDep.get \ "classifier").text
+ assert(cwClassifier == "client", s"Expected client for classified-war, got: '$cwClassifier'")
+ },
+ )
diff --git a/sbt-app/src/sbt-test/dependency-management/pom-artifact-type/test b/sbt-app/src/sbt-test/dependency-management/pom-artifact-type/test
new file mode 100644
index 000000000..8d831496e
--- /dev/null
+++ b/sbt-app/src/sbt-test/dependency-management/pom-artifact-type/test
@@ -0,0 +1 @@
+> checkPom