ObjectMojo Documentation v1.0

(In Progress; please send errata/suggestions/feedback to avishek.sen.gupta@gmail.com)

 

Contents

 

1.      What is ObjectMojo ?

2.      Who should use ObjectMojo ?

3.      When should you use ObjectMojo ?

4.      Getting Started

5.      The EnhancedObject system

6.   Translators

7.   Controllers

8.   Layouts

9.   ObjectMojo annotations

10. Factories, mappers and proxies.

 

 

1. What is ObjectMojo?

 

ObjectMojo is a framework for building thick client GUIs out of objects with very little effort. It integrates the view and the underlying data into a tight bind to the extent that you don’t need to worry about whether the GUI is updated if you change the underlying value.

 

However, this does not involve code generation. Instead ObjectMojo builds the GUI using composition during runtime, by inspecting the type and data of the candidate objects. Using a system of controllers which can be customised and overridden to any extent, it lets the developer wire in custom GUI logic wherever necessary.

 

To make this uniform and intuitive in all situations as well as to facilitate the binding between the GUI and data, ObjectMojo uses a combination of reflection, dynamic proxies and Java 5 annotations. However, it is important to note that these facilities are used only during GUI construction. Any custom GUI logic or any change in the underlying data is achieved through a set of simple, well-defined interfaces.

 

Also, ObjectMojo enhances many of the wrapper types to be more robust and useful. Extending them or introducing new types is easy, too.

 

2. Who should use ObjectMojo?

 

Developers looking to create GUIs without the hassle of updating them everytime the underlying data model changes will benefit from ObjectMojo. In the same vein, developers looking to build a rapid functional GUI prototype will find this feature very useful.

 

3. When should you use ObjectMojo?

 

There are several situations:

 

 

 

4. Getting Started

 

So let’s create a simple object for ObjectMojo to show. Let’s call the class MyClass and let it contain an integer. Then the definition of MyClass looks like this:

 

public class MyClass implements SkeletonObject {

            private SkeletonInteger _integer;

// v0.84 Note: The reference is now SkeletonInteger, not SkeletonObject.

           

public MyClass(int x) {

            _integer = new EnhancedInteger(x);

}

 

public String toString() {

            return “MyClass”;

}

 

@SetterMethod public void setEqualTo(SkeletonObject o) {

}

 

@SetterMethod public void mark(Status s) {

}

 

public State getState() {

            return null;

}

 

public Object toPrimitive() {

            return null;

}

 

public SkeletonObject proxy() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

           

return null;

}

 

public boolean equals(Object o) {

            return super.equals(o);

}

 

public String name() {

            return toString();

}

}

 

All the methods that you see in MyClass have come in because we have implemented the SkeletonObject interface. It is not too important to implement any of them at this point, though you may wish to take note of them.

The only significant code in the above class is in the constructor where the int value is passed into a new EnhancedInteger object. We’ll look at the EnhancedInteger class in more detail shortly but for now, on with the code.

We need to present MyClass, or rather, an instance of MyClass, to the user. We write like so:

 

 

public class MinimumDemo {

            public static void main(String[] args) throws NonRenderableClassException {

                        SkeletonObject o = new MyClass(20);

                        new DefaultController(o, new SimpleFactory(o).buildUI()).start();

}

}

 

That’s all! So, let’s look at the code in brief. You can find more details in later chapters.

 

MyClass defines the class itself. As explained before, it implements the SkeletonObject interface. What the methods in the interface are for are explained in detail later. MyClass has one private member variable which is of type SkeletonObject. At this point, it seems appropriate to state ObjectMojo Writ #1:

 

ObjectMojo enforces programming to an interface.

 

0.84 Note: This is no longer a restriction, since ObjectMojo now uses cglib. However, it is possible to turn it on and use default Java proxies; see the Observable Mixin.However, there is an issue in which the derived proxies so initialised do not have their values set.

 

Which means that if you declared the _integer member variable in the MyClass class like this:

 

public class MyClass implements SkeletonObject {

            private EnhancedNumber _integer;

…}

 

You will get the following cheery RuntimeException:

 

Exception in thread "main" com.sourcerer.objectmojo.exceptions.NotInterfaceException: Reference _integer in class com.sourcerer.objectmojo.demo.MyClass must be an interface.

 

Why this is so will become apparent later.

 

Returning to our discussion of the code: in main(), we create an object of the MyClass type in the usual way passing in 20 as the constructor argument. The only thing remaining is to get the view out of the factory using the getUI() method and stuff it into a DefaultController object; which is what the code does.

 

More detailed information on the whole process is given later, but that’s all there is to it. Here’s the resulting screenshot.

 

 

OK, so what is so special about the above output? You can do the whole thing in Swing just as easily, except for picking up the value. Well, I could tell you, but here’s a teaser. Add one more field to the MyClass class, like so:

 

public class MyClass implements SkeletonObject {

            private SkeletonInteger _integer;

            private SkeletonString _string;    // Add this line

 

            public MyClass(int x, String s) {    // Change this line

                        _integer = new EnhancedInteger(x);

                        _string = new EnhancedString(s);    // Add this line

            }

 

And change the constructor invocation in main() to:

 

SkeletonObject o = new MyClass(20, "ObjectMojo");

 

and run the code again. Here’s the screenshot:

 

 

Wanna see more? Enter an invalid value like 12abcd in the _integer field and tab out. Here’s what you get:

 

 

There’s a beep too (hey, this is a document !).

 

Let’s write something a little more interesting now. We want the sum of two numbers, which we can change independently.

The objects are pretty simple: two operands and a sum. Let’s write the Adder class, like so:

 

public class Adder implements SkeletonObject {

            private SkeletonInteger _lhs = new EnhancedInteger();

            private SkeletonInteger _rhs = new EnhancedInteger();

            private SkeletonInteger _sum = new EnhancedInteger();

 

            @SetterMethod public void setEqualTo(SkeletonObject o) {

            }

 

            @SetterMethod public void mark(Status s) {

            }

 

            public State getState() {

                        return null;

            }

 

            public Object toPrimitive() {

                        return null;

            }

 

            public SkeletonObject proxy() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

                        return null;

            }

 

            public String name() {

                        return "Adder";

            }

 

            public SkeletonInteger getLhs() {

                        return _lhs;

            }

 

            public SkeletonInteger getRhs() {

                        return _rhs;

            }

 

            public SkeletonInteger getSum() {

                        return _sum;

            }

}

 

Nothing dramatic in that: we implemented SkeletonObject and wrote three lines of code to initialise three member variables. Let’s check and see that whatever we wrote is reflected in the GUI. We write AdderDemo, like so:

 

public class AdderDemo {

            public static void main(String[] args) throws NonRenderableClassException {

                        Adder operands = new Adder();

                        new DefaultController(operands, new SimpleFactory(operands).buildUI()).start();

            }

}

 

Nothing different here as well. It’s exactly like the previous example. Let’s run it.

 

 

Which is exactly we’d hoped to find. There is no logic wired up yet, so the sum text box behaves independently. Let’s go back to the code. What we want is for the sum text box to be updated whenever the user types a value and tabs out of one of the other operand boxes.

We want, in effect, an observer, which will do this for us. There are multiple options for what we want to do. The proper way to do it would be to write our own controller, but let’s keep things simple and let the Adder class take on the role of updating the sum field.

 

To do this is very simple. You only need to make Adder implement the BasicObserver interface. This is the BasicObserver interface:

 

public interface BasicObserver {

            public void alert(Object message);

}

 

So now, our Adder class reads like so:

 

public class Adder implements SkeletonObject, BasicObserver {

… // Rest of the code

            public void alert(Object message) {

                        _sum.setEqualTo(_lhs.add(_rhs));

            }

}

 

Pretty simple, huh? We are not done yet, though. The observer will need to observe something. In this case, the ‘something’ is the two operands. Add a default constructor to the Adder class, like so:

 

public class Adder implements SkeletonObject, BasicObserver {

            public Adder() {

                        ((Observable) _lhs).add(this);

                        ((Observable) _rhs).add(this);

}

… // Rest of the code

}

 

This simply states that Adder will be alerted to any change on _lhs or _rhs.

That’s all there is to it. Let’s run the code:

 

 

As soon as you tab out of Lhs or Rhs, the Sum box updates itself. Pretty nifty for about 8 lines of user-written code.

 

<deprecated >

There is a problem however. If you enter something illegal like abcd in any of the operand fields, you’ll get a stack trace along the lines of:

 

java.lang.ClassCastException: java.lang.String

            at com.sourcerer.objectmojo.enhanced.EnhancedNumber.value(EnhancedNumber.java:9)

            at com.sourcerer.objectmojo.enhanced.EnhancedInteger.add(EnhancedInteger.java:38)

            at com.sourcerer.objectmojo.enhanced.EnhancedInteger.add(EnhancedInteger.java:5)

 

This is not really anyone’s fault. When you wrote the code for adding the operands namely:

 

            public void alert(Object message) {

                        _sum.setEqualTo(_lhs.add(_rhs));

            }

 

there is no way for ObjectMojo to know what to do when you get a illegal value. What do you do in such a case? Well the answer depends upon you. Do you not want to update the sum field if any of the values are illegal? In which case you can write this:

 

            public void alert(Object message) {

                        if (!(_lhs.getState().isValid() && _rhs.getState().isValid()))  return;

                        _sum.setEqualTo(_lhs.add(_rhs));

            }

 

Or do you want to flag the sum field as illegal? In which case, you can do this:

 

            public void alert(Object message) {

                        if (!(_lhs.getState().isValid() && _rhs.getState().isValid())) {

                                    _sum.mark(Status.INVALID);

                                    return;

                        }

                        _sum.setEqualTo(_lhs.add(_rhs));

            }

 

Normally you’d validate such fields only on some action (like pressing a button), but this kind of thing might be needed in some cases.

</deprecated>

 

You may have noticed something, in all the code we’ve written there is not a single line of GUI update logic involved at all.

 

Let’s take this example a bit further before moving on to other stuff. We’ve decided that we want to add the two operands, as well as subtract the second one from the first. We want the user to select which operation he wants to do by pressing the appropriate button.

 

On with the show. Remove the alert() method from the Adder class. Remove the implements BasicObserver clause from the declaration too, so that the Adder class looks like what it was at the beginning of the example. Also remove the hookup code in the default contructor. Hell, remove the default constructor.

 

Good, that’s done. We need to write our own controller, since we need to have actions which the code will need to respond to. How do we write it? Like so:

 

public class AdderController extends DefaultController {

            public AdderController(SkeletonObject model, BasicView v) throws NonRenderableClassException {

                        super(model, v);

            }

}

 

Looks pretty simple, and it is. We’ve extended DefaultController for this example, but you might need to implement the Controller interface if you need more complex customisations.

 

Now we need to add buttons so that the controller can hook up to them and respond to them. So do we have to create these buttons? Do we have to hook the controller up to them?

 

The answer is no on both counts. Let’s see how simply we can do this. One step at a time. Let’s say we want the controller to allow adding. We write like so:

 

public class AdderController extends DefaultController {

            public AdderController(SkeletonObject model, BasicView v) throws NonRenderableClassException {

                        super(model, v);

            }

 

            @Action(name = “Add”)

public void add() {

                        Adder adder = (Adder) _model;

                        adder.setSum(adder.getLhs().add(adder.getRhs()));

            }

}

 

This is pretty straightforward; all we’ve done is set sum on the Adder class. However, we have qualified it with an annotation Action. It takes in a name which we have set to Add. What this will do is add a button with Add as its label and hook it up with the add method. All this is don behind the scenes of course leaving you with the above code. Easy.

Before we proceed further you need to implement the getLhs(), getRhs() and setSum() methods in the Adder class which is pretty straightforward.

 

            public SkeletonInteger getLhs() {

                        return _lhs;

            }

 

            public SkeletonInteger getRhs() {

                        return _rhs;

            }

 

            public void setSum(SkeletonInteger s) {

                        _sum.setEqualTo(s);

            }

 

Pretty simple stuff, what. Now change AdderDemo to use AdderController instead of DefaultController. Nothing much to do, just replace the name so that it reads:

 

public class AdderDemo {

            public static void main(String[] args) throws NonRenderableClassException {

                        Adder operands = new Adder();

                        new AdderController(operands, new SimpleFactory(operands).buildUI()).start();

            }

}

 

Here’s a screenshot.

 

 

Quite decent. Now we need to add the subtraction function. Do the same thing. The completed AdderController will now read like this:

 

public class AdderController extends DefaultController {

            public AdderController(SkeletonObject model, BasicView v) throws NonRenderableClassException {

                        super(model, v);

            }

 

            @Action(name = "Add")

            public void add() {

                        Adder adder = (Adder) _model;

                        SkeletonInteger sum = adder.getSum();

                        sum.setEqualTo(adder.getLhs().add(adder.getRhs()));

            }

 

            @Action(name = "Subtract")

            public void subtract() {

                        Adder adder = (Adder) _model;

                        SkeletonInteger sum = adder.getSum();

                        sum.setEqualTo(adder.getLhs().subtract(adder.getRhs()));

            }

}

 

Refactor this a bit if you fancy, so that it looks like so:

 

public class AdderController extends DefaultController {

            public AdderController(SkeletonObject model, BasicView v) throws NonRenderableClassException {

                        super(model, v);

            }

 

            @Action(name = "Add")

            public void add() {

                        sum().setEqualTo(adder().getLhs().add(adder().getRhs()));

            }

 

            @Action(name = "Subtract")

            public void subtract() {

                        sum().setEqualTo(adder().getLhs().subtract(adder().getRhs()));

            }

 

            private SkeletonInteger sum() {

                        return adder().getSum();

            }

 

            private Adder adder() {

                        return (Adder) _model;

            }

}

 

And run it. Here’s the final screenshot.

 

 

 

Let’s look at user-defined objects now.

 


 

5. The EnhancedObject system

 

ObjectMojo allows the programmer with a lot of flexibility on how he builds his model. In fact, there are no restrictions on what the model can be save one. The one requirement is that the model must implement the SkeletonObject interface. Let’s look at the SkeletonObject interface briefly.

 

public interface SkeletonObject extends Renderable {

            public String toString();

            @SetterMethod public void setEqualTo(SkeletonObject o);

            @SetterMethod public void mark(Status s);

            public State getState();

            public Object toPrimitive();

            public boolean equals(Object o);

public SkeletonObject proxy() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException;

}

 

The most notable method is the setEqualTo() method. The other methods will be discussed at length, but let’s talk of why there is such a method like setEqualTo().

 

The main aim of ObjectMojo is to group GUI and data into a tight bind. The binding should make it unnecessary for the programmer to touch the view in any way, letting him concentrate on the logic alone. The only time he might need to do that might be if he needs a heavily customised view, which we’ll not consider for the time being.

 

This implies that any change in the object, even a programmatic change, should trigger a change in the GUI. This means that if I have a String objects, I have no way of detecting if s has changed if I write the following:

 

String s = new String(“ABCD”);

 

For this reason, most of the primitive types like Integer, Double, String, etc. have been wrapped into their more “intelligent” counterparts. This helps achieve a standardised way of changing an object’s state. However, this doesn’t mean that setEqualTo() is the only way to change an object’s state: the programmer-defined model may have many other methods which change the object’s state. These are methods which ObjectMojo cannot anticipate.

 

Therefore, any method which may change the state of an object can be marked by the @SetterMethod annotation, as you can see in the SkeletonObject interface above. During runtime, these methods are linked to the actual views which refresh on calling each of these methods.

 

How these methods get linked without the model explicitly implementing an Observer pattern is discussed in Factories, Mappers and Proxies.