Skip the Headless API: Calling Liferay Objects Directly with ObjectEntryManager
This is LR Tools’ rewrite of a post by Laxit Khanpara on Liferay.dev covering a service-layer shortcut that’s easy to miss if you’ve only ever touched Liferay Objects through their REST API.
Two ways to talk to a Liferay Object
Liferay Objects let you model and manage custom data without a traditional Service Builder module, and most developers reach for the Headless REST API to work with them — an endpoint pattern like /o/c/{objectName} that’s well documented and works well for frontend applications and external integrations. What’s less obvious is that those Headless APIs are themselves built on top of an internal service layer, and backend code running inside an OSGi module can call that same layer directly — ObjectEntryManager — skipping the HTTP round-trip entirely.
What ObjectEntryManager actually is
ObjectEntryManager is the internal service that handles Object operations: creating entries, retrieving data, updating entries, deleting records, and searching or filtering. Four pieces are involved:
import com.liferay.object.model.ObjectDefinition;
import com.liferay.object.rest.dto.v1_0.ObjectEntry;
import com.liferay.object.rest.manager.v1_0.ObjectEntryManager;
import com.liferay.object.rest.manager.v1_0.ObjectEntryManagerRegistry;
ObjectDefinition represents the Object’s schema, ObjectEntry represents its data, ObjectEntryManager provides the CRUD operations, and ObjectEntryManagerRegistry resolves the correct manager implementation for a given Object.
Using it, step by step
Inject the registry:
@Reference
private ObjectEntryManagerRegistry objectEntryManagerRegistry;
Look up the Object you’re working with:
ObjectDefinition objectDefinition = ObjectDefinitionLocalServiceUtil.getObjectDefinitionByExternalReferenceCode("YOUR_OBJECT_ERC", companyId);
Get the manager for that Object’s storage type:
ObjectEntryManager objectEntryManager = objectEntryManagerRegistry.getObjectEntryManager(objectDefinition.getStorageType());
Create an entry:
Map<String, Serializable> values = new HashMap<>();
values.put("name", "John Doe");
values.put("email", "john@example.com");
long userId = contextUser.getUserId(); // or themeDisplay.getUserId()
ObjectEntry objectEntry = objectEntryManager.addObjectEntry(
userId, objectDefinition, values, null, null
);
Retrieve a single entry, or a page of entries:
ObjectEntry entry = objectEntryManager.getObjectEntry(
objectDefinition, entryId
);
Page<ObjectEntry> page = objectEntryManager.getObjectEntries(
objectDefinition, null, null, null, Pagination.of(1, 10)
);
Pagination works the way you’d expect:
Pagination pagination = Pagination.of(1, 20);
Page<ObjectEntry> page = objectEntryManager.getObjectEntries(
objectDefinition, null, null, null, pagination
);
Additional filtering and sorting can be layered on from there depending on what the use case needs.
Why this is actually faster
Going through the Headless API means: application → HTTP request → Headless API → service layer → database. Calling ObjectEntryManager directly collapses that to: application → ObjectEntryManager → database. Removing the HTTP hop is the entire performance argument — it’s not a different set of capabilities, just a shorter path to the same service layer the REST API already calls internally.
Permissions still apply
ObjectEntryManager doesn’t bypass permission checks — it enforces them against whatever user context you pass in:
long userId = contextUser.getUserId();
Always pass the actual current user’s context, confirm their roles genuinely have the Object permissions the operation needs, and avoid reaching for an admin user unless there’s a real reason to. Permissions are evaluated the same way regardless of which path — REST or direct service call — you took to get there.
When to reach for it, and when not to
ObjectEntryManager is the right call inside an OSGi module implementing backend business logic, when performance matters, or when you want to avoid an unnecessary internal HTTP call. It’s the wrong call for public or external APIs, frontend code that expects REST endpoints, anything requiring OAuth-based access, or situations where a loosely-coupled architecture is actually what you want.
| Use case | Approach |
|---|---|
| Frontend or external systems | Headless APIs |
| Backend processing and internal logic | ObjectEntryManager |
The takeaway
Headless APIs remain the right tool for external and frontend integration — nothing here argues against them. For backend-only processing running inside an OSGi module, though, going straight to the service layer through ObjectEntryManager is a faster, simpler path to the same data, without giving up permission enforcement along the way.
This article is LR Tools’ rewrite of the original post by Laxit Khanpara — read it on Liferay.dev for the author’s own framing.
Dieser Artikel ist adaptiert von: Laxit Khanpara, Liferay.dev