├── .java-version ├── src ├── com.greetings │ ├── module-info.java │ └── com │ │ └── greetings │ │ └── Main.java ├── com.socket │ ├── module-info.java │ └── com │ │ └── socket │ │ ├── spi │ │ └── NetworkSocketProvider.java │ │ └── NetworkSocket.java └── org.fastsocket │ ├── module-info.java │ └── org │ └── fastsocket │ ├── FastNetworkSocket.java │ └── FastNetworkSocketProvider.java ├── .gitignore ├── .tag.sh ├── step.sh └── README.md /.java-version: -------------------------------------------------------------------------------- 1 | 9-ea 2 | -------------------------------------------------------------------------------- /src/com.greetings/module-info.java: -------------------------------------------------------------------------------- 1 | module com.greetings { 2 | requires com.socket; 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | lib 3 | 4 | # IDEA 5 | .idea 6 | *.iml 7 | 8 | # Vim 9 | *.sw[op] 10 | -------------------------------------------------------------------------------- /src/com.socket/module-info.java: -------------------------------------------------------------------------------- 1 | module com.socket { 2 | exports com.socket; 3 | exports com.socket.spi; 4 | uses com.socket.spi.NetworkSocketProvider; 5 | } 6 | -------------------------------------------------------------------------------- /src/org.fastsocket/module-info.java: -------------------------------------------------------------------------------- 1 | module org.fastsocket { 2 | requires com.socket; 3 | provides com.socket.spi.NetworkSocketProvider 4 | with org.fastsocket.FastNetworkSocketProvider; 5 | } 6 | -------------------------------------------------------------------------------- /.tag.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | git tag -l | grep ^step | xargs git tag -d 4 | let i=0 5 | for sha in $(git log --grep openjdk --reverse --pretty=%h) 6 | do 7 | git tag -f step$i $sha 8 | let i=i+1 9 | done 10 | -------------------------------------------------------------------------------- /src/com.socket/com/socket/spi/NetworkSocketProvider.java: -------------------------------------------------------------------------------- 1 | package com.socket.spi; 2 | 3 | import com.socket.NetworkSocket; 4 | 5 | public interface NetworkSocketProvider { 6 | 7 | NetworkSocket openNetworkSocket(); 8 | } 9 | -------------------------------------------------------------------------------- /src/org.fastsocket/org/fastsocket/FastNetworkSocket.java: -------------------------------------------------------------------------------- 1 | package org.fastsocket; 2 | 3 | import com.socket.NetworkSocket; 4 | 5 | class FastNetworkSocket implements NetworkSocket { 6 | 7 | @Override 8 | public void close() { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/com.greetings/com/greetings/Main.java: -------------------------------------------------------------------------------- 1 | package com.greetings; 2 | 3 | import com.socket.NetworkSocket; 4 | 5 | public class Main { 6 | 7 | public static void main(String[] args) { 8 | NetworkSocket socket = NetworkSocket.open(); 9 | Object name = socket.getClass(); 10 | System.out.format("Greetings from %s!\n", name); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/org.fastsocket/org/fastsocket/FastNetworkSocketProvider.java: -------------------------------------------------------------------------------- 1 | package org.fastsocket; 2 | 3 | import com.socket.NetworkSocket; 4 | import com.socket.spi.NetworkSocketProvider; 5 | 6 | public class FastNetworkSocketProvider implements NetworkSocketProvider { 7 | 8 | @Override 9 | public NetworkSocket openNetworkSocket() { 10 | return new FastNetworkSocket(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/com.socket/com/socket/NetworkSocket.java: -------------------------------------------------------------------------------- 1 | package com.socket; 2 | 3 | import com.socket.spi.NetworkSocketProvider; 4 | 5 | import java.io.Closeable; 6 | import java.util.Iterator; 7 | import java.util.ServiceLoader; 8 | 9 | public interface NetworkSocket extends Closeable { 10 | 11 | static NetworkSocket open() { 12 | ServiceLoader serviceLoader = 13 | ServiceLoader.load(NetworkSocketProvider.class); 14 | 15 | Iterator providers = serviceLoader.iterator(); 16 | if (!providers.hasNext()) 17 | throw new RuntimeException("No service providers found!"); 18 | 19 | NetworkSocketProvider provider = providers.next(); 20 | return provider.openNetworkSocket(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /step.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set +x 4 | cat << task 5 | 6 | Compile 7 | 8 | task 9 | (rm -rf bin && mkdir bin) || exit 10 | mkdir bin/com.socket 11 | mkdir bin/com.greetings 12 | mkdir bin/org.fastsocket 13 | set -x 14 | 15 | javac -d bin/com.socket \ 16 | $(find src/com.socket -name '*.java') || exit 17 | 18 | javac -d bin/com.greetings \ 19 | --module-path bin \ 20 | $(find src/com.greetings -name '*.java') || exit 21 | 22 | javac -d bin/org.fastsocket \ 23 | --module-path bin \ 24 | $(find src/org.fastsocket -name '*.java') || exit 25 | 26 | find bin -type f 27 | 28 | 29 | set +x 30 | cat << task 31 | 32 | Assemble 33 | 34 | task 35 | (rm -rf lib && mkdir lib) || exit 36 | set -x 37 | 38 | jar --create --file=lib/com.socket.jar \ 39 | -C bin/com.socket . || exit 40 | 41 | jar --print-module-descriptor --file=lib/com.socket.jar || exit 42 | 43 | jar --create --file=lib/com.greetings.jar \ 44 | --main-class=com.greetings.Main \ 45 | -C bin/com.greetings . || exit 46 | 47 | jar --print-module-descriptor --file=lib/com.greetings.jar || exit 48 | 49 | jar --create --file=lib/org.fastsocket.jar \ 50 | -C bin/org.fastsocket . || exit 51 | 52 | jar --print-module-descriptor --file=lib/org.fastsocket.jar || exit 53 | 54 | 55 | set +x 56 | cat << task 57 | 58 | Run 59 | 60 | task 61 | set -x 62 | 63 | java \ 64 | --module-path lib \ 65 | -m com.greetings 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java Module System Quick-Start Guide 2 | 3 | This repository is based on Project Jigsaw's [Module System Quick-Start Guide](http://openjdk.java.net/projects/jigsaw/quick-start). The sections there have been reworked here into a series of commits and runnable code, each demonstrating a key aspect of Java's new module system. 4 | 5 | Along the way, you'll transform a traditional Java main class into a _Java module_ that makes use of all the major features Jigsaw has to offer. Each step can be run using the `step.sh` script, but the steps can also simply be read in order using `git log`. See below for instructions on both approaches. 6 | 7 | ## How to use this guide 8 | 9 | The commits in this repository are meant to be read in order like a tutorial, and the best way to do that is at the command line on your local machine. 10 | 11 | First, clone the repo: 12 | 13 | $ git clone https://github.com/cbeams/jigsaw-quick-start.git 14 | $ cd jigsaw-quick-start 15 | 16 | Then set up these two `git` aliases: 17 | 18 | $ git config alias.steps 'log --oneline --reverse step0^..step7' 19 | $ git config alias.read 'log -p --reverse step0^..step7' 20 | 21 | The first alias, `git steps` shows you an overview of each step in the guide: 22 | 23 | $ git steps 24 | c7facdc (tag: step0) Introduce com.greetings package and main class 25 | b4dbc1a (tag: step1) Transform com.greetings source into a Java module 26 | 7f62b33 (tag: step2) Assemble com.greetings into executable modular jar 27 | f131a70 (tag: step3) Introduce org.astro module dependency 28 | bdb74ae (tag: step4) Remove requires statement and fail at compile time 29 | cccaaab (tag: step5) Remove exports statement and fail at compile time 30 | 96cff2b Revert introduction of the org.astro module 31 | 7b3c7d1 (tag: step6) Introduce SPI without provider and fail at runtime 32 | a5db24c (tag: step7) Introduce service provider and bind successfully 33 | 34 | The second alias, `git read` displays the log of each commit, in order, including both comment and patch. This allows you to see exactly what changes in each step and why: 35 | 36 | ```diff 37 | $ git read 38 | commit c7facdca5d51370ef6a6df8725279eaec3c872d2 (tag: step0) 39 | Author: Chris Beams 40 | Date: Tue Oct 13 16:09:44 2015 +0200 41 | 42 | Introduce com.greetings package and main class 43 | 44 | This step adds a simple main class, compiles it with javac and runs it 45 | with java in the usual fashion. No Jigsaw and no modules yet; that will 46 | come in the next step. 47 | 48 | When this step is run, it should print the following to the console: 49 | 50 | $ ./step.sh 51 | Greetings from main! 52 | 53 | See http://openjdk.java.net/projects/jigsaw/quick-start#greeting 54 | 55 | diff --git src/com.greetings/com/greetings/Main.java 56 | new file mode 100644 57 | index 0000000..4f5991f 58 | --- /dev/null 59 | +++ src/com.greetings/com/greetings/Main.java 60 | @@ -0,0 +1,9 @@ 61 | +package com.greetings; 62 | + 63 | +public class Main { 64 | + 65 | + public static void main(String[] args) { 66 | + Object name = "main"; 67 | + System.out.format("Greetings from %s!\n", name); 68 | + } 69 | +} 70 | diff --git step.sh step.sh 71 | index 59bf8a3..b20a0fe 100755 72 | --- step.sh 73 | +++ step.sh 74 | @@ -7,9 +7,12 @@ cat << task 75 | 76 | task 77 | (rm -rf bin && mkdir bin) || exit 78 | -echo '(nothing to compile yet)' 79 | +mkdir bin/com.greetings 80 | set -x 81 | 82 | +javac -d bin/com.greetings \ 83 | + $(find src/com.greetings -name '*.java') || exit 84 | + 85 | find bin -type f 86 | 87 | @@ -30,5 +33,8 @@ cat << task 88 | Run 89 | 90 | task 91 | -echo '(nothing to run yet)' 92 | set -x 93 | + 94 | +java \ 95 | + -classpath bin/com.greetings \ 96 | + com.greetings.Main 97 | 98 | commit b4dbc1ab8cc23dc64aabdf6e79cb491ba6546407 (tag: step1) 99 | Author: Chris Beams 100 | Date: Thu Oct 8 16:12:50 2015 +0200 101 | 102 | Transform com.greetings source into a Java module 103 | 104 | This step transforms the existing `com.greetings` source into a Java 105 | module simply by introducing an empty `module-info.java` file at the 106 | source directory root. 107 | 108 | With this _module declaration_ file in place and compiled along with the 109 | rest of the sources, `java` can now be invoked with its new `--module-path` 110 | option as opposed to the traditional `-classpath` option. Note how the 111 | modulepath now need only contain the top-level `bin` output directory, 112 | while the path to the main class (the new `-m` option) needs to be fully 113 | qualified by both module and package. 114 | 115 | When this step is run, the output should remain the same as the previous 116 | step. Nothing has changed in the program itself; only how the compiled 117 | artifacts are structured and invoked has changed: 118 | 119 | $ ./step.sh 120 | Greetings from main! 121 | 122 | See http://openjdk.java.net/projects/jigsaw/quick-start#greetings 123 | 124 | diff --git src/com.greetings/module-info.java 125 | new file mode 100644 126 | index 0000000..4a27728 127 | --- /dev/null 128 | +++ src/com.greetings/module-info.java 129 | @@ -0,0 +1,2 @@ 130 | +module com.greetings { 131 | +} 132 | diff --git step.sh step.sh 133 | index b20a0fe..37b0c9f 100755 134 | --- step.sh 135 | +++ step.sh 136 | @@ -36,5 +36,5 @@ task 137 | set -x 138 | 139 | java \ 140 | - -classpath bin/com.greetings \ 141 | - com.greetings.Main 142 | + --module-path bin \ 143 | + -m com.greetings/com.greetings.Main 144 | ``` 145 | 146 | ## Run the steps 147 | 148 | The [step.sh](step.sh) script is present at each step in the guide, and you can run it to see Jigsaw in action. 149 | 150 | To do this, you'll first need a [JDK 9 early access build that includes project Jigsaw](https://jdk9.java.net/jigsaw/). Build 111 or better will work. 151 | 152 | Once properly installed, `java -version` should tell you something like this: 153 | 154 | $ java -version 155 | java version "9-ea" 156 | Java(TM) SE Runtime Environment (build 9-ea+111-2016-03-30-170352.javare.4768.nc) 157 | Java HotSpot(TM) 64-Bit Server VM (build 9-ea+111-2016-03-30-170352.javare.4768.nc, mixed mode) 158 | 159 | At this point you're ready to run through each step using the following commands: 160 | 161 | 1. Check out a step 162 | ``` 163 | $ git checkout step0 164 | ``` 165 | 166 | 2. Read the commit to understand what's changed 167 | ``` 168 | $ git show 169 | ``` 170 | 171 | 3. Run the demo script to see it all in action 172 | ``` 173 | $ ./step.sh 174 | ``` 175 | 176 | then repeat for each of the remaining steps 177 | 178 | $ git checkout step1 179 | $ git show 180 | $ ./step.sh 181 | ... 182 | 183 | and remember to use `git steps` as a table of contents if you want to jump around. 184 | --------------------------------------------------------------------------------