Metawidget User Guide and Reference Documentation

Version 4.2

Richard Kennard Table of Contents

Preface ...... xi Supported Technologies ...... xii 1. Introduction to Metawidget ...... 1 1.1. Part 1 ( version) - The First Metawidget Application ...... 1 1.1.1. The Object ...... 1 1.1.2. The Interface ...... 1 1.1.3. The Output ...... 2 1.1.4. Ordering The Properties ...... 4 1.1.5. Inspectors ...... 5 1.1.6. Combining Multiple Inspection Results ...... 7 1.1.7. Controlling The Layout ...... 8 1.1.8. Controlling Widget Creation ...... 11 1.1.9. Configuring Metawidget Externally ...... 15 1.2. Part 1 (JavaScript version) - The First Metawidget Application ...... 16 1.2.1. The Object ...... 16 1.2.2. The Interface ...... 17 1.2.3. The Output ...... 17 1.2.4. Inspectors ...... 18 1.2.5. Combining Multiple Inspection Results ...... 19 1.2.6. Controlling The Layout ...... 19 1.2.7. Controlling Widget Creation ...... 22 1.3. Part 2 - The Address Book Application ...... 24 1.3.1. Desktop Address Book ...... 24 Read-Only Mode ...... 26 Binding ...... 27 Localization ...... 28 1.3.2. Web Address Book ...... 28 Mixing Metawidgets ...... 31 Expression Based Lookups ...... 32 Alternate Widget Libraries (JSF 1.x) ...... 32 Alternate Widget Libraries (JSF 2.x) ...... 35 1.3.3. Mobile Address Book ...... 36 1.3.4. Conclusion ...... 40 1.4. Part 3 - Other Examples ...... 40 1.4.1. Applet Address Book Example ...... 40 1.4.2. Seam Example ...... 41 1.4.3. Groovy Example ...... 42 1.4.4. jBPM Example ...... 43 1.4.5. ICEfaces Example ...... 44 1.4.6. Java EE 6 Example ...... 45 1.4.7. Swing AppFramework Example ...... 45 1.4.8. Scala Example ...... 46 1.4.9. GWT Client Side Example ...... 48 1.4.10. GWT Hosted Mode Examples ...... 49 1.4.11. Static Metawidget Example ...... 51 2. Architecture ...... 52

Metawidget ii Metawidget User Guide and Reference Documentation

2.1. Metawidgets ...... 53 2.1.1. Interface ...... 53 2.1.2. Customizing Look and Feel ...... 54 2.1.3. Overriding Widget Creation ...... 54 2.1.4. Implementing Your Own Metawidget ...... 55 2.2. Inspectors ...... 55 2.2.1. Interface ...... 55 2.2.2. Usage ...... 56 2.2.3. CompositeInspector ...... 56 2.2.4. Defaults ...... 57 2.2.5. Immutability ...... 59 2.2.6. inspection-result ...... 60 2.2.7. Implementing Your Own Inspector (Java) ...... 60 2.3. Inspection Result Processors ...... 64 2.3.1. Interface ...... 64 2.3.2. Usage ...... 65 2.3.3. Defaults ...... 66 2.3.4. Immutability ...... 67 2.3.5. Implementing Your Own InspectionResultProcessor ...... 67 2.4. WidgetBuilders ...... 70 2.4.1. Interface ...... 70 2.4.2. Usage ...... 70 2.4.3. Advanced Interface ...... 70 2.4.4. CompositeWidgetBuilder ...... 71 2.4.5. OverriddenWidgetBuilder ...... 72 2.4.6. ReadOnlyWidgetBuilder ...... 73 2.4.7. Defaults ...... 74 2.4.8. Immutability ...... 76 2.4.9. Implementing Your Own WidgetBuilder ...... 76 Special considerations for Java Server Faces ...... 79 2.5. WidgetProcessors ...... 80 2.5.1. Interface ...... 80 2.5.2. Usage ...... 81 2.5.3. Advanced Interface ...... 82 2.5.4. Defaults ...... 83 2.5.5. Immutability ...... 84 2.5.6. Implementing Your Own WidgetProcessor ...... 85 2.6. Layouts ...... 87 2.6.1. Interface ...... 87 2.6.2. Advanced Interface ...... 88 2.6.3. LayoutDecorator ...... 89 2.6.4. Usage ...... 91 2.6.5. Defaults ...... 91 2.6.6. Immutability ...... 93 2.6.7. Implementing Your Own Layout ...... 93 2.7. metawidget. and ConfigReader ...... 95 2.7.1. Constructing New Objects ...... 96 2.7.2. Calling Setter Methods ...... 96

Metawidget iii Metawidget User Guide and Reference Documentation

2.7.3. Constructing Primitive Types ...... 97 2.7.4. Resolving Resources ...... 98 2.7.5. Understanding Immutability ...... 98 3. Metawidgets ...... 100 3.1. Desktop Metawidgets ...... 100 3.1.1. SwingMetawidget ...... 100 Installation ...... 100 Configuration ...... 100 Customizing Look and Feel ...... 100 Internationalization ...... 100 Under The Hood ...... 101 3.1.2. SwtMetawidget ...... 101 Installation ...... 101 Configuration ...... 101 Customizing Look and Feel ...... 101 Internationalization ...... 101 3.2. Web Metawidgets ...... 101 3.2.1. AngularJS Metawidget ...... 101 Installation ...... 102 Usage ...... 102 Configuration ...... 102 Customizing Look and Feel ...... 102 Two-Way Binding ...... 103 3.2.2. GwtMetawidget ...... 103 Installation ...... 103 Configuration ...... 104 Reflection and Annotations ...... 104 Client-Side Inspection ...... 105 Customizing Look and Feel ...... 105 Internationalization ...... 105 3.2.3. JavaScript Metawidget ...... 105 Installation ...... 106 Configuration ...... 106 Customizing Look and Feel ...... 107 Events ...... 107 Inspection Results ...... 108 Web Component ...... 108 3.2.4. JQuery UI Metawidget ...... 109 Installation ...... 109 Configuration ...... 109 3.2.5. Node.js ...... 109 3.2.6. HtmlMetawidgetTag (JSP) ...... 110 Installation ...... 110 Configuration ...... 111 Customizing Look and Feel ...... 111 Internationalization ...... 111 Overriding Widget Creation ...... 111 3.2.7. UIMetawidget (JSF) ...... 111

Metawidget iv Metawidget User Guide and Reference Documentation

Installation ...... 112 Configuration ...... 112 Customizing Look and Feel ...... 113 Internationalization ...... 114 Collections ...... 114 Facets ...... 114 JSF 2.0 ...... 115 ...... 115 3.2.8. SpringMetawidgetTag ...... 116 Installation ...... 116 Configuration ...... 116 Customizing Look and Feel ...... 117 Internationalization ...... 117 Overriding Widget Creation ...... 117 3.2.9. StrutsMetawidgetTag ...... 117 Installation ...... 117 Configuration ...... 118 Customizing Look and Feel ...... 118 Internationalization ...... 118 Overriding Widget Creation ...... 118 3.2.10. VaadinMetawidget ...... 119 Installation ...... 119 Configuration ...... 119 3.3. Mobile Metawidgets ...... 119 3.3.1. AndroidMetawidget ...... 119 Installation ...... 119 Configuration ...... 120 Customizing Look and Feel ...... 120 Internationalization ...... 120 Getting and Setting Values ...... 120 3.3.2. JQuery Mobile Metawidget ...... 121 Installation ...... 121 Configuration ...... 121 3.4. Static Metawidgets ...... 121 3.4.1. StaticPropertyStyle ...... 122 3.4.2. StaticMetawidget ...... 122 4. Inspectors ...... 123 4.1. Composite Inspector ...... 123 4.2. Property Inspectors ...... 123 4.2.1. BaseObjectInspector ...... 123 PropertyStyle ...... 124 JavaBeanPropertyStyle ...... 124 GroovyPropertyStyle ...... 125 JavassistPropertyStyle ...... 125 ScalaPropertyStyle ...... 125 Implementing Your Own PropertyStyle ...... 125 ActionStyle ...... 127 MetawidgetActionStyle ...... 127

Metawidget v Metawidget User Guide and Reference Documentation

SwingAppFrameworkActionStyle ...... 127 4.2.2. PropertyTypeInspector (Java version) ...... 127 4.2.3. JsonSchemaInspector (Java version) ...... 128 4.2.4. JsonSchemaInspector (JavaScript version) ...... 129 4.2.5. PropertyTypeInspector (JavaScript version) ...... 130 4.3. Annotation Inspectors ...... 131 4.3.1. BeanValidationInspector ...... 131 4.3.2. FacesAnnotationInspector ...... 131 4.3.3. HibernateValidatorInspector ...... 132 4.3.4. JacksonInspector ...... 132 4.3.5. JaxbInspector ...... 132 4.3.6. JpaInspector ...... 133 4.3.7. MetawidgetAnnotationInspector ...... 133 4.3.8. OvalInspector ...... 134 4.4. XML Inspectors ...... 134 4.4.1. BaseXmlInspector ...... 135 Mixing XML and Object-based Inspectors ...... 135 4.4.2. CommonsValidatorInspector ...... 136 4.4.3. HibernateInspector ...... 136 4.4.4. PageflowInspector ...... 136 4.4.5. SeamInspector ...... 137 4.4.6. XmlInspector ...... 137 4.4.7. XmlSchemaInspector ...... 137 4.4.8. WsdlInspector ...... 137 5. InspectionResultProcessors ...... 138 5.1. ComesAfterInspectionResultProcessor ...... 138 5.2. FacesInspectionResultProcessor ...... 138 5.3. JexlInspectionResultProcessor ...... 139 5.4. JspInspectionResultProcessor ...... 140 5.5. RestInspectionResultProcessor ...... 141 5.6. JavaToJavaScriptTypeMappingProcessor ...... 142 5.7. TypeMappingInspectionResultProcessor ...... 142 5.8. XmlSchemaToJavaTypeMappingProcessor ...... 142 6. WidgetBuilders ...... 143 6.1. Desktop WidgetBuilders ...... 143 6.1.1. Swing WidgetBuilders ...... 143 OverriddenWidgetBuilder ...... 143 ReadOnlyWidgetBuilder ...... 143 SwingWidgetBuilder ...... 143 SwingXWidgetBuilder ...... 144 6.1.2. SWT WidgetBuilders ...... 144 OverriddenWidgetBuilder ...... 144 ReadOnlyWidgetBuilder ...... 145 SwtWidgetBuilder ...... 145 6.2. Web WidgetBuilders ...... 146 6.2.1. GWT WidgetBuilders ...... 146 ExtGwtWidgetBuilder ...... 146 GwtWidgetBuilder ...... 146

Metawidget vi Metawidget User Guide and Reference Documentation

OverriddenWidgetBuilder ...... 146 ReadOnlyWidgetBuilder ...... 147 6.2.2. JavaScript WidgetBuilders ...... 147 HtmlWidgetBuilder ...... 147 OverriddenWidgetBuilder ...... 148 ReadOnlyWidgetBuilder ...... 148 6.2.3. JSP WidgetBuilders ...... 148 DisplayTagWidgetBuilder ...... 148 HtmlWidgetBuilder ...... 148 OverriddenWidgetBuilder ...... 149 ReadOnlyWidgetBuilder ...... 149 SpringWidgetBuilder ...... 149 StrutsWidgetBuilder ...... 150 6.2.4. JSF WidgetBuilders ...... 150 HtmlWidgetBuilder ...... 150 IceFacesWidgetBuilder ...... 151 OverriddenWidgetBuilder ...... 152 ReadOnlyWidgetBuilder ...... 152 PrimeFacesWidgetBuilder ...... 152 RichFacesWidgetBuilder ...... 153 TomahawkWidgetBuilder ...... 153 6.2.5. WidgetBuilders ...... 153 OverriddenWidgetBuilder ...... 153 ReadOnlyWidgetBuilder ...... 153 VaadinWidgetBuilder ...... 154 6.3. Mobile WidgetBuilders ...... 154 6.3.1. Android WidgetBuilders ...... 155 AndroidWidgetBuilder ...... 155 OverriddenWidgetBuilder ...... 155 ReadOnlyWidgetBuilder ...... 155 7. WidgetProcessors ...... 156 7.1. Desktop WidgetProcessors ...... 156 7.1.1. Swing WidgetProcessors ...... 156 Property Binding ...... 156 BeansBindingProcessor ...... 156 BeanUtilsProcessor ...... 157 Action Binding ...... 157 7.1.2. SWT WidgetProcessors ...... 158 DataBindingProcessor ...... 158 ReflectionBindingProcessor ...... 158 7.2. Web WidgetProcessors ...... 158 7.2.1. GWT WidgetProcessors ...... 158 Property Binding ...... 158 Action Binding ...... 159 StyleNameProcessor ...... 159 7.2.2. JavaScript WidgetProcessors ...... 159 AngularWidgetProcessor ...... 159 BootstrapWidgetProcessor ...... 159

Metawidget vii Metawidget User Guide and Reference Documentation

DisabledAttributeProcessor ...... 160 IdProcessor ...... 160 RequiredAttributeProcessor ...... 160 SimpleBindingProcessor ...... 160 7.2.3. JSF WidgetProcessors ...... 160 AjaxProcessor ...... 160 CssStyleProcessor ...... 160 HiddenFieldProcessor ...... 161 ImmediateAttributeProcessor ...... 161 LabelProcessor ...... 161 ReadableIdProcessor ...... 161 RequiredAttributeProcessor ...... 161 RichFacesProcessor ...... 161 StandardBindingProcessor ...... 161 StandardConverterProcessor ...... 161 StandardValidatorProcessor ...... 161 7.2.4. JSP WidgetProcessors ...... 162 HiddenFieldProcessor ...... 162 7.2.5. Vaadin WidgetProcessors ...... 162 CaptionProcessor ...... 162 MinimumMaximumValidatorProcessor ...... 162 RequiredProcessor ...... 162 SimpleBindingProcessor ...... 162 7.3. Mobile WidgetProcessors ...... 163 7.3.1. Android WidgetProcessors ...... 163 DisabledAttributeProcessor ...... 163 SimpleBindingProcessor ...... 163 8. Layouts ...... 165 8.1. Desktop Layouts ...... 165 8.1.1. Swing Layouts ...... 165 BoxLayout ...... 165 FlowLayout ...... 165 GridBagLayout ...... 165 GroupLayout ...... 166 MigLayout ...... 166 SeparatorLayoutDecorator ...... 166 TabbedPaneLayoutDecorator ...... 166 TitledPanelLayoutDecorator ...... 166 8.1.2. SWT Layouts ...... 167 FillLayout ...... 167 GridLayout ...... 167 MigLayout ...... 167 RowLayout ...... 167 SeparatorLayoutDecorator ...... 168 TabFolderLayoutDecorator ...... 168 8.2. Web Layouts ...... 168 8.2.1. GWT Layouts ...... 168 FlexTableLayout ...... 168

Metawidget viii Metawidget User Guide and Reference Documentation

FlowLayout ...... 168 LabelLayoutDecorator ...... 169 TabPanelLayoutDecorator ...... 169 8.2.2. JavaScript Layouts ...... 169 BootstrapDivLayout ...... 169 DefinitionListLayout ...... 169 DivLayout ...... 169 HeadingTagLayoutDecorator ...... 170 TabLayoutDecorator (Bootstrap) ...... 170 TabLayoutDecorator (JQuery UI) ...... 170 TableLayout ...... 170 SimpleLayout ...... 171 8.2.3. JSF Layouts ...... 171 HtmlDivLayoutRenderer ...... 171 HtmlTableLayoutRenderer ...... 171 OutputTextLayoutDecorator ...... 172 PanelGroupLayoutDecorator ...... 172 PanelLayoutDecorator ...... 173 PanelTabSetLayoutDecorator ...... 173 SimpleTogglePanelLayoutDecorator ...... 173 HtmlSimpleLayout ...... 173 TabPanelLayoutDecorator ...... 173 TabViewLayoutDecorator ...... 174 8.2.4. JSP Layouts ...... 174 HeadingTagLayoutDecorator ...... 174 HtmlTableLayout ...... 174 SpringTableLayout ...... 174 SimpleLayout ...... 174 8.2.5. Vaadin Layouts ...... 175 FormLayout ...... 175 HeadingTagLayoutDecorator ...... 175 HorizontalLayout ...... 175 TabSheetLayoutDecorator ...... 175 8.3. Mobile Layouts ...... 175 8.3.1. Android Layouts ...... 175 LinearLayout ...... 175 TableLayout ...... 175 TabHostLayoutDecorator ...... 176 TextViewLayoutDecorator ...... 176 9. How To's ...... 177 9.1. Order Properties ...... 177 9.2. View The Same Object In Different Ways ...... 177 9.3. Deploy As An Enterprise ARchive (EAR) ...... 178 9.4. Inspect Remotely ...... 179 9.4.1. Combine Remote Inspections ...... 180 9.5. Improve Performance ...... 180 9.5.1. JAR Size ...... 180 9.5.2. Memory Usage ...... 180

Metawidget ix Metawidget User Guide and Reference Documentation

9.5.3. DomInspector and DomInspectionResultProcessor ...... 181 9.5.4. Rebinding ...... 181 10. Troubleshooting ...... 182 10.1. General ...... 182 10.1.1. Metawidget Doesn't Work! ...... 182 10.2. Inspectors ...... 182 10.2.1. General Inspectors ...... 182 My Inspector does not return anything ...... 182 10.2.2. Annotation-Based Inspectors ...... 183 I get "java.lang.TypeNotPresentException" ...... 183 My inspector is not finding my annotations ...... 183 10.3. Web Metawidgets ...... 183 10.3.1. I put in my page but nothing appears ...... 183 10.3.2. Java Server Faces ...... 184 I have annotated my getter, but Metawidget is ignoring my annotations ...... 184 My parameterized List renders as a single column ...... 184 I get "View could not be restored" ...... 185 I get "The class ... does not have a readable property" ...... 185 10.3.3. Struts ...... 185 I get "Cannot find bean org.apache.struts.taglib..BEAN in any scope" ...... 185 I see "MultipartRequestHandler", "ServletWrapper" and other weird names ...... 185

Metawidget x Preface

Building user interfaces for domain objects can be cumbersome and time consuming in today's applications. Metawidget is an Object/User Interface Mapping tool. The term Object/User Interface mapping (OIM) refers to the technique of inspecting objects and creating User Interface (UI) widgets. As much as possible, Metawidget does this without introducing new technologies. As shown in Figure 1, Metawidget inspects an application's existing back-end architecture (such as REST, annotations, configuration files) and creates widgets native to its existing front-end framework (such as JavaScript, Java Server Faces, Android).

Figure 1. Metawidget inspects existing back-ends and creates widgets native to existing front-ends

Building great UIs is both art and science. Metawidget does not attempt to address the art, it only automates the science. That is to say, it does not overlap with those areas of UI design involving creativity and subjectivity - its goal is only to ease the creation of areas that are already rigidly defined. Typically, this means those areas that display data and those that collect data - these tend to be both commonplace and consistent (indeed, consistency is a desirable trait) so there is good opportunity for automation.

Note This User Guide and Reference Documentation is included in the Metawidget distribution as a PDF, a single HTML page or as multiple HTML pages, depending on your reading preference.

Metawidget xi Supported Technologies

A primary goal of Metawidget is to work with your existing front-end and back-end architecture. Out of the box, Metawidget supports a broad range of both front-end and back-end technologies, and makes it easy to add your own. Metawidget comes with a native UI component for each supported front-end. This support includes: Android, (including extensions such as ExtGWT), 'plain' HTML 5 (POH5), JavaScript (including extensions such as AngularJS, Bootstrap, JQuery Mobile, JQuery UI and Node.js), Java Server Faces (including extensions such as Facelets, ICEfaces, PrimeFaces, RichFaces and Tomahawk), 'plain' Java Server Pages (including extensions such as DisplayTag), Spring Web MVC, Struts, Swing (including extensions such as Beans Binding, JGoodies, MigLayout and SwingX), SWT and Vaadin. Metawidget can read domain object information from any combination of supported back-end technologies. This support includes: annotations, Bean Validation (JSR 303), Commons JEXL, Commons Validator, Groovy, Hibernate, Hibernate Validator, Jackson, JavaBeans, Java Persistence Architecture (JPA), Javassist, JBoss Forge, JBoss jBPM, JSON, JSON Schema, OVal, REST, Scala, Seam and the Swing AppFramework.

Note It is not a goal of Metawidget that all widgets look the same on every front-end framework, or that all back- end technologies conform to some 'lowest common denominator': every technology has different features, and Metawidget takes full advantage of this.

The next chapter presents a tutorial that covers using Metawidget with a variety of front-ends and back-ends. Chapter 2 then follows with a more in-depth architectual overview. Chapters 3-8 explore each supported front-end and back-end technology in detail. Finally, chapters 9 and 10 offer general advice and troubleshooting.

Metawidget xii 1. Introduction to Metawidget

This chapter is an introductory tutorial for new users of Metawidget. Before you begin, you need to download the binary distribution from http://metawidget.org/download.php. If you are using a Java-based framework (including Android, and Java-based web frameworks such as GWT or Java Server Faces) you should follow Section 1.1, “Part 1 (Java version) - The First Metawidget Application”. If you are using a pure JavaScript-based framework (such as AngularJS or JQuery Mobile) you should follow Section 1.2, “Part 1 (JavaScript version) - The First Metawidget Application”.

1.1 Part 1 (Java version) - The First Metawidget Application

Part 1 starts with a simple Swing application and develops it in easy to understand steps. Metawidget supports many Java- based UI frameworks, not just Swing, but we start with Swing because it ships with Java SE and requires minimal setup. This tutorial should take around 20 minutes. We recommend you use your preferred Java development environment. If you use an Integrated Development Environment (IDE), you will need to start a new Java project and add metawidget- all.jar to it. Otherwise, you just need to ensure metawidget-all.jar is on your CLASSPATH.

1.1.1 The Object

Metawidget is an Object/User Interface Mapping tool (OIM), so first we need an object to map from - the O in OIM. Create a class in your project called Person with the following code:

package com.myapp;

public class Person { private String mName; private int mAge; private boolean mRetired;

public String getName() { return mName; } public void setName( String name ) { mName = name; }

public int getAge() { return mAge; } public void setAge( int age ) { mAge = age; }

public boolean isRetired() { return mRetired; } public void setRetired( boolean retired ) { mRetired = retired; } }

1.1.2 The Interface

Next we need a User Interface framework - the I in OIM. Create a class in your project called Main with the following code:

package com.myapp;

Metawidget 1 Introduction to Metawidget

import javax.swing.*; import org.metawidget.swing.*;

public class Main {

public static void main( String[] args ) { Person person = new Person();

SwingMetawidget metawidget = new SwingMetawidget(); metawidget.setToInspect( person );

JFrame frame = new JFrame( "Metawidget Tutorial" ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.getContentPane().add( metawidget ); frame.setSize( 400, 250 ); frame.setVisible( true ); } }

Note Many IDEs include visual UI builders for dragging and dropping widgets. Metawidget integrates with these tools and Metawidgets can be dragged and dropped like any other. As we shall see, however, Metawidget widgets automatically fill themselves with child widgets at runtime, saving significant development time.

1.1.3 The Output

If you're using an IDE, such as NetBeans, your project should look something like pictured in Figure 1.1.

Metawidget 2 Introduction to Metawidget

Figure 1.1. Metawidget tutorial in NetBeans IDE

Run the code. You should see the screen in Figure 1.2.

Figure 1.2. SwingMetawidget rendering of Person class

The SwingMetawidget has automatically populated itself with child widgets at runtime. It has chosen JSpinner, JTextField and JCheckBox widgets based on the types of the properties of the Person class. This is the First Goal Of Metawidget:

Metawidget 3 Introduction to Metawidget

First Goal Of Metawidget Metawidget creates UI widgets by inspecting existing architectures

By default, SwingMetawidget has laid out the JComponents using java.awt.GridBagLayout. Try resizing the window, and the JComponents will resize with it. If you've ever tried using java.awt.GridBagLayout yourself, either through code or a visual UI builder, you'll know how fiddly it can be. Having Metawidget do it for you is a real time-saver.

Clearly this is not a complete UI. There are no Save or Cancel buttons, for example, and the JComponents appear uncomfortably tight to the left, top and right edges of the JFrame. This is explained by the Second Goal Of Metawidget:

Second Goal Of Metawidget Metawidget does not try to 'own' the entire UI - it focuses on creating native sub-widgets for slotting into existing UIs

You slot Metawidget alongside your standard UI components, often combining several Metawidgets on the same screen. We'll see how this works later.

1.1.4 Ordering The Properties

Currently the name, age and retired properties are arranged alphabetically in the UI - their order does not match the way they are defined in the Person class. This is because property ordering information is not retained within Java class files (as per the Java Language Specification). To correct this, Metawidget needs to gather additional information. There are several ways to do this (i.e. you don't have to use annotations), but the simplest for now is to use the built-in Metawidget annotation @UiComesAfter.

Annotate the Person class as shown below (lines to add are highlighted):

package com.myapp;

import org.metawidget.inspector.annotation.*;

public class Person { private String mName; private int mAge; private boolean mRetired;

public String getName() { return mName; } public void setName( String name ) { mName = name; }

@UiComesAfter( "name" ) ❶ public int getAge() { return mAge; } public void setAge( int age ) { mAge = age; }

@UiComesAfter( "age" ) public boolean isRetired() { return mRetired; } public void setRetired( boolean retired ) { mRetired = retired; } }

❶ Annotations can also be applied to the private fields, such as mAge, but that requires a little extra configuration.

Run the code again. This time the properties appear in the correct order:

Metawidget 4 Introduction to Metawidget

Figure 1.3. Properties in correct order

1.1.5 Inspectors

Introducing new annotations to improve the UI is not really in the spirit of the First Goal Of Metawidget. We' much rather improve it by gathering information from existing sources. To demonstrate, we'll need an external source of metadata. Create a file called metawidget-metadata.xml in the same folder as your Main class:

To recognise the XML file, Metawidget needs to use a different Inspector. Metawidget comes with multiple Inspectors, each targeting different sources of information. Change the Main class to use an XmlInspector (lines to add are highlighted):

package com.myapp;

import javax.swing.*; import org.metawidget.inspector.xml.*; import org.metawidget.swing.*;

public class Main {

public static void main( String[] args ) { Person person = new Person();

SwingMetawidget metawidget = new SwingMetawidget(); XmlInspectorConfig config = new XmlInspectorConfig(); config.setInputStream( Main.class.getResourceAsStream( "metawidget-metadata.xml" )); metawidget.setInspector( new XmlInspector( config ) );

Metawidget 5 Introduction to Metawidget

metawidget.setToInspect( person );

JFrame frame = new JFrame( "Metawidget Tutorial" ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.getContentPane().add( metawidget ); frame.setSize( 400, 250 ); frame.setVisible( true ); } }

Then remove all annotations from the Person class:

package com.myapp;

public class Person { private String mName; private int mAge; private boolean mRetired;

public String getName() { return mName; } public void setName( String name ) { mName = name; }

public int getAge() { return mAge; } public void setAge( int age ) { mAge = age; }

public boolean isRetired() { return mRetired; } public void setRetired( boolean retired ) { mRetired = retired; } }

Run the code again. It does not yield the correct result - the properties appear in the correct order, but the JSpinner and JCheckBox are now JTextFields! What happened?

Figure 1.4. Correct property order, but wrong JComponents

Metawidget Inspectors are very targeted in what they inspect. XmlInspector looks for metadata from XML files - but it does not look for anything else, such as JavaBean property types. Before we explicitly specified an XmlInspector, Metawidget had been implictly using two Inspectors for us, called PropertyTypeInspector and MetawidgetAnnotationInspector.

Metawidget 6 Introduction to Metawidget

1.1.6 Combining Multiple Inspection Results

What we need is to combine the results of PropertyTypeInspector, MetawidgetAnnotationInspector and XmlInspector before returning them to SwingMetawidget. We do this using CompositeInspector:

package com.myapp;

import javax.swing.*; import org.metawidget.inspector.annotation.*; import org.metawidget.inspector.composite.*; import org.metawidget.inspector.propertytype.*; import org.metawidget.inspector.xml.*; import org.metawidget.swing.*;

public class Main {

public static void main( String[] args ) { Person person = new Person();

SwingMetawidget metawidget = new SwingMetawidget(); XmlInspectorConfig config = new XmlInspectorConfig(); config.setInputStream( Main.class.getResourceAsStream( "metawidget-metadata.xml" )); CompositeInspectorConfig inspectorConfig = new CompositeInspectorConfig().setInspectors( new XmlInspector( config ), new PropertyTypeInspector(), new MetawidgetAnnotationInspector() ); metawidget.setInspector( new CompositeInspector( inspectorConfig ) ); metawidget.setToInspect( person );

JFrame frame = new JFrame( "Metawidget Tutorial" ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.getContentPane().add( metawidget ); frame.setSize( 400, 250 ); frame.setVisible( true ); } }

Run the code again. This time properties appear both in the correct order and using the correct JComponent:

Figure 1.5. Using multiple inspectors

This idea of combining multiple Inspectors to inspect different characteristics of your existing architecture is very powerful. Metawidget comes with pre-written Inspectors for many different technologies - from JPA and Hibernate

Metawidget 7 Introduction to Metawidget

Validator annotations, to struts-config.xml configuration files, to Groovy and Scala properties. There is a lot of metadata already lurking in back-end systems - it just needs extracting. For example, JpaInspector understands this...

import javax.persistence.Column;

public class Person { @Column( nullable = false ) public String getName() { ... }; }

...denotes name is a required property (could be rendered with an asterisk after it in the UI). Equally, PropertyTypeInspector understands that...

public class Person { private String mName;

public String getName() { return mName; }

// No setter }

...signifies name is a read-only property (could be rendered as a label in the UI).

1.1.7 Controlling The Layout

There are several ways to control the layout of the components. To demonstrate, Try adding the following properties to the Person class:

package com.myapp;

import org.metawidget.inspector.annotation.*;

public class Person {

public enum Gender { Male, Female }

private String mName; private int mAge; private boolean mRetired; private Gender mGender; private String mNotes; private String mEmployer; private String mDepartment;

public String getName() { return mName; } public void setName( String name ) { mName = name; }

public int getAge() { return mAge; } public void setAge( int age ) { mAge = age; }

public boolean isRetired() { return mRetired; } public void setRetired( boolean retired ) { mRetired = retired; }

@UiComesAfter( "retired" ) ❶ public Gender getGender() { return mGender; } public void setGender( Gender gender ) { mGender = gender; }

Metawidget 8 Introduction to Metawidget

@UiComesAfter( "gender" ) @UiLarge public String getNotes() { return mNotes; } public void setNotes( String notes ) { mNotes = notes; }

@UiComesAfter( "notes" ) @UiSection( "Work" ) public String getEmployer() { return mEmployer; } public void setEmployer( String employer ) { mEmployer = employer; }

@UiComesAfter( "employer" ) public String getDepartment() { return mDepartment; } public void setDepartment( String department ) { mDepartment = department; } }

❶ We'll use annotations again for brevity. But such metadata could be inspected from any source, such as an XML file.

This code produces the screen in Figure 1.6. Annotations have been used to define section headings and 'large' properties (i.e. a JTextArea).

Figure 1.6. Additional properties and a section heading

Note For a list of all the annotations MetawidgetAnnotationInspector recognises, see Section 4.3.7, “MetawidgetAnnotationInspector”.

By default, SwingMetawidget lays out JComponents using org.metawidget.swing.layout.GridBagLayout. You can configure this layout, or swap it for a different layout, using SwingMetawidget.setMetawidgetLayout. Modify the code to use a GridBagLayout with 2 columns:

package com.myapp;

import javax.swing.*; import org.metawidget.inspector.annotation.*; import org.metawidget.inspector.composite.*; import org.metawidget.inspector.propertytype.*; import org.metawidget.inspector.xml.*; import org.metawidget.swing.*; import org.metawidget.swing.layout.*;

public class Main {

Metawidget 9 Introduction to Metawidget

public static void main( String[] args ) { Person person = new Person();

SwingMetawidget metawidget = new SwingMetawidget(); XmlInspectorConfig config = new XmlInspectorConfig(); config.setInputStream( Main.class.getResourceAsStream( "metawidget-metadata.xml" )); CompositeInspectorConfig inspectorConfig = new CompositeInspectorConfig().setInspectors( new XmlInspector( config ), new PropertyTypeInspector(), new MetawidgetAnnotationInspector() ); metawidget.setInspector( new CompositeInspector( inspectorConfig ) ); GridBagLayoutConfig nestedLayoutConfig = new GridBagLayoutConfig().setNumberOfColumns( 2 ); SeparatorLayoutDecoratorConfig layoutConfig = new SeparatorLayoutDecoratorConfig().setLayout( new org.metawidget.swing.layout.GridBagLayout( nestedLayoutConfig )); metawidget.setMetawidgetLayout( new SeparatorLayoutDecorator( layoutConfig )); metawidget.setToInspect( person );

JFrame frame = new JFrame( "Metawidget Tutorial" ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.getContentPane().add( metawidget ); frame.setSize( 400, 250 ); frame.setVisible( true ); } }

Run the code. The JComponents are now arranged across two columns:

Figure 1.7. A two-column layout

You may have noticed the GridBagLayout is nested inside a SeparatorLayoutDecorator. This is responsible for separating widgets in different sections using JSeparators. However there are other choices for separating widgets. Modify the code to use TabbedPaneLayoutDecorator instead:

package com.myapp;

import javax.swing.*; import org.metawidget.inspector.annotation.*; import org.metawidget.inspector.composite.*; import org.metawidget.inspector.propertytype.*; import org.metawidget.inspector.xml.*; import org.metawidget.swing.*; import org.metawidget.swing.layout.*;

Metawidget 10 Introduction to Metawidget

public class Main {

public static void main( String[] args ) { Person person = new Person();

SwingMetawidget metawidget = new SwingMetawidget(); XmlInspectorConfig config = new XmlInspectorConfig(); config.setInputStream( Main.class.getResourceAsStream( "metawidget-metadata.xml" )); CompositeInspectorConfig inspectorConfig = new CompositeInspectorConfig().setInspectors( new XmlInspector( config ), new PropertyTypeInspector(), new MetawidgetAnnotationInspector() ); metawidget.setInspector( new CompositeInspector( inspectorConfig ) ); GridBagLayoutConfig nestedLayoutConfig = new GridBagLayoutConfig().setNumberOfColumns( 2 ); TabbedPaneLayoutDecoratorConfig layoutConfig = new TabbedPaneLayoutDecoratorConfig().setLayout( new org.metawidget.swing.layout.GridBagLayout( nestedLayoutConfig )); metawidget.setMetawidgetLayout( new TabbedPaneLayoutDecorator( layoutConfig )); metawidget.setToInspect( person );

JFrame frame = new JFrame( "Metawidget Tutorial" ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.getContentPane().add( metawidget ); frame.setSize( 400, 250 ); frame.setVisible( true ); } }

Run the code. The section heading is now a JTabbedPane:

Figure 1.8. Two-column layout with a JTabbedPane

Again, if you've ever used java.awt.GridBagLayout by hand, you'll appreciate how much easier Metawidget makes it to apply consistent layouts across all screens of your application.

1.1.8 Controlling Widget Creation

There are several ways to control widget creation. One way is to drop child controls inside the SwingMetawidget. This approach works well both programmatically within code and within visual UI builders.

Modify the code to add a JComboBox to the Metawidget:

package com.myapp;

Metawidget 11 Introduction to Metawidget

import javax.swing.*; import org.metawidget.inspector.annotation.*; import org.metawidget.inspector.composite.*; import org.metawidget.inspector.propertytype.*; import org.metawidget.inspector.xml.*; import org.metawidget.swing.*; import org.metawidget.swing.layout.*;

public class Main {

public static void main( String[] args ) { Person person = new Person();

SwingMetawidget metawidget = new SwingMetawidget(); XmlInspectorConfig config = new XmlInspectorConfig(); config.setInputStream( Main.class.getResourceAsStream( "metawidget-metadata.xml" )); CompositeInspectorConfig inspectorConfig = new CompositeInspectorConfig().setInspectors( new XmlInspector( config ), new PropertyTypeInspector(), new MetawidgetAnnotationInspector() ); metawidget.setInspector( new CompositeInspector( inspectorConfig ) ); GridBagLayoutConfig nestedLayoutConfig = new GridBagLayoutConfig().setNumberOfColumns( 2 ); TabbedPaneLayoutDecoratorConfig layoutConfig = new TabbedPaneLayoutDecoratorConfig().setLayout( new org.metawidget.swing.layout.GridBagLayout( nestedLayoutConfig )); metawidget.setMetawidgetLayout( new TabbedPaneLayoutDecorator( layoutConfig )); metawidget.setToInspect( person ); JComboBox combo = new JComboBox(); combo.setName( "retired" ); metawidget.add( combo );

JFrame frame = new JFrame( "Metawidget Tutorial" ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.getContentPane().add( metawidget ); frame.setSize( 400, 250 ); frame.setVisible( true ); } }

Run the code. The JComboBox appears in place of the retired JCheckBox, because it has the same name (i.e. 'retired') as Metawidget would have given the JCheckbox:

Figure 1.9. The 'retired' property has been overridden

Metawidget 12 Introduction to Metawidget

Note The default algorithm looks for child controls with the same name, but you can plug in your own implementation if you need to. See Section 2.4.5, “OverriddenWidgetBuilder”.

To suppress a widget's creation entirely, simply supplying an empty JPanel named 'retired' will not work as Metawidget will still create an accompanying label in the left hand column. Instead, Metawidget includes special Stub widgets for this purpose:

package com.myapp;

import javax.swing.*; import org.metawidget.inspector.annotation.*; import org.metawidget.inspector.composite.*; import org.metawidget.inspector.propertytype.*; import org.metawidget.inspector.xml.*; import org.metawidget.swing.*;

public class Main {

public static void main( String[] args ) { Person person = new Person();

SwingMetawidget metawidget = new SwingMetawidget(); XmlInspectorConfig config = new XmlInspectorConfig(); config.setInputStream( Main.class.getResourceAsStream( "metawidget-metadata.xml" )); CompositeInspectorConfig inspectorConfig = new CompositeInspectorConfig().setInspectors( new XmlInspector( config ), new PropertyTypeInspector(), new MetawidgetAnnotationInspector() ); metawidget.setInspector( new CompositeInspector( inspectorConfig ) ); GridBagLayoutConfig nestedLayoutConfig = new GridBagLayoutConfig().setNumberOfColumns( 2 ); TabbedPaneLayoutDecoratorConfig layoutConfig = new TabbedPaneLayoutDecoratorConfig().setLayout( new org.metawidget.swing.layout.GridBagLayout( nestedLayoutConfig )); metawidget.setMetawidgetLayout( new TabbedPaneLayoutDecorator( layoutConfig )); metawidget.setToInspect( person ); metawidget.add( new Stub( "retired" ));

JFrame frame = new JFrame( "Metawidget Tutorial" ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.getContentPane().add( metawidget ); frame.setSize( 400, 250 ); frame.setVisible( true ); } }

Run the code. The retired property and its label will not appear:

Metawidget 13 Introduction to Metawidget

Figure 1.10. The 'retired' property has been suppressed Another way is to use a @UiHidden annotation on the business class:

package com.myapp;

import org.metawidget.inspector.annotation.*;

public class Person {

public enum Gender { Male, Female }

private String mName; private int mAge; private boolean mRetired; private Gender mGender; private String mNotes; private String mEmployer; private String mDepartment;

public String getName() { return mName; } public void setName( String name ) { mName = name; }

public int getAge() { return mAge; } public void setAge( int age ) { mAge = age; }

@UiHidden public boolean isRetired() { return mRetired; } public void setRetired( boolean retired ) { mRetired = retired; }

@UiComesAfter( "retired" ) public Gender getGender() { return mGender; } public void setGender( Gender gender ) { mGender = gender; }

@UiComesAfter( "gender" ) @UiLarge public String getNotes() { return mNotes; } public void setNotes( String notes ) { mNotes = notes; }

@UiComesAfter( "notes" ) @UiSection( "Work" ) public String getEmployer() { return mEmployer; } public void setEmployer( String employer ) { mEmployer = employer; }

Metawidget 14 Introduction to Metawidget

@UiComesAfter( "employer" ) public String getDepartment() { return mDepartment; } public void setDepartment( String department ) { mDepartment = department; } }

In both cases, org.metawidget.swing.layout.GridBagLayout is smart enough to always give large JComponents like notes the full width of the JFrame.

1.1.9 Configuring Metawidget Externally

So far we have been instantiating our Inspectors and Layouts in Java code. Whilst this approach is possible for all Inspectors and Layouts, many UI frameworks employ visual UI builders or intermediate languages (such as JSP) that make getting to the Java code cumbersome (i.e. you have to derive custom widgets).

As an alternative, Metawidget supports external XML configuration. Create a file called metawidget.xml in the same folder as your Main class:

com/myapp/metawidget-metadata.xml 2

Now update your Main class to use this file:

package com.myapp;

Metawidget 15 Introduction to Metawidget

import javax.swing.*; import org.metawidget.swing.*;

public class Main {

public static void main( String[] args ) { Person person = new Person();

SwingMetawidget metawidget = new SwingMetawidget(); metawidget.setConfig( "com/myapp/metawidget.xml" ); metawidget.setToInspect( person );

JFrame frame = new JFrame( "Metawidget Tutorial" ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.getContentPane().add( metawidget ); frame.setSize( 400, 250 ); frame.setVisible( true ); } }

Run the code. The output is the same as before, but this time we are configuring our Metawidget via external XML.

Visual UI builders can call SwingMetawidget.setConfig from the builder, with no coding required. Other UI frameworks (e.g. JSPs, Android) have similar 'code free' approaches (e.g. setting an attribute on a JSP tag, setting an attribute in an Android layout file) to setting the XML file. We shall look at these sorts of frameworks in Part 2. Now skip to Section 1.3, “Part 2 - The Address Book Application”

1.2 Part 1 (JavaScript version) - The First Metawidget Application

Part 1 starts with a pure JavaScript application and develops it in easy to understand steps. Metawidget supports many JavaScript-based UI frameworks, but we start with pure JavaScript because it requires minimal setup. This tutorial should take around 20 minutes. We recommend you use your preferred JavaScript development environment.

1.2.1 The Object

Metawidget is an Object/User Interface Mapping tool (OIM), so first we need an object to map from - the O in OIM. Create a new HTML page in your project called index.html with the following code:

Metawidget 16 Introduction to Metawidget

1.2.2 The Interface

Next we need a User Interface - the I in OIM. Add the following code to your HTML page (lines to add are highlighted):

You will also need to copy js/lib/metawidget/core/metawidget-core.min.js from the Metawidget binary distribution into your project.

1.2.3 The Output

Open your HTML page in your browser. You should see the page in Figure 1.11.

Figure 1.11. Metawidget rendering of person object

Metawidget has automatically populated the div with child widgets at runtime. It has chosen text, number and checkbox inputs based on the types of the properties of the person object. This is the First Goal Of Metawidget:

First Goal Of Metawidget Metawidget creates UI widgets by inspecting existing architectures

Metawidget 17 Introduction to Metawidget

By default, Metawidget has laid out the HTML input components using a table. This may not be your preferred approach, and either way this is clearly not a complete UI. There are no Save or Cancel buttons, for example. This is explained by the Second Goal Of Metawidget:

Second Goal Of Metawidget Metawidget does not try to 'own' the entire UI - it focuses on creating native sub-widgets for slotting into existing UIs

You slot Metawidget alongside your standard UI components, often combining several Metawidgets on the same screen. We'll see how this works later.

1.2.4 Inspectors

Suppose we want the name property to be a required field. Such metadata cannot be represented using standard JavaScript Object Notation (JSON) so Metawidget needs a way to gather the additional information. There are several ways to do this, but the simplest for now is to add a custom Inspector (text to add is highlighted) that returns a JSON Schema:

var mw = new metawidget.Metawidget( document.getElementById( 'metawidget' ), {

inspector: function( toInspect, type, names ) {

return { properties: { name: { type: "string", required: true } } }; } } );

Refresh the page in your browser. It does not yield the correct result - the name property appears as a required field, but the age and retired properties have disappeared! What happened?

Figure 1.12. Name is required, but other properties are missing

Metawidget Inspectors are very targeted in what they inspect. Our custom Inspector returns information about name being a required field - but it does not return anything else, such as properties from our JSON object. Before we explicitly specified a new Inspector, Metawidget had been implictly using another Inspector for us, called PropertyTypeInspector.

Metawidget 18 Introduction to Metawidget

1.2.5 Combining Multiple Inspection Results

What we need is to combine the results of PropertyTypeInspector and our custom Inspector before returning them to the Metawidget. We do this using CompositeInspector:

var mw = new metawidget.Metawidget( document.getElementById( 'metawidget' ), {

inspector: new metawidget.inspector.CompositeInspector( [ new metawidget.inspector.PropertyTypeInspector(), function( toInspect, type, names ) {

return { properties: { name: { type: "string", ❶ required: true } } }; } } ] ) } );

❶ type can now be removed from our custom Inspector, as it will be looked up by PropertyTypeInspector.

Refresh the page again. This time all properties appear and name is marked as a required field.

Figure 1.13. Using multiple inspectors

This idea of combining multiple Inspectors to inspect different characteristics of your existing architecture is very powerful. Metawidget comes with pre-written Inspectors for many different technologies and makes it easy to add your own, such as for REST services (see Section 5.5, “RestInspectionResultProcessor”). There is a lot of metadata already lurking in back-end systems - it just needs extracting.

1.2.6 Controlling The Layout

There are several ways to control the layout of the components. To demonstrate, Try adding the following metadata for the person object:

function( toInspect, type, names ) {

return { properties: name: {

Metawidget 19 Introduction to Metawidget

required: true }, notes: { type: "string", large: true ❶ }, employer: { type: "string", section: "Work" }, department: { type: "string" } } }; }

❶ Metawidget supports a superset of JSON Schema (v3). Metadata such as large and section are not part of the JSON Schema specification, but are useful for UIs. This produces the screen in Figure 1.14. Metadata has been added to define section headings and 'large' properties (i.e. a textarea).

Figure 1.14. Additional properties and a section heading

By default, Metawidget lays out components using an HTML table. You can configure this layout or swap it for a different one. Modify the code as follows:

var mw = new metawidget.Metawidget( document.getElementById( 'metawidget' ), {

inspector: new metawidget.inspector.CompositeInspector( [ new metawidget.inspector.PropertyTypeInspector(), function( toInspect, type, names ) {

return { properties: name: { required: true }, notes: { type: "string", large: true }, employer: { type: "string", section: "Work" },

Metawidget 20 Introduction to Metawidget

department: { type: "string" } } }; } ] ),

layout: new metawidget.layout.HeadingTagLayoutDecorator( new metawidget.layout.TableLayout( { numberOfColumns: 2 } )) } );

Refresh the page. The components are now arranged across two columns:

Figure 1.15. A two-column layout

Note Your browser may not have stretched the textarea across the full width of the table, even though the colspan has been set to 4. You can add into the head to confirm this visually

You may have noticed the TableLayout is nested inside a HeadingTagLayoutDecorator. This is responsible for separating widgets in different sections using h1 tags. However there are other choices for separating widgets. Modify the code to use a JQuery UI-based TabLayoutDecorator instead:

You will also need to copy js/lib/metawidget/jquery-ui/metawidget-jqueryui.min.js from the Metawidget binary distribution into your project. Refresh the page. The section heading is now a tab:

Figure 1.16. Two-column layout with a JQuery UI tab

Metawidget makes it easy to apply consistent layouts across all pages of your application.

1.2.7 Controlling Widget Creation

There are several ways to control widget creation. One way is to add child controls inside the Metawidget:

Metawidget 22 Introduction to Metawidget

Refresh the page. The select box appears in place of the checkbox, because it has the same id (i.e. 'retired') as Metawidget would have given the checkbox. Notice Metawidget has still bound its value:

Figure 1.17. The 'retired' property has been overridden

Note The default algorithm looks for child controls with the same id, but you can plug in your own implementation if you need to. See Section 2.4.5, “OverriddenWidgetBuilder”.

To suppress a widget's creation entirely, simply supplying an empty div with id 'retired' will not work as Metawidget will still create an accompanying label in the left hand column. Instead, Metawidget includes special stub widgets for this purpose:

Refresh the page. The retired property and its label will not appear:

Figure 1.18. The 'retired' property has been suppressed

Metawidget 23 Introduction to Metawidget

Another way is to add a hidden attribute to the metadata:

function( toInspect, type, names ) { return { properties: name: { required: true }, retired: { hidden: true }, notes: { type: "string", large: true }, employer: { type: "string", section: "Work" }, department: { type: "string" } } }; }

In both cases, metawidget.layout.TableLayout is smart enough to always give large components like textarea the full colspan of the table.

1.3 Part 2 - The Address Book Application

Part 2 explores a more substantial application, and shows how Metawidget can be used to map the same back-end to multiple front-ends. We will develop an Address Book application with desktop-based, Web-based and mobile-based UIs. This tutorial should take around 45 minutes. Before you begin, you will need to download the examples distribution from http://metawidget.org/download.php. This includes pre-built example applications with full source code. To save time, we will not focus on any one front-end framework in detail. For detailed framework-specific instructions, please see Chapter 3, Metawidgets.

1.3.1 Desktop Address Book

The Desktop Address Book is essentially a larger version of the application developed in Part 1 - it just has more domain objects and more widgets.

Note If you are only interested in the JavaScript-based Metawidget, you should skip straight to Section 1.3.2, “Web Address Book”.

The application is pre-built for you in examples/swing/addressbook-swing.jar. This is a self-executing JAR. For convenience, it has MANIFEST.MF dependencies hard-coded into it, so it's best not to move it to a different folder (if you do, you'll need to manually fix up your CLASSPATH).

Metawidget 24 Introduction to Metawidget

Note There is also an SWT version of the Address Book sample in examples/swt/addressbook-swt.jar. You can mostly replace references to 'Swing' in this section with 'SWT' and follow along using SWT if preferred.

Run the code by navigating to the examples/swing folder and typing:

java -jar addressbook-swing.jar

The opening screen displays a search filter (at the top) and lists existing Address Book entries (at the bottom) as in Figure 1.19 (Swing version) and Figure 1.20 (SWT version).

Figure 1.19. Swing Desktop Address Book opening screen

Figure 1.20. SWT Desktop Address Book opening screen

The three search filter fields (Firstname, Surname and Type) are created by SwingMetawidget based on the ContactSearch business class. This includes populating the Type dropdown based on the ContactType enum. The Search, Add Personal Contact and Add Business Contact buttons are created by SwingMetawidget based on annotated action methods in the ContactDialog class. The rest of the screen - including the images, background and

Metawidget 25 Introduction to Metawidget layout - are managed by regular Swing code and are not controlled by Metawidget: Metawidget does not try to 'own' the entire UI.

Note Full source code for all the examples, such as the code for the ContactSearch, ContactType and ContactDialog classes, is included under the src/examples folder of the examples distribution.

Click Add Personal Contact. The screen displays a form for filling out Personal Contact information as in Figure 1.21.

Figure 1.21. Desktop Address Book 'Add Personal Contact' screen

All the form fields are created by SwingMetawidget based on the PersonalContact business class. This class is itself derived from the Contact business class. It includes some Metawidget annotations for dropdown values and section headings.

Note the code only has one JDialog class (ContactDialog), but is capable of supporting both PersonalContact and BusinessContact UIs. The fields in the UI change depending on the object passed to ContactDialog at runtime. This is the Third Goal Of Metawidget:

Third Goal Of Metawidget Metawidget can perform inspection at runtime, detecting types and subtypes dynamically

The Address property is created as a nested SwingMetawidget. This is the default behaviour when Metawidget encounters datatypes it does not know how to represent using any other UI widget. The Communications property has been overridden with a manually specified JTable.

In addition, JTable.setCellEditor uses SwingMetawidget to render single JComponents as CellEditors. This includes automatically populating dropdown values.

Read-Only Mode

The Desktop Address Book uses Metawidget's setReadOnly(true) method to display read-only screens. Return to the main screen, and double-click on an existing contact (such as Homer Simpson). The same ContactDialog is used, but this time all the widgets are read-only labels as in Figure 1.22.

Metawidget 26 Introduction to Metawidget

Figure 1.22. Desktop Address Book read-only mode

Click Edit. The labels are transformed into editable widgets by using Metawidget's setReadOnly(false), as in Figure 1.23.

Figure 1.23. Desktop Address Book edit mode

Binding

The data from the PersonalContact object is automatically inserted into the JComponents. It is also automatically saved back when clicking Save.

Swing does not define a JComponent to Object mapping mechanism, so by default SwingMetawidget only supplies setValue and getValue methods for manually fetching values. This situation is no worse than a normal Swing application, but Metawidget can do better.

SwingMetawidget directly supports third-party binding alternatives such as Apache BeanUtils and Beans Binding (JSR 295) via SwingMetawidget.addWidgetProcessor. These binding implementations automatically map JComponent

Metawidget 27 Introduction to Metawidget values to Object values, including performing the necessary conversions, further reducing the amount of boilerplate code required.

SwtMetawidget does something similar using org.eclipse.core.databinding.Binding.

Localization

All text within the application has been localized to the org.metawidget.example.shared.addressbook.resource.Resources resource bundle. Text created manually (such as the buttons) uses typical Swing localization code (e.g. bundle.getString). Text created by SwingMetawidget uses SwingMetawidget.setBundle, which internally defers to Swing's bundle.getString. Localization is very easy with Metawidget. For property names, if no resource bundle is supplied, Metawidget uses an 'uncamel-cased' version of the name (e.g. dateOfBirth becomes Date Of Birth). If a bundle is supplied, Metawidget uses the property name as the bundle key. For section headings, if a bundle is supplied, Metawidget uses a 'camel-cased' version of the headings as the key. This means developers can initially build their UIs without worrying about resource bundles, then turn on localization support later.

1.3.2 Web Address Book

As there are a large number of frameworks to choose from, this example comes written in nine of the most popular: AngularJS, Google Web Toolkit (GWT), Java Server Faces (JSF) 1.x and 2.x (using Facelets), Java Server Pages (JSP), JQuery Mobile, Spring Web MVC, Struts, Vaadin and Web Components. We recommend you follow along using the one most relevant to you. Web-based applications are inherently more difficult to setup and run than desktop-based applications because they require a server (this is true even for the pure client-side, JavaScript-based versions of the Address Book as they make REST calls). For this tutorial we recommend using Apache Tomcat as it is one of the easier containers to get running (the examples are tested against Tomcat 6.0.29). Tomcat can be downloaded from http://tomcat.apache.org.

Take a fresh install of Tomcat. The Address Book application is pre-built for you in either examples/js// addressbook, examples/js/jquery/mobile/addressbook, examples/js/webcomponent/addressbook, examples/java/faces/addressbook-faces.war, examples/java/gwt/addressbook-gwt.war, examples/ java/jsp/addressbook-jsp.war, examples/java/spring/addressbook-spring.war, examples/java/ struts/addressbook-struts.war or examples/java/vaadin/addressbook-struts.war. Alternatively you can build it yourself by changing to the src/examples folder and typing:

mvn -pl org.metawidget.examples.faces:addressbook-faces -am integration-test

(replacing faces with gwt, jsp, spring, struts or vaadin as appropriate).

Note For most web environments, deploying Metawidget is as simple as adding metawidget-all.jar to WEB- INF/lib or metawidget-core.min.js to lib/metawidget. For GWT, you'll also need to include metawidget-all.jar and additional/gwt/metawidget-all-sources.jar in the CLASSPATH during your GWTCompiler step.

Copy the application into Tomcat's webapps folder, start Tomcat, and open a Web browser to http://localhost:8080/ addressbook-faces. The home page displays a search filter (at the top) and lists existing Address Book entries (at the bottom) as in Figure 1.24.

Metawidget 28 Introduction to Metawidget

Figure 1.24. Web Address Book opening screen

Figure 1.25. Web Address Book opening screen (JQuery Mobile version)

As with the Desktop Address Book, the search filter fields are created by Metawidget (this time AngularMetawidget, UIMetawidget, GwtMetawidget, HtmlMetawidgetTag, JQueryMobileMetawidget, SpringMetawidgetTag, StrutsMetawidgetTag or VaadinMetawidget) based on the ContactSearch business class:

...

Again, this includes populating the Type dropdown and localizing the text. The Search, Add Personal Contact and Add Business Contact buttons are either manually specified in the JSP page (for GWT, Spring and Struts) or created by UIMetawidget based on annotated methods in the ContactBean (for JSF).

Note As with the Desktop Address Book, full source code for the examples can be found under src/examples.

Metawidget 29 Introduction to Metawidget

The look of the Web page relies entirely on HTML and CSS technologies. The CSS classes to use are configured in metawidget.xml (or services.js for AngularJS):

tableStyleClass table-form columnClasses table-label-column,table-component-column,table-required-column ...

Only the layout of 'one column for the label, one column for the widget' is dictated by Metawidget, and that is again pluggable and configurable.

Click Add Personal Contact. The page displays a form for filling out Personal Contact information as in Figure 1.26.

Figure 1.26. Web Address Book 'Add Personal Contact' screen

All the form fields are created by Metawidget based on the PersonalContact business class. The section headings are the same, but have this time been rendered as HTML.

The Address property is a nested Metawidget. The Communications property has been overridden in the page with a manually specified table. UIMetawidget understands a manually-specified widget to override an automatic one if it has the same value binding as the automatic widget would have (AngularMetawidget, GwtMetawidget, SpringMetawidgetTag, StrutsMetawidgetTag and VaadinMetawidget do something similar):

... ...

Metawidget 30 Introduction to Metawidget

...

JSF has built-in support for executing actions on table rows. In order to use it, however, the Set returned by Contact.getCommunications must be wrapped into a DataModel. This is handled by ContactController.getCurrentCommunications, but this presents a problem: the mapping for the HtmlDataTable must be #{contact.currentCommunications}, but the mapping required to override UIMetawidget's automatic widget creation is #{contact.current.communications}.

UIMetawidget supplies UIStub for these situations. Stubs have a binding, but do nothing with it and render nothing. They can be used either to suppress widget creation entirely (a stub with an empty body) or to replace the automatic widget creation with one or more other widgets with different bindings:

... ... ...

JSP, Spring, Struts lack some component-based features found in Swing and JSF. Specifically, whilst it is possible for tags to reference their parent (using TagSupport.findAncestorWithClass), they have no way to interrogate their children. Therefore, it is not possible to directly support arbitrary child tags within HtmlMetawidget, SpringMetawidgetTag and StrutsMetawidgetTag.

Instead, we wrap the overridden Communications property in Metawidget's Stub tag. Metawidget and its Stub tags have explicit support for co-ordinating the overriding of widget creation:

...

...
...

GwtMetawidget uses stubs around GWT widgets like FlexTable, but can use the overriding widget directly if it supports the HasName interface (e.g. TextBox, CheckBox, etc) and has a name matching the name of the domain object property.

Mixing Metawidgets

The section is specific to Spring/Struts.

Within the Communications table, implementing Add Communication calls for a design decision. Struts does not support multiple ActionForms per Action, so we are unable to combine PersonalContactForm with a CommunicationForm (as we did in the JSF). Spring has a similar limitation of not supporting multiple commandNames per form. Instead, we need to either:

• add properties from Communication to PersonalContactForm, and ignore them when saving the PersonalContact; or

Metawidget 31 Introduction to Metawidget

• output plain HTML tags (i.e. independent of Spring and Struts) and handle them manually

Both approaches would be valid. For this tutorial, we choose the latter as it allows us to introduce HtmlMetawidget (a Metawidget for plain HTML/JSP webapps that don't use Struts or Spring) and demonstrate mixing two Metawidgets on the same page:

...

... ...
...

The two different tag prefixes m: and mh: denote different tag libraries. HtmlMetawidget is very similiar to StrutsMetawidgetTag, but has to use jsp:useBean to manually instantiate the bean (rather than letting Struts do it). Within metawidget.xml, the default Layout for HtmlMetawidget has been set to org.metawidget.jsp.tagext.layout.SimpleLayout (i.e. a plain layout, without a label column)

Expression Based Lookups

This section does not apply to GWT.

In the Desktop Address Book, the title dropdown was populated by a static lookup attribute in metawidget- metadata.xml. JSP and JSF-based technologies can do better, because they have a built-in scope-based component model and Expression Language.

Contact.getTitle is annotated using @UiFacesLookup and @UiSpringLookup (and ContactForm.getTitle is annotated using @UiStrutsLookup). These are used at runtime to create dynamic lookups. These annotations, unlike the ones we have used so far, are UI-framework specific so you may prefer to declare them in metawidget-metadata.xml. Before doing so, however, you should understand we are still not introducing runtime dependencies into our business classes: an important feature of annotations is they 'fall away gracefully' if their implementing class is not found. Annotations never throw ClassDefNotFoundError.

Alternate Widget Libraries (JSF 1.x)

This section is specific to JSF 1.x.

Metawidget factors all widget creation into WidgetBuilders. Like Inspectors, multiple WidgetBuilders can be combined using a CompositeWidgetBuilder to support third-party component libraries. In this section we will override Metawidget's default and introduce a RichFacesWidgetBuilder alongside the standard JSF HtmlWidgetBuilder.

Go into Tomcat's webapps/addressbook-faces folder (the exploded WAR) and edit WEB-INF/metawidget.xml:

Metawidget 32 Introduction to Metawidget

version="1.0" xsi:schemaLocation="http://metawidget.org http://metawidget.org/xsd/metawidget-1.0.xsd">

... section-heading

Now restart Tomcat, refresh your Web browser and click on Homer Simpson. Notice how the Date of Birth field for Personal Contacts is now a RichFaces date picker widget, and the Number of Staff field for Business Contacts is a RichFaces slider widget.

Going futher, Metawidget's pluggable layouts make it easy to support third-party layout components. Edit WEB-INF/ metawidget.xml again:

Metawidget 33 Introduction to Metawidget

...

Restart Tomcat, refresh your Web browser and click on Homer Simpson again. Notice how the Contact Details and Other sections are laid out as tabs within a RichFaces TabPanel as in Figure 1.27.

Metawidget 34 Introduction to Metawidget

Figure 1.27. Web Address Book using JBoss RichFaces

This demonstrates how easy it is to leverage widget libraries with Metawidget (this example cheats a bit, as we've pre-added the RichFaces JARs into WEB-INF/lib and some lines into web.xml, but you get the idea).

Alternate Widget Libraries (JSF 2.x)

This section is specific to JSF 2.x.

As in the previous section, we can override Metawidget's default and introduce an alternate WidgetBuilder alongside the standard JSF HtmlWidgetBuilder. This time we will demonstrate using PrimeFaces.

Go into Tomcat's webapps/addressbook-faces2 folder (the exploded WAR) and edit WEB-INF/metawidget.xml:

...

Metawidget 35 Introduction to Metawidget

Restart Tomcat, refresh your Web browser and click on Charles Montgomery Burns. Notice how the Contact Details and Other sections are laid out as tabs within a PrimeFaces TabView and the Number of Staff field is a PrimeFaces Slider. See Figure 1.28.

Figure 1.28. Web Address Book using PrimeFaces

This demonstrates how easy it is to leverage widget libraries with Metawidget (this example cheats a bit, as we've pre-added the PrimeFaces JARs into WEB-INF/lib and some lines into web.xml, but you get the idea).

1.3.3 Mobile Address Book

For the Mobile Address Book we use the Android platform. Like Web-based applications, mobile applications require a container to run. If you have a physical Android device you can install the Mobile Address Book by downloading and opening http://metawidget.org/examples/android/addressbook-android.apk or scanning this QR Code:

Metawidget 36 Introduction to Metawidget

Figure 1.29. Mobile Address Book APK URL

Note The Android Address Book is a native mobile application. For an example of an HTML 5 hybrid mobile application see the JQuery Mobile Address Book in the previous section.

Alternatively download the Android SDK from http://code.google.com/android/download.html (the examples are tested against Android 1.1). Then change to the installation directory (usually defined by ANDROID_HOME) and run the emulator by opening a command prompt and typing:

tools\android create avd -n my_avd -t 1

Replacing -t 1 with the Android version you're using (e.g. -t 2 for 1.5, -t 3 for 1.6, -t 4 for 2.0). Android 1.1 doesn't use AVDs, so you can skip this step. Next type:

tools\emulator -avd my_avd

The emulator may take a little while to start. Once finished, it will display the phone's desktop. The Address Book APK is pre-built for you in examples/android/addressbook-android.apk. Alternatively you can build it yourself by changing to the src/examples folder and typing:

mvn -pl org.metawidget.examples.android:addressbook-android -am integration-test

Next, open a second command prompt, change to the Android installation directory and type:

platform-tools\adb install \examples\android\addressbook-android.apk

This deploys the APK into the emulator. To run it, click the emulator's Menu button and then choose the Address Book application. The emulator displays a search filter (at the top) and lists existing Address Book entries (at the bottom) as in Figure 1.30.

Metawidget 37 Introduction to Metawidget

Figure 1.30. Mobile Address Book opening screen

As with the Desktop and Web Address Books, the three search filter fields are created by Metawidget (this time AndroidMetawidget) based on the ContactSearch business class. Again, this includes populating the Type dropdown.

Note As with the Desktop Address Book, full source code for the examples can be found under src/examples. To open it in Eclipse we recommend installing Maven Integration for Android Development Tools.

The look of the screen relies entirely on Android XML layout files, styles and themes. Only the 'one column for the label, one column for the widget' layout is dictated by Metawidget, and that is pluggable and configurable.

Choose Add Personal from the Android menu. The page displays a form for filling out Personal Contact information as in Figure 1.31.

Metawidget 38 Introduction to Metawidget

Figure 1.31. Mobile Address Book 'Add Personal Contact' screen

UIs in Android are typically defined using XML layout files, though they can also be built programmatically. AndroidMetawidget supports both approaches. For example, the Personal Contact screen is defined in contact.xml, and contains a Metawidget defined in much the same way as in JSP (including configuring section style and overriding widget creation):