DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • How To Build Web Service Using Spring Boot 2.x
  • Visually Designing Views for Java Web Apps
  • How to Activate New User Accounts by Email
  • How to Setup the Spring Cloud Config Server With Git

Trending

  • Artificial Intelligence, Real Consequences: Balancing Good vs Evil AI [Infographic]
  • Measuring the Impact of AI on Software Engineering Productivity
  • Comparing SaaS vs. PaaS for Kafka and Flink Data Streaming
  • How to Practice TDD With Kotlin
  1. DZone
  2. Coding
  3. Frameworks
  4. Spring: How to Create Decoupled Swing Components

Spring: How to Create Decoupled Swing Components

The Spring Framework's applicability in the context of Swing seems to be underhighlighted, at least when one looks around on the web.

By 
Geertjan Wielenga user avatar
Geertjan Wielenga
·
Apr. 05, 08 · Tutorial
Likes (0)
Comment
Save
Tweet
Share
61.3K Views

Join the DZone community and get the full member experience.

Join For Free

The Spring Framework's applicability in the context of Swing seems to be underhighlighted, at least when one looks around on the web. What does Spring have to offer in this context? Rather than a highly theoretical discussion, let's look at a complete, compilable example, step by step, and draw our conclusions from there.

Let's first look at the Swing application's source structure that we will have at the end of this article:

The first aspect that is immediately observable from the above source structure is that we have one class for each of the Swing components we will deal with, i.e., those are the files above that are not highlighted—a JFrame, a JPanel, a JTextField, and a JButton. We also have a class for the ActionListener that we will add to our JButton. Everything in these classes, the ones that are not highlighted, is pure Java and pure Swing, there's nothing wacky going on there, each of the classes extends or implements the classes you would expect—JFrame, JPanel, JTextField, JButton, and ActionListener. Finally, there are two Spring-specific files, both of which are highlighted above. There's a class that will launch the entire application, using Spring-specific classes and the Spring configuration file that, as we will see, will hook everything together. When the application is run, the result is as follows:

It is a very humble result, admittedly. And, in this part, the Swing components don't even do anything meaningful. The point here is to simply add the Swing components to the application without adding any Java code to make that possible. However, just that is more than enough to illustrate most of the basic principles of the applicability of Spring in the context of Swing. Normally, in the absence of Spring, the Swing components in our application would be added to each other in Java code. You would use the "add" method on the JFrame to add the JPanel to the JFrame and you would use the "add" method on the JPanel to add the JTextField and JButton to it. However, in this case, there is no code like that. In fact, none of the classes refer to any of the other classes. They are all self-contained. They are, in fact, decoupled from each other. Here's the JFrame:

package springexample;import java.awt.Dimension;import javax.swing.JFrame;public class MyJFrame extends JFrame {   public void init() {                java.awt.EventQueue.invokeLater(new Runnable() {            public void run() {                setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);                setSize(new Dimension(300, 300));                setVisible(true);            }        });            }} 

The other classes are similar, providing only the code that is relevant to the specific Swing component it defines. Even the ActionListener is decoupled. The ActionListener is not added to the JButton in the code in the Java classes above. Everything is isolated, separated, insulated, pared down, and self-contained.

All this is possible because of the fact that the application has the Spring JARs on its classpath, together with a launcher that locates the Spring configuration file, which in turn is defined exactly as follows:

After the first five lines, which provide the header, consisting of the relevant Spring namespace, let's look at what each of the main elements above does:

  • Line 6-9: Sets the JFrame, specifying its "title" property and its "contentPane" property. Note that we also set an "init-method" attribute, which provides a value that is the name of the method in the JFrame class that we want to have used to instantiate the class.
  • Line 10-19: Sets the main JPanel, consisting of two JTextFields and another instance of the same JPanel, defined in line 20-27. We also pass a property called "axis" and a property called "panelComponents". Both of these will be handled by our JPanel class. The first of these is used to set the "axis" property of the layout used by the JPanel, which is set to BoxLayout. The "panelComponents" property will be filled by our three Swing components. An iterator in the JPanel class will loop through the received components, adding each to the JFrame as it does so. All this will happen in the "init" method, which is set as the value of the "init-method" attribute.
  • Line 20-27: Sets the lower panel, which in this case only provides a JButton. Notice that this JPanel is defined by the same class as the one used to define the main panel. So, we are reusing the JPanel via the Spring configuration file.
  • Line 28: Sets the first JTextField.
  • Line 29: Sets the second JTextField.
  • Line 30-37: Sets the JButton, together with its "text" property and "actionListener" property. Notice that we didn't set the "text" property of the JTextFields, which we could have done, had we wanted to do so. You can either set the "text" property, as well as most other properties, right in the Spring configuration file, if you chose to do so. Your choice.
  • Line 38: Sets the ActionListener.
  • That's the complete file and it is mostly quite readable with the naked eye, no big surprises, apart from (if you're new to this) the flexibility and power offered by the Spring configuration file. Now let's look at what's in those classes, exactly. The JFrame is already shown above. Below follow all the other classes:

    package springexample;import java.awt.Component;import java.util.Iterator;import java.util.List;import javax.swing.BoxLayout;import javax.swing.JPanel;public class MyJPanel extends JPanel {    private List panelComponents;    private int axis;    public void setAxis(int axis) {        this.axis = axis;    }    public void setPanelComponents(List panelComponents) {        this.panelComponents = panelComponents;    }    public void init() {        setLayout(new BoxLayout(this, axis));        for (Iterator iter = panelComponents.iterator(); iter.hasNext();) {            Component component = (Component) iter.next();            add(component);        }    }}
    package springexample;import javax.swing.JTextField;public class MyJTextField extends JTextField {    public void init() {        setText("hello world");    }}
    package springexample;import java.awt.event.ActionListener;import javax.swing.JButton;public class MyJButton extends JButton {    private ActionListener actionListener;    public void setActionListener(ActionListener actionListener) {        this.actionListener = actionListener;    }    public void init() {        this.addActionListener(actionListener);    }}
    package springexample;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JOptionPane;public class MyActionListener implements ActionListener {    public void actionPerformed(ActionEvent e) {        JOptionPane.showMessageDialog(null, "Hello from Spring!");    }}

    Though we've added, in the JButton, an ActionListener, we haven't specified which ActionListener. To change the ActionListener, you'd simply change line 38 in the Spring configuration file above. Just change the "classname" attribute to something different and then you're done. Clearly, there's no Java code that connects the "MyActionListener" class to the "MyJButton" class. Similarly, there's no Java code connecting the Swing components to each other. To the end user, there's no difference. To the developer, everything that connects anything is set in the Spring configuration file, thus creating decoupled Swing components, as well as decoupled behavior (i.e., as shown by the ActionListener).

    Finally, let's look at the launcher class, which uses Spring-specific code, but is self-explanatory:

    package springexample;import org.springframework.context.support.ClassPathXmlApplicationContext;public class SpringLauncher {    public static void main(String[] args) {        String[] contextPaths = new String[]{"springexample/app-context.xml"};        new ClassPathXmlApplicationContext(contextPaths);    }}  

    Now, what do we gain from all of this? Does Spring really encourage a complete disintegration of Swing components down to this low level? Not necessarily, but possibly. The point is, you can decouple as far as you like and as much as you like. All within the same application. But why would you want to do so? Now that we understand the WHAT, let's look at the WHY. There's whole books on the WHY. The WHY is "dependency injection" and "loose coupling". One nice advantage is that, because your components are really pared down and separated from each other, it is easier to test them. Your JUnit tests (or other tests) will be easier to write because there are no encumbrances from one class to another. Also, what about the plumbing code, i.e., the wiring, that you would normally need to maintain? All of it is now within the Spring configuration file; none of it is in the Java code. Also note that the Spring configuration file is non-invasive. You can simply drop it into an existing application, write a bean for the main class, and then add the launcher code. Then you're good to go. So, integration with your existing Swing applications can occur without you needing to change those existing applications, unless you want to do so to make the fit even better.

    Finally, look again at that JPanel. That's a reusable Swing component (just like the other Swing components used here, such as the JTextField, which you've reused too). You've used it twice within the same application, for different purposes. In each case, you have a lot of control over the layout of the JPanel, right from within the Spring configuration file so that, even though you're using the same JPanel, its content could be different each time you reuse it. Also, notice that we're using a generic List object there. Instead of specifying a particular Swing component, which would have made the JPanel less reusable, we've opted for a generic List object so that we're not limiting the components it is able to handle. That's something to consider when creating decoupled Swing components and, therefore, working in a decoupled way has an impact on your design process.

    I hope this serves as a useful introduction to the Spring Framework in the context of Swing. In the next part, we will let the behavior of one of the Swing components (the JButton) cause something to happen to one of the others (one of the JTextFields). Many thanks to Chad Woolley, who wrote a great tutorial on Swing and Spring from which I learned a lot. That tutorial was the starting point for this one. Another document to look at is Java Programming/Spring Framework by Hyad on Wikipedia.

     

    Spring Framework application Property (programming) Java (programming language)

    Opinions expressed by DZone contributors are their own.

    Related

    • How To Build Web Service Using Spring Boot 2.x
    • Visually Designing Views for Java Web Apps
    • How to Activate New User Accounts by Email
    • How to Setup the Spring Cloud Config Server With Git

    Partner Resources

    ×

    Comments
    Oops! Something Went Wrong

    The likes didn't load as expected. Please refresh the page and try again.

    ABOUT US

    • About DZone
    • Support and feedback
    • Community research
    • Sitemap

    ADVERTISE

    • Advertise with DZone

    CONTRIBUTE ON DZONE

    • Article Submission Guidelines
    • Become a Contributor
    • Core Program
    • Visit the Writers' Zone

    LEGAL

    • Terms of Service
    • Privacy Policy

    CONTACT US

    • 3343 Perimeter Hill Drive
    • Suite 100
    • Nashville, TN 37211
    • support@dzone.com

    Let's be friends:

    Likes
    There are no likes...yet! 👀
    Be the first to like this post!
    It looks like you're not logged in.
    Sign in to see who liked this post!