View Javadoc

1   /*
2    $Id: Invoker.java,v 1.65 2004/12/27 21:38:38 spullara 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.*;
49  import org.apache.xml.serialize.OutputFormat;
50  import org.apache.xml.serialize.XMLSerializer;
51  import org.w3c.dom.Element;
52  import org.w3c.dom.Node;
53  import org.w3c.dom.NodeList;
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.*;
62  import java.util.regex.Matcher;
63  import java.util.regex.Pattern;
64  
65  /***
66   * A helper class to invoke methods or extract properties on arbitrary Java objects dynamically
67   *
68   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
69   * @version $Revision: 1.65 $
70   */
71  public class Invoker {
72  
73      protected static final Object[] EMPTY_ARGUMENTS = {
74      };
75      protected static final Class[] EMPTY_TYPES = {
76      };
77  
78      public MetaClassRegistry getMetaRegistry() {
79          return metaRegistry;
80      }
81  
82      private MetaClassRegistry metaRegistry = new MetaClassRegistry();
83  
84      public MetaClass getMetaClass(Object object) {
85          return metaRegistry.getMetaClass(object.getClass());
86      }
87  
88      /***
89       * Invokes the given method on the object.
90       *
91       * @param object
92       * @param methodName
93       * @param arguments
94       * @return
95       */
96      public Object invokeMethod(Object object, String methodName, Object arguments) {
97          /*
98          System
99              .out
100             .println(
101                 "Invoker - Invoking method on object: "
102                     + object
103                     + " method: "
104                     + methodName
105                     + " arguments: "
106                     + InvokerHelper.toString(arguments));
107                     */
108 
109         if (object == null) {
110             throw new NullPointerException("Cannot invoke method: " + methodName + " on null object");
111         }
112 
113         // if the object is a Class, call a static method from that class
114         if (object instanceof Class) {
115             Class theClass = (Class) object;
116             MetaClass metaClass = metaRegistry.getMetaClass(theClass);
117             return metaClass.invokeStaticMethod(object, methodName, asArray(arguments));
118         }
119         else // it's an instance
120         {
121             // if it's not an object implementing GroovyObject (thus not builder, nor a closure)
122             if (!(object instanceof GroovyObject)) {
123                 Class theClass = object.getClass();
124                 MetaClass metaClass = metaRegistry.getMetaClass(theClass);
125                 return metaClass.invokeMethod(object, methodName, asArray(arguments));
126             }
127             // it's an object implementing GroovyObject
128             else
129             {
130                 // if it's a closure, use the closure's invokeMethod()
131                 if (object instanceof Closure) {
132                     Closure closure = (Closure) object;
133                     return closure.invokeMethod(methodName, arguments);
134                 }
135                 // it's some kind of wacky object that overrides invokeMethod() to do some groovy stuff
136                 // (like a proxy, a builder, some custom funny object which controls the invokation mechanism)
137                 else
138                 {
139                     GroovyObject groovy = (GroovyObject) object;
140                     try
141                     {
142                         // if there's a statically typed method or a GDK method
143                         return groovy.getMetaClass().invokeMethod(object, methodName, arguments);
144                     }
145                     catch (MissingMethodException e)
146                     {
147                         if (e.getMethod().equals(methodName) && object.getClass() == e.getType()) {
148                             // in case there's nothing else, invoke the object's own invokeMethod()
149                             return groovy.invokeMethod(methodName, arguments);
150                         } else {
151                             throw e;
152                         }
153                     }
154                 }
155             }
156         }
157     }
158 
159     public Object invokeSuperMethod(Object object, String methodName, Object arguments) {
160         if (object == null) {
161             throw new NullPointerException("Cannot invoke method: " + methodName + " on null object");
162         }
163 
164         Class theClass = object.getClass();
165 
166         MetaClass metaClass = metaRegistry.getMetaClass(theClass.getSuperclass());
167         return metaClass.invokeMethod(object, methodName, asArray(arguments));
168     }
169 
170     public Object invokeStaticMethod(String type, String method, Object arguments) {
171         MetaClass metaClass = metaRegistry.getMetaClass(loadClass(type));
172         List argumentList = asList(arguments);
173         return metaClass.invokeStaticMethod(null, method, asArray(arguments));
174     }
175 
176     public Object invokeConstructor(String type, Object arguments) {
177         //System.out.println("Invoking constructor of type: " + type);
178         return invokeConstructorOf(loadClass(type), arguments);
179     }
180 
181     public Object invokeConstructorOf(Class type, Object arguments) {
182         MetaClass metaClass = metaRegistry.getMetaClass(type);
183         return metaClass.invokeConstructor(asArray(arguments));
184     }
185 
186     /***
187      * Converts the given object into an array; if its an array then just
188      * cast otherwise wrap it in an array
189      */
190     public Object[] asArray(Object arguments) {
191         if (arguments == null) {
192             return EMPTY_ARGUMENTS;
193         }
194         if (arguments instanceof Tuple) {
195             Tuple tuple = (Tuple) arguments;
196             return tuple.toArray();
197         }
198         if (arguments instanceof Object[]) {
199             return (Object[]) arguments;
200         } else {
201             return new Object[]{arguments};
202         }
203     }
204 
205     public List asList(Object value) {
206         if (value == null) {
207             return Collections.EMPTY_LIST;
208         } else if (value instanceof List) {
209             return (List) value;
210         } else if (value.getClass().isArray()) {
211             return Arrays.asList((Object[]) value);
212         } else if (value instanceof Enumeration) {
213             List answer = new ArrayList();
214             for (Enumeration e = (Enumeration) value; e.hasMoreElements();) {
215                 answer.add(e.nextElement());
216             }
217             return answer;
218         } else {
219             // lets assume its a collection of 1
220             return Collections.singletonList(value);
221         }
222     }
223 
224     /***
225      * @param arguments
226      * @return
227      */
228     public Collection asCollection(Object value) {
229         if (value == null) {
230             return Collections.EMPTY_LIST;
231         } else if (value instanceof Collection) {
232             return (Collection) value;
233         } else if (value instanceof Map) {
234             Map map = (Map) value;
235             return map.entrySet();
236         } else if (value.getClass().isArray()) {
237             if (value.getClass().getComponentType().isPrimitive()) {
238                 return InvokerHelper.primitiveArrayToList(value);
239             }
240             return Arrays.asList((Object[]) value);
241         } else if (value instanceof MethodClosure) {
242             MethodClosure method = (MethodClosure) value;
243             IteratorClosureAdapter adapter = new IteratorClosureAdapter(method.getDelegate());
244             method.call(adapter);
245             return adapter.asList();
246         } else if (value instanceof String) {
247             return DefaultGroovyMethods.toList((String) value);
248         } else if (value instanceof File) {
249             try {
250                 return DefaultGroovyMethods.readLines((File) value);
251             } catch (IOException e) {
252                 throw new GroovyRuntimeException("Error reading file: " + value, e);
253             }
254         } else {
255             // lets assume its a collection of 1
256             return Collections.singletonList(value);
257         }
258     }
259 
260     public Iterator asIterator(Object value) {
261         if (value == null) {
262             return Collections.EMPTY_LIST.iterator();
263         }
264         if (value instanceof Iterator) {
265             return (Iterator) value;
266         }
267         if (value instanceof NodeList) {
268             final NodeList nodeList = (NodeList) value;
269             return new Iterator() {
270                 private int current = 0;
271 
272                 public boolean hasNext() {
273                     return current < nodeList.getLength();
274                 }
275 
276                 public Object next() {
277                     Node node = nodeList.item(current++);
278                     return node;
279                 }
280 
281                 public void remove() {
282                     throw new UnsupportedOperationException("Cannot remove() from an Enumeration");
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         } else if (value instanceof Matcher) {
304             final Matcher matcher = (Matcher) value;
305             return new Iterator() {
306                 private boolean found = false;
307                 private boolean done = false;
308 
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 
320                 public Object next() {
321                     if (!found) {
322                         if (!hasNext()) {
323                             throw new NoSuchElementException();
324                         }
325                     }
326                     found = false;
327                     return matcher.group();
328                 }
329 
330                 public void remove() {
331                     throw new UnsupportedOperationException();
332                 }
333             };
334         } else {
335             try {
336                 // lets try see if there's an iterator() method
337                 final Method method = value.getClass().getMethod("iterator", EMPTY_TYPES);
338 
339                 if (method != null) {
340                     AccessController.doPrivileged(new PrivilegedAction() {
341                         public Object run() {
342                             method.setAccessible(true);
343                             return null;
344                         }
345                     });
346 
347                     return (Iterator) method.invoke(value, EMPTY_ARGUMENTS);
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             } else {
370                 return left.equals(right);
371             }
372         }
373         return false;
374     }
375 
376     public String inspect(Object self) {
377         return format(self, true);
378     }
379 
380     /***
381      * Compares the two objects handling nulls gracefully and performing numeric type coercion if required
382      */
383     public int compareTo(Object left, Object right) {
384         //System.out.println("Comparing: " + left + " to: " + right);
385         if (left == right) {
386             return 0;
387         }
388         if (left == null) {
389             return -1;
390         } else if (right == null) {
391             return 1;
392         }
393         if (left instanceof Comparable) {
394             if (left instanceof Number) {
395                 if (isValidCharacterString(right)) {
396                     return asCharacter((Number) left).compareTo(asCharacter((String) right));
397                 }
398                 return DefaultGroovyMethods.compareTo((Number) left, asNumber(right));
399             } else if (left instanceof Character) {
400                 if (isValidCharacterString(right)) {
401                     return ((Character) left).compareTo(asCharacter((String) right));
402                 } else if (right instanceof Number) {
403                     return ((Character) left).compareTo(asCharacter((Number) right));
404                 }
405             } else if (right instanceof Number) {
406                 if (isValidCharacterString(left)) {
407                     return asCharacter((String) left).compareTo(asCharacter((Number) right));
408                 }
409                 return DefaultGroovyMethods.compareTo(asNumber(left), (Number) right);
410             } else if (left instanceof String && right instanceof Character) {
411                 return ((String) left).compareTo(right.toString());
412             }
413             Comparable comparable = (Comparable) left;
414             return comparable.compareTo(right);
415         }
416         if (left.getClass().isArray()) {
417             Collection leftList = asCollection(left);
418             if (right.getClass().isArray()) {
419                 right = asCollection(right);
420             }
421             return ((Comparable) leftList).compareTo(right);
422         }
423         /*** todo we might wanna do some type conversion here */
424         throw new GroovyRuntimeException("Cannot compare values: " + left + " and " + right);
425     }
426 
427     /***
428      * A helper method to provide some better toString() behaviour such as turning arrays
429      * into tuples
430      */
431     public String toString(Object arguments) {
432         return format(arguments, false);
433     }
434 
435     /***
436      * A helper method to format the arguments types as a comma-separated list
437      */
438     public String toTypeString(Object[] arguments) {
439         if (arguments == null) {
440             return "null";
441         }
442         StringBuffer argBuf = new StringBuffer();
443         for (int i = 0; i < arguments.length; i++) {
444             if (i > 0)
445                 argBuf.append(", ");
446             argBuf.append(arguments[i] != null ? arguments[i].getClass().getName() : "null");
447         }
448         return argBuf.toString();
449     }
450 
451     protected String format(Object arguments, boolean verbose) {
452         if (arguments == null) {
453             return "null";
454         } else if (arguments.getClass().isArray()) {
455             return format(asCollection(arguments), verbose);
456         } else if (arguments instanceof Range) {
457             Range range = (Range) arguments;
458             if (verbose) {
459                 return range.inspect();
460             } else {
461                 return range.toString();
462             }
463         } else if (arguments instanceof List) {
464             List list = (List) arguments;
465             StringBuffer buffer = new StringBuffer("[");
466             boolean first = true;
467             for (Iterator iter = list.iterator(); iter.hasNext();) {
468                 if (first) {
469                     first = false;
470                 } else {
471                     buffer.append(", ");
472                 }
473                 buffer.append(format(iter.next(), verbose));
474             }
475             buffer.append("]");
476             return buffer.toString();
477         } else if (arguments instanceof Map) {
478             Map map = (Map) arguments;
479             if (map.isEmpty()) {
480                 return "[:]";
481             }
482             StringBuffer buffer = new StringBuffer("[");
483             boolean first = true;
484             for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
485                 if (first) {
486                     first = false;
487                 } else {
488                     buffer.append(", ");
489                 }
490                 Map.Entry entry = (Map.Entry) iter.next();
491                 buffer.append(format(entry.getKey(), verbose));
492                 buffer.append(":");
493                 buffer.append(format(entry.getValue(), verbose));
494             }
495             buffer.append("]");
496             return buffer.toString();
497         } else if (arguments instanceof Element) {
498             Element node = (Element) arguments;
499             OutputFormat format = new OutputFormat(node.getOwnerDocument());
500             format.setOmitXMLDeclaration(true);
501             format.setIndenting(true);
502             format.setLineWidth(0);
503             format.setPreserveSpace(true);
504             StringWriter sw = new StringWriter();
505             XMLSerializer serializer = new XMLSerializer(sw, format);
506             try {
507                 serializer.asDOMSerializer();
508                 serializer.serialize(node);
509             } catch (IOException e) {
510             }
511             return sw.toString();
512         } else if (arguments instanceof String) {
513             if (verbose) {
514                 return "\"" + arguments + "\"";
515             } else {
516                 return (String) arguments;
517             }
518         } else {
519             return arguments.toString();
520         }
521     }
522 
523     /***
524      * Sets the property on the given object
525      *
526      * @param object
527      * @param property
528      * @param newValue
529      * @return
530      */
531     public void setProperty(Object object, String property, Object newValue) {
532         if (object == null) {
533             throw new GroovyRuntimeException("Cannot set property on null object");
534         } else if (object instanceof GroovyObject) {
535             GroovyObject pogo = (GroovyObject) object;
536             pogo.setProperty(property, newValue);
537         } else if (object instanceof Map) {
538             Map map = (Map) object;
539             map.put(property, newValue);
540         } else {
541             metaRegistry.getMetaClass(object.getClass()).setProperty(object, property, newValue);
542         }
543     }
544 
545     /***
546      * Looks up the given property of the given object
547      *
548      * @param object
549      * @param property
550      * @return
551      */
552     public Object getProperty(Object object, String property) {
553         if (object == null) {
554             throw new NullPointerException("Cannot get property: " + property + " on null object");
555         } else if (object instanceof GroovyObject) {
556             GroovyObject pogo = (GroovyObject) object;
557             return pogo.getProperty(property);
558         } else if (object instanceof Map) {
559             Map map = (Map) object;
560             return map.get(property);
561         } else {
562             return metaRegistry.getMetaClass(object.getClass()).getProperty(object, property);
563         }
564     }
565 
566     public int asInt(Object value) {
567         if (value instanceof Number) {
568             Number n = (Number) value;
569             return n.intValue();
570         }
571         throw new GroovyRuntimeException("Could not convert object: " + value + " into an int");
572     }
573 
574     public Number asNumber(Object value) {
575         if (value instanceof Number) {
576             return (Number) value;
577         } else if (value instanceof String) {
578             String s = (String) value;
579 
580             if (s.length() == 1)
581                 return new Integer(s.charAt(0));
582             else
583                 return Double.valueOf(s);
584         } else if (value instanceof Character) {
585             return new Integer(((Character) value).charValue());
586         } else {
587             throw new GroovyRuntimeException("Could not convert object: " + value + " into a Number");
588         }
589     }
590 
591     /***
592      * Attempts to load the given class via name using the current class loader
593      * for this code or the thread context class loader
594      */
595     protected Class loadClass(String type) {
596         try {
597             return getClass().getClassLoader().loadClass(type);
598         } catch (ClassNotFoundException e) {
599             try {
600                 return Thread.currentThread().getContextClassLoader().loadClass(type);
601             } catch (ClassNotFoundException e2) {
602                 try {
603                     return Class.forName(type);
604                 } catch (ClassNotFoundException e3) {
605                 }
606             }
607             throw new GroovyRuntimeException("Could not load type: " + type, e);
608         }
609     }
610 
611     /***
612      * Find the right hand regex within the left hand string and return a matcher.
613      *
614      * @param left  string to compare
615      * @param right regular expression to compare the string to
616      * @return
617      */
618     public Matcher objectFindRegex(Object left, Object right) {
619         String stringToCompare;
620         if (left instanceof String) {
621             stringToCompare = (String) left;
622         } else {
623             stringToCompare = toString(left);
624         }
625         String regexToCompareTo;
626         if (right instanceof String) {
627             regexToCompareTo = (String) right;
628         } else if (right instanceof Pattern) {
629             Pattern pattern = (Pattern) right;
630             return pattern.matcher(stringToCompare);
631         } else {
632             regexToCompareTo = toString(right);
633         }
634         Matcher matcher = Pattern.compile(regexToCompareTo).matcher(stringToCompare);
635         return matcher;
636     }
637 
638     /***
639      * Find the right hand regex within the left hand string and return a matcher.
640      *
641      * @param left  string to compare
642      * @param right regular expression to compare the string to
643      * @return
644      */
645     public boolean objectMatchRegex(Object left, Object right) {
646         Pattern pattern;
647         if (right instanceof Pattern) {
648             pattern = (Pattern) right;
649         } else {
650             pattern = Pattern.compile(toString(right));
651         }
652         String stringToCompare = toString(left);
653         Matcher matcher = pattern.matcher(stringToCompare);
654         RegexSupport.setLastMatcher(matcher);
655         return matcher.matches();
656     }
657 
658     /***
659      * Compile a regular expression from a string.
660      *
661      * @param regex
662      * @return
663      */
664     public Pattern regexPattern(Object regex) {
665         return Pattern.compile(regex.toString());
666     }
667 
668     public Object asType(Object object, Class type) {
669         if (object == null) {
670             return null;
671         }
672         if (type.isInstance(object)) {
673             return object;
674         }
675         if (type.equals(String.class)) {
676             return object.toString();
677         }
678         if (type.equals(Character.class)) {
679             if (object instanceof Number) {
680                 return asCharacter((Number) object);
681             } else {
682                 String text = object.toString();
683                 if (text.length() == 1) {
684                     return new Character(text.charAt(0));
685                 } else {
686                     throw new ClassCastException("Cannot cast: " + text + " to a Character");
687                 }
688             }
689         }
690         if (Number.class.isAssignableFrom(type)) {
691             if (object instanceof Character) {
692                 return new Integer(((Character) object).charValue());
693             } else if (object instanceof String) {
694                 String c = (String) object;
695                 if (c.length() == 1) {
696                     return new Integer(c.charAt(0));
697                 } else {
698                     throw new ClassCastException("Cannot cast: '" + c + "' to an Integer");
699                 }
700             }
701         }
702         if (object instanceof Number) {
703             Number n = (Number) object;
704             if (type.isPrimitive()) {
705                 if (type == byte.class) {
706                     return new Byte(n.byteValue());
707                 }
708                 if (type == char.class) {
709                     return new Character((char) n.intValue());
710                 }
711                 if (type == short.class) {
712                     return new Short(n.shortValue());
713                 }
714                 if (type == int.class) {
715                     return new Integer(n.intValue());
716                 }
717                 if (type == long.class) {
718                     return new Long(n.longValue());
719                 }
720                 if (type == float.class) {
721                     return new Float(n.floatValue());
722                 }
723                 if (type == double.class) {
724                     Double answer = new Double(n.doubleValue());
725                     //throw a runtime exception if conversion would be out-of-range for the type.
726                     if (!(n instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
727                             || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
728                         throw new GroovyRuntimeException("Automatic coercion of " + n.getClass().getName()
729                                 + " value " + n + " to double failed.  Value is out of range.");
730                     }
731                     return answer;
732                 }
733             } else {
734                 if (Number.class.isAssignableFrom(type)) {
735                     if (type == Byte.class) {
736                         return new Byte(n.byteValue());
737                     }
738                     if (type == Character.class) {
739                         return new Character((char) n.intValue());
740                     }
741                     if (type == Short.class) {
742                         return new Short(n.shortValue());
743                     }
744                     if (type == Integer.class) {
745                         return new Integer(n.intValue());
746                     }
747                     if (type == Long.class) {
748                         return new Long(n.longValue());
749                     }
750                     if (type == Float.class) {
751                         return new Float(n.floatValue());
752                     }
753                     if (type == Double.class) {
754                         Double answer = new Double(n.doubleValue());
755                         //throw a runtime exception if conversion would be out-of-range for the type.
756                         if (!(n instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
757                                 || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
758                             throw new GroovyRuntimeException("Automatic coercion of " + n.getClass().getName()
759                                     + " value " + n + " to double failed.  Value is out of range.");
760                         }
761                         return answer;
762                     }
763 
764                 }
765             }
766         }
767         if (type == Boolean.class) {
768             return asBool(object) ? Boolean.TRUE : Boolean.FALSE;
769         }
770         return object;
771     }
772 
773     public boolean asBool(Object object) {
774         if (object instanceof Boolean) {
775             Boolean booleanValue = (Boolean) object;
776             return booleanValue.booleanValue();
777         } else if (object instanceof Matcher) {
778             Matcher matcher = (Matcher) object;
779             RegexSupport.setLastMatcher(matcher);
780             return matcher.find();
781         } else if (object instanceof Collection) {
782             Collection collection = (Collection) object;
783             return !collection.isEmpty();
784         } else if (object instanceof Number) {
785             Number n = (Number) object;
786             return n.doubleValue() != 0;
787         } else {
788             return object != null;
789         }
790     }
791 
792     protected Character asCharacter(Number value) {
793         return new Character((char) value.intValue());
794     }
795 
796     protected Character asCharacter(String text) {
797         return new Character(text.charAt(0));
798     }
799 
800     /***
801      * @return true if the given value is a valid character string (i.e. has length of 1)
802      */
803     protected boolean isValidCharacterString(Object value) {
804         if (value instanceof String) {
805             String s = (String) value;
806             if (s.length() == 1) {
807                 return true;
808             }
809         }
810         return false;
811     }
812 
813     public void removeMetaClass(Class clazz) {
814         getMetaRegistry().removeMetaClass(clazz);
815     }
816 }