dev@javaserverfaces.java.net

RE: Seeking Review Impl portion of jsf-api 205: PropertyEditorConverter

From: <jacob_at_hookom.net>
Date: Fri, 11 Aug 2006 13:25:10 -0400

+0 on the concept

On ignoring registration under certain conditions, someone may expect that they can provide their own converter for lang types. If PropertyEditorManager is statically scoped, application restarts with converter registration could be difficult do correctly with the changebundle.

If kept, use Arrays.indexOf(...) instead of writing your own. Also, what about primitives-- class name of 'int', 'long', 'byte'.

ConverterPropertyEditor should be written like the other JSF ELResolvers and fail fast if FacesContext is not available.

Overall, an interesting solution, but I would prefer a literal ELResolver solution instead of piggy backing on the oddities of the Swing/Bean API here.

-- Jacob


>Hello,
>
>This issue was found by a user on ##jsf.
>
>I propose we fix this now in this manner, and then make an EG request to
>fix it in a more spec appropriate way.
>
>https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=205
>
>This change bundle creates a special ConverterPropertyEditor that
>enables user defined classes that have been registered to faces using
>the by-type conversion mechanism to be coerced using the EL coercion
>mechanism defined in section 1.18.7 of the EL spec. This section calls
>for teh use of JavaBeans PropertyEditors to do the conversion.
>
>It turns out the JavaBeans PropertyEditors are strikingly similar to JSF
>Converters, but offer more flexibility. Perhaps the JSF EG should have
>just use those instead of inventing something new? Ah well, it's
>(troubled) water underneath the bridge.
>
>SECTION: Impl changes
>
>
>
>M jsf-ri/src/com/sun/faces/application/ApplicationImpl.java
>
>- in addConverter(Class, String), make a call to
> addPropertyEditorIfNecessary.
>
>- new method addPropertyEditorIfNecessary().
>
> * <p>To enable EL Coercion to use JSF Custom converters, this
> * method will call <code>PropertyEditorManager.registerEditor()</code>,
> * passing the <code>ConverterPropertyEditor</code> class for the
> * <code>targetClass</code> if the target class is not one of the
>standard
> * by-type converter target classes.
>
>A jsf-ri/src/com/sun/faces/application/ConverterPropertyEditor.java
>M jsf-ri/src/com/sun/faces/renderkit/html_basic/HtmlBasicInputRenderer.java
>
>- This is the linchpin for this whole bugfix. Here is where we convey
> the information the ConverterPropertyEditor class needs to perform the
> conversion: the targetClass, and the UIComponent associated with the value.
>
> This information is conveyed using request scoped attributes.
>
>SECTION: Diffs
>
>Index: jsf-ri/src/com/sun/faces/application/ApplicationImpl.java
>===================================================================
>RCS file:
>/cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/application/ApplicationIm
>pl.java,v
>retrieving revision 1.78
>diff -u -r1.78 ApplicationImpl.java
>--- jsf-ri/src/com/sun/faces/application/ApplicationImpl.java 17 May 2006
>19:00:44 -0000 1.78
>+++ jsf-ri/src/com/sun/faces/application/ApplicationImpl.java 10 Aug 2006
>20:48:03 -0000
>@@ -82,6 +82,8 @@
> import com.sun.faces.el.VariableResolverImpl;
> import com.sun.faces.util.MessageUtils;
> import com.sun.faces.util.Util;
>+import java.beans.PropertyEditor;
>+import java.beans.PropertyEditorManager;
>
>
> /**
>@@ -670,10 +672,40 @@
> }
>
> converterTypeMap.put(targetClass, converterClass);
>+ addPropertyEditorIfNecessary(targetClass, converterClass);
>
> if (logger.isLoggable(Level.FINE)) {
> logger.fine("added converter of class type " + converterClass);
> }
>+ }
>+
>+ private final String [] STANDARD_BY_TYPE_CONVERTER_CLASSES = {
>+ "java.math.BigDecimal",
>+ "java.lang.Boolean",
>+ "java.lang.Byte",
>+ "java.lang.Character",
>+ "java.lang.Double",
>+ "java.lang.Float",
>+ "java.lang.Integer",
>+ "java.lang.Long",
>+ "java.lang.Short",
>+ "java.lang.Enum"
>+ };
>+
>+ private void addPropertyEditorIfNecessary(Class targetClass, String
>converterClass) {
>+ PropertyEditor editor =
>PropertyEditorManager.findEditor(targetClass);
>+ if (null != editor) {
>+ return;
>+ }
>+ String className = targetClass.getName();
>+ // Don't add a PropertyEditor for the standard by-type converters.
>+ for (String standardClass : STANDARD_BY_TYPE_CONVERTER_CLASSES) {
>+ if (-1 != standardClass.indexOf(className)) {
>+ return;
>+ }
>+ }
>+ PropertyEditorManager.registerEditor(targetClass,
>+ ConverterPropertyEditor.class);
> }
>
>
>Index:
>jsf-ri/src/com/sun/faces/renderkit/html_basic/HtmlBasicInputRenderer.java
>===================================================================
>RCS file:
>/cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/renderkit/html_basic/Html
>BasicInputRenderer.java,v
>retrieving revision 1.34
>diff -u -r1.34 HtmlBasicInputRenderer.java
>--- jsf-ri/src/com/sun/faces/renderkit/html_basic/HtmlBasicInputRenderer.java
>29 Mar 2006 23:03:48 -0000 1.34
>+++ jsf-ri/src/com/sun/faces/renderkit/html_basic/HtmlBasicInputRenderer.java
>10 Aug 2006 20:48:04 -0000
>@@ -31,6 +31,7 @@
>
> package com.sun.faces.renderkit.html_basic;
>
>+import com.sun.faces.application.ConverterPropertyEditor;
> import javax.el.ValueExpression;
> import javax.faces.application.Application;
> import javax.faces.component.UIComponent;
>@@ -42,6 +43,7 @@
>
> import com.sun.faces.util.MessageFactory;
> import com.sun.faces.util.MessageUtils;
>+import java.util.Map;
>
> import java.util.logging.Level;
>
>@@ -115,7 +117,7 @@
> String newValue = (String) submittedValue;
> // if we have no local value, try to get the valueExpression.
> ValueExpression valueExpression =
>component.getValueExpression("value");
>-
>+ Class converterType = null;
> Converter converter = null;
> Object result = null;
> // If there is a converter attribute, use it to to ask application
>@@ -126,8 +128,8 @@
> }
>
> if (null == converter && null != valueExpression) {
>- Class converterType =
>valueExpression.getType(context.getELContext());
>- // if converterType is null, assume the modelType is "String".
>+ converterType = valueExpression.getType(context.getELContext());
>+ // if converterType is null, assume the modelType is "String".
> if (converterType == null ||
> converterType == Object.class) {
> if (logger.isLoggable(Level.FINE)) {
>@@ -137,6 +139,7 @@
> }
> return newValue;
> }
>+
> // If the converterType is a String, and we don't have a
> // converter-for-class for java.lang.String, assume the type is
> // "String".
>@@ -185,6 +188,14 @@
> }
>
> if (converter != null) {
>+ // If the conversion eventually falls to needing to use EL type
>coercion,
>+ // make sure our special ConverterPropertyEditor knows about this
>value.
>+ Map<String, Object> requestMap =
>context.getExternalContext().getRequestMap();
>+
>requestMap.put(ConverterPropertyEditor.TARGET_CLASS_ATTRIBUTE_NAME,
>+ converterType);
>+
>requestMap.put(ConverterPropertyEditor.TARGET_COMPONENT_ATTRIBUTE_NAME,
>+ component);
>+
> result = converter.getAsObject(context, component, newValue);
> return result;
> } else {
>
>
>SECTION: New files
>
>/*
> * ConverterPropertyEditor.java
> *
> * Created on August 10, 2006, 12:39 PM
> *
> * The contents of this file are subject to the terms
> * of the Common Development and Distribution License
> * (the License). You may not use this file except in
> * compliance with the License.
> *
> * You can obtain a copy of the License at
> * https://javaserverfaces.dev.java.net/CDDL.html or
> * legal/CDDLv1.0.txt.
> * See the License for the specific language governing
> * permission and limitations under the License.
> *
> * When distributing Covered Code, include this CDDL
> * Header Notice in each file and include the License file
> * at legal/CDDLv1.0.txt.
> * If applicable, add the following below the CDDL Header,
> * with the fields enclosed by brackets [] replaced by
> * your own identifying information:
> * "Portions Copyrighted [year] [name of copyright owner]"
> *
> * [Name of File] [ver.__] [Date]
> *
> * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
> */
>
>package com.sun.faces.application;
>
>import com.sun.faces.RIConstants;
>import java.beans.PropertyEditorSupport;
>import javax.faces.FacesException;
>import javax.faces.component.UIComponent;
>import javax.faces.context.FacesContext;
>import javax.faces.convert.Converter;
>
>/**
> *
> * @author edburns
> */
>public class ConverterPropertyEditor extends PropertyEditorSupport {
>
> public static final String TARGET_CLASS_ATTRIBUTE_NAME =
>RIConstants.FACES_PREFIX + "ConverterPropertyEditorTargetClass";
> public static final String TARGET_COMPONENT_ATTRIBUTE_NAME =
>RIConstants.FACES_PREFIX + "ComponentForValue";
>
> /** Creates a new instance of ConverterPropertyEditor */
> public ConverterPropertyEditor() {
> }
>
> private String textValue = null;
>
> public void setAsText(String text) throws IllegalArgumentException {
> this.textValue = text;
> }
>
> public Object getValue() {
> FacesContext context = FacesContext.getCurrentInstance();
> Class targetClass = getTargetClass(context);
> UIComponent component = getComponent(context);
> Object retValue = null;
>
> if (null == textValue) {
> return null;
> }
>
> if (null == targetClass) {
> // PENDING(edburns): I18N
> throw new FacesException("Cannot discover target class for value "
>+
> textValue + ".");
> }
>
> Converter converter =
>context.getApplication().createConverter(targetClass);
>
> if (null == converter) {
> // PENDING(edburns): I18N
> throw new FacesException("Cannot create Converter to convert value
>" + textValue +
> " to instance of target class " + targetClass.getName() +
>".");
> }
>
> retValue = converter.getAsObject(context, component, textValue);
>
> return retValue;
> }
>
> private Class getTargetClass(FacesContext context) {
> return (Class)
>
>context.getExternalContext().getRequestMap().get(TARGET_CLASS_ATTRIBUTE_NAME);
>
> }
>
> private UIComponent getComponent(FacesContext context) {
> return (UIComponent)
>
>context.getExternalContext().getRequestMap().get(TARGET_COMPONENT_ATTRIBUTE_NAM
>E);
> }
>}
>
>--
>| ed.burns_at_sun.com | {home: 407 869 9587, office: 408 884 9519 OR x31640}
>| homepage: | http://purl.oclc.org/NET/edburns/
>| aim: edburns0sunw | iim: ed.burns_at_sun.com
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: dev-unsubscribe_at_javaserverfaces.dev.java.net
>For additional commands, e-mail: dev-help_at_javaserverfaces.dev.java.net
>