How do I perform a JAVA callback between classes?

JavaCallback

Java Problem Overview


I am coming from JavaScript, in which callbacks are pretty easy. I am trying to implement them into JAVA, without success.

I have a Parent class:

import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {
	ExecutorService workers = Executors.newFixedThreadPool(10);
	private ServerConnections serverConnectionHandler;

	public Server(int _address) {
		System.out.println("Starting Server...");
		serverConnectionHandler = new ServerConnections(_address);
		
		serverConnectionHandler.newConnection = function(Socket _socket) {
			System.out.println("A function of my child class was called.");
		};
		
		workers.execute(serverConnectionHandler);

		System.out.println("Do something else...");
	}
}

Then I have a child class, that is called from the parent:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ServerConnections implements Runnable {
	private int serverPort;
	private ServerSocket mainSocket;
	
	public ServerConnections(int _serverPort) {
		serverPort = _serverPort;
	}

	@Override
	public void run() {
		System.out.println("Starting Server Thread...");
		
		try {
			mainSocket = new ServerSocket(serverPort);

			while (true) {
				newConnection(mainSocket.accept());
			}
		} catch (IOException ex) {
			Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
		}
	}
	
	public void newConnection(Socket _socket) {
		
	}
}

What is the right way of implementing the

serverConnectionHandler.newConnection = function(Socket _socket) {
    System.out.println("A function of my child class was called.");
};

part, in the Parent class, which is clearly not correct?

Java Solutions


Solution 1 - Java

Define an interface, and implement it in the class that will receive the callback.

Have attention to the multi-threading in your case.

Code example from http://cleancodedevelopment-qualityseal.blogspot.com.br/2012/10/understanding-callbacks-with-java.html

interface CallBack {                   

//declare an interface with the callback methods, 
//so you can use on more than one class and just 
//refer to the interface

    void methodToCallBack();
}

class CallBackImpl implements CallBack {          

//class that implements the method to callback defined 
//in the interface

    public void methodToCallBack() {
        System.out.println("I've been called back");
    }
}

class Caller {

    public void register(CallBack callback) {
        callback.methodToCallBack();
    }

    public static void main(String[] args) {
        Caller caller = new Caller();
        CallBack callBack = new CallBackImpl();       

//because of the interface, the type is Callback even 
//thought the new instance is the CallBackImpl class. 
//This alows to pass different types of classes that have 
//the implementation of CallBack interface

        caller.register(callBack);
    }
} 

In your case, apart from multi-threading you could do like this:

interface ServerInterface {
    void newSeverConnection(Socket socket);
}

public class Server implements ServerInterface {

    public Server(int _address) {
        System.out.println("Starting Server...");
        serverConnectionHandler = new ServerConnections(_address, this);
        workers.execute(serverConnectionHandler);
        System.out.println("Do something else...");
    }

    void newServerConnection(Socket socket) {
        System.out.println("A function of my child class was called.");
    }

}

public class ServerConnections implements Runnable {

    private ServerInterface serverInterface;
    
    public ServerConnections(int _serverPort, ServerInterface _serverInterface) {
      serverPort = _serverPort;
      serverInterface = _serverInterface;
    }

    @Override
    public void run() {
        System.out.println("Starting Server Thread...");

        if (serverInterface == null) {
            System.out.println("Server Thread error: callback null");
        }

        try {
            mainSocket = new ServerSocket(serverPort);

            while (true) {
                serverInterface.newServerConnection(mainSocket.accept());
            }
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Multi-threading

Remember this does not handle multi-threading, this is another topic and can have various solutions depending on the project.

The observer-pattern

The observer-pattern does nearly this, the major difference is the use of an ArrayList for adding more than one listener. Where this is not needed, you get better performance with one reference.

Solution 2 - Java

Use the observer pattern. It works like this:

interface MyListener{
    void somethingHappened();
}

public class MyForm implements MyListener{
    MyClass myClass;
    public MyForm(){
        this.myClass = new MyClass();
        myClass.addListener(this);
    }
    public void somethingHappened(){
       System.out.println("Called me!");
    }
}
public class MyClass{
    private List<MyListener> listeners = new ArrayList<MyListener>();

    public void addListener(MyListener listener) {
        listeners.add(listener);
    }
    void notifySomethingHappened(){
        for(MyListener listener : listeners){
            listener.somethingHappened();
        }
    }
}

You create an interface which has one or more methods to be called when some event happens. Then, any class which needs to be notified when events occur implements this interface.

This allows more flexibility, as the producer is only aware of the listener interface, not a particular implementation of the listener interface.

In my example:

MyClass is the producer here as its notifying a list of listeners.

MyListener is the interface.

MyForm is interested in when somethingHappened, so it is implementing MyListener and registering itself with MyClass. Now MyClass can inform MyForm about events without directly referencing MyForm. This is the strength of the observer pattern, it reduces dependency and increases reusability.

Solution 3 - Java

IMO, you should have a look at the Observer Pattern, and this is how most of the listeners work

Solution 4 - Java

I don't know if this is what you are looking for, but you can achieve this by passing a callback to the child class.

first define a generic callback:

public interface ITypedCallback<T> {
	void execute(T type);
}

create a new ITypedCallback instance on ServerConnections instantiation:

public Server(int _address) {
    serverConnectionHandler = new ServerConnections(new ITypedCallback<Socket>() {
        @Override
        public void execute(Socket socket) {
            // do something with your socket here
        }
    });
}

call the execute methode on the callback object.

public class ServerConnections implements Runnable {

    private ITypedCallback<Socket> callback;

    public ServerConnections(ITypedCallback<Socket> _callback) {
        callback = _callback;
    }
    
    @Override
    public void run() {   
        try {
            mainSocket = new ServerSocket(serverPort);
            while (true) {
                callback.execute(mainSocket.accept());
            }
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

btw: I didn't check if it's 100% correct, directly coded it here.

Solution 5 - Java

In this particular case, the following should work:

serverConnectionHandler = new ServerConnections(_address) {
    public void newConnection(Socket _socket) {
        System.out.println("A function of my child class was called.");
    }
};

It's an anonymous subclass.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Question&#193;gota Horv&#225;thView Question on Stackoverflow
Solution 1 - JavaDiego C NascimentoView Answer on Stackoverflow
Solution 2 - JavaWilliam MorrisonView Answer on Stackoverflow
Solution 3 - JavasanbhatView Answer on Stackoverflow
Solution 4 - JavapichsenmeisterView Answer on Stackoverflow
Solution 5 - JavaakkermanView Answer on Stackoverflow