예제 #1
0
  /**
   * Method called to check if we can use the passed method or constructor (wrt access restriction
   * -- public methods can be called, others usually not); and if not, if there is a work-around for
   * the problem.
   */
  public static void checkAndFixAccess(Member member) {
    // We know all members are also accessible objects...
    AccessibleObject ao = (AccessibleObject) member;

    /* 14-Jan-2009, tatu: It seems safe and potentially beneficial to
     *   always to make it accessible (latter because it will force
     *   skipping checks we have no use for...), so let's always call it.
     */
    // if (!ao.isAccessible()) {
    try {
      ao.setAccessible(true);
    } catch (SecurityException se) {
      /* 17-Apr-2009, tatu: Related to [JACKSON-101]: this can fail on
       *    platforms like EJB and Google App Engine); so let's
       *    only fail if we really needed it...
       */
      if (!ao.isAccessible()) {
        Class<?> declClass = member.getDeclaringClass();
        throw new IllegalArgumentException(
            "Can not access "
                + member
                + " (from class "
                + declClass.getName()
                + "; failed to set access: "
                + se.getMessage());
      }
    }
    // }
  }
예제 #2
0
 /**
  * XXX Default access superclass workaround.
  *
  * <p>When a {@code public} class has a default access superclass with {@code public} members,
  * these members are accessible. Calling them from compiled code works fine. Unfortunately, on
  * some JVMs, using reflection to invoke these members seems to (wrongly) prevent access even when
  * the modifier is {@code public}. Calling {@code setAccessible(true)} solves the problem but will
  * only work from sufficiently privileged code. Better workarounds would be gratefully accepted.
  *
  * @param o the AccessibleObject to set as accessible
  * @return a boolean indicating whether the accessibility of the object was set to true.
  */
 static boolean setAccessibleWorkaround(final AccessibleObject o) {
   if (o == null || o.isAccessible()) {
     return false;
   }
   final Member m = (Member) o;
   if (!o.isAccessible()
       && Modifier.isPublic(m.getModifiers())
       && isPackageAccess(m.getDeclaringClass().getModifiers())) {
     try {
       o.setAccessible(true);
       return true;
     } catch (final SecurityException e) { // NOPMD
       // ignore in favor of subsequent IllegalAccessException
     }
   }
   return false;
 }
예제 #3
0
파일: ReflectUtil.java 프로젝트: rengy/jodd
 /**
  * Suppress access check against a reflection object. SecurityException is silently ignored.
  * Checks first if the object is already accessible.
  */
 public static void forceAccess(AccessibleObject accObject) {
   if (accObject.isAccessible() == true) {
     return;
   }
   try {
     accObject.setAccessible(true);
   } catch (SecurityException sex) {
     // ignore
   }
 }
예제 #4
0
 /**
  * Changes the accessibility of a reflection object and returns the previous value. This method
  * can be used to set the accessibility of {@link Method} and {@link Field} instances.
  *
  * @param ao accessible object to set the accessibility on
  * @param accessible the accessibility statues to set on the object
  * @return the previous value of the accessibility flag
  */
 public static boolean exchangeAccessible(final AccessibleObject ao, final boolean accessible) {
   //
   // At least synchronize on the object so that users of this
   // particular method won't step on their toes.
   //
   synchronized (ao) {
     final boolean oldAccessible = ao.isAccessible();
     ao.setAccessible(accessible);
     return oldAccessible;
   }
 }
예제 #5
0
 /**
  * XXX Default access superclass workaround
  *
  * <p>When a public class has a default access superclass with public members, these members are
  * accessible. Calling them from compiled code works fine. Unfortunately, on some JVMs, using
  * reflection to invoke these members seems to (wrongly) prevent access even when the modifier is
  * public. Calling setAccessible(true) solves the problem but will only work from sufficiently
  * privileged code. Better workarounds would be gratefully accepted.
  *
  * @param o the AccessibleObject to set as accessible
  */
 static void setAccessibleWorkaround(AccessibleObject o) {
   if (o == null || o.isAccessible()) {
     return;
   }
   Member m = (Member) o;
   if (Modifier.isPublic(m.getModifiers())
       && isPackageAccess(m.getDeclaringClass().getModifiers())) {
     try {
       o.setAccessible(true);
     } catch (SecurityException e) { // NOPMD
       // ignore in favor of subsequent IllegalAccessException
     }
   }
 }
예제 #6
0
  public static void makeAccessible(final AccessibleObject object) {
    if (!object.isAccessible()) {
      if (System.getSecurityManager() == null) {
        object.setAccessible(true);
      } else {
        AccessController.doPrivileged(
            new PrivilegedAction<Object>() {

              @Override
              public Object run() {
                object.setAccessible(true);
                return null;
              }
            });
      }
    }
  }
예제 #7
0
 private static void setAccessible(AccessibleObject accessible) {
   if (!accessible.isAccessible()) {
     AccessController.doPrivileged(new SetAccessibleAction(accessible));
   }
 }
예제 #8
0
 /**
  * Indicates whether the given <code>member</code> is accessible. It does so by checking whether
  * the member is non-final and public, or made accessible via reflection.
  *
  * @param member The member (field, method, constructor, etc) to check for accessibility
  * @return <code>true</code> if the member is accessible, otherwise <code>false</code>.
  */
 public static boolean isAccessible(AccessibleObject member) {
   return member.isAccessible()
       || (Member.class.isInstance(member) && isNonFinalPublicMember((Member) member));
 }
예제 #9
0
  protected void scanOptions(final Object object) {
    final Class<?> class1 = object.getClass();

    final List<Field> fields = new LinkedList<Field>();
    final List<Method> privateMethods = new LinkedList<Method>();

    final List<Method> otherPackageNonPrivateMethods = new LinkedList<Method>();

    final List<Method> currentPackageNonPrivateMethods = new LinkedList<Method>();

    Class<?> parentClass = class1;
    while (parentClass != null && !parentClass.equals(Object.class)) {
      // We cannot override fields in child classes, so we simple collect
      // all fields we found
      fields.addAll(Arrays.asList(parentClass.getDeclaredFields()));

      // for methods, we need to respect overridden methods when
      // inspecting the parent classes
      for (final Method method : parentClass.getDeclaredMethods()) {
        if (isPrivate(method)) {
          privateMethods.add(method);
        } else if (isPublicOrProtected(method)) {
          if (!containsMethod(otherPackageNonPrivateMethods, method)
              && !containsMethod(currentPackageNonPrivateMethods, method)) {
            currentPackageNonPrivateMethods.add(method);
          }
        } else if (isPackagePrivate(method)) {
          // if (!containsMethod(publicOrProtectedMethods, method)) {
          // method not overloaded
          if (isPackagePrivate(method)) {
            if (!containsMethod(currentPackageNonPrivateMethods, method)) {
              currentPackageNonPrivateMethods.add(method);
            }
          }
        }
      }

      final Package pack = parentClass.getPackage();
      parentClass = parentClass.getSuperclass();
      if ((pack == null && parentClass.getPackage() != null)
          || (pack != null && !pack.equals(parentClass.getPackage()))) {
        otherPackageNonPrivateMethods.addAll(currentPackageNonPrivateMethods);
        currentPackageNonPrivateMethods.clear();
      }
    }

    // inspect elements
    final Set<AccessibleObject> elements = new LinkedHashSet<AccessibleObject>();
    elements.addAll(fields);
    elements.addAll(privateMethods);
    elements.addAll(otherPackageNonPrivateMethods);
    elements.addAll(currentPackageNonPrivateMethods);

    for (final AccessibleObject element : elements) {

      if (element instanceof Field && element.getAnnotation(CmdOptionDelegate.class) != null) {
        debug("Found delegate object at: {0}", element);
        try {
          final boolean origAccessibleFlag = element.isAccessible();
          if (!origAccessibleFlag) {
            element.setAccessible(true);
          }
          final Object delegate = ((Field) element).get(object);
          if (!origAccessibleFlag) {
            // do not leave doors open
            element.setAccessible(origAccessibleFlag);
          }
          if (delegate != null) {
            scanOptions(delegate);
          }
        } catch (final IllegalArgumentException e) {
          debug("Could not scan delegate object at: {0}", element);
        } catch (final IllegalAccessException e) {
          debug("Could not scan delegate object at: {0}", element);
        }
        continue;
      }

      final CmdOption anno = element.getAnnotation(CmdOption.class);
      if (anno == null) {
        continue;
      }

      if (element instanceof Field && Modifier.isFinal(((Field) element).getModifiers())) {
        debug("Detected option on final field: {0}", element);
        // continue;
      }

      final String[] names = anno.names();

      final CmdOptionHandler handler = findHandler(element, anno.args().length, anno.handler());
      if (handler == null) {
        final PreparedI18n msg =
            i18n.preparetr(
                "No suitable handler found for option(s): {0} ({1} argument(s))",
                FList.mkString(anno.names(), ","), anno.args().length);
        throw new CmdlineParserException(msg.notr(), msg.tr());
      }

      if (names == null || names.length == 0) {
        // No names means this is the ONLY parameter
        if (parameter != null) {
          final PreparedI18n msg =
              i18n.preparetr(
                  "More than one parameter definition found. First definition: {0} Second definition: {1}",
                  parameter.getElement(), element);
          throw new CmdlineParserException(msg.notr(), msg.tr());
        }
        // TODO: should we ignore the help parameter?
        final OptionHandle paramHandle =
            new OptionHandle(
                new String[] {},
                anno.description(),
                handler,
                object,
                element,
                anno.args(),
                anno.minCount(),
                anno.maxCount(),
                false /*
                       * cannot
                       * be
                       * a
                       * help
                       * option
                       */,
                anno.hidden(),
                anno.requires(),
                anno.conflictsWith());

        if (paramHandle.getArgsCount() <= 0) {
          final PreparedI18n msg =
              i18n.preparetr("Parameter definition must support at least on argument.");
          throw new CmdlineParserException(msg.notr(), msg.tr());
        }
        parameter = paramHandle;

      } else {
        final OptionHandle option =
            new OptionHandle(
                names,
                anno.description(),
                handler,
                object,
                element,
                anno.args(),
                anno.minCount(),
                anno.maxCount(),
                anno.isHelp(),
                anno.hidden(),
                anno.requires(),
                anno.conflictsWith());

        for (final String name : names) {
          if (quickCommandMap.containsKey(name) || quickOptionMap.containsKey(name)) {
            final PreparedI18n msg =
                i18n.preparetr(
                    "Duplicate command/option name \"{0}\" found in: {1}", name, element);
            throw new CmdlineParserException(msg.notr(), msg.tr());
          }
          quickOptionMap.put(name, option);
        }
        options.add(option);
      }
    }
  }
예제 #10
0
  public void parse(
      final boolean dryrun, final boolean detectHelpAndSkipValidation, String... cmdline) {
    if (log.isDebugEnabled()) {
      log.debug(
          "About to start parsing. dryrun: "
              + dryrun
              + ", detectHelpAndSkipValidation: "
              + detectHelpAndSkipValidation
              + ", state: "
              + debugState("  "));
    }

    if (defaultCommandName != null && !quickCommandMap.containsKey(defaultCommandName)) {
      final PreparedI18n msg =
          i18n.preparetr("Default command \"{0}\" is not a known command.", defaultCommandName);
      throw new CmdlineParserException(msg.notr(), msg.tr());
    }

    // Avoid null access
    cmdline = cmdline == null ? new String[] {} : cmdline;

    if (argsFromFilePrefix.isDefined()) {
      cmdline =
          FList.flatMap(
                  cmdline,
                  new F1<String, List<String>>() {
                    @Override
                    public List<String> apply(final String arg) {
                      if (arg.startsWith(argsFromFilePrefix.get())) {
                        debug("Expanding {0} into argument list", arg);
                        final File file = new File(arg.substring(1));
                        if (file.exists() && file.isFile()) {
                          try {
                            final BufferedReader reader = new BufferedReader(new FileReader(file));
                            final List<String> args = new LinkedList<String>();
                            String line;
                            while ((line = reader.readLine()) != null) {
                              // if (line.trim().length() > 0) {
                              args.add(line);
                              // }
                            }
                            reader.close();
                            return args;
                          } catch (final FileNotFoundException e) {
                            final PreparedI18n msg =
                                i18n.preparetr("File referenced via {0} does not exist.", arg);
                            throw new CmdlineParserException(msg.notr(), e, msg.tr());
                          } catch (final IOException e) {
                            final PreparedI18n msg =
                                i18n.preparetr("File referenced via {0} could not be read.", arg);
                            throw new CmdlineParserException(msg.notr(), e, msg.tr());
                          }
                        } else {
                          final PreparedI18n msg =
                              i18n.preparetr("File referenced via {0} does not exist.", arg);
                          throw new CmdlineParserException(msg.notr(), msg.tr());
                        }
                      } else {
                        return Arrays.asList(arg);
                      }
                    }
                  })
              .toArray(new String[0]);
    }

    if (!dryrun) {
      debug("Parsing...");
      // Check without applying anything
      parse(true, detectHelpAndSkipValidation, cmdline);
    }

    if (dryrun) {
      validateOptions();
    }

    // Should be set to false, if an stopOption was found and parsing of
    // options is no longer allowed
    boolean parseOptions = true;
    final String stopOption = "--";

    // optionCount counts the occurrence for each option handle in the
    // cmdline
    final Map<OptionHandle, Integer> optionCount = new LinkedHashMap<OptionHandle, Integer>();
    for (final OptionHandle option : options) {
      optionCount.put(option, 0);
    }
    if (parameter != null) {
      optionCount.put(parameter, 0);
    }

    boolean helpDetected = false;

    // Actually iterate over the command line elements
    for (int index = 0; index < cmdline.length; ++index) {
      final String param = cmdline[index];
      if (parseOptions && stopOption.equals(param)) {
        parseOptions = false;

      } else if (debugAllowed && param.equals("--CMDOPTION_DEBUG")) {
        if (!debugMode) {
          debugMode = true;
          debug("Enabled debug mode\n" + debugState(""));
        }

      } else if (parseOptions && quickOptionMap.containsKey(param)) {
        // Found an option
        final OptionHandle optionHandle = quickOptionMap.get(param);
        optionCount.put(optionHandle, optionCount.get(optionHandle) + 1);
        if (optionHandle.isHelp()) {
          debug("Detected a help request through: " + param);
          helpDetected = true;
        }

        if (cmdline.length <= index + optionHandle.getArgsCount()) {
          final PreparedI18n msg =
              i18n.preparetr(
                  "Missing arguments(s): {0}. Option \"{1}\" requires {2} arguments, but you gave {3}.",
                  FList.mkString(
                      Arrays.asList(optionHandle.getArgs())
                          .subList(cmdline.length - index - 1, optionHandle.getArgsCount()),
                      ", "),
                  param,
                  optionHandle.getArgsCount(),
                  cmdline.length - index - 1);
          throw new CmdlineParserException(msg.notr(), msg.tr());
        }
        // slurp next cmdline arguments into option arguments
        final String[] optionArgs =
            Arrays.copyOfRange(cmdline, index + 1, index + 1 + optionHandle.getArgsCount());
        index += optionHandle.getArgsCount();

        final AccessibleObject element = optionHandle.getElement();
        final CmdOptionHandler handler = optionHandle.getCmdOptionHandler();

        if (!dryrun) {
          try {
            final boolean origAccessibleFlag = element.isAccessible();
            if (!origAccessibleFlag) {
              element.setAccessible(true);
            }
            handler.applyParams(optionHandle.getObject(), element, optionArgs, param);
            if (!origAccessibleFlag) {
              // do not leave doors open
              element.setAccessible(origAccessibleFlag);
            }
          } catch (final CmdOptionHandlerException e) {
            throw new CmdlineParserException(e.getMessage(), e, e.getLocalizedMessage());
          } catch (final Exception e) {
            final PreparedI18n msg =
                i18n.preparetr(
                    "Could not apply parameters {0} to field/method {1}",
                    Arrays.toString(optionArgs), element);
            throw new CmdlineParserException(msg.notr(), e, msg.tr());
          }
        }
      } else if (parseOptions && quickCommandMap.containsKey(param)) {
        // Found a command
        final CommandHandle commandHandle = quickCommandMap.get(param);
        if (!dryrun) {
          parsedCommandName = param;
        }
        // Delegate parsing of the rest of the cmdline to the command
        commandHandle
            .getCmdlineParser()
            .parse(
                dryrun,
                detectHelpAndSkipValidation,
                Arrays.copyOfRange(cmdline, index + 1, cmdline.length));
        // Stop parsing
        break;

      } else if (parameter == null
          && defaultCommandName != null
          && quickCommandMap.containsKey(defaultCommandName)) {
        // Assume a default command inserted here
        debug(
            "Unsupported option '"
                + param
                + "' found, assuming default command: "
                + defaultCommandName);
        final CommandHandle commandHandle = quickCommandMap.get(defaultCommandName);

        if (!dryrun) {
          parsedCommandName = defaultCommandName;
        }
        // Delegate parsing of the rest of the cmdline to the command
        commandHandle
            .getCmdlineParser()
            .parse(
                dryrun,
                detectHelpAndSkipValidation,
                Arrays.copyOfRange(cmdline, index, cmdline.length));
        // Stop parsing
        break;

      } else if (parameter != null) {
        // Found a parameter
        optionCount.put(parameter, optionCount.get(parameter) + 1);

        if (cmdline.length <= index + parameter.getArgsCount() - 1) {
          final int countOfGivenParams = cmdline.length - index;
          final PreparedI18n msg =
              i18n.preparetr(
                  "Missing arguments: {0} Parameter requires {1} arguments, but you gave {2}.",
                  Arrays.asList(parameter.getArgs())
                      .subList(countOfGivenParams, parameter.getArgsCount()),
                  parameter.getArgsCount(),
                  countOfGivenParams);
          throw new CmdlineParserException(msg.notr(), msg.tr());
        }
        // slurp next cmdline arguments into option arguments
        final String[] optionArgs =
            Arrays.copyOfRange(cmdline, index, index + parameter.getArgsCount());
        // -1, because index gets increased by one at end of for-loop
        index += parameter.getArgsCount() - 1;

        final AccessibleObject element = parameter.getElement();
        final CmdOptionHandler handler = parameter.getCmdOptionHandler();

        if (!dryrun) {
          try {
            debug("Apply main parameter from parameters: {0}", FList.mkString(optionArgs, ", "));
            final boolean origAccessibleFlag = element.isAccessible();
            if (!origAccessibleFlag) {
              element.setAccessible(true);
            }
            handler.applyParams(parameter.getObject(), element, optionArgs, param);
            if (!origAccessibleFlag) {
              // do not leave doors open
              element.setAccessible(origAccessibleFlag);
            }
          } catch (final CmdOptionHandlerException e) {
            throw new CmdlineParserException(e.getMessage(), e, e.getLocalizedMessage());
          } catch (final Exception e) {
            final PreparedI18n msg =
                i18n.preparetr(
                    "Could not apply parameters {0} to field/method {1}",
                    Arrays.toString(optionArgs), element);
            throw new CmdlineParserException(msg.notr(), e, msg.tr());
          }
        }

      } else {
        final PreparedI18n msg =
            i18n.preparetr("Unsupported option or parameter found: {0}", param);
        throw new CmdlineParserException(msg.notr(), msg.tr());
      }
    }

    if (!detectHelpAndSkipValidation || !helpDetected) {
      // Validate optionCount matches allowed
      for (final Entry<OptionHandle, Integer> optionC : optionCount.entrySet()) {
        final OptionHandle option = optionC.getKey();
        final Integer count = optionC.getValue();
        if (count < option.getMinCount()
            || (option.getMaxCount() > 0 && count > option.getMaxCount())) {
          final PreparedI18n rangeMsg;
          if (option.getMaxCount() < 0) {
            rangeMsg = i18n.preparetr("at least {0}", option.getMinCount());
          } else {
            if (option.getMinCount() == option.getMaxCount()) {
              rangeMsg = i18n.preparetr("exactly {0}", option.getMinCount());
            } else {
              rangeMsg =
                  i18n.preparetr("between {0} and {1}", option.getMinCount(), option.getMaxCount());
            }
          }
          final String msg;
          final Object[] msgArgs;
          final Object[] msgArgsTr;
          if (option.getNames() == null || option.getNames().length == 0) {
            msg =
                I18n.marktr(
                    "Main parameter \"{0}\" was given {1} times, but must be given {2} times");
            msgArgs = new Object[] {FList.mkString(option.getArgs(), " "), count, rangeMsg.notr()};
            msgArgsTr = new Object[] {FList.mkString(option.getArgs(), " "), count, rangeMsg.tr()};
          } else {
            msg = I18n.marktr("Option \"{0}\" was given {1} times, but must be given {2} times");
            msgArgs = new Object[] {option.getNames()[0], count, rangeMsg.notr()};
            msgArgsTr = new Object[] {option.getNames()[0], count, rangeMsg.tr()};
          }
          throw new CmdlineParserException(
              MessageFormat.format(msg, msgArgs), i18n.tr(msg, msgArgsTr));
        }
      }

      // Validate required options because of 'required' attribute in
      // other options
      for (final Entry<OptionHandle, Integer> optionC : optionCount.entrySet()) {
        if (optionC.getValue() > 0) {
          final OptionHandle calledOption = optionC.getKey();
          for (final String required : calledOption.getRequires()) {
            // check, of an option was called with that name, if
            // not, this is an error
            final OptionHandle reqOptionHandle = quickOptionMap.get(required);
            if (reqOptionHandle == null) {
              // required option does not exists, error
              // TODO: error

            } else {
              final Integer reqOptionCount = optionCount.get(reqOptionHandle);
              if (reqOptionCount == null || reqOptionCount.intValue() <= 0) {
                // required option was not called, this is an
                // error
                final PreparedI18n msg =
                    i18n.preparetr(
                        "When using option \"{0}\" also option \"{1}\" must be given.",
                        calledOption.getNames()[0], required);
                throw new CmdlineParserException(msg.notr(), msg.tr());
              }
            }
          }
          for (final String conflict : calledOption.getConflictsWith()) {
            // check, of an option was called with that name, if
            // not, this is an error
            final OptionHandle conflictOptionHandle = quickOptionMap.get(conflict);
            if (conflictOptionHandle == null) {
              // conflicting option does not exists, error
              // TODO: error

            } else {
              final Integer conflictOptionCount = optionCount.get(conflictOptionHandle);
              if (conflictOptionCount != null && conflictOptionCount.intValue() > 0) {
                // conflicting option was called, this is an
                // conflict
                final PreparedI18n msg =
                    i18n.preparetr(
                        "Options \"{0}\" and \"{1}\" cannot be used at the same time.",
                        calledOption.getNames()[0], conflict);
                throw new CmdlineParserException(msg.notr(), msg.tr());
              }
            }
          }
        }
      }
    }
  }