Writing URLClassLoader

Class loading a major concept when it comes to JVM internals. We can load jars from multiple locations from DB and From Remote location and we can also create our own class loader instead of using URLClassLoader.



package com.sfos;


import java.net.MalformedURLException;

import java.net.URL;

import java.net.URLClassLoader;


public class Main {

            public static void main(String[] args) {

                        URL url;

                        try{     

                         url = new URL("file:///Documents/Messager.jar");

                        URLClassLoader ucl = new URLClassLoader(new URL[]{url});              


                        Class clazz = ucl.loadClass("com.sfos.Message");

                        Object o = clazz.newInstance();

                        //com.sfos.Message o = clazz.newInstance(); We can’t use this

                        System.out.println(o.toString());

                        }catch(MalformedURLException e){

                                    e.printStackTrace();

                        } catch (ClassNotFoundException e) {

                                    e.printStackTrace();

                        } catch (InstantiationException e) {

                                    e.printStackTrace();

                        } catch (IllegalAccessException e) {

                                    e.printStackTrace();

                        }

                        }

}


Output:  com.sfos.Message@15db9742 hash code of Object

With the help of URLClassLoader I am calling Messager.jar which contains Message class. The URLClassLoader will take an array of jars to load not a specific type.  The problem with this example is that when I call new instance, I only get back something of type Object. Now I know that I should be getting back something of type com.sfos.Message, but I can’t use that type directly here because if I do that, that defeats that whole purpose of me using a class loader Because by using this type directly in line in the code, then I that case we’ll simply use the application class loader. So if I need to access the on the quote type. I need some other way to do that. And the way we do that typically is to break this down into using interfaces and implementations

Lets have an interface IMessage.java


package com.sfos;

public interface IMessage {

        String getMessage();

}

And Implementation class

Message.java



package com.sfos;

public class Message implements IMessage{
        

            public String getMessage(){

                        return "Hi How are you";

            }


}

Main.java


package com.sfos;

import java.net.MalformedURLException;

import java.net.URL;

import java.net.URLClassLoader;

public class Main {       

            public static void main(String[] args) {

                        URL url;

                        try{     

                        url = new  URL("file:///C:/Users/KrishnaPendyala/.m2/repository/ClassLoading/ClassLoading/0.0.1-SNAPSHOT/ClassLoading-0.0.1-SNAPSHOT");

                        URLClassLoader ucl = new URLClassLoader(new URL[]{url});

                        Class clazz = ucl.loadClass("com.sfos.Message");

                        IMessage message = (IMessage) clazz.newInstance();

                        System.out.println(message.getMessage());

                        }catch(MalformedURLException e){

                                    e.printStackTrace();

                        } catch (ClassNotFoundException e) {

                                    e.printStackTrace();

                        } catch (InstantiationException e) {

                                    e.printStackTrace();

                        } catch (IllegalAccessException e) {

                                    e.printStackTrace();

                        }

                        }

}


Output: Hi How are you

Now we used the Interface to call and execute particular Class Instead of referring an Object type.

So, till now we used URLClassLoader which is the part of JVM we got. Now I am gonna show how to write our own class loader.

Lets write our own classloader named SqlServerClassLoader.java by extending ClassLoader


package com.mantiso;

import java.io.Writer;

import java.sql.*;

public class SqlServerClassLoader extends ClassLoader {

    private ClassLoader parent;

    private String connectionString;


   public SqlServerClassLoader(String connectionString) {

        this(ClassLoader.getSystemClassLoader(), connectionString);

    }

    public SqlServerClassLoader(ClassLoader parent, String connectionString) {

        super(parent);

        this.parent = parent;

        this.connectionString = connectionString;

    }


    @Override

    protected Class<?> findClass(String name) throws ClassNotFoundException {

        Class cls = null;

        try {

            cls = parent.loadClass(name);

        } catch (ClassNotFoundException cnfe) {

            byte[] bytes = new byte[0];

            try {

                bytes = loadClassFromDatabase(name);

            } catch (SQLException sqle) {

                throw new ClassNotFoundException("Unable to load class", sqle);

            }

            return defineClass(name, bytes, 0, bytes.length);

        }

        return cls;

    }

    private byte[] loadClassFromDatabase(String name) throws SQLException, ClassNotFoundException {

        PreparedStatement pstmt = null;

        Connection connection = null;

        byte[] data = null;

        try {

            connection = DriverManager.getConnection(connectionString);

            String sql = "select class from CLASSES where ClassName= ?";

            pstmt = connection.prepareStatement(sql);

            pstmt.setString(1, name);

            ResultSet rs = pstmt.executeQuery();

            if (rs.next()) {

                Blob blob = rs.getBlob(1);

                data = blob.getBytes(1, (int) blob.length());

                return data;

            }

        } catch (SQLException sqlex) {

            System.out.println("Unexpected exception: " + sqlex.toString());

        } catch (Exception ex) {

            System.out.println("Unexpected exception: " + ex.toString());

        } finally {

            if (pstmt != null) pstmt.close();

            if (connection != null) connection.close();

        }

        if(data == null){

            throw new ClassNotFoundException();

        }

        return data;

    }

}

Main.java


package com.mantiso;

import com.sfos.IMessage;

public class Main {

    public static void main(String[] args) {

        try {

            SqlServerClassLoader cl = new  SqlServerClassLoader("jdbc:sqlserver://localhost\\SQLExpress;databaseName=classloading;integratedSecurity=true");

            Class clazz = cl.findClass("com.pluralsight.Quote");

            IQuote quote = (IQuote) clazz.newInstance();

            System.out.println(quote.getQuote());

        } catch (ClassNotFoundException e) {

            e.printStackTrace();

        } catch (InstantiationException e) {

            e.printStackTrace();

        } catch (IllegalAccessException e) {

            e.printStackTrace();

        }

    }

}

Output: Hi How are you

 

Balakrishna Pendyala

Author: Balakrishna Pendyala

Balakrishna is a Software Engineer working in Media Streaming Domain, and also worked on Banking and Health Care domains. His areas of interest include Object Oriented Design, SOLID Design principles, Restful Web Services and Open Source softwares including Spring, Spring Boot, and Hibernate.

If you found an error, highlight it and press Shift + Enter or click here to inform us.

Leave a Reply

Your email address will not be published. Required fields are marked *