org.kitesdk.compat.DynConstructors Maven / Gradle / Ivy
Show all versions of kite-hadoop-compatibility Show documentation
/*
* Copyright 2013 Cloudera Inc.
*
* 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 org.kitesdk.compat;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.security.AccessController;
import java.security.PrivilegedAction;
public class DynConstructors {
public static class Ctor extends DynMethods.UnboundMethod {
private final Constructor ctor;
private final Class extends C> constructed;
private Ctor(Constructor constructor, Class extends C> constructed) {
super(null, "newInstance");
this.ctor = constructor;
this.constructed = constructed;
}
public Class extends C> getConstructedClass() {
return constructed;
}
public C newInstanceChecked(Object... args) throws Exception {
try {
return ctor.newInstance(args);
} catch (InstantiationException e) {
throw e;
} catch (IllegalAccessException e) {
throw e;
} catch (InvocationTargetException e) {
// rethrow the cause is an exception
Throwables.propagateIfPossible(e.getCause(), Exception.class);
// otherwise, propagate the throwable
throw Throwables.propagate(e.getCause());
}
}
public C newInstance(Object... args) {
try {
return newInstanceChecked(args);
} catch (Exception e) {
throw Throwables.propagate(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(target, 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 boolean isStatic() {
return true;
}
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("constructor", ctor)
.add("class", constructed)
.toString();
}
}
public static class Builder {
private final Class> baseClass;
private ClassLoader loader = Thread.currentThread().getContextClassLoader();
private Ctor ctor = null;
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(Class>... types) {
impl(baseClass, types);
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 e) {
// cannot load this implementation
} catch (ClassNotFoundException e) {
// not the right implementation
}
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
}
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 e) {
// cannot load this implementation
} catch (ClassNotFoundException e) {
// not the right implementation
}
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
} catch (NoSuchMethodException e) {
// not the right implementation
}
return this;
}
@SuppressWarnings("unchecked")
public Ctor buildChecked() throws NoSuchMethodException {
if (ctor != null) {
return ctor;
}
throw new NoSuchMethodException(
"Cannot find constructor for " + baseClass);
}
@SuppressWarnings("unchecked")
public Ctor build() {
if (ctor != null) {
return ctor;
}
throw new RuntimeException("Cannot find constructor for " + baseClass);
}
}
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;
}
}
}