Showing posts with label Development. Show all posts
Showing posts with label Development. Show all posts

Saturday, January 24, 2009

Quick Tip : Getting Eclipse to help spot common errors

Since Java is a statically typed language, the compiler is pretty good at spotting errors, but sometimes we do things that are syntactically correct, but which are semantically wrong; take for example the following code sample.

public class TestError {
  String personName;

  public TestError(String personName) {
       personName = persionName;
  }

  public int getNameSize() {
       return personName.length();
  }
}

The above code contains a common mistake, namely that the parameter personName is hiding the class field personName; all that's really happening is the parameter is getting re-assigned the value it originally had. The main problem with this kind of mistake is that the developer assumes the object state is full initialized after calling the constructor, but on calling the (admittely worlds most pointless) getNameSize() method a NullPointerException would be thrown.

There are a few ways that the above code could be corrected in order for the compiler to spot the error. One way is to set the personName class field to final, which tells the compiler the personName field MUST be assigned a value in the constructor, and thus ensures the object state is intialized correctly, i.e.:

public class TestError {
    final String personName;

    public TestError(String personName) {
  personName = personName;
    }

    public int getNameSize() {
  return personName.length();
    }
}

The compiler will now throw a "Blank field Person may not have been initialize" error and compilation will fail. This is good (and you should certainly make as many fields as you can final), but it doesn't help if we want to actually update the person name in a later method.

Another way we can give a hint to the compiler is to make the personName parameter final:

public class TestError {
    String personName;
    
    public TestError(final String personName) {
         personName = personName;
    }
    
    public int getNameSize() {
         return personName.length();
    }
}

Now the compiler won't let us modify the personName parameter and will throw a "The local field variable personName cannot be assigned" error, and again stop compilation. Setting parameters to final is probably a good idea, and a good way to state your intention to the compiler, but we probably don't want to do this on EVERY method.

Luckily Eclipse can come to our aid by spotting this, and other common potential issues. If we look at the original code in the Eclipse editor we see this:

Notice the yellow warning underline underneath the parameter assignment. Eclipse is giving us a warning that "The assignment to variable personName has no effect" (you can check this by hovering over the margin marker); That's pretty useful, but we tend to get use to, or just don't see, warnings. What we want to do is have Eclipse scream at us here's a mistake and halt compilation; fortunately for this blog post, this can be done.

The trick lies in the depths of the Eclipse preferences under the Java section. The following image shows the full path:

In the resulting dialogue on the right hand side you'll see several sub-options, but the one we're interested in is the Potential programming problems; when expanded it looks as follows:

By default this dialogue has all the options set to warning or ignore, which results in Eclipse waving pathetically at us rather than screaming. The option that would have protected our original code is Assignment has no effect (eg 'x = x'):. If we set this to error, Eclipse will now halt all compilation until it's fixed; our original code now looks like this in the editor :

We've now found the error at compilation, rather than during testing, when it could be much harder to track down. There are lots more options within the potential programming problems section and I encourage you to take a look and set the relevant ones; you can find more information about each one by pressing F1 in the dialogue and reading the Eclipse help.

Warning

These Eclipse compiler options are indeed a great help but PLEASE don't use them as a short-cut to writing good defensive code! In the given example above, the best way to write the code is to make the personName field final which not only protects against the object being set up correctly, it also tells future developers the intent of the personName field.

Friday, January 02, 2009

Using Eclipse Debugger With GWT

GWT uses CSS styling in order to format rendered widgets, but since your abstracted away from the underlying DOM, it can sometimes be hard to create the exact CSS rule.  I recently created a composite GXT component and as a result couldn't quite get the CSS rule correct, (as it turns out, it was a rogue DIV element messing things up).  The following shows how to use some advanced features of the Eclipse debugger, with a GWT application running in hosted mode, in order to see the HTML that's rendered for a GWT widget.
  1. First we need to set a breakpoint at the correct position in the code.  For this we open ComplexPanel: press CTRL+SHIFT+T and enter ComplexPanel and press OK
  2. Press CTRL+O and type "add", this will show the add(Widget, Element) method, press enter to jump to it
  3. On line 86 (the adopt call) right click in the margin and choose Toggle Breakpoint Setting Breakpoint
  4. Once the breakpoint has been set, right click on the breakpoint marker (blue dot in margin) and select breakpoint properties
  5. In the breakpoint dialog, click Enable Condition : Enable Condition
  6. The enable condition allows the breakpoint to only be triggered when the condition is met.  In the Condition box, enter "this instanceof RootPanel".  This is because ComplexPanel::Add will be called for all panels, but we're only interested in the point where a widget is added to the RootPanel. Breakpoint Condition
  7. Click OK and use the GWT launcher configuration to start a hosted mode session in debug mode.
  8. When the breakpoint activates, Eclipse will change to the debug perspective, stopping at line 86:  Breakpoint Triggered
  9. Press F6 to step over the adopt call, which we need to do in order to setup the child.  (If you remember from a previous post it's only in the adopt call where the Widget::setParent is called and the whole attach process begins.) Step Over
  10. Now we need to see the child DOM HTML element which we can do with the fantastic Debug Display view.  Bring up the display view by selecting Window -> Show View -> Display
  11. The display view will open (possibly at the bottom of the screen).  The display view allows any Java code to be executed, so we'll use it to call the GWT DOM.toString method which takes an element and displays the elements DOM as a string.  Go to the display view and enter DOM followed by CTRL+SPACE which will bring up the auto complete box. Select the com.google.gwt.user.client.DOM class. Selecting DOM
  12. Finish off the call to DOM.toString as follows :  Step Over
  13. Now we can execute the statement by highlighting the whole thing and clicking on the execute selected text (or pressing CTRL+SHIFT+D): Execute Selected Statement
  14. Once executed, the DOM will be displayed : DOM Complete
  15. To carry on with your application, press F8, the program will break next time something is added to the RootPanel

Saturday, December 27, 2008

The GWT rendering process

The project I'm currently working on uses GWT and GXT and so I decided to dig into the frameworks to figure out how the both perform their magic of turning Java components into HTML elements. Since I've done the work, I thought I may as well share it incase anybody else is curious!

GWT Rendering

In order for GWT to render any component it MUST be added to the RootPanel, which is just a standard Panel component that wraps an actual existing element on the browsers HTML DOM; this can be see from the following hierarchy:

The RootPanel.get(String id) method, which will look up the specified element by id and return a RootPanel that wraps it, OR it will return a DefaultRootPanel which simply wraps the Body element (which is what you get if you call the RootPanel.get() method). The following code snippet from RootPanel.get(String) shows how all this is done:

    // Find the element that this RootPanel will wrap.
    Element elem = null;
    if (id != null) {
      if (null == (elem = DOM.getElementById(id))) {
        return null;
      }
    }

    // SNIP SNIP

    // Create the panel and put it in the map.
    if (elem == null) {
      // 'null' means use document's body element.
      rp = new DefaultRootPanel();
    } else {
      // Otherwise, wrap the existing element.
      rp = new RootPanel(elem);
    }

The process by which elements are added to this RootPanel is now the same for any standard panel, but before we get into that, we must understand two concepts in GWT regarding attachment, i.e the process by which a Widget becomes attached to the HTML DOM.

  • Logical Attachment : A component is said to be Logically Attached if it has been created (or even added to a parent), but has not been added to the physical DOM.
  • Physical Attachment : A component is physically attached when it has been added to the underlying DOM (and thus will be rendered by the browser)

Components are created using Logical Attachment (by, for example, creating and setting up new Panel objects), and then physically attached by adding them to a RootPanel. GXT extends on this idea to allow components to be lazily rendered as we'll see later. For now lets have a look at how this all works using the simple GWT Label widget.

Widget Creation

Since GWT is Java, creating a new Widget is as simple as instantiating it's constructor .i.e.

Label label = new Label("My Label");

And the constructor looks like so :

 public Label() {
    setElement(Document.get().createDivElement());
    setStyleName("gwt-Label");
  }

As we can see from the following code snippet, the label constructor calls into the special GWT DOM object in order to create a DIV element, this will be the actual element that will represent this Widget in the browser. Remember though that at this time the Element has not been physically attached to the underlying DOM, you could create thousands of these Label objects and none would currently appear in the browser.

The constructor calls the setElement method in order to inform the Widget what element it is going to use. This really calls down to the UIObject class which is the base of all, UI Objects in GWT. The element is simply registered for later use :

  protected void setElement(com.google.gwt.user.client.Element elem) {
    assert (element == null) : SETELEMENT_TWICE_ERROR;
    this.element = elem;
  }

Setting up the Widget

At this point in the process we have an empty label which isn't going to look very interesting on an HTML page so now we need to give it some text. This is done via the aptly named setText method. If we have a look at Widget.setText we can see it calls the standard setInnerText the DIV element created earlier :

  public void setText(String text) {
    getElement().setInnerText(text);
  }

Rendering the Widget

We now have a label with some text which we know is actually a DIV element with some inner text, which remember is still only Logically attached; as far as the browser is concerned our Widget doesn't currently exist. As said before, in order to physically attach the element we need to add it to a RootPanel, lets now look at the process our Label goes through when it's added.

  1. RootPanel.add is called to add the Label to the underlying browser DOM
  2. ComplexPanel.add gets called to add the Label as a child of this panel (RootPanels are after all normal panels around a well known DOM element). This logically attaches the Label as a child of the panel, then physically attaches the Label as a child of the panels DOM Element.
  3. ComplexPanel.adopt is called which calls Label.setParent() to inform the label it now has a parent
  4. Label.setParent will call the onAttach method if this parent has been physically attached to the DOM (which it will have been since the panel wraps an existing DOM element)
  5. In the case of the Label there is no onAttach implementation, the DIV element was created when the Label was created and the innerText of the DIV is set as soon as setLabel is called on the Label; therefore in the case of our simple Label example, the rendering process is complete.

The following diagram shows (or at least attempts to show), how this all hangs together:

Click for bigger image

GXT Rendering

GXT or (EXT for GWT), is the widget framework I'm working with on my current project, which changes the rendering process to provide lazy rendering of the components. GXT doesn't provide a Label component, but it does provide an Html component, so lets look at how GXT handles the rendering process.

  1. When the Html component is created, unlike the GWT Label, it DOESN'T create a DOM element, instead it acts just like a simple Java Object
  2. Html.setHtml(String) can be called at any time and, if the component hasn't been attached (rendered in GXT speak), the html is simply stored in a String field.
  3. A GXT Component extends the GWT Widget class and therefore can be added to a standard RootPanel
  4. The rendering process is the same as above, however the GXT Component.onAttach overrides the Widget.onAttach in order to perform the GXT rendering process. It's worth looking at the onAttach method in a little more detail because it solves a problem with lazy rendering of components.
  5. If you look at the previous diagram you'll see that AbsolutePanel.add(Widget) retrieves the DOM element of the component (with getElement()) and passes it to the ComplexPanel.add(Widget, Element) method. Unfortunately in GXT we don't want to create the DOM element until the onAttach method which is lower down the call stack. GXT solves this by adding a dummy DOM element if getElement is called on the widget before it's been rendered. The following code shows the important part of the getElement method:
         if (!rendered) {
          if (dummy == null) dummy = DOM.createDiv();
          return dummy;
        }
    
    The onAttach method then removes this dummy DOM element (which it calls a proxy) and calls the components render method.
  6. The components render method is the work horse of the framework and performs the following :
    • calls beforeRender()
    • Intializes plugins
    • calls createStyles()
    • calls onRender()
    • If events have been added, registers to revieve
    • Adds the base style name
    • calls afterRender()
    • Fires the Events.Render event
    Out of all of these, it's the onRender method that should be overriden by components. A component onRender method MUST call setElement otherwise on returning from the onRender method an exception will be thrown.

From this it can be seen that GXT makes the rendering process a little simpler by only requiring a component to override onRender. What's more there are times when you don't actually know what type of DOM element will represent the component until it's time to actually render it, the default GWT render process does not support this.

As an example, lets compare the GWT HTML widget with the GXT Html (camel case!) component. The GWT version needs to know the DOM component type up front, simply because setElement MUST be called during widget creation, which means the GWT HTML component is ALWAYS a DIV with the HTML as the innerHtml. GXT however allows components to defer the decision on the underlying DOM Element until render time and so the GXT Html component allows the actual parent tag type to be set at any time (before rendering) using the setTagName() method. At render time the correct component type is created and rendered.