0

So I have my own classloader class ServerLoader which is able to load classes from the local server with path http://localhost/app/1/ where are some .class files exist. But my program crashes when I try to define byte code of some class.

result = defineClass(name, ByteClass, 0, ByteClass.length);

So I am getting a Exception in thread "main" java.lang.NoClassDefFoundError: java/lang/Object

Here is the whole class:

package com.local;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

public class ServerLoader extends ClassLoader {

    private ClassLoader parent;
    private String urlPath;

    public ServerLoader(String urlPath) {
        parent = ServerLoader.class.getClassLoader();
        this.urlPath = urlPath;
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {

        Class<?> result = null;

        try {
            URL mainUrl = new URL(urlPath + name.substring(11);
            HttpURLConnection conn = (HttpURLConnection) mainUrl.openConnection();
            conn.setRequestMethod("GET");

            ByteArrayOutputStream out = new ByteArrayOutputStream();
            BufferedInputStream input = new BufferedInputStream(conn.getInputStream());

            int data;
            while ((data = input.read()) != -1) {
                out.write(data);
            }

            byte[] ByteClass = out.toByteArray();
            result = defineClass(name, ByteClass, 0, ByteClass.length);
            cacheClass.put(result.getName(), result);
            return result;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

}    

So here is main method

package com.local;

import java.lang.reflect.Method;

public class Main {

    public static void main(String[] args) throws Exception {
        ServerLoader loader = new ServerLoader("http://localhost/app/1/");

        Class<?> remoteInstanceClass = loader.loadClass("com.server.PluginA");

        Method mainMethod = remoteInstanceClass.getMethod("main", String[].class);
        mainMethod.invoke(remoteInstanceClass, (Object) args);
    }
}

And stack trace

com.local.Main
    Connected to the target VM, address: '127.0.0.1:54553', transport: 'socket'
    java.io.FileNotFoundException: http://localhost/app/1/Object.class
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1836)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
        at com.local.ServerLoader.ConnectAndResolveClass(ServerLoader.java:43)
        at com.local.ServerLoader.loadClass(ServerLoader.java:28)
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
        at com.local.ServerLoader.ConnectAndResolveClass(ServerLoader.java:51)
        at com.local.ServerLoader.loadClass(ServerLoader.java:28)
        at com.local.Main.main(Main.java:10)
    Exception in thread "main" java.lang.NoClassDefFoundError: java/lang/Object
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
        at com.local.ServerLoader.ConnectAndResolveClass(ServerLoader.java:51)
        at com.local.ServerLoader.loadClass(ServerLoader.java:28)
        at com.local.Main.main(Main.java:10)
    Disconnected from the target VM, address: '127.0.0.1:54553', transport: 'socket'

Process finished with exit code 1

All pathes and names are correct. So what can cause the problem?

Ivan
  • 1
  • 2

1 Answers1

0

I solved this problem. Every ClassLoader in LoadClass method must at first load the class using parent ClassLoader and then try to load it in another way. So this is correct LoadClass method.

@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {

    Class<?> result = null;

    try {
        result = parent.loadClass(name);
    } catch (ClassNotFoundException e) {
        try {
            URL mainURL = new URL(urlPath + name.substring(name.lastIndexOf('.') + 1) + ".class");
            HttpURLConnection conn = (HttpURLConnection) mainURL.openConnection();
            conn.setRequestMethod("GET");

            ByteArrayOutputStream out = new ByteArrayOutputStream();
            BufferedInputStream input = new BufferedInputStream(conn.getInputStream());

            int data;
            while ((data = input.read()) != -1) {
                out.write(data);
            }

            byte[] byteClass = out.toByteArray();
            result = defineClass(name, byteClass, 0, byteClass.length);

        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }

    return result;
}

You asked about example class:

package com.server;

public class PluginE {
    public static void main(String[] args) {
        System.out.println("Executing main method of PluginE");

    }
}
Ivan
  • 1
  • 2