Ok, in the end this means we cannot go with this - I am for using templates in the API and base-classes for everything else.
regards, Martin On Feb 7, 2008 6:47 PM, Leonardo Uribe <[EMAIL PROTECTED]> wrote: > 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 > -- http://www.irian.at Your JSF powerhouse - JSF Consulting, Development and Courses in English and German Professional Support for Apache MyFaces