Understanding Java projects structures and how it all works

Writing a simple Java project without using external dependencies like Eclipse / Maven

While working in Java using Eclipse or any other IDE, we usually forget / don’t know how it works underneath the hood.

I tried to look up how to make a simple application using a nice directory structure in pure Java, all I could see was articles related to Maven and Gradle.

So, I tried to explore how this works using the command line. I was finally able to make it work by observing the Eclipse directory structure.

This post contains my experience during the same.

Directory structure

src
├── main
│   └── java
│       └── Main.java
└── test
    └── java
        └── MainTest.java

Easy? Now let’s take a look at the code:

Main.java

package main.java;

import java.io.*;

public class Main {
    public static int squareIt(int n) {
        return n * n;
    }
}

MainTest.java

package test.java;

import main.java.Main;

class MainTest {
    public static void main(String[] args) {
        int n = 12;
        int sq = Main.squareIt(n);
        assert sq == (n * n) : "Incorrect";
        System.out.println("n = " + n + " sq = " + sq);
    }
}

Let’s take a look how I compiled the project and was able to make it work.

Compilation instructions

# go to src directory and compile the Main class
$ javac main/java/Main.java

# Now that our Main class is compiled, we can import it into 
$ javac test/java/MainTest.java

# Now we can run our test
$ java test.java.MainTest

Level up

Let’s try to make this a bigger project. When there are thousands of Java files, we can’t follow this approach, obviously. We should consider automating the process, and that too without using the names and paths of the file.

Compiling

# find all java files and output the names to sources.txt
$ find -name "*.java" > sources.txt

# compile all!
$ javac @sources.txt

JAR

A JAR (Java ARchive) is a package file format typically used to aggregate many Java class files and associated metadata and resources (text, images, etc.) into one file for distribution. This can further be used in other projects.

JAR files are archive files that include a Java-specific manifest file. Let’s make one for ourselves. in this file we only write the name of the class we want our JAR file to run.

$ Main-Class: test.java.MainTest

Now, let’s create our JAR:

# get compiled files and now output to sources.txt
$ find -name "*.class" > sources.txt

# create jar
$ jar cvfm Example.jar manifest.txt @sources.txt

Let’s check the contents of our JAR file:

# get contents of jar
$ jar tf Example.jar

Running JAR file:

$ java -jar Example.jar

Shell scripts

When it comes to automating builds, shell scripts can be very helpful. So, for this project, I wrote one. It looks like this:

# removing previously compiled files
rm -r */*/*.class

# advanced:
# find all java files and output the names to sources.txt
find -name "*.java" > sources.txt

# compile all!
javac @sources.txt

# get compiled files and now output to sources.txt
find -name "*.class" > sources.txt

# create jar
jar cvfm Example.jar manifest.txt @sources.txt

# get contents of jar
jar tf Example.jar

# run jar
java -jar Example.jar

Final structure

Finally, our project structure looks like this:

src
├── main
│   └── java
│       └── Main.java
├── manifest.txt
├── run.sh
└── test
    └── java
        └── MainTest.java

Code

The code written for this post can be found in this github repository: manparvesh/simple-java-app.

Observations

  • Take care while writing the package names.
  • Compilation can be done using simple the path to the java file, but when running a java file, write the complete name of the class, eg. java test.java.MainTest.
  • Linux is awesome!