All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.jexl2.internal.Introspector Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
/*
 * 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.jexl2.internal;

import java.lang.ref.SoftReference;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

import org.apache.commons.jexl2.internal.introspection.IntrospectorBase;
import org.apache.commons.jexl2.internal.introspection.MethodKey;

import org.apache.commons.logging.Log;

/**
 *  Default introspection services.
 *  

Finding methods as well as property getters & setters.

* @since 1.0 */ public class Introspector { /** The logger to use for all warnings & errors. */ protected final Log rlog; /** The soft reference to the introspector currently in use. */ private volatile SoftReference ref; /** * Creates an introspector. * @param log the logger to use for warnings. */ protected Introspector(Log log) { rlog = log; ref = new SoftReference(null); } /** * Coerce an Object to an Integer. * @param arg the Object to coerce * @return an Integer if it can be converted, null otherwise */ protected Integer toInteger(Object arg) { if (arg == null) { return null; } if (arg instanceof Number) { return Integer.valueOf(((Number) arg).intValue()); } try { return Integer.valueOf(arg.toString()); } catch (NumberFormatException xnumber) { return null; } } /** * Coerce an Object to a String. * @param arg the Object to coerce * @return a String if it can be converted, null otherwise */ protected String toString(Object arg) { return arg == null ? null : arg.toString(); } /** * Gets the current introspector base. *

If the reference has been collected, this method will recreate the underlying introspector.

* @return the introspector */ // CSOFF: DoubleCheckedLocking protected final IntrospectorBase base() { IntrospectorBase intro = ref.get(); if (intro == null) { // double checked locking is ok (fixed by Java 5 memory model). synchronized(this) { intro = ref.get(); if (intro == null) { intro = new IntrospectorBase(rlog); ref = new SoftReference(intro); } } } return intro; } // CSON: DoubleCheckedLocking /** * Sets the underlying class loader for class solving resolution. * @param loader the loader to use */ public void setClassLoader(ClassLoader loader) { base().setLoader(loader); } /** * Gets a class by name through this introspector class loader. * @param className the class name * @return the class instance or null if it could not be found */ public Class getClassByName(String className) { return base().getClassByName(className); } /** * Gets the field named by key for the class c. * * @param c Class in which the field search is taking place * @param key Name of the field being searched for * @return a {@link java.lang.reflect.Field} or null if it does not exist or is not accessible * */ public final Field getField(Class c, String key) { return base().getField(c, key); } /** * Gets the accessible field names known for a given class. * @param c the class * @return the class field names */ public final String[] getFieldNames(Class c) { return base().getFieldNames(c); } /** * Gets the method defined by name and * params for the Class c. * * @param c Class in which the method search is taking place * @param name Name of the method being searched for * @param params An array of Objects (not Classes) that describe the * the parameters * * @return a {@link java.lang.reflect.Method} * or null if no unambiguous method could be found through introspection. */ public final Method getMethod(Class c, String name, Object[] params) { return base().getMethod(c, new MethodKey(name, params)); } /** * Gets the method defined by key and for the Class c. * * @param c Class in which the method search is taking place * @param key MethodKey of the method being searched for * * @return a {@link java.lang.reflect.Method} * or null if no unambiguous method could be found through introspection. */ public final Method getMethod(Class c, MethodKey key) { return base().getMethod(c, key); } /** * Gets the accessible methods names known for a given class. * @param c the class * @return the class method names */ public final String[] getMethodNames(Class c) { return base().getMethodNames(c); } /** * Gets all the methods with a given name from this map. * @param c the class * @param methodName the seeked methods name * @return the array of methods */ public final Method[] getMethods(Class c, final String methodName) { return base().getMethods(c, methodName); } /** * Returns a general constructor. * @param ctorHandle the object * @param args contructor arguments * @return a {@link java.lang.reflect.Constructor} * or null if no unambiguous contructor could be found through introspection. */ public final Constructor getConstructor(Object ctorHandle, Object[] args) { String className = null; Class clazz = null; if (ctorHandle instanceof Class) { clazz = (Class) ctorHandle; className = clazz.getName(); } else if (ctorHandle != null) { className = ctorHandle.toString(); } else { return null; } return base().getConstructor(clazz, new MethodKey(className, args)); } /** * Returns a general method. * @param obj the object * @param name the method name * @param args method arguments * @return a {@link AbstractExecutor.Method}. */ public final AbstractExecutor.Method getMethodExecutor(Object obj, String name, Object[] args) { AbstractExecutor.Method me = new MethodExecutor(this, obj, name, args); return me.isAlive() ? me : null; } /** * Return a property getter. * @param obj the object to base the property from. * @param identifier property name * @return a {@link AbstractExecutor.Get}. */ public final AbstractExecutor.Get getGetExecutor(Object obj, Object identifier) { final Class claz = obj.getClass(); final String property = toString(identifier); AbstractExecutor.Get executor; // first try for a getFoo() type of property (also getfoo() ) if (property != null) { executor = new PropertyGetExecutor(this, claz, property); if (executor.isAlive()) { return executor; } //} // look for boolean isFoo() //if (property != null) { executor = new BooleanGetExecutor(this, claz, property); if (executor.isAlive()) { return executor; } } // let's see if we are a map... executor = new MapGetExecutor(this, claz, identifier); if (executor.isAlive()) { return executor; } // let's see if we can convert the identifier to an int, // if obj is an array or a list, we can still do something Integer index = toInteger(identifier); if (index != null) { executor = new ListGetExecutor(this, claz, index); if (executor.isAlive()) { return executor; } } // if that didn't work, look for set("foo") executor = new DuckGetExecutor(this, claz, identifier); if (executor.isAlive()) { return executor; } // if that didn't work, look for set("foo") executor = new DuckGetExecutor(this, claz, property); if (executor.isAlive()) { return executor; } return null; } /** * Return a property setter. * @param obj the object to base the property from. * @param identifier property name (or identifier) * @param arg value to set * @return a {@link AbstractExecutor.Set}. */ public final AbstractExecutor.Set getSetExecutor(final Object obj, final Object identifier, Object arg) { final Class claz = obj.getClass(); final String property = toString(identifier); AbstractExecutor.Set executor; // first try for a setFoo() type of property (also setfoo() ) if (property != null) { executor = new PropertySetExecutor(this, claz, property, arg); if (executor.isAlive()) { return executor; } } // let's see if we are a map... executor = new MapSetExecutor(this, claz, identifier, arg); if (executor.isAlive()) { return executor; } // let's see if we can convert the identifier to an int, // if obj is an array or a list, we can still do something Integer index = toInteger(identifier); if (index != null) { executor = new ListSetExecutor(this, claz, index, arg); if (executor.isAlive()) { return executor; } } // if that didn't work, look for set(foo) executor = new DuckSetExecutor(this, claz, identifier, arg); if (executor.isAlive()) { return executor; } // if that didn't work, look for set("foo") executor = new DuckSetExecutor(this, claz, property, arg); if (executor.isAlive()) { return executor; } return null; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy