View Javadoc

1   /*
2    $Id: Invoker.java,v 1.61 2004/07/10 03:31:42 bran Exp $
3   
4    Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5   
6    Redistribution and use of this software and associated documentation
7    ("Software"), with or without modification, are permitted provided
8    that the following conditions are met:
9   
10   1. Redistributions of source code must retain copyright
11      statements and notices.  Redistributions must also contain a
12      copy of this document.
13  
14   2. Redistributions in binary form must reproduce the
15      above copyright notice, this list of conditions and the
16      following disclaimer in the documentation and/or other
17      materials provided with the distribution.
18  
19   3. The name "groovy" must not be used to endorse or promote
20      products derived from this Software without prior written
21      permission of The Codehaus.  For written permission,
22      please contact info@codehaus.org.
23  
24   4. Products derived from this Software may not be called "groovy"
25      nor may "groovy" appear in their names without prior written
26      permission of The Codehaus. "groovy" is a registered
27      trademark of The Codehaus.
28  
29   5. Due credit should be given to The Codehaus -
30      http://groovy.codehaus.org/
31  
32   THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
36   THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43   OF THE POSSIBILITY OF SUCH DAMAGE.
44  
45   */
46  package org.codehaus.groovy.runtime;
47  
48  import groovy.lang.GroovyObject;
49  import groovy.lang.GroovyRuntimeException;
50  import groovy.lang.MetaClass;
51  import groovy.lang.MetaClassRegistry;
52  import groovy.lang.Range;
53  import groovy.lang.Tuple;
54  
55  import java.io.File;
56  import java.io.IOException;
57  import java.io.StringWriter;
58  import java.lang.reflect.Method;
59  import java.security.AccessController;
60  import java.security.PrivilegedAction;
61  import java.util.ArrayList;
62  import java.util.Arrays;
63  import java.util.Collection;
64  import java.util.Collections;
65  import java.util.Enumeration;
66  import java.util.Iterator;
67  import java.util.List;
68  import java.util.Map;
69  import java.util.NoSuchElementException;
70  import java.util.regex.Matcher;
71  import java.util.regex.Pattern;
72  
73  import org.apache.xml.serialize.OutputFormat;
74  import org.apache.xml.serialize.XMLSerializer;
75  import org.w3c.dom.Element;
76  import org.w3c.dom.Node;
77  import org.w3c.dom.NodeList;
78  
79  /***
80   * A helper class to invoke methods or extract properties on arbitrary Java objects dynamically
81   * 
82   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
83   * @version $Revision: 1.61 $
84   */
85  public class Invoker {
86  
87      protected static final Object[] EMPTY_ARGUMENTS = {
88      };
89      protected static final Class[] EMPTY_TYPES = {
90      };
91  
92      public MetaClassRegistry getMetaRegistry() {
93          return metaRegistry;
94      }
95  
96      private MetaClassRegistry metaRegistry = new MetaClassRegistry();
97  
98      public MetaClass getMetaClass(Object object) {
99          return metaRegistry.getMetaClass(object.getClass());
100     }
101 
102     /***
103      * Invokes the given method on the object. 
104      * 
105      * @param object
106      * @param methodName
107      * @param arguments
108      * @return
109      */
110     public Object invokeMethod(Object object, String methodName, Object arguments) {
111         /*
112         System
113             .out
114             .println(
115                 "Invoker - Invoking method on object: "
116                     + object
117                     + " method: "
118                     + methodName
119                     + " arguments: "
120                     + InvokerHelper.toString(arguments));
121                     
122                     */
123 
124         if (object == null) {
125             throw new NullPointerException("Cannot invoke method: " + methodName + " on null object");
126         }
127 
128         if (object instanceof GroovyObject) {
129             GroovyObject groovy = (GroovyObject) object;
130             return groovy.invokeMethod(methodName, arguments);
131         }
132         else {
133             if (object instanceof Class) {
134                 Class theClass = (Class) object;
135 
136                 MetaClass metaClass = metaRegistry.getMetaClass(theClass);
137                 return metaClass.invokeStaticMethod(object, methodName, asArray(arguments));
138             }
139             else {
140                 Class theClass = object.getClass();
141 
142                 MetaClass metaClass = metaRegistry.getMetaClass(theClass);
143                 return metaClass.invokeMethod(object, methodName, asArray(arguments));
144             }
145         }
146     }
147 
148     public Object invokeSuperMethod(Object object, String methodName, Object arguments) {
149         if (object == null) {
150             throw new NullPointerException("Cannot invoke method: " + methodName + " on null object");
151         }
152 
153         Class theClass = object.getClass();
154 
155         MetaClass metaClass = metaRegistry.getMetaClass(theClass.getSuperclass());
156         return metaClass.invokeMethod(object, methodName, asArray(arguments));
157     }
158 
159     public Object invokeStaticMethod(String type, String method, Object arguments) {
160         MetaClass metaClass = metaRegistry.getMetaClass(loadClass(type));
161         List argumentList = asList(arguments);
162         return metaClass.invokeStaticMethod(null, method, asArray(arguments));
163     }
164 
165     public Object invokeConstructor(String type, Object arguments) {
166         //System.out.println("Invoking constructor of type: " + type);
167         return invokeConstructorOf(loadClass(type), arguments);
168     }
169 
170     public Object invokeConstructorOf(Class type, Object arguments) {
171         MetaClass metaClass = metaRegistry.getMetaClass(type);
172         return metaClass.invokeConstructor(asArray(arguments));
173     }
174 
175     /***
176      * Converts the given object into an array; if its an array then just
177      * cast otherwise wrap it in an array
178      */
179     public Object[] asArray(Object arguments) {
180         if (arguments == null) {
181             return EMPTY_ARGUMENTS;
182         }
183         if (arguments instanceof Tuple) {
184             Tuple tuple = (Tuple) arguments;
185             return tuple.toArray();
186         }
187         if (arguments instanceof Object[]) {
188             return (Object[]) arguments;
189         }
190         else {
191             return new Object[] { arguments };
192         }
193     }
194 
195     public List asList(Object value) {
196         if (value == null) {
197             return Collections.EMPTY_LIST;
198         }
199         else if (value instanceof List) {
200             return (List) value;
201         }
202         else if (value.getClass().isArray()) {
203             return Arrays.asList((Object[]) value);
204         }
205         else if (value instanceof Enumeration) {
206             List answer = new ArrayList();
207             for (Enumeration e = (Enumeration) value; e.hasMoreElements();) {
208                 answer.add(e.nextElement());
209             }
210             return answer;
211         }
212         else {
213             // lets assume its a collection of 1
214             return Collections.singletonList(value);
215         }
216     }
217 
218     /***
219      * @param arguments
220      * @return
221      */
222     public Collection asCollection(Object value) {
223         if (value == null) {
224             return Collections.EMPTY_LIST;
225         }
226         else if (value instanceof Collection) {
227             return (Collection) value;
228         }
229         else if (value instanceof Map) {
230             Map map = (Map) value;
231             return map.entrySet();
232         }
233         else if (value.getClass().isArray()) {
234             if (value.getClass().getComponentType().isPrimitive()) {
235                 return InvokerHelper.primitiveArrayToList(value);
236             }
237             return Arrays.asList((Object[]) value);
238         }
239         else if (value instanceof MethodClosure) {
240             MethodClosure method = (MethodClosure) value;
241             IteratorClosureAdapter adapter = new IteratorClosureAdapter(method.getDelegate());
242             method.call(adapter);
243             return adapter.asList();
244         }
245         else if (value instanceof String) {
246             return DefaultGroovyMethods.toList((String) value);
247         }
248         else if (value instanceof File) {
249             try {
250                 return DefaultGroovyMethods.readLines((File) value);
251             }
252             catch (IOException e) {
253                 throw new GroovyRuntimeException("Error reading file: " + value, e);
254             }
255         }
256         else {
257             // lets assume its a collection of 1
258             return Collections.singletonList(value);
259         }
260     }
261 
262     public Iterator asIterator(Object value) {
263         if (value == null) {
264             Collections.EMPTY_LIST.iterator();
265         }
266         if (value instanceof Iterator) {
267             return (Iterator) value;
268         }
269         if (value instanceof NodeList) {
270             final NodeList nodeList = (NodeList) value;
271             return new Iterator() {
272                 private int current = 0;
273                 public boolean hasNext() {
274                     	return current < nodeList.getLength();
275                 }
276                 public Object next() { 
277                     	Node node = nodeList.item(current++);
278                     	return node;
279                 }
280                 public void remove() {
281                     throw new UnsupportedOperationException("Cannot remove() from an Enumeration");
282                 }
283             };
284         }
285         else if (value instanceof Enumeration) {
286             final Enumeration enumeration = (Enumeration) value;
287             return new Iterator() {
288                 private Object last;
289 
290                 public boolean hasNext() {
291                     return enumeration.hasMoreElements();
292                 }
293 
294                 public Object next() {
295                     last = enumeration.nextElement();
296                     return last;
297                 }
298 
299                 public void remove() {
300                     throw new UnsupportedOperationException("Cannot remove() from an Enumeration");
301                 }
302             };
303         }
304         else if (value instanceof Matcher) {
305             final Matcher matcher = (Matcher) value;
306             return new Iterator() {
307                 private boolean found = false;
308                 private boolean done = false;
309                 public boolean hasNext() {
310                     if (done)
311                         return false;
312                     if (!found) {
313                         found = matcher.find();
314                         if (!found)
315                             done = true;
316                     }
317                     return found;
318                 }
319                 public Object next() {
320                     if (!found) {
321                         if (!hasNext()) {
322                             throw new NoSuchElementException();
323                         }
324                     }
325                     found = false;
326                     return matcher.group();
327                 }
328                 public void remove() {
329                     throw new UnsupportedOperationException();
330                 }
331             };
332         }
333         else {
334             try {
335                 // lets try see if there's an iterator() method
336                 final Method method = value.getClass().getMethod("iterator", EMPTY_TYPES);
337                  
338                 if (method != null) {                  
339 	            		AccessController.doPrivileged(new PrivilegedAction() {
340 	    					public Object run() {
341 	    						method.setAccessible(true);
342 	    						return null;
343 	    					}
344 	    				});
345             		
346                     return (Iterator) method.invoke(value, EMPTY_ARGUMENTS);
347                 }
348             }
349             catch (Exception e) {
350             		//  ignore
351             }
352         }
353         return asCollection(value).iterator();
354     }
355 
356     /***
357      * @return true if the two objects are null or the objects are equal
358      */
359     public boolean objectsEqual(Object left, Object right) {
360         if (left == right) {
361             return true;
362         }
363         if (left != null) {
364             if (right == null) {
365                 return false;
366             }
367             if (left instanceof Comparable) {
368                 return compareTo(left, right) == 0;
369             }
370             else {
371                 return left.equals(right);
372             }
373         }
374         return false;
375     }
376 
377     public String inspect(Object self) {
378         return format(self, true);
379     }
380 
381     /***
382      * Compares the two objects handling nulls gracefully and performing numeric type coercion if required
383      */
384     public int compareTo(Object left, Object right) {
385         //System.out.println("Comparing: " + left + " to: " + right);
386         if (left == right) {
387             return 0;
388         }
389         if (left == null) {
390             return -1;
391         }
392         else if (right == null) {
393             return 1;
394         }
395         if (left instanceof Comparable) {
396             if (left instanceof Number) {
397                 if (isValidCharacterString(right)) {
398                     return asCharacter((Number) left).compareTo(asCharacter((String) right));
399                 }
400                 return DefaultGroovyMethods.compareTo((Number) left, asNumber(right));
401             }
402             else if (left instanceof Character) {
403                 if (isValidCharacterString(right)) {
404                     return ((Character) left).compareTo(asCharacter((String) right));
405                 }
406                 else if (right instanceof Number) {
407                     return ((Character) left).compareTo(asCharacter((Number) right));
408                 }
409             }
410             else if (right instanceof Number) {
411                 if (isValidCharacterString(left)) {
412                     return asCharacter((String) left).compareTo(asCharacter((Number) right));
413                 }
414                 return DefaultGroovyMethods.compareTo(asNumber(left), (Number) right);
415             }
416             else if (left instanceof String && right instanceof Character) {
417                 return ((String)left).compareTo(right.toString());
418             }
419             Comparable comparable = (Comparable) left;
420             return comparable.compareTo(right);
421         }
422         if (left.getClass().isArray()) {
423             Collection leftList = asCollection(left);
424             if (right.getClass().isArray()) {
425                 right = asCollection(right);
426             }
427             return ((Comparable) leftList).compareTo(right);
428         }
429         /*** todo we might wanna do some type conversion here */
430         throw new GroovyRuntimeException("Cannot compare values: " + left + " and " + right);
431     }
432 
433     /***
434      * A helper method to provide some better toString() behaviour such as turning arrays
435      * into tuples
436      */
437     public String toString(Object arguments) {
438         return format(arguments, false);
439     }
440 
441     /***
442 	 * A helper method to format the arguments types as a comma-separated list
443 	 */
444 	public String toTypeString(Object[] arguments) {
445 		if (arguments == null) {
446 			return "null";
447 		}
448 	    StringBuffer argBuf = new StringBuffer();
449 	    for (int i = 0; i < arguments.length; i++) {
450 	    	if (i>0)
451                 argBuf.append(", ");
452 			argBuf.append(arguments[i] != null ? arguments[i].getClass().getName() : "null");
453 		}
454 	    return argBuf.toString();
455 	}
456     
457     protected String format(Object arguments, boolean verbose) {
458         if (arguments == null) {
459             return "null";
460         }
461         else if (arguments.getClass().isArray()) {
462             return format(asCollection(arguments), verbose);
463         }
464         else if (arguments instanceof Range) {
465             Range range = (Range) arguments;
466             if (verbose) {
467                 return range.inspect();
468             }
469             else {
470                 return range.toString();
471             }
472         }
473         else if (arguments instanceof List) {
474             List list = (List) arguments;
475             StringBuffer buffer = new StringBuffer("[");
476             boolean first = true;
477             for (Iterator iter = list.iterator(); iter.hasNext();) {
478                 if (first) {
479                     first = false;
480                 }
481                 else {
482                     buffer.append(", ");
483                 }
484                 buffer.append(format(iter.next(), verbose));
485             }
486             buffer.append("]");
487             return buffer.toString();
488         }
489         else if (arguments instanceof Map) {
490             Map map = (Map) arguments;
491             if (map.isEmpty()) {
492                 return "[:]";
493             }
494             StringBuffer buffer = new StringBuffer("[");
495             boolean first = true;
496             for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
497                 if (first) {
498                     first = false;
499                 }
500                 else {
501                     buffer.append(", ");
502                 }
503                 Map.Entry entry = (Map.Entry) iter.next();
504                 buffer.append(format(entry.getKey(), verbose));
505                 buffer.append(":");
506                 buffer.append(format(entry.getValue(), verbose));
507             }
508             buffer.append("]");
509             return buffer.toString();
510         }
511         else if (arguments instanceof Element) {
512             Element node = (Element) arguments;
513             OutputFormat format = new OutputFormat(node.getOwnerDocument());
514             format.setOmitXMLDeclaration(true);
515             format.setIndenting(true);
516             format.setLineWidth(0);             
517             format.setPreserveSpace(true);
518             StringWriter sw = new StringWriter();
519             XMLSerializer serializer = new XMLSerializer (sw, format);
520             try {
521                 serializer.asDOMSerializer();
522                 serializer.serialize(node);
523             } catch (IOException e) {
524             }
525             return sw.toString();
526         }
527         else if (arguments instanceof String) {
528             if (verbose) {
529                 return "\"" + arguments + "\"";
530             }
531             else {
532                 return (String) arguments;
533             }
534         }
535         else {
536             return arguments.toString();
537         }
538     }
539 
540     /***
541      * Sets the property on the given object
542      * 
543      * @param object
544      * @param property
545      * @param newValue
546      * @return
547      */
548     public void setProperty(Object object, String property, Object newValue) {
549         if (object == null) {
550             throw new GroovyRuntimeException("Cannot set property on null object");
551         }
552         else if (object instanceof GroovyObject) {
553             GroovyObject pogo = (GroovyObject) object;
554             pogo.setProperty(property, newValue);
555         }
556         else if (object instanceof Map) {
557             Map map = (Map) object;
558             map.put(property, newValue);
559         }
560         else {
561             metaRegistry.getMetaClass(object.getClass()).setProperty(object, property, newValue);
562         }
563     }
564 
565     /***
566      * Looks up the given property of the given object
567      * 
568      * @param object
569      * @param property
570      * @return
571      */
572     public Object getProperty(Object object, String property) {
573         if (object == null) {
574             throw new NullPointerException("Cannot get property: " + property + " on null object");
575         }
576         else if (object instanceof GroovyObject) {
577             GroovyObject pogo = (GroovyObject) object;
578             return pogo.getProperty(property);
579         }
580         else if (object instanceof Map) {
581             Map map = (Map) object;
582             return map.get(property);
583         }
584         else {
585             return metaRegistry.getMetaClass(object.getClass()).getProperty(object, property);
586         }
587     }
588 
589     public int asInt(Object value) {
590         if (value instanceof Number) {
591             Number n = (Number) value;
592             return n.intValue();
593         }
594         throw new GroovyRuntimeException("Could not convert object: " + value + " into an int");
595     }
596 
597     public Number asNumber(Object value) {
598         if (value instanceof Number) {
599             return (Number) value;
600         }
601         else if (value instanceof String) {
602             String s = (String) value;
603 
604             if (s.length() == 1)
605                 return new Integer(s.charAt(0));
606             else
607                 return Double.valueOf(s);
608         }
609         else if (value instanceof Character) {
610             return new Integer(((Character) value).charValue());
611         }
612         else {
613             throw new GroovyRuntimeException("Could not convert object: " + value + " into a Number");
614         }
615     }
616 
617     /***
618      * Attempts to load the given class via name using the current class loader
619      * for this code or the thread context class loader
620      */
621     protected Class loadClass(String type) {
622         try {
623             return getClass().getClassLoader().loadClass(type);
624         }
625         catch (ClassNotFoundException e) {
626             try {
627                 return Thread.currentThread().getContextClassLoader().loadClass(type);
628             }
629             catch (ClassNotFoundException e2) {
630                 try {
631                     return Class.forName(type);
632                 }
633                 catch (ClassNotFoundException e3) {
634                 }
635             }
636             throw new GroovyRuntimeException("Could not load type: " + type, e);
637         }
638     }
639 
640     /***
641      * Find the right hand regex within the left hand string and return a matcher.
642      * 
643      * @param left string to compare
644      * @param right regular expression to compare the string to
645      * @return
646      */
647     public Matcher objectFindRegex(Object left, Object right) {
648         String stringToCompare;
649         if (left instanceof String) {
650             stringToCompare = (String) left;
651         }
652         else {
653             stringToCompare = toString(left);
654         }
655         String regexToCompareTo;
656         if (right instanceof String) {
657             regexToCompareTo = (String) right;
658         }
659         else if (right instanceof Pattern) {
660             Pattern pattern = (Pattern) right;
661             return pattern.matcher(stringToCompare);
662         }
663         else {
664             regexToCompareTo = toString(right);
665         }
666         Matcher matcher = Pattern.compile(regexToCompareTo).matcher(stringToCompare);
667         return matcher;
668     }
669 
670     /***
671      * Find the right hand regex within the left hand string and return a matcher.
672      * 
673      * @param left string to compare
674      * @param right regular expression to compare the string to
675      * @return
676      */
677     public boolean objectMatchRegex(Object left, Object right) {
678         Pattern pattern;
679         if (right instanceof Pattern) {
680             pattern = (Pattern) right;
681         }
682         else {
683             pattern = Pattern.compile(toString(right));
684         }
685         String stringToCompare = toString(left);
686         Matcher matcher = pattern.matcher(stringToCompare);
687         RegexSupport.setLastMatcher(matcher);
688         return matcher.matches();
689     }
690 
691     /***
692      * Compile a regular expression from a string.
693      * 
694      * @param regex
695      * @return
696      */
697     public Pattern regexPattern(Object regex) {
698         return Pattern.compile(regex.toString());
699     }
700 
701     public Object asType(Object object, Class type) {
702         if (object == null) {
703             return null;
704         }
705         if (type.isInstance(object)) {
706             return object;
707         }
708         if (type.equals(String.class)) {
709             return object.toString();
710         }
711         if (type.equals(Character.class)) {
712             if (object instanceof Number) {
713                 return asCharacter((Number) object);
714             }
715             else {
716                 String text = object.toString();
717                 if (text.length() == 1) {
718                     return new Character(text.charAt(0));
719                 }
720                 else {
721                     throw new ClassCastException("Cannot cast: " + text + " to a Character");
722                 }
723             }
724         }
725         if (Number.class.isAssignableFrom(type)) {
726             if (object instanceof Character) {
727                 return new Integer(((Character) object).charValue());
728             }
729             else if (object instanceof String) {
730                 String c = (String) object;
731                 if (c.length() == 1) {
732                     return new Integer(c.charAt(0));
733                 }
734                 else {
735                     throw new ClassCastException("Cannot cast: '" + c + "' to an Integer");
736                 }
737             }
738         }
739         if (object instanceof Number) {
740             Number n = (Number) object;
741             if (type.isPrimitive()) {
742                 if (type == byte.class) {
743                     return new Byte(n.byteValue());
744                 }
745                 if (type == char.class) {
746                     return new Character((char) n.intValue());
747                 }
748                 if (type == short.class) {
749                     return new Short(n.shortValue());
750                 }
751                 if (type == int.class) {
752                     return new Integer(n.intValue());
753                 }
754                 if (type == long.class) {
755                     return new Long(n.longValue());
756                 }
757                 if (type == float.class) {
758                     return new Float(n.floatValue());
759                 }
760                 if (type == double.class) {
761                     Double answer = new Double(n.doubleValue());
762                     //throw a runtime exception if conversion would be out-of-range for the type.
763                     if (!(n instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
764                             || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
765                         throw new  GroovyRuntimeException("Automatic coercion of "+n.getClass().getName()
766                                 +" value "+n+" to double failed.  Value is out of range.");
767                     }
768                     return answer;
769                 }
770             }
771             else {
772                 if (Number.class.isAssignableFrom(type)) {
773                     if (type == Byte.class) {
774                         return new Byte(n.byteValue());
775                     }
776                     if (type == Character.class) {
777                         return new Character((char) n.intValue());
778                     }
779                     if (type == Short.class) {
780                         return new Short(n.shortValue());
781                     }
782                     if (type == Integer.class) {
783                         return new Integer(n.intValue());
784                     }
785                     if (type == Long.class) {
786                         return new Long(n.longValue());
787                     }
788                     if (type == Float.class) {
789                         return new Float(n.floatValue());
790                     }
791                     if (type == Double.class) {
792                         Double answer = new Double(n.doubleValue());
793                         //throw a runtime exception if conversion would be out-of-range for the type.
794                         if (!(n instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
795                                 || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
796                             throw new  GroovyRuntimeException("Automatic coercion of "+n.getClass().getName()
797                                     +" value "+n+" to double failed.  Value is out of range.");
798                         }
799                         return answer;
800                     }
801 
802                 }
803             }
804         }
805         if (type == Boolean.class) {
806             return asBool(object) ? Boolean.TRUE : Boolean.FALSE;
807         }
808         return object;
809     }
810 
811     public boolean asBool(Object object) {
812        if (object instanceof Boolean) {
813             Boolean booleanValue = (Boolean) object;
814             return booleanValue.booleanValue();
815         }
816         else if (object instanceof Matcher) {
817             Matcher matcher = (Matcher) object;
818             RegexSupport.setLastMatcher(matcher);
819             return matcher.find();
820         }
821         else if (object instanceof Collection) {
822             Collection collection = (Collection) object;
823             return !collection.isEmpty();
824         }
825         else if (object instanceof Number) {
826             Number n = (Number) object;
827             return n.intValue() != 0;
828         }
829         else {
830             return object != null;
831         }
832     }
833 
834     protected Character asCharacter(Number value) {
835         return new Character((char) value.intValue());
836     }
837 
838     protected Character asCharacter(String text) {
839         return new Character(text.charAt(0));
840     }
841 
842     /***
843      * @return true if the given value is a valid character string (i.e. has length of 1)
844      */
845     protected boolean isValidCharacterString(Object value) {
846         if (value instanceof String) {
847             String s = (String) value;
848             if (s.length() == 1) {
849                 return true;
850             }
851         }
852         return false;
853     }
854 
855 }