blob: 86341049087b91e4a040f9fa81e91b0948403fdb [file] [log] [blame]
/*
* 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.Closure;
import groovy.lang.EmptyRange;
import groovy.lang.GroovyInterceptable;
import groovy.lang.GroovyObject;
import groovy.lang.GroovyRuntimeException;
import groovy.lang.IntRange;
import groovy.lang.MetaClass;
import groovy.lang.MissingMethodException;
import groovy.lang.MissingPropertyException;
import groovy.lang.NumberRange;
import groovy.lang.ObjectRange;
import groovy.lang.Tuple;
import org.codehaus.groovy.runtime.metaclass.MissingMethodExceptionNoStack;
import org.codehaus.groovy.runtime.metaclass.MissingMethodExecutionFailed;
import org.codehaus.groovy.runtime.metaclass.MissingPropertyExceptionNoStack;
import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
import org.codehaus.groovy.runtime.wrappers.GroovyObjectWrapper;
import org.codehaus.groovy.runtime.wrappers.PojoWrapper;
import org.codehaus.groovy.runtime.wrappers.Wrapper;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.BaseStream;
/**
* A static helper class to interface bytecode and runtime
*/
public class ScriptBytecodeAdapter {
public static final Object[] EMPTY_ARGS = {};
private static final Integer ONE = Integer.valueOf(1);
private static final Integer ZERO = Integer.valueOf(0);
private static final Integer MINUS_ONE = Integer.valueOf(-1);
// --------------------------------------------------------
// exception handling
// --------------------------------------------------------
public static Throwable unwrap(GroovyRuntimeException gre) {
if (gre.getCause()==null) {
if (gre instanceof MissingPropertyExceptionNoStack) {
MissingPropertyExceptionNoStack noStack = (MissingPropertyExceptionNoStack) gre;
return new MissingPropertyException(noStack.getProperty(), noStack.getType());
}
if (gre instanceof MissingMethodExceptionNoStack) {
MissingMethodExceptionNoStack noStack = (MissingMethodExceptionNoStack) gre;
return new MissingMethodException(noStack.getMethod(), noStack.getType(), noStack.getArguments(), noStack.isStatic());
}
}
Throwable th = gre;
if (th.getCause() != null && th.getCause() != gre) th = th.getCause();
if (th != gre && (th instanceof GroovyRuntimeException)) return unwrap((GroovyRuntimeException) th);
return th;
}
// --------------------------------------------------------
// methods for this
// --------------------------------------------------------
public static Object invokeMethodOnCurrentN(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable {
try {
boolean intercepting = (receiver instanceof GroovyInterceptable);
try {
if (intercepting) {
return receiver.invokeMethod(messageName, messageArguments);
} else {
return receiver.getMetaClass().invokeMethod(senderClass, receiver, messageName, messageArguments, false, true);
}
} catch (MissingMethodException e) {
if (e instanceof MissingMethodExecutionFailed) {
throw (MissingMethodException)e.getCause();
} else if (!intercepting && receiver.getClass() == e.getType() && e.getMethod().equals(messageName)) {
// in case there's nothing else, invoke the object's own invokeMethod()
return receiver.invokeMethod(messageName, messageArguments);
} else {
throw e;
}
}
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static Object invokeMethodOnCurrentNSafe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable {
return invokeMethodOnCurrentN(senderClass, receiver, messageName, messageArguments);
}
public static Object invokeMethodOnCurrentNSpreadSafe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable {
List<Object> answer = new ArrayList<>();
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
answer.add(invokeMethodNSafe(senderClass, it.next(), messageName, messageArguments));
}
return answer;
}
public static Object invokeMethodOnCurrent0(Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
return invokeMethodOnCurrentN(senderClass, receiver, messageName, EMPTY_ARGS);
}
public static Object invokeMethodOnCurrent0Safe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable {
return invokeMethodOnCurrentNSafe(senderClass, receiver, messageName, EMPTY_ARGS);
}
public static Object invokeMethodOnCurrent0SpreadSafe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable {
return invokeMethodOnCurrentNSpreadSafe(senderClass, receiver, messageName, EMPTY_ARGS);
}
// --------------------------------------------------------
// methods for super
// --------------------------------------------------------
public static Object invokeMethodOnSuperN(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable {
MetaClass metaClass = receiver.getMetaClass();
// ignore interception and missing method fallback
Object result = null;
try {
result = metaClass.invokeMethod(senderClass, receiver, messageName, messageArguments, true, true);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
return result;
}
public static Object invokeMethodOnSuperNSafe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable {
return invokeMethodOnSuperN(senderClass, receiver, messageName, messageArguments);
}
public static Object invokeMethodOnSuperNSpreadSafe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable {
List<Object> answer = new ArrayList<>();
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
answer.add(invokeMethodNSafe(senderClass, it.next(), messageName, messageArguments));
}
return answer;
}
public static Object invokeMethodOnSuper0(Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
return invokeMethodOnSuperN(senderClass, receiver, messageName, EMPTY_ARGS);
}
public static Object invokeMethodOnSuper0Safe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable {
return invokeMethodOnSuperNSafe(senderClass, receiver, messageName, EMPTY_ARGS);
}
public static Object invokeMethodOnSuper0SpreadSafe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable {
return invokeMethodOnSuperNSpreadSafe(senderClass, receiver, messageName, EMPTY_ARGS);
}
// --------------------------------------------------------
// normal method invocation
// --------------------------------------------------------
public static Object invokeMethodN(Class senderClass, Object receiver, String messageName, Object[] messageArguments) throws Throwable {
try {
return InvokerHelper.invokeMethod(receiver, messageName, messageArguments);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static Object invokeMethodNSafe(Class senderClass, Object receiver, String messageName, Object[] messageArguments) throws Throwable {
if (receiver == null) return null;
return invokeMethodN(senderClass, receiver, messageName, messageArguments);
}
public static Object invokeMethodNSpreadSafe(Class senderClass, Object receiver, String messageName, Object[] messageArguments) throws Throwable {
if (receiver == null) return null;
List<Object> answer = new ArrayList<>();
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
answer.add(invokeMethodNSafe(senderClass, it.next(), messageName, messageArguments));
}
return answer;
}
public static Object invokeMethod0(Class senderClass, Object receiver, String messageName) throws Throwable {
return invokeMethodN(senderClass, receiver, messageName, EMPTY_ARGS);
}
public static Object invokeMethod0Safe(Class senderClass, Object receiver, String messageName) throws Throwable {
if (receiver == null) return null;
return invokeMethodNSafe(senderClass, receiver, messageName, EMPTY_ARGS);
}
public static Object invokeMethod0SpreadSafe(Class senderClass, Object receiver, String messageName) throws Throwable {
return invokeMethodNSpreadSafe(senderClass, receiver, messageName, EMPTY_ARGS);
}
// --------------------------------------------------------
// static normal method invocation
// --------------------------------------------------------
public static Object invokeStaticMethodN(Class senderClass, Class receiver, String messageName, Object[] messageArguments) throws Throwable {
try {
return InvokerHelper.invokeStaticMethod(receiver, messageName, messageArguments);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static Object invokeStaticMethod0(Class senderClass, Class receiver, String messageName) throws Throwable {
return invokeStaticMethodN(senderClass, receiver, messageName, EMPTY_ARGS);
}
// --------------------------------------------------------
// normal constructor invocation (via new)
// --------------------------------------------------------
public static Object invokeNewN(Class senderClass, Class receiver, Object arguments) throws Throwable {
try {
return InvokerHelper.invokeConstructorOf(receiver, arguments);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static Object invokeNew0(Class senderClass, Class receiver) throws Throwable {
return invokeNewN(senderClass, receiver, EMPTY_ARGS);
}
// --------------------------------------------------------
// special constructor invocation (via this/super)
// --------------------------------------------------------
public static int selectConstructorAndTransformArguments(Object[] arguments, int numberOfConstructors, Class which) throws Throwable {
try {
MetaClass metaClass = InvokerHelper.getMetaClass(which);
return metaClass.selectConstructorAndTransformArguments(numberOfConstructors, arguments);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
// --------------------------------------------------------
// field handling super: get
// --------------------------------------------------------
public static Object getFieldOnSuper(Class senderClass, Object receiver, String messageName) throws Throwable {
try {
if (receiver instanceof Class) {
return InvokerHelper.getAttribute(receiver, messageName);
} else {
MetaClass mc = ((GroovyObject) receiver).getMetaClass();
return mc.getAttribute(senderClass, receiver, messageName, true);
}
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static Object getFieldOnSuperSafe(Class senderClass, Object receiver, String messageName) throws Throwable {
return getFieldOnSuper(senderClass, receiver, messageName);
}
public static Object getFieldOnSuperSpreadSafe(Class senderClass, Object receiver, String messageName) throws Throwable {
List<Object> answer = new ArrayList<>();
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
answer.add(getFieldOnSuper(senderClass, it.next(), messageName));
}
return answer;
}
// --------------------------------------------------------
// field handling super: set
// --------------------------------------------------------
public static void setFieldOnSuper(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable {
try {
if (receiver instanceof Class) {
InvokerHelper.setAttribute(receiver, messageName, messageArgument);
} else {
MetaClass mc = ((GroovyObject) receiver).getMetaClass();
mc.setAttribute(senderClass, receiver, messageName, messageArgument, true, true);
}
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static void setFieldOnSuperSafe(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable {
setFieldOnSuper(messageArgument, senderClass, receiver, messageName);
}
public static void setFieldOnSuperSpreadSafe(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable {
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
setFieldOnSuper(messageArgument, senderClass, it.next(), messageName);
}
}
// --------------------------------------------------------
// normal field handling : get
// --------------------------------------------------------
public static Object getField(Class senderClass, Object receiver, String messageName) throws Throwable {
try {
return InvokerHelper.getAttribute(receiver, messageName);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static Object getFieldSafe(Class senderClass, Object receiver, String messageName) throws Throwable {
if (receiver == null) return null;
return getField(senderClass, receiver, messageName);
}
public static Object getFieldSpreadSafe(Class senderClass, Object receiver, String messageName) throws Throwable {
if (receiver == null) return null;
List<Object> answer = new ArrayList<>();
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
answer.add(getFieldSafe(senderClass, it.next(), messageName));
}
return answer;
}
// --------------------------------------------------------
// normal field handling : set
// --------------------------------------------------------
public static void setField(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable {
try {
InvokerHelper.setAttribute(receiver, messageName, messageArgument);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static void setFieldSafe(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable {
if (receiver == null) return;
setField(messageArgument, senderClass, receiver, messageName);
}
public static void setFieldSpreadSafe(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable {
if (receiver == null) return;
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
setFieldSafe(messageArgument, senderClass, it.next(), messageName);
}
}
// --------------------------------------------------------
// normal GroovyObject field handling : get
// --------------------------------------------------------
public static Object getGroovyObjectField(Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
try {
return receiver.getMetaClass().getAttribute(senderClass, receiver, messageName, false);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static Object getGroovyObjectFieldSafe(Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
if (receiver == null) return null;
try {
return receiver.getMetaClass().getAttribute(senderClass, receiver, messageName, false);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static Object getGroovyObjectFieldSpreadSafe(Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
if (receiver == null) return null;
List<Object> answer = new ArrayList<>();
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
answer.add(getFieldSafe(senderClass, it.next(), messageName));
}
return answer;
}
// --------------------------------------------------------
// normal field handling : set
// --------------------------------------------------------
public static void setGroovyObjectField(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
try {
receiver.getMetaClass().setAttribute(senderClass, receiver, messageName, messageArgument, false, false);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static void setGroovyObjectFieldSafe(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
if (receiver == null) return;
try {
receiver.getMetaClass().setAttribute(receiver, messageName, messageArgument);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static void setGroovyObjectFieldSpreadSafe(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
if (receiver == null) return;
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
setFieldSafe(messageArgument, senderClass, it.next(), messageName);
}
}
// --------------------------------------------------------
// Property handling super: get
// --------------------------------------------------------
public static Object getPropertyOnSuper(Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
try {
return receiver.getMetaClass().getProperty(senderClass, receiver, messageName, true, false);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static Object getPropertyOnSuperSafe(Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
return getPropertyOnSuper(senderClass, receiver, messageName);
}
public static Object getPropertyOnSuperSpreadSafe(Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
List<Object> answer = new ArrayList<>();
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
answer.add(getPropertySafe(senderClass, it.next(), messageName));
}
return answer;
}
// --------------------------------------------------------
// Property handling super: set
// --------------------------------------------------------
public static void setPropertyOnSuper(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
try {
receiver.getMetaClass().setProperty(senderClass, receiver, messageName, messageArgument, true, false);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static void setPropertyOnSuperSafe(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
setPropertyOnSuper(messageArgument, senderClass, receiver, messageName);
}
public static void setPropertyOnSuperSpreadSafe(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
setPropertySafe(messageArgument, senderClass, it.next(), messageName);
}
}
// --------------------------------------------------------
// normal Property handling : get
// --------------------------------------------------------
public static Object getProperty(Class senderClass, Object receiver, String messageName) throws Throwable {
try {
if (receiver instanceof GroovyObject) {
var groovyObject = (GroovyObject) receiver;
return groovyObject.getProperty(messageName);
} else {
MetaClass metaClass = InvokerHelper.getMetaClass(receiver);
return metaClass.getProperty(senderClass, receiver, messageName, false, false);
}
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static Object getPropertySafe(Class senderClass, Object receiver, String messageName) throws Throwable {
if (receiver == null) return null;
return getProperty(senderClass, receiver, messageName);
}
public static Object getPropertySpreadSafe(Class senderClass, Object receiver, String messageName) throws Throwable {
if (receiver == null) return null;
List<Object> answer = new ArrayList<>();
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
answer.add(getPropertySafe(senderClass, it.next(), messageName));
}
return answer;
}
// --------------------------------------------------------
// normal Property handling : set
// --------------------------------------------------------
public static void setProperty(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable {
try {
if (receiver instanceof GroovyObject) {
var groovyObject = (GroovyObject) receiver;
groovyObject.setProperty(messageName, messageArgument);
} else {
MetaClass metaClass = InvokerHelper.getMetaClass(receiver);
metaClass.setProperty(senderClass, receiver, messageName, messageArgument, false, false);
}
} catch (GroovyRuntimeException gre) {
if (gre instanceof MissingPropertyException
&& receiver instanceof GroovyObject
&& GeneratedClosure.class.isAssignableFrom(senderClass)) {
do {
senderClass = senderClass.getEnclosingClass();
} while (GeneratedClosure.class.isAssignableFrom(senderClass));
if (senderClass != receiver.getClass() && senderClass.isInstance(receiver)) { // GROOVY-3142: retry with super sender class?
((GroovyObject) receiver).getMetaClass().setProperty(senderClass, receiver, messageName, messageArgument, false, false);
return;
}
}
throw unwrap(gre);
}
}
public static void setPropertySafe(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable {
if (receiver == null) return;
setProperty(messageArgument, senderClass, receiver, messageName);
}
public static void setPropertySpreadSafe(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable {
if (receiver == null) return;
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
setPropertySafe(messageArgument, senderClass, it.next(), messageName);
}
}
// --------------------------------------------------------
// normal GroovyObject Property handling : get
// --------------------------------------------------------
public static Object getGroovyObjectProperty(Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
try {
return receiver.getProperty(messageName);
} catch (GroovyRuntimeException gre) {
if (gre instanceof MissingPropertyException && senderClass!=receiver.getClass() && senderClass.isInstance(receiver)) {
return receiver.getMetaClass().getProperty(senderClass, receiver, messageName, false, false);
}
throw unwrap(gre);
}
}
public static Object getGroovyObjectPropertySafe(Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
if (receiver == null) return null;
return getGroovyObjectProperty(senderClass, receiver, messageName);
}
public static Object getGroovyObjectPropertySpreadSafe(Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
if (receiver == null) return null;
List<Object> answer = new ArrayList<>();
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
answer.add(getPropertySafe(senderClass, it.next(), messageName));
}
return answer;
}
// --------------------------------------------------------
// normal GroovyObject Property handling : set
// --------------------------------------------------------
public static void setGroovyObjectProperty(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
try {
receiver.setProperty(messageName, messageArgument);
} catch (GroovyRuntimeException gre) { // GROOVY-3142: retry with super sender class?
if (gre instanceof MissingPropertyException && senderClass != receiver.getClass() && senderClass.isInstance(receiver)) {
receiver.getMetaClass().setProperty(senderClass, receiver, messageName, messageArgument, false, false);
return;
}
throw unwrap(gre);
}
}
public static void setGroovyObjectPropertySafe(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
if (receiver == null) return;
receiver.setProperty(messageName, messageArgument);
}
public static void setGroovyObjectPropertySpreadSafe(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable {
if (receiver == null) return;
for (Iterator<?> it = InvokerHelper.asIterator(receiver); it.hasNext();) {
setPropertySafe(messageArgument, senderClass, it.next(), messageName);
}
}
// **********************************************************************************
// **********************************************************************************
// ************** methods not covered by the new MOP **************
// **********************************************************************************
// **********************************************************************************
// --------------------------------------------------------
// Closures
// --------------------------------------------------------
/**
* Returns a method closure for the given object and name.
*
* @param object the object or class providing the method
* @param methodName the method(s) of interest
* @return the resulting Closure
*/
public static Closure getMethodPointer(final Object object, final String methodName) {
return InvokerHelper.getMethodPointer(object, methodName);
}
// TODO: set sender class
public static Object invokeClosure(Object closure, Object[] arguments) throws Throwable {
return invokeMethodN(closure.getClass(), closure, "call", arguments);
}
// --------------------------------------------------------
// type conversion
// --------------------------------------------------------
/**
* Provides a hook for type coercion of the given object to the required type
*
* @param type of object to convert the given object to
* @param object the object to be converted
* @return the original object or a new converted value
* @throws Throwable if the coercion fails
*/
public static Object asType(Object object, Class type) throws Throwable {
if (object == null) object = NullObject.getNullObject();
return invokeMethodN(object.getClass(), object, "asType", new Object[]{type});
}
/**
* Provides a hook for type casting of the given object to the required type
*
* @param type of object to convert the given object to
* @param object the object to be converted
* @return the original object or a new converted value
* @throws Throwable if the type casting fails
*/
public static Object castToType(Object object, Class type) throws Throwable {
return DefaultTypeTransformation.castToType(object, type);
}
public static Tuple createTuple(Object[] array) {
return new Tuple(array);
}
public static List createList(Object[] values) {
return InvokerHelper.createList(values);
}
public static Wrapper createPojoWrapper(Object val, Class clazz) {
return new PojoWrapper(val, clazz);
}
public static Wrapper createGroovyObjectWrapper(GroovyObject val, Class clazz) {
return new GroovyObjectWrapper(val, clazz);
}
public static Map createMap(Object[] values) {
return InvokerHelper.createMap(values);
}
public static List createRange(Object from, Object to, boolean exclusiveLeft, boolean exclusiveRight) throws Throwable {
if (exclusiveLeft && exclusiveRight) {
if (compareEqual(from, to)) {
return new EmptyRange((Comparable) from);
}
Object tmpFrom;
if (compareLessThan(from, to)) {
tmpFrom = invokeMethod0(ScriptBytecodeAdapter.class, from, "next");
} else {
tmpFrom = invokeMethod0(ScriptBytecodeAdapter.class, from, "previous");
}
// Create an empty range if the difference between from and to is one and they have the same sign. This
// means that range syntaxes like 5<..<6 will result in an empty range, but 0<..<-1 won't, since the latter
// is used in list indexing where negative indices count from the end towards the beginning. Note that
// positive numbers and zeros are considered to have the same sign to make ranges like 0<..<1 be EmptyRanges
int fromComp = compareTo(from, 0);
int toComp = compareTo(to, 0);
boolean sameSign = (fromComp >= 0 && toComp >= 0) || (fromComp < 0 && toComp < 0);
if (compareEqual(tmpFrom, to) && sameSign) {
return new EmptyRange((Comparable) from);
}
}
if ((exclusiveLeft || exclusiveRight) && compareEqual(from, to)) {
return new EmptyRange((Comparable) from);
}
if (from instanceof Integer && to instanceof Integer) {
// Currently, empty ranges where from != to, the range is full exclusive (e.g. 0<..<-1) and from and to
// have a different sign are constructed as IntRanges. This is because these ranges can still be used to
// index into lists.
return new IntRange(!exclusiveLeft, !exclusiveRight, (Integer) from, (Integer) to);
}
if (from instanceof Number && to instanceof Number) {
return new NumberRange(comparableNumber((Number) from), comparableNumber((Number) to), !exclusiveLeft, !exclusiveRight);
}
// ObjectRange does not include information about inclusivity, so we need to consider it here
if (exclusiveRight) {
if (compareGreaterThan(from, to)) {
to = invokeMethod0(ScriptBytecodeAdapter.class, to, "next");
} else {
to = invokeMethod0(ScriptBytecodeAdapter.class, to, "previous");
}
}
if (exclusiveLeft) {
if (compareGreaterThan(from, to)) {
from = invokeMethod0(ScriptBytecodeAdapter.class, from, "previous");
} else {
from = invokeMethod0(ScriptBytecodeAdapter.class, from, "next");
}
}
return new ObjectRange((Comparable) from, (Comparable) to);
}
// Kept in for backwards compatibility
public static List createRange(Object from, Object to, boolean inclusive) throws Throwable {
return createRange(from, to, false, !inclusive);
}
@SuppressWarnings("unchecked")
private static <T extends Number & Comparable> T comparableNumber(Number n) {
return (T) n;
}
public static MetaClass initMetaClass(final Object object) {
return InvokerHelper.getMetaClass(object.getClass());
}
//--------------------------------------------------------------------------
//assert
public static void assertFailed(final Object expression, final Object message) {
InvokerHelper.assertFailed(expression, message);
}
//isCase
public static boolean isCase(final Object switchValue, final Object caseExpression) throws Throwable {
if (caseExpression == null) {
return switchValue == null;
}
return DefaultTypeTransformation.castToBoolean(invokeMethodN(caseExpression.getClass(), caseExpression, "isCase", new Object[]{switchValue}));
}
public static boolean isNotCase(final Object switchValue, final Object caseExpression) throws Throwable {
return !isCase(switchValue, caseExpression);
}
//compare
public static boolean compareIdentical(final Object left, final Object right) {
return left == right;
}
public static boolean compareNotIdentical(final Object left, final Object right) {
return left != right;
}
public static boolean compareEqual(final Object left, final Object right) {
if (left == right) return true;
if (left != null && right != null) {
Class leftClass = left.getClass();
if (leftClass == right.getClass()) {
if (leftClass == Integer.class) {
return left.equals(right);
}
if (leftClass == BigDecimal.class) {
return ((BigDecimal) left).compareTo((BigDecimal) right) == 0;
}
if (leftClass == BigInteger.class) {
return ((BigInteger) left).compareTo((BigInteger) right) == 0;
}
if (leftClass == Long.class) {
return left.equals(right);
}
if (leftClass == Double.class) {
return left.equals(right);
}
if (leftClass == Float.class) {
return left.equals(right);
}
if (leftClass == String.class) {
return left.equals(right);
}
if (leftClass == GStringImpl.class) {
return left.equals(right);
}
}
}
return DefaultTypeTransformation.compareEqual(left, right);
}
public static boolean compareNotEqual(final Object left, final Object right) {
return !compareEqual(left, right);
}
public static Integer compareTo(final Object left, final Object right) {
int answer = DefaultTypeTransformation.compareTo(left, right);
if (answer == 0) {
return ZERO;
}
return answer > 0 ? ONE : MINUS_ONE;
}
public static boolean compareLessThan(final Object left, final Object right) {
if (left != null && right != null) {
Class leftClass = left.getClass();
if (leftClass == right.getClass()) {
if (leftClass == Integer.class) {
return (Integer) left < (Integer) right;
}
if (leftClass == BigDecimal.class) {
return ((BigDecimal) left).compareTo((BigDecimal) right) < 0;
}
if (leftClass == BigInteger.class) {
return ((BigInteger) left).compareTo((BigInteger) right) < 0;
}
if (leftClass == Long.class) {
return (Long) left < (Long) right;
}
if (leftClass == Double.class) {
return (Double) left < (Double) right;
}
if (leftClass == Float.class) {
return (Float) left < (Float) right;
}
}
}
return compareTo(left, right) == MINUS_ONE;
}
public static boolean compareLessThanEqual(final Object left, final Object right) {
if (left != null && right != null) {
Class leftClass = left.getClass();
if (leftClass == right.getClass()) {
if (leftClass == Integer.class) {
return (Integer) left <= (Integer) right;
}
if (leftClass == BigDecimal.class) {
return ((BigDecimal) left).compareTo((BigDecimal) right) <= 0;
}
if (leftClass == BigInteger.class) {
return ((BigInteger) left).compareTo((BigInteger) right) <= 0;
}
if (leftClass == Long.class) {
return (Long) left <= (Long) right;
}
if (leftClass == Double.class) {
return (Double) left <= (Double) right;
}
if (leftClass == Float.class) {
return (Float) left <= (Float) right;
}
}
}
Integer result = compareTo(left, right);
return result == MINUS_ONE || result == ZERO;
}
public static boolean compareGreaterThan(final Object left, final Object right) {
if (left != null && right != null) {
Class leftClass = left.getClass();
if (leftClass == right.getClass()) {
if (leftClass == Integer.class) {
return (Integer) left > (Integer) right;
}
if (leftClass == BigDecimal.class) {
return ((BigDecimal) left).compareTo((BigDecimal) right) > 0;
}
if (leftClass == BigInteger.class) {
return ((BigInteger) left).compareTo((BigInteger) right) > 0;
}
if (leftClass == Long.class) {
return (Long) left > (Long) right;
}
if (leftClass == Double.class) {
return (Double) left > (Double) right;
}
if (leftClass == Float.class) {
return (Float) left > (Float) right;
}
}
}
return compareTo(left, right) == ONE;
}
public static boolean compareGreaterThanEqual(final Object left, final Object right) {
if (left != null && right != null) {
Class leftClass = left.getClass();
if (leftClass == right.getClass()) {
if (leftClass == Integer.class) {
return (Integer) left >= (Integer) right;
}
if (leftClass == BigDecimal.class) {
return ((BigDecimal) left).compareTo((BigDecimal) right) >= 0;
}
if (leftClass == BigInteger.class) {
return ((BigInteger) left).compareTo((BigInteger) right) >= 0;
}
if (leftClass == Long.class) {
return (Long) left >= (Long) right;
}
if (leftClass == Double.class) {
return (Double) left >= (Double) right;
}
if (leftClass == Float.class) {
return (Float) left >= (Float) right;
}
}
}
Integer result = compareTo(left, right);
return result == ONE || result == ZERO;
}
//regexpr
public static Matcher findRegex(final Object left, final Object right) throws Throwable {
return InvokerHelper.findRegex(left, right);
}
public static boolean matchRegex(final Object left, final Object right) {
return InvokerHelper.matchRegex(left, right);
}
public static Pattern regexPattern(final Object regex) {
return StringGroovyMethods.bitwiseNegate((CharSequence)regex.toString());
}
//spread
public static Object[] despreadList(final Object[] args, final Object[] spreads, final int[] positions) {
List<Object> ret = new ArrayList<>();
int argsPos = 0, spreadsPos = 0;
for (int position : positions) {
for (; argsPos < position; ++argsPos) {
ret.add(args[argsPos]);
}
Object value = spreads[spreadsPos];
if (value == null) {
ret.add(null);
} else if (value instanceof List) {
ret.addAll((List<?>) value);
} else if (value instanceof Iterable) {
((Iterable<?>) value).forEach(ret::add);
} else if (value instanceof Iterator) {
((Iterator<?>) value).forEachRemaining(ret::add);
} else if (value instanceof BaseStream) {
((BaseStream<?,?>) value).iterator().forEachRemaining(ret::add);
} else if (value.getClass().isArray()) {
ret.addAll(DefaultTypeTransformation.primitiveArrayToList(value));
} else {
String error = "cannot spread the type " + value.getClass().getName() + " with value " + value;
if (value instanceof Map) {
error += ", did you mean to use the spread-map operator instead?";
}
throw new IllegalArgumentException(error);
}
++spreadsPos;
}
for (; argsPos < args.length; ++argsPos) {
ret.add(args[argsPos]);
}
return ret.toArray();
}
public static Object spreadMap(final Object value) {
return InvokerHelper.spreadMap(value);
}
//unary
public static Object unaryMinus(final Object value) throws Throwable {
return InvokerHelper.unaryMinus(value);
}
public static Object unaryPlus(final Object value) throws Throwable {
try {
return InvokerHelper.unaryPlus(value);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
public static Object bitwiseNegate(final Object value) throws Throwable {
try {
return InvokerHelper.bitwiseNegate(value);
} catch (GroovyRuntimeException gre) {
throw unwrap(gre);
}
}
}