The recommended runtime environment for Adobe Experience Manager 6.5 (AEM) is Java 11. Let's see how to run it using Gradle AEM Plugin (GAP) and handle known discrepancies between Java 8 & 11.
In AEM instance setup using Gradle we presented how to set up AEM instances on Java 8 using GAP. Now, let's move a step forward and run AEM 6.5 on Oracle Java SE 11 JDK - 64bit.
Step by step:
- Handle the fact that the Common Annotations Module was removed from Java 11
- Expose extra packages in the system bundle (optional)
- Bypass known FELIX-6184 issue
- Open debug port (optional)
- Make reflection work (optional)
- Update Garbage Collector configuration (optional)
- Filter known errors in logs
Please see example GAP project running AEM 6.5 on Java 11.
1. Handle the fact that the Common Annotations Module was removed from Java 11
Since
the Java Common Annotations Module got removed from Java 11
we need to add javax.annotation-api
as a dependency, so that we're able to build our application on Java 11:
Maven | Gradle |
---|---|
|
|
For details please refer to the mentioned PERFICIENT/digital blog post.
2. Expose extra packages in the system bundle (optional)
In some cases, we might need to expose extra packages in the system bundle. Especially, when upgrading from previous
versions of AEM to AEM 6.5 and Java 11, in our application we might still depend on API available in Java 8 which is
missing in 11. It might result in our bundle being Installed but not Active - some dependencies cannot be resolved (e.g.
com.sun.org.apache.xpath.internal
).
To expose extra packages we need to configure org.osgi.framework.system.packages.extra
property in the AEM instance
crx-quickstart/conf/sling.properties
. It is possible to simply update this file manually, however, if you use GAP it
is easy to automate.
Use GAP to override sling.properies
To achieve that, add a file with the new property under gradle
directory in your project:
src/aem/localInstance/common/crx-quickstart/conf/sling.properties
org.osgi.framework.system.packages.extra=com.sun.org.apache.xpath.internal;version\="{dollar}{felix.detect.java.version}"
Now, when creating a new instance with this configuration, GAP will merge extracted sling.properties
with the one
provided by you. System bundle will expose new packages and instance setup will remain fully automated and repeatable.
3. Bypass known FELIX-6184 issue
Similar solution can be applied to bypass known FELIX-6184 issue which pops up as "random" exceptions after reinstalling a bundle:
java.lang.NoClassDefFoundError: jdk/internal/reflect/ConstructorAccessorImpl
at java.base/jdk.internal.misc.Unsafe.defineClass0(Native Method)
at java.base/jdk.internal.misc.Unsafe.defineClass(Unsafe.java:1192)
(...)
As described in the issue, we just need to add additional packages names for org.osgi.framework.bootdelegation
property in the same sling.properties
file:
org.osgi.framework.bootdelegation=sun.*,com.sun.*,jdk.internal.reflect,jdk.internal.reflect.*
Like in the previous section, we recommend using GAP to update instance sling.properties
file.
4. Open debug port (optional)
Another interesting fact to remember: since Java 9, Java Debug Wire Protocol (JDWP) agent
listens only on local network interface by
default so remote connections will be rejected. This sounds sensible and secure. However, what to do when you need to
debug a specific corner case related to content on your integration environment? A hostname of an asterisk (*) can be
used to achieve the old behavior which is to bind the JDWP socket connector to all available interfaces. In this case,
use following Java startup parameter: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:14502
.
It is simple to achieve that using GAP. We just need to specify debugAddress
parameter in the gradle.properties
:
instance.local-author.debugAddress=*
5. Make reflection work (optional)
Since Java 9 modules were introduced
reflectively accessing internal Java APIs will fail
if you won't allow it explicitly with --add-opens
JVM option. A common case is dependency injection libraries like
Guice that use the class loader’s internal API, which results in errors like the following:
Caused by: java.lang.reflect.InaccessibleObjectException:
Unable to make ClassLoader.defineClass accessible:
module java.base does not "opens java.lang" to unnamed module
Here is a handful of packages you might want to open for reflective access when running on AEM:
--add-opens=java.desktop/com.sun.imageio.plugins.jpeg=ALL-UNNAMED
--add-opens=java.base/sun.net.www.protocol.jrt=ALL-UNNAMED
--add-opens=java.naming/javax.naming.spi=ALL-UNNAMED
--add-opens=java.xml/com.sun.org.apache.xerces.internal.dom=ALL-UNNAMED
--add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens=java.base/java.net=ALL-UNNAMED
As with the debug port example, you can use GAP to automate issuing those options at startup time extending
gradle.properties
file:
instance.local-author.jvmOpts=--add-opens=java.desktop/com.sun.imageio.plugins.jpeg=ALL-UNNAMED \
--add-opens=java.base/sun.net.www.protocol.jrt=ALL-UNNAMED \
--add-opens=java.naming/javax.naming.spi=ALL-UNNAMED \
--add-opens=java.xml/com.sun.org.apache.xerces.internal.dom=ALL-UNNAMED \
--add-opens=java.base/java.lang=ALL-UNNAMED \
--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED \
--add-opens=java.base/java.net=ALL-UNNAMED
6. Update Garbage Collector configuration (optional)
Sometimes you might want to select Parallel Garbage Collector for performance reasons. Again, just extend your list of JVM options with:
-XX:+UseParallelGC
7. Filter known errors in logs
Last but not least, how to make your logging transparent when running AEM on Java 11? Few things you might to consider:
- Hide Java 11 Nashorn deprecation warnings on runtime
- Filter out or fix "WARN with NPE in logs when opening Page Properties"
- Filter out "WARN EclipseJavaCompiler Using unsupported java version '11'"
1. Hide Java 11 Nashorn deprecation warnings on runtime
Nashorn Script Engine is deprecated in Java 11. Running it on AEM will generate WARNs in AEM logs. To suppress those warnings simply extend the list of JVM options with:
-Dnashorn.args=--no-deprecation-warning
2. Filter out or fix "WARN with NPE in logs when opening Page Properties"
Running AEM 6.5 and Java 11, when you open Page Properties in edit mode you might observe warnings containing NPE thrown
from table_jsp.java:56
. This seems to be a known issue. You can try to fix it or filter it out from your logs when
using GAPs instanceTail
task by extending your src/aem/instance/tail/incidentFilter.txt
file with:
libs.granite.ui.components.coral.foundation.table Failed to wrap datasource for lookahead
See Filtering logs for more details.
3. Filter out "WARN EclipseJavaCompiler Using unsupported java version '11'"
There is another WARN related to
SLING-8322.
It is fixed in SLING but not released yet. A good candidate to filter it out with GAPs instanceTail
:
org.apache.sling.commons.compiler.impl.EclipseJavaCompiler Using unsupported java version '11', assuming latest supported version '9'
Summary
Running AEM 6.5 on Java 11 might not be the simplest thing to do! It is good to have an understanding of what changed between Java 8 and 11 and how those changes affect your AEM instance. As always, it is good to automate. Here is the summary of changes you can make to GAPs configuration to be able to run it smoothly on Java 11:
build.gradle.kts
- only if you use GAP to build your application (not covered in the example project):
dependencies {
compileOnly("javax.annotation:javax.annotation-api:1.3.2")
}
src/aem/localInstance/common/crx-quickstart/conf/sling.properties
org.osgi.framework.system.packages.extra=com.sun.org.apache.xpath.internal;version\="{dollar}{felix.detect.java.version}"
org.osgi.framework.bootdelegation=sun.*,com.sun.*,jdk.internal.reflect,jdk.internal.reflect.*
gradle.properties
instance.local-author.debugAddress=*
instance.local-author.jvmOpts=--add-opens=java.desktop/com.sun.imageio.plugins.jpeg=ALL-UNNAMED \
--add-opens=java.base/sun.net.www.protocol.jrt=ALL-UNNAMED \
--add-opens=java.naming/javax.naming.spi=ALL-UNNAMED \
--add-opens=java.xml/com.sun.org.apache.xerces.internal.dom=ALL-UNNAMED \
--add-opens=java.base/java.lang=ALL-UNNAMED \
--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED \
--add-opens=java.base/java.net=ALL-UNNAMED \
-XX:+UseParallelGC \
-Dnashorn.args=--no-deprecation-warning
src/aem/instance/tail/incidentFilter.txt
libs.granite.ui.components.coral.foundation.table Failed to wrap datasource for lookahead
org.apache.sling.commons.compiler.impl.EclipseJavaCompiler Using unsupported java version '11', assuming latest supported version '9'
You can find all those changes in one place in the example of GAP running AEM 6.5 on Java 11.