Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions _clojure_jvm/02_basic_java.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Interfaces can declare any number of super-interfaces, along with methods that i

__Hello.java__
{% highlight java %}
{% include code/basic_java/Hello.java %}
{% include code/basic_java/Hello.java -%}
{% endhighlight %}

This defines a class `Hello` in the package `test`. This class contains a single static `main` method which writes a short message to the console.
Expand Down Expand Up @@ -78,7 +78,7 @@ disk. They can be loaded from the network, a database or defined dynamically dep
core Java classes and loads them as required.

Older JVMs (before version 9) did ship core Java classes in a Java archive. This was usually located at `jre/lib/rt.jar` within the JVM distribution. The bootstrap class loader
was additionally configured with a 'bootstrap classpath' containing this core archive. Since the advent of Java modules in Java 9, core classes are distributed in a more efficient
was additionally configured with a 'bootstrap classpath' containing this core archive. Since the advent of Java modules in Java 9, core classes are distributed in a more efficient
format.

You can tell the `java` command to log more information on the class loading process with the `-verbose` option.
Expand Down
12 changes: 6 additions & 6 deletions _clojure_jvm/03_class_files.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Here's the simple Java class from the previous chapter:

__Hello.java__
{% highlight java %}
{% include code/basic_java/Hello.java %}
{% include code/basic_java/Hello.java -%}
{% endhighlight %}

When compiled with `javac`:
Expand All @@ -18,7 +18,7 @@ When compiled with `javac`:
it creates a `test/Hello.class` file in the current directory. Opening this file with `javap` shows a brief summary of the `test.Hello` class:

```
{% include code/basic_java/hello_summary %}
{% include code/basic_java/hello_summary -%}
```

The `.class` file contains all the information required to load the class and execute its methods. The full contents of the file can be displayed
Expand All @@ -29,7 +29,7 @@ using the `-verbose` option:
This shows much more detail:

```
{% include code/basic_java/hello_full %}
{% include code/basic_java/hello_full -%}
```

The format of `.class` files is described in full in the [JVM specification](https://docs.oracle.com/javase/specs/jvms/se20/html/jvms-4.html).
Expand All @@ -54,7 +54,7 @@ Note `.class` files are stored in big-endian order which may differ from the arc
od --endian=big -x test/Hello.class

```
{% include code/basic_java/hello_dump %}
{% include code/basic_java/hello_dump -%}
```

## Version number
Expand All @@ -63,7 +63,7 @@ The first information displayed by `javap` is the major and minor version of the
which means it is only supported by versions 14 or higher of the JVM. Attempting to load this class on an older version of the JVM will result in an error e.g.

```
{% include code/basic_java/version_error %}
{% include code/basic_java/version_error -%}
```

## Class properties
Expand All @@ -78,7 +78,7 @@ code. These names and their types are recorded in the constant pool.

### Binary names

The format of binary names within `.class` files differs slightly from those in `.java` files. The `.` separator used by Java is replaced within `.class` files.
The format of binary names within `.class` files differs slightly from those in `.java` files. The `.` separator used by Java is replaced within `.class` files.
For example the class `java.lang.Object` will be refered to as `java/lang/Object` within class files.

### Descriptors
Expand Down
20 changes: 10 additions & 10 deletions _clojure_jvm/04_jar_files.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,24 @@ After some back-and-forth, we settle on defining interfaces for sources and dest

__src/libhello/MessageSource.java__
``` java
{% include code/jar/src/libhello/MessageSource.java %}
{% include code/jar/src/libhello/MessageSource.java -%}
```

__src/libhello/MessageSink.java__
``` java
{% include code/jar/src/libhello/MessageSink.java %}
{% include code/jar/src/libhello/MessageSink.java -%}
```

In addition, we define a source of messages read from the command-line, and a sink which writes messages to a `PrintStream`:

__src/libhello/CommandLineMessageSource.java__
```java
{% include code/jar/src/libhello/CommandLineMessageSource.java %}
{% include code/jar/src/libhello/CommandLineMessageSource.java -%}
```

__src/libhello/PrintStreamMessageSink.java__
```java
{% include code/jar/src/libhello/PrintStreamMessageSink.java %}
{% include code/jar/src/libhello/PrintStreamMessageSink.java -%}
```

We compile these classes as usual and output the corresponding class files to the `libhello` directory:
Expand All @@ -62,7 +62,7 @@ This shows the archive contains the `.class` files as their expected locations o
This file is called the _manifest_ file and is described [below](#manifest-files).

```
{% include code/jar/jar_list %}
{% include code/jar/jar_list -%}
```

Note that JAR files are also zip files, so their contents can be listed with the `unzip` command:
Expand All @@ -73,7 +73,7 @@ Now we have build our library, we can re-write our application to use it:

__src/app/Echo.java__
```java
{% include code/jar/src/app/Echo.java %}
{% include code/jar/src/app/Echo.java -%}
```

As before, we compile it with `javac`. Since the application references the classes in `libhello.jar`, we have to place it on the classpath
Expand All @@ -89,7 +89,7 @@ available by adding the jar file to the classpath. We also add the build output
As expected, the application reads each message from the command line and writes it to the console

```
{% include code/jar/app_output %}
{% include code/jar/app_output -%}
```

Of course we should also create a JAR for the application:
Expand All @@ -113,7 +113,7 @@ The `jar` tool can be used to extract the contents of the default manifest file:
this is fairly minimal by default:

```
{% include code/jar/default_manifest.mf %}
{% include code/jar/default_manifest.mf -%}
```

There are two additional manifest properties we would like to set when building the application JAR:
Expand All @@ -125,7 +125,7 @@ We can add these properties to a file to be added to the manifest when building

__echo-manifest.mf__
```
{% include code/jar/echo-manifest.mf %}
{% include code/jar/echo-manifest.mf -%}
```

> jar --create --file echo.jar --manifest=echo-manifest.mf -C classes/app .
Expand Down Expand Up @@ -154,7 +154,7 @@ since all classes are contained within the new JAR.

__uber-manifest.mf__
```
{% include code/jar/uber-manifest.mf %}
{% include code/jar/uber-manifest.mf -%}
```

We can now build the new JAR:
Expand Down
26 changes: 13 additions & 13 deletions _clojure_jvm/05_dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ After a frenetic caffeine-fueled 10-hour coding session, we finally have our new

__src/libhello/JSONMessageSource.java__
```
{% include code/java_dependencies/JSONMessageSource.java %}
{% include code/java_dependencies/JSONMessageSource.java -%}
```

As before, we compile the library, updating the build classpath to include the dependency JAR:
Expand All @@ -35,12 +35,12 @@ We write a small test application and data file for the new source

__EchoJSON.java__
```java
{% include code/java_dependencies/EchoJSON.java %}
{% include code/java_dependencies/EchoJSON.java -%}
```

__messages.json__
```json
{% include code/java_dependencies/messages.json %}
{% include code/java_dependencies/messages.json -%}
```

and run it to check the input messages are displayed as expected:
Expand Down Expand Up @@ -78,7 +78,7 @@ where JARs can be published and retrieved, along with their dependencies.

Maven projects are defined by a Project Object Model (POM) file in XML format called `pom.xml`. This defines all aspects of the project, such as
where to find source and test files, build and packaging information, and dependency definitions. All project `pom.xml` files implicitly inherit
from a '[super POM](https://maven.apache.org/ref/3.0.4/maven-model-builder/super-pom.html)' file defined by the Maven distribution. This defines
from a '[super POM](https://maven.apache.org/ref/3.0.4/maven-model-builder/super-pom.html)' file defined by the Maven distribution. This defines
the standard layout of a Maven project.

### Dependencies
Expand Down Expand Up @@ -109,7 +109,7 @@ determined by the artifact packaging type - this is usually `jar` for Java artif

#### Maven Central

Maven defines a single repository `central` in the [super POM](https://maven.apache.org/ref/3.0.4/maven-model-builder/super-pom.html). This is located at `http://repo.maven.apache.org/maven2` and it means that Maven
Maven defines a single repository `central` in the [super POM](https://maven.apache.org/ref/3.0.4/maven-model-builder/super-pom.html). This is located at `http://repo.maven.apache.org/maven2` and it means that Maven
projects can reference dependencies published to this repository without any further configuration.

#### Local repositories
Expand All @@ -120,7 +120,7 @@ Therefore, version `0.2.6` of the `data.json` JAR would be fetched to `~/.m2/rep
## Maven library development

Now that we understand the basics of Maven we can create a project for our library. First we create a directory for the project and set it up in the
standard Maven layout. As defined in the [super POM](https://maven.apache.org/ref/3.0.4/maven-model-builder/super-pom.html), Java source files go under
standard Maven layout. As defined in the [super POM](https://maven.apache.org/ref/3.0.4/maven-model-builder/super-pom.html), Java source files go under
`${project.basedir}/src/main/java`.

```
Expand All @@ -139,14 +139,14 @@ Our `pom.xml` file defines the coordinates for the library itself along with its

**pom.xml**
```xml
{% include code/java_dependencies/maven/pom.xml %}
{% include code/java_dependencies/maven/pom.xml -%}
```

Now we can compile and package the library as a JAR:

mvn package

The super POM sets the default build directory to `${project.basedir}/target` and if we look there we can see a `libhello-1.0.0.jar` file has been
The super POM sets the default build directory to `${project.basedir}/target` and if we look there we can see a `libhello-1.0.0.jar` file has been
created.

This can be installed into our local repository with
Expand Down Expand Up @@ -174,7 +174,7 @@ json-test/

**pom.xml**
```xml
{% include code/java_dependencies/app/pom.xml %}
{% include code/java_dependencies/app/pom.xml -%}
```

The application POM declares a dependency on the version of the library we want to use. As before the JAR can be built with
Expand Down Expand Up @@ -207,17 +207,17 @@ during development:

mvn exec:java -Dexec.mainClass=test.EchoJSON -Dexec.args="messages.json"

Another option is to build uber JARs using the [Maven shade plugin](https://maven.apache.org/plugins/maven-shade-plugin/index.html).
Another option is to build uber JARs using the [Maven shade plugin](https://maven.apache.org/plugins/maven-shade-plugin/index.html).

## Publishing

Now the library and application are working locally, it's time to share the library with our colleagues. Our chief architect is convinced
it constitutes a key competitive advantage for the company and is unwilling to unleash it on an unsuspecting public. She arranges for a private
Maven repository to be set up, and our CI process to publish there instead of the Maven Central repository. We advise any teams wishing to use
Maven repository to be set up, and our CI process to publish there instead of the Maven Central repository. We advise any teams wishing to use
it to configure the private repository in their application POM files with the following fragment:

```xml
{% include code/java_dependencies/private_repository.xml %}
{% include code/java_dependencies/private_repository.xml -%}
```

### Repository settings
Expand All @@ -229,5 +229,5 @@ repository, we just need to configure the credentials to use:

**~/.m2/settings.xml**
```xml
{% include code/java_dependencies/settings.xml %}
{% include code/java_dependencies/settings.xml -%}
```
8 changes: 4 additions & 4 deletions _clojure_jvm/06_common_issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,21 @@ This error usually occurs when an application is compiled against one version of

**version1/Greeter.java**
```java
{% include code/common_issues/version1/Greeter.java %}
{% include code/common_issues/version1/Greeter.java -%}
```

After some time, a new version of this class is created with a new method:

**version2/Greeter.java**
```java
{% include code/common_issues/version2/Greeter.java %}
{% include code/common_issues/version2/Greeter.java -%}
```

An application is created which uses the newer version:

**GreetApp.java**
```java
{% include code/common_issues/GreetApp.java %}
{% include code/common_issues/GreetApp.java -%}
```

Compiling both class versions and the application against the newer version
Expand All @@ -91,7 +91,7 @@ Running with the old version on the classpath results in an error:

```
> java -cp .:version1 GreetApp
{% include code/common_issues/nosuchmethoderror.txt %}
{% include code/common_issues/nosuchmethoderror.txt -%}
```

Some libraries deprecate and subsequently remove methods from classes, so it is possible that
Expand Down
2 changes: 1 addition & 1 deletion _clojure_jvm/07_evaluating_clojure.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ If we define the above namespace

**src/org/picosoft/lib_hello/core.clj**
```java
{% include code/evaluating_clojure/src/org/picosoft/lib_hello/core.clj %}
{% include code/evaluating_clojure/src/org/picosoft/lib_hello/core.clj -%}
```

and place it in the appropriate place on the classpath, we can invoke it via `clojure.main`
Expand Down
12 changes: 6 additions & 6 deletions _clojure_jvm/08_compiling_clojure.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ two classes with `gen-class`:

**src/greet.clj**
```clojure
{% include code/compiling_clojure/greet/src/greet.clj %}
{% include code/compiling_clojure/greet/src/greet.clj -%}
```

This can be compiled with the [compile](https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/compile) function. As described in the documentation,
Expand All @@ -26,12 +26,12 @@ with `javap`:

**greet.Greeter**
```java
{% include code/compiling_clojure/Greeter_decompiled.java %}
{% include code/compiling_clojure/Greeter_decompiled.java -%}
```

**greet.main**
```java
{% include code/compiling_clojure/main_decompiled.java %}
{% include code/compiling_clojure/main_decompiled.java -%}
```

The generated class methods simply delegate to Clojure functions with the appropriately-prefixed names. For example the `greet.Greeter` class defines a function prefix
Expand All @@ -57,12 +57,12 @@ This allows us to write straightforward Clojure code which is compiled into a Ja

**src/greet/core.clj**
```clojure
{% include code/compiling_clojure/main/src/greet/core.clj %}
{% include code/compiling_clojure/main/src/greet/core.clj -%}
```

**src/greet/main.clj**
```clojure
{% include code/compiling_clojure/main/src/greet/main.clj %}
{% include code/compiling_clojure/main/src/greet/main.clj -%}
```

This can be compiled and run as before:
Expand All @@ -81,7 +81,7 @@ the application source files and any compiled classes. As before, we need to def

**manifest.mf**
```
{% include code/compiling_clojure/uberjar/manifest.mf %}
{% include code/compiling_clojure/uberjar/manifest.mf -%}
```

The fat JAR can then be built with
Expand Down
Loading