Joonas Javanainen

Thoughts about the ZK Web Framework: Technical stuff

As I mentioned in my previous post, ZK has a tendency to "just work". The overall technical quality is impressive and on par with most Java web frameworks, but I believe there are some parts of ZK that are less impressive.

Stuck on Java 1.4

ZK is built with Java 1.4, which greatly limits the flexibility of their API and internal code quality

Negative effects on ZK internal code

No annotations

Personally I'm not a fan of annotation-heavy frameworks because annotations are an extralinquistic feature and usually you end up annotations with string-based values that have no type safety. However, I know that some people would be overjoyed to have an API based on them.

No enums

There are many places in the ZK API where proper enums would be much better than the hacks that are used at the moment. The worst offender is Messagebox. Just look at this signature:

public static int show(String message,
                       String title,
                       int buttons,
                       java.lang.String icon,
                       int focus)

Ugh..the magic integers remind me of SWT (which is a great library with an awful API). Let's imagine an alternative version with enums and generics:

public static Messagebox.Button show(String message,
                       String title,
                       Set<Messagebox.Button> buttons,
                       Messagebox.Icon icon,
                       Messagebox.Button focus)

Much, much better and more typesafe. No more bitwise OR magic. I could code this in 10 minutes into ZK if it would use Java 1.5.

No generics

This is the worst part of being stuck on Java 1.4.

I'll just list some of the places where I'd like to see generics:

Collection values in API signatures

Example in org.zkoss.zk.ui.util.Initiator:

void doInit(Page page, Map args);

vs

void doInit(Page page, Map<String, Object> args);

Example in org.zkoss.zk.ui.Component:

List getChildren();

vs

List<Component> getChildren();

Collection-like classes

Example in ListModel:

public interface ListModel {
  ...
  Object getElementAt(int index);
  ...
}

vs

public interface ListModel<T> {
  ...
  T getElementAt(int index);
  ...
}

All ListModel* classes should also be generic (most extend java.util.Collection).

org.zkoss.zk.ui.event.EventListener

public interface EventListener {
  public void onEvent(Event event);
}

vs

public interface EventListener<T extends Event> {
  public void onEvent(T event);
}

org.zkoss.zk.ui.util.GenericAutowireComposer

public class GenericAutowireComposer {
  protected Component self;
  ...
}

vs

public class GenericAutowireComposer<T extends Component> {
  protected T self;
  ...
}

All *Renderer classes

Example in org.zkoss.zul.RowRenderer:

public interface RowRenderer {
  void render(Row row, Object data);
}

vs

public interface RowRenderer<T> {
  void render(Row row, T data);
}

Unimpressive server push implementations

The default PollingServerPush has latency and will absolutely kill your application server if there are many active users. CometServerPush is better, but it does not use non-blocking IO and will block servlet threads in your servlet container. Let's put this into perspective:

Tomcat 7.0 default configuration sets connector max threads to 200. This means that if you have 200 comet-enabled desktops, Tomcat will stop responding to other requests because all the threads are in use by comet. If the implementation used Servlet 3.0 or container-specific async APIs instead, you could run Tomcat even with one thread. It would of course be slow but it would not stop working!

Also, CometServerPush requires ZK EE so regular users are stuck with PollingServerPush. I'd say that's a pretty big limitation considering how server push is marketed. However, it's not surprising: proper non-blocking comet is hard to implement and requires non-blocking components in all parts of the pathway from the browser to the servlet code.

Zscript

I don't like zscript. It might have been a good feature many years ago, but I believe that today it should not be used at all. Why, oh why would someone want to replace typesafe compiled Java code with non-typechecked zscript mixed with ZUL templates?

So, if you put "Java code" (=BeanShell code) in zscript, you might want to rethink that.

Reliance on reflection

Many useful features rely on reflection, which limits what things the compiler can check for you. This is very typical thing in many Java libraries/frameworks, so it's not really a ZK-specific thing. As a Scala user I can see how the limitations of Java have guided most frameworks to the path of reflection/annotations. Reflection cannot always be avoided but I think it's a bad sign if most of the useful features rely on reflection. Here are some features in ZK that use reflection: