diff --git a/src/main/java/org/cyclonedx/generators/xml/BomXmlGenerator.java b/src/main/java/org/cyclonedx/generators/xml/BomXmlGenerator.java index e135dd69f..bc0f29beb 100644 --- a/src/main/java/org/cyclonedx/generators/xml/BomXmlGenerator.java +++ b/src/main/java/org/cyclonedx/generators/xml/BomXmlGenerator.java @@ -140,6 +140,7 @@ public String toXmlString() throws GeneratorException { * * @return a String of the BoM * @since 1.1.0 + * */ @Override public String toString() { 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 cd9971809..24f08dae2 100644 --- a/src/main/java/org/cyclonedx/model/component/crypto/AlgorithmProperties.java +++ b/src/main/java/org/cyclonedx/model/component/crypto/AlgorithmProperties.java @@ -5,8 +5,8 @@ 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.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import org.cyclonedx.model.component.crypto.enums.CertificationLevel; @@ -16,7 +16,6 @@ import org.cyclonedx.model.component.crypto.enums.Mode; import org.cyclonedx.model.component.crypto.enums.Padding; import org.cyclonedx.model.component.crypto.enums.Primitive; -import org.cyclonedx.util.deserializer.CertificationLevelDeserializer; @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_EMPTY) @@ -44,8 +43,7 @@ public class AlgorithmProperties private ImplementationPlatform implementationPlatform; - @JsonDeserialize(using = CertificationLevelDeserializer.class) - private CertificationLevel certificationLevel; + private List certificationLevel; private Mode mode; @@ -97,11 +95,14 @@ public void setImplementationPlatform(final ImplementationPlatform implementatio this.implementationPlatform = implementationPlatform; } - public CertificationLevel getCertificationLevel() { + @JacksonXmlElementWrapper(useWrapping = false) + @JacksonXmlProperty(localName = "certificationLevel") + @JsonProperty("certificationLevel") + public List getCertificationLevel() { return certificationLevel; } - public void setCertificationLevel(final CertificationLevel certificationLevel) { + public void setCertificationLevel(final List certificationLevel) { this.certificationLevel = certificationLevel; } diff --git a/src/main/java/org/cyclonedx/model/formulation/common/AbstractType.java b/src/main/java/org/cyclonedx/model/formulation/common/AbstractType.java index c537e169f..8e2561898 100644 --- a/src/main/java/org/cyclonedx/model/formulation/common/AbstractType.java +++ b/src/main/java/org/cyclonedx/model/formulation/common/AbstractType.java @@ -16,7 +16,7 @@ public abstract class AbstractType extends ExtensibleElement private ResourceReferenceChoice source; private ResourceReferenceChoice target; private ResourceReferenceChoice resource; - private List environmentVars; + private EnvironmentVars environmentVars; private AttachmentText data; private List properties; @@ -44,13 +44,12 @@ public void setResource(final ResourceReferenceChoice resource) { this.resource = resource; } - @JacksonXmlElementWrapper(localName = "environmentVars") - public List getEnvironmentVars() { + public EnvironmentVars getEnvironmentVars() { return environmentVars; } - public void setEnvironmentVars(final List environmentVars) { + public void setEnvironmentVars(final EnvironmentVars environmentVars) { this.environmentVars = environmentVars; } diff --git a/src/main/java/org/cyclonedx/model/formulation/common/EnvVariableChoice.java b/src/main/java/org/cyclonedx/model/formulation/common/EnvVariableChoice.java deleted file mode 100644 index 87066cfd8..000000000 --- a/src/main/java/org/cyclonedx/model/formulation/common/EnvVariableChoice.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.cyclonedx.model.formulation.common; - -import java.util.Objects; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; -import org.cyclonedx.model.Property; -import org.cyclonedx.util.deserializer.EnvVariableChoiceDeserializer; - -@JsonIgnoreProperties(ignoreUnknown = true) -@JsonInclude(JsonInclude.Include.NON_EMPTY) -@JsonDeserialize(using = EnvVariableChoiceDeserializer.class) -public class EnvVariableChoice -{ - @JacksonXmlProperty(localName = "value") - private String value; - - @JacksonXmlProperty(localName = "environmentVar") - private Property environmentVar; - - public String getValue() { - return value; - } - - public void setValue(final String value) { - this.value = value; - } - - public Property getEnvironmentVar() { - return environmentVar; - } - - public void setEnvironmentVar(final Property environmentVar) { - this.environmentVar = environmentVar; - } - - @Override - public boolean equals(final Object object) { - if (this == object) { - return true; - } - if (!(object instanceof EnvVariableChoice)) { - return false; - } - EnvVariableChoice that = (EnvVariableChoice) object; - return Objects.equals(value, that.value) && Objects.equals(environmentVar, that.environmentVar); - } - - @Override - public int hashCode() { - return Objects.hash(value, environmentVar); - } -} \ No newline at end of file diff --git a/src/main/java/org/cyclonedx/model/formulation/common/EnvironmentVars.java b/src/main/java/org/cyclonedx/model/formulation/common/EnvironmentVars.java new file mode 100644 index 000000000..a9c3a0338 --- /dev/null +++ b/src/main/java/org/cyclonedx/model/formulation/common/EnvironmentVars.java @@ -0,0 +1,26 @@ +package org.cyclonedx.model.formulation.common; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.cyclonedx.util.deserializer.EnvironmentVarsDeserializer; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_EMPTY) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") +@JsonDeserialize(using = EnvironmentVarsDeserializer.class) +public class EnvironmentVars +{ + private List choices; + + public List getChoices() { + return choices; + } + + public void setChoices(List choices) { + this.choices = choices; + } +} \ No newline at end of file diff --git a/src/main/java/org/cyclonedx/util/deserializer/AbstractDataTypeDeserializer.java b/src/main/java/org/cyclonedx/util/deserializer/AbstractDataTypeDeserializer.java index 5471d130f..5fa0b39fd 100644 --- a/src/main/java/org/cyclonedx/util/deserializer/AbstractDataTypeDeserializer.java +++ b/src/main/java/org/cyclonedx/util/deserializer/AbstractDataTypeDeserializer.java @@ -18,18 +18,20 @@ */ package org.cyclonedx.util.deserializer; -import java.util.ArrayList; +import java.io.IOException; import java.util.List; +import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; + import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.DeserializationContext; import org.cyclonedx.model.Property; import org.cyclonedx.model.formulation.common.AbstractType; -import org.cyclonedx.model.formulation.common.EnvVariableChoice; +import org.cyclonedx.model.formulation.common.EnvironmentVars; import org.cyclonedx.model.formulation.common.ResourceReferenceChoice; public abstract class AbstractDataTypeDeserializer @@ -37,19 +39,18 @@ public abstract class AbstractDataTypeDeserializer protected final ObjectMapper objectMapper = new ObjectMapper(); - protected void setEnvironmentVars(final JsonNode node, AbstractType data) throws JsonProcessingException { - JsonNode nodes = node.get("environmentVars"); - List environmentVars = new ArrayList<>(); - - if (nodes != null) { - ArrayNode environmentVarsNode = DeserializerUtils.getArrayNode(nodes, objectMapper); - for (JsonNode envVarNode : environmentVarsNode) { - EnvVariableChoice envVar = objectMapper.treeToValue(envVarNode, EnvVariableChoice.class); - environmentVars.add(envVar); - } - } + private final EnvironmentVarsDeserializer environmentVarsDeserializer = new EnvironmentVarsDeserializer(); - data.setEnvironmentVars(environmentVars); + protected void setEnvironmentVars( + final JsonNode node, + AbstractType data, + JsonParser jsonParser, + DeserializationContext ctxt) throws IOException + { + JsonNode nodes = node.get("environmentVars"); + JsonParser nodeParser = nodes.traverse(jsonParser.getCodec()); + EnvironmentVars envVar = environmentVarsDeserializer.deserialize(nodeParser, ctxt); + data.setEnvironmentVars(envVar); } protected void setReference(JsonNode node, String fieldName, AbstractType type) throws JsonProcessingException { diff --git a/src/main/java/org/cyclonedx/util/deserializer/CertificationLevelDeserializer.java b/src/main/java/org/cyclonedx/util/deserializer/CertificationLevelDeserializer.java deleted file mode 100644 index f77a7c8f0..000000000 --- a/src/main/java/org/cyclonedx/util/deserializer/CertificationLevelDeserializer.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.cyclonedx.util.deserializer; - -import java.io.IOException; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonNode; -import org.cyclonedx.model.component.crypto.enums.CertificationLevel; - -public class CertificationLevelDeserializer - extends JsonDeserializer -{ - @Override - public CertificationLevel deserialize(JsonParser parser, DeserializationContext context) throws IOException { - JsonNode node = parser.getCodec().readTree(parser); - JsonNode certificationLevelNode = node.has("certificationLevel") ? node.get("certificationLevel") : node; - - String certificationLevelText = certificationLevelNode.isArray() ? - certificationLevelNode.get(0).asText() : - certificationLevelNode.asText(); - - return CertificationLevel.fromString(certificationLevelText); - } -} \ No newline at end of file diff --git a/src/main/java/org/cyclonedx/util/deserializer/EnvVariableChoiceDeserializer.java b/src/main/java/org/cyclonedx/util/deserializer/EnvVariableChoiceDeserializer.java deleted file mode 100644 index 725360011..000000000 --- a/src/main/java/org/cyclonedx/util/deserializer/EnvVariableChoiceDeserializer.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of CycloneDX Core (Java). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * Copyright (c) OWASP Foundation. All Rights Reserved. - */ -package org.cyclonedx.util.deserializer; - -import java.io.IOException; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonNode; -import org.cyclonedx.model.Property; -import org.cyclonedx.model.formulation.common.EnvVariableChoice; - -public class EnvVariableChoiceDeserializer - extends JsonDeserializer -{ - @Override - public EnvVariableChoice deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { - JsonNode node = jsonParser.getCodec().readTree(jsonParser); - EnvVariableChoice envReferenceChoice = new EnvVariableChoice(); - - if(node.isObject()) { - if (node.has("value") && node.has("name")) { - Property prop = createProperty(node); - envReferenceChoice.setEnvironmentVar(prop); - } - else if (node.has("environmentVar")) { - JsonNode envVarNode = node.get("environmentVar"); - Property prop = createProperty(envVarNode); - envReferenceChoice.setEnvironmentVar(prop); - } - } else { - envReferenceChoice.setValue(node.asText()); - } - return envReferenceChoice; - } - - private Property createProperty(JsonNode envVarNode){ - Property prop = new Property(); - - if (envVarNode.has("name")) { - String name = envVarNode.get("name").asText(); - prop.setName(name); - } - if (envVarNode.has("")) { - String value = envVarNode.get("").asText(); - prop.setValue(value); - } else if (envVarNode.has("value")) { - String value = envVarNode.get("value").asText(); - prop.setValue(value); - } - return prop; - } -} diff --git a/src/main/java/org/cyclonedx/util/deserializer/EnvironmentVarsDeserializer.java b/src/main/java/org/cyclonedx/util/deserializer/EnvironmentVarsDeserializer.java new file mode 100644 index 000000000..4a2ad90f8 --- /dev/null +++ b/src/main/java/org/cyclonedx/util/deserializer/EnvironmentVarsDeserializer.java @@ -0,0 +1,108 @@ +/* + * This file is part of CycloneDX Core (Java). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) OWASP Foundation. All Rights Reserved. + */ +package org.cyclonedx.util.deserializer; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import org.cyclonedx.model.Property; + +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.cyclonedx.model.formulation.common.EnvironmentVars; + +import java.util.ArrayList; +import java.util.List; + +public class EnvironmentVarsDeserializer extends StdDeserializer { + + public EnvironmentVarsDeserializer() { + this(null); + } + + public EnvironmentVarsDeserializer(Class vc) { + super(vc); + } + + @Override + public EnvironmentVars deserialize(JsonParser jp, DeserializationContext ctxt) + throws IOException{ + JsonNode node = jp.getCodec().readTree(jp); + EnvironmentVars environmentVars = new EnvironmentVars(); + List choices = new ArrayList<>(); + + if (node.isObject()) { + processObject(node, choices); + } + else if (node.isArray()) { + for (JsonNode n : node) { + processObject(n, choices); + } + } + else { + choices.add(node.asText()); + } + + environmentVars.setChoices(choices); + return environmentVars; + } + + private void processObject(JsonNode node, List choices ){ + if (node.has("environmentVar") && node.has("value")) { + JsonNode envVarNode = node.get("environmentVar"); + Property environmentVar = createProperty(envVarNode); + choices.add(environmentVar); + choices.add(node.get("value").asText()); + } + else if (node.has("value")) { + if (node.has("name")) { + Property environmentVar = createProperty(node); + choices.add(environmentVar); + } + else { + choices.add(node.get("value").asText()); + } + } + else if (node.has("environmentVar")) { + JsonNode envVarNode = node.get("environmentVar"); + Property environmentVar = createProperty(envVarNode); + choices.add(environmentVar); + } else if(node.isTextual()) { + choices.add(node.asText()); + } + } + + private Property createProperty(JsonNode envVarNode){ + Property prop = new Property(); + + if (envVarNode.has("name")) { + String name = envVarNode.get("name").asText(); + prop.setName(name); + } + if (envVarNode.has("")) { + String value = envVarNode.get("").asText(); + prop.setValue(value); + } else if (envVarNode.has("value")) { + String value = envVarNode.get("value").asText(); + prop.setValue(value); + } + return prop; + } +} diff --git a/src/main/java/org/cyclonedx/util/deserializer/InputTypeDeserializer.java b/src/main/java/org/cyclonedx/util/deserializer/InputTypeDeserializer.java index c4bed2f8e..3d8e355e9 100644 --- a/src/main/java/org/cyclonedx/util/deserializer/InputTypeDeserializer.java +++ b/src/main/java/org/cyclonedx/util/deserializer/InputTypeDeserializer.java @@ -26,10 +26,8 @@ import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; import org.cyclonedx.model.AttachmentText; -import org.cyclonedx.model.Property; import org.cyclonedx.model.formulation.common.InputType; import org.cyclonedx.model.formulation.common.InputType.Parameter; -import org.cyclonedx.model.formulation.common.ResourceReferenceChoice; public class InputTypeDeserializer extends AbstractDataTypeDeserializer { @@ -41,13 +39,13 @@ public InputType deserialize(JsonParser jsonParser, DeserializationContext deser InputType inputType = new InputType(); setSourceAndTarget(node, inputType); - createInputDataInfo(node, inputType); + createInputDataInfo(node, inputType, jsonParser, deserializationContext); setProperties(node, inputType); return inputType; } - private void createInputDataInfo(JsonNode node, InputType inputType) + private void createInputDataInfo(JsonNode node, InputType inputType, JsonParser jsonParser, DeserializationContext ctxt) throws IOException { if (node.has("resource")) { @@ -57,7 +55,7 @@ private void createInputDataInfo(JsonNode node, InputType inputType) List parameters = objectMapper.convertValue(parametersNode, new TypeReference>() {}); inputType.setParameters(parameters); } else if (node.has("environmentVars")) { - setEnvironmentVars(node, inputType); + setEnvironmentVars(node, inputType, jsonParser, ctxt); } else if (node.has("data")) { JsonNode dataNode = node.get("data"); AttachmentText data = objectMapper.treeToValue(dataNode, AttachmentText.class); diff --git a/src/main/java/org/cyclonedx/util/deserializer/OutputTypeDeserializer.java b/src/main/java/org/cyclonedx/util/deserializer/OutputTypeDeserializer.java index 92d29a391..2cf4d7cb5 100644 --- a/src/main/java/org/cyclonedx/util/deserializer/OutputTypeDeserializer.java +++ b/src/main/java/org/cyclonedx/util/deserializer/OutputTypeDeserializer.java @@ -19,18 +19,13 @@ package org.cyclonedx.util.deserializer; import java.io.IOException; -import java.util.List; import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; import org.cyclonedx.model.AttachmentText; -import org.cyclonedx.model.Property; import org.cyclonedx.model.formulation.common.OutputType; import org.cyclonedx.model.formulation.common.OutputType.OutputTypeEnum; -import org.cyclonedx.model.formulation.common.ResourceReferenceChoice; public class OutputTypeDeserializer extends AbstractDataTypeDeserializer { @@ -43,7 +38,7 @@ public OutputType deserialize(JsonParser jsonParser, DeserializationContext dese OutputType outputType = new OutputType(); setSourceAndTarget(node, outputType); - createOutputDataInfo(node, outputType); + createOutputDataInfo(node, outputType, deserializationContext, jsonParser); setProperties(node, outputType); if(node.has("type")) { @@ -55,12 +50,14 @@ public OutputType deserialize(JsonParser jsonParser, DeserializationContext dese return outputType; } - private void createOutputDataInfo(JsonNode node, OutputType outputType) throws JsonProcessingException { + private void createOutputDataInfo(JsonNode node, OutputType outputType, DeserializationContext ctxt, JsonParser jsonParser) + throws IOException + { if (node.has("resource")) { setResource(node, outputType); } else if (node.has("environmentVars")) { - setEnvironmentVars(node, outputType); + setEnvironmentVars(node, outputType, jsonParser, ctxt); } else if (node.has("data")) { JsonNode dataNode = node.get("data"); diff --git a/src/main/java/org/cyclonedx/util/serializer/AbstractDataTypeSerializer.java b/src/main/java/org/cyclonedx/util/serializer/AbstractDataTypeSerializer.java deleted file mode 100644 index abfd857f3..000000000 --- a/src/main/java/org/cyclonedx/util/serializer/AbstractDataTypeSerializer.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.cyclonedx.util.serializer; - -import java.io.IOException; -import java.util.List; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import org.cyclonedx.model.formulation.common.AbstractType; -import org.cyclonedx.model.formulation.common.EnvVariableChoice; - - -public abstract class AbstractDataTypeSerializer extends StdSerializer -{ - - public AbstractDataTypeSerializer(Class t) { - super(t); - } - - protected void parseEnvironmentVars(final JsonGenerator jsonGenerator, final List vars) - throws IOException - { - jsonGenerator.writeArrayFieldStart("environmentVars"); - for (EnvVariableChoice envVarChoice : vars) { - if (envVarChoice.getEnvironmentVar() != null) { - jsonGenerator.writeStartObject(); - jsonGenerator.writeObjectField("environmentVar", envVarChoice.getEnvironmentVar()); - jsonGenerator.writeEndObject(); - } - else if (envVarChoice.getValue() != null) { - jsonGenerator.writeStartObject(); - jsonGenerator.writeObjectField("value", envVarChoice.getValue()); - jsonGenerator.writeEndObject(); - } - } - jsonGenerator.writeEndArray(); - } - - protected void writeField(JsonGenerator jsonGenerator, String fieldName, Object fieldValue) throws IOException { - if (fieldValue != null) { - jsonGenerator.writeFieldName(fieldName); - jsonGenerator.writeObject(fieldValue); - } - } - -} diff --git a/src/main/java/org/cyclonedx/util/serializer/EnvironmentVarsSerializer.java b/src/main/java/org/cyclonedx/util/serializer/EnvironmentVarsSerializer.java new file mode 100644 index 000000000..3f0c3bffa --- /dev/null +++ b/src/main/java/org/cyclonedx/util/serializer/EnvironmentVarsSerializer.java @@ -0,0 +1,97 @@ +package org.cyclonedx.util.serializer; + +import java.io.IOException; +import java.util.List; + +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.cyclonedx.model.Property; +import org.cyclonedx.model.formulation.common.EnvironmentVars; + +public class EnvironmentVarsSerializer + extends StdSerializer +{ + private final boolean isXml; + + public EnvironmentVarsSerializer(boolean isXml) { + this(null, isXml); + } + + public EnvironmentVarsSerializer(Class t, boolean isXml) { + super(t); + this.isXml = isXml; + } + + @Override + public void serialize(EnvironmentVars value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) + throws IOException { + + List choices = value.getChoices(); + + if (isXml && jsonGenerator instanceof ToXmlGenerator) { + ToXmlGenerator xmlGenerator = (ToXmlGenerator) jsonGenerator; + serializeXml(choices, xmlGenerator); + } else { + serializeJson(choices, jsonGenerator); + } + } + + private void serializeXml(List choices, ToXmlGenerator xmlGenerator) throws IOException { + xmlGenerator.writeFieldName("environmentVars"); + if (choices.size() == 1 && choices.get(0) instanceof String) { + xmlGenerator.writeStartObject(); + xmlGenerator.writeStringField("value", (String) choices.get(0)); + xmlGenerator.writeEndObject(); + } else { + xmlGenerator.writeStartObject(); + for (Object choice : choices) { + if (choice instanceof Property) { + xmlGenerator.writeFieldName("environmentVar"); + xmlGenerator.writeStartObject(); + Property prop = (Property) choice; + xmlGenerator.setNextIsAttribute(true); + xmlGenerator.writeFieldName("name"); + xmlGenerator.writeString(prop.getName()); + xmlGenerator.setNextIsAttribute(false); + + xmlGenerator.setNextIsUnwrapped(true); + xmlGenerator.writeStringField("", prop.getValue()); + xmlGenerator.writeEndObject(); + } else if (choice instanceof String) { + xmlGenerator.writeFieldName("value"); + xmlGenerator.writeString((String) choice); + } + } + xmlGenerator.writeEndObject(); + } + } + + private void serializeJson(List choices, JsonGenerator jsonGenerator) throws IOException { + jsonGenerator.writeFieldName("environmentVars"); + jsonGenerator.writeStartArray(); + if (choices.size() == 1 && choices.get(0) instanceof String) { + jsonGenerator.writeString((String) choices.get(0)); + } else { + + for (Object choice : choices) { + if (choice instanceof Property) { + jsonGenerator.writeStartObject(); + Property property = (Property) choice; + jsonGenerator.writeStringField("name", property.getName()); + jsonGenerator.writeStringField("value", property.getValue()); + jsonGenerator.writeEndObject(); + } else if (choice instanceof String) { + jsonGenerator.writeString((String) choice); + } + } + } + jsonGenerator.writeEndArray(); + } + + @Override + public Class handledType() { + return EnvironmentVars.class; + } +} \ No newline at end of file diff --git a/src/main/java/org/cyclonedx/util/serializer/InputTypeSerializer.java b/src/main/java/org/cyclonedx/util/serializer/InputTypeSerializer.java index 3b433c1be..7fc253c95 100644 --- a/src/main/java/org/cyclonedx/util/serializer/InputTypeSerializer.java +++ b/src/main/java/org/cyclonedx/util/serializer/InputTypeSerializer.java @@ -4,11 +4,12 @@ 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.cyclonedx.model.formulation.common.InputType; public class InputTypeSerializer - extends AbstractDataTypeSerializer + extends StdSerializer { private final boolean isXml; @@ -26,31 +27,31 @@ public void serialize(InputType value, JsonGenerator jsonGenerator, SerializerPr throws IOException { if (isXml && jsonGenerator instanceof ToXmlGenerator) { ToXmlGenerator xmlGenerator = (ToXmlGenerator) jsonGenerator; - createInputChoice(value, xmlGenerator); + createInputChoice(value, xmlGenerator, serializerProvider); } else { - createInputChoice(value, jsonGenerator); + createInputChoice(value, jsonGenerator, serializerProvider); } } - private void createInputChoice(final InputType input, final JsonGenerator jsonGenerator) + private void createInputChoice(final InputType input, final JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeStartObject(); if (input.getResource() != null) { jsonGenerator.writeFieldName("resource"); - jsonGenerator.writeObject( input.getResource()); + jsonGenerator.writeObject(input.getResource()); } else if (input.getParameters() != null && !input.getParameters().isEmpty()) { jsonGenerator.writeFieldName("parameters"); - jsonGenerator.writeObject( input.getParameters()); + jsonGenerator.writeObject(input.getParameters()); } - else if (input.getEnvironmentVars() != null && !input.getEnvironmentVars().isEmpty()) { - parseEnvironmentVars(jsonGenerator, input.getEnvironmentVars()); + else if (input.getEnvironmentVars() != null) { + new EnvironmentVarsSerializer(isXml).serialize(input.getEnvironmentVars(), jsonGenerator, serializerProvider); } else if (input.getData() != null) { jsonGenerator.writeFieldName("data"); - jsonGenerator.writeObject( input.getData()); + jsonGenerator.writeObject(input.getData()); } writeField(jsonGenerator, "source", input.getSource()); @@ -60,6 +61,13 @@ else if (input.getData() != null) { jsonGenerator.writeEndObject(); } + protected void writeField(JsonGenerator jsonGenerator, String fieldName, Object fieldValue) throws IOException { + if (fieldValue != null) { + jsonGenerator.writeFieldName(fieldName); + jsonGenerator.writeObject(fieldValue); + } + } + @Override public Class handledType() { return InputType.class; diff --git a/src/main/java/org/cyclonedx/util/serializer/OutputTypeSerializer.java b/src/main/java/org/cyclonedx/util/serializer/OutputTypeSerializer.java index add9cb16d..a231cef4e 100644 --- a/src/main/java/org/cyclonedx/util/serializer/OutputTypeSerializer.java +++ b/src/main/java/org/cyclonedx/util/serializer/OutputTypeSerializer.java @@ -4,11 +4,12 @@ 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.cyclonedx.model.formulation.common.OutputType; public class OutputTypeSerializer - extends AbstractDataTypeSerializer + extends StdSerializer { private final boolean isXml; @@ -26,16 +27,13 @@ public void serialize(OutputType value, JsonGenerator jsonGenerator, SerializerP throws IOException { if (isXml && jsonGenerator instanceof ToXmlGenerator) { ToXmlGenerator xmlGenerator = (ToXmlGenerator) jsonGenerator; - xmlGenerator.writeStartObject(); - xmlGenerator.writeFieldName("input"); - createOutputChoice(value, xmlGenerator); - xmlGenerator.writeEndObject(); + createOutputChoiceXml(value, xmlGenerator, serializerProvider); } else { - createOutputChoice(value, jsonGenerator); + createOutputChoiceJson(value, jsonGenerator, serializerProvider); } } - private void createOutputChoice(final OutputType output, final JsonGenerator jsonGenerator) + private void createOutputChoiceJson(final OutputType output, final JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeStartObject(); @@ -44,8 +42,8 @@ private void createOutputChoice(final OutputType output, final JsonGenerator jso jsonGenerator.writeFieldName("resource"); jsonGenerator.writeObject( output.getResource()); } - else if (output.getEnvironmentVars() != null && !output.getEnvironmentVars().isEmpty()) { - parseEnvironmentVars(jsonGenerator, output.getEnvironmentVars()); + else if (output.getEnvironmentVars() != null) { + new EnvironmentVarsSerializer(isXml).serialize(output.getEnvironmentVars(), jsonGenerator, serializerProvider); } else if (output.getData() != null) { jsonGenerator.writeFieldName("data"); @@ -59,7 +57,48 @@ else if (output.getData() != null) { jsonGenerator.writeEndObject(); } + private void createOutputChoiceXml(final OutputType output, final ToXmlGenerator xmlGenerator, SerializerProvider serializerProvider) + throws IOException + { + xmlGenerator.writeStartObject(); + + if (output.getResource() != null) { + xmlGenerator.writeFieldName("resource"); + xmlGenerator.writeObject( output.getResource()); + } + else if (output.getEnvironmentVars() != null) { + new EnvironmentVarsSerializer(isXml).serialize(output.getEnvironmentVars(), xmlGenerator, serializerProvider); + } + else if (output.getData() != null) { + xmlGenerator.writeFieldName("data"); + xmlGenerator.writeObject( output.getData()); + } + if (output.getType() != null) { + xmlGenerator.writeFieldName("type"); + xmlGenerator.writeObject(output.getType()); + } + if (output.getSource() != null) { + xmlGenerator.writeFieldName("source"); + xmlGenerator.writeObject(output.getSource()); + } + if (output.getTarget() != null) { + xmlGenerator.writeFieldName("target"); + xmlGenerator.writeObject(output.getTarget()); + } + if (output.getProperties() != null) { + xmlGenerator.writeFieldName("properties"); + xmlGenerator.writeObject( output.getProperties()); + } + xmlGenerator.writeEndObject(); + } + + protected void writeField(JsonGenerator jsonGenerator, String fieldName, Object fieldValue) throws IOException { + if (fieldValue != null) { + jsonGenerator.writeFieldName(fieldName); + jsonGenerator.writeObject(fieldValue); + } + } @Override public Class handledType() { diff --git a/src/main/java/org/cyclonedx/util/serializer/SignatorySerializer.java b/src/main/java/org/cyclonedx/util/serializer/SignatorySerializer.java index ea8ca3c46..4322c907b 100644 --- a/src/main/java/org/cyclonedx/util/serializer/SignatorySerializer.java +++ b/src/main/java/org/cyclonedx/util/serializer/SignatorySerializer.java @@ -62,8 +62,7 @@ private void serializeJson(final JsonGenerator gen, final Signatory signatory) if (signatory.getSignature() != null && !isXml) { shouldSerialize = true; - } - else if (signatory.getExternalReference() != null && signatory.getOrganization() != null) { + } else if (signatory.getExternalReference() != null && signatory.getOrganization() != null) { shouldSerialize = true; } diff --git a/src/test/java/org/cyclonedx/BomJsonGeneratorTest.java b/src/test/java/org/cyclonedx/BomJsonGeneratorTest.java index ae1207108..09aea41ee 100644 --- a/src/test/java/org/cyclonedx/BomJsonGeneratorTest.java +++ b/src/test/java/org/cyclonedx/BomJsonGeneratorTest.java @@ -362,6 +362,42 @@ public void schema15_testEvidence() throws Exception { assertTrue(parser.isValid(loadedFile, version)); } + @Test + public void schema16_testFormulation() throws Exception { + Version version = Version.VERSION_16; + Bom bom = createCommonXmlBom("/1.6/valid-formulation-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_testCrypto() throws Exception { + Version version = Version.VERSION_16; + Bom bom = createCommonXmlBom("/1.6/valid-cryptography-full-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_testML() throws Exception { + Version version = Version.VERSION_16; + Bom bom = createCommonXmlBom("/1.6/valid-machine-learning-1.6.xml"); + + BomJsonGenerator generator = BomGeneratorFactory.createJson(version, bom); + File loadedFile = writeToFile(generator.toJsonString()); + + JsonParser parser = new JsonParser(); + assertTrue(parser.isValid(loadedFile, version)); + } + private void assertLicenseInformation(Bom bom, Version version) { //First Component diff --git a/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java b/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java index 3a4035239..6f6c54b5a 100644 --- a/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java +++ b/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java @@ -480,6 +480,54 @@ public void schema15_testEvidence() throws Exception { assertTrue(parser.isValid(loadedFile, version)); } + @Test + public void schema16_testFormulation() throws Exception { + Version version = Version.VERSION_16; + Bom bom = createCommonJsonBom("/1.6/valid-formulation-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_testCompositions() throws Exception { + Version version = Version.VERSION_16; + Bom bom = createCommonJsonBom("/1.6/valid-compositions-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_testCrypto() throws Exception { + Version version = Version.VERSION_16; + Bom bom = createCommonJsonBom("/1.6/valid-cryptography-full-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_testML() throws Exception { + Version version = Version.VERSION_16; + Bom bom = createCommonJsonBom("/1.6/valid-machine-learning-1.6.json"); + + BomXmlGenerator generator = BomGeneratorFactory.createXml(version, bom); + File loadedFile = writeToFile(generator.toXmlString()); + + XmlParser parser = new XmlParser(); + assertTrue(parser.isValid(loadedFile, version)); + } + private void assertLicenseInformation(Bom bom, Version version) { //First Component diff --git a/src/test/java/org/cyclonedx/parsers/JsonParserTest.java b/src/test/java/org/cyclonedx/parsers/JsonParserTest.java index c4762d95c..94edd03a6 100644 --- a/src/test/java/org/cyclonedx/parsers/JsonParserTest.java +++ b/src/test/java/org/cyclonedx/parsers/JsonParserTest.java @@ -559,7 +559,7 @@ public void schema16_cbom() throws Exception { assertEquals("128", ap.getParameterSetIdentifier()); assertEquals(ExecutionEnvironment.SOFTWARE_PLAIN_RAM, ap.getExecutionEnvironment()); assertEquals(ImplementationPlatform.X86_64, ap.getImplementationPlatform()); - assertEquals(CertificationLevel.NONE, ap.getCertificationLevel()); + assertEquals(CertificationLevel.NONE, ap.getCertificationLevel().get(0)); assertEquals(Mode.GCM, ap.getMode()); assertEquals(128, ap.getClassicalSecurityLevel()); assertEquals(1, ap.getNistQuantumSecurityLevel()); diff --git a/src/test/java/org/cyclonedx/parsers/XmlParserTest.java b/src/test/java/org/cyclonedx/parsers/XmlParserTest.java index c4a00fc47..c2aadeadd 100644 --- a/src/test/java/org/cyclonedx/parsers/XmlParserTest.java +++ b/src/test/java/org/cyclonedx/parsers/XmlParserTest.java @@ -704,7 +704,7 @@ public void schema16_cbom() throws Exception { assertEquals("128", ap.getParameterSetIdentifier()); assertEquals(ExecutionEnvironment.SOFTWARE_PLAIN_RAM, ap.getExecutionEnvironment()); assertEquals(ImplementationPlatform.X86_64, ap.getImplementationPlatform()); - assertEquals(CertificationLevel.NONE, ap.getCertificationLevel()); + assertEquals(CertificationLevel.NONE, ap.getCertificationLevel().get(0)); assertEquals(Mode.GCM, ap.getMode()); assertEquals(128, ap.getClassicalSecurityLevel()); assertEquals(1, ap.getNistQuantumSecurityLevel()); diff --git a/src/test/resources/1.6/valid-formulation-1.6.json b/src/test/resources/1.6/valid-formulation-1.6.json index ce49ece6d..0f8ee5a6f 100644 --- a/src/test/resources/1.6/valid-formulation-1.6.json +++ b/src/test/resources/1.6/valid-formulation-1.6.json @@ -250,7 +250,7 @@ "workspaces": [ { "bom-ref": "workspace-2", - "uid": "workspace-1", + "uid": "workspace-2", "name": "My workspace", "aliases": [ "default-workspace" ], "description": "Description here",