Skip to content

Commit

Permalink
refactor: separate custom marshalling logic from model
Browse files Browse the repository at this point in the history
Signed-off-by: nscuro <[email protected]>
  • Loading branch information
nscuro committed Sep 25, 2022
1 parent 2826fe2 commit 0c2ebff
Show file tree
Hide file tree
Showing 6 changed files with 486 additions and 397 deletions.
207 changes: 0 additions & 207 deletions cyclonedx.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,7 @@
package cyclonedx

import (
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"io"
"regexp"
)

Expand Down Expand Up @@ -98,24 +94,6 @@ func Bool(value bool) *bool {

type BOMReference string

// bomReferenceXML is temporarily used for marshalling and unmarshalling BOMReference instances to and from XML
type bomReferenceXML struct {
Ref string `json:"-" xml:"ref,attr"`
}

func (b BOMReference) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
return e.EncodeElement(bomReferenceXML{Ref: string(b)}, start)
}

func (b *BOMReference) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
bXML := bomReferenceXML{}
if err := d.DecodeElement(&bXML, &start); err != nil {
return err
}
*b = BOMReference(bXML.Ref)
return nil
}

type ComponentType string

const (
Expand Down Expand Up @@ -185,19 +163,6 @@ type Copyright struct {
Text string `json:"text" xml:"-"`
}

func (c Copyright) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
return e.EncodeElement(c.Text, start)
}

func (c *Copyright) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var text string
if err := d.DecodeElement(&text, &start); err != nil {
return err
}
(*c).Text = text
return nil
}

type Credits struct {
Organizations *[]OrganizationalEntity `json:"organizations,omitempty" xml:"organizations>organization,omitempty"`
Individuals *[]OrganizationalContact `json:"individuals,omitempty" xml:"individuals>individual,omitempty"`
Expand All @@ -222,52 +187,6 @@ type Dependency struct {
Dependencies *[]Dependency `xml:"dependency,omitempty"`
}

// dependencyJSON is temporarily used for marshalling and unmarshalling Dependency instances to and from JSON
type dependencyJSON struct {
Ref string `json:"ref"`
DependsOn []string `json:"dependsOn,omitempty"`
}

func (d Dependency) MarshalJSON() ([]byte, error) {
if d.Dependencies == nil || len(*d.Dependencies) == 0 {
return json.Marshal(&dependencyJSON{
Ref: d.Ref,
})
}

dependencyRefs := make([]string, len(*d.Dependencies))
for i, dependency := range *d.Dependencies {
dependencyRefs[i] = dependency.Ref
}

return json.Marshal(&dependencyJSON{
Ref: d.Ref,
DependsOn: dependencyRefs,
})
}

func (d *Dependency) UnmarshalJSON(bytes []byte) error {
dependency := new(dependencyJSON)
if err := json.Unmarshal(bytes, dependency); err != nil {
return err
}
d.Ref = dependency.Ref

if len(dependency.DependsOn) == 0 {
return nil
}

dependencies := make([]Dependency, len(dependency.DependsOn))
for i, dep := range dependency.DependsOn {
dependencies[i] = Dependency{
Ref: dep,
}
}
d.Dependencies = &dependencies

return nil
}

type Diff struct {
Text *AttachedText `json:"text,omitempty" xml:"text,omitempty"`
URL string `json:"url,omitempty" xml:"url,omitempty"`
Expand Down Expand Up @@ -394,70 +313,6 @@ type License struct {

type Licenses []LicenseChoice

func (l Licenses) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if len(l) == 0 {
return nil
}

if err := e.EncodeToken(start); err != nil {
return err
}

for _, choice := range l {
if choice.License != nil && choice.Expression != "" {
return fmt.Errorf("either license or expression must be set, but not both")
}

if choice.License != nil {
if err := e.EncodeElement(choice.License, xml.StartElement{Name: xml.Name{Local: "license"}}); err != nil {
return err
}
} else if choice.Expression != "" {
if err := e.EncodeElement(choice.Expression, xml.StartElement{Name: xml.Name{Local: "expression"}}); err != nil {
return err
}
}
}

return e.EncodeToken(start.End())
}

func (l *Licenses) UnmarshalXML(d *xml.Decoder, _ xml.StartElement) error {
licenses := make([]LicenseChoice, 0)

for {
token, err := d.Token()
if err != nil {
if errors.Is(err, io.EOF) {
break
}
return err
}

switch tokenType := token.(type) {
case xml.StartElement:
if tokenType.Name.Local == "expression" {
var expression string
if err = d.DecodeElement(&expression, &tokenType); err != nil {
return err
}
licenses = append(licenses, LicenseChoice{Expression: expression})
} else if tokenType.Name.Local == "license" {
var license License
if err = d.DecodeElement(&license, &tokenType); err != nil {
return err
}
licenses = append(licenses, LicenseChoice{License: &license})
} else {
return fmt.Errorf("unknown element: %s", tokenType.Name.Local)
}
}
}

*l = licenses
return nil
}

type LicenseChoice struct {
License *License `json:"license,omitempty" xml:"-"`
Expression string `json:"expression,omitempty" xml:"-"`
Expand Down Expand Up @@ -599,60 +454,6 @@ const (
SpecVersion1_4 // 1.4
)

func (sv SpecVersion) MarshalJSON() ([]byte, error) {
return json.Marshal(sv.String())
}

func (sv *SpecVersion) UnmarshalJSON(bytes []byte) error {
var v string
err := json.Unmarshal(bytes, &v)
if err != nil {
return err
}

switch v {
case SpecVersion1_0.String():
*sv = SpecVersion1_0
case SpecVersion1_1.String():
*sv = SpecVersion1_1
case SpecVersion1_2.String():
*sv = SpecVersion1_2
case SpecVersion1_3.String():
*sv = SpecVersion1_3
case SpecVersion1_4.String():
*sv = SpecVersion1_4
}

return nil
}

func (sv SpecVersion) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
return e.EncodeElement(sv.String(), start)
}

func (sv *SpecVersion) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var v string
err := d.DecodeElement(&v, &start)
if err != nil {
return err
}

switch v {
case SpecVersion1_0.String():
*sv = SpecVersion1_0
case SpecVersion1_1.String():
*sv = SpecVersion1_1
case SpecVersion1_2.String():
*sv = SpecVersion1_2
case SpecVersion1_3.String():
*sv = SpecVersion1_3
case SpecVersion1_4.String():
*sv = SpecVersion1_4
}

return nil
}

type SWID struct {
Text *AttachedText `json:"text,omitempty" xml:"text,omitempty"`
URL string `json:"url,omitempty" xml:"url,attr,omitempty"`
Expand Down Expand Up @@ -720,11 +521,3 @@ const (
VulnerabilityStatusAffected VulnerabilityStatus = "affected"
VulnerabilityStatusNotAffected VulnerabilityStatus = "unaffected"
)

var xmlNamespaces = map[SpecVersion]string{
SpecVersion1_0: "http://cyclonedx.org/schema/bom/1.0",
SpecVersion1_1: "http://cyclonedx.org/schema/bom/1.1",
SpecVersion1_2: "http://cyclonedx.org/schema/bom/1.2",
SpecVersion1_3: "http://cyclonedx.org/schema/bom/1.3",
SpecVersion1_4: "http://cyclonedx.org/schema/bom/1.4",
}
93 changes: 93 additions & 0 deletions cyclonedx_json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// This file is part of CycloneDX Go
//
// 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 cyclonedx

import "encoding/json"

// dependencyJSON is temporarily used for marshalling and unmarshalling Dependency instances to and from JSON
type dependencyJSON struct {
Ref string `json:"ref"`
DependsOn []string `json:"dependsOn,omitempty"`
}

func (d Dependency) MarshalJSON() ([]byte, error) {
if d.Dependencies == nil || len(*d.Dependencies) == 0 {
return json.Marshal(&dependencyJSON{
Ref: d.Ref,
})
}

dependencyRefs := make([]string, len(*d.Dependencies))
for i, dependency := range *d.Dependencies {
dependencyRefs[i] = dependency.Ref
}

return json.Marshal(&dependencyJSON{
Ref: d.Ref,
DependsOn: dependencyRefs,
})
}

func (d *Dependency) UnmarshalJSON(bytes []byte) error {
dependency := new(dependencyJSON)
if err := json.Unmarshal(bytes, dependency); err != nil {
return err
}
d.Ref = dependency.Ref

if len(dependency.DependsOn) == 0 {
return nil
}

dependencies := make([]Dependency, len(dependency.DependsOn))
for i, dep := range dependency.DependsOn {
dependencies[i] = Dependency{
Ref: dep,
}
}
d.Dependencies = &dependencies

return nil
}

func (sv SpecVersion) MarshalJSON() ([]byte, error) {
return json.Marshal(sv.String())
}

func (sv *SpecVersion) UnmarshalJSON(bytes []byte) error {
var v string
err := json.Unmarshal(bytes, &v)
if err != nil {
return err
}

switch v {
case SpecVersion1_0.String():
*sv = SpecVersion1_0
case SpecVersion1_1.String():
*sv = SpecVersion1_1
case SpecVersion1_2.String():
*sv = SpecVersion1_2
case SpecVersion1_3.String():
*sv = SpecVersion1_3
case SpecVersion1_4.String():
*sv = SpecVersion1_4
}

return nil
}
Loading

0 comments on commit 0c2ebff

Please sign in to comment.