Repository: CycloneDX/cyclonedx-core-java
Pull request #504 (2024-09-12 19:36:17)

Code Improvements
Some code enhancements were detected while running tests for things that were missing 


Patch:
diff --git a/src/main/java/org/cyclonedx/generators/json/BomJsonGenerator.java b/src/main/java/org/cyclonedx/generators/json/BomJsonGenerator.java
index a462d6bb1..cb9260bc2 100644
--- a/src/main/java/org/cyclonedx/generators/json/BomJsonGenerator.java
+++ b/src/main/java/org/cyclonedx/generators/json/BomJsonGenerator.java
@@ -45,6 +45,7 @@ public class BomJsonGenerator extends AbstractBomGenerator
   /**
    * Constructs a new BomGenerator object.
    * @param bom the BOM to generate
+   * @param version the version of the CycloneDX schema to use.
    */
   public BomJsonGenerator(Bom bom, final Version version) {
     super(version, bom, Format.JSON);
diff --git a/src/main/java/org/cyclonedx/generators/xml/BomXmlGenerator.java b/src/main/java/org/cyclonedx/generators/xml/BomXmlGenerator.java
index fe721d092..e135dd69f 100644
--- a/src/main/java/org/cyclonedx/generators/xml/BomXmlGenerator.java
+++ b/src/main/java/org/cyclonedx/generators/xml/BomXmlGenerator.java
@@ -48,6 +48,7 @@ public class BomXmlGenerator extends AbstractBomGenerator
     /**
      * Constructs a new BomXmlGenerator object.
      * @param bom the BOM to generate
+     * @param version the version of the CycloneDX schema to use.
      */
     public BomXmlGenerator(final Bom bom, final Version version) {
         super(version, bom, Format.XML);
@@ -121,6 +122,7 @@ public class BomXmlGenerator extends AbstractBomGenerator
      * Creates a CycloneDX BoM from a set of Components.
      * @return an XML Document representing a CycloneDX BoM
      * @since 1.1.0
+     * @throws ParserConfigurationException if an error occurs
      */
     public Document generate() throws ParserConfigurationException {
         return generateDocument(bom);
diff --git a/src/main/java/org/cyclonedx/model/Annotation.java b/src/main/java/org/cyclonedx/model/Annotation.java
index ad9698405..4cfa8a362 100644
--- a/src/main/java/org/cyclonedx/model/Annotation.java
+++ b/src/main/java/org/cyclonedx/model/Annotation.java
@@ -58,6 +58,8 @@ public class Annotation extends ExtensibleElement
 
     private String text;
 
+    @JsonOnly
+    @JsonProperty("signature")
     private Signature signature;
 
     public String getBomRef() {
diff --git a/src/main/java/org/cyclonedx/model/Evidence.java b/src/main/java/org/cyclonedx/model/Evidence.java
index 3a925bd19..453e680c8 100644
--- a/src/main/java/org/cyclonedx/model/Evidence.java
+++ b/src/main/java/org/cyclonedx/model/Evidence.java
@@ -78,8 +78,8 @@ public class Evidence
         this.licenses = licenses;
     }
 
-    @JacksonXmlElementWrapper(useWrapping = false)
-    @JacksonXmlProperty(localName = "copyright")
+    @JacksonXmlElementWrapper(localName = "copyright")
+    @JacksonXmlProperty(localName = "text")
     @JsonProperty("copyright")
     public List<Copyright> getCopyright() {
         return copyright;
diff --git a/src/main/java/org/cyclonedx/model/component/crypto/AlgorithmProperties.java b/src/main/java/org/cyclonedx/model/component/crypto/AlgorithmProperties.java
index 946219aee..cd9971809 100644
--- a/src/main/java/org/cyclonedx/model/component/crypto/AlgorithmProperties.java
+++ b/src/main/java/org/cyclonedx/model/component/crypto/AlgorithmProperties.java
@@ -26,7 +26,10 @@ import org.cyclonedx.util.deserializer.CertificationLevelDeserializer;
     "curve",
     "executionEnvironment",
     "implementationPlatform",
-    "certificationLevel", "mode", "padding", "cryptoFunctions",
+    "certificationLevel",
+    "mode",
+    "padding",
+    "cryptoFunctions",
     "classicalSecurityLevel", "nistQuantumSecurityLevel"
 })
 public class AlgorithmProperties
diff --git a/src/main/java/org/cyclonedx/model/definition/Standard.java b/src/main/java/org/cyclonedx/model/definition/Standard.java
index f0e5f3050..bee0df96b 100644
--- a/src/main/java/org/cyclonedx/model/definition/Standard.java
+++ b/src/main/java/org/cyclonedx/model/definition/Standard.java
@@ -10,6 +10,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
 import org.cyclonedx.model.ExternalReference;
+import org.cyclonedx.model.JsonOnly;
 import org.cyclonedx.model.Signature;
 
 @JsonIgnoreProperties(ignoreUnknown = true)
@@ -44,6 +45,7 @@ public class Standard
 
   private List<ExternalReference> externalReferences;
 
+  @JsonOnly
   private Signature signature;
 
   public String getBomRef() {
diff --git a/src/main/java/org/cyclonedx/model/vulnerability/ProofOfConcept.java b/src/main/java/org/cyclonedx/model/vulnerability/ProofOfConcept.java
new file mode 100644
index 000000000..89f6a832d
--- /dev/null
+++ b/src/main/java/org/cyclonedx/model/vulnerability/ProofOfConcept.java
@@ -0,0 +1,74 @@
+package org.cyclonedx.model.vulnerability;
+
+import java.util.List;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.AttachmentText;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonPropertyOrder({
+    "reproductionSteps",
+    "environment",
+    "supportingMaterial"
+})
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class ProofOfConcept
+{
+  private String reproductionSteps;
+
+  private String environment;
+
+  private List<AttachmentText> supportingMaterial;
+
+  public String getEnvironment() {
+    return environment;
+  }
+
+  public void setEnvironment(final String environment) {
+    this.environment = environment;
+  }
+
+  @JacksonXmlElementWrapper(localName = "supportingMaterial")
+  @JacksonXmlProperty(localName = "attachment")
+  @JsonProperty("supportingMaterial")
+  public List<AttachmentText> getSupportingMaterial() {
+    return supportingMaterial;
+  }
+
+  public void setSupportingMaterial(final List<AttachmentText> supportingMaterial) {
+    this.supportingMaterial = supportingMaterial;
+  }
+
+  public String getReproductionSteps() {
+    return reproductionSteps;
+  }
+
+  public void setReproductionSteps(final String reproductionSteps) {
+    this.reproductionSteps = reproductionSteps;
+  }
+
+  @Override
+  public boolean equals(final Object object) {
+    if (this == object) {
+      return true;
+    }
+    if (!(object instanceof ProofOfConcept)) {
+      return false;
+    }
+    ProofOfConcept that = (ProofOfConcept) object;
+    return Objects.equals(reproductionSteps, that.reproductionSteps) &&
+        Objects.equals(environment, that.environment) &&
+        Objects.equals(supportingMaterial, that.supportingMaterial);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(reproductionSteps, environment, supportingMaterial);
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/org/cyclonedx/model/vulnerability/Vulnerability.java b/src/main/java/org/cyclonedx/model/vulnerability/Vulnerability.java
index 13617daaa..3d7fe822e 100644
--- a/src/main/java/org/cyclonedx/model/vulnerability/Vulnerability.java
+++ b/src/main/java/org/cyclonedx/model/vulnerability/Vulnerability.java
@@ -47,6 +47,8 @@ import org.cyclonedx.util.serializer.CustomDateSerializer;
     "description",
     "detail",
     "recommendation",
+    "workaround",
+    "proofOfConcept",
     "advisories",
     "created",
     "published",
@@ -74,6 +76,13 @@ public class Vulnerability
   private String description;
   private String detail;
   private String recommendation;
+
+  @VersionFilter(org.cyclonedx.Version.VERSION_15)
+  private String workaround;
+
+  @VersionFilter(org.cyclonedx.Version.VERSION_15)
+  private ProofOfConcept proofOfConcept;
+
   private List<Advisory> advisories;
   @JsonSerialize(using = CustomDateSerializer.class)
   @VersionFilter(org.cyclonedx.Version.VERSION_14)
@@ -273,6 +282,22 @@ public class Vulnerability
     this.properties = properties;
   }
 
+  public String getWorkaround() {
+    return workaround;
+  }
+
+  public void setWorkaround(final String workaround) {
+    this.workaround = workaround;
+  }
+
+  public ProofOfConcept getProofOfConcept() {
+    return proofOfConcept;
+  }
+
+  public void setProofOfConcept(final ProofOfConcept proofOfConcept) {
+    this.proofOfConcept = proofOfConcept;
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) return true;
@@ -296,31 +321,35 @@ public class Vulnerability
             Objects.equals(tools, rhs.tools) &&
             Objects.equals(analysis, rhs.analysis) &&
             Objects.equals(affects, rhs.affects) &&
+            Objects.equals(workaround, rhs.workaround) &&
+            Objects.equals(proofOfConcept, rhs.proofOfConcept) &&
             Objects.equals(properties, rhs.properties);
   }
 
   @Override
   public int hashCode() {
     return Objects.hash(
-            bomRef,
-            id,
-            source,
-            references,
-            ratings,
-            cwes,
-            description,
-            detail,
-            recommendation,
-            advisories,
-            created,
-            published,
-            updated,
-            rejected,
-            credits,
-            tools,
-            analysis,
-            affects,
-            properties);
+        bomRef,
+        id,
+        source,
+        references,
+        ratings,
+        cwes,
+        description,
+        detail,
+        recommendation,
+        advisories,
+        created,
+        published,
+        updated,
+        rejected,
+        credits,
+        tools,
+        analysis,
+        affects,
+        workaround,
+        proofOfConcept,
+        properties);
   }
 
   @JsonInclude(JsonInclude.Include.NON_NULL)
diff --git a/src/main/java/org/cyclonedx/util/deserializer/AttachmentTextDeserializer.java b/src/main/java/org/cyclonedx/util/deserializer/AttachmentTextDeserializer.java
index 144941847..d2b0c0b27 100644
--- a/src/main/java/org/cyclonedx/util/deserializer/AttachmentTextDeserializer.java
+++ b/src/main/java/org/cyclonedx/util/deserializer/AttachmentTextDeserializer.java
@@ -31,6 +31,8 @@ public class AttachmentTextDeserializer extends StdDeserializer<AttachmentText>
       attachmentText.setText(contentNode.asText());
     } else if (node.has("")) {
       attachmentText.setText(node.get("").asText());
+    } else if (node.isTextual()) {
+      attachmentText.setText(node.textValue());
     }
 
     JsonNode contentTypeNode = getContentTypeNode(node);
diff --git a/src/main/java/org/cyclonedx/util/serializer/SignatorySerializer.java b/src/main/java/org/cyclonedx/util/serializer/SignatorySerializer.java
index 544231d87..e3f6f2283 100644
--- a/src/main/java/org/cyclonedx/util/serializer/SignatorySerializer.java
+++ b/src/main/java/org/cyclonedx/util/serializer/SignatorySerializer.java
@@ -6,6 +6,7 @@ import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.databind.SerializerProvider;
 import com.fasterxml.jackson.databind.ser.std.StdSerializer;
 import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.cyclonedx.model.attestation.affirmation.Signatory;
 
@@ -34,29 +35,59 @@ public class SignatorySerializer
     }
   }
 
-  private void serializeJson(final JsonGenerator gen, final Signatory signatory)
+  private void serializeXml(final ToXmlGenerator gen, final Signatory signatory, final SerializerProvider provider)
       throws IOException
   {
-    gen.writeStartObject();
+    //It might have extensible types (signature)
+    if (CollectionUtils.isNotEmpty(signatory.getExtensibleTypes())) {
+      gen.writeStartObject();
 
-    if (StringUtils.isNotBlank(signatory.getName())) {
-      gen.writeStringField("name", signatory.getName());
-    }
+      if (StringUtils.isNotBlank(signatory.getName())) {
+        gen.writeStringField("name", signatory.getName());
+      }
+
+      if (StringUtils.isNotBlank(signatory.getRole())) {
+        gen.writeStringField("role", signatory.getRole());
+      }
 
-    if (StringUtils.isNotBlank(signatory.getRole())) {
-      gen.writeStringField("role", signatory.getRole());
+      new ExtensibleTypesSerializer().serialize(signatory.getExtensibleTypes(), gen, provider);
+      gen.writeEndObject();
     }
+  }
+
+  private void serializeJson(final JsonGenerator gen, final Signatory signatory)
+      throws IOException
+  {
+    boolean shouldSerialize = false;
 
-    if (signatory.getSignature() != null) {
-      gen.writeObjectField("signature", signatory.getSignature());
+    if (signatory.getSignature() != null && !isXml) {
+      shouldSerialize = true;
+    }
+    else if (signatory.getExternalReference() != null && signatory.getOrganization() != null) {
+      shouldSerialize = true;
     }
-    else {
-      if (signatory.getExternalReference() != null && signatory.getOrganization() != null) {
+
+    // Only serialize if the required values are set
+    if (shouldSerialize) {
+      gen.writeStartObject();
+
+      if (StringUtils.isNotBlank(signatory.getName())) {
+        gen.writeStringField("name", signatory.getName());
+      }
+
+      if (StringUtils.isNotBlank(signatory.getRole())) {
+        gen.writeStringField("role", signatory.getRole());
+      }
+
+      if (signatory.getSignature() != null) {
+        gen.writeObjectField("signature", signatory.getSignature());
+      }
+      else if (signatory.getExternalReference() != null && signatory.getOrganization() != null) {
         gen.writeObjectField("organization", signatory.getOrganization());
         gen.writeObjectField("externalReference", signatory.getExternalReference());
       }
+      gen.writeEndObject();
     }
-    gen.writeEndObject();
   }
 
   @Override


Test patch:
diff --git a/src/main/java/org/cyclonedx/model/attestation/Attestation.java b/src/main/java/org/cyclonedx/model/attestation/Attestation.java
index e7b3e67f9..f1c31b80c 100644
--- a/src/main/java/org/cyclonedx/model/attestation/Attestation.java
+++ b/src/main/java/org/cyclonedx/model/attestation/Attestation.java
@@ -8,6 +8,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.JsonOnly;
 import org.cyclonedx.model.Signature;
 
 @JsonIgnoreProperties(ignoreUnknown = true)
@@ -26,6 +27,7 @@ public class Attestation
 
   private List<AttestationMap> map;
 
+  @JsonOnly
   private Signature signature;
 
   public String getSummary() {
diff --git a/src/main/java/org/cyclonedx/model/attestation/Claim.java b/src/main/java/org/cyclonedx/model/attestation/Claim.java
index 02b6c9382..0997efb38 100644
--- a/src/main/java/org/cyclonedx/model/attestation/Claim.java
+++ b/src/main/java/org/cyclonedx/model/attestation/Claim.java
@@ -10,6 +10,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
 import org.cyclonedx.model.ExternalReference;
+import org.cyclonedx.model.JsonOnly;
 import org.cyclonedx.model.Signature;
 
 @JsonIgnoreProperties(ignoreUnknown = true)
@@ -44,6 +45,7 @@ public class Claim
 
   private List<ExternalReference> externalReferences;
 
+  @JsonOnly
   private Signature signature;
 
   public String getBomRef() {
@@ -111,7 +113,7 @@ public class Claim
   }
 
   @JacksonXmlElementWrapper(localName = "externalReferences")
-  @JacksonXmlProperty(localName = "externalReference")
+  @JacksonXmlProperty(localName = "reference")
   public List<ExternalReference> getExternalReferences() {
     return externalReferences;
   }
diff --git a/src/main/java/org/cyclonedx/model/attestation/Declarations.java b/src/main/java/org/cyclonedx/model/attestation/Declarations.java
index 2943147bf..c1da306bf 100644
--- a/src/main/java/org/cyclonedx/model/attestation/Declarations.java
+++ b/src/main/java/org/cyclonedx/model/attestation/Declarations.java
@@ -8,6 +8,8 @@ import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.ExtensibleElement;
+import org.cyclonedx.model.JsonOnly;
 import org.cyclonedx.model.Signature;
 import org.cyclonedx.model.attestation.affirmation.Affirmation;
 import org.cyclonedx.model.attestation.evidence.Evidence;
@@ -23,7 +25,7 @@ import org.cyclonedx.model.attestation.evidence.Evidence;
     "affirmation",
     "signature"
 })
-public class Declarations
+public class Declarations extends ExtensibleElement
 {
   private List<Assessor> assessors;
 
@@ -37,8 +39,11 @@ public class Declarations
 
   private Affirmation affirmation;
 
+  @JsonOnly
   private Signature signature;
 
+  @JacksonXmlElementWrapper(localName = "assessors")
+  @JacksonXmlProperty(localName = "assessor")
   public List<Assessor> getAssessors() {
     return assessors;
   }
diff --git a/src/main/java/org/cyclonedx/model/attestation/affirmation/Affirmation.java b/src/main/java/org/cyclonedx/model/attestation/affirmation/Affirmation.java
index fd76a100d..39dc42f2b 100644
--- a/src/main/java/org/cyclonedx/model/attestation/affirmation/Affirmation.java
+++ b/src/main/java/org/cyclonedx/model/attestation/affirmation/Affirmation.java
@@ -8,6 +8,8 @@ import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.ExtensibleElement;
+import org.cyclonedx.model.JsonOnly;
 import org.cyclonedx.model.Signature;
 
 @JsonIgnoreProperties(ignoreUnknown = true)
@@ -17,12 +19,13 @@ import org.cyclonedx.model.Signature;
     "signatories",
     "signature"
 })
-public class Affirmation
+public class Affirmation extends ExtensibleElement
 {
   private String statement;
 
   private List<Signatory> signatories;
 
+  @JsonOnly
   private Signature signature;
 
   public String getStatement() {
diff --git a/src/main/java/org/cyclonedx/model/attestation/affirmation/Signatory.java b/src/main/java/org/cyclonedx/model/attestation/affirmation/Signatory.java
index 84c85454c..bd714e6c3 100644
--- a/src/main/java/org/cyclonedx/model/attestation/affirmation/Signatory.java
+++ b/src/main/java/org/cyclonedx/model/attestation/affirmation/Signatory.java
@@ -4,23 +4,27 @@ import java.util.Objects;
 
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 import com.fasterxml.jackson.annotation.JsonTypeName;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import org.cyclonedx.model.ExtensibleElement;
 import org.cyclonedx.model.ExternalReference;
+import org.cyclonedx.model.JsonOnly;
 import org.cyclonedx.model.OrganizationalEntity;
 import org.cyclonedx.model.Signature;
 import org.cyclonedx.util.deserializer.SignatoryDeserializer;
 
 @JsonIgnoreProperties(ignoreUnknown = true)
 @JsonInclude(JsonInclude.Include.NON_EMPTY)
-@JsonTypeName("signatory")
+@JsonPropertyOrder({"name", "role", "signature", "organization", "externalReference"})
 @JsonDeserialize(using = SignatoryDeserializer.class)
-public class Signatory
+public class Signatory extends ExtensibleElement
 {
   private String name;
 
   private String role;
 
+  @JsonOnly
   private Signature signature;
 
   private OrganizationalEntity organization;
diff --git a/src/main/java/org/cyclonedx/model/attestation/evidence/Evidence.java b/src/main/java/org/cyclonedx/model/attestation/evidence/Evidence.java
index 68336cc2d..f3baa324a 100644
--- a/src/main/java/org/cyclonedx/model/attestation/evidence/Evidence.java
+++ b/src/main/java/org/cyclonedx/model/attestation/evidence/Evidence.java
@@ -11,6 +11,8 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.cyclonedx.model.ExtensibleElement;
+import org.cyclonedx.model.JsonOnly;
 import org.cyclonedx.model.OrganizationalContact;
 import org.cyclonedx.model.Signature;
 import org.cyclonedx.util.serializer.CustomDateSerializer;
@@ -27,7 +29,7 @@ import org.cyclonedx.util.serializer.CustomDateSerializer;
     "reviewer",
     "signature"
 })
-public class Evidence
+public class Evidence extends ExtensibleElement
 {
   @JacksonXmlProperty(isAttribute = true, localName = "bom-ref")
   @JsonProperty("bom-ref")
@@ -49,6 +51,7 @@ public class Evidence
 
   private OrganizationalContact reviewer;
 
+  @JsonOnly
   private Signature signature;
 
   public String getBomRef() {
diff --git a/src/test/java/org/cyclonedx/BomJsonGeneratorTest.java b/src/test/java/org/cyclonedx/BomJsonGeneratorTest.java
index 723c14092..ae1207108 100644
--- a/src/test/java/org/cyclonedx/BomJsonGeneratorTest.java
+++ b/src/test/java/org/cyclonedx/BomJsonGeneratorTest.java
@@ -290,6 +290,66 @@ public class BomJsonGeneratorTest {
         assertTrue(parser.isValid(loadedFile, version));
     }
 
+    @Test
+    public void schema16_testExpressions() throws Exception {
+        Version version = Version.VERSION_16;
+        Bom bom = createCommonXmlBom("/1.6/valid-license-expression-1.6.xml");
+
+        BomJsonGenerator generator = BomGeneratorFactory.createJson(version, bom);
+        File loadedFile = writeToFile(generator.toJsonString());
+
+        JsonParser parser = new JsonParser();
+        assertTrue(parser.isValid(loadedFile, version));
+    }
+
+    @Test
+    public void schema16_testAttestations() throws Exception {
+        Version version = Version.VERSION_16;
+        Bom bom = createCommonXmlBom("/1.6/valid-attestation-1.6.xml");
+
+        BomJsonGenerator generator = BomGeneratorFactory.createJson(version, bom);
+        File loadedFile = writeToFile(generator.toJsonString());
+
+        JsonParser parser = new JsonParser();
+        assertTrue(parser.isValid(loadedFile, version));
+    }
+
+    @Test
+    public void schema16_testAttestations_json() throws Exception {
+        Version version = Version.VERSION_16;
+        Bom bom = createCommonJsonBom("/1.6/valid-attestation-1.6.json");
+
+        BomJsonGenerator generator = BomGeneratorFactory.createJson(version, bom);
+        File loadedFile = writeToFile(generator.toJsonString());
+
+        JsonParser parser = new JsonParser();
+        assertTrue(parser.isValid(loadedFile, version));
+    }
+
+    @Test
+    public void schema16_testCompositions() throws Exception {
+        Version version = Version.VERSION_16;
+        Bom bom = createCommonXmlBom("/1.6/valid-compositions-1.6.xml");
+
+        BomJsonGenerator generator = BomGeneratorFactory.createJson(version, bom);
+        File loadedFile = writeToFile(generator.toJsonString());
+
+        JsonParser parser = new JsonParser();
+        assertTrue(parser.isValid(loadedFile, version));
+    }
+
+    @Test
+    public void schema16_testVulnerabilities() throws Exception {
+        Version version = Version.VERSION_16;
+        Bom bom = createCommonXmlBom("/1.6/valid-vulnerability-1.6.xml");
+
+        BomJsonGenerator generator = BomGeneratorFactory.createJson(version, bom);
+        File loadedFile = writeToFile(generator.toJsonString());
+
+        JsonParser parser = new JsonParser();
+        assertTrue(parser.isValid(loadedFile, version));
+    }
+
     @Test
     public void schema15_testEvidence() throws Exception {
         Version version = Version.VERSION_15;
diff --git a/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java b/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java
index 759486eff..3a4035239 100644
--- a/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java
+++ b/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java
@@ -24,6 +24,7 @@ import org.cyclonedx.exception.ParseException;
 import org.cyclonedx.generators.BomGeneratorFactory;
 import org.cyclonedx.generators.json.BomJsonGenerator;
 import org.cyclonedx.generators.xml.*;
+import org.cyclonedx.model.Attribute;
 import org.cyclonedx.model.Bom;
 import org.cyclonedx.model.Component;
 import org.cyclonedx.model.ExtensibleType;
@@ -411,6 +412,62 @@ public class BomXmlGeneratorTest {
         assertTrue(parser.isValid(loadedFile, version));
     }
 
+    @Test
+    public void schema16_testExpressions() throws Exception {
+        Version version = Version.VERSION_16;
+        Bom bom = createCommonJsonBom("/1.6/valid-license-expression-1.6.json");
+
+        BomXmlGenerator generator = BomGeneratorFactory.createXml(version, bom);
+        File loadedFile = writeToFile(generator.toXmlString());
+
+        XmlParser parser = new XmlParser();
+        assertTrue(parser.isValid(loadedFile, version));
+    }
+
+    @Test
+    public void schema16_testAttestations() throws Exception {
+        Version version = Version.VERSION_16;
+        Bom bom = createCommonJsonBom("/1.6/valid-attestation-1.6.json");
+
+        BomXmlGenerator generator = BomGeneratorFactory.createXml(version, bom);
+        File loadedFile = writeToFile(generator.toXmlString());
+
+        XmlParser parser = new XmlParser();
+        assertTrue(parser.isValid(loadedFile, version));
+    }
+
+    @Test
+    public void schema16_testAttestations_xml() throws Exception {
+        Version version = Version.VERSION_16;
+        Bom bom = createCommonBomXml("/1.6/valid-attestation-1.6.xml");
+        addSignature(bom);
+
+        BomXmlGenerator generator = BomGeneratorFactory.createXml(version, bom);
+        File loadedFile = writeToFile(generator.toXmlString());
+
+        XmlParser parser = new XmlParser();
+        assertTrue(parser.isValid(loadedFile, version));
+    }
+
+    private void addSignature(Bom bom) {
+        List<Attribute> attributes = new ArrayList<>();
+        attributes.add(new Attribute("xmlns", "http://www.w3.org/2000/09/xmldsig#"));
+        ExtensibleType signature = new ExtensibleType("ds", "Signature",  attributes, "");
+        bom.getDeclarations().getAffirmation().getSignatories().get(0).addExtensibleType(signature);
+    }
+
+    @Test
+    public void schema16_testVulnerabilities() throws Exception {
+        Version version = Version.VERSION_16;
+        Bom bom = createCommonJsonBom("/1.6/valid-vulnerability-1.6.json");
+
+        BomXmlGenerator generator = BomGeneratorFactory.createXml(version, bom);
+        File loadedFile = writeToFile(generator.toXmlString());
+
+        XmlParser parser = new XmlParser();
+        assertTrue(parser.isValid(loadedFile, version));
+    }
+
     @Test
     public void schema15_testEvidence() throws Exception {
         Version version = Version.VERSION_15;