Grim
Grim

Reputation: 1986

Load jar using bytearray, cant find nested classes

Idea

I have a jar (postgresql-9.4.1208.jre7.jar) in a byte[]. Id like to load and connect and run some basic SQL commands in runtime.

Implementation

Therefore I created a new Classloader:

public class JarClassloader extends ClassLoader {

    public interface DriverProblemReporter {
        void reportDriverProblem(String name, Throwable e);
    }

    private final byte[] driverdata;

    private final DriverProblemReporter problemReporter;

    public JarClassloader(byte[] jar, String drivername, DriverProblemReporter reporter) {
        super(ClassLoader.getSystemClassLoader());
        this.problemReporter = reporter;

        try {
            JarInputStream jis = new JarInputStream(new ByteArrayInputStream(jar));
            JarEntry entry = jis.getNextJarEntry();
            while (entry != null) {
                handleEntry(entry, jis);
                entry = jis.getNextJarEntry();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        this.driverdata = jar;
    }

    private void handleEntry(JarEntry entry, JarInputStream jis) {
        if (!entry.isDirectory()) {
            ByteArrayOutputStream baos;
            try {
                baos = new ByteArrayOutputStream();
                IOUtils.copy(jis, baos);
                baos.flush();
            } catch (IOException e) {
                problemReporter.reportDriverProblem(entry.getName(), e);
                return;
            }
            try {
                defineClass(baos.toByteArray(), 0, baos.size());
            } catch (LinkageError e) {
                problemReporter.reportDriverProblem(entry.getName(), e);
            }
        }
    }
}

The Jar loads successfully and I am able to get a instance of the Driver.

Point of interrest

On the call to connect to a Database I get this Error:

java.lang.NoClassDefFoundError: org/postgresql/hostchooser/HostRequirement$1
    at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:107)
    at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:66)
    at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:215)
    at org.postgresql.Driver.makeConnection(Driver.java:406)
    at org.postgresql.Driver.connect(Driver.java:274)

In the stacktrace I see the working instance of org.postgresql.Driver looking for a class named org/postgresql/hostchooser/HostRequirement$1.

Assumption

My JarClassloader does not load anonymous nested classes.

Question

What shall I do to successfully load all classes in the jar?

Upvotes: 1

Views: 129

Answers (1)

user207421
user207421

Reputation: 310909

You need to load the classes in the order the classloader needs them, not in the order they happen to be in the JAR file. So you need to override the findClass() method and search the JAR file at that point for the class being requested.

It would be a lot simpler to use a file.

Upvotes: 1

Related Questions