alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (FuturesGetChecked.java)

This example Java source code file (FuturesGetChecked.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

annotation, boolean, canignorereturnvalue, class, classvalue, exception, executionexception, future, futuresgetchecked, getcheckedtypevalidator, list, override, reflection, threading, threads, throwable, util, visiblefortesting

The FuturesGetChecked.java Java example source code

/*
 * Copyright (C) 2006 The Guava Authors
 *
 * 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 com.google.common.util.concurrent;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.Thread.currentThread;
import static java.util.Arrays.asList;

import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.collect.Ordering;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.j2objc.annotations.J2ObjCIncompatible;

import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;

import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import javax.annotation.Nullable;

/**
 * Static methods used to implement {@link Futures#getChecked(Future, Class)}.
 */
@GwtIncompatible
final class FuturesGetChecked {
  @CanIgnoreReturnValue
  static <V, X extends Exception> V getChecked(Future future, Class exceptionClass) throws X {
    return getChecked(bestGetCheckedTypeValidator(), future, exceptionClass);
  }

  /**
   * Implementation of {@link Futures#getChecked(Future, Class)}.
   */
  @CanIgnoreReturnValue
  @VisibleForTesting
  static <V, X extends Exception> V getChecked(
      GetCheckedTypeValidator validator, Future<V> future, Class exceptionClass) throws X {
    validator.validateClass(exceptionClass);
    try {
      return future.get();
    } catch (InterruptedException e) {
      currentThread().interrupt();
      throw newWithCause(exceptionClass, e);
    } catch (ExecutionException e) {
      wrapAndThrowExceptionOrError(e.getCause(), exceptionClass);
      throw new AssertionError();
    }
  }

  /**
   * Implementation of {@link Futures#getChecked(Future, Class, long, TimeUnit)}.
   */
  @CanIgnoreReturnValue
  static <V, X extends Exception> V getChecked(
      Future<V> future, Class exceptionClass, long timeout, TimeUnit unit) throws X {
    // TODO(cpovirk): benchmark a version of this method that accepts a GetCheckedTypeValidator
    bestGetCheckedTypeValidator().validateClass(exceptionClass);
    try {
      return future.get(timeout, unit);
    } catch (InterruptedException e) {
      currentThread().interrupt();
      throw newWithCause(exceptionClass, e);
    } catch (TimeoutException e) {
      throw newWithCause(exceptionClass, e);
    } catch (ExecutionException e) {
      wrapAndThrowExceptionOrError(e.getCause(), exceptionClass);
      throw new AssertionError();
    }
  }

  @VisibleForTesting
  interface GetCheckedTypeValidator {
    void validateClass(Class<? extends Exception> exceptionClass);
  }

  private static GetCheckedTypeValidator bestGetCheckedTypeValidator() {
    return GetCheckedTypeValidatorHolder.BEST_VALIDATOR;
  }

  @VisibleForTesting
  static GetCheckedTypeValidator weakSetValidator() {
    return GetCheckedTypeValidatorHolder.WeakSetValidator.INSTANCE;
  }

  @J2ObjCIncompatible // ClassValue
  @VisibleForTesting
  static GetCheckedTypeValidator classValueValidator() {
    return GetCheckedTypeValidatorHolder.ClassValueValidator.INSTANCE;
  }

  /**
   * Provides a check of whether an exception type is valid for use with
   * {@link FuturesGetChecked#getChecked(Future, Class)}, possibly using caching.
   *
   * <p>Uses reflection to gracefully fall back to when certain implementations aren't available.
   */
  @VisibleForTesting
  static class GetCheckedTypeValidatorHolder {
    static final String CLASS_VALUE_VALIDATOR_NAME =
        GetCheckedTypeValidatorHolder.class.getName() + "$ClassValueValidator";

    static final GetCheckedTypeValidator BEST_VALIDATOR = getBestValidator();

    @IgnoreJRERequirement // getChecked falls back to another implementation if necessary
    @J2ObjCIncompatible // ClassValue
    enum ClassValueValidator implements GetCheckedTypeValidator {
      INSTANCE;

      /*
       * Static final fields are presumed to be fastest, based on our experience with
       * UnsignedBytesBenchmark. TODO(cpovirk): benchmark this
       */
      private static final ClassValue<Boolean> isValidClass =
          new ClassValue<Boolean>() {
            @Override
            protected Boolean computeValue(Class<?> type) {
              checkExceptionClassValidity(type.asSubclass(Exception.class));
              return true;
            }
          };

      @Override
      public void validateClass(Class<? extends Exception> exceptionClass) {
        isValidClass.get(exceptionClass); // throws if invalid; returns safely (and caches) if valid
      }
    }

    enum WeakSetValidator implements GetCheckedTypeValidator {
      INSTANCE;

      /*
       * Static final fields are presumed to be fastest, based on our experience with
       * UnsignedBytesBenchmark. TODO(cpovirk): benchmark this
       */
      /*
       * A CopyOnWriteArraySet<WeakReference> is faster than a newSetFromMap of a MapMaker map with
       * weakKeys() and concurrencyLevel(1), even up to at least 12 cached exception types.
       */
      private static final Set<WeakReference> validClasses =
          new CopyOnWriteArraySet<WeakReference>();

      @Override
      public void validateClass(Class<? extends Exception> exceptionClass) {
        for (WeakReference<Class knownGood : validClasses) {
          if (exceptionClass.equals(knownGood.get())) {
            return;
          }
          // TODO(cpovirk): if reference has been cleared, remove it?
        }
        checkExceptionClassValidity(exceptionClass);

        /*
         * It's very unlikely that any loaded Futures class will see getChecked called with more
         * than a handful of exceptions. But it seems prudent to set a cap on how many we'll cache.
         * This avoids out-of-control memory consumption, and it keeps the cache from growing so
         * large that doing the lookup is noticeably slower than redoing the work would be.
         *
         * Ideally we'd have a real eviction policy, but until we see a problem in practice, I hope
         * that this will suffice. I have not even benchmarked with different size limits.
         */
        if (validClasses.size() > 1000) {
          validClasses.clear();
        }

        validClasses.add(new WeakReference<Class(exceptionClass));
      }
    }

    /**
     * Returns the ClassValue-using validator, or falls back to the "weak Set" implementation if
     * unable to do so.
     */
    static GetCheckedTypeValidator getBestValidator() {
      try {
        Class<?> theClass = Class.forName(CLASS_VALUE_VALIDATOR_NAME);
        return (GetCheckedTypeValidator) theClass.getEnumConstants()[0];
      } catch (Throwable t) { // ensure we really catch *everything*
        return weakSetValidator();
      }
    }
  }

  // TODO(cpovirk): change parameter order to match other helper methods (Class, Throwable)?
  private static <X extends Exception> void wrapAndThrowExceptionOrError(
      Throwable cause, Class<X> exceptionClass) throws X {
    if (cause instanceof Error) {
      throw new ExecutionError((Error) cause);
    }
    if (cause instanceof RuntimeException) {
      throw new UncheckedExecutionException(cause);
    }
    throw newWithCause(exceptionClass, cause);
  }

  /*
   * TODO(user): FutureChecker interface for these to be static methods on? If so, refer to it in
   * the (static-method) Futures.getChecked documentation
   */

  private static boolean hasConstructorUsableByGetChecked(
      Class<? extends Exception> exceptionClass) {
    try {
      Exception unused = newWithCause(exceptionClass, new Exception());
      return true;
    } catch (Exception e) {
      return false;
    }
  }

  private static <X extends Exception> X newWithCause(Class exceptionClass, Throwable cause) {
    // getConstructors() guarantees this as long as we don't modify the array.
    @SuppressWarnings({"unchecked", "rawtypes"})
    List<Constructor constructors = (List) Arrays.asList(exceptionClass.getConstructors());
    for (Constructor<X> constructor : preferringStrings(constructors)) {
      @Nullable X instance = newFromConstructor(constructor, cause);
      if (instance != null) {
        if (instance.getCause() == null) {
          instance.initCause(cause);
        }
        return instance;
      }
    }
    throw new IllegalArgumentException(
        "No appropriate constructor for exception of type "
            + exceptionClass
            + " in response to chained exception",
        cause);
  }

  private static <X extends Exception> List> preferringStrings(
      List<Constructor constructors) {
    return WITH_STRING_PARAM_FIRST.sortedCopy(constructors);
  }

  private static final Ordering<Constructor WITH_STRING_PARAM_FIRST =
      Ordering.natural()
          .onResultOf(
              new Function<Constructor() {
                @Override
                public Boolean apply(Constructor<?> input) {
                  return asList(input.getParameterTypes()).contains(String.class);
                }
              })
          .reverse();

  @Nullable
  private static <X> X newFromConstructor(Constructor constructor, Throwable cause) {
    Class<?>[] paramTypes = constructor.getParameterTypes();
    Object[] params = new Object[paramTypes.length];
    for (int i = 0; i < paramTypes.length; i++) {
      Class<?> paramType = paramTypes[i];
      if (paramType.equals(String.class)) {
        params[i] = cause.toString();
      } else if (paramType.equals(Throwable.class)) {
        params[i] = cause;
      } else {
        return null;
      }
    }
    try {
      return constructor.newInstance(params);
    } catch (IllegalArgumentException e) {
      return null;
    } catch (InstantiationException e) {
      return null;
    } catch (IllegalAccessException e) {
      return null;
    } catch (InvocationTargetException e) {
      return null;
    }
  }

  @VisibleForTesting
  static boolean isCheckedException(Class<? extends Exception> type) {
    return !RuntimeException.class.isAssignableFrom(type);
  }

  @VisibleForTesting
  static void checkExceptionClassValidity(Class<? extends Exception> exceptionClass) {
    checkArgument(
        isCheckedException(exceptionClass),
        "Futures.getChecked exception type (%s) must not be a RuntimeException",
        exceptionClass);
    checkArgument(
        hasConstructorUsableByGetChecked(exceptionClass),
        "Futures.getChecked exception type (%s) must be an accessible class with an accessible "
            + "constructor whose parameters (if any) must be of type String and/or Throwable",
        exceptionClass);
  }

  private FuturesGetChecked() {}
}

Other Java examples (source code examples)

Here is a short list of links related to this Java FuturesGetChecked.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.