Home » apache-openjpa-1.1.0-source » org.apache.openjpa » enhance » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one
    3    * or more contributor license agreements.  See the NOTICE file
    4    * distributed with this work for additional information
    5    * regarding copyright ownership.  The ASF licenses this file
    6    * to you under the Apache License, Version 2.0 (the
    7    * "License"); you may not use this file except in compliance
    8    * with the License.  You may obtain a copy of the License at
    9    *
   10    * http://www.apache.org/licenses/LICENSE-2.0
   11    *
   12    * Unless required by applicable law or agreed to in writing,
   13    * software distributed under the License is distributed on an
   14    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   15    * KIND, either express or implied.  See the License for the
   16    * specific language governing permissions and limitations
   17    * under the License.    
   18    */
   19   package org.apache.openjpa.enhance;
   20   
   21   import java.lang.reflect.AccessibleObject;
   22   import java.lang.reflect.Field;
   23   import java.lang.reflect.InvocationTargetException;
   24   import java.lang.reflect.Method;
   25   import java.lang.reflect.Modifier;
   26   import java.security.AccessController;
   27   
   28   import org.apache.commons.lang.StringUtils;
   29   import org.apache.openjpa.lib.util.J2DoPrivHelper;
   30   import org.apache.openjpa.lib.util.Localizer;
   31   import org.apache.openjpa.util.GeneralException; 
   32   import org.apache.openjpa.util.UserException; 
   33   
   34   /**
   35    * Reflection utilities used to support and augment enhancement.  Used both
   36    * at enhancement time and at runtime.
   37    *
   38    * @author Abe White
   39    */
   40   public class Reflection {
   41   
   42       private static final Localizer _loc = Localizer.forPackage
   43           (Reflection.class);
   44   
   45       /**
   46        * Return the getter method matching the given property name, optionally
   47        * throwing an exception if none.
   48        */
   49       public static Method findGetter(Class cls, String prop, boolean mustExist) {
   50           prop = StringUtils.capitalize(prop);
   51           String name = "get" + prop;
   52           Method m;
   53           try {
   54               // this algorithm searches for a get<prop> or is<prop> method in
   55               // a breadth-first manner.
   56               for (Class c = cls; c != null && c != Object.class;
   57                   c = c.getSuperclass()) {
   58                   m = getDeclaredMethod(c, name, null);
   59                   if (m != null) {
   60                       return m;
   61                   } else {
   62                       m = getDeclaredMethod(c, "is" + prop, null);
   63                       if (m != null && (m.getReturnType() == boolean.class
   64                           || m.getReturnType() == Boolean.class))
   65                           return m;
   66                   }
   67               }
   68           } catch (Exception e) {
   69               throw new GeneralException(e);
   70           }
   71   
   72           if (mustExist)
   73               throw new UserException(_loc.get("bad-getter", cls, prop));
   74           return null;
   75       }
   76   
   77       /**
   78        * Return the setter method matching the given property name, optionally
   79        * throwing an exception if none.  The property must also have a getter.
   80        */
   81       public static Method findSetter(Class cls, String prop, boolean mustExist) {
   82           Method getter = findGetter(cls, prop, mustExist);
   83           return (getter == null) ? null 
   84               : findSetter(cls, prop, getter.getReturnType(), mustExist);
   85       }
   86   
   87       /**
   88        * Return the setter method matching the given property name, optionally
   89        * throwing an exception if none.
   90        */
   91       public static Method findSetter(Class cls, String prop, Class param,
   92           boolean mustExist) {
   93           String name = "set" + StringUtils.capitalize(prop);
   94           Method m;
   95           try {
   96               for (Class c = cls; c != null && c != Object.class;
   97                   c = c.getSuperclass()) {
   98                   m = getDeclaredMethod(c, name, param);
   99                   if (m != null)
  100                       return m;
  101               }
  102           } catch (Exception e) {
  103               throw new GeneralException(e);
  104           }
  105   
  106           if (mustExist)
  107               throw new UserException(_loc.get("bad-setter", cls, prop));
  108           return null;
  109       }
  110   
  111       /**
  112        * Invokes <code>cls.getDeclaredMethods()</code>, and returns the method
  113        * that matches the <code>name</code> and <code>param</code> arguments.
  114        * Avoids the exception thrown by <code>Class.getDeclaredMethod()</code>
  115        * for performance reasons. <code>param</code> may be null. Additionally,
  116        * if there are multiple methods with different return types, this will
  117        * return the method defined in the least-derived class.
  118        *
  119        * @since 0.9.8
  120        */
  121       static Method getDeclaredMethod(Class cls, String name,
  122           Class param) {
  123           Method[] methods = (Method[]) AccessController.doPrivileged(
  124               J2DoPrivHelper.getDeclaredMethodsAction(cls));
  125           Method candidate = null;
  126           for (int i = 0 ; i < methods.length; i++) {
  127       	    if (name.equals(methods[i].getName())) {
  128                   Class[] methodParams = methods[i].getParameterTypes();
  129                   if (param == null && methodParams.length == 0)
  130                       candidate = mostDerived(methods[i], candidate);
  131                   else if (param != null && methodParams.length == 1
  132                       && param.equals(methodParams[0]))
  133                       candidate = mostDerived(methods[i], candidate);
  134               }
  135           }
  136           return candidate;
  137       }
  138   
  139       static Method mostDerived(Method meth1, Method meth2) {
  140           if (meth1 == null)
  141               return meth2;
  142           if (meth2 == null)
  143               return meth1;
  144           
  145           Class cls2 = meth2.getDeclaringClass();
  146           Class cls1 = meth1.getDeclaringClass();
  147   
  148           if (cls1.equals(cls2)) {
  149               Class ret1 = meth1.getReturnType();
  150               Class ret2 = meth2.getReturnType();
  151               if (ret1.isAssignableFrom(ret2))
  152                   return meth2;
  153               else if (ret2.isAssignableFrom(ret1))
  154                   return meth1;
  155               else
  156                   throw new IllegalArgumentException(
  157                       _loc.get("most-derived-unrelated-same-type", meth1, meth2)
  158                           .getMessage());
  159           } else {
  160               if (cls1.isAssignableFrom(cls2))
  161                   return meth2;
  162               else if (cls2.isAssignableFrom(cls1))
  163                   return meth1;
  164               else
  165                   throw new IllegalArgumentException(
  166                       _loc.get("most-derived-unrelated", meth1, meth2)
  167                           .getMessage());
  168           }
  169       }
  170   
  171       /**
  172        * Return the field with the given name, optionally throwing an exception
  173        * if none.
  174        */
  175       public static Field findField(Class cls, String name, boolean mustExist) {
  176           try {
  177               Field f;
  178               for (Class c = cls; c != null && c != Object.class;
  179                   c = c.getSuperclass()) {
  180                   f = getDeclaredField(c, name);
  181                   if (f != null)
  182                       return f;
  183               }
  184           } catch (Exception e) {
  185               throw new GeneralException(e);
  186           }
  187   
  188           if (mustExist)
  189               throw new UserException(_loc.get("bad-field", cls, name));
  190           return null;
  191       }
  192   
  193       /**
  194        * Invokes <code>cls.getDeclaredFields()</code>, and returns the field
  195        * that matches the <code>name</code> argument.  Avoids the exception
  196        * thrown by <code>Class.getDeclaredField()</code> for performance reasons.
  197        *
  198        * @since 0.9.8
  199        */
  200       private static Field getDeclaredField(Class cls, String name) {
  201           Field[] fields = (Field[]) AccessController.doPrivileged(
  202               J2DoPrivHelper.getDeclaredFieldsAction(cls));
  203           for (int i = 0 ; i < fields.length; i++) {
  204       	    if (name.equals(fields[i].getName()))
  205   		        return fields[i];
  206           }
  207           return null;
  208       }
  209   
  210       /**
  211        * Return the value of the given field in the given object.
  212        */
  213       public static Object get(Object target, Field field) {
  214           if (target == null || field == null)
  215               return null;
  216           makeAccessible(field, field.getModifiers());
  217           try {
  218               return field.get(target);
  219           } catch (Throwable t) {
  220               throw wrapReflectionException(t);
  221           }
  222       }
  223   
  224       /**
  225        * Make the given member accessible if it isn't already.
  226        */
  227       private static void makeAccessible(AccessibleObject ao, int mods) {
  228           try {
  229               if (!Modifier.isPublic(mods) && !ao.isAccessible())
  230                   AccessController.doPrivileged(J2DoPrivHelper
  231                       .setAccessibleAction(ao, true));
  232           } catch (SecurityException se) {
  233               throw new UserException(_loc.get("reflect-security", ao)).
  234                   setFatal(true);
  235           }
  236       }
  237   
  238       /**
  239        * Wrap the given reflection exception as a runtime exception.
  240        */
  241       private static RuntimeException wrapReflectionException(Throwable t) {
  242           if (t instanceof InvocationTargetException)
  243               t = ((InvocationTargetException) t).getTargetException();    
  244           if (t instanceof RuntimeException)
  245               return (RuntimeException) t;
  246           return new GeneralException(t);
  247       }
  248   
  249       /**
  250        * Return the value of the given field in the given object.
  251        */
  252       public static boolean getBoolean(Object target, Field field) {
  253           if (target == null || field == null)
  254               return false;
  255           makeAccessible(field, field.getModifiers());
  256           try {
  257               return field.getBoolean(target);
  258           } catch (Throwable t) {
  259               throw wrapReflectionException(t);
  260           }
  261       }
  262   
  263       /**
  264        * Return the value of the given field in the given object.
  265        */
  266       public static byte getByte(Object target, Field field) {
  267           if (target == null || field == null)
  268               return (byte) 0;
  269           makeAccessible(field, field.getModifiers());
  270           try {
  271               return field.getByte(target);
  272           } catch (Throwable t) {
  273               throw wrapReflectionException(t);
  274           }
  275       }
  276   
  277       /**
  278        * Return the value of the given field in the given object.
  279        */
  280       public static char getChar(Object target, Field field) {
  281           if (target == null || field == null)
  282               return (char) 0;
  283           makeAccessible(field, field.getModifiers());
  284           try {
  285               return field.getChar(target);
  286           } catch (Throwable t) {
  287               throw wrapReflectionException(t);
  288           }
  289       }
  290   
  291       /**
  292        * Return the value of the given field in the given object.
  293        */
  294       public static double getDouble(Object target, Field field) {
  295           if (target == null || field == null)
  296               return 0D;
  297           makeAccessible(field, field.getModifiers());
  298           try {
  299               return field.getDouble(target);
  300           } catch (Throwable t) {
  301               throw wrapReflectionException(t);
  302           }
  303       }
  304   
  305       /**
  306        * Return the value of the given field in the given object.
  307        */
  308       public static float getFloat(Object target, Field field) {
  309           if (target == null || field == null)
  310               return 0F;
  311           makeAccessible(field, field.getModifiers());
  312           try {
  313               return field.getFloat(target);
  314           } catch (Throwable t) {
  315               throw wrapReflectionException(t);
  316           }
  317       }
  318   
  319       /**
  320        * Return the value of the given field in the given object.
  321        */
  322       public static int getInt(Object target, Field field) {
  323           if (target == null || field == null)
  324               return 0;
  325           makeAccessible(field, field.getModifiers());
  326           try {
  327               return field.getInt(target);
  328           } catch (Throwable t) {
  329               throw wrapReflectionException(t);
  330           }
  331       }
  332   
  333       /**
  334        * Return the value of the given field in the given object.
  335        */
  336       public static long getLong(Object target, Field field) {
  337           if (target == null || field == null)
  338               return 0L;
  339           makeAccessible(field, field.getModifiers());
  340           try {
  341               return field.getLong(target);
  342           } catch (Throwable t) {
  343               throw wrapReflectionException(t);
  344           }
  345       }
  346   
  347       /**
  348        * Return the value of the given field in the given object.
  349        */
  350       public static short getShort(Object target, Field field) {
  351           if (target == null || field == null)
  352               return (short) 0;
  353           makeAccessible(field, field.getModifiers());
  354           try {
  355               return field.getShort(target);
  356           } catch (Throwable t) {
  357               throw wrapReflectionException(t);
  358           }
  359       }
  360   
  361       /**
  362        * Return the return value of the given getter in the given object.
  363        */
  364       public static Object get(Object target, Method getter) {
  365           if (target == null || getter == null)
  366               return null;
  367           makeAccessible(getter, getter.getModifiers());
  368           try {
  369               return getter.invoke(target, (Object[]) null);
  370           } catch (Throwable t) {
  371               throw wrapReflectionException(t);
  372           }
  373       }
  374   
  375       /**
  376        * Return the return value of the given getter in the given object.
  377        */
  378       public static boolean getBoolean(Object target, Method getter) {
  379           Object o = get(target, getter);
  380           return (o == null) ? false : ((Boolean) o).booleanValue();
  381       }
  382   
  383       /**
  384        * Return the return value of the given getter in the given object.
  385        */
  386       public static byte getByte(Object target, Method getter) {
  387           Object o = get(target, getter);
  388           return (o == null) ? (byte) 0 : ((Number) o).byteValue();
  389       }
  390   
  391       /**
  392        * Return the return value of the given getter in the given object.
  393        */
  394       public static char getChar(Object target, Method getter) {
  395           Object o = get(target, getter);
  396           return (o == null) ? (char) 0 : ((Character) o).charValue();
  397       }
  398   
  399       /**
  400        * Return the return value of the given getter in the given object.
  401        */
  402       public static double getDouble(Object target, Method getter) {
  403           Object o = get(target, getter);
  404           return (o == null) ? 0D : ((Number) o).doubleValue();
  405       }
  406   
  407       /**
  408        * Return the return value of the given getter in the given object.
  409        */
  410       public static float getFloat(Object target, Method getter) {
  411           Object o = get(target, getter);
  412           return (o == null) ? 0F : ((Number) o).floatValue();
  413       }
  414   
  415       /**
  416        * Return the return value of the given getter in the given object.
  417        */
  418       public static int getInt(Object target, Method getter) {
  419           Object o = get(target, getter);
  420           return (o == null) ? 0 : ((Number) o).intValue();
  421       }
  422   
  423       /**
  424        * Return the return value of the given getter in the given object.
  425        */
  426       public static long getLong(Object target, Method getter) {
  427           Object o = get(target, getter);
  428           return (o == null) ? 0L : ((Number) o).longValue();
  429       }
  430   
  431       /**
  432        * Return the return value of the given getter in the given object.
  433        */
  434       public static short getShort(Object target, Method getter) {
  435           Object o = get(target, getter);
  436           return (o == null) ? (short) 0 : ((Number) o).shortValue();
  437       }
  438   
  439       /**
  440        * Set the value of the given field in the given object.
  441        */
  442       public static void set(Object target, Field field, Object value) {
  443           if (target == null || field == null)
  444               return;
  445           makeAccessible(field, field.getModifiers());
  446           try {
  447               field.set(target, value);
  448           } catch (Throwable t) {
  449               throw wrapReflectionException(t);
  450           }
  451       }
  452   
  453       /**
  454        * Set the value of the given field in the given object.
  455        */
  456       public static void set(Object target, Field field, boolean value) {
  457           if (target == null || field == null)
  458               return;
  459           makeAccessible(field, field.getModifiers());
  460           try {
  461               field.setBoolean(target, value);
  462           } catch (Throwable t) {
  463               throw wrapReflectionException(t);
  464           }
  465       }
  466   
  467       /**
  468        * Set the value of the given field in the given object.
  469        */
  470       public static void set(Object target, Field field, byte value) {
  471           if (target == null || field == null)
  472               return;
  473           makeAccessible(field, field.getModifiers());
  474           try {
  475               field.setByte(target, value);
  476           } catch (Throwable t) {
  477               throw wrapReflectionException(t);
  478           }
  479       }
  480   
  481       /**
  482        * Set the value of the given field in the given object.
  483        */
  484       public static void set(Object target, Field field, char value) {
  485           if (target == null || field == null)
  486               return;
  487           makeAccessible(field, field.getModifiers());
  488           try {
  489               field.setChar(target, value);
  490           } catch (Throwable t) {
  491               throw wrapReflectionException(t);
  492           }
  493       }
  494   
  495       /**
  496        * Set the value of the given field in the given object.
  497        */
  498       public static void set(Object target, Field field, double value) {
  499           if (target == null || field == null)
  500               return;
  501           makeAccessible(field, field.getModifiers());
  502           try {
  503               field.setDouble(target, value);
  504           } catch (Throwable t) {
  505               throw wrapReflectionException(t);
  506           }
  507       }
  508   
  509       /**
  510        * Set the value of the given field in the given object.
  511        */
  512       public static void set(Object target, Field field, float value) {
  513           if (target == null || field == null)
  514               return;
  515           makeAccessible(field, field.getModifiers());
  516           try {
  517               field.setFloat(target, value);
  518           } catch (Throwable t) {
  519               throw wrapReflectionException(t);
  520           }
  521       }
  522   
  523       /**
  524        * Set the value of the given field in the given object.
  525        */
  526       public static void set(Object target, Field field, int value) {
  527           if (target == null || field == null)
  528               return;
  529           makeAccessible(field, field.getModifiers());
  530           try {
  531               field.setInt(target, value);
  532           } catch (Throwable t) {
  533               throw wrapReflectionException(t);
  534           }
  535       }
  536   
  537       /**
  538        * Set the value of the given field in the given object.
  539        */
  540       public static void set(Object target, Field field, long value) {
  541           if (target == null || field == null)
  542               return;
  543           makeAccessible(field, field.getModifiers());
  544           try {
  545               field.setLong(target, value);
  546           } catch (Throwable t) {
  547               throw wrapReflectionException(t);
  548           }
  549       }
  550   
  551       /**
  552        * Set the value of the given field in the given object.
  553        */
  554       public static void set(Object target, Field field, short value) {
  555           if (target == null || field == null)
  556               return;
  557           makeAccessible(field, field.getModifiers());
  558           try {
  559               field.setShort(target, value);
  560           } catch (Throwable t) {
  561               throw wrapReflectionException(t);
  562           }
  563       }
  564   
  565       /**
  566        * Set the value of the given field in the given object.
  567        * Same behavior as above methods, but parameter ordering is rearranged
  568        * to simplify usage from generated bytecodes.
  569        *
  570        * @since 1.0.0
  571        */
  572       public static void set(Object target, Object value, Field field) {
  573           set(target, field, value);
  574       }
  575   
  576       /**
  577        * Set the value of the given field in the given object.
  578        * Same behavior as above methods, but parameter ordering is rearranged
  579        * to simplify usage from generated bytecodes.
  580        *
  581        * @since 1.0.0
  582        */
  583       public static void set(Object target, boolean value, Field field) {
  584           set(target, field, value);
  585       }
  586   
  587       /**
  588        * Set the value of the given field in the given object.
  589        * Same behavior as above methods, but parameter ordering is rearranged
  590        * to simplify usage from generated bytecodes.
  591        *
  592        * @since 1.0.0
  593        */
  594       public static void set(Object target, byte value, Field field) {
  595           set(target, field, value);
  596       }
  597   
  598       /**
  599        * Set the value of the given field in the given object.
  600        * Same behavior as above methods, but parameter ordering is rearranged
  601        * to simplify usage from generated bytecodes.
  602        *
  603        * @since 1.0.0
  604        */
  605       public static void set(Object target, char value, Field field) {
  606           set(target, field, value);
  607       }
  608   
  609       /**
  610        * Set the value of the given field in the given object.
  611        * Same behavior as above methods, but parameter ordering is rearranged
  612        * to simplify usage from generated bytecodes.
  613        *
  614        * @since 1.0.0
  615        */
  616       public static void set(Object target, double value, Field field) {
  617           set(target, field, value);
  618       }
  619   
  620       /**
  621        * Set the value of the given field in the given object.
  622        * Same behavior as above methods, but parameter ordering is rearranged
  623        * to simplify usage from generated bytecodes.
  624        *
  625        * @since 1.0.0
  626        */
  627       public static void set(Object target, float value, Field field) {
  628           set(target, field, value);
  629       }
  630   
  631       /**
  632        * Set the value of the given field in the given object.
  633        * Same behavior as above methods, but parameter ordering is rearranged
  634        * to simplify usage from generated bytecodes.
  635        *
  636        * @since 1.0.0
  637        */
  638       public static void set(Object target, int value, Field field) {
  639           set(target, field, value);
  640       }
  641   
  642       /**
  643        * Set the value of the given field in the given object.
  644        * Same behavior as above methods, but parameter ordering is rearranged
  645        * to simplify usage from generated bytecodes.
  646        *
  647        * @since 1.0.0
  648        */
  649       public static void set(Object target, long value, Field field) {
  650           set(target, field, value);
  651       }
  652   
  653       /**
  654        * Set the value of the given field in the given object.
  655        * Same behavior as above methods, but parameter ordering is rearranged
  656        * to simplify usage from generated bytecodes.
  657        *
  658        * @since 1.0.0
  659        */
  660       public static void set(Object target, short value, Field field) {
  661           set(target, field, value);
  662       }
  663   
  664       /**
  665        * Invoke the given setter on the given object.
  666        */
  667       public static void set(Object target, Method setter, Object value) {
  668           if (target == null || setter == null)
  669               return;
  670           makeAccessible(setter, setter.getModifiers());
  671           try {
  672               setter.invoke(target, new Object[] { value });
  673           } catch (Throwable t) {
  674               throw wrapReflectionException(t);
  675           }
  676       }
  677   
  678       /**
  679        * Invoke the given setter on the given object.
  680        */
  681       public static void set(Object target, Method setter, boolean value) {
  682           set(target, setter, (value) ? Boolean.TRUE : Boolean.FALSE);
  683       }
  684   
  685       /**
  686        * Invoke the given setter on the given object.
  687        */
  688       public static void set(Object target, Method setter, byte value) {
  689           set(target, setter, new Byte(value));
  690       }
  691   
  692       /**
  693        * Invoke the given setter on the given object.
  694        */
  695       public static void set(Object target, Method setter, char value) {
  696           set(target, setter, new Character(value));
  697       }
  698   
  699       /**
  700        * Invoke the given setter on the given object.
  701        */
  702       public static void set(Object target, Method setter, double value) {
  703           set(target, setter, new Double(value));
  704       }
  705   
  706       /**
  707        * Invoke the given setter on the given object.
  708        */
  709       public static void set(Object target, Method setter, float value) {
  710           set(target, setter, new Float(value));
  711       }
  712   
  713       /**
  714        * Invoke the given setter on the given object.
  715        */
  716       public static void set(Object target, Method setter, int value) {
  717           set(target, setter, new Integer(value));
  718       }
  719   
  720       /**
  721        * Invoke the given setter on the given object.
  722        */
  723       public static void set(Object target, Method setter, long value) {
  724           set(target, setter, new Long(value));
  725       }
  726   
  727       /**
  728        * Invoke the given setter on the given object.
  729        */
  730       public static void set(Object target, Method setter, short value) {
  731           set(target, setter, new Short(value));
  732       }
  733   }

Save This Page
Home » apache-openjpa-1.1.0-source » org.apache.openjpa » enhance » [javadoc | source]