Dynamically Instantiating Classes in Java

Edited 2021-02-08 to reflect API changes for Java 11.

There are a number of cases when you may not know exactly what class you will be instantiating and want to be able to dynamically instantiate specific classes based on a configuration file or a condition during runtime.

To do so, you will need to define a parent class, abstract class, or interface for your classes and can then use the following code as a guide.

Given the following class definitions:

An abstract class

package com.ryanchapin.examples;

public abstract class MyAbstractClass {

    protected int x;
    protected int y;

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public MyAbstractClass() {}

    public MyAbstractClass(Integer x, Integer y) {
        this.x = x;
        this.y = y;
    }

    public abstract int doSomething();
}

Two concrete implementations

package com.ryanchapin.examples;

public class MyMultiplyingClass extends MyAbstractClass {

    public MyMultiplyingClass() {}

    public MyMultiplyingClass(Integer x, Integer y) {
        super(x, y);
    }

    @Override
    public int doSomething() {
        return x * y;
    }
}
package com.ryanchapin.examples;

public class MyAddingClass extends MyAbstractClass {

    public MyAddingClass() {}

    public MyAddingClass(Integer x, Integer y) {
        super(x, y);
    }

    @Override
    public int doSomething() {
        return x + y;
    }
}

A Main class in which we can run the example

package com.ryanchapin.examples;

public class Main {

    public static void main(String[] args) {
        String myMultiplyingClass = "com.ryanchapin.examples.MyMultiplyingClass";
        String myAddingClass = "com.ryanchapin.examples.MyAddingClass";

        /*
         * Instantiating the class via the no-arg constructor and then using the
         * setters to "configure" the instance.
         */
        MyAbstractClass noArgConstructorInstance = null;
        try {
            @SuppressWarnings("unchecked")
            Class<MyAbstractClass> instanceClass =
                (Class<MyAbstractClass>) Class.forName(myMultiplyingClass);
            noArgConstructorInstance = instanceClass
                .getDeclaredConstructor()
                .newInstance();
        } catch(Exception e) {
            e.printStackTrace();
        }
        noArgConstructorInstance.setX(5);
        noArgConstructorInstance.setY(2);
        System.out.println(noArgConstructorInstance.doSomething());

        /*
         * Instantiating the class via the constructor that takes the x and y
         * parameter values.
         */
        MyAbstractClass xyArgConstructorInstance = null;
        try {
            @SuppressWarnings("unchecked")
            Class<MyAbstractClass> instanceClass =
                (Class<MyAbstractClass>) Class.forName(myAddingClass);
            /*
             * Specify the signature of the constructor that we want to invoke
             * by passing in the types defined in the target constructor.  Then,
             * pass in the arguments to the constructor with the newInstance
             * method.
             */
            xyArgConstructorInstance = instanceClass
                .getDeclaredConstructor(Integer.class, Integer.class)
                .newInstance(5, 2);
        } catch(Exception e) {
            e.printStackTrace();
        }
        System.out.println(xyArgConstructorInstance.doSomething());
    }
}

The Main class illustrates two different ways that we can instantiate our class. One, using the no-arg constructor, and another, by using reflection to get a reference to the constructor with the defined arguments.

The Main class assumes that it will be called with the fully qualified class name as the first argument and will use that String to attempt to instantiate a concrete instance of the MyAbstractClass. The abstract class can be either an interface, or a concrete parent class.

Preserving File Permissions When Copying Files with Ant

If you want to retain the file permissions of a file that you copy with ant you must use the <exec> command instead of? <copy>.

So, instead of:

<copy file=”${source.file}” tofile=”${dest.path}/${dest.file}” overwrite=”true”/>

Use:

<exec executable=”cp”>
? <arg value=”-pf”/>
? <arg value=”${source.file}”/>
? <arg value=”${dest.path}/${dest.file}”/>
</exec>

java.lang.OutOfMemoryError: unable to create new native thread Exception When Using SmbFileInputStream

I am writing an application that copies files from a Samba share using the JCIFC Java CIFS Client Library (which, btw, is a very helpful, widely used, and well developed project).

As usual I am under the gun to get something up and running so I do not have the luxury to explore all of the details as much as I would like. My application gets a directory listing of a Samba share and then spawns a new thread for each new file (with a limit, of course) which copies the file to the local file system via a SmbFileInputStream and FileOutputStream as follows (without the obligatory try/catch blocks for readability):

(An SmbFile instance is provided by the calling code)

byte[] readBuffer = new byte[1024];
int bytesRead = 0;

File fileDestination = new File(“/tmp/”, “destinationFile”);
FileOutputStream fileDestinationFOS = new FileOuputStream(fileDestination);

SmbFileInputStream smbFIS = new SmbFileInputStream(smbFile);

while ((bytesRead = smbFIS.read(readBuffer)) != -1 ) {
fileDestination.write(readBuffer, 0, bytesRead);
}

smbFIS.close();
fileDestinationFOS.close();

When I run it I get the following Exception:

Exception in thread “Thread-3” java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:614)
at jcifs.UniAddress.lookupServerOrWorkgroup(UniAddress.java:173)
at jcifs.UniAddress.getAllByName(UniAddress.java:290)
at jcifs.UniAddress.getByName(UniAddress.java:245)
at jcifs.smb.Dfs.getTrustedDomains(Dfs.java:62)
at jcifs.smb.Dfs.resolve(Dfs.java:167)
at jcifs.smb.SmbFile.resolveDfs(SmbFile.java:671)
at jcifs.smb.SmbFile.send(SmbFile.java:773)
at jcifs.smb.SmbFileInputStream.readDirect(SmbFileInputStream.java:181)
at jcifs.smb.SmbFileInputStream.read(SmbFileInputStream.java:142)
at jcifs.smb.SmbFileInputStream.read(SmbFileInputStream.java:132)
at com.ngc.amap.mapDaemon.FileScanDaemon$RemoteFileCopier.run(FileScanDaemon.java:461)
at java.lang.Thread.run(Thread.java:636)

After considerable searching and testing I determined that the call to jcifs.smb.SmbFile.resolveDfs(SmbFile.java:671) was spawning numerous Threads that were consuming all of the RAM availble to naitive thread in my JVM. Increasing the amount of RAM to the JVM didn’t help.

The solution that I found was to set the following properties in my application prior to the instantiation of any of the jcifs.* classes. In this case, these properties were set in the main method of my entry point class.

System.setProperty(“jcifs.resolveOrder”, “DNS”);
System.setProperty(“jcifs.smb.client.dfs.disabled”, “true”);

Once set, I was able to run as expected without the OutOfMemoryErrors

Adding a ShutdownHook to a Java Program to Enable Clean Exit on CTRL-C

Often times I will be building a Java program that will either be run from a command-line or as a system service.  In most cases, during development, I’ll be running it directly from the command-line and will want to kill it by pressing control c on the keyboard.

When I do that I want to make sure that my program cleanly exits, closing any open files, socket connections, database connects, or what have you.

To do so, you must invoke the addShutdownHook(Thread) method on the Runtime.getRuntime() instance for a given process.

Following is a quick how-to on setting that up.

You need the following 4 things:

  1. The class that you want to be able to shutdown cleanly, we will call this the Parent.
  2. A class that extends Thread, we will call this the ShutdownThread class.  This class will call a method in the Parent
  3. An interface that the Parent will implement, called the ShutdownInterface.
  4. The invocation of the Runtime.getRuntime().addShutdownHook(ShutdownInstance) in the Parent.

The classes:

/** ***************************************************
 *
 * The ShutdownInterface
 */


public interface IShutdownThreadParent {
    public void shutdown();
}


/** ***************************************************
 *
 * The ShutdownThread
 */


public class ShutdownThread extends Thread {

    private IShutdownThreadParent mShutdownThreadParent;

    public ShutdownThread(IShutdownThreadParent mShutdownThreadParent) {
        this.mShutdownThreadParent = mShutdownThreadParent;
    }

    @Override
    public void run() {
        this.mShutdownThreadParent.shutdown();
    }
}

 /** ***************************************************
 *
 * The Parent
 */

public class Parent implements IShutdownThreadParent{

    private  ShutdownThread fShutdownThread;

    public Parent() {
        // Instantiate a new ShutdownThread instance and invoke the addShutdownHook method.
        fShutdownThread = new ShutdownThread(this);
        Runtime.getRuntime().addShutdownHook(fShutdownThread);
    }

    @Override
    public void shutdown() {
        // code to cleanly shutdown your Parent instance.
    }

    public static void main(String[] args) {
        Parent parent = new Parent();
    }
}

When instantiated the Parent class instantiates a new ShutdownThread instance, passing it a reference to itself.  The Parent class then invokes the addShutdownHook() method passing it the reference to the ShudownThread instance.

When CTRL-C is pressed on the keyboard, the JVM will invoke the run method in the ShutdownThread class which will then invoke the shutdown() method in the parent class enabling you to cleanly exit before the JVM exits.

Replacing Smart Quotes (<91> and <92>) in vi

Smart quotes will be displayed as <91> and <92> in vi. A number of other special characters will also be displayed in similar fashion <96>, etc. . . .

To replaced them use do the following:

  1. Type:? ‘:’ 1,%s/
  2. Then, since it is a special character, you can’t simply type ‘<91>’ or that string will not be matched, so:
  1. Press: CTRL and V
  2. Then type: [space] x [space] 91
  3. [Enter]