Implementation:Haifengl Smile Read Object API
Overview
The Read.object() static method is the primary API for deserializing trained Smile ML models from .sml files. It reads a binary file produced by Write.object(), reconstructs the serialized Java object graph using ObjectInputStream, and returns the result as a generic Object. The caller then casts it to the appropriate type (typically smile.model.Model).
Source Location
| Item | Location |
|---|---|
| Read interface | base/src/main/java/smile/io/Read.java (Lines 52-59) |
| Write interface | base/src/main/java/smile/io/Write.java (Lines 54-60) |
| Model interface | core/src/main/java/smile/model/Model.java |
Import Statements
import smile.io.Read;
import smile.io.Write;
import java.nio.file.Path;
import java.io.IOException;
External Dependencies
| Dependency | Package | Purpose |
|---|---|---|
| Java Serialization | java.io.ObjectInputStream |
Deserializes object from byte stream |
| Java Serialization | java.io.ObjectOutputStream |
Serializes object to byte stream (Write side) |
| Java NIO | java.nio.file.Files, java.nio.file.Path |
File I/O operations |
Type
API Doc
API Signature
Read.object() -- Deserialization
public interface Read {
/**
* Reads a serialized object from a file.
* @param path the file path.
* @return the serialized object.
* @throws IOException when fails to read the stream.
* @throws ClassNotFoundException when fails to load the class.
*/
static Object object(Path path) throws IOException, ClassNotFoundException;
}
Write.object() -- Serialization
public interface Write {
/**
* Writes a serializable object to a file.
* @param o the object to serialize.
* @param path the file path.
* @throws IOException when fails to write the stream.
*/
static void object(Serializable o, Path path) throws IOException;
}
Inputs and Outputs
| Method | Inputs | Outputs | Exceptions |
|---|---|---|---|
Read.object() |
Path path -- absolute or relative path to a .sml file |
Object -- the deserialized object (cast to Model at runtime) |
IOException if file cannot be read; ClassNotFoundException if the serialized class is not on the classpath
|
Write.object() |
Serializable o -- the object to persist; Path path -- destination file |
void |
IOException if file cannot be written
|
Implementation Details
The Read.object() implementation is straightforward:
static Object object(Path path) throws IOException, ClassNotFoundException {
InputStream file = Files.newInputStream(path);
ObjectInputStream in = new ObjectInputStream(file);
Object o = in.readObject();
in.close();
file.close();
return o;
}
Step-by-step breakdown:
- Opens an
InputStreamto the file at the givenPathusingFiles.newInputStream(). - Wraps the raw stream in an
ObjectInputStreamwhich handles the Java serialization protocol. - Calls
readObject()to reconstruct the full object graph from the binary data. - Closes both streams explicitly.
- Returns the reconstructed object as a generic
Object.
The corresponding Write.object() mirrors this process:
static void object(Serializable o, Path path) throws IOException {
OutputStream file = Files.newOutputStream(path);
ObjectOutputStream out = new ObjectOutputStream(file);
out.writeObject(o);
out.close();
file.close();
}
Usage Examples
Saving a Trained Model
import smile.io.Write;
import smile.model.Model;
import smile.data.formula.Formula;
import java.nio.file.Path;
// Train a classification model
Formula formula = Formula.lhs("species");
var model = Model.classification("random-forest", formula, irisData, null, params);
// Add metadata tags
model.setProperty(Model.ID, "iris-classifier");
model.setProperty(Model.VERSION, "2");
// Serialize to .sml file
Write.object(model, Path.of("/models/iris-classifier.sml"));
Loading a Model for Inference
import smile.io.Read;
import smile.model.Model;
import smile.model.ClassificationModel;
import java.nio.file.Path;
// Deserialize the model
Object obj = Read.object(Path.of("/models/iris-classifier.sml"));
// Cast to the Model interface
Model model = (Model) obj;
// Inspect metadata
System.out.println("Algorithm: " + model.algorithm()); // "random-forest"
System.out.println("Schema: " + model.schema());
System.out.println("ID: " + model.getTag(Model.ID)); // "iris-classifier"
System.out.println("Version: " + model.getTag(Model.VERSION)); // "2"
// Use for prediction (via ClassificationModel)
if (model instanceof ClassificationModel cm) {
int prediction = cm.predict(inputTuple);
}
How InferenceService Uses Read.object()
In the serve module, InferenceService calls Read.object() at startup to load models:
private void loadModel(Path path) {
try {
logger.infof("Loading model from '%s'", path);
var obj = Read.object(path); // <-- deserialization happens here
if (obj instanceof Model dummy) {
var model = new InferenceModel(dummy, path);
models.put(model.id(), model);
} else {
logger.errorf("'%s' is not a valid model", path);
}
} catch (Exception ex) {
logger.errorf(ex, "Failed to load model '%s'", path);
}
}
The loaded object is validated with instanceof Model before being wrapped in an InferenceModel and registered in the model map.