eu.stratosphere.util.InstantiationUtil Maven / Gradle / Ivy
/***********************************************************************************************************************
* Copyright (C) 2010-2013 by the Stratosphere project (http://stratosphere.eu)
*
* 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 eu.stratosphere.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import eu.stratosphere.configuration.Configuration;
/**
* Utility class to create instances from class objects and checking failure reasons.
*/
public class InstantiationUtil {
/**
* A custom ObjectInputStream that can also load user-code using a
* user-code ClassLoader.
*
*/
private static class ClassLoaderObjectInputStream extends ObjectInputStream {
private ClassLoader classLoader;
@Override
public Class> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (classLoader != null) {
return Class.forName(desc.getName(), false, classLoader);
}
return super.resolveClass(desc);
}
public ClassLoaderObjectInputStream(InputStream in, ClassLoader classLoader) throws IOException {
super(in);
this.classLoader = classLoader;
}
}
/**
* Creates a new instance of the given class.
*
* @param The generic type of the class.
* @param clazz The class to instantiate.
* @param castTo Optional parameter, specifying the class that the given class must be a subclass off. This
* argument is added to prevent class cast exceptions occurring later.
* @return An instance of the given class.
*
* @throws RuntimeException Thrown, if the class could not be instantiated. The exception contains a detailed
* message about the reason why the instantiation failed.
*/
public static T instantiate(Class clazz, Class super T> castTo) {
if (clazz == null) {
throw new NullPointerException();
}
// check if the class is a subclass, if the check is required
if (castTo != null && !castTo.isAssignableFrom(clazz)) {
throw new RuntimeException("The class '" + clazz.getName() + "' is not a subclass of '" +
castTo.getName() + "' as is required.");
}
return instantiate(clazz);
}
/**
* Creates a new instance of the given class.
*
* @param The generic type of the class.
* @param clazz The class to instantiate.
* @return An instance of the given class.
*
* @throws RuntimeException Thrown, if the class could not be instantiated. The exception contains a detailed
* message about the reason why the instantiation failed.
*/
public static T instantiate(Class clazz) {
if (clazz == null) {
throw new NullPointerException();
}
// try to instantiate the class
try {
return clazz.newInstance();
}
catch (InstantiationException iex) {
// check for the common problem causes
checkForInstantiation(clazz);
// here we are, if non of the common causes was the problem. then the error was
// most likely an exception in the constructor or field initialization
throw new RuntimeException("Could not instantiate type '" + clazz.getName() +
"' due to an unspecified exception: " + iex.getMessage(), iex);
}
catch (IllegalAccessException iaex) {
// check for the common problem causes
checkForInstantiation(clazz);
// here we are, if non of the common causes was the problem. then the error was
// most likely an exception in the constructor or field initialization
throw new RuntimeException("Could not instantiate type '" + clazz.getName() +
"' due to an unspecified exception: " + iaex.getMessage(), iaex);
}
catch (Throwable t) {
String message = t.getMessage();
throw new RuntimeException("Could not instantiate type '" + clazz.getName() +
"' Most likely the constructor (or a member variable initialization) threw an exception" +
(message == null ? "." : ": " + message), t);
}
}
/**
* Checks, whether the given class has a public nullary constructor.
*
* @param clazz The class to check.
* @return True, if the class has a public nullary constructor, false if not.
*/
public static boolean hasPublicNullaryConstructor(Class> clazz) {
Constructor>[] constructors = clazz.getConstructors();
for (int i = 0; i < constructors.length; i++) {
if (constructors[i].getParameterTypes().length == 0 &&
Modifier.isPublic(constructors[i].getModifiers())) {
return true;
}
}
return false;
}
/**
* Checks, whether the given class is public.
*
* @param clazz The class to check.
* @return True, if the class is public, false if not.
*/
public static boolean isPublic(Class> clazz) {
return Modifier.isPublic(clazz.getModifiers());
}
/**
* Checks, whether the class is a proper class, i.e. not abstract or an interface, and not a primitive type.
*
* @param clazz The class to check.
* @return True, if the class is a proper class, false otherwise.
*/
public static boolean isProperClass(Class> clazz) {
int mods = clazz.getModifiers();
return !(Modifier.isAbstract(mods) || Modifier.isInterface(mods) || Modifier.isNative(mods));
}
/**
* Checks, whether the class is an inner class that is not statically accessible. That is especially true for
* anonymous inner classes.
*
* @param clazz The class to check.
* @return True, if the class is a non-statically accessible inner class.
*/
public static boolean isNonStaticInnerClass(Class> clazz) {
if (clazz.getEnclosingClass() == null) {
// no inner class
return false;
} else {
// inner class
if (clazz.getDeclaringClass() != null) {
// named inner class
return !Modifier.isStatic(clazz.getModifiers());
} else {
// anonymous inner class
return true;
}
}
}
/**
* Performs a standard check whether the class can be instantiated by {@code Class#newInstance()}.
*
* @param clazz The class to check.
* @throws RuntimeException Thrown, if the class cannot be instantiated by {@code Class#newInstance()}.
*/
public static void checkForInstantiation(Class> clazz) {
final String errorMessage = checkForInstantiationError(clazz);
if (errorMessage != null) {
throw new RuntimeException("The class '" + clazz.getName() + "' is not instantiable: " + errorMessage);
}
}
public static String checkForInstantiationError(Class> clazz) {
if (!isPublic(clazz)) {
return "The class is not public.";
} else if (clazz.isArray()) {
return "The class is an array. An array cannot be simply instantiated, as with a parameterless constructor.";
} else if (!isProperClass(clazz)) {
return "The class is no proper class, it is either abstract, an interface, or a primitive type.";
} else if (isNonStaticInnerClass(clazz)) {
return "The class is an inner class, but not statically accessible.";
} else if (!hasPublicNullaryConstructor(clazz)) {
return "The class has no (implicit) public nullary constructor, i.e. a constructor without arguments.";
} else {
return null;
}
}
public static Object readObjectFromConfig(Configuration config, String key, ClassLoader cl) throws IOException, ClassNotFoundException {
byte[] bytes = config.getBytes(key, null);
if (bytes == null) {
return null;
}
return deserializeObject(bytes, cl);
}
public static void writeObjectToConfig(Object o, Configuration config, String key) throws IOException {
byte[] bytes = serializeObject(o);
config.setBytes(key, bytes);
}
public static Object deserializeObject(byte[] bytes, ClassLoader cl) throws IOException, ClassNotFoundException {
ObjectInputStream oois = null;
try {
oois = new ClassLoaderObjectInputStream(new ByteArrayInputStream(bytes), cl);
return oois.readObject();
} finally {
if (oois != null) {
oois.close();
}
}
}
public static byte[] serializeObject(Object o) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
return baos.toByteArray();
}
// --------------------------------------------------------------------------------------------
/**
* Private constructor to prevent instantiation.
*/
private InstantiationUtil() {
throw new RuntimeException();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy