https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=1782
The proposed solution is to enhance the composite component metadata
specification to include information about the list of composite
component attributes for which default attribute values have been
declared.
This information is used in the Facelets tag layer in the code that
installs the ValueExpression for any child attributes in the using page.
In this case, the MetadataHandler manually removes the attribute from
the attributes map if there is a ValueExpression for an attribute for
which there also is a composite component attribute.
SECTION: Modified Files
----------------------------
M Spec section 3.6.2.1 Composite Component Metadata
Add a new paragraph at the end of the section, which would fall under
the bullet that describes the runtime representation of the
<cc:attribute> element.
The composite component BeanDescriptior must return a
Collection<String> when its getValue() method is called with an
argument equal to the value of the symbolic constant
UIComponent.ATTRS_WITH_DECLARED_DEFAULT_VALUES. The
Collection<String> must contain the names of any <cc:attribute>
elements for which the default attribute was specified, or null, if
none of the attributes have been given a default value.
M jsf-api/src/main/java/javax/faces/component/UIComponent.java
- Add constant:
+ * <p class="changed_added_2_1">This constant enables one to quickly
discover
+ * the names of the declared composite component attributes that have been
+ * given default values by the composite component author. The information
+ * is exposed as a <code>Collection<String></code> returned
from the
+ * <code>getValue()</code> method on the <em>composite component
+ * BeanDescriptor</em>, when this constant is passed as the
argument.</p>
+ *
+ * @since 2.1
+ */
+ public static final String ATTRS_WITH_DECLARED_DEFAULT_VALUES =
+ "javax.faces.component.ATTR_NAMES_WITH_DEFAULT_VALUES";
M
jsf-ri/src/main/java/com/sun/faces/facelets/tag/jsf/CompositeComponentTagHandler.java
- Consider the inner class CompositeExpressionMetadata. This class
deals with attributes of a composite component instance in a using
page that are of type ValueExpressionsp For example:
<tmo:block collapsable="#{'true'}"/>
If the corresponding attribute has been declared with a default value
in the composite component declaration, such as:
<composite:interface>
<composite:attribute name="collapsable" required="false"
default="false"/>
</composite:interface>
then the default attribute will have already been stored in the
attributes map of the composite component by the time the
CompositeExpressionMetadata.applyMetadata() method is called. (See
ApplicationImpl.pushDeclaredDefaultValuesToAttributesMap()). This
change uses the new element of composite component metadata to inspect
if the attribute in question has a default value. If so, we remove
the attribute from the component attributes map so that the one from
the using page is used, instead of the default value.
M jsf-ri/src/main/java/com/sun/faces/application/ApplicationImpl.java
- in createComponent(String,Resource), and
pushDeclaredDefaultValuesToAttributesMap(), implement the new portion
of the composite component metadata specification.
M jsf-ri/systest/src/com/sun/faces/composite/CompositeComponentsTestCase.java
- new testcase
SECTION: Diffs
----------------------------
Index: jsf-api/src/main/java/javax/faces/component/UIComponent.java
===================================================================
--- jsf-api/src/main/java/javax/faces/component/UIComponent.java (revision 8566)
+++ jsf-api/src/main/java/javax/faces/component/UIComponent.java (working copy)
@@ -210,6 +210,19 @@
*/
public static final String COMPOSITE_FACET_NAME =
"javax.faces.component.COMPOSITE_FACET_NAME";
+ /**
+ * <p class="changed_added_2_1">This constant enables one to quickly
discover
+ * the names of the declared composite component attributes that have been
+ * given default values by the composite component author. The information
+ * is exposed as a <code>Collection<String></code> returned
from the
+ * <code>getValue()</code> method on the <em>composite component
+ * BeanDescriptor</em>, when this constant is passed as the
argument.</p>
+ *
+ * @since 2.1
+ */
+ public static final String ATTRS_WITH_DECLARED_DEFAULT_VALUES =
+ "javax.faces.component.ATTR_NAMES_WITH_DEFAULT_VALUES";
+
enum PropertyKeysPrivate {
attributesThatAreSet
}
Index:
jsf-ri/src/main/java/com/sun/faces/facelets/tag/jsf/CompositeComponentTagHandler.java
===================================================================
---
jsf-ri/src/main/java/com/sun/faces/facelets/tag/jsf/CompositeComponentTagHandler.java (revision
8566)
+++
jsf-ri/src/main/java/com/sun/faces/facelets/tag/jsf/CompositeComponentTagHandler.java (working
copy)
@@ -65,6 +65,7 @@
import com.sun.faces.util.RequestStateManager;
import com.sun.faces.util.Util;
import com.sun.faces.util.FacesLogger;
+import java.beans.BeanDescriptor;
import javax.el.ELException;
import javax.el.ValueExpression;
@@ -95,6 +96,7 @@
import java.beans.IntrospectionException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -599,6 +601,18 @@
ValueExpression ve = attr.getValueExpression(ctx, type);
UIComponent cc = (UIComponent) instance;
assert (UIComponent.isCompositeComponent(cc));
+ Map<String, Object> attrs = cc.getAttributes();
+ BeanInfo componentMetadata = (BeanInfo)
attrs.get(UIComponent.BEANINFO_KEY);
+ BeanDescriptor desc = componentMetadata.getBeanDescriptor();
+ Collection<String> attributesWithDeclaredDefaultValues =
(Collection<String>)
+ desc.getValue(UIComponent.ATTRS_WITH_DECLARED_DEFAULT_VALUES);
+ if (null != attributesWithDeclaredDefaultValues &&
+ attributesWithDeclaredDefaultValues.contains(name)) {
+ // It is necessary to remove the value from the attribute
+ // map because the ELexpression transparancy doesn't know
+ // about the value's existence.
+ attrs.remove(name);
+ }
cc.setValueExpression(name, ve);
}
Index: jsf-ri/src/main/java/com/sun/faces/application/ApplicationImpl.java
===================================================================
--- jsf-ri/src/main/java/com/sun/faces/application/ApplicationImpl.java (revision 8566)
+++ jsf-ri/src/main/java/com/sun/faces/application/ApplicationImpl.java (working copy)
@@ -1031,6 +1031,8 @@
PropertyDescriptor[] declaredAttributes =
componentMetadata.getPropertyDescriptors();
Object defaultValue;
String key;
+ Collection<String> attributesWithDeclaredDefaultValues = null;
+
for (PropertyDescriptor cur : declaredAttributes) {
defaultValue = cur.getValue("default");
if (null != defaultValue) {
@@ -1043,6 +1045,19 @@
// ensure this attribute is not a method-signature. method-signature
// declared default values are handled in retargetMethodExpressions.
if (null == cur.getValue("method-signature") || null !=
cur.getValue("type")) {
+
+ if (null == attributesWithDeclaredDefaultValues) {
+ BeanDescriptor desc = componentMetadata.getBeanDescriptor();
+ attributesWithDeclaredDefaultValues = (Collection<String>)
+
desc.getValue(UIComponent.ATTRS_WITH_DECLARED_DEFAULT_VALUES);
+ if (null == attributesWithDeclaredDefaultValues) {
+ attributesWithDeclaredDefaultValues = new
ArrayList<String>();
+
desc.setValue(UIComponent.ATTRS_WITH_DECLARED_DEFAULT_VALUES,
+ attributesWithDeclaredDefaultValues);
+ }
+ }
+ attributesWithDeclaredDefaultValues.add(key);
+
attrs.put(key, defaultValue);
}
}
Index: jsf-ri/systest/src/com/sun/faces/composite/CompositeComponentsTestCase.java
===================================================================
--- jsf-ri/systest/src/com/sun/faces/composite/CompositeComponentsTestCase.java (revision
8566)
+++ jsf-ri/systest/src/com/sun/faces/composite/CompositeComponentsTestCase.java (working
copy)
@@ -963,6 +963,13 @@
assertTrue(text.contains("The following facets(s) are required, but no
facets have been supplied for them: table."));
}
+ public void testDefaultAttributeValueELOverrides() throws Exception {
+ HtmlPage page = getPage("/faces/composite/issue-1782-using.xhtml");
+ String text = page.asText();
+ System.out.println(text);
+ assertTrue(text.matches("(?s).*collapsable\\s=\\strue.*"));
+ }
+
// --------------------------------------------------------- Private Methods
--
| edward.burns(a)oracle.com | office: +1 407 458 0017
| homepage: |
http://ridingthecrest.com/
| 14 work days until JSF 2.1 Milestone 3