You are here: Home ยป Blog

Wrapping the constant interface anti pattern into an Enum

Posted on Tuesday, June 24 2014 at 15:54 | Category: Java | 0 Comment(s)

Especially in legacy code, we sometimes come across code like this, also known as the Constant Interface Antipattern:

public interface Constants {
   static int DML_DELETE = 0x02; 
   static int DML_INSERT = 0x05;
   static int DML_UPDATE = 0x10; 
}

Since Java 5, a much better alternative is to use an enum. If possible, code like the above which only defines constants should be converted into a corresponding enum. However, sometimes this is not possible, for example when using a library where the source code is not available. Then, we can still take advantage of enums in our own code by wrapping the legacy constants into an enum type. By default, a Java enum only allows to map from the the enum name to the enum itself, but in our scenario we also need to be able to map the legacy integer constants to the corresponding enum.

The following code shows how the above interface could be wrapped into an enum:

public enum ConstEnum {
   DML_DELETE(Constants.DML_DELETE),
   DML_INSERT(Constants.DML_INSERT),
   DML_UPDATE(Constants.DML_UPDATE);
   
   private int constValue;

   // we need to create a reverse map for the enum in order to allow reverse lookups
   private static HashMap<Integer, ConstEnum> revMap = new HashMap<>();
   static {
      for (ConstEnum e : values()) {
         revMap.put(e.value(), e);
      }
   }

   // private constructor for the integer value
   private ConstEnum(int someValue) {
      constValue = someValue;
   }

   public int value() {
      return constValue;
   }

   public static ConstEnum enumFor(int value) {
      ConstEnum result = revMap.get(value);
      if (result == null) {
         throw new NoSuchElementException(ConstEnum.class.getName() + " for " + value); 
      }
      return result;
   }
}

The core of this code is the revMap hashmap which is initialized in the static initializer and puts all available enum objects and their corresponding integer values into a hashmap, so that we can look up the enum object by its integer value, which is done in the enumFor() method. The static values() method is provided automatically by the java compiler for all enum types. The following samples show how the enum type can now be used:

List all available values:

for (ConstEnum val : ConstEnum.values()) {
   System.err.println(val + "=" + val.value());
}
DML_DELETE=2
DML_INSERT=5
DML_UPDATE=16

Convert legacy int value into enum:

int someValue = 5;
ConstEnum e = ConstEnum.enumFor(someValue);
System.err.println(e + "=" + e.value());
DML_INSERT=5

Switch on a legacy int value:

someValue = 2;
ConstEnum e = ConstEnum.enumFor(someValue);
switch(e) {
   case DML_DELETE : System.err.println("DELETE");  break;
   case DML_INSERT : System.err.println("INSERT");  break;
   case DML_UPDATE : System.err.println("UPDATE");  break;
}
DELETE

Using capture groups in regular expressions

Posted on Tuesday, May 20 2014 at 10:00 | Category: Java | 0 Comment(s)

Using regular expressions, it is easy to extract parts which match a particular pattern from a string. Suppose the input string contains some text, followed by a number, possibly followed by some garbage which is of no further interest:

"Hello World12345Garbage"

To extract the leading text part ("Hello World") and the number ("12345"), the following regular expression can be used:

(\D*)(\d*)

\D is a special sequence inside a regular expression which matches any non-numeric characters. \d is the opposite and matches any numeric character. The * specifies that we want to match any number of the preceeding character, so \D* matches any number (including none) of non-digits, while \d* matches any number of digits.

Finally, the parentheses define so-called capture groups. They group the various parts of the pattern so that these groups can later be accessed. Since we want to match text (non-digits) followed by a number (digits), the capture groups are (\D*) for the text part and (\d*) for the numeric part. See http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html for a complete list of the supported regular expression syntax.

The following code shows a complete example, using the Pattern and the Matcher classes. Note that we need to escape the backslash with another backslash in the regular expression string, so that the java compiler actually inserts a backslash character, and does not treat it as an escape sequence. We can then access the two groups using Matcher.group(int group):


String input = "Hello World12345Garbage";
String regexp = "(\\D*)(\\d*)";

Pattern pattern = Pattern.compile(regexp);
Matcher matcher = pattern.matcher(input);
matcher.find();
System.out.println("Text  : " + matcher.group(1));
System.out.println("Number: " + matcher.group(2));

Output:

Text  : Hello World
Number: 12345 

Accessing the capture groups by index can be misleading and difficult to maintain, especially for more complex regular expressions. Starting with Java 7, the API also supports named capture groups. A capture group can be given a name by adding ?<name> directly after the opening paranthesis:

(?<text>\D*)(?<number>\d*)

Then, the capture groups can be accessed by their name instead of their index, using Matcher.group(String name):


String input = "Hello World12345Garbage";

String regexp = "(?<text>\\D*)(?<number>\\d*)";

Pattern pattern = Pattern.compile(regexp);
Matcher matcher = pattern.matcher(input);
matcher.find();
System.out.println("Text  : " + matcher.group("text"));
System.out.println("Number: " + matcher.group("number"));

Output:

Text  : Hello World
Number: 12345 

Resolving build dependencies through manifest file

Posted on Monday, April 07 2014 at 12:27 | Category: Java | 0 Comment(s)

The MANIFEST.MF file in a jar file can be used to define runtime dependencies through the Class-Path attribute. In the manifest specification, it says:

Class-Path: The value of this attribute specifies the relative URLs
of the extensions or libraries that this application or extension needs. 
URLs are separated by one or more spaces. 
The application or extension class loader uses the value of this attribute
to construct its internal search path.

Since it explicitly states "application or extension class loader", it is not completely clear from the specification that the Class-Path attribute is also considered by the javac compiler to resolve build dependencies. However, it is - this is the bug which introduced that feature in Java 5: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4212732

Consider the following sample code which imports classes from some third party jar files:


package com.example;

import org.apache.log4j.PropertyConfigurator;
import com.google.gson.Gson;

public class Sample {

   public static void main(String[] args) {
      PropertyConfigurator.configure("log4j.properties");
      Gson gson = new Gson();

      // ...
   }
}

We can create a jar file like libs.jar with a Class-Path reference to the corresponding libraries:

$ cat manifest.txt
Class-Path: lib/gson-2.2.2.jar lib/log4j-1.2.17.jar

$ jar cvfm libs.jar manifest.txt
added manifest

By simply adding the libs.jar to the classpath when invoking javac, the additional jar files get pulled in:

$ javac -d bin -classpath libs.jar -sourcepath src src/com/example/Sample.java

$ ls -la bin/com/example/Sample.class
-rw-r--r-- 1 andreas users 432 Apr  7 12:20 bin/com/example/Sample.class

A real-world sample where this is used is the Oracle Platform Security Services. There is only one jar file which needs to be added to the build path, jps-manifest.jar, which references all other required jar files through its Class-Path attribute.


New features in Java 8

Posted on Monday, March 17 2014 at 21:18 | Category: Java | 2 Comment(s)

Java 8 is to be released tomorrow. Time to have a look at some of the new features: New features in Java 8 


Displaying results 13 to 16 out of 23