Completed Object Support
Completed DSL Objects are immutable results of KlumAST construction. Client code may still need to inspect where an
object came from, navigate its ownership structure, or traverse its composed children. KlumObjectSupport is the stable,
Java-first entry point for those operations without exposing the object's internal Model companion.
The facade accepts either a completed root object or any completed DSL Object in its subtree:
import com.blackbuild.klum.ast.runtime.KlumObjectSupport;
import com.blackbuild.klum.ast.runtime.validation.KlumValidationResult;
import java.util.List;
import java.util.Map;
KlumObjectSupport<Deployment> support = KlumObjectSupport.of(deployment);
Deployment object = support.getObject();
String constructionPath = support.getConstructionPath();
String modelPath = support.getModelPath();
KlumObjectSupport.Structure<Deployment> structure = support.getStructure();
Map<String, Service> services = structure.findAll(Service.class);
KlumObjectSupport.Validation<Deployment> validation = support.getValidation();
KlumValidationResult result = validation.getResult();
List<KlumValidationResult> subtreeResults = validation.getSubtreeResults();
The Javadoc for KlumObjectSupport and its nested Structure and Validation helpers is the source of truth for complete
signatures, overloads, return types, and exceptional cases.
Construction and structural model paths
The final 4.0 facade names the Builder/factory call path getConstructionPath(). It is the immutable construction path
through which the object was created. getModelPath() reports the object's structural location in the completed model.
These answer different questions and are not interchangeable.
(See: CompletedObjectSupportDocumentaryTest#'reports distinct construction and structural paths for a completed deployment'.)
given:
@DSL class Deployment {
Service service
}
@DSL class Service {
}
when:
def deployment = Deployment.Create.With {
service {}
}
def deploymentSupport = KlumObjectSupport.of(deployment)
def serviceSupport = KlumObjectSupport.of(deployment.service)
then:
assert deploymentSupport.constructionPath == '$/Deployment.With'
assert serviceSupport.constructionPath == '$/Deployment.With/service'
assert deploymentSupport.modelPath == '<root>'
assert serviceSupport.modelPath == '<root>.service'
There is no public getBreadcrumbPath() alias. BreadcrumbCollector remains an internal implementation name. The
construction path is not provenance: KlumAST does not retain a source-lineage, applied-Template, or lifecycle-event
record.
Traversal methods produce contextual traversal paths. Managed import contributes an import source, and validation records a validation location. Neither is a substitute for the construction or structural model path.
Ownership, paths, and traversal
getStructure() groups operations that inspect the completed composition graph:
- direct and single-owner lookup, owner hierarchy, and nearest ancestors by type;
- full paths from the composition root and relative paths from one object to an owned descendant; and
- typed
findAllandvisittraversal. The public traversal signatures arevisit(Class<R>, BiConsumer<String, R>)andfindAll(Class<R>); the runtime traversal visitor is internal.
Traversal follows composed DSL values only. Owner and LINK edges are not followed, and identity-based cycle protection
ensures that object graphs remain safe even when DSL types override equals.
(See: CompletedObjectSupportDocumentaryTest#'traverses a deployment composition without following linked services'.)
given:
@DSL class Deployment {
Service api
List<Service> services
@Field(FieldType.LINK) Service catalogService
}
@DSL class Service {
@Key String name
@Owner Deployment deployment
}
def catalog = Service.Create.With('catalog') {}
when:
def deployment = Deployment.Create.With {
api('api') {}
services {
service('worker') {}
}
catalogService catalog
}
def structure = KlumObjectSupport.of(deployment).structure
then:
assert structure.getRelativePath(deployment.services[0]) == 'services[0]'
assert KlumObjectSupport.of(deployment.api).structure.singleOwner.get().is(deployment)
assert structure.findAll(Service).keySet() == ['<root>.api', '<root>.services[0]']
Stored validation
(See: CompletedObjectSupportDocumentaryTest#'reads stored validation results for a completed deployment'.)
def deployment = Deployment.Create.With {
service {}
}
def validation = KlumObjectSupport.of(deployment).validation
assert validation.result.issues
assert validation.subtreeResults == [
validation.result,
KlumObjectSupport.of(deployment.service).validation.result
]
getValidation().getResult() returns the result already stored for the target object.
getValidation().getSubtreeResults() reads all stored results for that target and its owned composition subtree.
verify() uses the configured failure level, while verify(level) uses the supplied level. These operations only inspect
lifecycle results: they do not execute InstanceValidators, create results, or mutate recorded issues.
The facade may also start at a subtree:
import java.util.Optional;
KlumObjectSupport<Service> serviceSupport = KlumObjectSupport.of(service);
Optional<Object> owner = serviceSupport.getStructure().getSingleOwner();
String pathFromDeployment = support.getStructure().getRelativePath(service);
Compatibility APIs
StructureUtil remains as a deprecated adapter for existing callers. New completed-object code should use
KlumObjectSupport directly. KlumModelProxy and its raw metadata are internal implementation details and are not a
supported client extension API.
Validator result readers are removed in 4.0 with no compatibility adapter. Completed-object code uses
KlumObjectSupport.getValidation() as described in Validation.