Reading & Writing Data
This guide explains how to read, write, and convert OSCAL documents using liboscal-java.
One of the core capabilities of liboscal-java is format-agnostic serialization—the ability to read and write OSCAL documents in XML, JSON, and YAML formats using the same Java objects. This means you can:
- Load OSCAL documents in any format and work with them as strongly-typed Java objects
- Convert between formats by reading in one format and writing in another
- Process documents without needing to know or care about the original format
- Output documents in whichever format your downstream tools require
The library handles all format-specific details automatically. Whether your input is XML, JSON, or YAML, you get the same Catalog, Profile, or SystemSecurityPlan object.
Before diving into code, understand these core concepts:
OscalBindingContext- The entry point for all serialization operations. Use the singleton instance viaOscalBindingContext.instance().IDeserializer<T>- Reads a specific document type (e.g.,Catalog) from a file, URL, or streamISerializer<T>- Writes a specific document type to a file or streamFormat- Enum specifying the data format:Format.XML,Format.JSON, orFormat.YAML
import dev.metaschema.oscal.lib.OscalBindingContext;
import dev.metaschema.oscal.lib.model.Catalog;
import dev.metaschema.databind.io.Format;
import dev.metaschema.databind.io.IDeserializer;
import java.nio.file.Path;
OscalBindingContext context = OscalBindingContext.instance();
// Read JSON
IDeserializer<Catalog> deserializer = context.newDeserializer(
Format.JSON, Catalog.class);
Catalog catalog = deserializer.deserialize(Path.of("catalog.json"));
// Read XML
deserializer = context.newDeserializer(Format.XML, Catalog.class);
catalog = deserializer.deserialize(Path.of("catalog.xml"));
// Read YAML
deserializer = context.newDeserializer(Format.YAML, Catalog.class);
catalog = deserializer.deserialize(Path.of("catalog.yaml"));
import java.net.URI;
IDeserializer<Catalog> deserializer = context.newDeserializer(
Format.JSON, Catalog.class);
Catalog catalog = deserializer.deserialize(
URI.create("https://example.com/catalog.json").toURL());
import java.io.InputStream;
try (InputStream is = getClass().getResourceAsStream("/catalog.json")) {
IDeserializer<Catalog> deserializer = context.newDeserializer(
Format.JSON, Catalog.class);
Catalog catalog = deserializer.deserialize(is,
URI.create("classpath:/catalog.json"));
}
Detect format from file extension:
Path file = Path.of("document.json");
Format format = Format.valueOf(file); // Returns Format.JSON
IDeserializer<Catalog> deserializer = context.newDeserializer(
format, Catalog.class);
import dev.metaschema.databind.io.ISerializer;
ISerializer<Catalog> serializer = context.newSerializer(
Format.JSON, Catalog.class);
serializer.serialize(catalog, Path.of("output.json"));
import java.io.OutputStream;
import java.nio.file.Files;
try (OutputStream os = Files.newOutputStream(Path.of("output.json"))) {
ISerializer<Catalog> serializer = context.newSerializer(
Format.JSON, Catalog.class);
serializer.serialize(catalog, os);
}
import java.io.StringWriter;
StringWriter writer = new StringWriter();
ISerializer<Catalog> serializer = context.newSerializer(
Format.JSON, Catalog.class);
serializer.serialize(catalog, writer);
String json = writer.toString();
// Read XML
IDeserializer<Catalog> xmlReader = context.newDeserializer(
Format.XML, Catalog.class);
Catalog catalog = xmlReader.deserialize(Path.of("catalog.xml"));
// Write JSON
ISerializer<Catalog> jsonWriter = context.newSerializer(
Format.JSON, Catalog.class);
jsonWriter.serialize(catalog, Path.of("catalog.json"));
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
public void convertDirectory(Path inputDir, Path outputDir,
Format inputFormat, Format outputFormat) throws IOException {
OscalBindingContext context = OscalBindingContext.instance();
try (Stream<Path> files = Files.list(inputDir)) {
files.filter(p -> Format.valueOf(p) == inputFormat)
.forEach(inputPath -> {
try {
// Read
IDeserializer<Catalog> reader = context.newDeserializer(
inputFormat, Catalog.class);
Catalog catalog = reader.deserialize(inputPath);
// Write
String outputName = inputPath.getFileName().toString()
.replaceAll("\\.[^.]+$", outputFormat.getDefaultExtension());
Path outputPath = outputDir.resolve(outputName);
ISerializer<Catalog> writer = context.newSerializer(
outputFormat, Catalog.class);
writer.serialize(catalog, outputPath);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
}
}
import dev.metaschema.oscal.lib.model.SystemSecurityPlan;
IDeserializer<SystemSecurityPlan> deserializer = context.newDeserializer(
Format.JSON, SystemSecurityPlan.class);
SystemSecurityPlan ssp = deserializer.deserialize(Path.of("ssp.json"));
// Access SSP content
System.out.println("System Name: " +
ssp.getSystemCharacteristics().getSystemName());
import dev.metaschema.oscal.lib.model.Profile;
IDeserializer<Profile> deserializer = context.newDeserializer(
Format.JSON, Profile.class);
Profile profile = deserializer.deserialize(Path.of("profile.json"));
// Access imports
profile.getImports().forEach(imp ->
System.out.println("Imports: " + imp.getHref()));
import dev.metaschema.oscal.lib.model.ComponentDefinition;
IDeserializer<ComponentDefinition> deserializer = context.newDeserializer(
Format.JSON, ComponentDefinition.class);
ComponentDefinition compDef = deserializer.deserialize(
Path.of("component.json"));
import dev.metaschema.databind.io.DeserializationException;
try {
Catalog catalog = deserializer.deserialize(Path.of("catalog.json"));
} catch (DeserializationException e) {
// Handle parsing errors
System.err.println("Failed to parse: " + e.getMessage());
} catch (IOException e) {
// Handle I/O errors
System.err.println("Failed to read file: " + e.getMessage());
}
- Use try-with-resources for streams
- Detect format from extension using
Format.valueOf(Path) - Reuse the binding context - don't create new instances
- Handle exceptions appropriately for your use case
- Close resources properly when using streams
Continue learning about liboscal-java with these related guides:
- Resolving Profiles - Resolve profiles to catalogs
- Executing Metapath - Query OSCAL data
- Validating with Constraints - Validate content

