Maven Integration

Maven Integration allows BoxLang to seamlessly incorporate Java dependencies into your runtime, expanding your application's capabilities with the vast Java ecosystem.

BoxLang offers seamless integration with Maven, the widely used Java build and dependency management tool. This integration enables you to easily integrate third-party Java libraries into your BoxLang runtime, providing access to the vast Java ecosystem without requiring complex setup procedures.

Overview

The Maven integration in BoxLang works through a simple but powerful mechanism:

  • Centralized Dependency Management: Use Maven's pom.xml to declare all your Java dependencies

  • Automatic Download: Maven handles downloading and resolving dependency conflicts

  • Runtime Integration: BoxLang automatically loads all JARs from the lib/ folder

  • Simple Workflow: Add dependencies, run mvn install, and start using Java libraries immediately

Installing Maven

Before you can use Maven integration, you need to have Maven installed on your system.

Option 1: Using Chocolatey (Recommended)

choco install maven

Option 2: Using Scoop

scoop install maven

Option 3: Manual Installation

  1. Download Maven from maven.apache.org

  2. Extract to C:\Program Files\Apache\maven

  3. Add C:\Program Files\Apache\maven\bin to your PATH environment variable

Verify Installation

After installation, verify that Maven is working:

mvn -version

You should see output showing the Maven version, Java version, and OS information.

Getting Started

The BoxLang home by default is located in your user's home directory: ~/.boxlang from here is where you will be making maven installation commands. Fire up a terminal and navigate to your BoxLang HOME.


cd $BOXLANG_HOME

// or
cd ~/.boxlang

The BoxLang POM File

BoxLang Home includes a pre-configured pom.xml file specifically designed for runtime dependency management:

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>io.boxlang</groupId>
    <artifactId>runtime-library</artifactId>
    <version>@build.version@</version>

    <dependencies>
        <!-- Add your Java dependencies here -->
    </dependencies>

    <build>
        <directory>${project.basedir}/.tmp</directory>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>3.1.2</version>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>install</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.basedir}/lib</outputDirectory>
                            <includeScope>runtime</includeScope>
                            <excludeScope>test</excludeScope>
                            <excludeScope>provided</excludeScope>
                            <overWriteReleases>true</overWriteReleases>
                            <overWriteSnapshots>true</overWriteSnapshots>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Basic Workflow

  1. Edit the POM: Add your desired dependencies to the <dependencies> section

  2. Install Dependencies: Run mvn install in the BoxLang Home directory

  3. Use Libraries: Start using the Java libraries in your BoxLang code immediately

Adding Dependencies

Finding Dependencies

Use Maven Central to find the dependencies you need. Simply search for the library and copy the Maven coordinates.

Adding a Dependency

Edit the pom.xml file and add your dependency inside the <dependencies> section:

<dependencies>
    <!-- Apache Commons Text for string manipulation -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-text</artifactId>
        <version>1.12.0</version>
    </dependency>
    
    <!-- QR Code generation -->
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>3.5.2</version>
    </dependency>

</dependencies>

Installing Dependencies

Navigate to your BoxLang Home directory and run:

mvn install

This command will:

  • Download all declared dependencies and their transitive dependencies

  • Place all JARs in the lib/ folder

  • Make them available to the BoxLang runtime

Cleaning Dependencies

To remove all downloaded dependencies:

mvn clean

This will clear the lib/ folder of all Maven-managed JARs.

Practical Examples

Text Processing with Apache Commons

Add powerful text processing capabilities to your BoxLang applications:

<!-- Add to pom.xml -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-text</artifactId>
    <version>1.12.0</version>
</dependency>
// Use in BoxLang after mvn install
stringEscapeUtils = new org.apache.commons.text.StringEscapeUtils()
wordUtils = new org.apache.commons.text.WordUtils()

// Escape HTML
safeHTML = stringEscapeUtils.escapeHtml4( "<script>alert('xss')</script>" )
println( "Safe HTML: " & safeHTML )

// Capitalize words
title = wordUtils.capitalizeFully( "the quick brown fox" )
println( "Title: " & title ) // "The Quick Brown Fox"

// Text similarity
similarity = new org.apache.commons.text.similarity.JaroWinklerSimilarity()
score = similarity.apply( "BoxLang", "BoxScript" )
println( "Similarity: " & score )

QR Code Generation

Add QR code generation capabilities to your BoxLang applications:

<!-- Add to pom.xml -->
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.5.2</version>
</dependency>
// QR Code generator utility
function createQRCodeGenerator() {
    return {
        "generate": ( text, size = 300 ) -> {
            var writer = new com.google.zxing.qrcode.QRCodeWriter()
            var bitMatrix = writer.encode( 
                text, 
                new com.google.zxing.BarcodeFormat().QR_CODE, 
                size, 
                size 
            )
            
            return new com.google.zxing.client.j2se.MatrixToImageWriter()
                .toBufferedImage( bitMatrix )
        },
        
        "saveToFile": ( text, filePath, size = 300 ) -> {
            var image = this.generate( text, size )
            var file = new java.io.File( filePath )
            
            new javax.imageio.ImageIO().write( image, "PNG", file )
            return filePath
        },
        
        "generateDataURL": ( text, size = 300 ) -> {
            var image = this.generate( text, size )
            var baos = new java.io.ByteArrayOutputStream()
            
            new javax.imageio.ImageIO().write( image, "PNG", baos )
            var bytes = baos.toByteArray()
            var encoder = new java.util.Base64().getEncoder()
            
            return "data:image/png;base64," & encoder.encodeToString( bytes )
        }
    }
}

// Usage
qrGenerator = createQRCodeGenerator()

// Generate QR code for a URL
qrFile = qrGenerator.saveToFile( 
    "https://boxlang.ortussolutions.com", 
    "/tmp/boxlang-qr.png", 
    400 
)
println( "QR code saved to: " & qrFile )

// Generate QR code as data URL for web use
dataURL = qrGenerator.generateDataURL( "BoxLang is awesome!" )
println( "Data URL: " & dataURL.left( 50 ) & "..." )

Encryption and Security

Add cryptographic capabilities with Bouncy Castle:

<!-- Add Bouncy Castle for cryptography -->
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk18on</artifactId>
    <version>1.77</version>
</dependency>
// Encryption utility
function createEncryptionUtil() {
    // Add Bouncy Castle as security provider
    var provider = new org.bouncycastle.jce.provider.BouncyCastleProvider()
    var security = new java.security.Security()
    security.addProvider( provider )
    
    return {
        "generateKeyPair": () -> {
            var keyGen = new java.security.KeyPairGenerator().getInstance( "RSA", "BC" )
            keyGen.initialize( 2048 )
            return keyGen.generateKeyPair()
        },
        
        "encrypt": ( data, publicKey ) -> {
            var cipher = new javax.crypto.Cipher().getInstance( "RSA/ECB/PKCS1Padding", "BC" )
            cipher.init( new javax.crypto.Cipher().ENCRYPT_MODE, publicKey )
            return cipher.doFinal( data.getBytes() )
        },
        
        "decrypt": ( encryptedData, privateKey ) -> {
            var cipher = new javax.crypto.Cipher().getInstance( "RSA/ECB/PKCS1Padding", "BC" )
            cipher.init( new javax.crypto.Cipher().DECRYPT_MODE, privateKey )
            var decrypted = cipher.doFinal( encryptedData )
            return new java.lang.String( decrypted )
        }
    }
}

// Usage
encryption = createEncryptionUtil()
keyPair = encryption.generateKeyPair()

message = "Secret BoxLang message"
encrypted = encryption.encrypt( message, keyPair.getPublic() )
decrypted = encryption.decrypt( encrypted, keyPair.getPrivate() )

println( "Original: " & message )
println( "Decrypted: " & decrypted )

Advanced Usage Patterns

Multi-Module Dependencies

For large applications, organize dependencies by functionality:

<dependencies>
    
    <!-- QR Code Generation -->
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>3.5.2</version>
    </dependency>
    
    <!-- Cryptography -->
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk18on</artifactId>
        <version>1.77</version>
    </dependency>
</dependencies>

Version Management

Use properties for easier version management:

<properties>
    <zxing.version>3.5.2</zxing.version>
    <commons.version>1.12.0</commons.version>
</properties>

<dependencies>
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>${zxing.version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-text</artifactId>
        <version>${commons.version}</version>
    </dependency>
</dependencies>

Excluding Transitive Dependencies

Sometimes you need to exclude specific transitive dependencies:

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext7-core</artifactId>
    <version>8.0.2</version>
    <type>pom</type>
    <exclusions>
        <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Best Practices

1. Keep Dependencies Updated

Regularly check for newer versions of your dependencies:

mvn versions:display-dependency-updates

2. Use Specific Versions

Always specify exact versions rather than ranges:

<!-- Good -->
<version>2.16.0</version>

<!-- Avoid -->
<version>[2.0,3.0)</version>

3. Document Your Dependencies

Add comments explaining why each dependency is needed:

<dependencies>
    <!-- Apache Commons Text - Used for advanced string manipulation in templates -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-text</artifactId>
        <version>1.12.0</version>
    </dependency>
    
    <!-- ZXing - Required for QR code generation in reports -->
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>3.5.2</version>
    </dependency>
    
    <!-- Bouncy Castle - Cryptography for secure operations -->
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk18on</artifactId>
        <version>1.77</version>
    </dependency>
</dependencies>

4. Test After Adding Dependencies

Always test your BoxLang application after adding new dependencies:

// Test that dependencies loaded correctly
function testDependencies() {
    try {
        // Test ZXing (QR Codes)
        var qrWriter = new com.google.zxing.qrcode.QRCodeWriter()
        println( "✅ ZXing QR Code library loaded successfully" )
        
        // Test Bouncy Castle
        var provider = new org.bouncycastle.jce.provider.BouncyCastleProvider()
        println( "✅ Bouncy Castle loaded successfully" )
        
        return true
    } catch ( any e ) {
        println( "❌ Dependency loading failed: " & e.message )
        return false
    }
}

testDependencies()

5. Monitor Dependency Size

Keep an eye on the total size of your lib/ folder:

# Check total size of dependencies
du -sh lib/

# List individual JAR sizes
ls -lh lib/*.jar

Troubleshooting

Dependency Conflicts

If you encounter dependency conflicts, use Maven's dependency tree to investigate:

mvn dependency:tree

Class Loading Issues

If classes aren't found after installation:

  1. Verify the JAR is in the lib/ folder

  2. Restart the BoxLang runtime

  3. Check for package name typos in your BoxLang code

If you continue to experience class loading issues, we recommend building BoxLang modules for complete isolation.

Version Compatibility

Some dependencies may require specific versions of Java. Check compatibility before adding:

# Check Java version
java -version

# Check Maven version
mvn -version

Conclusion

Maven integration makes BoxLang incredibly powerful by providing access to the entire Java ecosystem. Whether you need advanced text processing, HTTP clients, database drivers, encryption libraries, or specialized tools, Maven integration makes it simple to add and manage these dependencies.

Key benefits:

  • 🚀 Easy Setup: Simple mvn install command to add dependencies

  • 🔧 Automatic Management: Maven handles dependency resolution and conflicts

  • 📚 Vast Ecosystem: Access to thousands of Java libraries

  • 🔄 Version Control: Easy dependency updates and rollbacks

  • 🧹 Clean Management: Simple cleanup with mvn clean

With Maven integration, BoxLang applications can leverage decades of Java library development, making it possible to build enterprise-grade applications with minimal setup complexity.

Last updated

Was this helpful?