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

org.apache.parquet.util.DynConstructors Maven / Gradle / Ivy

/*
 * 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.parquet.util;

import org.apache.parquet.Preconditions;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;

import static org.apache.parquet.Exceptions.throwIfInstance;

public class 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 {
        return ctor.newInstance(args);
      } catch (InstantiationException | IllegalAccessException e) {
        throw e;
      } catch (InvocationTargetException e) {
        throwIfInstance(e.getCause(), Exception.class);
        throwIfInstance(e.getCause(), RuntimeException.class);
        throw new RuntimeException(e.getCause());
      }
    }

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

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

    @Override
    @SuppressWarnings("unchecked")
    public  R invokeChecked(Object target, Object... args) throws Exception {
      Preconditions.checkArgument(target == null,
          "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 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 loader a ClassLoader * @return this Builder for method chaining */ public Builder loader(ClassLoader loader) { this.loader = loader; 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") 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 (NoSuchMethodException | SecurityException e) { // unusable or 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 new NoSuchMethodException("Cannot find constructor for " + baseClass + "\n" + formatProblems(problems)); } @SuppressWarnings("unchecked") public Ctor build() { if (ctor != null) { return ctor; } throw new RuntimeException("Cannot find constructor for " + baseClass + "\n" + formatProblems(problems)); } } private static class MakeAccessible implements PrivilegedAction { private Constructor hidden; public MakeAccessible(Constructor hidden) { this.hidden = hidden; } @Override public Void run() { hidden.setAccessible(true); return null; } } 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