Now that you’ve imported your plugin project to Liferay Dev Studio DXP, you probably see compile errors for some of the Liferay classes it uses. These classes are listed as undefined classes or unresolved symbols because they’ve been moved, renamed, or removed. As a part of modularization in Liferay DXP, many of these classes reside in new modules.
You must resolve all of these Liferay classes for your plugin. Some of the class changes are quick and easy to fix. Changes involving the new modules require more effort to resolve, but doing so is still straightforward.
Liferay class changes and required adaptations are described here:
-
Class moved to a package that’s in the classpath: This change is common and easy to fix. Since the module is already on your classpath, you need only update the class import. You can do this by using the Liferay Code Upgrade Tool or by organizing imports in Dev Studio DXP. The Upgrade Planner reports each moved class for you to address one by one. Organizing imports in Dev Studio DXP automatically resolves multiple classes at once.
It’s typically faster to resolve moved classes using the mentioned Eclipse feature. Since Liferay Dev Studio DXP is based on Eclipse, you can generate imports of classes in your classpath with the Organize Imports keyboard sequence Ctrl-Shift-o. Comment out or remove any imports marked as errors, then press Ctrl-Shift-o. If there’s only one match for the import, Dev Studio DXP automatically generates its import statement. Otherwise, a wizard appears that lets you select the correct import.
-
Class moved to a module that’s not in the classpath: You must resolve the new module as a dependency for your project. This requires identifying the module and specifying your project’s dependency on it.
-
Class replaced or removed: The class has been replaced by another class or removed from the product. The Upgrade Planner (discussed later) explains what happened to the class, how to handle the change, and why the change was made.
Resolving a class that’s moved within your classpath is straightforward. Consider resolving such classes first. The remainder of this tutorial explains how to resolve the last two cases and starts with configuring your plugin project to declare the modules it needs.
Identifying Module Dependencies
Before Liferay DXP 7.1, all the platform APIs were in portal-service.jar
. Many
of these APIs are now in independent modules. Modularization has resulted in
many benefits, as described in the article
Benefits of Liferay DXP 7.1 for Liferay Portal 6 Developers.
One such advantage is that these API modules can evolve separately from the
platform kernel. They also simplify future upgrades. For example, instead of
having to check all of Liferay’s APIs, each module’s
Semantic Versioning
indicates whether the module contains any backwards-incompatible changes. You
need only adapt your code to such modules (if any).
As part of the modularization, portal-service.jar
has been renamed
appropriately to portal-kernel.jar
, as it continues to hold the portal
kernel’s APIs.
Each app module consists of a set of classes that are highly cohesive and have a specific purpose, such as providing the app’s API, implementation, or UI. The app modules are therefore much easier to understand. Next, you’ll track down the modules that now hold the classes referenced by your plugin.
The reference article
Classes Moved from portal-service.jar
contains a table that maps each class moved from portal-service.jar
to its new
module. The table includes each class’s new package and symbolic name
(artifact ID). You’ll use this information to configure your plugin’s
dependencies on these modules.
Your plugin might reference classes that are in Liferay utility modules formerly
known as util-java
, util-bridges
, util-taglib
, or util-slf4j
.
The following table shows each Liferay utility module’s symbolic name.
Liferay Utility | Symbolic Name (Artifact ID) |
---|---|
util-bridges | com.liferay.util.bridges |
util-java | com.liferay.util.java |
util-slf4j | com.liferay.util.slf4j |
util-taglib | com.liferay.util.taglib |
You can use Liferay DXP’s App Manager, Felix Gogo Shell, or module JAR file manifests to find versions of modules deployed on your Liferay DXP instance.
Resolving Dependencies
Now that you have the module artifact IDs and versions, you can make the modules available to your plugin project. The modules your plugin uses must be available to it at compile time and run time. Here are two options for resolving module dependencies in your traditional plugin project:
Option 1: Use a dependency management tool
Option 2: Manage dependencies manually
The next sections explain and demonstrate these options.
Using a Dependency Management Tool
Dependency management tools such as Ant/Ivy, Maven, and Gradle facilitate acquiring Java artifacts that provide packages your plugins need. They can download artifacts from public repositories or from internal repositories you configure as a proxies. From internal repositories you can audit dependencies.
The Liferay Plugins SDK provides an Ant/Ivy infrastructure. You declare
your dependencies in an ivy.xml
file in your plugin project’s root folder. The
Plugins SDK’s Ant tasks leverage the ivy.xml
file and the Plugins SDK’s Ivy
scripts to download the specified modules and their dependencies and make them
available to your plugin.
Here’s an example dependency element for the Liferay Journal API module, version 2.0.1:
<dependency name="com.liferay.journal.api" org="com.liferay" rev="2.0.1" />
Each dependency includes the module’s name (name
), organization (org
), and
revision number (rev
). The
Configuring Dependencies
tutorial explains how to determine the module’s organization (org
).
At compile time, Ivy downloads the dependency JAR files to a cache folder so you can compile against them.
At deployment, Liferay DXP’s WAB Generator creates an OSGi Web Application Bundle (WAB) for the plugin. The WAB generator detects the Java packages your plugin uses and declares dependencies on them. Your plugin can use the packages once a registered OSGi service provides them.
If your project doesn’t already have an ivy.xml
file, you can get one by
creating a new plugin project in Liferay Dev Studio DXP and copying the ivy.xml
file it
generates.
Here’s an example of an ivy.xml
file from the Liferay Portal 6.2 Knowledge
Base portlet:
<?xml version="1.0"?>
<ivy-module
version="2.0"
xmlns:m2="http://ant.apache.org/ivy/maven"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd"
>
<info module="knowledge-base-portlet" organisation="com.liferay">
<extends extendType="configurations,description,info" location="${sdk.dir}/ivy.xml" module="com.liferay.sdk" organisation="com.liferay" revision="latest.integration" />
</info>
<dependencies defaultconf="default">
<dependency org="com.liferay" name="com.liferay.markdown.converter" rev="1.0.2" />
</dependencies>
</ivy-module>
The Plugins SDK works with project Ivy files to store artifacts and make them accessible to your plugin projects.
If you don’t want to use Ivy or some other dependency management framework, you can store dependency JARs within your plugin project manually. You’ll learn about this next.
Managing Plugin Dependencies Manually
Plugins rely on their dependencies’ availability at compile time and run time.
To compile your plugin, you must make sure the dependencies are available in the
plugin’s WEB-INF/lib
folder. To run your plugin, the container must be able to
find them: either 1) the dependency Java packages must already be active in
Liferay DXP’s OSGi framework or 2) the dependency JARs must be included in the WAB
generated for the plugin. Your plugin can use both the JARs it currently has and
the packages Liferay DXP exports.
Using Packages Portal Exports
The Plugins SDK for Liferay Portal 6 provided a way to compile against JARs it
had. You’d specify these JARs in the portal-dependency-jars
property in your
liferay-plugin-package.properties
file. On seeing a plugin’s portal-dependency-jars
list, the Liferay Plugins
SDK copied the JARs into the plugin’s WEB-INF/lib
. The Plugins SDK refrained
from adding the JARs to the plugin WAR. This kept the WARs small for deploying
faster. It was especially useful for deploying WARs remotely or to cluster
nodes.
In Liferay DXP 7.1, the portal-dependency-jars
property is deprecated and
behaves differently from previous versions. Because importing and exporting Java
packages has replaced wholesale use of JARs, modules and WABs can import
packages without concerning themselves with JARs. This means that Liferay DXP
can’t make available to plugins the same Java classes it did in the past.
These files list the packages that the portal exports:
modules/core/portal-bootstrap/system.packages.extra.bnd
file in the GitHub repository. It lists exported packages on separate lines, making them easy to read.META-INF/system.packages.extra.mf
file in[LIFERAY_HOME]/osgi/core/com.liferay.portal.bootstrap.jar
. The file is available in Liferay DXP bundles. It lists exported packages in a paragraph wrapped at 70 columns–they’re harder to read here than in thesystem.packages.extra.bnd
file.
If you’re still using the portal-dependency-jars
property, you may run into
one of the scenarios below. Follow the instructions below the scenario to fix
the issue.
-
I’ve specified a JAR, but in Liferay DXP 7.1 none of the classes are available to my plugin.
Some JARs that Liferay Portal 6.2 used were removed in Liferay DXP 7.1. If you specify them in your
portal-dependency-jars
, Liferay DXP can’t provide them. If you still need them, remove them from theportal-dependency-jars
property and add the JARs you need to your plugin’sWEB-INF/lib
folder. -
I’ve specified JARs, and Liferay DXP 7.1 also exports all the JAR’s packages my plugin imports
Keep the JAR in your
portal-dependency-jars
list. The Plugins SDK copies the JAR to your plugin’sWEB-INF/lib
folder at compile time but refrains from adding the JAR to the plugin WAB. The WAB generated for the plugin imports the packages from a registered provider at run time. -
Liferay DXP 7.1 provides the JAR but doesn’t export a package my plugin imports
Keep the JAR in your
portal-dependency-jars
property. The Plugins SDK copies the JAR to your plugin’sWEB-INF/lib
folder at compile time and adds the JAR to the plugin WAB at deployment.
Understanding Excluded JARs
Portal property module.framework.web.generator.excluded.paths
declares JARs that are stripped from all Liferay DXP generated WABs. These JARs
are excluded from WABs because Liferay DXP provides them already. All JARs listed
for this property are excluded from the WABs, even if the plugins listed the JAR
in their portal-dependency-jars
property.
If your plugin requires different versions of the packages Liferay DXP exports,
you must include them in JARs named differently from the ones
module.framework.web.generator.excluded.paths
excludes.
For example, Liferay DXP’s
system.packages.extra.bnd
file
exports Spring Framework version 4.1.9 packages:
Export-Package:\
...
org.springframework.*;version='4.1.9',\
...
Liferay DXP uses the module.framework.web.generator.excluded.paths
portal
property to exclude their JARs.
module.framework.web.generator.excluded.paths=\
...
WEB-INF/lib/spring-aop.jar,\
WEB-INF/lib/spring-aspects.jar,\
WEB-INF/lib/spring-beans.jar,\
WEB-INF/lib/spring-context.jar,\
WEB-INF/lib/spring-context-support.jar,\
WEB-INF/lib/spring-core.jar,\
WEB-INF/lib/spring-expression.jar,\
WEB-INF/lib/spring-jdbc.jar,\
WEB-INF/lib/spring-jms.jar,\
WEB-INF/lib/spring-orm.jar,\
WEB-INF/lib/spring-oxm.jar,\
WEB-INF/lib/spring-tx.jar,\
WEB-INF/lib/spring-web.jar,\
WEB-INF/lib/spring-webmvc.jar,\
WEB-INF/lib/spring-webmvc-portlet.jar,\
...
To use a different Spring Framework version in your WAB, you must name the
corresponding Spring Framework JARs differently from the glob-patterned JARs
module.framework.web.generator.excluded.paths
lists.
For example, to use Spring Framework version 3.0.7’s Spring AOP JAR, include it
in your plugin’s WEB-INF/lib
but name it something other than
spring-aop.jar
. Adding the version to the JAR name (i.e.,
spring-aop-3.0.7.RELEASE.jar
) differentiates it from the excluded JAR and
prevents it from being stripped from the WAB.
Using Packages Portal Doesn’t Export
You must download and install to your plugin’s WEB-INF/lib
folder JARs that
provide packages Liferay DXP doesn’t export that your plugin requires.
Follow these steps to do this:
-
Go to Maven Central at https://search.maven.org/.
-
Search for the module by its artifact ID and group ID.
-
Navigate the search results to find the version of the module you want.
-
Click the jar link to download the module’s JAR file.
-
Add the JAR to your project’s
WEB-INF/lib
folder.
As you manage module JARs, make sure not to deploy any OSGi framework JARs
or Liferay module JARs (e.g., com.liferay.journal.api.jar
). If you deploy
these, they’ll conflict with the JARs already installed in the OSGi framework.
Identical JARs in two different classloaders can cause class cast exceptions.
The easiest way to exclude such JARs from your plugin’s deployment is to list
them in a deploy-excludes
property in your plugin’s
liferay-plugin-package.properties
. You must otherwise remove the JARs manually
from the plugin WAR file. To exclude JARs in your plugin’s
liferay-plugin-package.properties
file, add an entry like the one below,
replacing the square-bracketed items with the names of JAR files to exclude:
deploy-excludes=\
**/WEB-INF/lib/[module-artifact.jar],\
**/WEB-INF/lib/[another-module-artifact.jar]
For example, here’s an example property that excludes the OSGi framework JAR
osgi.core.jar
and the Liferay app module JAR com.liferay.journal.api.jar
:
deploy-excludes=\
**/WEB-INF/lib/com.liferay.portal.journal.api.jar,\
**/WEB-INF/lib/org.osgi.core.jar
How do you know what modules are already installed in Liferay DXP? If your
Liferay DXP instance has a particular Liferay app suite installed, then don’t
deploy module JARs you know are in that app suite. For example, if the Web
Experience Management App Suite is already installed (which is the case for a
Liferay DXP bundle), then don’t deploy Web Content module JARs such as
com.liferay.journal.api.jar
. Searching for a module in Liferay DXP’s
App Manager
is a sure-fire way to verify existing module installations.