📄 function.java
字号:
/* * Copyright 2004-2005 Gary Bentley * * Licensed 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.josql.expressions;import java.util.List;import java.util.ArrayList;import java.util.Arrays;import java.util.Map;import java.util.TreeMap;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import com.gentlyweb.utils.Getter;import org.josql.Query;import org.josql.QueryExecutionException;import org.josql.QueryParseException;import org.josql.internal.Utilities;/** * This class represents a Function that can be "called" in JoSQL. * <p> * Last Modified By: $Author: barrygently $<br /> * Last Modified On: $Date: 2005/01/07 17:08:07 $<br /> * Current Revision: $Revision: 1.6 $<br /> */public class Function extends ValueExpression{ private String name = null; private List params = null; private Method function = null; private Object handler = null; private boolean fixedResult = true; private Object fixedValue = null; private String acc = null; private Getter get = null; public Getter getGetter () { return this.get; } public String getAccessor () { return this.acc; } public void setAccessor (String acc) { this.acc = acc; } /** * Get the expected return type from the function. The exact class returned is * dependent upon the function (Java method) that is being called. * * @param q The Query object. * @return The class of the expected return type. */ public Class getExpectedReturnType (Query q) { if (this.get != null) { return this.get.getType (); } return this.function.getReturnType (); } /** * This is a complex method that will initialise the function. * Firstly all of the "arguments" to the function are inited and then * their expected return types gained from calling: {@link Function#getExpectedReturnType(Query)}. * Then the function handlers, user-defined and then built-in are searched until they * find a match for the function name, ensure that it's a public method and that all the * arguments match, widening the match where necessary. * * @param q The Query object. * @throws QueryParseException If something goes wrong whilst initing the arguments to the * function or if the function cannot be found. */ public void init (Query q) throws QueryParseException { // Need to init the params (if present) first because the expected type may not be // present otherwise. if (this.params != null) { int s = this.params.size (); for (int i = 0; i < s; i++) { Expression exp = (Expression) this.params.get (i); exp.init (q); } } Class[] ps = null; if (this.params != null) { int s = params.size (); ps = new Class[s]; for (int i = 0; i < s; i++) { // Need to get the expected return type. Expression exp = (Expression) params.get (i); ps[i] = exp.getExpectedReturnType (q); } } // Try and find the relevant method, first in the user-defined function handler (if present) // or the built-in handlers. List fhs = q.getFunctionHandlers (); if (fhs != null) { int s = fhs.size (); TreeMap ms = new TreeMap (); for (int i = 0; i < s; i++) { Object fh = fhs.get (i); this.getMethods (fh.getClass (), q, ms); } // Get the one with the highest score. if (ms.size () > 0) { this.function = (Method) ms.get (ms.lastKey ()); Class c = this.function.getDeclaringClass (); // What a pain! for (int i = 0; i < fhs.size (); i++) { Object o = fhs.get (i); if (o.getClass ().isAssignableFrom (c)) { this.handler = o; } } } } List dfhs = q.getDefaultFunctionHandlers (); if (this.function == null) { TreeMap ms = new TreeMap (); for (int i = 0; i < dfhs.size (); i++) { Object dfh = dfhs.get (i); this.getMethods (dfh.getClass (), q, ms); } // Get the one with the highest score. if (ms.size () > 0) { this.function = (Method) ms.get (ms.lastKey ()); Class c = this.function.getDeclaringClass (); // What a pain! for (int i = 0; i < dfhs.size (); i++) { Object o = dfhs.get (i); if (o.getClass ().isAssignableFrom (c)) { this.handler = o; } } } } if (this.function == null) { // Can't find the function. throw new QueryParseException ("Unable to find function (method): \"" + Utilities.formatSignature (this.name, ps) + "\" in any user-defined function handlers or the default function handler"); } // Now see if we have an accessor for the function. if (this.acc != null) { // We have an accessor, see what the functions return type is. Class retType = this.function.getReturnType (); // Ensure that the function DOES have a return type. if (Void.TYPE.isAssignableFrom (retType)) { // The return type is void, barf! throw new QueryParseException ("Function: " + this + " maps to method: " + this.function + " however methods return type is \"void\" and an accessor: " + this.acc + " has been defined."); } // See if the return type is an object. If it is then defer trying to // get the accessor until run-time. Have to do it this way since // type comparisons are a little pointless. if (!retType.getName ().equals (Object.class.getName ())) { // The return type is NOT java.lang.Object, so now try and get the // accessor. try { this.get = new Getter (this.acc, retType); } catch (Exception e) { throw new QueryParseException ("Function: " + this + " maps to method: " + this.function + " and has accessor: " + this.acc + " however no valid accessor has been found in return type: " + retType.getName (), e); } } } // A function has/can have a fixed result if all it's arguments // also have a fixed result, if there aren't any args then assume // it won't have a fixed result. if (this.params != null) { for (int i = 0; i < this.params.size (); i++) { Expression exp = (Expression) this.params.get (i); if (!exp.hasFixedResult (q)) { this.fixedResult = false; break; } } } else { this.fixedResult = false; } } /** * Return the List of {@link Expression} objects that constitute the arguments * to the function, no guarantee is made here as to whether they have been inited. * * @return The List of {@link Expression} objects. */ public List getParameters () { return this.params; } public void setParameters (List ps) { this.params = ps; } public void setName (String name) { this.name = name; } public String getName () { return this.name; } /** * Evaluate this function on the current object. It should be noted that not * all functions will use the current object in their execution, functions from the * {@link org.josql.functions.GroupingFunctions} class are notable exceptions. * * @param o The current object. * @param q The Query object. * @return The result of evaluating the function. * @throws QueryExecutionException If something goes wrong during execution of the * function or gaining the values to be used as arguments. */ public Object evaluate (Object o, Query q) throws QueryExecutionException { // See if we have a fixed result. if (this.fixedResult) { // Evaluated once... if (this.fixedValue != null) { return this.fixedValue; } } // Get the values for the parameters... if any... Object[] ps = null; if (this.params != null) { int s = this.params.size (); ps = new Object[s]; for (int i = 0; i < s; i++) { Expression exp = (Expression) this.params.get (i); if (Expression.class.isAssignableFrom (this.function.getParameterTypes ()[i])) { // Leave this one alone.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -