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

org.apache.kyuubi.util.reflect.DynConstructors 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.
 */

package org.apache.kyuubi.util.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/** Copied from parquet-common */
public class DynConstructors {

  private DynConstructors() {}

  public static class Ctor extends DynMethods.UnboundMethod {
    private final Constructor ctor;
    private final Class constructed;

    private Ctor(Constructor constructor, Class constructed) {
      super(null, "newInstance");
      this.ctor = constructor;
      this.constructed = constructed;
    }

    public Class getConstructedClass() {
      return constructed;
    }

    public C newInstanceChecked(Object... args) throws Exception {
      try {
        if (args.length > ctor.getParameterCount()) {
          return ctor.newInstance(Arrays.copyOfRange(args, 0, ctor.getParameterCount()));
        } else {
          return ctor.newInstance(args);
        }
      } catch (InstantiationException | IllegalAccessException e) {
        throw e;
      } catch (InvocationTargetException e) {
        if (e.getCause() instanceof Exception) {
          throw (Exception) e.getCause();
        }
        if (e.getCause() instanceof RuntimeException) {
          throw (RuntimeException) e.getCause();
        }
        throw new RuntimeException(e.getCause());
      }
    }

    public C newInstance(Object... args) {
      try {
        return newInstanceChecked(args);
      } catch (Exception e) {
        if (e instanceof RuntimeException) {
          throw (RuntimeException) e;
        }
        throw new RuntimeException(e);
      }
    }

    @Override
    @SuppressWarnings("unchecked")
    public  R invoke(Object target, Object... args) {
      if (target != null) {
        throw new IllegalArgumentException("Invalid call to constructor: target must be null");
      }
      return (R) newInstance(args);
    }

    @Override
    @SuppressWarnings("unchecked")
    public  R invokeChecked(Object target, Object... args) throws Exception {
      if (target != null) {
        throw new IllegalArgumentException("Invalid call to constructor: target must be null");
      }
      return (R) newInstanceChecked(args);
    }

    @Override
    public DynMethods.BoundMethod bind(Object receiver) {
      throw new IllegalStateException("Cannot bind constructors");
    }

    @Override
    public boolean isStatic() {
      return true;
    }

    @Override
    public String toString() {
      return getClass().getSimpleName() + "(constructor=" + ctor + ", class=" + constructed + ")";
    }
  }

  public static Builder builder() {
    return new Builder();
  }

  public static Builder builder(Class baseClass) {
    return new Builder(baseClass);
  }

  @SuppressWarnings("rawtypes")
  public static class Builder {
    private final Class baseClass;
    private ClassLoader loader = Thread.currentThread().getContextClassLoader();
    private Ctor ctor = null;
    private Map problems = new HashMap<>();

    public Builder(Class baseClass) {
      this.baseClass = baseClass;
    }

    public Builder() {
      this.baseClass = null;
    }

    /**
     * Set the {@link ClassLoader} used to lookup classes by name.
     *
     * 

If not set, the current thread's ClassLoader is used. * * @param newLoader a ClassLoader * @return this Builder for method chaining */ public Builder loader(ClassLoader newLoader) { this.loader = newLoader; return this; } public Builder impl(String className, Class... types) { // don't do any work if an implementation has been found if (ctor != null) { return this; } try { Class targetClass = Class.forName(className, true, loader); impl(targetClass, types); } catch (NoClassDefFoundError | ClassNotFoundException e) { // cannot load this implementation problems.put(className, e); } return this; } public Builder impl(Class targetClass, Class... types) { // don't do any work if an implementation has been found if (ctor != null) { return this; } try { ctor = new Ctor(targetClass.getConstructor(types), targetClass); } catch (NoSuchMethodException e) { // not the right implementation problems.put(methodName(targetClass, types), e); } return this; } public Builder hiddenImpl(Class... types) { hiddenImpl(baseClass, types); return this; } @SuppressWarnings({"unchecked", "rawtypes"}) public Builder hiddenImpl(String className, Class... types) { // don't do any work if an implementation has been found if (ctor != null) { return this; } try { Class targetClass = Class.forName(className, true, loader); hiddenImpl(targetClass, types); } catch (NoClassDefFoundError | ClassNotFoundException e) { // cannot load this implementation problems.put(className, e); } return this; } public Builder hiddenImpl(Class targetClass, Class... types) { // don't do any work if an implementation has been found if (ctor != null) { return this; } try { Constructor hidden = targetClass.getDeclaredConstructor(types); AccessController.doPrivileged(new MakeAccessible(hidden)); ctor = new Ctor(hidden, targetClass); } catch (SecurityException e) { // unusable problems.put(methodName(targetClass, types), e); } catch (NoSuchMethodException e) { // not the right implementation problems.put(methodName(targetClass, types), e); } return this; } @SuppressWarnings("unchecked") public Ctor buildChecked() throws NoSuchMethodException { if (ctor != null) { return ctor; } throw buildCheckedException(baseClass, problems); } @SuppressWarnings("unchecked") public Ctor build() { if (ctor != null) { return ctor; } throw buildRuntimeException(baseClass, problems); } } private static class MakeAccessible implements PrivilegedAction { private Constructor hidden; MakeAccessible(Constructor hidden) { this.hidden = hidden; } @Override public Void run() { hidden.setAccessible(true); return null; } } private static NoSuchMethodException buildCheckedException( Class baseClass, Map problems) { NoSuchMethodException exc = new NoSuchMethodException( "Cannot find constructor for " + baseClass + "\n" + formatProblems(problems)); problems.values().forEach(exc::addSuppressed); return exc; } private static RuntimeException buildRuntimeException( Class baseClass, Map problems) { RuntimeException exc = new RuntimeException( "Cannot find constructor for " + baseClass + "\n" + formatProblems(problems)); problems.values().forEach(exc::addSuppressed); return exc; } private static String formatProblems(Map problems) { StringBuilder sb = new StringBuilder(); boolean first = true; for (Map.Entry problem : problems.entrySet()) { if (first) { first = false; } else { sb.append("\n"); } sb.append("\tMissing ") .append(problem.getKey()) .append(" [") .append(problem.getValue().getClass().getName()) .append(": ") .append(problem.getValue().getMessage()) .append("]"); } return sb.toString(); } private static String methodName(Class targetClass, Class... types) { StringBuilder sb = new StringBuilder(); sb.append(targetClass.getName()).append("("); boolean first = true; for (Class type : types) { if (first) { first = false; } else { sb.append(","); } sb.append(type.getName()); } sb.append(")"); return sb.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy