5

First off I have seen Load Java-Byte-Code at Runtime and it was helpful in so far as getting to me to the same spot I'm stuck at currently.

I'm trying to load a class from a byte array to avoid storing a file on disk. For testing purpose in this example I am simply reading in a .class file into a byte array so obviously the file is still stored on disk, but it is just to see if the code can work.

I take this byte array and then use a custom ClassLoader with the method loadClass to load a Class, but it doesn't work.

    byte[] bytearray = null;
    try{    
    RandomAccessFile f = new RandomAccessFile("/sdcard/ClassToGet.dex", "r");
    bytearray = new byte[(int) f.length()];
    f.read(bytearray);

    MyClassLoader classloader = new MyClassLoader();
    classloader.setBuffer(bytearray); 
    classloader.loadClass("com.pack.ClassIWant");
    } 

Here is the ClassLoader implementation:

public class MyClassLoader extends DexClassLoader {

 private byte[] buffer;

  @Override
    public Class findClass(String className){
    byte[] b = getBuffer();
    return this.defineClass(className, b, 0, b.length);
    }

public void setBuffer(byte[] b){
    buffer = b;
}
public byte[] getBuffer(){
    return buffer;
}

And the error I am receiving is this:

java.lang.UnsupportedOperationException: can't load this type of class file at java.lang.VMClassLoader.defineClass(Native Method)

I have supplied it with .class files, .dex files, .apk, .jar, etc... I have no idea what "type of class file" it wants from me and the documentation on it is nonexistent. Any help would be great I've been trying to get this work for four days straight.

4
  • stackoverflow.com/a/3024261/61855 Commented Aug 4, 2012 at 8:12
  • I'm still getting the same error message of "UnsupportedOperationException" even using the dex files / jar files. What did you end up doing from your example? Commented Aug 6, 2012 at 17:29
  • Who are you adressing? Me? If you reference to my question which you linked: I was not using Android for this project, so no problems there. Commented Aug 6, 2012 at 18:59
  • Android 26 has InMemoryDexClassLoader developer.android.com/reference/dalvik/system/… Commented Oct 28, 2017 at 11:26

3 Answers 3

2

I have the same problem that you have.

The reason why I get the error "can't load this type of class file" is simple.

In the platform source, "/dalvik/vm/native/java_lang_VMClassLoader.cpp" which is related to the method "defineClass" always returns exception as follows. (version: ICS)

Finally, I reached the conclusion that I can't load .dex in byte array format.

Is there anyone who can load .dex by using byte array? (not using files)

/*
 * static Class defineClass(ClassLoader cl, String name,
 *     byte[] data, int offset, int len)
 *     throws ClassFormatError
 *
 * Convert an array of bytes to a Class object.
 */
static void Dalvik_java_lang_VMClassLoader_defineClass(const u4* args, JValue* pResult)
{
    Object* loader = (Object*) args[0];
    StringObject* nameObj = (StringObject*) args[1];
    const u1* data = (const u1*) args[2];
    int offset = args[3];
    int len = args[4];
    char* name = NULL;

    name = dvmCreateCstrFromString(nameObj);
    ALOGE("ERROR: defineClass(%p, %s, %p, %d, %d)",
        loader, name, data, offset, len);
    dvmThrowUnsupportedOperationException(
        "can't load this type of class file");

    free(name);
    RETURN_VOID();
}

/*
 * static Class defineClass(ClassLoader cl, byte[] data, int offset,
 *     int len)
 *     throws ClassFormatError
 *
 * Convert an array of bytes to a Class object. Deprecated version of
 * previous method, lacks name parameter.
 */
static void Dalvik_java_lang_VMClassLoader_defineClass2(const u4* args, JValue* pResult)
{
    Object* loader = (Object*) args[0];
    const u1* data = (const u1*) args[1];
    int offset = args[2];
    int len = args[3];

    ALOGE("ERROR: defineClass(%p, %p, %d, %d)",
        loader, data, offset, len);
    dvmThrowUnsupportedOperationException(
        "can't load this type of class file");

    RETURN_VOID();
}
Sign up to request clarification or add additional context in comments.

1 Comment

Looking at that code it appears that defineClass ALWAYS throws the unsupported operation exception no matter what input, which is in tune to what you said. If that's the case why even allow it into the API??
1

Make sure your .dex file is a genuine dx-produced Dalvik executable and not a Java .class file in disguise. If you use the .dex extension the file must be a .dex file; otherwise use a .jar extension for a ZIP file that contains a classes.dex entry.

Not all versions of Dalvik can load classes from memory. You can work around this by loading the class from the file system. There's an example in DexMaker's generateAndLoad method:

    byte[] dex = ...

    /*
     * This implementation currently dumps the dex to the filesystem. It
     * jars the emitted .dex for the benefit of Gingerbread and earlier
     * devices, which can't load .dex files directly.
     *
     * TODO: load the dex from memory where supported.
     */
    File result = File.createTempFile("Generated", ".jar", dexCache);
    result.deleteOnExit();
    JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(result));
    jarOut.putNextEntry(new JarEntry(DexFormat.DEX_IN_JAR_NAME));
    jarOut.write(dex);
    jarOut.closeEntry();
    jarOut.close();
    try {
        return (ClassLoader) Class.forName("dalvik.system.DexClassLoader")
                .getConstructor(String.class, String.class, String.class, ClassLoader.class)
                .newInstance(result.getPath(), dexCache.getAbsolutePath(), null, parent);
    } catch (ClassNotFoundException e) {
        throw new UnsupportedOperationException("load() requires a Dalvik VM", e);
    } catch (InvocationTargetException e) {
        throw new RuntimeException(e.getCause());
    } catch (InstantiationException e) {
        throw new AssertionError();
    } catch (NoSuchMethodException e) {
        throw new AssertionError();
    } catch (IllegalAccessException e) {
        throw new AssertionError();
    }

Comments

0

Android does not run JVM bytecode, but Dalvik bytecode. So your operation should include this line before defineClass()

context.setOptimizationLevel(-1);

3 Comments

Could you go into a little more detail on what that does / how to use it? The only examples I see from a quick google search are using Rhino which I am not using. Why wouldn't loading a .dex file suffice instead of the .class?
I looked into in some more and noticed this answer on SO. I bet it would help you. You will have to store it as a .dex
I am still receiving the same Error of "UnsupportedOperationException: can't load this type of class file" for .dex files as well. I have tried .class, .dex, .apk, and .jar and none work. What am I doing wrong?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.