in core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/ObjectManager.java [63:262]
public record ObjectManager(
MetaModelContext mmc,
ChainOfResponsibility<ObjectSpecification, ManagedObject> objectCreator,
ChainOfResponsibility<ProtoObject, ManagedObject> objectLoader,
ChainOfResponsibility<BulkLoadRequest, Can<ManagedObject>> objectBulkLoader,
ChainOfResponsibility<MementoRecreateRequest, ManagedObject> objectDementifier
) implements HasMetaModelContext {
public record BulkLoadRequest(
ObjectSpecification objectSpecification,
Query<?> query) {
}
public record MementoRecreateRequest(
@NonNull ObjectSpecification objectSpecification,
@NonNull ObjectMemento memento) {
}
public ObjectManager(final MetaModelContext mmc) {
this(mmc,
ObjectCreatorFactory.createChain(mmc),
ObjectLoaderFactory.createChain(),
ObjectBulkLoaderFactory.createChain(),
ObjectDementifierFactory.createChain());
}
/**
* Creates and initializes an instance conforming to given request parameters.
* <p>
* Resolves injection-points for the result. (Handles service injection.)
*/
public ManagedObject createObject(final ObjectSpecification objectCreateRequest) {
return objectCreator().handleElseFail(objectCreateRequest);
}
/**
* Loads an instance identified with given request parameters.
* <p>
* Resolves injection-points for the result. (Handles service injection.)
*/
public ManagedObject loadObject(final ProtoObject objectLoadRequest) {
return objectLoader().handleElseFail(objectLoadRequest);
}
/**
* Recovers an object (graph) from given {@code bookmark}.
* <p>
* Resolves injection-points for the result. (Handles service injection.)
* <p>
* Supports alias lookup.
*/
public Optional<ManagedObject> loadObject(final @Nullable Bookmark bookmark) {
if(bookmark==null) {
return Optional.empty();
}
var specLoader = getMetaModelContext().getSpecificationLoader();
return ProtoObject.resolve(specLoader, bookmark)
.map(this::loadObject);
}
/**
* Introduced for serializing action parameter values to bookmarks and vice versa.
* <p>
* Does NOT handle {@link PackedManagedObject}. (Needs to be handled by the caller.)
* @see #debookmark(Bookmark)
*/
public Bookmark bookmark(final @NonNull ManagedObject managedObj) {
return ManagedObjects.bookmark(managedObj)
.orElseGet(()->Bookmark.empty(managedObj.logicalType()));
}
/**
* Introduced for de-serializing action parameter values from bookmarks and vice versa.
* <p>
* Does NOT handle {@link PackedManagedObject}. (Needs to be handled by the caller.)
* @see #bookmark(ManagedObject)
*/
public ManagedObject debookmark(final @NonNull Bookmark bookmark) {
return bookmark.isEmpty()
? ManagedObject.empty(getSpecificationLoader().specForBookmarkElseFail(bookmark))
: loadObjectElseFail(bookmark);
}
/**
* @see #loadObject(Bookmark)
*/
public ManagedObject loadObjectElseFail(final @NonNull Bookmark bookmark) {
var adapter = loadObject(bookmark)
.orElseThrow(() -> new BookmarkNotFoundException(String.format("Bookmark %s was not found.", bookmark)));
if(adapter.specialization().isEntity()) {
_Assert.assertEquals(bookmark, adapter.getBookmark().orElse(null),
()->"object loaded from bookmark must itself return an equal bookmark");
}
return adapter;
}
/**
* Resolves injection-points for the result. (Handles service injection.)
*/
public Can<ManagedObject> queryObjects(final BulkLoadRequest objectQuery) {
return objectBulkLoader().handleElseFail(objectQuery);
}
public Optional<ObjectSpecification> specForPojo(final @Nullable Object pojo) {
if(pojo==null) return Optional.empty();
return specForType(pojo.getClass());
}
@Override
public Optional<ObjectSpecification> specForType(final @Nullable Class<?> domainType) {
return getMetaModelContext().getSpecificationLoader().specForType(domainType);
}
// -- ADAPTING POJOS
/**
* Not suitable for adapting a plural.
* If {@code pojo} is an entity, automatically memoizes its bookmark.
* <p>
* Resolves injection-points for the result. (Handles service injection.)
* <p>
* see also {@link #adapt(Object, Supplier)},
* where the 2nd arg supplies the {@link ObjectSpecification} if known (eg for null args).
*
* @see ManagedObject#adaptSingular(ObjectSpecification, Object)
* @see ManagedObject#adaptParameter(ObjectActionParameter, Object)
* @see ManagedObject#adaptProperty(OneToOneAssociation, Object)
*/
public ManagedObject adapt(final @Nullable Object pojo) {
return adapt(pojo, ()->specForType(Object.class).orElseThrow());
}
/**
* Suitable for adapting a plural.
* If {@code pojo} is an entity, automatically memoizes its bookmark.
* <p>
* Resolves injection-points for the result. (Handles service injection.)
*/
public ManagedObject adapt(
final @Nullable Object pojo,
final @NonNull Supplier<ObjectSpecification> fallbackElementType) {
if(pojo==null) {
ObjectSpecification objectSpecification = fallbackElementType.get();
if (objectSpecification.isSingular()) {
return ManagedObject.empty(objectSpecification);
}
// best we can do?
return ManagedObject.unspecified();
}
if(pojo instanceof ManagedObject) {
// yet ignoring any bookmarking policy, assuming this is not required here
return (ManagedObject) pojo;
}
// could be any pojo, even of a type, that is vetoed for introspection (spec==null)
var spec = specForType(pojo.getClass()).orElse(null);
if(spec==null) {
// best we can do?
return ManagedObject.unspecified();
}
return spec.isSingular()
? ManagedObject.adaptSingular(spec, pojo)
: ManagedObject.packed(
spec.getElementSpecification().orElseGet(fallbackElementType),
_NullSafe.streamAutodetect(pojo)
.map(element->adapt(element))
.collect(Can.toCan()));
}
// -- OBJECT MEMENTOS
public Optional<ObjectMemento> mementify(final @Nullable ManagedObject object) {
return Optional.ofNullable(object)
.flatMap(ManagedObject::getMemento);
}
public ObjectMemento mementifyElseFail(final @NonNull ManagedObject object) {
return object.getMemento()
.orElseThrow(()->
_Exceptions.unrecoverable("failed to create memento for %s", object.objSpec()));
}
public ManagedObject demementify(final @Nullable ObjectMemento memento) {
if(memento==null) return null;
var spec = mmc.getSpecificationLoader()
.specForLogicalType(memento.logicalType())
.orElse(null);
if(spec==null) {
return memento.isEmpty()
? ManagedObject.unspecified()
: null;
}
return objectDementifier().handleElseFail(new MementoRecreateRequest(spec, memento));
}
@Override
public MetaModelContext getMetaModelContext() {
return mmc;
}
}