/*
* Copyright 2016 NAVER Corp.
*
* 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.navercorp.pinpoint.profiler.util;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
/**
* // TODO duplicate BytecodeUtils : com.navercorp.pinpoint.test.util.BytecodeUtils
*/
public final class BytecodeUtils {
private static final Method DEFINE_CLASS = getDefineClassMethod();
private BytecodeUtils() {
}
private static Method getDefineClassMethod() {
try {
final Method method = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
method.setAccessible(true);
return method;
} catch (NoSuchMethodException e) {
// link error
throw new RuntimeException("defineClass not found. Error:" + e.getMessage(), e);
} catch (SecurityException e) {
// link error
throw new RuntimeException("defineClass error. Error:" + e.getMessage(), e);
}
}
public static Class<?> defineClass(ClassLoader classLoader, String className, byte[] classFile) {
try {
return (Class<?>) DEFINE_CLASS.invoke(classLoader, className, classFile, 0, classFile.length);
} catch (Throwable ex) {
throw new RuntimeException("defineClass error. Caused:" + ex.getMessage(), ex);
}
}
public static byte[] getClassFile(ClassLoader classLoader, String className) {
if (classLoader == null) {
classLoader = ClassLoader.getSystemClassLoader();
}
if (className == null) {
throw new NullPointerException("className must not be null");
}
final String classInternalName = JavaAssistUtils.javaNameToJvmName(className);
final InputStream is = classLoader.getResourceAsStream(classInternalName + ".class");
if (is == null) {
throw new RuntimeException("No such class file: " + className);
}
try {
return readClass(is, false);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
close(is);
}
}
/**
* COPY ASM method. reference : org.objectweb.asm.ClassReader
*
* Reads the bytecode of a class.
*
* @param is
* an input stream from which to read the class.
* @param close
* true to close the input stream after reading.
* @return the bytecode read from the given input stream.
* @throws IOException
* if a problem occurs during reading.
*/
public static byte[] readClass(final InputStream is, boolean close)
throws IOException {
if (is == null) {
throw new IOException("Class not found");
}
try {
byte[] b = new byte[is.available()];
int len = 0;
while (true) {
int n = is.read(b, len, b.length - len);
if (n == -1) {
if (len < b.length) {
byte[] c = new byte[len];
System.arraycopy(b, 0, c, 0, len);
b = c;
}
return b;
}
len += n;
if (len == b.length) {
int last = is.read();
if (last < 0) {
return b;
}
byte[] c = new byte[b.length + 1000];
System.arraycopy(b, 0, c, 0, len);
c[len++] = (byte) last;
b = c;
}
}
} finally {
if (close) {
close(is);
}
}
}
private static void close(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException ignore) {
// skip
}
}
}
}