DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • JDev Flies on NetBeans
  • NetBeans Platform Control Application for Testing of Cellular Networks
  • My Experiences with Maven in IntelliJ IDEA and NetBeans IDE
  • NetBeans Platform Offshore

Trending

  • Unlocking AI Coding Assistants Part 4: Generate Spring Boot Application
  • The Modern Data Stack Is Overrated — Here’s What Works
  • Java’s Next Act: Native Speed for a Cloud-Native World
  • A Guide to Container Runtimes
  1. DZone
  2. Coding
  3. Tools
  4. NetBeans: From Modulizing JavaFX on AdoptOpenJDK to Runtime Generation and Distribution

NetBeans: From Modulizing JavaFX on AdoptOpenJDK to Runtime Generation and Distribution

Explore a simple configuration for a modular project using NetBeans with this step-by-step guide.

By 
Chris Luff user avatar
Chris Luff
·
Updated Sep. 01, 22 · Tutorial
Likes (9)
Comment
Save
Tweet
Share
35.3K Views

Join the DZone community and get the full member experience.

Join For Free

In this article, I’ll share with you a comprehensive guide to working with JavaFX with NetBeans. First, I’ll demonstrate how to modulize JavaFx from NetBeans. Then, you’ll learn how to generate a runtime from Maven before turning to focus on distribution. I’ll outline all of the programs, equipment, and information you need from start to finish.

Building a Modular JavaFX from NetBeans

I really struggled to get a clear lead on how to modulize my JavaFX applications on AdoptOpenJDK, therefore, I am going to share a simple configuration for a modular project.

First off, you will need to grab a few things and move them into the right places:

  • OpenJFX — from here, you'll need the jmods

  • AdoptOpenJDK

Place the jmods inside the module jmods directory of the installed JDK and jpackager binary and supporting jar inside the bin directory. 

We'll do this in maven because of the great integration with NetBeans. I am using the latest incarnation from the Apache Software Foundation, version 11.0.

Open a new Maven project. You can choose the JavaFX Application because it will create the default folder set to house the fxml, etc.

Image title

At this point, the project will not build, so it is a good time to ensure the correct JDK is selected. This can be done by selecting the project Properties -> Build -> Compile. To be honest, most of the pom.xml can be junked and replaced at this point.

The following illustrates the dependencies needed to get this project to build on the JDK. It will still not run at this point, but we're getting closer.

<dependencies>
  <dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-base</artifactId>
    <version>${javafx.version}</version>
  </dependency>
  <dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-fxml</artifactId>
    <version>${javafx.version}</version>
  </dependency>
  <dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-graphics</artifactId>
    <version>${javafx.version}</version>
  </dependency>
  <dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-controls</artifactId>
    <version>${javafx.version}</version>
  </dependency>
</dependencies>

The important thing to notice is that upon including these dependencies, the platform-specific versions are also included.

Let's now change them to create the module. The module-info.java goes in the root folder of the project, NetBeans will helpfully create this for you, but it will need a small tweak once generated to open the module to its dependencies. New -> Other (if not in the quick picks) -> Java -> Java Module Info.

module com.luff.javafx.test {
    requires javafx.baseEmpty;
    requires javafx.base;
    requires javafx.fxmlEmpty;
    requires javafx.fxml;
    requires javafx.controlsEmpty;
    requires javafx.controls;
    requires javafx.graphicsEmpty;
    requires javafx.graphics;

    opens com.luff.javafx.test;
}

And the FXMLController ensures that the paths are provided in this form...I have had lots of trouble with this in the past, and this format seems to get it done in every scenario.

 @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(new URL(getClass().getResource("/fxml/Scene.fxml").toExternalForm()));

        Scene scene = new Scene(root);
        scene.getStylesheets().add(getClass().getResource("/styles/Styles.css").toExternalForm());

        stage.setTitle("JavaFX and Maven");
        stage.setScene(scene);
        stage.show();
    }

Once this is done, we have an effective module. This is the part that I figured out fairly quickly; it was all the plugins to get everything in the correct place that took most of the effort.

Include a properties section in the pom.xml.

<properties>
  <javafx.version>11.0.2</javafx.version>
  <mainClass>com.luff.javafx.test.MainApp</mainClass>
  <moduleName>com.luff.javafx.test</moduleName>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
  • maven-compiler-plugin — 3.8.0, at the time of writing, is the latest version supporting Java 11 and modularity.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.8.0</version>
  <configuration>
    <release>11</release>
  </configuration>
</plugin>
  • exec-maven-plugin — effectively informing the runtime of the execution path and dependencies.

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>exec-maven-plugin</artifactId>
  <version>1.6.0</version>
  <executions>
    <execution>
      <goals>
        <goal>exec</goal>
      </goals>
      <configuration>
        <executable>${java.home}/bin/java</executable>
        <arguments>
          <argument>--module-path</argument>
          <argument>${project.build.directory}/modules</argument>
          <argument>--module</argument>
          <argument>${moduleName}/${mainClass}</argument>
        </arguments>
      </configuration>
    </execution>
  </executions>
</plugin>
  • maven-dependency-plugin — no more or less, move all the dependencies into a place that will become the module path.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <version>3.1.1</version>
  <executions>
    <execution>
      <id>copy-libs</id>
      <phase>prepare-package</phase>
      <goals>
        <goal>copy-dependencies</goal>
      </goals>
      <configuration>
        <outputDirectory>${project.build.directory}/modules</outputDirectory>
        <includeScope>runtime</includeScope>
      </configuration>
    </execution>
  </executions>
</plugin>
  • copy-rename-maven-plugin — rename and copy our jar to the module path.

<plugin>
  <groupId>com.coderplus.maven.plugins</groupId>
  <artifactId>copy-rename-maven-plugin</artifactId>
  <version>1.0.1</version>
  <executions>
    <execution>
      <id>copy-target</id>
      <phase>package</phase>
      <goals>
        <goal>copy</goal>
      </goals>
      <configuration>
        <sourceFile>${project.build.directory}/${project.build.finalName}.jar</sourceFile>
        <destinationFile>${project.build.directory}/modules/${project.build.finalName}.jar</destinationFile>
      </configuration>
    </execution>
  </executions>
</plugin>

At this point, we have created a project, included the dependencies, built a module-info, included a whole host of plugins, and all we have to show for it is a successful compilation. So let's go ahead and set this up to run!

If you try to use the default run command in NetBeans at this point, you will not get very far — we need to tell NetBeans where the modules are. Guess what? We already know this because it was done to build the jar.

You'll notice in the Project Files section of the Projects Navigator that there is a file named nbactions.xml. This is how NetBeans executes the projects for us using maven plugins. All we need to do is replace the run command with a custom configuration.

<action>
  <actionName>run</actionName>
  <packagings>
    <packaging>jar</packaging>
  </packagings>
  <goals>
    <goal>process-classes</goal>
    <goal>org.codehaus.mojo:exec-maven-plugin:1.6.0:exec</goal>
  </goals>
  <properties>
    <!--<Env.JAVA_HOME>/Library/Java/JavaVirtualMachines/adoptopenjdk-12.jdk/Contents/Home</Env.JAVA_HOME>-->
    <exec.args>--module-path ${project.build.directory}/modules --module ${moduleName}/${mainClass}</exec.args>
    <exec.executable>java</exec.executable>
  </properties>
</action>   

Instead of the classpath, we have the same commands as a regular debug and the module path. You'll be able to break and step as usual.

Of course, getting the application to run in the IDE is really only the first stage. Of course, we’ll want to be able to run it like a standard application with an icon and a delivery mechanism.

<properties>
  <!--<Env.JAVA_HOME>/Library/Java/JavaVirtualMachines/adoptopenjdk-12.jdk/Contents/Home</Env.JAVA_HOME>-->
  <exec.args>-agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} --module-path ${project.build.directory}/modules --module ${moduleName}/${mainClass}</exec.args>
  <exec.executable>java</exec.executable>
  <jpda.listen>true</jpda.listen>
</properties>

Instead of the classpath, we have the same commands as a regular debug and the module path. You'll be able to break and step as usual.

Of course, getting the application to run in the IDE is really only the first stage. We'll, of course, want to be able to run it like a standard application with an icon and a delivery mechanism. In Part 2, we'll use the same project to include jlink, and in Part 3, jpackager.

Generating a Runtime from Maven

Next, we are going to start by removing the module-info from the root of the project. I know, counter-intuitive, right? We are going to use ModiTect, a Maven plugin authored for the very purpose of managing module descriptors and runtime images.

Compared to authoring module descriptors by hand, using ModiTect saves you work by defining dependence clauses based on your project's dependencies, describing exported and opened packages with patterns (instead of listing all packages separately), auto-detecting service usages, and more.

 
<plugin>
  <groupId>org.moditect</groupId>
  <artifactId>moditect-maven-plugin</artifactId>
  <version>1.0.0.Beta2</version>
  <executions>
    <execution>
      <id>add-module-info-to-deps</id>
      <phase>package</phase>
      <goals>
        <goal>add-module-info</goal>
      </goals>
      <configuration>
        <overwriteExistingFiles>true</overwriteExistingFiles>
        <jvmVersion>${jvm.version}</jvmVersion>
        <module>    
          <moduleInfo>
            <name>com.luff.javafx.test</name>
            <opens>com.luff.javafx.test;</opens>
          </moduleInfo>
        </module>
      </configuration>
    </execution>
  </executions>
</plugin>

We'll add the plugin and some generic configuration to create the module-info and set us back to the same position we were, having previously manually detailed the module-info. Now, however, we want to go further and turn this into a runtime image.

 
<execution>
  <id>create-runtime-image</id>
  <phase>package</phase>
  <goals>
    <goal>create-runtime-image</goal>
  </goals>
  <configuration>
    <modulePath>
      <path>${project.build.directory}/modules</path> <!--our modules-->
    </modulePath>
    <modules> <!--everything we need-->
      <module>${moduleName}</module>
      <module>java.base</module>
      <module>javafx.base</module>
      <module>javafx.fxml</module>
      <module>javafx.swing</module>
      <module>javafx.controls</module>
      <module>javafx.graphics</module>
      <module>javafx.web</module>
    </modules>
    <excludedResources>
      <pattern>glob:/com.luff/**</pattern>
    </excludedResources>
    <launcher>
      <name>Test</name> <!--the name of the application executable-->
      <module>${moduleName}/${mainClass}</module>
    </launcher>
    <stripDebug>true</stripDebug>
    <compression>2</compression>
    <no-header-files>true</no-header-files>
    <no-man-pages>true</no-man-pages>
    <jdepsExtraArgs>
      <args>--strip-native-commands</args>
    </jdepsExtraArgs>
    <outputDirectory>${project.build.directory}/jlink-image</outputDirectory>
  </configuration>
</execution>

Add the create-runtime-image execution right after the add-module-info execution; they will run sequentially.

At this point, go ahead and run a clean:build again — you'll find it takes a little longer, but this time we are rewarded with a new jlink-image directory in the build location. Navigate through that and you'll see a folder structure similar to the below image.

clean:build

Note the Test executable and if you execute it, we have our little app.

That was simple, right? The thing is, projects are not simple! They usually include stuff that is not always at the bleeding edge of development. Say, for example, I wanted to include a dependency that is not modular.

 
<dependency>
  <groupId>eu.hansolo</groupId>
  <artifactId>Medusa</artifactId>
  <version>8.3</version>
</dependency>
 
@FXML
private Clock clock;

private static final ScheduledExecutorService TICKING = Executors.newSingleThreadScheduledExecutor();;
private final Runnable run = FXMLController.this::changeDisplay;

@Override
public void initialize(URL url, ResourceBundle rb) {
  TICKING.scheduleAtFixedRate(run, 0, 1, TimeUnit.SECONDS);
}

private void changeDisplay() {
  Platform.runLater(() -> clock.setTime(ZonedDateTime.now()));
}
 
<?xml version="1.0" encoding="UTF-8"?>

<?import eu.hansolo.medusa.Clock?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.luff.javafx.test.FXMLController">
  <children>
    <Clock fx:id="clock" animated="true" layoutX="14.0" layoutY="50.0" lcdFont="STANDARD" prefHeight="169.0" prefWidth="292.0" skinType="TEXT" AnchorPane.bottomAnchor="50.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="50.0">
      <customFont>
        <Font name="Arial" size="12.0" />
      </customFont></Clock>
  </children>
</AnchorPane>

Let's see what happens if we try to build the code: 

Failed to execute goal org.moditect:moditect-maven-plugin:1.0.0.Beta2:create-runtime-image (create-runtime-image) on project Test: Execution create-runtime-image of goal org.moditect:moditect-maven-plugin:1.0.0.Beta2:create-runtime-image failed: Execution of jlink failed -> [Help 1] 

Moditect did do its part: it generated the module-info for our project.

 
module Test {
  requires Medusa;
  requires javafx.base;

  requires transitive javafx.fxml;
  requires transitive javafx.graphics;

  exports com.luff.javafx.test;

}

Here is the issue. We need to tell Moditect that we have a jar that is not a module; it needs a module descriptor.

 
<plugin>
  <groupId>org.moditect</groupId>
  <artifactId>moditect-maven-plugin</artifactId>
  <version>1.0.0.Beta2</version>
  <executions>
    <execution>
      <id>add-module-info-to-deps</id>
      <phase>package</phase>
      <goals>
        <goal>add-module-info</goal>
      </goals>
      <configuration>
        <overwriteExistingFiles>true</overwriteExistingFiles>
        <jvmVersion>${jvm.version}</jvmVersion>
        <modules>
          <module>
            <artifact>
              <groupId>eu.hansolo</groupId>
              <artifactId>Medusa</artifactId>
            </artifact>
            <additionalDependencies>
              <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-controls</artifactId>
                <version>${javafx.version}</version>
                <classifier>mac</classifier>
              </dependency>
              <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-base</artifactId>
                <version>${javafx.version}</version>
                <classifier>mac</classifier>
              </dependency>
              <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-graphics</artifactId>
                <version>${javafx.version}</version>
                <classifier>mac</classifier>
              </dependency>
            </additionalDependencies>
            <moduleInfo>
              <name>eu.hansolo.Medusa</name>
            </moduleInfo>
          </module>
        </modules>
        <module>    
          <moduleInfo>
            <name>com.luff.javafx.test</name>
            <opens>com.luff.javafx.test;</opens>
          </moduleInfo>
        </module>
      </configuration>
    </execution>

Notice the significantly expanded modules section. Medusa relies upon JavaFX and needs a module-info attaching that describes that dependency.

 
module Medusa {
  requires transitive javafx.base;
  requires transitive javafx.controls;
  requires transitive javafx.graphics;

  exports eu.hansolo.medusa;
  exports eu.hansolo.medusa.events;
  exports eu.hansolo.medusa.skins;
  exports eu.hansolo.medusa.tools;

}

With this modified section the project will now build, the correct module descriptors will be built and the code will run. To generate the binary, we simply add our newly-created module to the modules in the create-runtime-image-section.

 
<modules>
  <module>${moduleName}</module>
  <module>java.base</module>
  <module>javafx.base</module>
  <module>javafx.fxml</module>
  <module>javafx.swing</module>
  <module>javafx.controls</module>
  <module>javafx.graphics</module>
  <module>javafx.web</module>
  <module>eu.hansolo.Medusa</module>
</modules>

Focusing on Distribution

Finally, we’ll look at the distribution of our new application. I am working in MacOS but it will work for Linux and Windows. The only requirement for Windows is an installation of Inno Setup. I have even begun working on this for my current obsession, Haiku-OS — I encourage you to check it out.

Back into NetBeans, we need to make some more pom.xml changes. In the normal course of things, you would probably not want to create the binary and package during development and test builds. To make things a little cleaner, you would probably set up Maven profiles.

 
<profiles>
  <profile>
    <id>package</id>
    <build>
      <plugins>
        ...
      </plugins>
    </build>
  </profile>
</profiles>

This would be the most basic implementation and will work fine. However, like me, you'll want to build for multiple platforms — after all, that is the foundation of Java. So we need to create profiles for each platform; for brevity, I have only added Mac and Windows.

Grab the create-runtime-image execution we previously defined and add it complete with plugin definition in the build section of the package profile, not forgetting to remove it from where it was copied. Now the binary will only be created when the package profile is explicitly defined. There is no need to explicitly select a platform profile. If you want to, however, you can separate the profiles with a comma; -Pmac,package. Alternatively, you can create a custom goal from the context menu in NetBeans; much easier, namable, and reusable!

 
<profiles>
  <profile>
    <id>macos</id>
    <activation>
      <activeByDefault>true</activeByDefault>
      <os>
        <family>mac</family>
      </os>
    </activation>
    <properties>
      <bundle.type>pkg</bundle.type>
      <exec.executable>${java.home}/bin/java</exec.executable>
    </properties>
  </profile>
  <profile>
    <id>win</id>
    <activation>
      <activeByDefault>true</activeByDefault>
      <os>
        <family>windows</family>
      </os>
    </activation>
    <properties>
      <bundle.type>exe</bundle.type>
      <exec.executable>${java.home}\bin\java</exec.executable>
    </properties>
  </profile>
  <profile>
    <id>package</id>
    <build>
      <plugins>
        <plugin>
          <groupId>org.moditect</groupId>
          <artifactId>moditect-maven-plugin</artifactId>
          <executions>
            <execution>
              <id>create-runtime-image</id>
              <phase>package</phase>
              <goals>
                <goal>create-runtime-image</goal>
              </goals>
              <configuration>
                <modulePath>
                  <path>${project.build.directory}/modules</path>
                </modulePath>
                <modules>
                  <module>${moduleName}</module>
                  <module>java.base</module>
                  <module>javafx.base</module>
                  <module>javafx.fxml</module>
                  <module>javafx.swing</module>
                  <module>javafx.controls</module>
                  <module>javafx.graphics</module>
                  <module>javafx.web</module>
                  <module>eu.hansolo.Medusa</module>
                </modules>
                <excludedResources>
                  <pattern>glob:/com.luff/**</pattern>
                </excludedResources>
                <!--<baseJdk>version=11,vendor=openjdk,platform=mac</baseJdk>-->
                <launcher>
                  <name>Test</name>
                  <module>${moduleName}/${mainClass}</module>
                </launcher>
                <stripDebug>true</stripDebug>
                <compression>2</compression>
                <outputDirectory>${project.build.directory}/jlink-image</outputDirectory>
              </configuration>
            </execution>
          </executions>
        </plugin>

Let's add the important bit — the packaging plugin. No such luck! At the time of writing, it does not exist and probably does not need to, as it would really only obfuscate the actual packager. Oracle removed the JavaPackager in JDK11 at the same time as JavaFX and work on a replacement is detailed in JEP 343. OpenJFX has come to the rescue by back porting the work to JDK 11. Download the port for the system you are building on and move it to the bin directory of the JDK. Unfortunately, at the moment it has not been ported to JDK 12, but early access releases are available for JDK 13 if you are feeling brave.

We still want to do this in Maven, however, as part of our packaging phase. To do this, we will simply implement the exec-maven-plugin. As part of the implementation, define the executable for the jpackager that was downloaded.

 
<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>exec-maven-plugin</artifactId>
  <executions>
    <execution>
      <id>create-package</id>
      <phase>package</phase>
      <goals>
        <goal>exec</goal>
      </goals>
      <configuration>
        <executable>${java.home}/bin/jpackager</executable>
        <workingDirectory>${project.build.directory}</workingDirectory>
        <longModulepath>false</longModulepath>
        <environmentVariables>
          <JAVA_HOME>${java.home}</JAVA_HOME>
        </environmentVariables>
        <arguments>
          <argument>create-installer</argument>
          <argument>${bundle.type}</argument>
          <argument>--verbose</argument>
          <argument>--echo-mode</argument>
          <!--<argument>--icon</argument>
          <argument>${icons}</argument>-->
          <argument>--output</argument>
          <argument>package</argument>
          <argument>--version</argument>
          <argument>${project.version}</argument>
          <argument>--copyright</argument>
          <argument>Luff Corp</argument>
          <argument>--name</argument>
          <argument>Test</argument>
          <argument>--runtime-image</argument>
          <argument>${project.build.directory}/jlink-image</argument>
          <argument>--module</argument>
          <argument>${moduleName}/${mainClass}</argument>
        </arguments>
      </configuration>
    </execution>
  </executions>
</plugin>

That really is all that is needed. Run the package profile by changing the dropdown in the toolbar of NetBeans or -Ppackage from the command line. If all has gone to plan, you should have a target/package directory with the pkg or EXE contained within. Go ahead and execute the installer and voila.

Of course, I have generally followed the path of least resistance — the complications are many as the application gets bigger. The one major issue I have is still the size of the bundle. On the command line, you can review the modules in the custom runtime.

 /target/jlink-image/bin/java --list-modules 

 
com.luff.javafx.test@1.0.0
eu.hansolo.Medusa@8.3
java.base@11.0.2
java.datatransfer@11.0.2
java.desktop@11.0.2
java.prefs@11.0.2
java.scripting@11.0.2
java.xml@11.0.2
javafx.base
javafx.controls
javafx.fxml
javafx.graphics
javafx.media
javafx.swing
javafx.web
jdk.jsobject@11.0.2
jdk.unsupported@11.0.2
jdk.unsupported.desktop@11.0.2
jdk.xml.dom@11.0.2

A PR for Moditect will bring support for no-man-pages and no-header-files.

It is not essential that you’ve followed the information in this guide step-by-step — the implementation is transferable. However, if you wish to skip forward, I have another project on this subject published on GitHub.

NetBeans

Opinions expressed by DZone contributors are their own.

Related

  • JDev Flies on NetBeans
  • NetBeans Platform Control Application for Testing of Cellular Networks
  • My Experiences with Maven in IntelliJ IDEA and NetBeans IDE
  • NetBeans Platform Offshore

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!