Creating Dynamic Swing Views with Reflection by Extending MVC
Often large GUI projects need to be deployed quickly and adhere to strict guidelines; therefore design and implementation process is assigned to multiple developer groups doing the work simultaneously. With the arrival of Model–View–Controller (MVC) architecture, several developer groups can work on business logic or model layer, data representation or views, and Controller independently; combining the pieces at the end. MVC has been used extensively in GUI and Web–Based applications; in this article I’ll show how to extend MVC architectural pattern to build a Swing GUI program by using Reflection to dynamically generate Views. The Controller will read a property file, generate Views, and corresponding Models, and execute simple business logic. Developers working on Views and following this design will only need to update properties file and their new class instances will automatically be added to the main project, without the need to modify Controller or any other part of the project. Reflection will be used to instantiate new objects and call required methods.On a historical note, model–view–controller architectural pattern was conceived in the mid–1980's by developers of the Smalltalk-80 GUI library. It has since then been extensively used in most object oriented user interfaces, it has also been extensively covered in numerous books and publications. According to the MVC pattern, the model should be separated from the actual implementation of its view. The reason being, that there could be many representations of the same data and closely coupling views with the model would complicate project’s development, modifications and create maintenance nightmares.
In other words, you do not want to change your business logic every time you change your view.
When working on a large Swing GUI project, one way to represent views is to use Tabs or JTabbedPane as an underling class. Development of different modules should be assigned to different programmer groups and at the end and each Tab (view) has to be added to the main application. And before any coding is done, project architects usually come up with object relationship diagrams, use-case diagrams, object flow diagrams and hand out coding responsibilities. At the same time, GUI programmers or designers create appropriate screen prototypes for all sections.
Sample Project
In order to show how to extent MVC to create and coordinate views, I have created a simple GUI project that shows an application containing several tabs and several buttons with attached actions; this project has all the components of a template for a large–scale projects, and with small modifications can easily be reused in other GUI applications. The project contains – a controller that, as any MVC controller, deals with all data flow and coordinates object relationships, but on top of that it also literally creates all views. A model layer – represented by interface ModelInterface and several concrete classes extending it, and a view layer – represented by abstract class AbstractView (that by itself extends generic JPanel component) and several concrete tab classes extending AbstractView class. The model layer is actually a set of beans that perform some rudimentary business logic operations. The beans are not EJBs, but simply objects that manipulate data. The project also has one main property file.In an enterprise level application properties are usually read as java.util.Properties and include data-store locations, connection pool information, environment variables, debug levels and other global information. For our purposes only views info in a text file will suffice. Additional services managed by controller like persistence, distribution or security, are also beyond the scope of this article.
Main Controller
The Controller is the brain of the project, its responsibility is to capture user events and to determine which actions each of these events imply, and in my case to instantiate new View objects and corresponding Model objects and coordinate actions between them. I called the controlled class “MainController”, it has three methods: init – where all the initialization and views instantiation takes place, execute – where an action from a View invokes some operation from a corresponding Model, and loadProperties method that reads a text file with names of the concrete Views to add. The text properties file is called smvc.property and has just three lines – the actual names of concrete views or tabs:ConcreteView1
ConcreteView2
ConcreteView3
MainController also has three fields: a main JTabbedPane
to add new Views too, an array of Tabs and a HashMap of to store Model objects.
In the init method I call the loadProperties("smvc.properties")
to fill the array with tab names from the property file. As each view’s
class name is read from the properties file, I use Java Reflection API to instantiate
actual objects and add them to the main JTabbedPane. See listing
1 at the end of this article.
{
Class newClass = Class.forName((String) tabs.get(i));
//try to make an object – extending AbstractView
AbstractView anyTab = (AbstractView) newClass.newInstance();
//add our new view tab here, and set its name
mainPane.addTab(anyTab.getName(), anyTab);
// I also set
a reference back to the Controller
// let each tab know who is its controller
anyTab.setParent(this);
}
As soon as I add all dynamic Tabs, we can see them:

Swing Views
As I said, each Tab (view) in the project is a subclass of AbstractView
abstract class. The AbstractView itself has methods to set
the Tab name, set parent component (reference to the controller object), and
init method that automatically uses Class name as Tab name (you can
change that of cause); very useful since concrete Views will inherent them all.
(See source listing for complete AbstractView code).
// get the
name of the class - for tab name
String name = this.getClass().getName();
// get rig of all package info just leave class
name
setViewName(name.substring(name.lastIndexOf('.') + 1));
I created several concrete view classes; each concrete View class
calls an init method of its super class to set its name and adds a
button to invoke a simple action from a corresponding Model, via MainConntoller
object. Usually a view layer implements a rendering of the model, but in our
case I will only call an action. The view is responsible for getting and showing
information from the corresponding model that is appropriate based the model
state. The view also gathers information to pass on to the model via controller.
If I wanted too, I could’ve added some fields in the each Model and got
their data when a matching action was requested from my Tab.
When the button on concrete View 1 is pressed, it will call MainController execute
method (via its reference to parent we set earlier) and pass a String key or
Model name to let the Controller know to which model it should delegate the
request. Code below demonstrated this.
//inside anonymous class for action listener attached to a button
public void actionPerformed(java.awt.event.ActionEvent e) {
((MainController) ConcreteView1.this.parent).execute(ConcreteView1.this,"Model1");
}
