Skip to content

Project Structure

Classes and resources form a Java program. Resources can include videos, tracks, images, text files, data files and so on. One program can contain thousands of classes, and thousands of resource files. Often you're just going to write some of the classes yourself, and actually use a lot of classes written by others.

Java applications come in three main types:

  • Native applications that are installed on the user's desktop , laptop, or mobile device and run directly on it.
  • Web applications, supported by a web server, and usually run on it.
  • Applications WebStart that are stored on a server but downloaded and run on request.

All of the classes and resources are usually zipped into a single file. This is a JAR file for client applications and webstart apps; this is a WAR or JAR file for webapps. Both jars and wars use the common (nice and portable) zip-format.

Organizing the application

It is necessary to keep your workspace organized when dealing with large programs. The following structure of directories has become standard; you should follow:

All under target is "derived" and thus does not undergo revision control. You can place your source code files in Java under src/main/java for example. The Java compiler places the resulting class files under target when those are compiled. Everything under src/main will be inserted to the distributed application (you don't pack your tests into your app).

Since you could have hundreds of source files in Java, they need to be grouped into packages. Make sure that the initial part of the package name meets the standard to use the "reversed" internet domain (such as com.cstopics. The application's folder structure needs to mirror the package names!

Suppose we 're writing a web application for a calculator. We'd need Java classes for controllers, validators, and services and maybe some tests.

A larger application might have many subpackages within an application, for example one per each functional subsystem of the project. And within each subsystem, we may need more than just two classes; we might want separate packages for validators, domain classes, daos, types, utility classes, factories, property editors, etc.

Now if we would creating a client application, we could probably place imeages, scripts, movies and so on into the resources folder, but the convention is to put these things under src/main/webapp as shown in the following diagram. The resources folder does keep properties files and other run-time configuration files (e.g., Hibernate mapping files). In our example, we assume that we are building our application using the earlier versions of Spring Framework.

Packages

A package contains one or more classes that share a namespace for classes. Class names need only be unique within a package. This avoids possible naming conflicts between different classes, which are dynamically loaded from the local hard disk or over the network.

To assign a Java file to a package, you can write a package statement at the beginning of the file.

package com.cstopics.calc;

This defines the package com.cstopics.calc, which contains the classes defined in the file. If the file does not contain a package statement, the classes defined in the file are assigned to the default nameless package.

If you want to use classes of another package in a file, you must specify the class name completely with package name. For example, if you want to use the Date class in the java.util package, you do this as in the example below.

java.util.Date d = new java.util.Date();
System.out.println("today is: "+d);

The full package names can be omitted if the import statement is used.

import java.util.date;
...
Date d = new Date();
System.out.println("today is: "+d);

You can also use * to import all class names of a package or all methods and variables of a class.

import java.util.*;
...
Date d = new Date();
System.out.println("today is: "+d);
...
Vector v = new Vector();
v.addElement("hello");
v.addElement("bye");

The package java.lang contains the base classes for Java and is always imported. Therefore you can use e.g. Object, System, Integer etc. without their package name java.lang.

Scope of the JDKs

The Java API (Application Programming Interface) (JDK-1.0) consists of the classes defined in the following eight packages:

java.applet
java.awt
java.awt.image
java.awt.peer
java.io
java.lang
java.net
java.util

With the Java 1.1 API (JDK-1.1) the packages mentioned above have changed slightly and the following packages have been added:

java.beans components
java.event
java.math
java.rmi
java.sql
java.text
java.util.zip

With the Java-2-API (JDK-1.2) many extensions and improvements of existing packages are added, among others the following packages:

java.security
java.awt.swing
java.awt.accessability
java.lang.ref interact with CG 
java.lang.reflect
java.util.jar
javax.swing
javax.servlet
org.omg.CORBA

Java API documentation of JDK-1.8 can be seen here.

Java API documentation of JDK 14 can be seen here.

Organizing the packages

There are different possible options in the context of package organization, that we will see in the following sections.

Package by Layer

The most commonly recognized similarity between project classes is their responsibility. In this approach we can use this property for organizing the packages, which is also known as horizontal slice. The simplicity of this approach allows keeping the project in order, even by less-experienced developers, as the structure is easily understandable. A major disadvantage of the package by layer approach is overuse of the public access modifier.

Package by Feature

You can organize the packages around features or domain models, which is also known as the vertical slice organization. If you work only with the horizontal slice, at the first glance, it might look a little bit messy. But in the end, it’s just a question of mindset. In the horizontal slice, packages have the same set of names in each project while, in the vertical slice approach, packages have much more meaningful names describing their functional purpose.

Mixed Approach

You may think no extremity is fine. Should we not only take what is best from both approaches and build a new intermediate level between two extremes? There are two potential mergers. Either the first level of packages is divided by layer and the features are their kids, or the features create the top level and the sub-nodes are layers.

Class Loading

Whenever a new JVM is started the bootstrap classloader is responsible to load key Java classes (from java.lang package) and other runtime classes to the memory first. The bootstrap classloader is a parent of all other classloaders. Consequently, it is the only one without a parent.

Next comes the extension classloader. It has the bootstrap classloader as parent and is responsible for loading classes from all .jar files kept in the java.ext.dirs path--these are available regardless of the JVM’s classpath.

The third and most important classloader from a developer’s perspective is the system classpath classloader, which is an immediate child of the extension classloader. It loads classes from directories and jar files specified by the CLASSPATH environment variable, java.class.path system property or -classpath command line option.

Classpaths

A classpath is simply a list of directories and jar files. The bootstrap class loader searches a classpath when it looks for the classes (or source files) it needs, after searching the platform and extension locations.

On Windows the classpath entries are separated with semicolons.

Example:

c:\worksapce\stuff.jar;c:\other\crap;c:\mylibs\junit.jar

If you requested the class a.b.C from the bootstrap classloader, and that class was not found in rt.jar or in the extensions, it would look for, in this order:

  1. a\b\C.class in c:\worksapce\stuff.jar
  2. c:\other\crap\a\b\C.class
  3. a\b\C.class in c:\mylibs\junit.jar

Specify the classpath when invoking a tool, for example

javac -cp c:\worksapce\stuff.jar;c:\other\crap;c:\mylibs\junit.jar *.java

or, less flexibly, set the CLASSPATH environment variable (which may seem like a timesaver but can cause headaches). It's suggested you leave this environment variable unset and use a specific classpath when you invoke a tool.

  • Exercise 1: use class Loader to load a class:

    Class myClass = Class.forName("className"); 
    ClassLoader loader = myClass.getClassLoader(); 
    Class c1  = Class.forName("java.lang.String", true,  loader); 
    System.out.print("Class represented by c1: " + c1.toString());
    

  • Exercise 2:

    • Use java.lang.ClassLoader.getResourceAsStream() to read a file from classPath
      • Test the code by printing the content of the file