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);
+}