How To Upgrade Service Builder Modules

Although it's not difficult, it's not as easy as you might hope.

Between major versions of Liferay, the internal structure of Service Builder (SB) modules can change—sometimes subtly, sometimes significantly. These changes might affect how services are implemented, extended, or referenced, and can easily break existing SB modules during an upgrade.

As developers, we often hope that a simple update to gradle.properties is enough. Change the liferay.workspace.product to your new target version, build, deploy… and everything just works.

But if you’re here, you probably already know: it doesn’t.

So let’s walk through the correct and complete process for upgrading Service Builder modules properly—without carrying forward technical debt or breaking runtime behavior.

Step 1: Update the Target Liferay Version

Before doing anything else, update the liferay.workspace.product in your root gradle.properties to reflect your new version of Liferay, whatever that might be.

This tells the workspace which product dependencies to use for building and deploying.

Step 2: Create Brand New SB Modules (Controversial, But Necessary)

Here’s where things might get a little controversial.

Many developers recommend deleting all generated source files and running buildService to regenerate. While that can work, it comes with risks:

  • Old cruft may remain in the module

  • Non-source files (like service descriptors) might retain outdated structure

  • New Liferay version-specific defaults won’t be applied correctly

Instead, I strongly recommend creating fresh SB modules. This ensures a clean slate with no lingering legacy files and full compatibility with the new version.

Use Blade CLI:

$ blade create -t service-builder my-service-2025

It doesn’t matter that the module has a different folder name (e.g., my-service-2025)—the final artifact names will still be defined by the bnd.bnd file.

Step 3: Copy Over Configuration — Carefully

From the old my-service modules:

  1. Copy the bnd.bnd files to the new -api and -service modules.

    Be sure not to lose any directives, such as:

    	-dsannotations-options: inherit	
  2. Copy service metadata selectively :

    Open the old service.xml

    Copy the <namespace>, package-path, <entity> blocks, and <exceptions>

    Do not overwrite the DTD declaration. Service Builder relies on the DTD version to generate version-specific code.
  3. Check for new DTD attributes:

    If upgrading from older versions like 7.1 to 7.4+, newer attributes may exist that you might need to add. In my 7.1 to 7.4 update, I added change-tracking-enabled="false" external-reference-code="false" mvcc-enabled="false" to my entities because I didn't need or want these additional columns or functionality.

Step 4: Run  buildService on the New Modules

Now build your new modules for the first time:

$ blade gw buildService

This will generate:

  • All interfaces and implementations

  • Empty method stubs

  • Clean portlet-model-hints.xml and service.properties

Step 5: Compare and Sync Configuration Files

Verify and sync the following:

  • portlet-model-hints.xml

    Ensure all expected columns and types are present.

    Copy over any old hint settings as needed.
     
  • service.properties

    Copy from the old module to preserve the build number and prevent future deployment errors.

Step 6: Migrate Implementation Logic — Selectively

Now move your implementation logic from the old module carefully and manually:

  • Open the old model/impl and service/impl classes.

  • Copy only your custom methods, business logic, and helper utilities.

  • Do not copy old constructors, annotations, or class declarations.

This avoids bringing in outdated annotations, incorrect inheritance, or unsupported code patterns.

Also copy over:

  • resource-actions (if used)

  • META-INF/custom-sql (for custom queries)

  • Any custom Finder implementation classes

  • Constants, Configuration classes, and model helpers in the -api module

Once done, run buildService again to regenerate the interfaces based on your implementation changes.

Step 7: Compile and Validate the Modules

Build both -api and -service to verify that all your custom methods, references, and imports are valid under the new Liferay version.

Step 8: Deploy and Test

Now deploy the modules to your updated Liferay environment.

  • Verify that the modules deploy without errors

  • Watch for missing dependencies, OSGi errors, or unresolved component issues

  • Use the services in your portal to test:

    • Data access

    • CRUD operations

    • Custom finders

    • JSON/SOAP/GraphQL endpoints (if relevant)

Pay attention to:

  • Log errors (e.g., NPEs, IllegalArgumentException)

  • Unexpected data behavior

  • Permission or localization regressions

Conclusion: Clean Slate, Clean Upgrade

Upgrading SB modules between major versions of Liferay isn’t just about flipping a version flag. It’s about ensuring your services are:

  • Regenerated cleanly

  • Free from outdated configuration and binding

  • Using the latest APIs and conventions

While the process outlined here is more involved, it also ensures that you’re not carrying forward legacy quirks, obsolete code, or platform mismatches.

Once you’ve walked through these steps, your SB modules are truly upgraded—and ready to thrive on your new Liferay version.