23 July 2026 · 11 min read
Morphix — ServiceBuilderToObject
A Control Panel tool that turns older Service Builder data into modern Liferay Objects, records included — Discover, check what can move, run the move, confirm it arrived, and roll back if something looks wrong.
Morphix — ServiceBuilderToObject is a simple Control Panel tool that turns older Service Builder data into modern Liferay Objects, including the records themselves. You do not need to be a developer to follow it: Discover your model, check what can move, run the move, then confirm everything arrived. Old tables are left in place; if something looks wrong you can roll the new Object data back.
What it is
Morphix ships as a Liferay Workspace OSGi module (com.morphix.web 2.0.0) for Liferay DXP 2026.Q2. Company admins open Control Panel → Objects → Morphix. The UI is native Clay / Lexicon — no custom design system. Source lives on GitHub: codepapu/morphix.
The name comes from morph: take a Service Builder model and change its shape into a Liferay Object.
Why it exists
Plenty of portals still run custom Service Builder modules with their own tables, primary keys, and relationships. Liferay Objects are the modern, headless-friendly model — but moving to them by hand means re-typing every field, writing one-off copy scripts, and hoping the row counts match afterwards.
A migration you cannot count, explain, or undo is not a migration — it is a hope with a deploy button.
The journey
Morphix is a step-by-step wizard. Later tabs stay locked until the earlier steps succeed, so nobody can migrate without a plan and a dry-run first.
Overview — “Are we ready?”
A readiness dashboard: DXP build, database connectivity, whether the Objects API is available, read-only mode, and current Morphix jobs. Confirm the portal can create Objects before you upload anything.
Discover — “What are we morphing?”
Upload your own service.xml or download a sample. Morphix reads the package path, namespace, entities, columns, and relationship hints, blocks portal-core namespaces (com.liferay.*), and builds an Analyze plan automatically.
- Low — one company-scoped entity; the simplest create + migrate.
- Medium — Department → Employee (1-N); parent before child, foreign keys remapped.
- High — site
groupId, localization, an N-N mapping table, and status columns.
Analyze — “What is safe, and how should it map?”
Every column is marked Supported, Partial, or Blocked. You can skip or rename fields; primary keys become the external reference code instead of a field.
- Types — String → Text, boolean → Boolean, int / long / double / Date → Integer / LongInteger / Decimal / Date, status-like columns → Picklist. Blob is Blocked; localized String is Partial.
- Relationships — detected from
entityandmapping-tablehints, with 1-N / N-N cardinality and a deletion policy (prevent / disassociate / cascade). - Scope — entities with
groupIddefault to site, others to company; override per entity. - Mode per entity — Migrate (default), Keep (leave in Service Builder), Defer (later), or Integrate (download a system Object stub instead of copying data).
Run Dry-Run counts rows per entity and summarises supported / partial / blocked / skipped fields. It writes nothing, and Execute stays locked until it has run.
Execute — “Create Objects and move the data”
Choose Create only, Migrate only, or Create + Migrate, pick an Object folder, then type the confirm token I_UNDERSTAND. The job runs in the background and survives a page refresh.
- Creates picklists, Object definitions, fields, and relationships — parents before children — and publishes them.
- Copies rows in dependency order with external reference code = the old primary key, then remaps foreign keys and N-N links.
- Rows that fail go to quarantine — nothing is dropped silently.
- Afterwards you can download a runbook, a batch client extension, a promote package, and Integrate / sync stubs.
Reconcile — “Did everything arrive?”
Per entity, Morphix compares the Service Builder COUNT(*) with the Object entry count, samples external reference codes, and checks relationship and mapping-table counts. You get a PASS / FAIL table, a CSV export, headless REST links, and a smoke-test badge.
Audit & settings
Every important action is appended to data/morphix/audit.jsonl. Guards and defaults come from portal properties:
morphix.read.only=false
morphix.batch.size=100
morphix.notify.on.job=true
# morphix.sync.webhook.url=https://your-sync-endpoint.example/hookAccuracy rules
- Support matrix before execute.
- No silent column or relationship drop.
- Every explicit skip is audited.
- External reference code = legacy primary key.
- Reconcile after migrate, with PASS / FAIL.
- Per-row failures go to quarantine.
- Dry-run before Execute (wizard lock).
Rollback & promote
Every migrated row is recorded on the job. Rollback deletes those Object entries — and only those. Service Builder tables are never dropped or truncated, so the old data is always there to compare against or re-run from.
To move the result to UAT or production, Morphix exports a batch client extension that upserts the Object folder and definitions by external reference code:
morphix-batch-<namespace>/
client-extension.yaml
batch/00-object-folder.batch-engine-data.json
batch/01-object-definition.batch-engine-data.json
README.mdThe promote package bundles that client extension with the runbook, a partition pre-flight report, and a CI script. For pipelines there is a small REST API under /o/morphix/v1.0: /ready, job list and detail, job rollback, and a POST /ci/dry-run-report gate that fails when a service.xml has blocked fields.
Security model
- Company admin / omniadmin only.
- Execute requires the confirm token
I_UNDERSTAND. - Read-only mode keeps Discover and Analyze usable but blocks Create and Migrate.
- Mutating actions are audited.
- Rollback never touches Service Builder tables.
Honest limits
- Rollback handles company-scoped entries reliably; site / depot entries may need manual cleanup.
- The batch client extension export covers scalar fields today — relationships and picklists are follow-ups.
- Integrate and sync stubs are ZIPs you compile and deploy; Morphix does not hot-install generated modules.
- Localized fields migrate as base Text (Partial).
- Out of scope by design: rewriting
*LocalServiceImpllogic, converting JSP UI to Fragments, migrating portal core entities, and dropping old tables.
Ship it
From the workspace root, with liferay.workspace.home.dir pointing at your DXP home:
cd morphix
./gradlew :modules:liferay-morphix:deploy- Sign in as admin → Control Panel → Objects → Morphix.
- Discover — upload a
service.xml(or the Low sample). - Analyze — review fields, relationships, scope, mode → Run Dry-Run.
- Execute — Create + Migrate → type
I_UNDERSTAND→ wait for COMPLETED. - Reconcile — run it and confirm PASS.
Takeaways
- A migration is only done when the counts match — reconcile is a feature, not an afterthought.
- Keep the old tables. Rollback should delete what you created, never what you had.
- Dry-run first, then a typed confirm token — make the risky step deliberate.
- Promote with a batch client extension, not by clicking the same wizard again on every environment.