Interacting with Java Libraries in Lucee 6.2

With Lucee 6.2, one of our main objectives was to simplify Java integration as much as possible. We focused on making it easier to load libraries and adapt existing Java code to work seamlessly in Lucee. To achieve this, we approached it with a simple challenge: pick a third-party Java library and try to use it in Lucee with the least amount of friction. If we encountered any hurdles, we adapted Lucee accordingly. In short, we learned a lot from real-world examples and worked to overcome any unexpected challenges.

As a result of this process, two new extensions will be coming out:

  • Quartz Scheduler
  • LangChain4j for Retrieval-Augmented Generation (RAG)

But let’s dive into an example instead of just talking about it.

Example: ZXing (QR Code Generator)

For this example, we followed this post as a guide to get ZXing working with Lucee. Here’s how the Java code looks in Lucee:

component javasettings='{
        "maven":[
            {
                "groupId" : "com.google.zxing",
                "artifactId" : "core",
                "version" : "3.3.0"
            },
            {
                "groupId" : "com.google.zxing",
                "artifactId" : "javase",
                "version" : "3.3.0"
            }
        ]
    }' {
        import java.io.File;
        import java.util.HashMap;
        import com.google.zxing.BarcodeFormat;
        import com.google.zxing.EncodeHintType;
        import com.google.zxing.MultiFormatWriter;
        import com.google.zxing.NotFoundException;
        import com.google.zxing.client.j2se.MatrixToImageWriter;
        import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

        public static void function createQR(String data, String path, numeric height, numeric width) {
            
            var hashMap = new HashMap();
            hashMap.put(EncodeHintType::ERROR_CORRECTION,ErrorCorrectionLevel::L);
            
            var matrix = new MultiFormatWriter().encode(data, BarcodeFormat::QR_CODE, width, height);
            MatrixToImageWriter::writeToFile(
                matrix,
                listLast(path, "."),
                new File(path)
            );
        }
}

Using this component in Lucee is straightforward:

<cfscript>
    path = getDirectoryFromPath(getCurrentTemplatePath()) & "qr.png";
    ZXingSimple::createQR("www.lucee.org", path, 200, 200);
    echo('<img src="#contractPath(path)#">');
</cfscript>

As you can see, we were able to take the Java example almost as-is, with only a few small modifications.

Maven Integration

First, we import the necessary Maven dependencies. Lucee will automatically download the libraries and all their dependencies when needed.
Maven is similar to ForgeBox, but operates at a much larger scale since it is used for Java packages globally.

component javasettings='{
        "maven":[
            {
                "groupId" : "com.google.zxing",
                "artifactId" : "core",
                "version" : "3.3.0"
            },
            {
                "groupId" : "com.google.zxing",
                "artifactId" : "javase",
                "version" : "3.3.0"
            }
        ]
    }' {
    ...

More details about Maven support in Lucee 6.2: Maven Documentation

Importing Java Classes

Next, we import the necessary Java classes. In Lucee 6.2, you can import Java classes the same way you import CFML components. You can even use wildcards like * to import all classes from a package.

...
import java.io.File;
import java.util.HashMap;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
...

More details about import support in Lucee 6.2: Import Documentation

Interacting with Java Classes

Finally, interacting with the Java classes themselves is simple. There’s no need for createObject or other complex syntax. You can now load Java classes just like CFML components, using the new operator and :: for static methods.

...
public static void function createQR(String data, String path, numeric height, numeric width) {
            
    var hashMap = new HashMap();
    hashMap.put(EncodeHintType::ERROR_CORRECTION, ErrorCorrectionLevel::L);
    
    var matrix = new MultiFormatWriter().encode(data, BarcodeFormat::QR_CODE, width, height);
    MatrixToImageWriter::writeToFile(
        matrix,
        listLast(path, "."),
        new File(path)
    );
}
...

More details about the new operator in Lucee 6.2: New Operator Documentation

Bonus: Enable Documentation in Lucee 6.2

If you’ve enabled the “documentation” monitor, all these recipes linked above and more will appear at the end of the page in the monitor output.

8 Likes

the Maven part is super interesting!

When I use third party java libraries I always waste a lot of time copying them to my working directory.
Now everything should be easier.

Thanks! :heart:

I know and updating them is even worse. Specially to get sure you have all dependencies in the correct version. Using it that way (in the component) you also get a better separation, so no conflicts when you load the component in an environment using different versions of the libraries.

3 Likes

Oh boy… cant wait to play with this… #superawesome

Get donating people! #morefeatures #moredevtime

1 Like

Our server is offline,firewall setting only connect to server web service (443 port). If I download the jar file from ‘https://repo1.maven.org/maven2/com/google/zxing/core/3.5.3/core-3.5.3.jar,’ how do I manually copy it to the correct directory in Lucee 6.2?