Extreme Java When vanilla Java is not enough

28Nov/080

One more strange bug

I've noticed that all Java applications on my machine are slowing down a lot. But, when I my brand-new and self-made budget application freezes while doing a "new JFileChooser()", this really pi**es me off. Asking Google, I found another weird bug: when your Windows Desktop has a lot of ZIP files, Java will implicity use Windows "zip folder" feature.

You can also blame Microsoft, because Win32ShellFolder.isDirectory() returns "true" (in W32API terms) when checking zip files. Don't you love proprietary API?

Workarounds:

  1. Clean your Desktop
  2. If you are as lazy as me, you can disable "zip folder" with:
    regsvr32 /u %windir%\system32\zipfldr.dll
19Nov/080

NetBeans 6.5

Finally, NB 6.5 was released! Grab your copy!

Unfortunatelly the download link is blocked here... I hate proxies...

Tagged as: No Comments
6Nov/080

Dynamic code in Java (a.k.a. "eval in Java")

I really don't like eval-like structures. They are evil. It is a headache to test, makes code ugly, hard to optimize, etc. I simply don't like them.

But I finally found a use to them. It's very common to use scripting to create a flexible system. I have a ticket filter that uses Spring and EL to create filtering rules in a "building blocks"-way. It is cool, easy to maintain, but it is not optimized: hundreds of instances in a Composite Pattern (with some expressions) must be navigated to find a simple boolean answer: keep or discard?

Java 6 has a not-so-secret feature that allows invoking the javac using Java code: you pass the files to the framework, it builds compiled classes. You can find how in the JavaCompiler's API. It mentions an example of a JavaSourceFromString class that you can implement and give the compiler java code stored in String. Very useful!

But, if you try and run a test (like this one), you will receive a nice class file. But that's not what I want. I want it loaded and ready-to-go. How to interface with this new class when it is loaded? Reflection? Maybe, but I prefer another way: interfaces. I already have this simple one:

package pkg;
public interface Filter {
    boolean filter(VO vo);
}

It is the base of my filter infrastructure. If I change JavaBeat test code to something that "implements pkg.Filter", my whole problem is solved, with minimal changes on the rest of the code.

Nice! We can interface with the class, but it is not loaded! I could read the class file and pass it to the ClassLoader, but I don't want to create a file. This class does the trick:

class JavaObjectToByteArray extends SimpleJavaFileObject {
    private ByteArrayOutputStream output = new ByteArrayOutputStream();
    public JavaObjectToByteArray(String className, Kind kind)
            throws URISyntaxException {
        super(new URI(className), kind);
    }
    @Override
    public OutputStream openOutputStream() throws IOException {
        return output;
    }
}

You can pass this object by overriding ForwardingJavaFileManager.getJavaFileForOutput:

fileManager = new ForwardingJavaFileManager(fileManager) {
  @Override
  public JavaFileObject getJavaFileForOutput(Location location,
      String clazz, Kind kind, FileObject sibling) throws IOException {
    try {
      JavaObjectToByteArray jfo = new JavaObjectToByteArray(clazz, kind);
      cl = new ByteArrayClassLoader(className, jfo.output);
      return jfo;
    } catch (Exception ex) {
      throw new IOException(ex);
    }
  }
};

ByteArrayClassLoader is:

class ByteArrayClassLoader extends ClassLoader {
  private String clazz;
  private ByteArrayOutputStream baos;
  public ByteArrayClassLoader(String clazz, ByteArrayOutputStream baos) {
    this.baos = baos;
    this.className = className;
  }
  @Override
  protected Class<?> findClass(String name) throws ClassNotFoundException {
    byte[] data = baos.toByteArray();
    return defineClass(name, data, 0, data.length);
  }
  public Class<?> loadClass() throws ClassNotFoundException {
    return loadClass(className);
  }
}

The "loadClass" method is a convenience method, since this class loader only loads one class. With one line of code, I can use my brand-new-dynamic-class:

Class<?> clz = cl.loadClass();
Filter f = (Filter) clz.newInstance();
System.out.println(f.filter(vo));

BTW, there's only one small change in JavaBeat's code. I need a "public" class, and this means the java file must be named "MyClass.java" (not "MyClass"). You only need to change JavaObjectFromString constructor from:

super(new URI(className), Kind.SOURCE);

to:

super(new URI(className + ".java"), Kind.SOURCE);

Easy, huh? It is not like "eval" in JavaScript, but it is better, since this class will be JIT'ed.