diff --git a/CHANGES.txt b/CHANGES.txt index 12add5121e..cd5b1096e5 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -151,6 +151,11 @@ Trunk (unreleased changes) HADOOP-6536. Fixes FileUtil.fullyDelete() not to delete the contents of the sym-linked directory. (Ravi Gummadi via amareshwari) + HADOOP-6881. Make WritableComparator intialize classes when + looking for their raw comparator, as classes often register raw + comparators in initializers, which are no longer automatically run + in Java 6 when a class is referenced. (cutting via omalley) + Release 0.21.0 - Unreleased INCOMPATIBLE CHANGES diff --git a/src/java/org/apache/hadoop/io/WritableComparator.java b/src/java/org/apache/hadoop/io/WritableComparator.java index e55036c6c0..bfb1673222 100644 --- a/src/java/org/apache/hadoop/io/WritableComparator.java +++ b/src/java/org/apache/hadoop/io/WritableComparator.java @@ -42,13 +42,38 @@ public class WritableComparator implements RawComparator { new HashMap(); // registry /** Get a comparator for a {@link WritableComparable} implementation. */ - public static synchronized WritableComparator get(Class c) { + public static synchronized + WritableComparator get(Class c) { WritableComparator comparator = comparators.get(c); - if (comparator == null) - comparator = new WritableComparator(c, true); + if (comparator == null) { + // force the static initializers to run + forceInit(c); + // look to see if it is defined now + comparator = comparators.get(c); + // if not, use the generic one + if (comparator == null) { + comparator = new WritableComparator(c, true); + comparators.put(c, comparator); + } + } return comparator; } + /** + * Force initialization of the static members. + * As of Java 5, referencing a class doesn't force it to initialize. Since + * this class requires that the classes be initialized to declare their + * comparators, we force that initialization to happen. + * @param cls the class to initialize + */ + private static void forceInit(Class cls) { + try { + Class.forName(cls.getName(), true, cls.getClassLoader()); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Can't initialize class " + cls, e); + } + } + /** Register an optimized comparator for a {@link WritableComparable} * implementation. */ public static synchronized void define(Class c, diff --git a/src/test/core/org/apache/hadoop/io/TestWritable.java b/src/test/core/org/apache/hadoop/io/TestWritable.java index 9e7de1e633..a60ef1b8d2 100644 --- a/src/test/core/org/apache/hadoop/io/TestWritable.java +++ b/src/test/core/org/apache/hadoop/io/TestWritable.java @@ -96,4 +96,27 @@ public static Writable testWritable(Writable before return after; } + private static class FrobComparator extends WritableComparator { + public FrobComparator() { super(Frob.class); } + @Override public int compare(byte[] b1, int s1, int l1, + byte[] b2, int s2, int l2) { + return 0; + } + } + + private static class Frob implements WritableComparable { + static { // register default comparator + WritableComparator.define(Frob.class, new FrobComparator()); + } + @Override public void write(DataOutput out) throws IOException {} + @Override public void readFields(DataInput in) throws IOException {} + @Override public int compareTo(Object o) { return 0; } + } + + /** Test that comparator is defined. */ + public static void testGetComparator() throws Exception { + assert(WritableComparator.get(Frob.class) instanceof FrobComparator); + } + + }