Monday, June 25, 2012

Multi value fields and Beans in XPages

I had an issue with multi value fields bound to bean fields in an XPages I worked on.

I got this error message on refresh:
java.lang.IllegalArgumentException: argument type mismatch

The issue turned out to be a somewhat inconsistent underlying API. When the field is empty, or has single value, it tries to set a string. When there are multiple values, it tries to set a list.

To work around the issue, have the getter return an Object, and the setter accept an object.
E.g.

public Object getInputMulti() {
 return this.inputMulti;
}
...
@SuppressWarnings( "unchecked" )
public void setInputMulti( Object inputMulti ) {
 if( inputMulti == null ){
  this.inputMulti = null;
 }
 
 if( inputMulti instanceof String ) {
  Vector inputNameList = new Vector();
  inputNameList.add( (String) inputMulti );
  this.inputMulti = inputNameList;  
 }
 if( inputMulti instanceof List ) {
  this.inputMulti = (Vector) inputMulti;
 }
}

You can have the translation for the setter be done in a utility method. E.g.
@SuppressWarnings("unchecked")
public static Vector translateToVector( Object object ){
 if( object instanceof String ){
  Vector list = new Vector();
  list.add( object );
  return list;
 }
 
 if( object instanceof List ){
  return (Vector)object;
 }
 
 return null;
}

Then, for the setter:

@SuppressWarnings( "unchecked" )
public void setInputMulti( Object inputMulti ) {
  this.inputMulti = UtilityClass.translateToVector( inputMulti );
}

Example of multi value fields: Checkbox group, multi value fields (fields with multipleSeparator), list boxes.

Friday, June 22, 2012

Update for Enhanced Messages Control - Show "system" messages

In response to this question on the XPages Forums, I've updated the source code for my Enhanced Messages Control, so that it also shows messages not bound to controls.

The "system" messages are show above the messages from components.

Friday, June 15, 2012

Recommended tutorials for doing asynchronous processing in beans

Asynchronous processing in Java applications – leveraging those multi-cores

Using asynchronous mechanisms in Java and JavaScript for improving the user experience

Friday, June 8, 2012

Update for Enhanced Messages - Now in page order

I added a small snippet of code that sorts the messages in the order that the components are in the page.

I only had a simple page to test on, but in theory it should work for large pages with complex structure.

Original post with source code for custom control

Thursday, May 31, 2012

Improving performance in Domino Designer when developing XPages

If the XPage has a view data source/the view name is a static value, it looks like Domino Designer is constantly polling the view for column info/etc.

If you are done dragging and dropping columns from the view to the view panel/etc. Go into source mode and compute the viewName.

Before

<xp:dominoView var="view1" viewName="MyView" />

After

<xp:dominoView var="view1" viewName="${javascript:return 'MyView'}" />

When the view name is computed, Domino Designer can't determine what view it should check -> No more lag.

I haven't tested this with Document Data source, but you might get a performance boost if you compute the formName as well, as Domino Designer won't have to check the fields for drag/drop.

Optimally I would wish the Designer team implemented a refresh fields/columns button for the data pane.

Share and enjoy!

Tuesday, May 29, 2012

Using Java reflection and Domino form to auto populate beans

>> Download DemoApp

Due to a lot of positive posts about using beans/MVC pattern for developing XPages apps, I've started writing more Java and less SSJS. I really like the performance improvements/stricter structure of code.

In one of my recent apps, I wrote a Model class for each of the forms in the app. The class has fields for all the form fields. Whilst writing the app, I thought about using Java reflection/Domino Form to auto populate the class instance. Java reflection lets you fetch methods from classes using their name (as a String). The Form class contains methods that lets you fetch all the declared field names in the form.

A couple of advantages to using auto population of fields is less code to maintain (~less bugs), and "auto discovery" of typos in either field names or getters/setters. If you call a field firs_name (typo), and write getters/setters for first_name, using the methodology I use, the code would crash, and you would instantly be aware of some error. If you use some kind of logging, you could look at the stack trace to determine what failed.

A couple of disadvantages. Using reflection/fetching field information adds a slight performance penalty. I don't notice any slowness, but it's something to be aware of if you're aiming for light speed/serving the entire Republic of China on one server. :)

In most of my apps, I use underscores to separate "words" in my field names. To make this work with reflection I convert the underscore field names to ProperCase, and prepend get/set.

E.g.
Field: first_name
ProperCased: FirstName
Getter: getFirstName
Setter: setFirstName

In the attached DemoApp, I have a helper class that deals with the most common field types. It has two methods:
setObjectFieldsFromDocument( String form, Object object, DominoDocument doc )
setDocumentFieldsFromObject( String form, Object object, DominoDocument doc ).

The first parameter is the name of the form that you want to use as "schema" for the population of the instance fields. The second parameter is the Java instance. The third parameter is a Document wrapped in a simple helper class.

The demoapp has a XPage that uses a controller bean (PersonController) to handle interaction with the model (Person). It's bound to view scope. When the XPage is loaded, it checks for a parameter (id). If id is available, the controller uses setObjectFieldsFromDocument to populate the model. When save is called, the controller uses setDocumentFieldsFromObject to update the underlying Notes Document with values from the model.

If this sounds interesting. Download the Demoapp, look at the Person XPage for the data binding, and use Package Explorer to take a look at underlying java code.

I'll just add the source code for the Person model class, in case some of you fear that everything in Java is complex

package com.dontpanic82;

import java.io.Serializable;
import java.util.Date;

public class Person implements Serializable {
 private static final long serialVersionUID = 1L;

 public static final String FORM = "Person";

 private String id;
 private String firstName;
 private String lastName;
 private String email;
 private String homepage;
 private Double age;
 private Date birthdate;

 public Person() {
 }

 public Double getAge() {
  return age;
 }

 public Date getBirthdate() {
  return birthdate;
 }

 public String getEmail() {
  return email;
 }

 public String getFirstName() {
  return firstName;
 }

 public String getHomepage() {
  return homepage;
 }

 public String getId() {
  return id;
 }

 public String getLastName() {
  return lastName;
 }

 public void setAge( Double age ) {
  this.age = age;
 }

 public void setBirthdate( Date birthdate ) {
  this.birthdate = birthdate;
 }

 public void setEmail( String email ) {
  this.email = email;
 }

 public void setFirstName( String firstName ) {
  this.firstName = firstName;
 }
 
 public void setHomepage( String homepage ) {
  this.homepage = homepage;
 }

 public void setId( String id ) {
  this.id = id;
 }

 public void setLastName( String lastName ) {
  this.lastName = lastName;
 }

}