Java ClassLoader (1) – What is a ClassLoader?

In this article we will give a very simple explanation of what ClassLoaders do in Java. This article starts a series, and in following articles we will show some ways of “replacing” the default class loader and what interesting things come out of it.

In contrary to such languages like C++ or Fortran where source code is compiled directly to machine’s native code, Java’s source code is compiled to platform-independent Java bytecode. Normally Java Virtual Machine loads this bytecode for every required class from .class files from the local file system. Java gives us however a possibility to greatly influence the way bytecode is load – customized class loaders.

Every request for a class from inside the code goes through a chain of default class loaders. Normally there are three of them:

  1. Bootstrap class loader – loads core Java classes like java.lang.System or java.lang.Integer
  2. Extensions class loader – loads classes from <JAVA_HOME>/lib/ext
  3. System class loader – loads classes from the current CLASSPATH

“Chaining” of class loaders means, that every class loader has a parent class loader, and in most cases it asks its parent to load a requested class before trying to resolve it on its own. If the parent can not find the class, the class loader itself tries to load the class. A rough view of class loading is represented on the image below:





Bootstrap class loader is pretty special, in that it is implemented in native code. All other class loaders are written in Java (apart from some native methods) and extend the java.lang.ClassLoader class. We could get the class loader which was used to load any particular class with class.getClassLoader() method:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
public class ShowClassLoaders {
    /**
     * This main method shows which class
     * loaders are used for loading classes
     * like Integer, BlowfishCipher (lib/ext)
     * and ShowClassLoaders.
     */
    public static void main(String[] args) {
        System.out.println("class loader for Integer: "
            + Integer.class.getClassLoader());
        System.out.println("class loader for BlowfishCipher: "
            + com.sun.crypto.provider
            .BlowfishCipher.class.getClassLoader());
        System.out.println("class loader for this class: "
            + ShowClassLoaders.class.getClassLoader());
    }
}

When we run this program, we will see the following output:

class loader for Integer: null
class loader for BlowfishCipher: sun.misc.Launcher$ExtClassLoader@9cab16
class loader for this class: sun.misc.Launcher$AppClassLoader@d9f9c3

java.lang.Integer was loaded using the bootstrap class loader. In most implementations getClassLoader() method returns null for the bootstrap class loader. com.sun.crypto.provider.BlowfishCipher class is stored inside the <JAVA_HOME>/lib/ext/sunjce_provider.jar so it was loaded with the extensions class loader. Classes implemented by us, like the class with the main method, was loaded by system class loader.

Java ClassLoader is a powerful tool that can be used in a various of ways to extend the possibilities of Java applications. One of the most well-known usages of custom class loaders are Java Applets, where a class loader is used to dynamically download code from the webpage. Customized ClassLoaders are also the base element of Java Application Servers and Web Containers. ClassLoaders are one of things that make the Java platform so extensible and flexible.

More informations on ClassLoader (for example how to create your own one, or how it interacts with namespaces in Java) coming up in the next articles, so stay tuned!

You can also check out such places like ClassLoader’s javadoc on http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ClassLoader.html or Wikipedia http://en.wikipedia.org/wiki/Java_Classloader. There are also great articles available on http://mindprod.com/jgloss/classloader.html, http://www.developer.com/java/other/article.php/2248831/Java-Class-Loading-The-Basics.htm and on http://www.securingjava.com/chapter-two/chapter-two-7.html

Internationalization with MessageFormat

In this post I want to show a quick example of how to internationalize your application in a easy simple way by taking advantage of MessageFormat class.

The design is fairly simple: for each single locale/language we have a properties file with translated messages. At the start we load the properties into a MessageGenerator object and then use it’s methods to get the formatted messages and use them in the code. To encapsulate the loading we have a MessageGeneratorFactory with static methods creating appropriate MessageGenerator objects.

The following are examples of properties files that contain translated messages. Notice that each line has a message identifying label and a translated text with placeholders for values. The English properties (translation_en.properties):

ImportCsv=Import csv files into database
MapTypeError=Couldn't map type for table='{0}' column='{1}'
MonitorAsOf=Monitor (as of {0,date,full})

The same messages in French (translation_fr.properties):

ImportCsv=Importer des fichiers csv dans la base de données
MapTypeError=Impossible de faire correspondre le type \
             pour la colonne {1} de la table {0}
MonitorAsOf=Moniteur (au {0,date,full})

The class providing the localized messages in the application is MessageGenerator. See that for each single message there is a separate get method. This way not only we get type checking of provided arguments but also separate the way messages are prepared from their usage. Internally MessageGenerator uses precompiled MessageFormat objects – they are prepared in class constructor and based on properies file loaded by ResourceBundle.

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
public class MessageGenerator {
    // For each of the available messages MessageGenerator
    // keeps the precompiled MessageFormat object, a identifying
    // String label and a 'get' method.
    private final String importCsvLabel = "ImportCsv";
    private final MessageFormat importCsv;

    private final String mapTypeErrorLabel = "MapTypeError";
    private final MessageFormat mapTypeError;

    private final String monitorAsOfLabel = "MonitorAsOf";
    private final MessageFormat monitorAsOf;

    MessageGenerator(ResourceBundle bundle, Locale locale) {
        // Load and precompile each of the MessageFormat objects
        importCsv = new MessageFormat(
                bundle.getString(importCsvLabel), locale);
        mapTypeError = new MessageFormat(
                bundle.getString(mapTypeErrorLabel), locale);
        monitorAsOf = new MessageFormat(
                bundle.getString(monitorAsOfLabel), locale);
    }

    public String getImportCsvMessage() {
        return importCsv.format(new Object[] {});
    }

    public String getMapTypeErrorMessage(String tableName,
                String columnName) {
        return mapTypeError.format(new Object[] {tableName, columnName});
    }

    public String getMonitorAsOfMessage(Date date) {
        return monitorAsOf.format(new Object[] {date});
    }
}

See that in the code above the constructor is made package-private. This is because we do not want the user to freely construct MessageGenerator objects, but to use a static factory provided by us. This way we can keep only one instance of this object for each locale (notice that it is immutable).

Now the code of MessageGeneratorFactory. See that to load properties files we use ResourceBundle class.

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
public class MessageGeneratorFactory {
    // This is a static factory, so no constructor is needed
    private MessageGeneratorFactory() {
    }

    private static MessageGenerator englishMessages = null;
    private static MessageGenerator frenchMessages = null;

    // Methods creating/returning MessageGenerator objects
    // for specific languages/localisations:

    public static MessageGenerator getEnglishMessages() throws IOException {
        if (englishMessages == null)
            englishMessages = initMessages(Locale.ENGLISH);
        return englishMessages;
    }

    public static MessageGenerator getFrenchMessages() throws IOException {
        if (frenchMessages == null)
            frenchMessages = initMessages(Locale.FRENCH);
        return frenchMessages;
    }

    // Helper method loading the Properties and creating MessageGenerator
    private static MessageGenerator initMessages(Locale locale) {
        // We use ResourceBundle to load the properties files.
        // It assumes specific file naming. For instance we expect
        // the French translations to be in 'i18n/translation_fr.properties'
        ResourceBundle resourceBundle =
            ResourceBundle.getBundle("i18n/translation", locale);
        return new MessageGenerator(resourceBundle, locale);
    }
}

Now lets use both of the classes shown above and have fun with a piece of code that prints out some of the messages to the console:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
public class MainProgram {

    public static void printSomeLocalizedMessages(
            MessageGenerator generator) {
        System.out.println(generator.getImportCsvMessage());
        System.out.println(generator.getMapTypeErrorMessage("X", "Y"));
        System.out.println(generator.getMonitorAsOfMessage(new Date()));
        System.out.println();
    }

    public static void main(String[] args) throws Exception {
        // Prepare 2 generators: one French and one English
        MessageGenerator englishGenerator = MessageGeneratorFactory
                .getEnglishMessages();

        MessageGenerator frenchGenerator = MessageGeneratorFactory
                .getFrenchMessages();

        // Test the generators by printing some of the messages
        printSomeLocalizedMessages(englishGenerator);
        printSomeLocalizedMessages(frenchGenerator);
    }
}

If you are curious what will be printed out go ahead, copy-paste this code and compile it yourself! You can also download the slightly more complicated version of the code above here.

It is important to mention that there are many things that can be improved in this design – this is a very simple code to be used as an example, feel free to use it and improve it yourself. For instance one of the improvements could be loading properties with translations from XML files (see an example how to do that on www.codewrapper.com)

Scripting in Java

Did you know that you can compile and run scripting languages like JavaScript, Python, Ruby and many others directly from your Java code? API responsible for it has been created as a result of Java Specification Request 223 and sits in the javax.script package.

Let’s see on a minimalist example how to use the Java Scripting API to run a JavaScript command:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class ScriptTest {
    public static void main(String[] args) throws ScriptException {
        // create a script engine manager
        ScriptEngineManager manager =
            new ScriptEngineManager();
        // create a JavaScript engine
        ScriptEngine javaScriptEngine =
            manager.getEngineByName("JavaScript");
        // evaluate JavaScript code from String
        javaScriptEngine.eval(
            "println('Hello World from JavaScript');");
    }
}

This code should compile and run without problems on Java 6. As a result you should get following output:

Hello World from JavaScript

Support for JavaScript comes included in the standard JRE in form of Rhino: JavaScript for Java ScriptEngine. But other languages are not included by default. Getting support for them is however very easy. Let’s see how you could get support for Python.

You will first need to get Jython, which is a Java implementation for Python. You can download it directly from this URL. If it does not work, go to http://www.jython.org/ and get the newest version from section ‘Download’.

Jython comes with a JAR installer (for example jython_installer-2.5.1.jar). Run it with command ‘java -jar jython_installer-2.5.1.jar’ and install in any directory. After the installation you will find file ‘jython.jar’ inside the directory where you installed Jython. You should include this file in the CLASSPATH when running the next example (You could do this in Eclipse by clicking right mouse button on your project, then Properties->Java Build Path->Libraries->Add External Library).

With jython.jar on the CLASSPATH, let’s run the next code:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class ScriptTestJython {
    public static void main(String[] args) throws ScriptException {
        // create a script engine manager
        ScriptEngineManager manager =
            new ScriptEngineManager();

        //Printing all available scripting languages
        for (ScriptEngineFactory factory :
            manager.getEngineFactories()) {
            System.out.println("Available language: " +
                factory.getLanguageName());
        }

        // create a Jython engine
        ScriptEngine jythonEngine =
            manager.getEngineByName("python");
        // evaluate Jython code from String
        jythonEngine.eval(
            "print \"Hello World from Jython\\n\"");
    }
}

This time on the beginning we print all the available scripting languages. We expect to see there JavaScript, which is always supported by default, and Jython because we included it in the classpath. After that we run a simple Python’s code. Let’s see what comes out:

Available language: ECMAScript
Available language: python
Hello World from Jython

(If you got, besides the lines above, also a lot of strange info lines in red, don’t be worried. Jython prints them once during initialization. You should not see them by the next run)
Some of you may be surprised by the first line ‘ECMAScript’. It is actually JavaScript engine for which ECMA is a base (you can read more about it here). On the next line you see that our Jython was properly loaded and the last line shows proper execution of Python’s code.

There is a pretty good tutorial showing many useful features of Java Scripting API like loading script from a file, exchanging variables, loading Java classes in the script and much more, available on this Sun’s site. You can see the list of available scripting languages and download JAR files for them on this site.

This article was inspired by a comment from Ricky on one of our previous post. Thanks!