defaultgroovymethods.java

来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 1,794 行 · 第 1/5 页

JAVA
1,794
字号
/*
 * $Id: DefaultGroovyMethods.java 4598 2006-12-22 20:21:21Z blackdrag $
 *
 * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
 *
 * Redistribution and use of this software and associated documentation
 * ("Software"), with or without modification, are permitted provided that the
 * following conditions are met:
 *  1. Redistributions of source code must retain copyright statements and
 * notices. Redistributions must also contain a copy of this document.
 *  2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *  3. The name "groovy" must not be used to endorse or promote products
 * derived from this Software without prior written permission of The Codehaus.
 * For written permission, please contact info@codehaus.org.
 *  4. Products derived from this Software may not be called "groovy" nor may
 * "groovy" appear in their names without prior written permission of The
 * Codehaus. "groovy" is a registered trademark of The Codehaus.
 *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
 *
 * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 */
package org.codehaus.groovy.runtime;

import groovy.lang.*;
import groovy.util.CharsetToolkit;
import groovy.util.ClosureComparator;
import groovy.util.OrderBy;

import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
import org.codehaus.groovy.runtime.typehandling.NumberMath;
import org.codehaus.groovy.tools.RootLoader;
import org.w3c.dom.NodeList;

/**
 * This class defines all the new groovy methods which appear on normal JDK
 * classes inside the Groovy environment. Static methods are used with the
 * first parameter the destination class.
 *
 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
 * @author Jeremy Rayner
 * @author Sam Pullara
 * @author Rod Cope
 * @author Guillaume Laforge
 * @author John Wilson
 * @author Hein Meling
 * @author Dierk Koenig
 * @author Pilho Kim
 * @author Marc Guillemot
 * @author Russel Winder
 * @author bing ran
 * @author Jochen Theodorou
 * @version $Revision: 4598 $
 */
public class DefaultGroovyMethods {

    private static final Logger LOG = Logger.getLogger(DefaultGroovyMethods.class.getName());
    private static final Integer ONE = new Integer(1);

    /**
     * Identity check. Since == is overridden in Groovy with the meaning of equality
     * we need some fallback to check for object identity.
     *
     * @param self
     * @param other
     * @return true if self and other are identical, false otherwise
     */
    public static boolean is(Object self, Object other) {
        return self == other;
    }

    /**
     * Allows the closure to be called for the object reference self
     *
     * @param self    the object to have a closure act upon
     * @param closure the closure to call on the object
     * @return result of calling the closure
     */
    public static Object identity(Object self, Closure closure) {
        final Closure clonedClosure = (Closure) closure.clone();
        clonedClosure.setDelegate(self);
        return clonedClosure.call(self);
    }

    /**
     * Allows the subscript operator to be used to lookup dynamic property values.
     * <code>bean[somePropertyNameExpression]</code>. The normal property notation
     * of groovy is neater and more concise but only works with compile-time known
     * property names.
     *
     * @param self the object to act upon
     */
    public static Object getAt(Object self, String property) {
        return InvokerHelper.getProperty(self, property);
    }

    /**
     * Allows the subscript operator to be used to set dynamically named property values.
     * <code>bean[somePropertyNameExpression] = foo</code>. The normal property notation
     * of groovy is neater and more concise but only works with property names which
     * are known at compile time.
     *
     * @param self     the object to act upon
     * @param property the name of the property to set
     * @param newValue the value to set
     */
    public static void putAt(Object self, String property, Object newValue) {
        InvokerHelper.setProperty(self, property, newValue);
    }

    /**
     * Generates a detailed dump string of an object showing its class,
     * hashCode and fields
     */
    public static String dump(Object self) {
        if (self == null) {
            return "null";
        }
        StringBuffer buffer = new StringBuffer("<");
        Class klass = self.getClass();
        buffer.append(klass.getName());
        buffer.append("@");
        buffer.append(Integer.toHexString(self.hashCode()));
        boolean groovyObject = self instanceof GroovyObject;

        /*jes this may be rewritten to use the new getProperties() stuff
         * but the original pulls out private variables, whereas getProperties()
         * does not. What's the real use of dump() here?
         */
        while (klass != null) {
            Field[] fields = klass.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                final Field field = fields[i];
                if ((field.getModifiers() & Modifier.STATIC) == 0) {
                    if (groovyObject && field.getName().equals("metaClass")) {
                        continue;
                    }
                    AccessController.doPrivileged(new PrivilegedAction() {
                        public Object run() {
                            field.setAccessible(true);
                            return null;
                        }
                    });
                    buffer.append(" ");
                    buffer.append(field.getName());
                    buffer.append("=");
                    try {
                        buffer.append(InvokerHelper.toString(field.get(self)));
                    } catch (Exception e) {
                        buffer.append(e);
                    }
                }
            }

            klass = klass.getSuperclass();
        }

        /* here is a different implementation that uses getProperties(). I have left
         * it commented out because it returns a slightly different list of properties;
         * ie it does not return privates. I don't know what dump() really should be doing,
         * although IMO showing private fields is a no-no
         */
        /*
        List props = getProperties(self);
            for(Iterator itr = props.keySet().iterator(); itr.hasNext(); ) {
            String propName = itr.next().toString();

            // the original skipped this, so I will too
            if(pv.getName().equals("metaClass")) continue;
            if(pv.getName().equals("class")) continue;

            buffer.append(" ");
            buffer.append(propName);
            buffer.append("=");
            try {
                buffer.append(InvokerHelper.toString(props.get(propName)));
            }
            catch (Exception e) {
                buffer.append(e);
            }
        }
        */

        buffer.append(">");
        return buffer.toString();
    }

    /**
     * Retrieves the list of {@link MetaProperty} objects for 'self' and wraps it
     * in a list of {@link PropertyValue} objects that additionally provide
     * the value for each property of 'self'.
     *
     * @param self the receiver object
     * @return list of {@link PropertyValue} objects
     * @see groovy.util.Expando#getMetaPropertyValues()
     */
    public static List getMetaPropertyValues(Object self) {
        MetaClass metaClass = InvokerHelper.getMetaClass(self);
        List mps = metaClass.getProperties();
        List props = new ArrayList(mps.size());
        for (Iterator itr = mps.iterator(); itr.hasNext();) {
            MetaProperty mp = (MetaProperty) itr.next();
            PropertyValue pv = new PropertyValue(self, mp);
            props.add(pv);
        }
        return props;
    }

    /**
     * Convenience method that calls {@link #getMetaPropertyValues(Object)}(self)
     * and provides the data in form of simple key/value pairs, i.e. without
     * type() information.
     *
     * @param self the receiver object
     * @return meta properties as Map of key/value pairs
     */
    public static Map getProperties(Object self) {
        List metaProps = getMetaPropertyValues(self);
        Map props = new HashMap(metaProps.size());

        for (Iterator itr = metaProps.iterator(); itr.hasNext();) {
            PropertyValue pv = (PropertyValue) itr.next();
            try {
                props.put(pv.getName(), pv.getValue());
            } catch (Exception e) {
                LOG.throwing(self.getClass().getName(), "getProperty(" + pv.getName() + ")", e);
            }
        }
        return props;
    }

    /**
     * Scoped use method
     */
    public static void use(Object self, Class categoryClass, Closure closure) {
        GroovyCategorySupport.use(categoryClass, closure);
    }

    /**
     * Scoped use method with list of categories
     */
    public static void use(Object self, List categoryClassList, Closure closure) {
        GroovyCategorySupport.use(categoryClassList, closure);
    }


    /**
     * use() a list of categories, specifying the list as varargs:<br>
     * use(CategoryClass1, CategoryClass2) { ... }<br>
     * This method prevents the error of forgetting to wrap the the category
     * classes in a list.
     *
     * @param self
     * @param array
     */
    public static void use(Object self, Object[] array) {
        if (array.length < 2)
            throw new IllegalArgumentException(
                    "Expecting at least 2 arguments, a category class and a Closure");
        Closure closure;
        try {
            closure = (Closure) array[array.length - 1];
        } catch (ClassCastException e) {
            throw new IllegalArgumentException("Expecting a Closure to be the last argument");
        }
        List list = new ArrayList(array.length - 1);
        for (int i = 0; i < array.length - 1; ++i)
            list.add(array[i]);
        GroovyCategorySupport.use(list, closure);
    }

    /**
     * Print to a console in interactive format
     */
    public static void print(Object self, Object value) {
        System.out.print(InvokerHelper.toString(value));
    }

    /**
     * Print a linebreak to the standard out.
     */
    public static void println(Object self) {
        System.out.println();
    }

    /**
     * Print to a console in interactive format along with a newline
     */
    public static void println(Object self, Object value) {
        System.out.println(InvokerHelper.toString(value));
    }

    /**
     * Printf to a console.  Only works with JDK1.5 or later.
     */
    public static void printf(Object self, String format, Object[] values) {
        if (System.getProperty("java.version").charAt(2) == '5') {
            //
            //  Cannot just do:
            //
            //        System.out.printf(format, values) ;
            //
            //  because this fails to compile on JDK1.4.x and earlier.  So until the entire world is using
            //  JDK1.5 or later then we have to do things by reflection so as to hide the use of printf
            //  from the compiler.  In JDK1.5 you might try:
            //
            //        System.out.getClass().getMethod("printf", String.class, Object[].class).invoke(System.out, format, values) ;
            //
            //  but of course this doesn't work on JDK1.4 as it relies on varargs.  argh.  So we are
            //  forced into:
            //
            try {
                System.out.getClass().getMethod("printf", new Class[]{String.class, Object[].class}).invoke(System.out, new Object[]{format, values});
            } catch (NoSuchMethodException nsme) {
                throw new RuntimeException("getMethod threw a NoSuchMethodException.  This is impossible.");
            } catch (IllegalAccessException iae) {
                throw new RuntimeException("invoke threw a IllegalAccessException.  This is impossible.");
            } catch (java.lang.reflect.InvocationTargetException ite) {
                throw new RuntimeException("invoke threw a InvocationTargetException.  This is impossible.");
            }
        } else {
            throw new RuntimeException("printf requires JDK1.5 or later.");
        }
    }

    /**
     * Returns a formatted string using the specified format string and

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?