codepapu
the playbook

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 entity and mapping-table hints, with 1-N / N-N cardinality and a deletion policy (prevent / disassociate / cascade).
  • Scope — entities with groupId default 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:

properties
morphix.read.only=false
morphix.batch.size=100
morphix.notify.on.job=true
# morphix.sync.webhook.url=https://your-sync-endpoint.example/hook

Accuracy rules

  1. Support matrix before execute.
  2. No silent column or relationship drop.
  3. Every explicit skip is audited.
  4. External reference code = legacy primary key.
  5. Reconcile after migrate, with PASS / FAIL.
  6. Per-row failures go to quarantine.
  7. 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:

text
morphix-batch-<namespace>/
  client-extension.yaml
  batch/00-object-folder.batch-engine-data.json
  batch/01-object-definition.batch-engine-data.json
  README.md

The 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 *LocalServiceImpl logic, 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:

bash
cd morphix
./gradlew :modules:liferay-morphix:deploy
  1. Sign in as admin → Control Panel → Objects → Morphix.
  2. Discover — upload a service.xml (or the Low sample).
  3. Analyze — review fields, relationships, scope, mode → Run Dry-Run.
  4. Execute — Create + Migrate → type I_UNDERSTAND → wait for COMPLETED.
  5. 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.