Coming Up for Air

Easily Switching JDKs

Monday, August 26, 2019 |

Development environments can get fairly complex, and making sure you’re using the right version of some library or another can be annoying on the best of days. I have a situation like that where my "day job" requires (still, and hopefully not for much longer) JDK 8, but my side projects, learning efforts, etc. can use a more modern version.

Years ago, Charles Nutter shared a shell script he uses to switch JDKs. I’ve been happily using it, but I’ve made some minor tweaks, so I thought I’d share my version here in case it helps someone (and make it easier for me to find in the future ;).

UPDATE: It seems the original author is Nick Sieger. Thanks to you as well, Nick, for a great little utility!

The two primary changes in my script versus Charles' is that I try to set JDKS_ROOT if it’s not already set, and I try to filter out "false" JDK entries (where the Ubuntu packages, for example, seem to like to create symlinks). I have not tested these changes to make sure I haven’t broken MacOS support, however, so if you’re on a Mac and this doesn’t work correctly, please let me know. :)

Without further ado:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
#!/bin/bash
#
# Provides a function that allows you to choose a JDK.  Just set the environment
# variable JDKS_ROOT to the directory containing multiple versions of the JDK
# and the function will prompt you to select one.  JAVA_HOME and PATH will be cleaned
# up and set appropriately.

# Usage:
# Include in .profile or .bashrc or source at login to get 'pickjdk' command.
# 'pickjdk' alone to bring up a menu of installed JDKs on OS X. Select one.
# 'pickjdk <jdk number>' to immediately switch to one of those JDKs.

_checkos()
{
    if [ $(uname -s) = $1 ]; then
        return 0
    else
        return 1
    fi
}

if [ -z "$JDKS_ROOT" ] ; then
    if _checkos Linux ; then
        JDKS_ROOT=/usr/lib/jvm
    elif _checkos Darwin ; then
        JDKS_ROOT=/Library/Java/JavaVirtualMachines
    fi
fi

pickjdk()
{
    if [ -z "$JDKS_ROOT" ]; then
        return 1
    fi

    declare -a JDKS
    local n=1 jdk total_jdks choice=0 currjdk=$JAVA_HOME explicit_jdk
    for jdk in $JDKS_ROOT/[0-9a-z]*; do
        if [ ! -L $jdk -a -d $jdk -a -e $jdk/bin ]; then
            JDKNAMES[$n]="$(basename $jdk)"
            if _checkos Darwin ; then
                jdk=$jdk/Contents/Home
            fi
            if [ -z "$1" ]; then
              echo -n " $n) ${JDKNAMES[$n]}"
              if [ $jdk = "$currjdk" ]; then
                  echo " < CURRENT"
              else
                  echo
              fi
            fi
            JDKS[$n]=$jdk
            total_jdks=$n
            n=$[ $n + 1 ]
        fi
    done
    if [ -z "$1" ]; then
      echo " $n) None"
    fi
    JDKS[$n]=None
    total_jdks=$n

    if [ $total_jdks -gt 1 ]; then
        if [ -z "$1" ]; then
          while [ -z "${JDKS[$choice]}" ]; do
              echo -n "Choose one of the above [1-$total_jdks]: "
              read choice
          done
        else
          choice=$1
        fi
    fi

    if [ -z "$currjdk" ]; then
        currjdk=$(dirname $(dirname $(type -path java)))
    fi

    if [ ${JDKS[$choice]} != None ]; then
        export JAVA_HOME=${JDKS[$choice]}
    else
        unset JAVA_HOME
    fi

    explicit_jdk=
    for jdk in ${JDKS[*]}; do
        if [ "$currjdk" = "$jdk" ]; then
            explicit_jdk=$jdk
            break
        fi
    done

    if [ "$explicit_jdk" ]; then
        if [ -z "$JAVA_HOME" ]; then
            PATH=$(echo $PATH | sed "s|$explicit_jdk/bin:*||g")
        else
            PATH=$(echo $PATH | sed "s|$explicit_jdk|$JAVA_HOME|g")
        fi
    elif [ "$JAVA_HOME" ]; then
        PATH="$JAVA_HOME/bin:$PATH"
    fi

    echo "New JDK: ${JDKNAMES[$choice]}"

    hash -r
}

To use this, add the following to your Bash profile:

1
source /path/to/pickjdk.sh

Restart your shell (or source the file directly), and you can do this:

1
2
3
4
5
$ pickjdk
 1) java-11-openjdk-amd64 < CURRENT
 2) oracle-java8-jdk-amd64
 3) None
Choose one of the above [1-3]:

Make your selection, and you’re all set. It’s awesome.

Search

    Quotes

    Sample quote

    Quote source

    About

    My name is Jason Lee. I am a software developer living in the middle of Oklahoma. I’ve been a professional developer since 1997, using a variety of languages, including Java, Javascript, PHP, Python, Delphi, and even a bit of C#. I currently work for Red Hat on the WildFly/EAP team, where, among other things, I maintain integrations for some MicroProfile specs, OpenTelemetry, Micrometer, Jakarta Faces, and Bean Validation. (Full resume here. LinkedIn profile)

    I am the president of the Oklahoma City JUG, and an occasional speaker at the JUG and a variety of technical conferences.

    On the personal side, I’m active in my church, and enjoy bass guitar, running, fishing, and a variety of martial arts. I’m also married to a beautiful woman, and have two boys, who, thankfully, look like their mother.

    My Links

    Publications