Running multiple version of JDK in Windows commandLine, the fun? way
Tags: java, productivity, terminal, windows
Published: 2022-09-26 16:50:24

In this blog I'll walk you through on how to config your various terminal to dynamically switch JDK version in a painless? and a bit cooler way right from your terminal.

## Table Of Contents
  * [Prepare JDK and prerequisites](#prepare-jdk-and-prerequisites)
  * [Command Prompt](#command-prompt)
  * [Powershell 5 & 7](#powershell-5-amp-7)
  * [Cmder](#cmder)

---

> why not use the wsl?

yes, we can config it easily like we did in any bash in linux, which is cool 😁 and another great thing I found out recently about WSL is that it can execute windows binary file like those `exe` directly from wsl terminal.


Don't believe me? here's an example 😜


> I'll test on `oc` cli that I'm using to do stuff with my openshift cluster as an example in this case.

- let's start with check where the `oc.exe` is located

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/avr2nxd5uwffmcbdlmqj.png)

- test some command

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yd66i00938vbjh9u3dpy.png)

- now switch to ubuntu wsl terminal and notice the `oc` bin that belong to this ubuntu wsl

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gywvplwwvdkf0afhvli7.png)

- let's test some command, we will noticed the `unauth` response since I didn't share the config between windows/wsl

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a0yzh7m74bsni8i4eky8.png)

- now let's `cd` into the windows folder with the `exe` file we want to test, in order to access our windows file, the path will have to be pre-fix with `/mnt/` and followed by normal drive letter without colon symbol

> for example: /mnt/c/windows/system32/

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h4s0c3tijtsjnxzpcgcy.png)

- when call the `oc.exe` file we'll notice the response returned normally instead of `unauth` like the above command, this because we invoked the one that belong in windows env which is the same as we invoked in windows `cmd`, amazing isn't it?

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qzkzho3aow1qm8i7pgdg.png)

---

ok but that's not the point of this blog, if you're like me who don't like context-switching too much and only use it when neccessery, let's continue see what we can do to run multiple JDK in windows env.

---

## 🤖 Prepare JDK and pre-requisites
usually when we installed JDK package through windows installer we'll ended up with something like this

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u9wy9q4j8jxxtke4ilyb.png)

and when we run the java version check it'll run one of these 3 depends on how you installed it, notice that I didn't set the `JAVA_HOME` yet

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7uw1w1rlc54gpgi5ualq.png)

next, you'll need [chocolatey](https://docs.chocolatey.org/en-us/choco/setup#install-with-cmd.exe) package manager for its `refreshenv` utility, if you don't want to install chocolatey or other reason, you can get this util directly from [chocolatey github](https://github.com/chocolatey/choco/blob/1.1.0/src/chocolatey.resources/redirects/RefreshEnv.cmd) then register the `bat` in `PATH` environment variable

and that's it for preparation part.

## 💻 Command Prompt

in order to do `alias` or other custom command, we'll have to go extra miles(or Km) to config this `ol-cmd` terminal(seriously, please replace it with something powerful Microsoft 😗)

- Choose the location to store our new script files, in this case I'll use `cmd_script` in my `%userprofile%` to store it

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kpbpmnj0c9k0qmzr7g6m.png">
  <figcaption>create new folder to use as script location</figcaption>
</figure>
---

- add it to the `PATH` by going to environment variable settings

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twf2ikzi8lfwjwq4muae.png">
  <figcaption>type `env` in search bar</figcaption>
</figure>
---

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v0etbm5scwxvxz6y2t4o.png">
  <figcaption>click on `Environment Variable`</figcaption>
</figure>
---

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/slgx2o4b02ynr2rlcivf.png">
  <figcaption>look for `PATH` then edit it to add our script location we created earlier</figcaption>
</figure>
---

- create new folder named `alias` inside the script folder then add it to the `PATH`

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/30g3drw9tfliiigu4033.png">
  <figcaption>alias folder will serve as our alias</figcaption>
</figure>
---

- create new script called `usejdk.cmd` or `usejdk.bat` 

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vfguszegm7wf3a02tm2r.png">
  <figcaption>create new script in the script folder</figcaption>
</figure>

> the above process should be the same when you add `refreshEnv.cmd` if you didn't use chocolatey

---

- add the following script to the `usejdk` bat file

```shell
@echo off

set JDK_VERSION=%~1

if "%JDK_VERSION%" == "" (
  goto usage
) else if "%JDK_VERSION%" == "8" (
    set JAVA_HOME="C:\Program Files\Eclipse Adoptium\jdk-8.0.345.1-hotspot"
)
GOTO :eof

:usage
ECHO Please select your Java Version
ECHO Usage: useJDK [version]
EXIT /B 1
```

> change the JAVA_HOME path to suit your need and add addtional condition if you have more than 2 JDK

- Test the script if it's working correctly

```shell
C:\Users\Rujra>usejdk 11

C:\Users\Rujra>echo %JAVA_HOME%
"C:\Program Files\Eclipse Adoptium\jdk-11.0.16.101-hotspot"

C:\Users\Rujra>java -version
openjdk version "1.8.0_345"
OpenJDK Runtime Environment (Temurin)(build 1.8.0_345-b01)
OpenJDK 64-Bit Server VM (Temurin)(build 25.345-b01, mixed mode)

C:\Users\Rujra>
```

> noticed that even though we set the `JAVA_HOME` the java runtime didn't changed, that's because it's registered in `PATH` env, hardcoded. 

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ip0bkhzeqjf5qjaig0i0.png">
  <figcaption>the hard-coded path env that we didn't touch earlier</figcaption>
</figure>
---

- this can be solve in 2 ways
  1. remove the jdk/bin path from our `PATH` env then add a new one with `%JAVA_HOME%\bin`
  2. leave it be but move those down to the bottom of `PATH` env then add the java home from `1.` and move it up to the top
      - this method can be useful if you want to run something like `where java` which will list all knows java binary in `PATH`

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9i32leoxhzu8vgkgz286.png">
  <figcaption>the PATH env after some changes</figcaption>
</figure>
---

- let's try again
```shell
C:\Users\Rujra>usejdk 11

C:\Users\Rujra>echo %JAVA_HOME%
"C:\Program Files\Eclipse Adoptium\jdk-11.0.16.101-hotspot"

C:\Users\Rujra>java -version
openjdk version "1.8.0_345"
OpenJDK Runtime Environment (Temurin)(build 1.8.0_345-b01)
OpenJDK 64-Bit Server VM (Temurin)(build 25.345-b01, mixed mode)
```
> still not working 😾

- now let's check the `PATH`
```shell
C:\Users\Rujra>PATH
PATH=C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.14.2282.0_x64__8wekyb3d8bbwe;%JAVA_HOME%\bin;[other path env blah blah blah];
```
> noticed the %JAVA_HOME% in PATH? that's where our `refreshenv` will come into play next

- modify the `usejdk` script with our long-awaited `refreshenv` util
```shell
...
) else if "%JDK_VERSION%" == "8" (
    set JAVA_HOME="C:\Program Files\Eclipse Adoptium\jdk-8.0.345.1-hotspot"
    refreshenv
)
...
```

- third?? time's a charm, I hope 😗.
```shell
C:\Users\Rujra>usejdk 11
Refreshing environment variables from registry for cmd.exe. Please wait...Finished..

C:\Users\Rujra>PATH
PATH="C:\Program Files\Eclipse Adoptium\jdk-11.0.16.101-hotspot"\bin;[other path env blah blah blah];

C:\Users\Rujra>java -version
openjdk version "11.0.16.1" 2022-08-12
OpenJDK Runtime Environment Temurin-11.0.16.1+1 (build 11.0.16.1+1)
OpenJDK 64-Bit Server VM Temurin-11.0.16.1+1 (build 11.0.16.1+1, mixed mode)
```
> now it's working, WOW, so easy! 🤯 I almost had a migraine tbh🤷‍♂️.

---

## 💠 Powershell 5 & 7

In powershell, it's a bit easier to manipulate the env var/alias since everything is stored inside "special" `env:` and `alias:` PSdrive
> why is it matters? because we will use these to help us switch between multiple JDK in a moment

> ! important: before we proceed please make sure you have set the `PATH` variable with `%JAVA_HOME%\bin` at the top like we did in `CMD` steps

#### Environment Variable
to display the current env we can do the following

```shell
PS C:\Users\Rujra> dir env:

Name                           Value
----                           -----
ALLUSERSPROFILE                C:\ProgramData
ChocolateyInstall              C:\ProgramData\chocolatey
``` 
> to query specific key, just add the key to path `dir env:\some_thing` 
> to query value only, add `$` to env `$env:some_thing`

---

#### Alias
to display Alias is the same as Env var

```shell
PS C:\Users\Rujra> dir alias:

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           % -> ForEach-Object
Alias           ? -> Where-Object
Alias           CFS -> ConvertFrom-String                          3.1.0.0    Microsoft.PowerShell.Utility
``` 
> to query specific key, just add the key to path `dir alias:\some_thing`
> to query value only, add `$` to env `$alias:some_thing`

---

#### Steps
- in order to persist configuration across terminal session we'll have to create a profile for powershell by do the following command

```powershell
new-item -path $profile -itemtype file -force
```
- now open the profile in your favourite ide and add the following script

```powershell
function java8 { 
    $Env:JAVA_HOME = "[your JDK ROOT PATH]"
    refreshenv
}
function java11 { 
    $Env:JAVA_HOME = "[your JDK ROOT PATH]"
    refreshenv
}
...
```
- re-open your powershell and see if the function getting load normally, however on the first time you might ran into this problem

```powershell
. : File ...\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 cannot be loaded because
running scripts is disabled on this system. For more information, see about_Execution_Policies at
https:/go.microsoft.com/fwlink/?LinkID=135170.
At line:1 char:3
+ . '...\WindowsPowerShell\Microsoft.Powe ...
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : SecurityError: (:) [], PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess
```
> this [stackoverflow](https://stackoverflow.com/a/26955050) answer give a great explanation on how to solve this issue without compromise much of your machine security

- after powershell started successfully, now it's the time to test our little script

```powershell
PS C:\Users\Rujra> java8
Refreshing environment variables from registry for cmd.exe. Please wait...Finished..
PS C:\Users\Rujra> $env:PATH
%JAVA_HOME%\bin;[other PATH env blah blah blah]
PS C:\Users\Rujra> $env:JAVA_HOME
C:\Program Files\Eclipse Adoptium\jdk-8.0.345.1-hotspot
PS C:\Users\Rujra> java -version
openjdk version "17.0.4.1" 2022-08-12
OpenJDK Runtime Environment Temurin-17.0.4.1+1 (build 17.0.4.1+1)
OpenJDK 64-Bit Server VM Temurin-17.0.4.1+1 (build 17.0.4.1+1, mixed mode, sharing)
```
> noticed that even with `refreshenv` it didn't worked, this is because it refresh `cmd.exe` and not `powershell.exe` we'll have to come up with another solution

- from previous test, we'll see that it didn't worked as we expected, so, let's try another method by modify our script as below

```powershell
function java8 { 
    $Env:JAVA_HOME = "[your JDK ROOT PATH]"
    $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine")
}
function java11 { 
    $Env:JAVA_HOME = "[your JDK ROOT PATH]"
    $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine")
}
...
```
> this will replace `refreshenv` with manually load new env var from the machine env var to current `powershell` session

- now let's close and re-open `powershell` and see if this time it working correctly.

```powershell
PS C:\Users\Rujra> $env:PATH
%JAVA_HOME%\bin;[other PATH env blah blah blah]
PS C:\Users\Rujra> java -version
openjdk version "17.0.4.1" 2022-08-12
OpenJDK Runtime Environment Temurin-17.0.4.1+1 (build 17.0.4.1+1)
OpenJDK 64-Bit Server VM Temurin-17.0.4.1+1 (build 17.0.4.1+1, mixed mode, sharing)
PS C:\Users\Rujra> $env:JAVA_HOME
PS C:\Users\Rujra> java11
PS C:\Users\Rujra> $env:PATH
C:\Program Files\Eclipse Adoptium\jdk-11.0.16.101-hotspot\bin;[other PATH env blah blah blah]
PS C:\Users\Rujra> $env:JAVA_HOME
C:\Program Files\Eclipse Adoptium\jdk-11.0.16.101-hotspot
PS C:\Users\Rujra> java -version
openjdk version "11.0.16.1" 2022-08-12
OpenJDK Runtime Environment Temurin-11.0.16.1+1 (build 11.0.16.1+1)
OpenJDK 64-Bit Server VM Temurin-11.0.16.1+1 (build 11.0.16.1+1, mixed mode)
```
> now it's working, a bit easier to config than `CMD` for sure, cheers 🥂

---

## 🖲️ Cmder

Now we've come to the last terminal I'll config for this blog, The powerful [Cmder](https://cmder.app/)

Cmder itself has many features off-the-shelf including linux commands that you can use alongside your normal windows commands whether it's `ls -lha` `dir` etc, but now I'll add a bit more power to it by adding ability to dynamically switch JDK version with alias.

> ! important: before we proceed please make sure you have set the `PATH` variable with `%JAVA_HOME%\bin` at the top like we did in `CMD` or `Powershell` steps

- first, after you've downloaded and extracted cmder to your machine, you'll have something like this below

```bash
D:\Programs\Cmder
λ ls -lha
total 169K
drwxr-xr-x 1 Rujra 197609    0 Feb  3  2022  ./
drwxr-xr-x 1 Rujra 197609    0 Sep  4 13:47  ../
drwxr-xr-x 1 Rujra 197609    0 Jan 26  2020  bin/
-rwxr-xr-x 1 Rujra 197609 139K Jan 17  2022  Cmder.exe*
-rw-r--r-- 1 Rujra 197609   33 Mar  9  2020  cmder_shell.bat
drwxr-xr-x 1 Rujra 197609    0 Sep 27 18:56  config/
drwxr-xr-x 1 Rujra 197609    0 Jan 26  2020  icons/
-rw-r--r-- 1 Rujra 197609 1.1K Jan 17  2022  LICENSE
drwxr-xr-x 1 Rujra 197609    0 Oct 31  2021  opt/
drwxr-xr-x 1 Rujra 197609    0 Feb  3  2022  vendor/
-rw-r--r-- 1 Rujra 197609    0 Jan 17  2022 'Version 1.3.19.1181'
```

- inside `config` folder there will be some config files, but we will be focus on 2 configs only
  - user_aliases.cmd
  - user_profile.cmd

```bash
D:\Programs\Cmder\config
λ ls -lha
total 508K
drwxr-xr-x 1 Rujra 197609    0 Sep 27 18:58 ./
drwxr-xr-x 1 Rujra 197609    0 Feb  3  2022 ../
-rw-r--r-- 1 Rujra 197609 4.2K Sep 27 18:58 clink.log
-rw-r--r-- 1 Rujra 197609 377K Sep 27 18:56 clink_history
-rw-r--r-- 1 Rujra 197609  121 Sep 27 18:58 clink_history_23924
-rw-r--r-- 1 Rujra 197609   97 Sep 27 18:56 clink_history_23924.removals
-rw-r--r-- 1 Rujra 197609    0 Sep 27 18:56 clink_history_23924~
-rw-r--r-- 1 Rujra 197609  507 Oct 31  2021 clink_settings
-rw-r--r-- 1 Rujra 197609 2.0K Mar 16  2022 cmder_prompt_config.lua
-rw-r--r-- 1 Rujra 197609  29K May 11  2021 mini_dump.dmp
drwxr-xr-x 1 Rujra 197609    0 Feb  3  2022 profile.d/
-rw-r--r-- 1 Rujra 197609  887 Jan 17  2022 Readme.md
-rw-r--r-- 1 Rujra 197609  672 Sep 26 19:29 user_aliases.cmd
-rw-r--r-- 1 Rujra 197609  967 Sep 26 18:42 user_profile.cmd
-rw-r--r-- 1 Rujra 197609  408 Dec 23  2018 user_profile.ps1
-rw-r--r-- 1 Rujra 197609  54K Jun 23 16:18 user-ConEmu.xml
```

- inside `user_profile.cmd` add the following config
```bat
...
:: JAVA config
set JAVA_8_HOME="[your JDK ROOT PATH]"
set JAVA_11_HOME="[your JDK ROOT PATH]"
:: Other jdk you're using
...
```

- now after we set env on the profile, we'll set alias in `user_aliases.cmd` to switch the java version whenever we needed.

```bat
;= JAVA_HOME

java8=set JAVA_HOME=%JAVA_8_HOME%&refreshenv
java11=set JAVA_HOME=%JAVA_11_HOME%&refreshenv
```

- saves and open up `Cmder` and let's try the new alias

```bash

C:\Users\Rujra
λ echo %PATH%
%JAVA_HOME%\bin;[other PATH env blah blah blah];

C:\Users\Rujra
λ echo %JAVA_HOME%
%JAVA_HOME%

C:\Users\Rujra
λ java -version
openjdk version "17.0.4.1" 2022-08-12
OpenJDK Runtime Environment Temurin-17.0.4.1+1 (build 17.0.4.1+1)
OpenJDK 64-Bit Server VM Temurin-17.0.4.1+1 (build 17.0.4.1+1, mixed mode, sharing)

C:\Users\Rujra
λ java11
Refreshing environment variables from registry for cmd.exe. Please wait...Finished..

C:\Users\Rujra
λ echo %PATH%
"C:\Program Files\Eclipse Adoptium\jdk-11.0.16.101-hotspot"\bin;[other PATH env blah blah blah];

C:\Users\Rujra
λ echo %JAVA_HOME%
"C:\Program Files\Eclipse Adoptium\jdk-11.0.16.101-hotspot"

C:\Users\Rujra
λ java -version
openjdk version "11.0.16.1" 2022-08-12
OpenJDK Runtime Environment Temurin-11.0.16.1+1 (build 11.0.16.1+1)
OpenJDK 64-Bit Server VM Temurin-11.0.16.1+1 (build 11.0.16.1+1, mixed mode)
```
> work like a charm 😁👾

---

and that's it, thank you for reading, this is my first (finished)blog, any feedbacks & suggestions are gladly welcome! 🙌

---