This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ant-antlibs-cyclonedx.git


The following commit(s) were added to refs/heads/main by this push:
     new 159b309  tweaks
159b309 is described below

commit 159b3096753ce55143498c8eb3ef589d53dc38f4
Author: Stefan Bodewig <[email protected]>
AuthorDate: Sat May 16 13:22:24 2026 +0200

    tweaks
---
 docs/component.html                              |   2 +-
 src/main/org/apache/ant/cyclonedx/Component.java | 106 +++++++++++++----------
 src/tests/antunit/component-test.xml             |  33 +++++++
 3 files changed, 93 insertions(+), 48 deletions(-)

diff --git a/docs/component.html b/docs/component.html
index c5ad4d9..fbb402a 100644
--- a/docs/component.html
+++ b/docs/component.html
@@ -73,7 +73,7 @@ <h3>Attributes</h3>
             (purl)</a> of the component.</td>
         <td>No - if not set but <code>name</code>, <code>group</code>
           and <code>version</code> are present an implicit purl is
-          calculated as <code>pkg:maven</code> purl from these
+          calculated as <code>pkg:maven</code> jar purl from these
           values.</td>
       </tr>
       <tr>
diff --git a/src/main/org/apache/ant/cyclonedx/Component.java 
b/src/main/org/apache/ant/cyclonedx/Component.java
index 0e123f2..8445ac3 100644
--- a/src/main/org/apache/ant/cyclonedx/Component.java
+++ b/src/main/org/apache/ant/cyclonedx/Component.java
@@ -308,6 +308,7 @@ public class Component extends DataType {
     public void addComponent(Component c) {
         checkChildrenAllowed();
         nestedComponents.add(c);
+        // the newly added component may cause a circular dependency
         setChecked(false);
     }
 
@@ -415,6 +416,10 @@ public class Component extends DataType {
         return result;
     }
 
+    /**
+     * Whether this component links to an external SBOM and wants to
+     * read data from it.
+     */
     public boolean hasSbomLink() {
         if (isReference()) {
             return getRef().hasSbomLink();
@@ -423,13 +428,22 @@ public class Component extends DataType {
         return sbomLink != null;
     }
 
-    public Collection<Component> resolve() throws IOException {
+    /**
+     * Read the linked SBOM (if any) and merge its content with the
+     * one already defined for this component.
+     *
+     * @return the "addtional" components defined in the linked SBOM
+     * that are dependencies of this component.
+     */
+    public synchronized Collection<Component> resolve() throws IOException {
         if (isReference()) {
             return getRef().resolve();
         }
         dieOnCircularReference();
 
         if (sbomLink != null && !sbomLinkResolved) {
+            sbomLinkResolved = true;
+
             Bom bom = readLinkedSbom();
             if (bom.getMetadata() == null) {
                 throw new BuildException("referenced SBOM file lacks 
metadata");
@@ -439,23 +453,14 @@ public class Component extends DataType {
                 throw new BuildException("referenced SBOM file lacks 
component");
             }
             List<org.cyclonedx.model.Dependency> allDependencies = 
bom.getDependencies();
-            fillFrom(real, allDependencies);
-
-            List<org.cyclonedx.model.Component> additionalComponents = 
bom.getComponents();
-            if (additionalComponents != null && !areDependenciesUnknown()) {
-                List<Component> toReturn = new ArrayList<>();
-                for (org.cyclonedx.model.Component c : additionalComponents) {
-                    Component dep = from(c, Collections.emptyList());
-                    if (dependencies.stream().anyMatch(d -> 
Objects.equals(dep.getBomRef(), d.getBomRef()))) {
-                        // only include "additional components" this component 
depends on directly.
-                        // we don't want to resolve transitive dependencies 
automatically
-                        dep.setUnknownDependencies(true);
-                        toReturn.add(dep);
-                    }
+            fillFromBomLink(real, allDependencies);
+
+            if (!areDependenciesUnknown() && !dependencies.isEmpty()) {
+                List<org.cyclonedx.model.Component> additionalComponents = 
bom.getComponents();
+                if (additionalComponents != null) {
+                    return 
extractComponentsThatAreDirectDependencies(additionalComponents);
                 }
-                return toReturn;
             }
-            sbomLinkResolved = true;
         }
 
         return Collections.emptyList();
@@ -484,16 +489,10 @@ public class Component extends DataType {
         if (scope != null) {
             component.setScope(scope);
         }
+        // add isExternal once VERSION_17 is supported by cyclonedx-java-core
         return component;
     }
 
-    private static Component from(org.cyclonedx.model.Component real,
-                                  List<org.cyclonedx.model.Dependency> 
dependencies) {
-        Component c = new Component();
-        c.fillFrom(real, dependencies);
-        return c;
-    }
-
     private org.cyclonedx.model.Component toCycloneDxComponent(Version 
bomVersion)
         throws IOException {
         dieOnCircularReference();
@@ -548,20 +547,6 @@ public class Component extends DataType {
         if (supplier != null) {
             component.setSupplier(supplier.toOrganizationalEntity());
         }
-        if (!authors.isEmpty()) {
-            component.setAuthors(authors);
-        }
-        if (!properties.isEmpty()) {
-            component.setProperties(properties);
-        }
-        if (!tags.isEmpty()) {
-            component.setTags(new 
Tags(tags.stream().sorted().collect(Collectors.toList())));
-        }
-        if (!licenses.isEmpty()) {
-            LicenseChoice lc = new LicenseChoice();
-            lc.setLicenses(licenses);
-            component.setLicenses(lc);
-        }
         String purl = getPurl();
         if (purl != null) {
             component.setPurl(purl);
@@ -572,19 +557,45 @@ public class Component extends DataType {
         } else if (!dependencies.isEmpty()) {
             throw new BuildException("a component with dependencies must 
provide a bomRef");
         }
-        if (!externalReferences.isEmpty()) {
-            component.setExternalReferences(externalReferences);
-        }
+        component.setAuthors(authors);
+        component.setProperties(properties);
+        component.setTags(new 
Tags(tags.stream().sorted().collect(Collectors.toList())));
+        LicenseChoice lc = new LicenseChoice();
+        lc.setLicenses(licenses);
+        component.setLicenses(lc);
+        component.setExternalReferences(externalReferences);
         for (Component c : nestedComponents) {
             
component.addComponent(c.toAdditionalCycloneDxComponent(bomVersion));
         }
-        // add isExternal once VERSION_17 is supported by cyclonedx-java-core
         addHashes(component, bomVersion);
         return component;
     }
 
-    private void fillFrom(org.cyclonedx.model.Component real,
-                          List<org.cyclonedx.model.Dependency> 
allDependencies) {
+    private List<Component> 
extractComponentsThatAreDirectDependencies(List<org.cyclonedx.model.Component> 
cs) {
+        List<Component> toReturn = new ArrayList<>();
+        for (org.cyclonedx.model.Component c : cs) {
+            Component dep = from(c, Collections.emptyList());
+            if (dependencies.stream().anyMatch(d -> 
Objects.equals(dep.getBomRef(), d.getBomRef()))) {
+                // only include "additional components" this component depends 
on directly.
+                // we don't want to resolve transitive dependencies 
automatically
+                dep.setUnknownDependencies(true);
+                toReturn.add(dep);
+            }
+        }
+        return toReturn;
+    }
+
+    private static Component from(
+        org.cyclonedx.model.Component real,
+        List<org.cyclonedx.model.Dependency> dependencies) {
+        Component c = new Component();
+        c.fillFromBomLink(real, dependencies);
+        return c;
+    }
+
+    private void fillFromBomLink(
+        org.cyclonedx.model.Component real,
+        List<org.cyclonedx.model.Dependency> allDependencies) {
         if (type == null) {
             setType(ComponentType.from(real.getType()));
         }
@@ -668,11 +679,11 @@ public class Component extends DataType {
             }
         }
         if (dependencies.isEmpty() && allDependencies != null) {
-            fillDependencies(allDependencies);
+            fillDependenciesFromBomLink(allDependencies);
         }
     }
 
-    private void fillDependencies(List<org.cyclonedx.model.Dependency> 
allDependencies) {
+    private void 
fillDependenciesFromBomLink(List<org.cyclonedx.model.Dependency> 
allDependencies) {
         setUnknownDependencies(true);
         org.cyclonedx.model.Dependency myDependencies = allDependencies
             .stream()
@@ -766,15 +777,16 @@ public class Component extends DataType {
                 return bomRef;
             }
 
+            String refid = componentRef.getRefId();
             Object component = componentRef.getReferencedObject();
             if (component instanceof Component) {
                 String b = ((Component) component).getBomRef();
                 if (b == null) {
-                    throw new BuildException("component with id '" + 
componentRef.getRefId() + "' doesn't provide a bomRef");
+                    throw new BuildException("component with id '" + refid + 
"' doesn't provide a bomRef");
                 }
                 return b;
             }
-            throw new BuildException("componentRef '" + 
componentRef.getRefId() + "' doesn't refer to a component");
+            throw new BuildException("componentRef '" + refid + "' doesn't 
refer to a component");
         }
 
         static Dependency from(org.cyclonedx.model.Dependency dependency) {
diff --git a/src/tests/antunit/component-test.xml 
b/src/tests/antunit/component-test.xml
index be612d6..8bc47c4 100644
--- a/src/tests/antunit/component-test.xml
+++ b/src/tests/antunit/component-test.xml
@@ -913,6 +913,39 @@
         value='&lt;hash alg="SHA-256"&gt;${ant.file.sha256}&lt;/hash&gt;'/>
   </target>
 
+  <target
+      name="testSbomLinkDoesNotUseLinkedSupplierIfManufacturerIsSupplier"
+      depends="createMaximalComponentData">
+    <cdx:componentbom
+        bomName="merged"
+        outputdirectory="${output}"
+        format="xml"
+        xmlns:cdx="antlib:org.apache.ant.cyclonedx">
+      <component manufacturerIsSupplier="true">
+        <sbomLink>
+          <file file="${output}/bom.json"/>
+        </sbomLink>
+      </component>
+    </cdx:componentbom>
+    <xmlproperty file="${output}/merged.xml"/>
+    <au:assertPropertyEquals
+        xmlns:au="antlib:org.apache.ant.antunit"
+        name="bom.metadata.component.manufacturer.name"
+        value="Example"/>
+    <au:assertPropertyEquals
+        xmlns:au="antlib:org.apache.ant.antunit"
+        name="bom.metadata.component.manufacturer.url"
+        value="https://example.org/"/>
+    <au:assertPropertyEquals
+        xmlns:au="antlib:org.apache.ant.antunit"
+        name="bom.metadata.component.supplier.name"
+        value="Example"/>
+    <au:assertPropertyEquals
+        xmlns:au="antlib:org.apache.ant.antunit"
+        name="bom.metadata.component.supplier.url"
+        value="https://example.org/"/>
+  </target>
+
   <target
       name="testDataFromLinkedSbomCanBeOverwerittenOrMerged"
       depends="createMaximalComponentData">

Reply via email to