On more than one occasion recently I’ve wanted to incorporate Java libraries into ColdFusion applications. You can do this in your CFML, but it usually involves the following:
- CFML code littered with createObject(“java”,”whatever.Whatever”);
- Zero content assist for the Java objects
- Optionally, Putting jar files in your CF installation’s lib directories and deploying those to all servers (dev, test, staging, prod) and developer machines
1 and 2 are the worst problems because 3 is solved with Mark Mandel’s javaloader (more on that later).
Ideally, I’d be able to write Java code in Java source files, compile it and test it in Eclipse, and fairly seamlessly use it in my CFML… in the same project. In this post, I’ll show you how to set it up in ColdFusion Builder. Note that these same steps apply to CFEclipse as well. In a follow-up post, I’ll show a more real-world example
Create your CFML project
- In CFBuilder or CFEclipse, either create a new project or use an existing one.
- Create a directory named “java”
- under there, create “src”, “bin”, and “lib” directories
- Download javaloader from Mark’s site, and drag the “javaloader” directory into the root of your project (or put it in your webroot)
- If you put it into your project, add this to your Application.cfc: this.mappings["/javaloader"] = getDirectoryFromPath(getCurrentTemplatePath());
By now, your project should look something like this:
Apply the Java Nature
- Close the project: right click – “Close Project”
- From the file system, open the project’s “.project” file in a text editor
- In the “<natures>” element, add this: <nature>org.eclipse.jdt.core.javanature</nature>
- In the “<buildSpec>” element, add the following:
<buildCommand> <name>org.eclipse.jdt.core.javabuilder</name> <arguments> </arguments> </buildCommand>
Back in Eclipse, open the project (right click -- “Open Project”). Once you do that, it’s going to look very strange… something like this:
Configure the Java Build Path
Your project now looks funky because it’s treating everything as a Java source folder. Let’s fix that.
- On the project, right click, select “Build Path”, then “Configure Build Path”
- In the “Source” tab, remove any entries
- In the same tab, select “Add Folder” and navigate to your project’s “java/src” folder
- Down at the bottom, in “Default output folder” text field, browse to your project’s “java/bin” directory
Now, your project should look something like this:
That’s better.
Create a simple Java file
Note in that screenshot above that you have “java/src” with a package decorator… that’s where you’ll be working. Ignore the “java” directory that you see in that screenshot… we don’t care about it for now.
- In the “java/src” directory, right click, select “New – Package”. Name it “hello”.
- In that (now empty) package, right click, select “New – Java Class”. Name it “Hello”
- This will open a new Hello.java in a java editor. Let’s create a simple “echo” method. For now, just use a “main” method to drive it in Eclipse… we don’t need to get fancy with unit tests just yet:
package hello; public class Hello { public String echo(String input){ return "Hello. You said: " + input; } public static void main(String[] args) { Hello h = new Hello(); System.out.println(h.echo("marc")); } }
If all goes well, you should be able to run this file and see output in the console. To run it, select “Hello.java” in the Project Explorer and hit the green “Play” button in the toolbar, or right click in Hello.java and select “run as – java application”, or hit “Alt-Shift-X, J"
Use it in your CFML
To use it in your CFML, you’ll want to use javaloader. Conceptually, you simply tell javaloader where your compiled classes are, where any additional .jar files live, and then use it to create objects. Here’s what it looks like in practice. For demo purposes, I just created a file in my project root; thus, all paths you see in here are relative to that file in the root.
<!--- set up javaloader ---> <cfset binDir = expandPath("java/bin")> <cfset libDir = expandPath("java/lib")> <cfset jars = directoryList(libDir)> <cfset arrayAppend(jars,binDir)> <cfset loader = createObject("component","javaloader.JavaLoader").init(jars)> <!--- run it ---> <h1>Hello!</h1> <h2>Echo example</h2> <cfset hello = loader.create("hello.Hello")> <cfoutput>#hello.echo("marc")#</cfoutput>
If you’ve done everything right, when you run this in your browser you should see the expected output. If you go back into your java file, make a change, and hit refresh in the browser, the changes you made should be reflected.
Final Thoughts
For years, folk have praised the ability to integrate Java into CFML. However, the workflow has always been complicated and the tooling nonexistent. CFMLers who’ve worked for years without content assist on their own Components most likely have no idea just how powerful an ally their IDE can be. So we suffer, typing “whatever = createObject(“java”, “some.Java”); whatever.NowWhatWasThatMethodAgain(AndWhatWereThoseArgumentsAgain)”, not realizing that if we were writing our java in a “real” editor, you’d get all the richness the IDE can offer. In other words, most CFMLers don’t know what they’re missing when they have to incorporate java into their projects.
I am not saying that when you create Java objects in your CFML code that you’re going to get content assist; rather, what I’m saying is that if you have more than a few lines of Java code in your CFML, then perhaps it’s best to put that code into its own Java sources – inside the same project, as I’ve described above – and simplify the work you have to do with Java without sacrificing workflow and deployment speed.
It also opens up some other nice possibilities: If you’ve a Groovy fan, or have a problem that would be better suited for Groovy – yes… even if the thing you want to do is simply more enjoyable in that language --- then you could do very similar steps to turn your CFML project into a hybrid Groovy project. Create your Whatever.g sources, and use Barney Boivert’s excellent CFGroovy to run your Groovy sources.
If you need to write some java of your own, and you need to incorporate it into your CFML projects, then this IDE setup can help you.
Coming soon: a real-world example.