如何从JNI中JAR文件的字节数组加载所有类<我的代码
#include <jni.h>
#include <string>
using namespace std;
int main() {
JavaVM* jvm;
JNIEnv* env;
long res = CreateJVM(&jvm, &env, "");
jclass class_loader = env->FindClass("java/lang/ClassLoader");
jobject system_loader = env->CallStaticObjectMethod(class_loader, env->GetStaticMethodID(class_loader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"));
jbyte* bytes = <bytes>
// define all classes from this bytes
env->DefineClass("Main", system_loader, bytes, sizeof(bytes));
...
if (res == JNI_OK) {
jclass cls = env->FindClass("Main");
jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(cls, mid, NULL);
}
jvm->DestroyJavaVM();
}
我需要读取JAR文件的字节,将它们转换成jbytes并从这些字节加载所有java类
比如java中的代码
final var classes = new ArrayList<byte[]>();
try( final var inputStream = new JarInputStream( new ByteArrayInputStream( bytes ) ) )
{
var entry = inputStream.getNextJarEntry();
while( nonNull( entry ) )
{
var buffer = new bytes [entry.getSize()];
inputStream.read( buffer, 0, entry.getSize()];
classes.add( buffer );
entry = inputStream.getNextJarEntry();
}
}
Java代码无法正确加载jar。至少它没有定义类或跟踪jar中条目的名称。
这适用于我过去测试过的所有罐子:
#include <jni.h>
#include <iostream>
#include <memory>
#include <vector>
struct JVM
{
JavaVM* vm;
JNIEnv* env;
};
JVM create_java_vm()
{
const char* argv[] = {"-Djava.compiler=NONE",
"-Djava.class.path=."}; //"-verbose:jni"
const int argc = static_cast<int>(sizeof(argv) / sizeof(argv[0]));
JavaVMInitArgs jvm_args;
JavaVMOption options[argc];
for (int i = 0; i < argc; ++i)
{
options[i].optionString = const_cast<char*>(argv[i]);
}
JavaVM* vm = nullptr;
JNIEnv* env = nullptr;
JNI_GetDefaultJavaVMInitArgs(&jvm_args);
jvm_args.version = JNI_VERSION_1_8;
jvm_args.nOptions = argc;
jvm_args.options = options;
jvm_args.ignoreUnrecognized = false;
if (JNI_CreateJavaVM(&vm, reinterpret_cast<void**>(&env), &jvm_args) != JNI_OK)
{
return {vm, env};
}
return {vm, env};
}
bool load_jar(JNIEnv* env, const std::vector<std::uint8_t> &jar_data, bool ignore_exceptions = false)
{
auto string_replace_all = [&](std::string str, const std::string& from, const std::string& to) -> std::string {
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos)
{
str.replace(start_pos, from.length(), to);
}
return str;
};
auto byte_array_input_stream = [](JNIEnv* env, const std::vector<std::uint8_t> &buffer) -> jobject {
jbyteArray arr = env->NewByteArray(static_cast<jsize>(buffer.size()));
if (arr)
{
env->SetByteArrayRegion(arr, 0, static_cast<jsize>(buffer.size()), reinterpret_cast<const jbyte*>(&buffer[0]));
jclass cls = env->FindClass("java/io/ByteArrayInputStream");
if (cls)
{
jmethodID method = env->GetMethodID(cls, "<init>", "([B)V");
if (method)
{
jobject result = env->NewObject(cls, method, arr);
if (result)
{
env->DeleteLocalRef(std::exchange(result, env->NewGlobalRef(result)));
env->DeleteLocalRef(cls);
env->DeleteLocalRef(arr);
return result;
}
}
env->DeleteLocalRef(cls);
}
env->DeleteLocalRef(arr);
}
return nullptr;
};
auto jar_input_stream = [](JNIEnv* env, jobject input_stream) -> jobject {
jclass cls = env->FindClass("java/util/jar/JarInputStream");
if (cls)
{
jmethodID method = env->GetMethodID(cls, "<init>", "(Ljava/io/InputStream;)V");
if (method)
{
jobject result = env->NewObject(cls, method, input_stream);
if (result)
{
env->DeleteLocalRef(std::exchange(result, env->NewGlobalRef(result)));
env->DeleteLocalRef(cls);
return result;
}
}
env->DeleteLocalRef(cls);
}
return nullptr;
};
auto input_stream_read = [](JNIEnv* env, jobject input_stream) -> jint {
jclass cls = env->GetObjectClass(input_stream);
if (cls)
{
jmethodID method = env->GetMethodID(cls, "read", "()I");
if (method)
{
jint result = env->CallIntMethod(input_stream, method);
env->DeleteLocalRef(cls);
return result;
}
env->DeleteLocalRef(cls);
}
return -1;
};
auto byte_array_output_stream = [](JNIEnv* env) -> jobject {
jclass cls = env->FindClass("java/io/ByteArrayOutputStream");
if (cls)
{
jmethodID method = env->GetMethodID(cls, "<init>", "()V");
if (method)
{
jobject result = env->NewObject(cls, method);
if (result)
{
env->DeleteLocalRef(std::exchange(result, env->NewGlobalRef(result)));
env->DeleteLocalRef(cls);
return result;
}
}
env->DeleteLocalRef(cls);
}
return nullptr;
};
auto output_stream_write = [](JNIEnv* env, jobject output_stream, jint value) {
jclass cls = env->GetObjectClass(output_stream);
if (cls)
{
jmethodID method = env->GetMethodID(cls, "write", "(I)V");
if (method)
{
env->CallVoidMethod(output_stream, method, value);
}
env->DeleteLocalRef(cls);
}
};
auto byte_array_output_stream_to_byte_array = [](JNIEnv* env, jobject output_stream) -> std::vector<std::uint8_t> {
jclass cls = env->GetObjectClass(output_stream);
if (cls)
{
jmethodID method = env->GetMethodID(cls, "toByteArray", "()[B");
if (method)
{
jbyteArray bytes = reinterpret_cast<jbyteArray>(env->CallObjectMethod(output_stream, method));
if (bytes)
{
void* arr = env->GetPrimitiveArrayCritical(bytes, nullptr);
if (arr)
{
jsize size = env->GetArrayLength(bytes);
auto result = std::vector<std::uint8_t>(static_cast<std::uint8_t*>(arr),
static_cast<std::uint8_t*>(arr) + size);
env->ReleasePrimitiveArrayCritical(bytes, arr, 0);
env->DeleteLocalRef(bytes);
env->DeleteLocalRef(cls);
return result;
}
}
}
env->DeleteLocalRef(cls);
}
return {};
};
auto get_next_jar_entry = [](JNIEnv* env, jobject jar_input_stream) -> jobject {
jclass cls = env->GetObjectClass(jar_input_stream);
if (cls)
{
jmethodID method = env->GetMethodID(cls, "getNextJarEntry", "()Ljava/util/jar/JarEntry;");
if (method)
{
jobject result = env->CallObjectMethod(jar_input_stream, method);
env->DeleteLocalRef(std::exchange(result, env->NewGlobalRef(result)));
env->DeleteLocalRef(cls);
return result;
}
env->DeleteLocalRef(cls);
}
return nullptr;
};
auto jar_entry_get_name = [](JNIEnv* env, jobject jar_entry) -> std::string {
jclass cls = env->FindClass("java/util/jar/JarEntry");
if (cls)
{
jmethodID method = env->GetMethodID(cls, "getName", "()Ljava/lang/String;");
if (method)
{
jstring jstr = reinterpret_cast<jstring>(env->CallObjectMethod(jar_entry, method));
const char *name_string = env->GetStringUTFChars(jstr, 0);
std::string result = std::string(name_string);
env->ReleaseStringUTFChars(jstr, name_string);
env->DeleteLocalRef(jstr);
env->DeleteLocalRef(cls);
return result;
}
env->DeleteLocalRef(cls);
}
return std::string();
};
// Load the Jar
jobject bais = byte_array_input_stream(env, jar_data);
if (!bais)
{
std::cerr<<"Failed to open ByteArrayInputStream\n";
return false;
}
jobject jis = jar_input_stream(env, bais);
if (!jis)
{
env->DeleteGlobalRef(bais);
std::cerr<<"Failed to open JarInputStream\n";
return false;
}
// Read the jar entries
jobject jar_entry = nullptr;
const std::string extension = ".class";
while((jar_entry = get_next_jar_entry(env, jis)))
{
std::string name = jar_entry_get_name(env, jar_entry);
if ((name.length() > extension.length()) && (name.rfind(extension) == name.length() - extension.length()))
{
jobject baos = byte_array_output_stream(env);
if (!baos)
{
std::cerr<<"Failed to open ByteArrayOutputStream for: "<<name<<"\n";
if (!ignore_exceptions)
{
env->DeleteGlobalRef(jar_entry);
env->DeleteGlobalRef(jis);
env->DeleteGlobalRef(bais);
return false;
}
}
// Define the class
jint value = -1;
while((value = input_stream_read(env, jis)) != -1)
{
output_stream_write(env, baos, value);
}
std::vector<std::uint8_t> bytes = byte_array_output_stream_to_byte_array(env, baos);
std::string canonicalName = string_replace_all(string_replace_all(name, "/", "."),
".class",
std::string());
jclass cls = env->DefineClass(string_replace_all(name, ".class", "").c_str(),
nullptr, reinterpret_cast<jbyte*>(bytes.data()),
static_cast<jint>(bytes.size()));
if (cls)
{
std::cerr<<"Defined: "<<canonicalName<<" Size: "<<bytes.size()<<"\n";
env->DeleteLocalRef(cls);
}
else
{
std::cerr<<"Failed to define: "<<canonicalName<<" Size: "<<bytes.size()<<"\n";
if (env->ExceptionCheck())
{
env->ExceptionDescribe();
env->ExceptionClear();
if (!ignore_exceptions)
{
env->DeleteGlobalRef(jar_entry);
env->DeleteGlobalRef(jis);
env->DeleteGlobalRef(bais);
return false;
}
}
}
}
else
{
std::cerr<<"Skipping Resource: "<<name<<"\n";
}
env->DeleteGlobalRef(jar_entry);
}
env->DeleteGlobalRef(jis);
env->DeleteGlobalRef(bais);
return true;
}
int main(int argc, const char* argv[])
{
JVM jvm = create_java_vm();
if (!jvm.vm)
{
std::cerr<<"Failed to Create JavaVM\n";
return 0;
}
if (load_jar(jvm.env, some_jar_as_bytes, true))
{
std::cout<<"Jar loaded successfully\n";
}
else
{
std::cerr<<"Failed to load Jar\n";
}
jvm.vm->DestroyJavaVM();
return 0;
}
我试图将一个类加载到字节数组中。MainC、Loader、ClassByte和byteClassLoader都是用来加载类的。 主C是起点。 这里我们加载类并调用方法。 在这里,我们可以获得要加载的类和字节数组。 包含字节的类加载器 下面是我想执行的类 Startclass的startmethod()是起点 和 但也有例外。 线程“main”java中的StartMethod 异常。朗。反思。在太
问题内容: 我想知道如何将字节数组加载到 内存 URLClassLoader中?字节数组是jar文件的解密字节(如下所示)! 大多数内存类加载器都使用ClassLoader而不是URLClassLoader!我需要它使用URLClassLoader。 谢谢! 问题答案: 我将在这里发布我过去做过的实现: 我的自定义ClassLoader:
问题内容: 给定任意实例,包括运行时生成的实例(磁盘上没有文件),是否有任何方法获取类字节? 问题答案: 通常,这是不可能的。在加载类时,JVM会解析其字节码并将其转换为内部表示形式。此后,JVM可以随意忘记原始字节码,这就是HotSpot JVM真正发生的情况。 但是,对于某些黑客,可以检查内部类表示并将其转换回有效的类文件(尽管它将与原始字节码不同)。在HotSpot JVM中,该过程用于重新
问题内容: 我正在尝试使用android NDK。 有没有办法将在JNI中创建的数组(以我的情况为例)返回给Java?如果是这样,请提供一个可以执行此操作的JNI函数的简单示例。 问题答案: 如果你已经阅读了文档,但仍然有一些问题应作为最初问题的一部分。在这种情况下,示例中的JNI函数将创建多个数组。外部数组由使用JNI函数创建的“对象”数组组成。从JNI的角度来看,这就是一个二维数组,即一个包含
问题内容: 我正在寻找编写一个自定义类加载器,它将通过自定义网络加载文件。最后,我要做的只是文件的字节数组。 我无法将字节数组转储到文件系统上并使用。 我的第一个计划是从流或字节数组创建对象,但它仅支持对象。 我已经写了一些使用的东西: 这对于小型文件可能很好用,但是我尝试加载包含几乎所有类的jar文件,它只是为了遍历所有条目而已,更不用说加载找到的类了。 如果有人知道一个解决方案比每次加载类都遍
我正在尝试从ODT模板文件生成一个PDF,其中包含我需要填充的字段。 我想获得这个ODT模板的字节数组,它存在于我的项目的根文件夹中。我的应用程序是以这样一种方式提供字节数组来生成PDF。