The final step in developing a LuciadLightspeed application is obfuscating the code. This step is required by Hexagon to transition to the deployment phase and brings several benefits for your application:

  • Protection of the source code of an application from reverse engineering.

  • Reduction of application footprint. Obfuscated names are shorter and can significantly reduce the application footprint. Obfuscation programs, such as Proguard, also allow for other optimizations. One example is ‘shrinking’ which removes unused byte code. This can also drastically reduce the application footprint. Experiments with Lucy resulted in a functional Lucy application that was less than 4MB in size.

What is obfuscation?

Obfuscating Java class files means replacing the original class names, method names, and field names by short, meaningless names. For instance, obfuscation may rename a method double getX() to double a(). Obfuscation makes it much harder to reverse engineer the code. Although it does not necessarily make decompilation impossible, understanding the decompiled code becomes more difficult.

Obfuscation also removes the debugging information that is not required for deployment. By default, Java class files still contain all class/method/field/argument/variable names, source file names, and source line numbers. Removing this information typically reduces the footprint of the application by 30% as an interesting side-effect.

In addition, many obfuscating tools further shrink the processed applications by removing classes, methods, and fields that are not actually used in the code. Especially when your are using large APIs like LuciadLightspeed, this operation can considerably reduce the size of the jars.

LuciadLightspeed and obfuscation

Your LuciadLightspeed license requires you to obfuscate the class files of the LuciadLightspeed API when you deploy your applications (i.e. application, applet, servlet, …​). This requirement serves as protection against uncontrolled distribution of the API. You are not required to obfuscate your own code, in the sense of changing its class names, method names, and field names, but you will have to process your code together with the LuciadLightspeed API, in order to make sure all references to the LuciadLightspeed API are updated correctly.

When your LuciadLightspeed application has been obfuscated, it is ready to be deployed. You should then replace the developer license file (development_license.jar) in your class path by an end user license file (deployment_license.jar).

How to obfuscate your application

In these instructions, it is assumed that you are using a recent version of the obfuscation program ProGuard, which we highly recommend.

LuciadLightspeed comes with a collection of sample scripts and ProGuard configuration files that demonstrate how to obfuscate your application. To use them, download the most recent version of ProGuard and place its proguard.jar in the build/proguard folder of the LuciadLightspeed release, next to the configuration files (+*+.pro). The sample deployment scripts are located in build/samples and build/fusionplatform. The scripts are written for Ant, which is also included in the release.

You can call the *.xml scripts directly using Ant, or you can call one of the wrapper shell scripts (*.bat or *.sh) to automatically use the bundled Ant. The sections below explain how you can use the scripts for basic obfuscation. For a more advanced usage, see the documentation in the script source files.

Using the sample deployment scripts to obfuscate your code

To obfuscate an application with ProGuard, you must specify a few things. The sample scripts take care of all of this and do not require any parameters:

  • injars: the code to be obfuscated. This means all Luciad jars (lcd_*.jar) and your own code.

  • libraryjars: all dependencies of the code. This means all other jars, including the Java run-time libraries.

  • outjars: a directory or jar file to write the obfuscated result to.

  • The configuration to use, either specified directly or in a .pro file.

We suggest using the sample scripts as a guide when obfuscating your own application.

Configuring ProGuard correctly

The sample configuration files in build/proguard specify all required and recommended settings for deploying and obfuscating a LuciadLightspeed-based application. They can be included in your own configuration with -include and are also used in the sample scripts mentioned above. If you are modifying or extending these configuration files, take the following into account:

  • Obfuscators typically rename all classes by default, making their names unrecognizable. Therefore, at least specify the main class of your application to the obfuscator, so its name can be preserved as an entry point.

  • The names of classes that are instantiated dynamically, based on their names (using the method Class.forName), must be preserved. For instance, classes that implement javax.swing.plaf.ComponentUI are instantiated dynamically, so their names must be kept. LuciadLightspeed also instantiates a number of classes dynamically. For instance, all implementations of ILcdGXYPainter and ILcdGXYEditor in the packages com.luciad.internal.symbology and sub-packages have to be kept.

  • You can find a complete list of LuciadLightspeed classes that have to be preserved in the configuration file /build/proguard/luciad_fusion_platform_service.pro. You can find a sample configuration for processing all the samples in the file build/proguard/samples.pro.

Troubleshooting

Below is a list of considerations and common problems during and after obfuscation. Also take a look at ProGuard’s troubleshooting page. If you encounter an unlisted problem that you are unable to solve, contact the Luciad Support Desk services and provide:

  • A detailed description of the problem, including any stack traces.

  • An explanation of the steps leading to the problem.

  • The ProGuard version you used.

  • Your ProGuard configuration files.

  • The full obfuscation log. Those are all the messages that ProGuard writes to the console.

Known issues and considerations

Always use the ProGuard configuration files shipped with the product and version that you are using.

Those files are updated regularly. Using the files of another product, or of an older version, will likely result in errors.

The ProGuard Maven plugin is not supported.

It is very difficult, if not impossible, to configure this plugin correctly. We recommend against it. Instead, set up obfuscation as a separate step in your build pipeline and use ProGuard directly or through Ant.

ProGuard does not support multi-release jars.

Multi-release jars were introduced in Java 9, but are not supported by ProGuard. If your application includes or depends on such jars, you must filter out the alternate versions or ProGuard will complain about duplicate definitions.

Do not shrink or optimize your application.

Shrinking or optimizing your application causes ProGuard to remove what it considers unused code. It discards code too eagerly, however. Using these options in a LuciadLightspeed-based application will cause run-time errors such as java.lang.NoSuchMethodError.

Always use the latest version of ProGuard.

ProGuard has its own set of issues and gets updated frequently. It is recommended to use the latest version at all times.

The latest ProGuard version might not support OracleJDK/OpenJDK 11 yet.

If you want to compile and obfuscate using OracleJDK/OpenJDK 11 and the latest ProGuard version does not support this version yet, contact the Luciad Support Desk services.

Common problems

Warning message: library class …​ depends on program class …​

This warning is thrown if you have incorrectly split your code into injars and libraryjars. Make sure that all Luciad jars (lcd_*.jar) and your own code are specified as injar and other libraries as libraryjar.

A VerifyError is thrown at run-time.

This can be caused by turning off pre-verification or enabling optimization when running ProGuard. Make sure that -dontpreverify is not specified anywhere in your configuration and that -dontoptimize is specified.

Classes in java.lang or javax.crypto cannot be found.

Make sure that you have specified both rt.jar and jce.jar (part of the JRE) as libraryjar.

You get a bunch of NoClassDefFoundErrors, NoSuchMethodErrors, class cast exceptions or similar.

You may be mixing obfuscated and non-obfuscated code. Make sure that your class path includes only obfuscated jars and has no reference to any of the original, non-obfuscated code. Take special care when using wildcards.