View Javadoc

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