The Artima Developer Community
Sponsored Link

Weblogs Forum
Subduing CLASSPATH

26 replies on 2 pages. Most recent reply: Mar 11, 2007 6:40 PM by Michael Easter

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 26 replies on 2 pages [ 1 2 | » ]
Bruce Eckel

Posts: 868
Nickname: beckel
Registered: Jun, 2003

Subduing CLASSPATH (View in Weblogs)
Posted: Aug 20, 2006 10:55 PM
Reply to this message Reply
Summary
Setting CLASSPATH for directories and jars driving you crazy? I finally decided to do something about it.
Advertisement
The answer is some heavy-handed automation and convention. First, why bother trying to put files in the jre\lib\ext directory? Last I heard, there was some kind of security issue so it's prevented, maybe, in some cases. I don't want to have to know what those cases are.

Besides, you have to click down a bunch of directories to find jre\lib\ext, and at least on my system there always seems to end up being two of them, one for the JDK and one for the JRE, and half the time I put it in the wrong place. Too confusing, too much effort.

How about if all jar files just go in a directory called C:\jar? I don't think that will hurt anything, and it will be much easier to manage. Also, if you need to move your setup from your desktop to your laptop, all you have to do is copy that directory.

Well, almost. The other problem is that every time you add a new jar or a new directory to the CLASSPATH, you have to go in and set the environment variables on my computer, editing a really long line in a little tiny window. I'll be happy if I don't have to do that again.

Also, it's very easy to get incorrect and old, nonexistent elements in your CLASSPATH. I'd like that to be automatically fixed, as well.

Conveniently, Python is very good at all kinds of file and directory stuff. But even better, it has the _winreg module (as part of the standard Python distribution), which allows you to directly modify the registry.

The following program pulls your current CLASSPATH from the registry (so there are no problems if the CLASSPATH has been temporarily changed for one command window), removes duplicates and dead links, and then does one of three things:

  1. If there are jar files in the current directory and you don't provide command-line arguments, all the jar files are added to your CLASSPATH.
  2. If there are no jar files in the current directory, that directory is added to the CLASSPATH.
  3. If you provide command-line arguments, those are assumed to be jar files and added to the classpath.

So if you put this program in your C:\jars directory, every time you throw in a new jar file you can just double-click it to add that jar to your CLASSPATH. Should make hand-installation a lot simpler!

Finally, this might be the ideal solution for beginners and classroom situations, where lots of time is lost struggling with silly CLASSPATH issues.

I got most of the information about how to do this by googling for it, but this article was especially helpful.


#!python
"""
SetClasspath.py by Bruce Eckel, 2006 www.MindView.net
Permission granted for free use and distribution as long as this notice is maintained.

Warning! This program modifies the Windows Registry! Use at your own risk.

With no arguments:
    If there are jar files in the current directory, each one is added to the CLASSPATH.
    If there are no jar files, the current directory is added to the CLASSPATH.

With arguments:
    Each argument must be a jar file name. Each argument is added to the CLASSPATH.

Duplicate CLASSPATH entries and nonexistent paths are removed.

I recommend creating C:\jars directory, and adding this program to that directory.
Whenever you need to add a new jar, throw it in C:\jars and double-click this program.
That way, if you need the same set of jars on another machine, just copy the
directory and run this program.

It's also useful to create a batch/cmd file to run this program, and to place
that file in your Windows PATH. Then you can run the program from any directory.
The batch file might look like this:
python C:\jars\SetClassPath.py %1 %2 %3 %4 %5 %6 %7 %8 %9
If you're running Cygwin, you can make a shell file to do the same thing:
python C:/jars/SetClassPath.py $1 $2 $3 $4 $5 $6 $7 $8 $9

This program requires PythonWin, which you can find at:
http://starship.python.net/crew/mhammond/win32/
"""
from _winreg import *
import os, glob, sys
import win32gui, win32con # From PythonWin
path = r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'

def getClassPath():
    try:
        reg = ConnectRegistry(None, HKEY_LOCAL_MACHINE)
        key = OpenKey(reg, path, 0, KEY_ALL_ACCESS)
        i = 0
        while True:
            try:
                name, value, valueType = EnumValue(key, i)
                if name == 'CLASSPATH':
                    return value
                i += 1
            except EnvironmentError:
                return ""
    finally:
        CloseKey(key)
        CloseKey(reg)

def setClassPath(newPath):
    try:
        reg = ConnectRegistry(None, HKEY_LOCAL_MACHINE)
        key = OpenKey(reg, path, 0, KEY_ALL_ACCESS)
        SetValueEx(key, 'CLASSPATH', 0, REG_SZ, newPath)
        win32gui.SendMessage(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment')
    finally:
        CloseKey(key)
        CloseKey(reg)

if __name__=='__main__':
    # set prevents duplicates, 'if os.path.exists(p)' prunes nonexistent paths:
    pathparts = set([p for p in getClassPath().split(os.pathsep) if os.path.exists(p)])
    pathparts.add(".")
    pathparts.add("..")
    if len(sys.argv) > 1:
        for arg in sys.argv[1:]:
            if not arg.endswith(".jar"):
                print "Arguments must be jar file names: problem with [" + arg + "]"
                sys.exit(1)
            if not os.path.exists(arg):
                print arg, "does not exist in this directory"
                sys.exit(1)
            pathparts.add(os.path.abspath(arg))
    else:
        jars = glob.glob("*.jar")
        if jars:
            for jar in jars:
                pathparts.add(os.path.abspath(jar))
        else:
            pathparts.add(os.getcwd())
    result = list(pathparts)
    result.sort()
    newClasspath = os.pathsep.join(result) + os.pathsep
    setClassPath(newClasspath)
    print getClassPath()

If there's a Linuxphile among you who would like to add a Linux (and presumably OSX would work for free) option to the above program, I'd love to incorporate that.


Michael Stover

Posts: 28
Nickname: mstover
Registered: Jul, 2005

Re: Subduing CLASSPATH Posted: Aug 21, 2006 8:08 AM
Reply to this message Reply
1) Having a system-wide classpath is a sure way to screw up your development efforts. If you only run one java app or work on one java project on your computer, that's great, but that's not the norm. Each project/app should maintain it's own classpath.

2) Most developers and app writers automate this using ant and java itself to build the classpath at runtime, or they use a startup script to build the runtime classpath (a lesser option, IMO). Rather than use python to munge the CLASSPATH, let java do it for itself. it's more robust and more usable and fewer steps (ie, no setting system classpath, no running a separate script, etc).

3) If you're writing a book and have 30 chapters and 30 tiny little micro java projects, I would think one ant script could be made that would do 95% of the work and then a separate ant script for each chapter could import it and finish off the remaining 5%. You could possibly even make do with only a properties file for each chapter.

In short, I think you have python on the brain - it's better than having perl on the brain, but it seems to have caused similar symptoms (ie, string-munging as the solution to all problems).

CB

Posts: 5
Nickname: broken
Registered: Aug, 2004

Re: Subduing CLASSPATH Posted: Aug 21, 2006 8:56 AM
Reply to this message Reply
1) Use an IDE
2) -Djava.ext.dirs=lib

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Subduing CLASSPATH Posted: Aug 21, 2006 9:06 AM
Reply to this message Reply
Instead of all those complicated rules, why not just add a commandline argument like: 'jd' (jar directory) that identifies a directory where all jars should be added to the classpath.

One thing I have done in the past when working with hibernate and Jython (too many jars to keep strack of) is this simple command to get a classpath from the hibernate lib directory:

ls [hibernate-lib] | regex -x "\S+" "\$0:" > cp.txt

nes

Posts: 137
Nickname: nn
Registered: Jul, 2004

Re: Subduing CLASSPATH Posted: Aug 21, 2006 12:03 PM
Reply to this message Reply
> Instead of all those complicated rules, why not just add a
> commandline argument like: 'jd' (jar directory) that
> identifies a directory where all jars should be added to
> the classpath.
>
> One thing I have done in the past when working with
> hibernate and Jython (too many jars to keep strack of) is
> this simple command to get a classpath from the hibernate
> lib directory:
>
> ls [hibernate-lib] | regex -x "\S+" "\$0:" > cp.txt

Why don't the java tools have a parameter to add directories with jar files in them instead of having to add each Jar file individually? It drives me nuts each time I download a library (jar) and put them in c:\app1libs or c:\app2libs that I have to start fiddling with the classpath stuff. I understand the desire of some in the Java crowd to over-engineer everything but should I really need to install and configure an IDE or Ant just to include a few libraries?

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Subduing CLASSPATH Posted: Aug 21, 2006 12:49 PM
Reply to this message Reply
> Why don't the java tools have a parameter to add
> directories with jar files in them instead of having to
> add each Jar file individually?

That's my question too.

> It drives me nuts each
> time I download a library (jar) and put them in
> c:\app1libs or c:\app2libs that I have to start fiddling
> with the classpath stuff. I understand the desire of some
> in the Java crowd to over-engineer everything but should I
> really need to install and configure an IDE or Ant just to
> include a few libraries?

I've worked with some tools that have done this in the past. It shouldn't be too hard to write a shell script that takes such arguments and converts them to an actual path and then passes it to the real Java app and then create an alias in unix or name the script java.bat and put it in the path in Windows.

BTW: One thing that Bruce's code doesn't deal with, though is that some (common) jar files end in .zip but you can always rename them to .jar.

Bruce Eckel

Posts: 868
Nickname: beckel
Registered: Jun, 2003

Re: Subduing CLASSPATH Posted: Aug 21, 2006 3:21 PM
Reply to this message Reply
> I understand the desire of some
> in the Java crowd to over-engineer everything but should I
> really need to install and configure an IDE or Ant just to
> include a few libraries?

Yes, and replies of "just do (whatever the replier does)" don't help either. Maybe there are many tools like ant and eclipse that deal with classpath issues in their own way, but those don't help with the original Java least-common-denominator solution.

And they especially don't help when teaching new Java programmers, or when people are installing the code from my book and they need to initially set up their CLASSPATH so they can run javac.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Subduing CLASSPATH Posted: Aug 21, 2006 4:53 PM
Reply to this message Reply
My experience has been that setting the CLASSPATH in Windows is to be avoided. It's problematic for many reasons. I only use it when a tool I am using requires it. Wouldn't you expect that someone learning to program in Java would at least know how to update a small bat file that you provide?

Simon Li

Posts: 2
Nickname: simonli
Registered: Aug, 2006

Re: Subduing CLASSPATH Posted: Aug 21, 2006 10:09 PM
Reply to this message Reply
Could there be issues similar to "DLL hell" in the old time?

1. jar name confliction from different vendor.
2. new version jar with a different time, but forget to remove the old one.

Simon Li

Posts: 2
Nickname: simonli
Registered: Aug, 2006

Re: Subduing CLASSPATH Posted: Aug 21, 2006 10:10 PM
Reply to this message Reply
> 2. new version jar with a different time
Sorry, should be "different name".

Andreas Mross

Posts: 12
Nickname: amross
Registered: Apr, 2004

Re: Subduing CLASSPATH Posted: Aug 21, 2006 11:03 PM
Reply to this message Reply
Putting all your jars in a c:\jar directory is a good idea.

Using the global CLASSPATH environment variable is bad practise and should not be taught to Java beginners. The classpath should instead be specified using the -classpath attribute.
This is no hassle in simple beginners programs, where the classpath is usually short (just add it to a one line shell script). If a project is large enough to require importing multiple third part libraries, it's probably time to get organised and use a proper IDE or an ANT script.

But yeah, CLASSPATH is bad, mmmkay?

Gregg Wonderly

Posts: 317
Nickname: greggwon
Registered: Apr, 2003

Re: Subduing CLASSPATH Posted: Aug 21, 2006 11:21 PM
Reply to this message Reply
I usually have a VI editor handy, and either the cygwin tools, on windows, or real unix tools. I pop open the editor to create a script to run my java program as in

bash$ vi myapp

then, I type

!!ls lib some*.jar etc.jar

and the current line in the editor is replaced by all of the files that matched the patterns I passed to ls. I then type

:map q Jr:
or
:map q Jr;

and then just start typing q's until all the lines are joined and the appropriate path separator character is in place.

Sometimes when the list is long, or volatile, I'll leave one entry on a line and just put :\ at the end of the line with the 'q' map instead.

Then, I define that string of files/directors as the CLASSPATH environment variable, setup a command line with
all the other arguments and properties I need and I'm done.

The script startup file is great because I can capture some todo's or variations on arguments or other things in that file as comments.

Gregor Zeitlinger

Posts: 108
Nickname: gregor
Registered: Aug, 2005

Re: Subduing CLASSPATH Posted: Aug 22, 2006 2:12 AM
Reply to this message Reply
> Could there be issues similar to "DLL hell" in the old
> time?
>
> 1. jar name confliction from different vendor.
you could rename the jar file

> 2. new version jar with a different time, but forget to
> remove the old one.
this, too, can only happen do not manually maintain the jar list, which you have to do in large projects

Even then, however, there is "DLL hell"

3. Two libraries require different versions of JDOM, for example. This requires you to replace one of the libraries. I haven't run into this problem yet. Has anybody?

4. Some jars overlap. For example, two SAX implementations could both have the SAX API, but everything will work if you get the classpath order right. I've actually had this problem with the the SAX API in the JDK and in xerces.

Michael Stover

Posts: 28
Nickname: mstover
Registered: Jul, 2005

Re: Subduing CLASSPATH Posted: Aug 22, 2006 11:11 AM
Reply to this message Reply
> > I understand the desire of some
> > in the Java crowd to over-engineer everything but should
> I
> > really need to install and configure an IDE or Ant just
> to
> > include a few libraries?
>
> Yes, and replies of "just do (whatever the replier does)"
> don't help either. Maybe there are many tools like ant and
> eclipse that deal with classpath issues in their own way,
> but those don't help with the original Java
> least-common-denominator solution.

But if you're teaching Java, you ought to teach these relatively standard java-centric ways of doing things rather than bringing in a brand new solution using python.

>
> And they especially don't help when teaching new Java
> programmers, or when people are installing the code from
> my book and they need to initially set up their CLASSPATH
> so they can run javac.

You should be providing shell scripts that will just run right on (at least) a windows or unix systems. That way, they can immediately run the examples. Later on, learning how to properly deal with CLASSPATH is essential to. Setting a Global CLASSPATH is a bad way to start out.

Dino Octavian

Posts: 15
Nickname: dinoo33
Registered: Jul, 2006

Re: Subduing CLASSPATH Posted: Aug 23, 2006 3:50 PM
Reply to this message Reply
> 3. Two libraries require different versions of JDOM, for
> example. This requires you to replace one of the
> libraries. I haven't run into this problem yet. Has
> anybody?

I did. And I decided to rewrite a lot of code in order to solve the dependecies correctly.

I didn't even bother to look at ways to hack a quick fix in. My experience is that versioning problems must be addressed fully and correctly ASAP.

Flat View: This topic has 26 replies on 2 pages [ 1  2 | » ]
Topic: Subduing CLASSPATH Previous Topic   Next Topic Topic: Recording of Java/Flex eSeminar


Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us