Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 22 additions & 18 deletions GETTING-STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ The `SpdxModelFactory.init()` will not overwrite an already initialized default

### Programmatically Creating SPDX Data

See the [Spdx3Example.java](src/examples/java/org/spdx/example/Spdx3Example.java) file for the complete code example.

All SPDX elements are required to have a unique SPDX ID which is an Object URI. In the SPDX Java libraries, this is commonly referred to as the `objectUri` to avoid confusion with the SPDX 2.X version short SPDX IDs.

A good practice is to create a common prefix to use for your programmatic session. The prefix should be unique to the session. There are convenience methods in the library to append identifiers unique to the model store.
Expand All @@ -73,42 +75,44 @@ In these examples, we'll use:
String prefix = "https://org.spdx.spdxdata/899b1918-f72a-4755-9215-6262b3c346df/";
```

Since SPDX 3.0 requires creation info on every element, the easiest way to start is to use the SPDX 3 model convenience method `SpdxModelClassFactory.createCreationInfo(...)` which will create the `Agent` and `CreationInfo` classes which can be added to all the subsequent elements.
Since SPDX 3.0 requires creation info on every element, the easiest way to start is to use the SPDX 3 model convenience method `SpdxModelFactory.createCreationInfoV3(...)` which will create the `Agent` and `CreationInfo` classes which can be added to all the subsequent elements.

For example:

```java
CreationInfo creationInfo = SpdxModelClassFactory.createCreationInfo(
CreationInfo creationInfo = SpdxModelFactoryV3.createCreationInfo(
modelStore, prefix + "Agent/Gary01123", "Gary O'Neall",
copyManager);
```

We're now ready to create our first SPDX element. You can start anywhere, but let's start with an SBOM element.

There is a factory method you can use to get started:
Every SPDX object has builder methods for all the SPDX objects.

```java
Sbom sbom = SpdxModelClassFactory.getModelObject(modelStore,
prefix + "sbom/mysbom", SpdxConstantsV3.SOFTWARE_SBOM,
copyManager, true, prefix);
```

Let's not forget to add the creation info:
To build the initial SBOM, we can call the builder method for Sbom.
The only parameter is the Object URI for the element - we'll use the same prefix for consistency.
We might as well add a name while we're at it.

```java
sbom.setCreationInfo(creationInfo);
Sbom sbom = creationInfo.createSbom(prefix + "sbom/mysbom")
.setName("My SBOM")
.build();
```

From here on, things get easier. We can get and set properties to the sbom we just created.
Note that the builder add all the creation information from the
object calling the builder method, so no need to add the creationInfo,
modelStore or copyManager.

From here on out, we can just use the builder methods to create objects and the getter / setter methods.

If we want to create another SPDX object or element, we can use the builder convenience methods available to all SPDX objects. For example, if we want to create a package to add to the SBOM we can call:
For example, if we want to create a package to add to the SBOM as a root we can call:

```java
sbom.getElements().add(
sbom.createSpdxPackage(prefix + "package/mypackage")
.setName("Package Name")
.build()
);
SpdxPackage pkg = sbom.createSpdxPackage(prefix + "package/mypackage")
.setName("Package Name")
.build();
sbom.getElements().add(pkg);
sbom.getRootElements().add(pkg);
```

The model store, creation info, copy manager, and prefix information will all be copied from the sbom allowing you to focus just on the properties you need to add.
Expand Down
19 changes: 19 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,25 @@
<artifactId>dependency-check-maven</artifactId>
<version>${dependency-check-maven.version}</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/examples/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
Expand Down
81 changes: 81 additions & 0 deletions src/examples/java/org/spdx/example/Spdx3Example.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2025 Source Auditor Inc.
* SPDX-FileType: SOURCE
* SPDX-License-Identifier: Apache-2.0
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
*/

package org.spdx.example;

import org.spdx.core.IModelCopyManager;
import org.spdx.core.InvalidSPDXAnalysisException;
import org.spdx.library.ModelCopyManager;
import org.spdx.library.SpdxModelFactory;
import org.spdx.library.model.v3_0_1.SpdxModelClassFactoryV3;
import org.spdx.library.model.v3_0_1.core.CreationInfo;
import org.spdx.library.model.v3_0_1.software.Sbom;
import org.spdx.library.model.v3_0_1.software.SpdxPackage;
import org.spdx.storage.simple.InMemSpdxStore;

/**
* Example which creates an SBOM from scratch
* NOTE: Snippets from this file are used in the GETTING_STARTED.md file - any changes to this file
* should update the GETTING_STARTED.md file
*/
public class Spdx3Example {

public static Sbom createSbomFromScratch() throws InvalidSPDXAnalysisException {
// Before executing any of the model class methods, the model versions need to be initialized
SpdxModelFactory.init();
// SPDX data is stored in a "model store" and copying between model stores requires a copy manager.
// A simple store is provided in the java library
InMemSpdxStore modelStore = new InMemSpdxStore();
IModelCopyManager copyManager = new ModelCopyManager();

// All SPDX elements are required to have a unique SPDX ID which is an Object URI.
// In the SPDX Java libraries, this is commonly referred to as the objectUri to avoid confusion with the SPDX 2.X version short SPDX IDs.
// A good practice is to create a common prefix to use for your programmatic session.
// The prefix should be unique to the session.
// There are convenience methods in the library to append identifiers unique to the model store.
String prefix = "https://org.spdx.spdxdata/899b1918-f72a-4755-9215-6262b3c346df/";

// Since SPDX 3.0 requires creation info on every element,
// the easiest way to start is to use the SPDX 3 model convenience method SpdxModelClassFactoryV3.createCreationInfo(...)
// which will create the Agent and CreationInfo classes which can be added to all the subsequent elements.
CreationInfo creationInfo = SpdxModelClassFactoryV3.createCreationInfo(
modelStore, prefix + "Agent/Gary01123", "Gary O'Neall",
copyManager);

// Every SPDX object has builder methods for all the SPDX objects.
// To build the initial SBOM, we can call the builder method for Sbom.
// The only parameter is the Object URI for the element - we'll use the same prefix for consistency.
Sbom sbom = creationInfo.createSbom(prefix + "sbom/mysbom")
// we might as well add a name while we're at it. - you can add any of the property during the build
// Don't worry if you don't have all the properties, they can be added later
.setName("My SBOM")
.build();

// From here on out, we can just use the builder methods to create objects and the getter / setter methods
// on the objects to update any properties.
// Let's create an SPDX Package and add it to the SBOM and make it the root
SpdxPackage pkg = sbom.createSpdxPackage(prefix + "package/mypackage")
.setName("Package Name")
.build();
sbom.getElements().add(pkg);
sbom.getRootElements().add(pkg);

return sbom;
}

}
34 changes: 34 additions & 0 deletions src/test/java/org/spdx/example/Spdx3ExampleTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2025 Source Auditor Inc.
* SPDX-FileType: SOURCE
* SPDX-License-Identifier: Apache-2.0
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
*/

package org.spdx.example;

import junit.framework.TestCase;
import org.spdx.core.InvalidSPDXAnalysisException;
import org.spdx.library.model.v3_0_1.software.Sbom;

import java.util.List;

public class Spdx3ExampleTest extends TestCase {

public void testCreateSbomFromScratch() throws InvalidSPDXAnalysisException {
Sbom result = Spdx3Example.createSbomFromScratch();
List<String> verify = result.verify();
assertTrue(verify.isEmpty());
}
}