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

org.apache.beehive.controls.system.jdbc.parser.ReflectionFragment Maven / Gradle / Ivy

The 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.
 *
 * $Header:$
 */

package org.apache.beehive.controls.system.jdbc.parser;

import org.apache.beehive.controls.api.ControlException;
import org.apache.beehive.controls.api.context.ControlBeanContext;
import org.apache.beehive.controls.system.jdbc.TypeMappingsFactory;
import org.apache.beehive.controls.system.jdbc.JdbcControl;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * Represents a method parameter substitution into the SQL annotation's statement member.  Delimited by '{' and '}'.
 * Method parameter names must exactly match the name used in the SQL statement in order for the substitution to occur.
 * 

*

 * SQL(statement="SELECT * FROM {tableName}")
 * public void getAll(String tableName) throws SQLException;
 * 
*/ public final class ReflectionFragment extends SqlFragment { private static final String PREPARED_STATEMENT_SUB_MARK = "?"; private static final Pattern s_parameterNamePattern = Pattern.compile("\\."); private final String _parameterName; private final String[] _nameQualifiers; private int _sqlDataType; /** * Create a new ReflectionFragment with the specifed method parameter name. * * @param parameterName The name of the parameter whose value should be substituted at this location. */ protected ReflectionFragment(String parameterName) { _parameterName = parameterName; _sqlDataType = TypeMappingsFactory.TYPE_UNKNOWN; _nameQualifiers = s_parameterNamePattern.split(_parameterName); } /** * Create a new ReflectionFragment with the specified method parameter name and SQL type. * * @param parameterName The name of the parameter whose value should be substituted at this location. * @param sqlDataType A String specifing the SQL data type for this parameter. */ protected ReflectionFragment(String parameterName, String sqlDataType) { this(parameterName); if (sqlDataType != null) { _sqlDataType = TypeMappingsFactory.getInstance().convertStringToSQLType(sqlDataType); } } /** * Return text generated by this fragment for a PreparedStatement * * @param context A ControlBeanContext instance. * @param m The annotated method. * @param args The method's parameters * @return Always returns a PREPARED_STATEMENT_SUB_MARK */ protected String getPreparedStatementText(ControlBeanContext context, Method m, Object[] args) { // this reflection fragment may resolve to a JdbcControl.ComplexSqlFragment // if so it changes the behavior a bit. Object val = getParameterValue(context, m, args); if (val instanceof JdbcControl.ComplexSqlFragment) { return ((JdbcControl.ComplexSqlFragment)val).getSQL(); } else { return PREPARED_STATEMENT_SUB_MARK; } } /** * A reflection fragment may evaluate to an JdbcControl.ComplexSqlFragment type, * which requires additional steps to evaluate after reflection. * * @param context Control bean context. * @param m Method. * @param args Method args. * @return true or false. */ protected boolean hasComplexValue(ControlBeanContext context, Method m, Object[] args) { Object val = getParameterValue(context, m, args); return val instanceof JdbcControl.ComplexSqlFragment; } /** * Always true for ReflectionFragment. * * @return true */ protected boolean hasParamValue() { return true; } /** * Get the parameter name (as specified in the SQL statement). * * @return The parameter name. */ protected String getParameterName() { return _parameterName; } /** * Get a copy of the array of parameter name qualifiers. * * @return An array of parameter name qualifiers. */ protected String[] getParameterNameQualifiers() { String[] nameQualifiersCopy = new String[_nameQualifiers.length]; System.arraycopy(_nameQualifiers, 0, nameQualifiersCopy, 0, _nameQualifiers.length); return nameQualifiersCopy; } /** * Get the SQL data type of this param. * * @return The SQL data type for this param. */ protected int getParamSqlDataType() { return _sqlDataType; } /** * For JUnit testing. * * @return The String value of this fragment. */ public String toString() { return PREPARED_STATEMENT_SUB_MARK; } /** * Get the value of this parameter. * * @param context ControlBeanContext instance to evaluate the parameter's value against. * @param method Method instance to evaluate against. * @param args Method argument values * @return All parameter object values contained within this fragment */ protected Object[] getParameterValues(ControlBeanContext context, Method method, Object[] args) { Object value = getParameterValue(context, method, args); if (value instanceof JdbcControl.ComplexSqlFragment) { JdbcControl.SQLParameter[] params = ((JdbcControl.ComplexSqlFragment)value).getParameters(); Object[] values = new Object[params.length]; for (int i = 0; i < params.length; i++) { values[i] = params[i].value; } return values; } return new Object[]{value}; } // // /////////////////////////////////////////////// PRIVATE METHODS ///////////////////////////////////////////// // /** * Get the value from the method param. * @param method * @param args * @return Value of reflected method param. */ private Object getParameterValue(ControlBeanContext context, Method method, Object[] args) { Object value; try { value = context.getParameterValue(method, _nameQualifiers[0], args); } catch (IllegalArgumentException iae) { throw new ControlException("Invalid argument name in SQL statement: " + _nameQualifiers[0], iae); } for (int i = 1; i < _nameQualifiers.length; i++) { // handle maps, properties, and fields... value = extractValue(value, _nameQualifiers[i - 1], _nameQualifiers[i]); } return value; } /** * Get the value from the referenced method parameter using java reflection * * @param aValue * @param aName * @param bName * @return The value */ private Object extractValue(Object aValue, String aName, String bName) { Class aClass = aValue.getClass(); Object value; // // a.isB() or a.getB() // String bNameCapped = Character.toUpperCase(bName.charAt(0)) + bName.substring(1); Method getMethod = null; Class retType; // // try a.isB() first, if found verify that a.isB() returns a boolean value, // and that there is not also a a.getB() method - if there is except // try { getMethod = aClass.getMethod("is" + bNameCapped, (Class[]) null); retType = getMethod.getReturnType(); if (!(retType.equals(Boolean.class) || retType.equals(Boolean.TYPE))) { // only boolean returns can be isB() getMethod = null; } else { /** * make sure ("get" + bNameCapped) does not exist as well * see CR216159 */ boolean getMethodFound = true; try { aClass.getMethod("get" + bNameCapped, (Class[])null); } catch (NoSuchMethodException e) { getMethodFound = false; } if (getMethodFound) { throw new ControlException("Colliding field accsessors in user defined class '" + aClass.getName() + "' for field '" + bName + "'. Please use is for boolean fields and get name for other datatypes."); } } } catch (NoSuchMethodException e) { // ignore } // // try a.getB() if a.isB() was not found. // if (getMethod == null) { try { getMethod = aClass.getMethod("get" + bNameCapped, (Class[])null); } catch (NoSuchMethodException e) { // ignore } } if (getMethod != null) { // OK- a.getB() try { value = getMethod.invoke(aValue, (Object[]) null); } catch (IllegalAccessException e) { throw new ControlException("Unable to access public method: " + e.toString()); } catch (java.lang.reflect.InvocationTargetException e) { throw new ControlException("Exception thrown when executing : " + getMethod.getName() + "() to use as parameter"); } return value; } // // try a.b // try { value = aClass.getField(bName).get(aValue); return value; } catch (NoSuchFieldException e) { // ignore } catch (IllegalAccessException e) { // ignore } // // try a.get(b) // if (aValue instanceof Map) { try { value = TypeMappingsFactory.getInstance().lookupType(aValue, new Object[]{bName}); return value; } catch (Exception mapex) { throw new ControlException("Exception thrown when executing Map.get() to resolve parameter" + mapex.toString()); } } // no other options... throw new ControlException("Illegal argument in SQL statement: " + _parameterName + "; unable to find suitable method of retrieving property " + bName + " out of object " + aName + "."); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy