blob: 06f660bebff1f70a97fd18669fa2280e330516f8 [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.apache.commons.jexl3.internal.introspection;
import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.introspection.JexlMethod;
import org.apache.commons.jexl3.introspection.JexlPropertyGet;
import org.apache.commons.jexl3.introspection.JexlPropertySet;
/**
* Abstract class that is used to execute an arbitrary
* method that is introspected. This is the superclass
* for all other AbstractExecutor classes.
*
* @since 1.0
*/
abstract class AbstractExecutor {
/** A marker for invocation failures in tryInvoke. */
public static final Object TRY_FAILED = JexlEngine.TRY_FAILED;
/**
* A helper to initialize the marker methods (array.get, list.get, etc...).
* @param clazz the class to introspect
* @param name the name of the method
* @param parms the parameters
* @return the method
*/
static java.lang.reflect.Method initMarker(final Class<?> clazz, final String name, final Class<?>... parms) {
try {
return clazz.getMethod(name, parms);
} catch (final Exception xnever) {
throw new Error(xnever);
}
}
/**
* Coerce an Object which must be a number to an Integer.
* @param arg the Object to coerce
* @return an Integer if it can be converted, null otherwise
*/
static Integer castInteger(final Object arg) {
return arg instanceof Number? ((Number) arg).intValue() : null;
}
/**
* Coerce an Object to a String.
* @param arg the Object to coerce
* @return a String if it can be converted, null otherwise
*/
static String castString(final Object arg) {
return arg instanceof CharSequence || arg instanceof Integer ? arg.toString() : null;
}
/**
* Creates an arguments array.
* @param args the list of arguments
* @return the arguments array
*/
static Object[] makeArgs(final Object... args) {
return args;
}
/**
* Gets the class of an object or Object if null.
* @param instance the instance
* @return the class
*/
static Class<?> classOf(final Object instance) {
return instance == null? Object.class : instance.getClass();
}
/** The class this executor applies to. */
protected final Class<?> objectClass;
/** Method to be executed. */
protected final java.lang.reflect.Method method;
/**
* Default and sole constructor.
* @param theClass the class this executor applies to
* @param theMethod the method held by this executor
*/
protected AbstractExecutor(final Class<?> theClass, final java.lang.reflect.Method theMethod) {
objectClass = theClass;
method = theMethod;
}
@Override
public boolean equals(final Object obj) {
return this == obj || (obj instanceof AbstractExecutor && equals((AbstractExecutor) obj));
}
@Override
public int hashCode() {
return method.hashCode();
}
/**
* Indicates whether some other executor is equivalent to this one.
* @param arg the other executor to check
* @return true if both executors are equivalent, false otherwise
*/
public boolean equals(final AbstractExecutor arg) {
// common equality check
if (!this.getClass().equals(arg.getClass())) {
return false;
}
if (!this.getMethod().equals(arg.getMethod())) {
return false;
}
if (!this.getTargetClass().equals(arg.getTargetClass())) {
return false;
}
// specific equality check
final Object lhsp = this.getTargetProperty();
final Object rhsp = arg.getTargetProperty();
if (lhsp == null && rhsp == null) {
return true;
}
if (lhsp != null && rhsp != null) {
return lhsp.equals(rhsp);
}
return false;
}
/**
* Tell whether the executor is alive by looking
* at the value of the method.
*
* @return boolean Whether the executor is alive.
*/
public final boolean isAlive() {
return (method != null);
}
/**
* Specifies if this executor is cacheable and able to be reused for this
* class of object it was returned for.
*
* @return true if can be reused for this class, false if not
*/
public boolean isCacheable() {
return method != null;
}
/**
* Gets the method to be executed or used as a marker.
* @return Method The method used by execute in derived classes.
*/
public final java.lang.reflect.Method getMethod() {
return method;
}
/**
* Gets the object class targeted by this executor.
* @return the target object class
*/
public final Class<?> getTargetClass() {
return objectClass;
}
/**
* Gets the property targeted by this executor.
* @return the target property
*/
public Object getTargetProperty() {
return null;
}
/**
* Gets the method name used.
* @return method name
*/
public final String getMethodName() {
return method.getName();
}
/**
* Checks whether a tryExecute failed or not.
* @param exec the value returned by tryExecute
* @return true if tryExecute failed, false otherwise
*/
public final boolean tryFailed(final Object exec) {
return exec == JexlEngine.TRY_FAILED;
}
/**
* Abstract class that is used to execute an arbitrary 'get' method.
*/
public abstract static class Get extends AbstractExecutor implements JexlPropertyGet {
/**
* Default and sole constructor.
* @param theClass the class this executor applies to
* @param theMethod the method held by this executor
*/
protected Get(final Class<?> theClass, final java.lang.reflect.Method theMethod) {
super(theClass, theMethod);
}
}
/**
* Abstract class that is used to execute an arbitrary 'set' method.
*/
public abstract static class Set extends AbstractExecutor implements JexlPropertySet {
/**
* Default and sole constructor.
* @param theClass the class this executor applies to
* @param theMethod the method held by this executor
*/
protected Set(final Class<?> theClass, final java.lang.reflect.Method theMethod) {
super(theClass, theMethod);
}
}
/**
* Abstract class that is used to execute an arbitrary method.
*/
public abstract static class Method extends AbstractExecutor implements JexlMethod {
/** The method key discovered from the arguments. */
protected final MethodKey key;
/**
* Creates a new instance.
* @param c the class this executor applies to
* @param m the method
* @param k the MethodKey
*/
protected Method(final Class<?> c, final java.lang.reflect.Method m, final MethodKey k) {
super(c, m);
key = k;
}
@Override
public Object getTargetProperty() {
return key;
}
@Override
public final Class<?> getReturnType() {
return method.getReturnType();
}
}
}