Hi This mail is about the wiki http://wiki.apache.org/myfaces/Code_Generation: An the topic on this wiki page Generating base classes instead of templatesFinally I have found the reasons about my previous suggestions, so I will proceed with the proper update of the wiki. These are the changes:
*".......Note that (in a feature that may surprise some Java developers) it appears quite valid for a class to have a package-scoped parent; the class can still be subclassed or instantiated from outside the package. It inherits public and protected members from its package-scoped parent which can be called as normal. The only constraint is that it cannot be cast to its parent type, as this is not accessible (although the Class object for that type can still be obtained). It is not yet known whether inserting such a package-scoped ancestor class into the ancestry of a component class in the javax.faces package scope would be acceptable to the JSF TCK or not. If the TCK accepts this, then the approach of generating a base class could also be applied to myfaces core components......".* In the practice the problem is that jsf core (myfaces and ri) uses reflection to set the attributes and the following case fail: //base component class from api public class BaseComponent extends Object { //......// } //package scope class abstract class AbstractComponent extends BaseComponent { private String value; public String getValue() { return value; } public void setValue(String value) { this.value = value; } } public class RealComponent extends AbstractComponent { //......// } If an instance of RealComponent is created, you can access to the public api defined on AbstractComponent. But if you use reflection to call getValue or setValue using a code like this: public Object getValue(BaseComponent component){ Object resp = null; try { BeanInfo beanInfo = null; try { beanInfo = Introspector.getBeanInfo(component.getClass()); } catch (IntrospectionException e) { e.printStackTrace(); } PropertyDescriptor[] propertyDescriptors = beanInfo .getPropertyDescriptors(); HashMap<String, PropertyDescriptor> _propertyDescriptorMap = new HashMap<String, PropertyDescriptor>(); for (int i = 0; i < propertyDescriptors.length; i++) { PropertyDescriptor propertyDescriptor = propertyDescriptors[i]; if (propertyDescriptor.getReadMethod() != null) { _propertyDescriptorMap.put(propertyDescriptor.getName(), propertyDescriptor); } } PropertyDescriptor pd = _propertyDescriptorMap.get("value"); Method readMethod = pd.getReadMethod(); Object[] EMPTY_ARGS = new Object[0]; resp = readMethod.invoke(component, EMPTY_ARGS); } catch (Exception e) { e.printStackTrace(); } return resp; } Fail with the following exception java.lang.IllegalAccessException: Class javax.faces.component._Util can not access a member of class org.apache.myfaces.test.AbstractComponent with modifiers "public" at sun.reflect.Reflection.ensureMemberAccess(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at javax.faces.component._Util.getValue(_Util.java:54) at javax.faces.component.BaseComponent.getValueReflection( BaseComponent.java:32) at javax.faces.other.ComponentTest.main(ComponentTest.java:14) This behavior is a JDK bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4533479 One possible workaround is put the following line before invoke: readMethod.setAccessible(true); Or make AbstractComponent public. The conclusion is that the abstract base class should be public if and only if it has in his body a attribute definition available on the tld. If the abstract base class has some different code it can be package scope. This behavior discard this approach for myfaces core api! *".....Question: When there are multiple source trees for a module, does maven build against them all simultaneously? That is, if a normal source file references a source file in the generated-source tree which itself references a source file in the normal source tree, does this work?..." * Response: One successful example is this hierarchy used for t:schedule javax.faces.UIComponentBase -----------myfaces core api org.apache.myfaces.custom.schedule.AbstractUIScheduleBase ----------- on src/main/java org.apache.myfaces.custom.schedule.UIScheduleBase ------------ generated on target/maven-faces-plugin/main/java org.apache.myfaces.custom.schedule.UISchedule ------------ on src/main/java org.apache.myfaces.custom.schedule.HtmlSchedule ------------ generated on target/maven-faces-plugin/main/java COMMENT: Generate in src/main/java or in target/maven-faces-plugin/main/java is transparent for the IDE. If we generate in src/main/java, the generated code will mix with hand written code, if we translate generated code to a separate directory on src/main/java (for example src/main/java-generated) technically it is equivalent to generate in target/maven-faces-plugin/main/java (the difference is if we do mvn clean, the code in target is deleted). regards Leonardo Uribe