VW InsyncCodeGenerationAndModelingSupportForInterfacesAbstractAndGenericTypes

Support for code generation and modeling of Interfaces, Abstract Classes, Generic Type Beans in Insync

Meeting Details

Meeting Date : April 20th 2007 from 3:00pm to 4pm

Attendeees  : Craig M., David V., Deva J., Sandip C.

Background

CAUTION: The beans we discuss below are fields(properties) of the managed bean classes such as Page1.java or SessionBean1.java in the Java language (JavaBeans sense).

Current mechanism for generation Initialization code

When beans are added to the VW pages using a visual mechanism such as drag and drop - it is required that the designtime support handle the initialization of such beans. Since the Creator 1 days, Insync has taken a simple approach to the generation of initialization code. For example, if the bean is of type Foo, then the generated code is of the form:

    private Foo foo1 = new Foo();

    public Foo getFoo1() {
        return foo1;
    }

    public void setFoo1(Foo foo1) {
        this.foo1 = foo1;
    }

In other words new Foo() was derived from the type Foo of the bean. This presents a problem in case of CachedRowsetImpl. Why? See below.

Modeling of interface and abstract class typed beans at designtime

From the Creator 1 days there has been an issue of the lack of support for modeling of beans of interface and abstract class types. The simple reason for this has been the fact that these types can not be instantiated using the simple, reflection based mechanism beansClass.newInstance(). For this reason the user added beans had to be coded like this:

    private ArrayList persons = ...; // intentionally shown as ... to not give an impression that this initialization code is used by Insync to instantiate the Bean at designtime

    public ArrayList getPersons() {
        return persons ;
    }

    public void setPersons (ArrayList persons ) {
        this.persons = persons ;
    }

This allowed Insync to model the Bean using the following pseudo code:

    :
    Class beanClass = Class.forName("java.util.ArrayList");
    Object bean = beanClass.newInstance();
    :

It must be noted that this is not done based on interpretation of initialization code but simply based on the type of field persons.

This is SOOOO not Effective Java which recommends preference to interface or abstract class type for field declaration when possible:

    private List persons = new ArrayList();

    public List getPersons() {
        return persons ;
    }

    public void setPersons(List persons ) {
        this.persons = persons ;
    }

Now that we are moving to the standard CachedRowSet (which is an interface) to support Database access a problem has emerged. Due to the above described limitations thefollowing code will have to be used:

    private CachedRowSetImpl cachedRowSetImpl1 = new CachedRowSetImpl(); // i.e. the concrete implementation class as the type of field

    public CachedRowSetImpl getCachedRowSetImpl1() {
        return cachedRowSetImpl1;
    }

    public void setCachedRowSetImpl1(CachedRowSetImpl cachedRowSetImpl1) {
        this.cachedRowSetImpl1= cachedRowSetImpl1;
    }

instead of:

    private CachedRowSet cachedRowSet1 = new CachedRowSetImpl();

    public CachedRowSet getCachedRowSet1() {
        return cachedRowSet1;
    }

    public void setCachedRowSet1(CachedRowSet cachedRowSet1) {
        this.cachedRowSet1= cachedRowSet1;
    }

However there is a problem. The new CachedRowSetImpl() thows an exception. The compiler will not allow such code. What to do? See below.

Support for Generics

With the JDK 1.5 the Generics (e.g. List<Person>) were introduced in Java language. The Generics are used by the Java Persistence Architecture (henceforth JPA) to provide a simple POJO based, yet strongly typed access to Databases (as opposed to low level JDBC access). Thus it becomes imperative to support the Generic typed Beans in the Visual Web's (henceforth VW) designtime support.

Possible solutions

We had a meeting to discuss possible solutions for the issues discussed above. We came up with the following solutions.

Solution for generation Initialization code

The whole Creator and VW story had been possible due to the Designtime API (which augments JavaBean API). Using the Designtime API + JavaBeans API, the writers of beans can influence the way the tools deal with the bean at design time. We can make use of these mechanism to give the writers of Bean's design time support to control how the Bean instance is initialized. We propose the following solution. The BeanInfo of the Bean will have an attribute called

"INSTANCE_INITIALIZATION"

There could be an enum of same name.

Its values could be:

"NONE",
"DEFAULT_CONSTRUCTOR",
"INITIALIZATION_EXPRESSION",
"MANAGED"

These could be enum values.

I am proposing a more general solution here. We can scale back on it for M10 or even 6.0.

I am not clear about where these will be defined. I guess somewhere in Designtime API or the newer DesigntimeExt APIs?

The value NONE will indicate that Insync should not generate any initialization code. This can work for JSF component beans because the JSF lifecycle manages the creation of JSF components in the Create/Restore view phase. If the BeanInfos of all of the JSF components we bundle use inheritance then it should be simple matter of introducing this attribute in the base BeanInfo of Standard, Braveheart and Woodstock components.

The value DEFAULT_CONSTRUCTOR will indicate that Insync should generate initialization code as it does today i.e. for a bean of type Foo generate new Foo(). For backward compatibility we will assume this as the deault behavior. Agree?

The value INITIALIZATION_EXPRESSION will indicate that Insync should generate initialization code specified by another attribute named INITIALIZATION_EXPRESSION_STRING. It is obvious that specified expression string should not result in a syntax error. This mechaism will allow the bean writers to make use of factory methods to create the instance at run time. Insync may have to automatically attempt to fix imports for factory classes etc. This could be tricky. Alternativly the expression should make use of FQNs.

The value MANAGED will indicate that the bean designtime support (DesignInfo) handles the initialization code in the _init() method using the already available ContextMethod mechanism of Designtime API. In such cases Insync will not generate any initialization code. The Bean's DesignInfo will manage the insertion and deletion of intialization code in the bean create setup and bean delete cleanup call backs. We recommend that this be achieved by inserting the initialization code surrounded with special comment block which can be later be found using a simple text/regexp search when the cleanup is required. This is because the ContextMethod mechanism works using the text of the method bodies.

It should be noted that the effect of NONE could be achieved by using the value of MANAGED and not doing anything in the bean create setup and bean delete cleanup call backs.

For backward compatibility if the attribute is absent in BeanInfo, Insync will assume DEFAULT_CONSTRUCTOR and do what it does today.

This has a relative priority of P1 and is recommended to be done for M10.

Solution for modeling of interface and abstract class typed beans at designtime

As noted above it is desirable to prefer interfaces or abstract classes as the type of a field declarations. However such types cannot be instantiated using no arg CTOR. We propose that there be another attribte in the bean's BeanDescriptor:

"DESIGNTIME_INSTANCE_FACTORY"

The value of this attribute will be an object of type:

/**
 * Factory for creation of bean instances at design time.
 */
public interface DesigntimeInstanceFactory {
   /**
    * This will return an instance which should be castable to the bean's type
    */
   public Object getDesigntimeInstance(DesignContext designContext,
                                       String instanceTypeFQN, // e.g. "javax.sql.CachedRowSet" or "java.util.List<Person>". ''is this redundant?''
                                       String instanceName);   // e.e. "cashedRowSet1". ''could we pass DesignBeans here or is that chicken and egg problem?''
}

For example:

/**
 * Factory for creation of bean instances of CachedRowset at design time.
 */
public class CachedRowsetDesigntimeInstanceFactory implements DesigntimeInstanceFactory {
   /**
    * This will return an instance (CachedRowsetImpl) which should be castable to the bean's type (CachedRowSet)
    */
   public Object getDesigntimeInstance(DesignContext designContext,
                                       String instanceTypeFQN,
                                       String instanceName) {
       try {
           return new CachedRowsetImpl();
       } catch (SqlException se) {
           // Log or Notify
           return null;
       }
   }
}


If the attribute is present, Insync will retrieve it and use it to create the instance for modeling purposes. If the attribute is absent, Insync will fall back to the current behavior.

This has a relative priority of P2 and is recommended to be done for 6.0FCS.

Solution for modeling of Generic typed beans

If a bean is declared with a parameterized type such as:

   private List<Person> persons = ....;
   :
   :

Insync could make use of the type argument type such as Person above to give better designtime support. This could be useful when there is no designtime instance available. In such case Insync could switch to reflection to provide the designtime support. Think of this as is an implicit equivalent of the explicit element object type setting mechanism of Object*DataProviders.

This has a relative priority of P2 and is recommended to be done for 6.0FCS.

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo