Showing posts with label Java API. Show all posts
Showing posts with label Java API. Show all posts

Sunday, 3 August 2008

Java abstract enumeration and java.lang.Class.isEnum() problem

One of new features in Java 1.5 is direct support of enumeration using enum keyword. According to this the new method isEnum() has been added to java.lang.Class class (which is part of Java Reflections API). The problem is that the isEnum method doesn’t always behave as you would expect.

Let’s start with the following Java code:

public class MainTest {

// Enum with custom constructor
enum EnumPrivate {

VALUE(1);

private int value;

private EnumPrivate(int value) {
this.value = value;
}

public int getValue() {
return value;
}

}

// Enum having an abstract method
enum EnumAbstract {

VALUE(1) {
public int getRandomValue() {
return 10;
}
};

private int value;

private EnumAbstract(int value) {
this.value = value;
}

public abstract int getRandomValue();

}


/**
* @param args
*/
public static void main(String[] args) {
System.out.println(EnumPrivate.VALUE.getClass().isEnum());
System.out.println(EnumAbstract.VALUE.getClass().isEnum());
}

}


Both EnumPrivate and EnumAbstract are not simple enums. The first one has custom constructor (which must be private) and the second an abstract method which must be implemented in each enum’s value. Let’s try to run the main method. You would probably expect “true” twice in the output but you will get the “true” and “false”. It’s quite strange isn’t it?

Let’s try to find out what the java.lang.Class documentation says about isEnum() method. You would find the following:

Returns true if and only if this class was declared as an enum in the source code.

The description of the method doesn’t say anything special about enums with abstract methods so let’s find the isEnum method’s source code in JDK. You could find the following:

public boolean isEnum() {
return (this.getModifiers() & ENUM) != 0 &&
this.getSuperclass() == java.lang.Enum.class;
}


You can see that isEnum returns true if the super class of the class represeting an enum is java.lang.Enum class (we will not bother about modifier) but what's the supeclass of the our enum class? How to find out? The answer is that they are compiled to ordinary Java classes in the same way as any other class so let’s try to decompile them. You would get the result similar to the following:

final class EnumPrivate extends Enum
{

public static final EnumPrivate VALUE;
private int value;
private static final EnumPrivate ENUM_VALUES[];

static
{
VALUE = new EnumPrivate("VALUE", 0, 1);
ENUM_VALUES = (new EnumPrivate[] {
VALUE
});
}

private EnumPrivate(String s, int i, int value)
{
super(s, i);
this.value = value;
}



}

abstract class EnumAbstract extends Enum
{

public static final EnumAbstract VALUE;
private int value;
private static final EnumAbstract ENUM_VALUES[];

static
{
VALUE = new EnumAbstract("VALUE", 0, 1) {

public int getRandomValue()
{
return 10;
}

};
ENUM_VALUES = (new EnumAbstract[] {
VALUE
});
}

private EnumAbstract(String s, int i, int value)
{
super(s, i);
this.value = value;
}

public abstract int getRandomValue();

EnumAbstract(String s, int i, int j, EnumAbstract EnumAbstract)
{
this(s, i, j);
}

….

}


If you compare EnumPrivate and EnumAbstract then you should find the problem. EnumPrivate extends the Enum and it’s VALUE is EnumPrivate. EnumAbstract extends Enum as well but because it has the abstract method it must be the abstract class. VALUE is then anonymous inner child class of the EnumAbstract so its superclass is not Enum but EnumAbstract!

As you can see enums (or isEnum) should be corrected a bit in the future versions of Java. You have got two enumerations according to specification but only one of them is correctly recognized as enumeration.

You can find many issues when using enums with abstract methods in combination with third party libraries (or applications). Assume a library for automatic converting standard Java types to e.g. String. The library will get the Object and then need to find out the type of object to correctly do the conversion to String. If the library relies on the isEnum() method to recognize enums then it won’t correctly recognize your enum with abstract method value as enum. This happened to me and I spend a few hours searching for the problem and that’s the reason why I decided to share my experience with you.

Sunday, 8 June 2008

How to call private constructor/method from outside in Java

As you certainly know, one of the OOP’s features is encapsulation. Java has private keyword to specify encapsulated constructors, methods or attributes. These methods and attributes should not be accessible from the rest of the world (they are not part of the API) and Java doesn’t allow you to do that ordinarily.

You can however use Java reflections API to access any private method, field or constructor of any class and it’s really very simple task. Let’s assume we have got the following simple class:
public class Test {

private Test() {
System.out.println("private constructor has been called");
}

private void test() {
System.out.println("private test() method has been called");
}

}
The class has private constructor and method (notice that such class is worthless because there is no way how to ordinarily get or create instance of it). Now I’ll show you how to get instance of the class using Java reflections and call the private method:
public class Main {

public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException, SecurityException, NoSuchMethodException {

Class<Test> clazz = Test.class;

Constructor<Test> c = clazz.getDeclaredConstructor((Class[])null);
c.setAccessible(true); //hack
Test test = c.newInstance((Object[])null);

Method privateMethod = clazz.getDeclaredMethod("test", (Class[])null);
privateMethod.setAccessible(true); //hack
privateMethod.invoke(test, (Object[])null);
}

}
If you hadn’t called the setAccessible(true) method you would have got the java.lang.IllegalAccessException indicating that you call a method/constructor which is not meant to be called from outside.

Java reflections breaks OOP in many ways and you should very rarely use its “special” features like accessing private methods in your projects.

Monday, 19 May 2008

Java enum in Java Native Interface (JNI)

A few days ago I started to take interest in JNI (http://en.wikipedia.org/wiki/Java_Native_Interface). JNI is used to call java native methods that are written in other language than Java. Java native methods are usually system dependent and are used to provide functionality that has to be handled by an operating system. Example is creating and handling threads in Java. This functionality is system dependent and has to be handled directly by an operating system (let’s try to open and go through java.lang.Thread class source code in JDK). You can find very useful specification of JNI containing a few examples at http://java.sun.com/j2se/1.5.0/docs/guide/jni/. JNI provides many methods for manipulating Java primitive types, objects, exceptions, non-native methods and so long, but what is missing in the JNI guide is description how to manipulate enums in native code (implemented using e.g. C++) and that’s what I’m going to show you here (using C++).

Let’s assume we have got the following simple enum:

package test;

public enum MyEnum {
VALUE1, VALUE2, VALUE3;
}


Since Java version 1.5 enums are converted to ordinary Java classes so treat them is similar to any other Java object (I recommend you to decompile compiled MyEnum.class file). For the following native method declaration:

package test;

public class SomeClass {
public native String enumTest(MyEnum myEnum);
}


is then, using javah generator (it’s part of JDK, not just JRE), generated following C header:
JNIEXPORT jstring JNICALL Java_test_SomeClass_ enumTest(JNIEnv *, jobject, jobject);
The first parameter is pointer to Java environment, second is Java the object on which is the native method called and the third is the myEnum parameter (notice that the type is object). The way how to handle object in native code is a little bit similar to the Java reflections.

The first thing you have to do is to find the name of the method that returns actual "value" of the enum. You can find in the documentation (http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Enum.html) that every enum has (among others) method name() that returns name of the value of the enum as String (the second usable method is ordinal() ). Now I’m going to show you how to call the name() method in native code implemented using C++:
JNIEXPORT jstring JNICALL Java_test_SomeClass_ enumTest(JNIEnv *env, jobject obj, jobject enumObj) {
jclass enumClass = env->FindClass("test/MyEnum");
jmethodID getNameMethod = env->GetMethodID(enumClass, "name", "()Ljava/lang/String;");
jstring value = (jstring)env->CallObjectMethod(enumObj, getNameMethod);
const char* valueNative = env->GetStringUTFChars(value, 0);
if (strcmp(valueNative, "VALUE1") == 0) {
printf("Enum has the VALUE1 value");
}
// ...
return NULL;
}
On the first line the pointer to the class is obtained using FindClass (http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/functions.html#wp16027) method. You should notice that package name is delimited by "/" and not by ".". On the second line the pointer to the correct method - name() is obtained using GetMethodID (http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/functions.html#wp16660) method. You have to provide correct method’s signature (look into the specification how to get correct method’s signature). The third line calls the method against given object. CallObjectMethod (http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/functions.html#wp4256) means that the method itself returns object (String). The fourth line converts returned string value from UTF-8 (which is used as encoding of strings in Java) to C encoding and finally the last line just compares obtained valued against one of the enum’s values.

Monday, 24 March 2008

Java 6 compiler API tutorial

One of the new features in Java 6 is compiler API. It let’s you compile any Java source code file on the fly and after compilation you can load compiled class using a class loader and start using it. Because Java compiler doesn’t know anything about classes compiled on the fly, so you can use them only using java reflections.

In the first step we need to prepare a class that is going to be compiled using Compiler API. I prepared the following simple class:

package com.blogspot.mike_java;

public class ToBeCompiled {

public void callMe() {
System.out.println("Method callMe has been called");
}

}

And saved it to the directory “d:\javafiles\src” (absolute path to the ToBeCompiled.java file is “d:\javafiles\src\com\blogspot\mike_java\ ToBeCompiled.java”) and prepared directory for compiled files “d:\javafiles\bin”. The next step is to prepare a class that compiles ToBeCompiled class, loads it and runs method callMe() on an instance of it. I prepared in my favorite IDE Eclipse following class:

package com.blogspot.mike_java;

public class CompilerAPITest {

public static void main(String[] args) {
// source code is going to be here
}
}


All following source code lines will be in the main method of the CompilerAPITest class.

At first we need to get instance of JavaCompiler and StandardJavaFileManager:

JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager sjfm = jc.getStandardFileManager(null, null, null);


The next step is to get Iterable collection of files to be compiled and prepare options for compiler (you can find list of compiler options at http://java.sun.com/javase/6/docs/technotes/tools/windows/javac.html):

File javaFile = new File("d:/javafiles/src/com/blogspot/mike_java/ToBeCompiled.java");
Iterable fileObjects = sjfm.getJavaFileObjects(javaFile);
String[] options = new String[]{"-d", "d:/javafiles/bin"};


The next step is to compile Iterable collection of java files and close file manager:

jc.getTask(null, null, null, Arrays.asList(options), null, fileObjects).call();
sjfm.close();
System.out.println("Class has been successfully compiled");


After this step all compiled classes would be saved in directory “d:\javafiles\bin”. The next step is to load compiled class using class loader and run method callMe. At first we need to load compiled class:

URL[] urls = new URL[]{ new URL("file://d:/javafiles/bin/") };
URLClassLoader ucl = new URLClassLoader(urls);
Class clazz = ucl.loadClass("com.blogspot.mike_java.ToBeCompiled");
System.out.println("Class has been successfully loaded");


And get the method callMe using reflections:

Method method = clazz.getDeclaredMethod("callMe", null);


Finally we need to create new instance of the just loaded class and call method callMe on it:

Object object = clazz.newInstance();
method.invoke(object, null);


You can download source codes at http://rapidshare.com/files/102030988/compiler_api.zip. I hope that this tutorial was useful for you.

Sunday, 24 February 2008

Java date & time API vs. JODA

Java has simple API for working with date and time. Many people find the API deficient and I’m one of them. Although I was using SimpleDateFormat and GregorianCalendar classes in Java API for long time, sometimes I found it very cumbersome and unsuitable for my task. Sometimes there were problems with parsing input text and the problems couldn’t be directly solved using Java API. Java community is working on new Java date and time API (see https://jsr-310.dev.java.net/), but I think it will take a while to be finished. A few weeks ago I came across JODA API and without delay tried using it. I was really very pleasantly surprised how useful and simple the JODA is.

Java API has in fact 2 (in words two) classes for working with date and time – java.text.SimpleDateFormat for parsing and converting date and time and java.util.GregorianCalendar for manipulating a date and time. Either class extends its own abstract ascendant but it’s not important in light of functionality. Creating an instance of SimpleDateFormat is simple; you pass format string and a Locale instance and start using the instance. The most confusing thing for a beginner can be leniency of the new instance. Default behavior of a new instance of SimpleDateFormat is not to be lenient. That means you can pass any string to its parse(…) method and you get a result without any exception. If you forget to set leniency by setLenient(true) method you can later unreasonably get unknown behavior of your application.

JODA API (see http://joda-time.sourceforge.net/) has in contrast to Java API much more (tens) classes to work with data and time. JODA architecture contains Instants (a moment in the datetime continuum), Intervals (an interval of time from one instant to another instant), Durations (a duration between two Intervals in milliseconds, doesn’t have start and end), Periods (a duration in e.g. years, months, days and hours), Chronology (a calculation engine that supports the complex rules for a calendar system), TimeZones (don’t need commentary I hope) and then many tools to manipulate, parse and format date and time. First thing we need to do is create new Instant:
DateTime dateTime = new DateTime();
The dateTime instance contains date and time according to the date and time it was instantiated (similarly to Java API and its java.util.Date class). You should notice that a dateTime instance is immutable and can be shared among threads without need of access synchronization. Need to get last possible day in actual month? No problem:
int lastDay = dateTime.dayOfMonth().getMaximumValue();
Creating of a Duration instance is simple and intuitive:
DateTime before = new DateTime();
Thread.sleep(30);
Interval interval = new Interval(before, new DateTime());
int timeInterval = interval.toDuration().getMillis();
The snippet above should create interval of 30 miliseconds but the interval is longer because of time spent during threads scheduling. JODA uses formatter classes to format and parse date and time. Creating of a custom formatter looks similarly to Java API:
DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
Then simply use the instance of the formatter to format a DateTime instance:
String formattedTime = dateTime.toString(dtf);
Need to create DateTime with different time zone (e.g. New York)? No problem in JODA:
DateTime newYork2 = new DateTime(DateTimeZone.forID("America/New_York"));
All supported time zone ID strings are located in package org.joda.time.tz.data. Of course you can “change” time zone of existing DateTime instance (in fact you can’t change existing DateTime instance, you have to create new):
DateTime newYorkTZ = dateTime.withZone(DateTimeZone.forID("America/New_York"));
Need to add 3 days to an existing DateTime instance? There’s nothing simpler:
DateTime add3Days = dateTime.dayOfMonth().addToCopy(3);
You can really do many and many things using JODA API and much more simply then using Java API.

One of my targets when I was preparing this post was to do a performace test and measure performance of parsing and formatting input in either API. I decided to do it in the following way: call parse and format method of each API specific number of times (e.g. 100 000x) and measure time spent using System.currentTimeMillis(). Following snippet shows how I measured formatting performance of Java API:
DateFormat javaFormatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
Date date = new Date();
String result = null;
beforeTest = System.currentTimeMillis();
for (int i = 0; i < testCount; i++) {
result = javaFormatter.print(dateTime);
}
aftertest = System.currentTimeMillis();
I got the following results:



You can see that while Java and JODA formats an input string at the same speed, parsing takes much less time in JODA.