NetBeans 9 Early Access
Java 9 is around the corner, and so is NetBeans 9. In this article we shall see the support that NetBeans 9 Early Access provides to developers to build Java 9 compatible applications.
Java 9 provides many (around 90) new features including Modules and JShell, a Read-Eval-Print-Loop (REPL), among many others. You may seek more information in the references at the end of this article and especially this link on NetBeans 9 support to JDK 9.
In this article we will learn how to:
- download and build Java 9 EA from sources
- download and build NetBeans 9 EA from sources
- use JShell REPL from NetBeans 9 EA
- create and build modules and dependencies among them using NetBeans 9 EA to make our life easier
1. Build OpenJDK 9 EA
OpenJDK is the reference implementation of any JDK Enhancement Proposals (JEPs) or even Java Specification Requests (JSRs). You might have many reasons why you want to build it from sources and don’t download one of the pre-built binaries, e.g.:
- company policy that enforces you to build open source projects from source
- you wish to get access to the latest early access OpenJDK
- you want a build for your special platform
Of course you can proceed with this article by downloading a pre-built binary. But if you want to learn how to build JDK 9 then continue reading. Building your own JDK image provides a number of advantages, e.g. you don’t need to install anything or modify e.g. the Windows registry or the Java Preferences pane on MacOS destroying your current default JDK (see e.g. this article). The executables will always be created in the same location, and by updating your repository and re-building the sources you can always have the latest version.
You can download the latest OpenJDK 9 binaries from this page. Sources can be found in the Mercurial repositories. E.g. OpenJDK 9 repos are here; project Jigsaw repo contains the hitting edge of the modular implementation, if you wish to be in the hitting edge. Below, you get some tips on how to build OpenJDK 9.
- Clone the JDK 9 Master mercurial repository.
- Read the
README
orREADME-builds.html
file for more instructions. - Next step before you start building is to execute:
bash get_source.sh
or./get_source.sh
if your shell is already bash. It is very important, after each update to call this command. The reason is thathg update
only updates the master repository. OpenJDK consists of a number of mercurial repositories which need to be updated, too. This can be done by theget_source.sh
command. ./configure --disable-warnings-as-errors
sudo make all
The above commands build the latest version of OpenJDK. If you wish to build an earlier version of OpenJDK you need to follow these tips:
hg up [tag]
e.g.jdk-9+147
cd corba
hg up [tag]
e.g.jdk-9+147
- Repeat steps 2 & 3 for directories:
hotspot, jaxp, jaxws, jdk, langtools, nashorn
./configure --disable-warnings-as-errors
sudo make clean
sudo make all
The binaries are created in build/<platform_dir>/jdk
, e.g. if you use a Mac in build/macosx-x86_64-normal-server-release/jdk
.
2. Build and configure NetBeans 9 EA
You may download the latest NetBeans with JDK 9 support from http://wiki.netbeans.org/JDK9Support or build it from sources:
hg clone http://hg.netbeans.org/main
cd main
hg clone http://hg.netbeans.org/main/contrib
cd ..
ant
Binary is created in nbbuild/netbeans
. Configure it to run with JDK 8 or JDK 9 EA (etc/netbeans.conf
). For jshell
to be enabled, you need to setup NetBeans 9 with JDK 9 EA, though. So edit etc/netbeans.conf
to point to the JDK 9 EA you built in Step 1:
netbeans_jdkhome="<path to OpenJDK 9 EA>/build/<platform_dir>/jdk"
Take a backup of this file, because the next time you build NetBeans it will be overriden and you will have to do this modification again.
Start netbeans by issuing the command: bin/netbeans
or bin\netbeans.exe
depending on your platform. Register the latest JDK 9 EA build as a Java Platform in NetBeans by means of Tools | Java Platforms | Add Platform (see Fig. 1) and select the OpenJDK 9 EA you built in Step 1.
3. JShell support in NetBeans 9 EA
If you started NetBeans 9 with a JDK 9 implementation, then you can access JShell from the menu Tools | Open Java Platform Shell. JShell works the same as from the command line and additionally the NetBeans shortcuts work with it (e.g. sout --> (tab)
). You may read more about JShell in the resources.
4. Modules support in NetBeans 9 EA
NetBeans 9 EA provides a number of goodies to facilitate you with your modular projects. Before you continue, you must setup JDK 9 EA Platform in Tools | Java Platforms | Add Platform and select the path to OpenJDK 9 EA binaries you built in Step 1.
To transform an existing project into a module you need to perform two tasks:
- Setup the project to be JDK 9 compatible in Project Properties:
- In Libraries set Java Platform to your JDK 9 EA Java platform (Fig. 3).
- In Sources set Source/Binary Format to JDK 9 (Fig. 4).
- Add a Java Module Info (i.e. a module descriptor
module-info.java
) in your project (see Fig. 5):- File | New File…| Java (category) | Java Module Info (File type)
module-info.java
must always be in the root of a Java project in NetBeans 9. This is a restriction in NetBeans 9 and not of JDK 9. The only exception where we can have more than one module-info.java
files in a single Java project is when we have unit tests. You can add module-info.java
files inside Test Packages
.
But let’s learn about NetBeans 9 EA modules support by implementing the quick start guide of project Jigsaw in NetBeans 9 EA.
4.1. My first modular application with NetBeans 9
This first example is a module named com.greetings
that simply prints “Greetings!”. The module consists of two source files: the module declaration (module-info.java
) and the main class.
By convention (a module name can be a Java-qualified identifier), the source code for the module is in a directory that is the name of the module (in our case com.greetings
) — even though this is not necessary.
Create a new Java project in NetBeans by following these steps:
- File | New Project…
- Select Java (Category) and Java Application (Project) and click on Next
- In the next page select a Project Location and enter “com.greetings” as the project name because of the convention followed by the tutorial but a normal Java Project name like “Greetings” could also have been used. Rename the Main Class to be
com.greetings.Main
. Click Finish.
You should see a Java Project named com.greetings
and inside it a class com.greetings.Main
that contains a main()
method. Modify it like so:
com.greetings.Main
package com.greetings; /** @author javacodegeeks */ public class Main { /** @param args the command line arguments */ public static void main(String[] args) { System.out.println("Greetings!"); } }
To transform the Java Project into a module, add a module-info.java
as described previously, i.e. by right-clicking on the project name and selecting File | New File…| Java (category) | Java Module Info (File type).
An empty module-info.java
is created in the root package of the project. Rename it as follows to be in accordance with the Jigsaw tutorial:
com.greetings.module-info.java
module com.greetings { }
You must clean and build the project for the renaming of the module to take effect and run it with success. You should see the message “Greetings!” in the Output window.
With NetBeans you don’t need to care about command line syntax and arguments of javac
and java
commands. These are taken care by NetBeans IDE.
4.2. Adding dependencies
The second example updates the module declaration to declare a dependency on module org.astro
. Module org.astro
exports the API package org.astro
.
Create a new Java project named org.astro
by following the steps of the previous sub-chapter. Don’t create a Main Class this time. Once the project is created, right-click onto it and select New | Java Class… Enter World
as the class name and org.astro
as the package name and click Finish. Update the newly created class like so:
org.astro.World.java
package org.astro; /** @author javacodegeeks */ public class World { public static String name() { return "world"; } }
Add a module-info.java
like we did before for com.greetings
.
org.astro.module-info.java
module org.astro { }
Don’t forget to clean and build for the module renaming to take effect.
Now we need to add a dependency from com.greetings
module to org.astro
module in order to use its method World.name()
. But before that, org.astro
must export the package that contains this method. Both actions need to be made in module-info.java
files of the two modules. NetBeans 9 provides you with useful hints on how to do that.
- Open
org.astro
‘smodule-info.java
and inside the brackets typeCtrl-Space
. A popup menu appears that displays the available commands as shown in Fig. 6. Selectexports
and continue by typingorg.astro
which is the package name to export. NetBeans provides you hints as you type. Once you savemodule-info.java
you will notice that the lock icon of the package in the Projects tab changes to an open lock. - Open
com.greetings
‘smodule-info.java
and inside the brackets follow the steps described above to enter the commandrequires org.astro
, this time referring to the module name and not the package name (another reason why the convention chosen by the quick start guide of project Jigsaw is not that successful as it is confusing to distinguish between package and module names). However, NetBeans complains with an error messagemodule not found
. In order for NetBeans to be able to locate the module, one more step is needed. - Right-click on Libraries folder of
com.greetings
Java project and select Add Project from the popup menu. Select theorg.astro
Java Project and click on Add Project JAR Files. The error is gone. Another way to do the same thing is to right-click on projectcom.greetings
and select Properties from the popup menu. In the Project Properties dialog box click on the category Libraries and click on the + sign next to Modulepath. Select Add Project then theorg.astro
Java Project and click on Add Project JAR Files. Keep in mind that if you try to add cyclic dependencies (e.g. from `org.astro` tocom.greetings
), NetBeans will display a dialog box with the message: Can’t add cyclic references (see Fig. 7). - Modify
Main.main()
method like so and clean and build both modules.
com.greetings.Main.java
package com.greetings; import org.astro.World; /** @author javacodegeeks */ public class Main { /** @param args the command line arguments */ public static void main(String[] args) { System.out.format("Greetings %s!%n", World.name()); } }
When you paste the new System.out.format(...)
statement NetBeans recognizes the class World
and proposes to add the import
statement. This is only possible because you have already updated the module-info.java
files of the two modules, which are shown below:
com.greetings.module-info.java
module org.astro { exports org.astro; }
org.astro.module-info.java
module com.greetings { requires org.astro; }
NetBeans 9 EA provides you with a visual representation of the dependencies (the module graph). Simply click on the Graph button while in the editor of org.greetings module-info.java
to see a nice graph of the modules’ dependencies as shown in the following figure.
Run com.greetings
module to see the output: Greetings world!
as expected.
Compare to the original quick start guide of project Jigsaw to see how many typings you have saved yourself, thanks to NetBeans IDE.
4.3. Packaging modules
Packaging modules is very easy with NetBeans. Right-click on project com.greetings
and select Properties from the popup menu. In the Project Properties dialog box (Fig. 9) click on the category Packaging under Build and select Create JLink distribution and Create Launcher and click OK. Next time you clean and build NetBeans will generate a Java runtime image inside dist
folder of com.greetings
Java project which contains only the JDK modules needed for com.greetings
to run (i.e. only java.base
module). No need to remember the syntax of jlink
command.
4.4. Java modular project
As we mentioned in the beginning, NetBeans 9 only allows a single module per Java project. However, using a Java modular project one can define many modules inside this special Java project. We shall re-implement the previous modules using a Java modular project. This is an ant based project containing several modules and compiling them at once.
- File | New Project…
- Select Java (Category) and Java Modular Project (Project) (Fig. 10) and click on Next
- Enter
ModularGreetings
as the Project name and click Finish. - Right-click on the newly created project and select New Module from the popup menu.
- Enter
com.greetings
as the module name and click Finish. NetBeans opens themodule-info.java
file for this module. - Repeat previous step to create
org.astro
module. - Create the dependencies between the two modules as described in 4.2
- Create (or copy from the previous modules created in 4.2) the packages inside
classes
of each module. - Clean and Build. No need to add
org.astro
to the module path ofcom.greetings
; it is done automatically. - Run the project to see the correct output:
Greetings world!
You see that the Java Modular Project has a number of advantages, like you don’t need to add explicitly other projects to the Module path; this is done automagically when you update the module-info.java
.
4.5. Services
Loose-coupling refers to systems in which each component has, or makes use of, little or no knowledge of the definitions of other separate components. This allows the various components to change independently without affecting other components.
But let’s describe an example to understand what it’ all about before we dig into the details of the Quick Start Guide.
Suppose you have a Provider that provides a service. E.g. this could be an AlertService
(which provides various system or application alerts), a CoordinatesProvider
(which provides various coordinate systems, e.g. Lat/Lon, GEOREF, UTM etc.), an AlgorithmProvider
(which provides various algorithmic solutions to a problem) etc. To achieve loose-coupling, you provide an interface to your caller classes hiding the actual implementation(s) behind it. The caller (or service consumer) classes do not need to know anything of the actual implementations; they only need to know how to access the relevant methods. Then, the implementations are somehow provided to the caller classes at runtime. This way the actual implementations can be changed at any time without the caller classes knowing about it, as long as the Provider
interface does not change.
There are a number of ways to achieve loose-coupling. This is usually done by a service provider. The Service Locator design pattern provides a global point of access to a service without coupling callers (service consumers) to the concrete class(es) that implement(s) it. E.g. Spring uses Dependency Injection (one form of Inversion of Control), NetBeans’ RCP Modular API uses Lookups and ServiceProviders, etc. Jigsaw uses ServiceLoader from Java 6. The service consumer and service provider classes can reside in different modules.
From the Jigsaw Quick Start Guide, module com.socket
provides a service NetworkSocketProvider
for NetworkSocket
s. Two implementations of this service are provided in two different modules: org.fastsocket
and org.smartsocket
. Our service consumer module com.greetings
needs a dependency only on the com.socket
service provider module, but not on the service implementation modules.
Let’s see how can we achieve this. In NetBeans 9 EA, create a new Java Project com.socket
as we saw before, without providing a Main
class.
Create the two classes com.socket.NetworkSocket
and com.socket.spi.NetworkSocketProvider
as described in the Quick Start Guide, add a new module-info.java
to transform the project to a Java 9 module and export these two packages to the consumer classes:
com.socket.module-info.java
module com.socket { exports com.socket; exports com.socket.spi; uses com.socket.spi.NetworkSocketProvider; }
The last statement declares that this module provides the com.socket.spi.NetworkSocketProvider
service to consumers. Don’t forget to clean and build this module for the changes to take effect.
Next, let’s create the org.fastsocket
module. As before, create the two classes org.fastsocket.FastNetworkSocket
and org.fastsocket.FastNetworkSocketProvider
as described in the Quick Start Guide, add a new module-info.java
to transform the project to a Java 9 module and add a dependency to com.socket
module:
org.fastsocket.module-info.java
module org.fastsocket { requires com.socket; provides com.socket.spi.NetworkSocketProvider with org.fastsocket.FastNetworkSocketProvider; }
The last statement provides an implementation of the com.socket.spi.NetworkSocketProvider
service provider. Notice that this module does not export any packages!
However, the project contains compilation errors. Can you tell why?
We need to add com.socket
to the modulepath (refer back earlier in this article if you don’t remember how to do that). Clean and build to make sure there are no errors.
You could repeat the above steps to create org.smartsocket
in a similar way, however, the quick start guide doesn’t do that, so you could create your own implementations, if you wish, as an exercise.
Last, create the consumer com.greetings
Java project (use another directory to not mess up with the com.greetings
module we created in chapter 4.1 and 4.2) with a com.greetings.Main
class, copy the contents from the Quick Start Guide, add a new module-info.java
to transform the project to a Java 9 module and add a dependency to com.socket
:
com.greetings.module-info.java
module com.greetings { requires com.socket; }
Make sure you add in your modulepath com.socket
and you are done. Clean and build, then run com.greetings
and you will see an error:
Runtime exception
Exception in thread "main" java.lang.RuntimeException: No service providers found! at com.socket/com.socket.NetworkSocket.open(NetworkSocket.java:19) at com.greetings/com.greetings.Main.main(Main.java:8)
Why? We did exactly what the Quick Start Guide mentions. NetBeans Java projects require that you add org.fastsocket
in the module path (which is then added automatically to the module-info.java
) and then the exception goes away:
org.fastsocket.FastNetworkSocket
class org.fastsocket.FastNetworkSocket
As an exercise you may repeat the above using a Java Modular Project. And here you don’t need to add the service provider implementation modules (like org.fastsocket
) to the module path of com.greetings
.
But how does it work? Jigsaw uses ServiceLoader to locate the various service provider implementations:
ServiceLoader
ServiceLoader<NetworkSocketProvider> sl = ServiceLoader.load(NetworkSocketProvider.class); Iterator<NetworkSocketProvider> iter = sl.iterator();
sl.iterator()
will iterate through org.fastsocket.FastNetworkSocketProvider
and com.smartsocket.SmartNetworkSocketProvider
(if you implemented it).
Under the hood, ServiceLoader creates a provider configuration file, which is stored in the META-INF/services
directory of the service provider’s JAR file. The name of the configuration file is the fully qualified class name of the service provider, in which each component of the name is separated by a period (.
), and nested classes are separated by a dollar sign ($
). In other words, ServiceLoader
creates a text file package.Provider
inside build/classes/META-INF/services/
folder (or dist/provider.jar
) of the module which contains the fully qualified names of the implementation classes, e.g. package.ProviderImpl
.
In our example, com.socket/build/classes/META-INF/services/
contains the text file com.socket.spi.NetworkSocketProvider
which contains the fully qualified names of the implementation classes org.fastsocket.FastNetworkSocketProvider
(and com.smartsocket.SmartNetworkSocketProvider
if you implemented it).
Or at least, this should have been the ‘under the hood’ implementation if Java 6 ServiceLoader
was used! Unfortunately, Java 9 has modified ServiceLoader
‘s implementation.
Java 6 ServiceLoader
has a number of restrictions:
- it isn’t dynamic (you cannot install/uninstall a plugin/service at runtime)
- it does all service loading at startup (as a result it requires longer startup time and more memory usage)
- it cannot be configured; there is a standard constructor and it doesn’t support factory methods
- it doesn’t allow for ranking/ordering, i.e. we cannot choose which service to load first (ordering of services is done as they are discovered)
Additionally, Java 9 has modified Java 6 ServiceLoader
as follows:
- No relative services; the new module-based service locator does not have relative behaviour
- Ordering of services (as they were discovered) is lost
- All service interfaces and implementations on the module path are flattened into a single, global namespace
- No extensibility/customizability of service loading; the service layer provider must provide a fixed mapping of available services up front
- multiple-site declarations; every module that uses a service must also declare that the service is being used in the module descriptor; no global layer-wide service registry
In other words, if you search for com.socket/build/classes/META-INF/services/
or com.socket/dist/com.socket.jar/META-INF/services/
you will find nothing.
NetBeans RCP provides ServiceProvider instead, which does not have the drawbacks of ServiceLoader
mentioned above. It is dynamic, so you can plugin/unplug modules while your application is running, it doesn’t load all services at startup and allows you to set priorities (with the position
attribute of @ServiceProvider
annotation). Unfortunately, it does not work with Jigsaw.
5. NetBeans further improvements
To make a package available to other modules, one must edit module-info.java
and add an exports
statement passing the package name as an argument. This results in the package icon to change to an icon with an open lock instead of a locked one.
A nice shortcut would be to be able to right-click on a package and select an action Export Package as shown in the following figure, that would automatically modify the module-info.java
accordingly without the need to type the export
command.
This functionality already exists in NetBeans RCP Modules API, the API that comes with NetBeans Rich Client Platform.
In a project that consists of many modules, it is often difficult to find inside which module our dependencies exist. A nice addition would be to be able to search the class we look for throughout our modules (and/or libraries modules). A similar functionality already exists in NetBeans RCP Modules API, the API that comes with NetBeans Rich Client Platform.
Clicking on a hints blob, when an error is encountered because NetBeans cannot find the dependency, would open a dialog box where the developer can type the desired class, as shown in the following figure, and then choose the appropriate module. The same dialog box could be accessed when the developer requests to add a module dependency to the module path (e.g. by right-clicking on Libraries).
Finally, one can add a new module to a Java Modular Project, but there is no way to remove a module, while these lines are written at least. This is an EA bug that will be fixed.
NetBeans 9 EA is still in heavy development and it hasn’t passed official testing (a.k.a. NetCat), yet, so it is normal that some bugs or strange behaviour will be encountered at this stage.
6. Conclusion
In this article we saw how NetBeans 9 EA supports JDK 9 EA and makes the life of the developer easier. As a developer you don’t need to remember the details of how to build and execute java modules using the module path, or how to compose the jlink
command; NetBeans 9 hides the details. JShell is also well integrated. Some improvements can, of course, make the life of developers even easier, but these will come in future releases of NetBeans or as plugins.
We saw the two kinds of projects one can use to create modular Java applications. We saw the use of four of the five available commands one can use inside module-info.java
: exports, requires, uses
and provides
. opens
allows other modules to use reflection to access types in the package that you open.
Specific packages in normal modules can be ‘opened’, so that only that package is available for deep reflection at run time:
com.greetings.module-info.java
module com.greetings { opens com.greetings; }
Several Java frameworks and tools rely heavily on reflection to access your non-exported module’s code at runtime. They provide features such as dependency injection, serialization, implementation for the Java Persistence API, code-automation, debugging etc. Examples are Spring and Hibernate. These frameworks and libraries do not know about your application modules but they need access to the types and private members of your modules, which breaks the premise of strong encapsulation in JDK 9. One can also open the whole module for reflection, e.g.:
com.greetings.module-info.java
open module com.greetings { requires com.socket; }
Comparing exports
with opens
, the exports
statement lets you access only the public API of the specified package at compile-time and runtime, while the opens
statement lets you access public and private members of all types in the specified package using reflection at runtime.
It is not all roses when working with Jigsaw. The Community of Experts hasn’t embraced Jigsaw and have many concerns about a number of critical deficiencies that they have encountered.
7. References
- NetBeans 9 EA
- NetBeans 9 EA JDK 9 Support
- Ultimate Guide to Java 9, Sitepoint
- JDK 9 Feature Complete, JavaCodeGeeks
- Java Magazine, July-August 2017
- Java 9 series: JShell, Voxxed
- Java 9 series: HTTP/2 Client, Voxxed
- Java 9 series: the JVM, Voxxed
- Java 9 series: HTML5 and Javadoc, Voxxed
- Java 9 series: Concurrency Updates, Voxxed
- Java 9 series: Variable Handles, Voxxed
- Java 9 series: Encapsulate Most Internal APIs, Voxxed
- Java 9 series: Multi-Release JAR Files, Voxxed
- Java 9 series: Segmented Code Cache, Voxxed
- Java 9 series: Convenience Factory Methods for Collections, Voxxed
- Critical Deficiencies in Jigsaw
- Bateman A. (2016), “Prepare for JDK 9”, JavaOne.
- Bateman A. (2016), “Introduction to Modular Development”,JavaOne.
- Bateman A. & Buckley A. (2016), “Advanced Modular Development”, JavaOne.
- Buckley A. (2016), “Modules and Services”, JavaOne.
- Buckley A. (2016), “Project Jigsaw: Under The Hood”, JavaOne.
- Bateman A., Chung M., Reinhold M. (2016), “Project Jigsaw Hack Session”, JavaOne.
- Deitel P. & Deitel H. (2017), Java 9 for Programmers, 4th Ed., Deitel.
- Evans, B. (2016), “An Early Look at Java 9 Modules”, Java Magazine, Issue 26, January-February, pp.59-64.
- Gupta A. (2015), JDK 9 REPL: Getting Started, JavaCodeGeeks
- Jog T-M. (2016), Learning Modular Java Programming, Packt.
- Mak S. & Bakker P. (2016), Java 9 Modularity, O’Reilly (Early Release)
- Reinhold M. (2016), Problem modules reflective access, Voxxed
- Sharan K. (2017), Java 9 Revealed For Early Adoption and Migration, Apress.
- Verhas P. (2017), Java 9 Programming By Example, Packt.
- Zhitnitsky A. (2015), Java 9 Early Access: A Hands-on Session with JShell – The Java REPL, JavaCodeGeeks.