org.codehaus.groovy.runtime.InvokerHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of groovy Show documentation
Show all versions of groovy Show documentation
Groovy: A powerful, dynamic language for the JVM
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.codehaus.groovy.runtime;
import groovy.lang.Binding;
import groovy.lang.Closure;
import groovy.lang.GString;
import groovy.lang.GroovyInterceptable;
import groovy.lang.GroovyObject;
import groovy.lang.GroovyRuntimeException;
import groovy.lang.GroovySystem;
import groovy.lang.MetaClass;
import groovy.lang.MetaClassRegistry;
import groovy.lang.MissingMethodException;
import groovy.lang.MissingPropertyException;
import groovy.lang.Range;
import groovy.lang.Script;
import groovy.lang.SpreadMap;
import groovy.lang.SpreadMapEvaluatingException;
import groovy.lang.Tuple;
import groovy.lang.Writable;
import org.apache.groovy.io.StringBuilderWriter;
import org.codehaus.groovy.control.ResolveVisitor;
import org.codehaus.groovy.reflection.ClassInfo;
import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl;
import org.codehaus.groovy.runtime.metaclass.MissingMethodExecutionFailed;
import org.codehaus.groovy.runtime.powerassert.PowerAssertionError;
import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
import org.codehaus.groovy.runtime.wrappers.PojoWrapper;
import org.w3c.dom.Element;
import java.beans.Introspector;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.lang.Math.max;
/**
* A static helper class to make bytecode generation easier and act as a facade over the Invoker
*/
public class InvokerHelper {
private static final Object[] EMPTY_MAIN_ARGS = new Object[]{new String[0]};
public static final Object[] EMPTY_ARGS = {};
protected static final Object[] EMPTY_ARGUMENTS = EMPTY_ARGS;
protected static final Class[] EMPTY_TYPES = {};
// heuristic size to pre-alocate stringbuffers for collections of items
private static final int ITEM_ALLOCATE_SIZE = 5;
public static final MetaClassRegistry metaRegistry = GroovySystem.getMetaClassRegistry();
public static final String MAIN_METHOD_NAME = "main";
private static final String XMLUTIL_CLASS_FULL_NAME = "groovy.xml.XmlUtil";
private static final String SERIALIZE_METHOD_NAME = "serialize";
public static void removeClass(Class clazz) {
metaRegistry.removeMetaClass(clazz);
ClassInfo.remove(clazz);
Introspector.flushFromCaches(clazz);
}
public static Object invokeMethodSafe(Object object, String methodName, Object arguments) {
if (object != null) {
return invokeMethod(object, methodName, arguments);
}
return null;
}
public static Object invokeStaticMethod(String klass, String methodName, Object arguments) throws ClassNotFoundException {
Class type = Class.forName(klass);
return invokeStaticMethod(type, methodName, arguments);
}
public static Object invokeStaticNoArgumentsMethod(Class type, String methodName) {
return invokeStaticMethod(type, methodName, EMPTY_ARGS);
}
public static Object invokeConstructorOf(String klass, Object arguments) throws ClassNotFoundException {
Class type = Class.forName(klass);
return invokeConstructorOf(type, arguments);
}
public static Object invokeNoArgumentsConstructorOf(Class type) {
return invokeConstructorOf(type, EMPTY_ARGS);
}
public static Object invokeClosure(Object closure, Object arguments) {
return invokeMethod(closure, "doCall", arguments);
}
public static List asList(Object value) {
if (value == null) {
return Collections.EMPTY_LIST;
}
if (value instanceof List) {
return (List) value;
}
if (value.getClass().isArray()) {
return Arrays.asList((Object[]) value);
}
if (value instanceof Enumeration) {
Enumeration e = (Enumeration) value;
List answer = new ArrayList();
while (e.hasMoreElements()) {
answer.add(e.nextElement());
}
return answer;
}
// let's assume its a collection of 1
return Collections.singletonList(value);
}
public static String toString(Object arguments) {
return format(arguments, false, -1, false);
}
public static String inspect(Object self) {
return format(self, true);
}
public static Object getAttribute(Object object, String attribute) {
if (object == null) {
object = NullObject.getNullObject();
}
if (object instanceof Class) {
return metaRegistry.getMetaClass((Class) object).getAttribute(object, attribute);
} else if (object instanceof GroovyObject) {
return ((GroovyObject) object).getMetaClass().getAttribute(object, attribute);
} else {
return metaRegistry.getMetaClass(object.getClass()).getAttribute(object, attribute);
}
}
public static void setAttribute(Object object, String attribute, Object newValue) {
if (object == null) {
object = NullObject.getNullObject();
}
if (object instanceof Class) {
metaRegistry.getMetaClass((Class) object).setAttribute(object, attribute, newValue);
} else if (object instanceof GroovyObject) {
((GroovyObject) object).getMetaClass().setAttribute(object, attribute, newValue);
} else {
metaRegistry.getMetaClass(object.getClass()).setAttribute(object, attribute, newValue);
}
}
public static Object getProperty(Object object, String property) {
if (object == null) {
object = NullObject.getNullObject();
}
if (object instanceof GroovyObject) {
GroovyObject pogo = (GroovyObject) object;
return pogo.getProperty(property);
} else if (object instanceof Class) {
Class c = (Class) object;
return metaRegistry.getMetaClass(c).getProperty(object, property);
} else {
return ((MetaClassRegistryImpl) metaRegistry).getMetaClass(object).getProperty(object, property);
}
}
public static Object getPropertySafe(Object object, String property) {
if (object != null) {
return getProperty(object, property);
}
return null;
}
public static void setProperty(Object object, String property, Object newValue) {
if (object == null) {
object = NullObject.getNullObject();
}
if (object instanceof GroovyObject) {
GroovyObject pogo = (GroovyObject) object;
pogo.setProperty(property, newValue);
} else if (object instanceof Class) {
metaRegistry.getMetaClass((Class) object).setProperty(object, property, newValue);
} else {
((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(object).setProperty(object, property, newValue);
}
}
/**
* This is so we don't have to reorder the stack when we call this method.
* At some point a better name might be in order.
*/
public static void setProperty2(Object newValue, Object object, String property) {
setProperty(object, property, newValue);
}
/**
* This is so we don't have to reorder the stack when we call this method.
* At some point a better name might be in order.
*/
public static void setGroovyObjectProperty(Object newValue, GroovyObject object, String property) {
object.setProperty(property, newValue);
}
public static Object getGroovyObjectProperty(GroovyObject object, String property) {
return object.getProperty(property);
}
/**
* This is so we don't have to reorder the stack when we call this method.
* At some point a better name might be in order.
*/
public static void setPropertySafe2(Object newValue, Object object, String property) {
if (object != null) {
setProperty2(newValue, object, property);
}
}
/**
* Returns the method pointer for the given object name
*/
public static Closure getMethodPointer(Object object, String methodName) {
if (object == null) {
throw new NullPointerException("Cannot access method pointer for '" + methodName + "' on null object");
}
return new MethodClosure(object, methodName);
}
public static Object unaryMinus(Object value) {
if (value instanceof Integer) {
Integer number = (Integer) value;
return -number;
}
if (value instanceof Long) {
Long number = (Long) value;
return -number;
}
if (value instanceof BigInteger) {
return ((BigInteger) value).negate();
}
if (value instanceof BigDecimal) {
return ((BigDecimal) value).negate();
}
if (value instanceof Double) {
Double number = (Double) value;
return -number;
}
if (value instanceof Float) {
Float number = (Float) value;
return -number;
}
if (value instanceof Short) {
Short number = (Short) value;
return (short) -number;
}
if (value instanceof Byte) {
Byte number = (Byte) value;
return (byte) -number;
}
if (value instanceof ArrayList) {
// value is a list.
List newlist = new ArrayList();
for (Object o : ((ArrayList) value)) {
newlist.add(unaryMinus(o));
}
return newlist;
}
return invokeMethod(value, "negative", EMPTY_ARGS);
}
public static Object unaryPlus(Object value) {
if (value instanceof Integer ||
value instanceof Long ||
value instanceof BigInteger ||
value instanceof BigDecimal ||
value instanceof Double ||
value instanceof Float ||
value instanceof Short ||
value instanceof Byte) {
return value;
}
if (value instanceof ArrayList) {
// value is a list.
List newlist = new ArrayList();
for (Object o : ((ArrayList) value)) {
newlist.add(unaryPlus(o));
}
return newlist;
}
return invokeMethod(value, "positive", EMPTY_ARGS);
}
/**
* Find the right hand regex within the left hand string and return a matcher.
*
* @param left string to compare
* @param right regular expression to compare the string to
*/
public static Matcher findRegex(Object left, Object right) {
String stringToCompare;
if (left instanceof String) {
stringToCompare = (String) left;
} else {
stringToCompare = toString(left);
}
String regexToCompareTo;
if (right instanceof String) {
regexToCompareTo = (String) right;
} else if (right instanceof Pattern) {
Pattern pattern = (Pattern) right;
return pattern.matcher(stringToCompare);
} else {
regexToCompareTo = toString(right);
}
return Pattern.compile(regexToCompareTo).matcher(stringToCompare);
}
/**
* Find the right hand regex within the left hand string and return a matcher.
*
* @param left string to compare
* @param right regular expression to compare the string to
*/
public static boolean matchRegex(Object left, Object right) {
if (left == null || right == null) return false;
Pattern pattern;
if (right instanceof Pattern) {
pattern = (Pattern) right;
} else {
pattern = Pattern.compile(toString(right));
}
String stringToCompare = toString(left);
Matcher matcher = pattern.matcher(stringToCompare);
RegexSupport.setLastMatcher(matcher);
return matcher.matches();
}
public static Tuple createTuple(Object[] array) {
return new Tuple(array);
}
public static SpreadMap spreadMap(Object value) {
if (value instanceof Map) {
Object[] values = new Object[((Map) value).keySet().size() * 2];
int index = 0;
for (Object key : ((Map) value).keySet()) {
values[index++] = key;
values[index++] = ((Map) value).get(key);
}
return new SpreadMap(values);
}
throw new SpreadMapEvaluatingException("Cannot spread the map " + typeName(value) + ", value " + value);
}
public static List createList(Object[] values) {
List answer = new ArrayList(values.length);
// GROOVY-8995: Improve the performance of creating list
// answer.addAll(Arrays.asList(values));
Collections.addAll(answer, values);
return answer;
}
/**
* According to the initial entry count, calculate the initial capacity of hash map, which is power of 2
* (SEE https://stackoverflow.com/questions/8352378/why-does-hashmap-require-that-the-initial-capacity-be-a-power-of-two)
*
* @param initialEntryCnt the initial entry count
* @return the initial capacity
*/
public static int initialCapacity(int initialEntryCnt) {
if (0 == initialEntryCnt) return 16;
return Integer.highestOneBit(initialEntryCnt) << 1;
}
public static Map createMap(Object[] values) {
Map answer = new LinkedHashMap(initialCapacity(values.length / 2));
for (int i = 0, n = values.length; i < n - 1; ) {
if ((values[i] instanceof SpreadMap) && (values[i + 1] instanceof Map)) {
Map smap = (Map) values[i + 1];
for (Object e : smap.entrySet()) {
Map.Entry entry = (Map.Entry) e;
answer.put(entry.getKey(), entry.getValue());
}
i += 2;
} else {
answer.put(values[i++], values[i++]);
}
}
return answer;
}
public static void assertFailed(Object expression, Object message) {
if (message == null || "".equals(message)) {
throw new PowerAssertionError(expression.toString());
}
throw new AssertionError(message + ". Expression: " + expression);
}
public static Object runScript(Class scriptClass, String[] args) {
Binding context = new Binding(args);
Script script = createScript(scriptClass, context);
return invokeMethod(script, "run", EMPTY_ARGS);
}
static class NullScript extends Script {
public NullScript() { this(new Binding()); }
public NullScript(Binding context) { super(context); }
public Object run() { return null; }
}
public static Script createScript(Class scriptClass, Binding context) {
Script script;
if (scriptClass == null) {
script = new NullScript(context);
} else {
try {
if (Script.class.isAssignableFrom(scriptClass)) {
script = newScript(scriptClass, context);
} else {
final GroovyObject object = (GroovyObject) scriptClass.getDeclaredConstructor().newInstance();
// it could just be a class, so let's wrap it in a Script
// wrapper; though the bindings will be ignored
script = new Script(context) {
public Object run() {
Object argsToPass = EMPTY_MAIN_ARGS;
try {
Object args = getProperty("args");
if (args instanceof String[]) {
argsToPass = args;
}
} catch (MissingPropertyException e) {
// They'll get empty args since none exist in the context.
}
object.invokeMethod(MAIN_METHOD_NAME, argsToPass);
return null;
}
};
Map variables = context.getVariables();
MetaClass mc = getMetaClass(object);
for (Object o : variables.entrySet()) {
Map.Entry entry = (Map.Entry) o;
String key = entry.getKey().toString();
// assume underscore variables are for the wrapper script
setPropertySafe(key.startsWith("_") ? script : object, mc, key, entry.getValue());
}
}
} catch (Exception e) {
throw new GroovyRuntimeException(
"Failed to create Script instance for class: "
+ scriptClass + ". Reason: " + e, e);
}
}
return script;
}
public static Script newScript(Class> scriptClass, Binding context) throws InstantiationException, IllegalAccessException, InvocationTargetException {
Script script;
try {
Constructor constructor = scriptClass.getConstructor(Binding.class);
script = (Script) constructor.newInstance(context);
} catch (NoSuchMethodException e) {
// Fallback for non-standard "Script" classes.
script = (Script) scriptClass.newInstance();
script.setBinding(context);
}
return script;
}
/**
* Sets the properties on the given object
*/
public static void setProperties(Object object, Map map) {
MetaClass mc = getMetaClass(object);
for (Object o : map.entrySet()) {
Map.Entry entry = (Map.Entry) o;
String key = entry.getKey().toString();
Object value = entry.getValue();
setPropertySafe(object, mc, key, value);
}
}
private static void setPropertySafe(Object object, MetaClass mc, String key, Object value) {
try {
mc.setProperty(object, key, value);
} catch (MissingPropertyException mpe) {
// Ignore
} catch (InvokerInvocationException iie) {
// GROOVY-5802 IAE for missing properties with classes that extend List
Throwable cause = iie.getCause();
if (!(cause instanceof IllegalArgumentException)) throw iie;
}
}
/**
* Writes an object to a Writer using Groovy's default representation for the object.
*/
public static void write(Writer out, Object object) throws IOException {
if (object instanceof String) {
out.write((String) object);
} else if (object instanceof Object[]) {
out.write(toArrayString((Object[]) object));
} else if (object instanceof Map) {
out.write(toMapString((Map) object));
} else if (object instanceof Collection) {
out.write(toListString((Collection) object));
} else if (object instanceof Writable) {
Writable writable = (Writable) object;
writable.writeTo(out);
} else if (object instanceof InputStream || object instanceof Reader) {
// Copy stream to stream
Reader reader;
if (object instanceof InputStream) {
reader = new InputStreamReader((InputStream) object);
} else {
reader = (Reader) object;
}
try (Reader r = reader) {
char[] chars = new char[8192];
for (int i; (i = r.read(chars)) != -1; ) {
out.write(chars, 0, i);
}
}
} else {
out.write(toString(object));
}
}
/**
* Appends an object to an Appendable using Groovy's default representation for the object.
*/
public static void append(Appendable out, Object object) throws IOException {
if (object instanceof String) {
out.append((String) object);
} else if (object instanceof Object[]) {
out.append(toArrayString((Object[]) object));
} else if (object instanceof Map) {
out.append(toMapString((Map) object));
} else if (object instanceof Collection) {
out.append(toListString((Collection) object));
} else if (object instanceof Writable) {
Writable writable = (Writable) object;
Writer stringWriter = new StringBuilderWriter();
writable.writeTo(stringWriter);
out.append(stringWriter.toString());
} else if (object instanceof InputStream || object instanceof Reader) {
// Copy stream to stream
try (Reader reader =
object instanceof InputStream
? new InputStreamReader((InputStream) object)
: (Reader) object) {
char[] chars = new char[8192];
for (int i; (i = reader.read(chars)) != -1; ) {
for (int j = 0; j < i; j++) {
out.append(chars[j]);
}
}
}
} else {
out.append(toString(object));
}
}
@SuppressWarnings("unchecked")
public static Iterator
© 2015 - 2024 Weber Informatics LLC | Privacy Policy