8

I understand that launch4j doesn't bundle the JRE in the .exe but that you have to place it next to it. My question is, how am I supposed to do that? Is there a way for maven to automatically locate and copy the JRE of the JDK I'm using to build my application and copy it to a given directory?

I've tried doing something like this:

    <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.6</version>
        <executions>
            <execution>
                <id>copy-resources</id>
                <!-- here the phase you need -->
                <phase>package</phase>
                <goals>
                    <goal>copy-resources</goal>
                </goals>
                <configuration>
                    <outputDirectory>${basedir}/target/windows/jre</outputDirectory>
                    <resources>
                        <resource>
                            <directory>${java.home}</directory>
                        </resource>
                    </resources>
                </configuration>
            </execution>
        </executions>
    </plugin>

but the program doesn't start. It shows a little dialog that immediately disappears (it seems to be blank, but it goes away too quickly for me to really notice it).

Pablo Fernandez
  • 279,434
  • 135
  • 377
  • 622
  • Do you only need to support Windows as a platform? – Sarel Botha Apr 06 '18 at 13:23
  • @SarelBotha: for now, yes, Windows 7, 8 and 10; 32 and 64 bit. – Pablo Fernandez Apr 06 '18 at 13:24
  • Does the maven build output indicate it is trying to copy the directory? try hard-coding the path to the JRE directory. – Sarel Botha Apr 06 '18 at 13:30
  • When does maven call launch4j? During the package phase? Will this be before your custom execution is called? Maybe change your custom execution to run in the compile phase to make sure it is done first. – Sarel Botha Apr 06 '18 at 13:32
  • Planning on using the 32 bit JRE for both 32 and 64 bit Windows to simplify this? – Sarel Botha Apr 06 '18 at 13:34
  • @SarelBotha: if that's the only option, yes. Otherwise, I'd rather give 32 and 64 bit binaries to my customers. – Pablo Fernandez Apr 06 '18 at 14:05
  • Updated my answer. I believe it does what you want now. – Sarel Botha Apr 06 '18 at 15:11
  • Oracle does not want anyone downloading the JRE from them at install time because they want to force everyone to accept the license agreement. I believe for this reason there are no official ways to do this and finding ways to do this are rare. You can use the repository alfresco provides with the older version or host your own private repository and manually update the version from time to time. This is what we do. – Sarel Botha Apr 06 '18 at 15:26

2 Answers2

15

UPDATE: Deleted my previous answer and replacing with tested working example

UPDATE 2: This pom.xml now downloads the JRE tgz and unpacks it and the launch4j exe uses it and it works. I added comments to explain how it works.

I would recommend sticking with just a 32 bit exe and JRE. The only reason to use the 64 bit JRE would be if your program needs to use more than 4 GB of RAM.

Of course now you need an installer that takes all this and installs to Program Files. I've used NSIS for this in the past. There is a learning curve for NSIS but it is not too bad.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.akathist.encc</groupId>
    <artifactId>mavenproject1</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- This is the win32 JRE tgz hosted by alfresco - https://mvnrepository.com/artifact/com.oracle.java/jre -->
        <dependency>
            <groupId>com.oracle.java</groupId>
            <artifactId>jre</artifactId>
            <classifier>win32</classifier>
            <type>tgz</type>
            <version>1.8.0_131</version>
        </dependency>
    </dependencies>
    <repositories>
        <repository>
            <!-- this repository has the JRE tgz -->
            <id>alfresco</id>
            <url>https://artifacts.alfresco.com/nexus/content/repositories/public/</url>
        </repository>
    </repositories>
    <build>
        <plugins>
            <plugin>
                <!-- this is to extract the JRE tgz file we downloaded -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.5.1</version>
                <executions>
                    <execution>
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>unpack-dependencies</goal>
                        </goals>
                        <configuration>
                            <includeGroupIds>com.oracle.java</includeGroupIds>
                            <includeTypes>tgz</includeTypes>
                            <includeArtifactIds>jre</includeArtifactIds>
                            <includeClassifiers>win32</includeClassifiers>
                            <outputDirectory>target/win32</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <!-- This calls launch4j to create the program EXE -->
                <groupId>com.akathist.maven.plugins.launch4j</groupId>
                <artifactId>launch4j-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>l4j-clui</id>
                        <phase>package</phase>
                        <goals>
                            <goal>launch4j</goal>
                        </goals>
                        <configuration>
                            <headerType>console</headerType>
                            <outfile>target/encc.exe</outfile>
                            <jar>target/mavenproject1-1.0-SNAPSHOT.jar</jar>
                            <errTitle>encc</errTitle>
                            <classPath>
                                <mainClass>com.akathist.encc.Clui</mainClass>
                                <addDependencies>false</addDependencies>
                                <preCp>anything</preCp>
                            </classPath>
                            <jre>
                                <path>./win32/java</path>
                            </jre>
                            <versionInfo>
                                <fileVersion>1.2.3.4</fileVersion>
                                <txtFileVersion>txt file version?</txtFileVersion>
                                <fileDescription>a description</fileDescription>
                                <copyright>my copyright</copyright>
                                <productVersion>4.3.2.1</productVersion>
                                <txtProductVersion>txt product version</txtProductVersion>
                                <productName>E-N-C-C</productName>
                                <internalName>ccne</internalName>
                                <originalFilename>original.exe</originalFilename>
                            </versionInfo>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

UPDATE 3: The sad fact is that there exists no offical or even up-to-date maven repo with the JREs that you want. You could host your own maven repo that has the desired JREs. You will have to update this as new releases are done. It is also a good idea to test with the new version before releasing with it. The third Tuesday of every month is when new Java releases are done. You can set a reminder for this to check if a new version was released and download it. Automating this is a pain because of the license agreement check. This post might help but you probably can't download the tar.gz version of the JRE this way: Java check latest version programmatically

If you want to support multiple platforms then hosting your own maven repo is a good way to go. You can host your own repo and update it with the new JRE tar.gz every time a release is done with this: https://stackoverflow.com/a/29261502/35264

The simplest option is to do what you were aiming for already and just use the JRE that you are building with. This will allow you to support Windows 32 and 64 as long as you build with the 32 bit JRE. You can update this occasionally as you have time to test with the new version. Here is a working pom.xml that does this:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.akathist.encc</groupId>
    <artifactId>mavenproject1</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <build>
        <plugins>
            <plugin>
                <!-- This copies the JRE used to do the build from java.home - should be 32 bit Windows JRE -->
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.6</version>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <!-- here the phase you need -->
                        <phase>package</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${basedir}/target/win32/java</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>${java.home}</directory>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <!-- This calls launch4j to create the program EXE -->
                <groupId>com.akathist.maven.plugins.launch4j</groupId>
                <artifactId>launch4j-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>l4j-clui</id>
                        <phase>package</phase>
                        <goals>
                            <goal>launch4j</goal>
                        </goals>
                        <configuration>
                            <headerType>console</headerType>
                            <outfile>target/encc.exe</outfile>
                            <jar>target/mavenproject1-1.0-SNAPSHOT.jar</jar>
                            <errTitle>encc</errTitle>
                            <classPath>
                                <mainClass>com.akathist.encc.Clui</mainClass>
                                <addDependencies>false</addDependencies>
                                <preCp>anything</preCp>
                            </classPath>
                            <jre>
                                <path>./win32/java</path>
                            </jre>
                            <versionInfo>
                                <fileVersion>1.2.3.4</fileVersion>
                                <txtFileVersion>txt file version?</txtFileVersion>
                                <fileDescription>a description</fileDescription>
                                <copyright>my copyright</copyright>
                                <productVersion>4.3.2.1</productVersion>
                                <txtProductVersion>txt product version</txtProductVersion>
                                <productName>E-N-C-C</productName>
                                <internalName>ccne</internalName>
                                <originalFilename>original.exe</originalFilename>
                            </versionInfo>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
Sarel Botha
  • 12,419
  • 7
  • 54
  • 59
  • Is gvSIG.confDir supposed to make make it work? Because I'm already configuring launch4j like that. Also, your answer doesn't include how to put the jre in the ../jre path, which is what I'm asking. I've read the question you linked to (and many launch4j questions here in SO as well as elsewhere and I couldn't find anything about sourcing the JRE). – Pablo Fernandez Apr 06 '18 at 13:23
  • Not sure what the point of gvSIG.confDir is. I would attack this in two phases. First make it work with the JRE directory manually copied next to the launch4j XML file. Then after that try to make it automatically copy the JRE dir. – Sarel Botha Apr 06 '18 at 13:27
  • Thank you for the answer Sarel. Unfortunately, it seems that repo is stuck at 1.8.0_133. Already missing some fixes I'm counting on by using 1.8.0_162 (although I don't remember what they were, I just remember needing to upgrade, I might need to do some research here). But also there's no Java 9 or 10. :( – Pablo Fernandez Apr 07 '18 at 11:21
  • I updated the answer to address the concerns. Yes, there are pros and cons with the different approaches. You will have to choose based on what you are willing to live with. Java 9 and 10 do not support 32 bit Windows so it will probably be a while before you can make that switch. – Sarel Botha Apr 08 '18 at 20:38
  • Hello Sarel. Isn't the last example in which you use the JRE you are compiling with the same as mine in the question? That one as in the question, is failing silently. – Pablo Fernandez Apr 08 '18 at 23:46
  • I couldn't use the other one because having the `tgz` dependency interferes with shade: `[ERROR] Failed to execute goal org.apache.maven.plugins:maven-shade-plugin:3.1.0:shade (default) on project dashman: Error creating shaded jar: error in opening zip file C:\Users\pupeno\.m2\repository\com\oracle\java\jre\1.8.0_131\jre-1.8.0_131-win32.tgz -> [Help 1]`. I'm sure this is trivial to solve, but I'm new to Maven. – Pablo Fernandez Apr 08 '18 at 23:53
  • Ok... I think I found a new exception that the jar was throwing and correcting that one made the '.exe' and now it worked. I had the jar working before and the exe not working... I have no idea what changed though :( – Pablo Fernandez Apr 09 '18 at 00:42
  • Yes, the last option goes back to what you were trying to do originally. I think that's the best option in the short term since you want a newer Java version. Then this shade issue should go away. In the future if you use tgz again you can probably tell shade to exclude the tgz because the build process is extracting the tgz anyway. It is not being referenced on the classpath by Java: https://maven.apache.org/plugins/maven-shade-plugin/examples/includes-excludes.html . Yes, I am new to maven too. This has been an interesting learning experience. – Sarel Botha Apr 09 '18 at 13:40
  • The problem you originally had that makes it flash the black command prompt window quickly was that path to the JRE was wrong. If you have in copy-resources ${basedir}/target/windows/jre then you should have in launch4j ./windows/jre – Sarel Botha Apr 09 '18 at 13:48
  • I don't think so, the binary is in the windows directory too. – Pablo Fernandez Apr 09 '18 at 15:28
  • Is there a way we can use the JRE from the installed JDK in our development environment? We can grab the environment variable (${env.JAVA17_HOME}) but I'm not sure how to configure launch4j to use it. – White_King Mar 15 '23 at 07:15
0

I believe this is what you are looking for:

<plugin>
  <groupId>com.akathist.maven.plugins.launch4j</groupId>
  <artifactId>launch4j-maven-plugin</artifactId>
  <executions>
    <execution>
      ...
      <configuration>
        ...
        <jre>
          <path>${java.home}</path> <!-- SEE THIS -->
        </jre>
        ...
      </configuration>
    </execution>
  </executions>
</plugin>

Java lets you access JRE path using java.home system property. And you can access java system properties within pom. And you have a plugin that wraps launch4j. Put all of these together and you have the solution.

James
  • 2,756
  • 17
  • 19