You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ma...@apache.org on 2007/12/10 08:37:05 UTC

svn commit: r602796 - /myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/

Author: matzew
Date: Sun Dec  9 23:37:03 2007
New Revision: 602796

URL: http://svn.apache.org/viewvc?rev=602796&view=rev
Log:
TRINIDAD-858
Thx to Max Starets for his patch.
Commit of the ported version for 1.1

Added:
    myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/Converter.java
    myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/ReverseDiscoveryGenericConverter.java
Modified:
    myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/ConvertException.java
    myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/DateTimeConverter.java
    myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/GenericConverter.java
    myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/GenericConverterFactory.java

Modified: myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/ConvertException.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/ConvertException.java?rev=602796&r1=602795&r2=602796&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/ConvertException.java (original)
+++ myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/ConvertException.java Sun Dec  9 23:37:03 2007
@@ -18,7 +18,7 @@
  */
 package org.apache.myfaces.trinidadinternal.convert;
 
-class ConvertException extends RuntimeException
+public class ConvertException extends RuntimeException
 {
   public ConvertException(Object source, Class<?> targetType, Throwable error)
   {

Added: myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/Converter.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/Converter.java?rev=602796&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/Converter.java (added)
+++ myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/Converter.java Sun Dec  9 23:37:03 2007
@@ -0,0 +1,34 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.myfaces.trinidadinternal.convert;
+
+/**
+ * Defines convertion capability for generic Converters
+ */
+
+public interface Converter
+{
+  /**
+   * converts the given Object into an instance of the 
+   * targetType.
+   * @return an instance of the targetType.
+   */
+  public Object convert(Object source, Class<?> targetType);
+}

Modified: myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/DateTimeConverter.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/DateTimeConverter.java?rev=602796&r1=602795&r2=602796&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/DateTimeConverter.java (original)
+++ myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/DateTimeConverter.java Sun Dec  9 23:37:03 2007
@@ -40,6 +40,7 @@
 import javax.faces.convert.ConverterException;
 import javax.faces.el.ValueBinding;
 
+import org.apache.myfaces.trinidad.component.UIXEditableValue;
 import org.apache.myfaces.trinidad.context.RenderingContext;
 import org.apache.myfaces.trinidad.convert.ClientConverter;
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
@@ -113,7 +114,7 @@
    * the expected type and convert if necessary: bug 4549630:
    */
   static Object __typeConvert(FacesContext context, Converter converter,
-      UIComponent component, String strValue, Object value)
+      UIComponent component, String strValue, Object value) throws ConverterException
   {
     assert value != null;
     ValueBinding binding = component.getValueBinding("value");
@@ -138,7 +139,23 @@
         {
           GenericConverterFactory fac = GenericConverterFactory
               .getCurrentInstance();
-          value = fac.convert(value, expectedType);
+          try
+          {
+            value = fac.convert(value, expectedType);
+          }
+          catch(ConvertException e)
+          {
+            // Use underlying exception's message if ConvertException
+            // wrapped exception raised by the converter
+            Throwable cause = e.getCause();
+            if (cause == null)
+              cause = e;
+           
+            FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, 
+                                                MessageFactory.getString(context, UIXEditableValue.CONVERSION_MESSAGE_ID),
+                                                cause.getLocalizedMessage());
+            throw new ConverterException(msg, e);
+          }
         }
       }
     }

Modified: myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/GenericConverter.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/GenericConverter.java?rev=602796&r1=602795&r2=602796&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/GenericConverter.java (original)
+++ myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/GenericConverter.java Sun Dec  9 23:37:03 2007
@@ -26,7 +26,7 @@
  * A converter may be capable of converting a single Object into
  * many different types.
  */
-public abstract class GenericConverter
+public abstract class GenericConverter implements Converter
 {
   /**
    * converts the given Object into an instance of the 

Modified: myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/GenericConverterFactory.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/GenericConverterFactory.java?rev=602796&r1=602795&r2=602796&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/GenericConverterFactory.java (original)
+++ myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/GenericConverterFactory.java Sun Dec  9 23:37:03 2007
@@ -40,8 +40,9 @@
 {
   private GenericConverterFactory()
   {
-    _cache = new HashMap<Key, GenericConverter>(16);
+    _cache = new HashMap<Key, Converter>(16);
     _converters = new ArrayList<GenericConverter>(3);
+    _reverseDiscoveryConverters = new ArrayList<ReverseDiscoveryGenericConverter>(2);
     registerConverter(new SqlConverter());
     registerConverter(new BaseConverter());
   }
@@ -59,14 +60,14 @@
    * requests for the same source and target types will be fast.
    * @return null if there is no such converter.
    */
-  public GenericConverter getConverter(Class<?> sourceType, Class<?> targetType)
+  public Converter getConverter(Class<?> sourceType, Class<?> targetType)
   {
     Key key = new Key(sourceType, targetType);
     // check the cache first:
     Object cached = _cache.get(key);
     if (cached != null)
     {
-      return (cached == _NULL) ? null : (GenericConverter) cached;
+      return (cached == _NULL) ? null : (Converter) cached;
     }
 
     // we are going to start searching to see if some chain of converters
@@ -78,7 +79,20 @@
     // cache to store all the classes we've tested already. This is to
     // avoid our chains from looping indefinitely:
     Set<Class<?>> cache  = new HashSet<Class<?>>(16);
-    GenericConverter converter = _findConverter(sourcesToBeSearched, targetType, cache);
+    
+    // Try to find a converter chain without "reverse discovery" converetrs.
+    // Our particular implementation of the "reverse discovery" converter uses Java Reflection,
+    // so it is better to use a chain of normal generic converters
+    Converter converter = _findConverter(sourcesToBeSearched, targetType, cache, false);
+    
+    // If we failed, try to use "reverse discovery" converters
+    if (converter == null && _reverseDiscoveryConverters.size() > 0)
+    {
+      cache.clear();
+      sourcesToBeSearched.add(start);
+      converter = _findConverter(sourcesToBeSearched, targetType, cache, true);
+    }
+    
     if (converter == null)
     {
       // cache the fact that no such converter exists:
@@ -99,16 +113,20 @@
    * sourceType and the chain of converters needed to produce this sourceType.
    * @param targetType the type that is needed
    * @param cache used to record which classes we've searched already.
+   * @param useRevserseDiscovery true if "reverse discovery" converters should be used, false otherwise
    * @return null if no converter was found.
    */
-  private GenericConverter _findConverter(
+  private Converter _findConverter(
     LinkedList<Node> sourcesToBeSearched,
     Class<?> targetType, 
-    Set<Class<?>> cache)
+    Set<Class<?>> cache,
+    boolean useRevserseDiscovery)
   {
     while(!sourcesToBeSearched.isEmpty())
     {
       Node source = sourcesToBeSearched.removeFirst();
+      Converter match = null;
+      
       // loop through all the converters and see what types they can turn 
       // the current sourceType into 
       // (the current sourceType is source.targetType):
@@ -120,14 +138,22 @@
         if (_searchTargetTypes(sourcesToBeSearched, source, conv, targetType,
                                cache))
         {
-          // see if there is no chain:
-          if (source.previous == null)
-            return conv;
-            
-          // there is a chain:
-          return new CompositeConverter(source, conv, targetType);
+          match = conv;
         }
       }
+      
+      if (match == null && useRevserseDiscovery)
+        match = _searchSourceTypes(source.targetType, targetType);
+      
+      if (match != null)
+      {
+        // see if there is no chain:
+        if (source.previous == null)
+          return match;
+          
+        // there is a chain:
+        return new CompositeConverter(source, match, targetType);
+      }
     }
     return null;
   }
@@ -151,7 +177,7 @@
     GenericConverter currentConverter,
     Class<?> searchType,
     Set<Class<?>> cache)
-  {
+  { 
     Class<?> sourceType = currentSource.targetType;
     List<Class<?>> targetTypes = currentConverter.getTargetTypes(sourceType);
     for(int i=0,sz=targetTypes.size(); i<sz; i++)
@@ -177,6 +203,27 @@
   }
   
   /**
+   * Finds a suitable converter by searching source types supported for a
+   * given target type
+   * @param sourceType - source type
+   * @param targetType - target type
+   * @return a suitable Converter is found, null otherwise
+   */
+  private Converter _searchSourceTypes(Class<?> sourceType, Class<?> targetType)
+  {
+    for (ReverseDiscoveryGenericConverter conv:_reverseDiscoveryConverters)
+    {
+      List<Class<?>> sourceTypes = conv.getSourceTypes(targetType);
+      for (Class<?> type: sourceTypes)
+      {
+        if (type.isAssignableFrom(sourceType))
+          return conv;
+      }
+    }
+    return null;
+  }
+  
+  /**
    * Registers a converter. Registering a new converter causes the internal
    * cache to be cleared.
    */
@@ -185,6 +232,16 @@
     _converters.add(converter);
     _cache.clear();
   }
+  
+  /**
+   * Registers a "reverse discovery" converter. Registering a new converter causes the internal
+   * cache to be cleared.
+   */
+  public void registerReverseDiscoveryConverter(ReverseDiscoveryGenericConverter converter)
+  {
+    _reverseDiscoveryConverters.add(converter);
+    _cache.clear();
+  }
 
   /**
    * converts the given source instance into an object of the targetType.
@@ -200,7 +257,7 @@
     if (targetType.isAssignableFrom(source.getClass()))
       return source;
   
-    GenericConverter converter = getConverter(source.getClass(), targetType);
+    Converter converter = getConverter(source.getClass(), targetType);
     if (converter != null)
     {
       return converter.convert(source, targetType);
@@ -221,33 +278,27 @@
     if (targetType.isAssignableFrom(source.getClass()))
       return true;
     
-    GenericConverter converter = getConverter(source.getClass(), targetType);
+    Converter converter = getConverter(source.getClass(), targetType);
     return converter != null;
   }
   
-  private final Map<Key, GenericConverter> _cache;
+  private final Map<Key, Converter> _cache;
   private final List<GenericConverter> _converters;
+  private final List<ReverseDiscoveryGenericConverter> _reverseDiscoveryConverters;
   // 2006-08-02: -= Simon Lessard =-
   //             Using a GenericConverter null value instead 
   //             of Node.class to be typesafe
-  private static final GenericConverter _NULL = new GenericConverter()
+  private static final Converter _NULL = new Converter()
   {
-    @Override
     public Object convert(Object source, Class<?> targetType)
     {
       return null;
     }
-    
-    @Override
-    public List<Class<?>> getTargetTypes(Class<?> sourceType)
-    {
-      return Collections.emptyList();
-    }
   };
 
   private static final class Node
   {
-    public Node(Node previous, GenericConverter converter, Class<?> targetType)
+    public Node(Node previous, Converter converter, Class<?> targetType)
     {
       this.previous = previous;
       this.converter = converter;
@@ -264,15 +315,8 @@
       return source;
     }
     
-    public Class<?> getSourceType()
-    {
-      if (previous == null)
-        return targetType;
-      return previous.getSourceType();
-    }
-    
     public final Node previous;
-    public final GenericConverter converter;
+    public final Converter converter;
     public final Class<?> targetType;
   }
   
@@ -312,15 +356,14 @@
     private final Class<?> _target;
   }
   
-  private static final class CompositeConverter extends GenericConverter
+  private static final class CompositeConverter implements Converter
   {
-    public CompositeConverter(Node source, GenericConverter conv, Class<?> targetType)
+    public CompositeConverter(Node source, Converter conv, Class<?> targetType)
     {
       assert source != null;
       _chain = new Node(source, conv, targetType) ;
     }
 
-    @Override
     public Object convert(Object source, Class<?> targetType)
     {
       if (targetType.isAssignableFrom(_chain.targetType))
@@ -330,18 +373,6 @@
       else
         throw new IllegalArgumentException(_LOG.getMessage(
           "CANNOT_CONVERT", new Object[]{source, targetType.getName()}));
-    }
-
-    @Override
-    public List<Class<?>> getTargetTypes(Class<?> sourceType)
-    {
-      if (_chain.getSourceType().isAssignableFrom(sourceType))
-      {
-        List<Class<?>> list = new ArrayList<Class<?>>(1);
-        list.add(_chain.targetType);
-        return list;
-      }
-      return Collections.emptyList();
     }
     
     private final Node _chain;

Added: myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/ReverseDiscoveryGenericConverter.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/ReverseDiscoveryGenericConverter.java?rev=602796&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/ReverseDiscoveryGenericConverter.java (added)
+++ myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/convert/ReverseDiscoveryGenericConverter.java Sun Dec  9 23:37:03 2007
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.myfaces.trinidadinternal.convert;
+
+import java.util.List;
+
+/**
+ * This class is capable of converting
+ * one Object into another.
+ * Users of this class may discover source types supported by this Converter
+ * by specifying a target type. Regular GenericConverter allows discovery of supported
+ * target types by specifying a source type
+ */
+
+public abstract class ReverseDiscoveryGenericConverter implements Converter
+{
+  /**
+   * converts the given Object into an instance of the 
+   * targetType.
+   * @return an instance of the targetType.
+   */
+  public abstract Object convert(Object source, Class<?> targetType);
+    
+  /**
+   * Gets all the supported source types for the given targetType.
+   * This converter must be able to convert each source type into the
+   * targetType.
+   * @return Each item is of type {@link Class}. An empty list must be
+   * returned if the given targetType cannot be converted from anything.
+   */
+  public abstract List<Class<?>> getSourceTypes(Class<?> targetType);
+}