Using java.ext.dirs to manage the Classpath for Clojure REPLs

409 views
Skip to first unread message

Stephen C. Gilardi

unread,
Jan 4, 2009, 12:59:29 PM1/4/09
to clo...@googlegroups.com
The "java.ext.dirs" System property provides a very convenient way to
set up and maintain a Classpath for Clojure REPLs. The property can be
set from the command line used to launch Clojure (typically within a
launcher script). Its value is a list of directories whose *contents*
will be the Classpath roots for Clojure.

In my case, I set the value of java.ext.dirs to a list of just one
directory. That directory contains (relative) symbolic links to all
the Jar files and directories I want Clojure to use as its Classpath.

As a concrete example, here's what I have in that directory:

clojure-contrib.classes -> ../../clojure-contrib/classes
clojure-contrib.src -> ../../clojure-contrib/src
clojure.jar -> ../../clojure/clojure.jar
derby.jar -> ../javadb/lib/derby.jar
etc -> ../../../clj/etc
itext-2.0.6.jar -> ../jfreechart/lib/itext-2.0.6.jar
jcommon-1.0.12.jar -> ../jfreechart/lib/jcommon-1.0.12.jar
jfreechart-1.0.9.jar -> ../jfreechart/lib/jfreechart-1.0.9.jar
jsr166y.jar -> ../jsr166y/jsr166y.jar
local -> ../../../clj/local
miglayout-3.6-sources.jar -> ../miglayout/miglayout-3.6-sources.jar
miglayout-3.6-swing.jar -> ../miglayout/miglayout-3.6-swing.jar

I've enclosed the bash script I'm currently using the launch Clojure.
The one required environment variable is CLOJURE_DIRS which I set to
the directory containing the links above. I like how simple the script
is and how easy it is to manage which jars and directories are
available to Clojure REPLs using this method.

--Steve

(note: using this with clojure.contrib.repl-ln requires revision 337
(of today) or later)

#!/bin/bash

# clj: Launches a Clojure REPL with command line arguments
#
# Environment variables:
#
# Required:
#
# CLOJURE_DIRS A list of paths to directories containing (either
directly
# or via symbolic links) the jar files and directories
that
# Clojure will use as its Classpath. The paths are
separated
# by File.pathSeparatorChar (: on UNIX).
#
# Optional:
#
# CLOJURE_MAIN The Java class to launch
# default: clojure.main
# example: clojure.contrib.repl_ln
#
# CLOJURE_OPTS Java options for this REPL's JVM instance
# default:
# example:"-Xms32M -Xmx128M -server"
#
# CLOJURE_INIT Path to an init file to run, an @ prefix specifies a
# classpath-relative path.
# default:
# example:"@init.clj"

set -o errexit
set -o nounset
#set -o xtrace

JAVA=java
OPTS=${CLOJURE_OPTS:-}
DIRS="-Djava.ext.dirs=${CLOJURE_DIRS}"
MAIN=${CLOJURE_MAIN:-clojure.main}
INIT=${CLOJURE_INIT:+--init ${CLOJURE_INIT}}
REPL=--repl

exec $JAVA $OPTS $DIRS $MAIN $INIT $REPL $@

lpetit

unread,
Jan 4, 2009, 6:06:29 PM1/4/09
to Clojure
Note that since JDK 1.6, it is possible to use the * wildcard in
classpath items to embed all the jars in a directory at once.

So with proper use of links in a "root" directory containing a bunch
of jars, it's possible to shorten the classpath to DIR/*:classes:src

BTW, java.ext.dirs' semantics is to provide directories to the JVM for
JDK extensions implementing JDK's APIs. (http://java.sun.com/javase/6/
docs/technotes/guides/extensions/spec.html)

It does not seem appropriate to me to abuse java.ext.dirs to put in it
each an every jar or class directory one may want to use in its
application ?

HTH,

--
Laurent
>  smime.p7s
> 3KViewDownload

RZez...@gmail.com

unread,
Jan 4, 2009, 6:58:44 PM1/4/09
to Clojure
I think this should be fine for 99% of situations, but I think it's
also fair to say this is an unorthodox use of java.ext.dirs. I've
never really had a firm grip on the idiomatic use of Java's extension
mechanism, but I do know that they claim it is for well-established
extension/optional packages. One example might be the bouncycastle
crypto provider. The one thing I think you do have to be careful
about is that if you put something in the extensions path, it will be
loaded by the extensions classloader, and you will force everything
running on that JVM process to use that particular version (you can
get around this, but it's not always obvious). For most applications
this shouldn't matter, but for an application that hosts other
applications (eg. an application server) this can be problematic. I
know from experience after 3 years of dealing with IBM WebSphere. You
will probably never run into any problems, but I couldn't help but
comment.

Another solution you might want to look at is Apache's Common
Launcher. It's not the most elegant solution in the world, but it
makes it easy to add an entire directory of JARs to the classpath, and
it makes it easy to have a cross-platform execution script.
>  smime.p7s
> 3KViewDownload

RZez...@gmail.com

unread,
Jan 4, 2009, 7:02:52 PM1/4/09
to Clojure


On Jan 4, 6:06 pm, lpetit <laurent.pe...@gmail.com> wrote:
> Note that since JDK 1.6, it is possible to use the * wildcard in
> classpath items to embed all the jars in a directory at once.
>
> So with proper use of links in a "root" directory containing a bunch
> of jars, it's possible to shorten the classpath to DIR/*:classes:src
>

This is nice to know! Ever since I started using Java (1.4), I
wondered why they didn't have this feature. I have yet to read what's
new in Java 6; I'm so far behind!

Drew Raines

unread,
Jan 4, 2009, 10:07:17 PM1/4/09
to clo...@googlegroups.com
Stephen C. Gilardi wrote:

> The "java.ext.dirs" System property provides a very convenient way to
> set up and maintain a Classpath for Clojure REPLs.

[...]

> In my case, I set the value of java.ext.dirs to a list of just one
> directory. That directory contains (relative) symbolic links to all
> the Jar files and directories I want Clojure to use as its Classpath.
>
> As a concrete example, here's what I have in that directory:

java.ext.dirs has a default value that -Djava.ext.dirs overwrites, so
make sure you replace whatever your platform's Java expects (like
$JAVA_HOME/lib/ext). I've been bitten before trying to speak HTTPS
while not having sunpkcs11.jar available.

-Drew

Stephen C. Gilardi

unread,
Jan 4, 2009, 10:59:08 PM1/4/09
to clo...@googlegroups.com

On Jan 4, 2009, at 10:07 PM, Drew Raines wrote:

> java.ext.dirs has a default value that -Djava.ext.dirs overwrites, so
> make sure you replace whatever your platform's Java expects (like
> $JAVA_HOME/lib/ext). I've been bitten before trying to speak HTTPS
> while not having sunpkcs11.jar available.

Thanks for the info, Drew, R, and Laurent.

I've come up with this alternative for Mac OS X and Linux that gives
the same convenient management, but doesn't use java.ext.dirs.

--Steve

#!/bin/bash

# clj: Launches a Clojure REPL with command line arguments
#
# Environment variables:
#
# Required:
#

# CLOJURE_EXT The path to a directory containing symlinks to the jar
# files and directories that Clojure will use as its
# Classpath.


#
# Optional:
#
# CLOJURE_MAIN The Java class to launch
# default: clojure.main
# example: clojure.contrib.repl_ln
#
# CLOJURE_OPTS Java options for this REPL's JVM instance
# default:
# example:"-Xms32M -Xmx128M -server"
#
# CLOJURE_INIT Path to an init file to run, an @ prefix specifies a
# classpath-relative path.
# default:
# example:"@init.clj"

set -o errexit
set -o nounset
#set -o xtrace

EXT="$(find ${CLOJURE_EXT} -type l -print0 | tr "\0" ":")"
export CLASSPATH="${EXT}${CLASSPATH:-}"

JAVA=java
OPTS=${CLOJURE_OPTS:-}


MAIN=${CLOJURE_MAIN:-clojure.main}
INIT=${CLOJURE_INIT:+--init ${CLOJURE_INIT}}
REPL=--repl

exec $JAVA $OPTS $MAIN $INIT $REPL $@

Stuart Sierra

unread,
Jan 5, 2009, 7:17:43 PM1/5/09
to Clojure
On Jan 4, 12:59 pm, "Stephen C. Gilardi" <squee...@mac.com> wrote:
> In my case, I set the value of java.ext.dirs to a list of just one
> directory. That directory contains (relative) symbolic links to all
> the Jar files and directories I want Clojure to use as its Classpath.

Symlinks! Ack! Terrible visions of asdf-install swim before my
eyes! Oh, the pain!

Ok, I'm done. Never mind.

-S
Reply all
Reply to author
Forward
0 new messages