Geertjan is a DZone Zone Leader and has posted 459 posts at DZone. You can read more from them at their website. View Full User Profile

Spring: How to Create Decoupled Swing Components

04.05.2008
| 44782 views |
  • submit to reddit

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.

     

    AttachmentSize
    spring-1.png200.23 KB
    spring-2.png19.49 KB
    spring-3.png7.97 KB
    Published at DZone with permission of its author, Geertjan Wielenga.

    Comments

    Jens Göring replied on Sat, 2008/04/05 - 5:15pm

    I recently applied the same principles for GWT using the Rocket-GWT DI framework. It works like a charm, although I don't recommend to configure EVERY widget in the xml config file - only those that actually carry any logic.

    Robert O'connor replied on Sun, 2008/04/06 - 2:40am

    That looks pretty awesome. However, you might want to create the Swing widgets on the event dispatch thread, rather than the main thread - it avoids some subtle and hard-to-reproduce bugs.You probably want to pack() MyJFrame in its init() method, too.

    Carl Antaki replied on Sun, 2008/04/06 - 9:29am

    Does the JGoodies FormLayout integration works well?

    Dan Dyer replied on Sun, 2008/04/06 - 12:15pm

    Making sure that your components are decoupled and easy to test is all very well, but you don't need to use Spring to achieve that.  You could just as easily use all of the decoupled classes that you have written but wire them together in some Java code.

    I fail to see the advantage of 100s of lines of XML, several JAR dependencies and moving errors from compile time to runtime, over a much more concise Java wiring of the components. 

    Geertjan Wielenga replied on Mon, 2008/04/07 - 1:03am in response to: Dan Dyer

    [quote=dwdyer]

    Making sure that your components are decoupled and easy to test is all very well, but you don't need to use Spring to achieve that. You could just as easily use all of the decoupled classes that you have written but wire them together in some Java code.

    I fail to see the advantage of 100s of lines of XML, several JAR dependencies and moving errors from compile time to runtime, over a much more concise Java wiring of the components.

    [/quote]

    I think there might be several reasons why one would take this approach. A simple usecase might be if the developer/s is/are already familiar with Spring in the context of the web/Java EE world. In that context, it would be nice to continue using the same framework within the desktop space.

    Secondly, imagine that, instead of 4 or 5 Swing components as in this example, you had dozens, or even hundreds or thousands. Having one centralized location where you manage the interactions between these components can only be a good thing, right? Because in that case your wiring code would be spread across MANY Java classes, I don't believe having a single Java class handling all the interactions of thousands of Swing components would be conceivable. 

    Mark Unknown replied on Mon, 2008/04/07 - 8:27am in response to: Geertjan Wielenga

    [quote=geertjan][quote=dwdyer]

    Making sure that your components are decoupled and easy to test is all very well, but you don't need to use Spring to achieve that. You could just as easily use all of the decoupled classes that you have written but wire them together in some Java code.

    I fail to see the advantage of 100s of lines of XML, several JAR dependencies and moving errors from compile time to runtime, over a much more concise Java wiring of the components.

    [/quote]

    I think there might be several reasons why one would take this approach. A simple usecase might be if the developer/s is/are already familiar with Spring in the context of the web/Java EE world. In that context, it would be nice to continue using the same framework within the desktop space.

    Secondly, imagine that, instead of 4 or 5 Swing components as in this example, you had dozens, or even hundreds or thousands. Having one centralized location where you manage the interactions between these components can only be a good thing, right? Because in that case your wiring code would be spread across MANY Java classes, I don't believe having a single Java class handling all the interactions of thousands of Swing components would be conceivable.

    [/quote]

    I have a reason: As soon as I get the green light, I have an application that needs to be configured by a non- developer. I will code the application once and he will configure it for each client. I already have one like this but I am not using Spring. Should have. That beening said, not everything is in the configuration. Just the things that need to be configurable.

     

    Mark Unknown replied on Mon, 2008/04/07 - 8:29am

    Thx for posting this Geertjan.  Seems perfect for what I need to do.  And now seems so obvoius ... :)

    johan mslms replied on Mon, 2008/04/07 - 10:54am

    As Robert O'Connor said, everything related to swing component manipulation must be done from the Event Dispatching thread. Take a look at some java swing tutorials, it is written everywhere : swing is not thread safe and to avoid problems, use EDT via SwingUtilities or EventQueue.

    You may want to take a look at how Spring RCP -Spring desktop- works.

    But your article is a good sample of the basic concept.

    Geertjan Wielenga replied on Mon, 2008/04/07 - 12:21pm

    johan and robert, I fixed the EDT problem. Is there someone here who has used the approach to Spring that is described here, i.e., in a desktop environment? I'd be interested in interviewing you for Javalobby, if so.

    Dan Hinojosa replied on Mon, 2008/04/07 - 3:18pm

    That was a great article.  I have a tough question.  Lets say you have one app that has the possiblity of creating multiple internal windows, like a word processor.  Each of the documents has it's own controllers, model, views, etc.  How do you deal with such a possibility with spring and swing together?

    Robert O'connor replied on Mon, 2008/04/07 - 6:34pm in response to: Geertjan Wielenga

    [quote=geertjan]johan and robert, I fixed the EDT problem. Is there someone here who has used the approach to Spring that is described here, i.e., in a desktop environment? I'd be interested in interviewing you for Javalobby, if so.[/quote]

     Cool :) That EDT problem is bad :)

    oxbow_ lakes replied on Tue, 2008/04/08 - 4:22am

    This whole thing is such a bad idea on so many levels. If you have a good UI design, why do you want to move stuff around? How do people maintaining your code figure out where some panel class MyPanel exists within your application?

    Spring is fantastic at configuring "service" classes which can be accessed from within an app but it is not an appropriate XML description on so many levels for configuring instances of any old POJO (whether that be data classes or GUI components). I see "bean, I see "property", I see "value" and I see "list" but nowhere do I get a feel for what the panel contains nor its layout.

    Just take one step back and look at the sheer awfulness of the XML you've posted above!

    • How would you integrate this with GridBagLayout? Or BoxLayout? Via the MethodInvokingFactoryBean?
    • How would you reconcile the above with the rule of thumb that each GUI component should have a no-arg constructor?
    • How do you quickly view sub-panels of your app, without creating reams and reams of near identical Spring config files?

    Geertjan Wielenga replied on Tue, 2008/04/08 - 4:59am in response to: oxbow_ lakes

    [quote=cm38280]

    This whole thing is such a bad idea on so many levels. If you have a good UI design, why do you want to move stuff around?

    [/quote]

    As pointed out by one or two people above, maybe you have different end users and the person doing the packaging is not a Java programmer. The Spring config file would be a way for the assembler, a non Java programmer, to assemble an application from the decoupled Swing components provided by the programmer.

    [quote=cm38280]

    How do people maintaining your code figure out where some panel class MyPanel exists within your application?

    [/quote]

    Most IDEs (at least NetBeans does, for sure) have support within Spring config files exactly for that purpose. You can click on a reference to a Java source file and then the source file in question opens. You also have code completion for the value of the "class" attribute, so that can be used for filling in the values and verifying that the referenced class actually exists.

    [quote=cm38280]  

    Spring is fantastic at configuring "service" classes which can be accessed from within an app but it is not an appropriate XML description on so many levels for configuring instances of any old POJO (whether that be data classes or GUI components).

    [/quote]

    I agree that this approach is probably atypical. But at the same time there could be scenarios out there where this could be useful. And the XML would not necessarily be reams and reams of tags either -- possibly you'd have three or four panels that could be exchanged with each other and the assembler would do this via the Spring config file. Again, I'm not making this scenario up myself -- look at the comments above where at least one respondent sees this as being applicable to their real life needs. 

    [quote=cm38280] 

    I see "bean, I see "property", I see "value" and I see "list" but nowhere do I get a feel for what the panel contains nor its layout.

    [/quote]

    In the scenario of there being an assembler of the application, that's not relevant, they don't need to see the panel (or other decoupled Swing component) in question. However, if they do want to see the layout or other content, they can simply click to it from the Spring config file (as pointed out above). 

    [quote=cm38280]  

    Just take one step back and look at the sheer awfulness of the XML you've posted above!

    • How would you integrate this with GridBagLayout? Or BoxLayout? Via the MethodInvokingFactoryBean?
    • How would you reconcile the above with the rule of thumb that each GUI component should have a no-arg constructor?
    • How do you quickly view sub-panels of your app, without creating reams and reams of near identical Spring config files?

    [/quote]

    I think I've responded to these points. I'm not arguing that this is useful for each and every Swing app, I'm just pointing out that this is possible in those cases where it makes sense. 

    Chad Woolley replied on Wed, 2008/04/09 - 3:12am

    Hi,

    I wrote the article [1] referenced above by Geertjan. He asked me to chime in on this thread, so I will.

    I'm not a Spring or a Swing expert, but my article was based on an actual application, which was Test-Driven from scratch using Spring and Swing over 4 years ago and is still running (almost maintenance-free) in production last I heard (I left soon after).

    Anyway, the point of this approach, and of Dependency Injection/Inversion Of Control (DI) in general, is to drive a good Object Oriented design. Two primary principles of good OO are loose coupling and high cohesion (linked and discussed in my article). I agree that it can be overkill to have a separately wired Spring component for every Swing GUI element. However, an app that is designed this way is much easier to debug and maintain. You end up with a LOT of small classes, but they are also reusable, and easy to unit test and debug. This sort of design also lends itself well to Test-Driven development. You can implement and fully test the portions you need, and mock out the collaborating objects you have not written yet. Then, the mocks serve as a blueprint for the API of the collaborators once you are ready to implement them. This is a powerful design approach which has a profound impact on your overall architecture, and leads you to write only the minimal code you need to get the job done, in a loosely coupled, highly cohesive way.

    So, to rephrase: This approach will result in a lot of small classes which do one thing, and one thing only, in an easily testable, reusable way. The dependency injection framework (Spring) allows you to assemble these classes into an application in a centralized, flexible, easily maintained way. Yes, there will still be complexity, especially in large apps, but it is better to assemble small parts in a well understood, flexible way; than to write large, complex parts which are hard to understand and hard to control.

    Also, as Geertjan points out, you don't have to be completely granular. The benefit of a sophisticated DI framework like Spring is that it allows you to be cohesive and loosely coupled at the micro class level as well as the macro module level. You can have multiple Spring config files which represent large modules of application functionality, and still have a narrow, well-defined interface to other modules in the overall app. The principles of loose coupling and high cohesion apply at all levels.

    Now, about this assertion: "...everything related to swing component manipulation must be done from the Event Dispatching thread. Take a look at some java swing tutorials, it is written everywhere : swing is not thread safe and to avoid problems, use EDT via SwingUtilities or EventQueue." As I said, I'm not a Swing expert, but in my application, I did not use the EventQueue AT ALL. The Real App I wrote using this approach used threads, but they were all implemented using standard Java and Spring event listeners - and I was able to implement asynchronous remote file downloads with progress indicators, multiple tabs, and real-time live updating lists based on file download status. This was all in a fully-responsive, multithreaded way, and I did not use EventQueue AT ALL. Think about it - if you have language which implements Threads, and you know how to use the Observer (Listener) design pattern, that is all you need to write a good multithreaded app. It doesn't matter if it is a GUI, and you don't need some special "EventQueue". You just need to manage concurrently and multithreaded behavior properly - and a loosely coupled and highly cohesive design makes this much easier to do. And, if you think about it, coupling many of your classes to an "EventQueue" might just make this HARDER to do, even if this is the way all the Swing(tm) tutorials do it. I may be completely off base, but maybe not - all I know is what worked for me. I mean, Sun has never been known to push a bad architecture model, have they? (cough J2EE cough cough).

    Next, to address these: "100s of lines of XML..." - "moving errors from compile time to runtime" - "more concise Java wiring of the components" - "the sheer awfulness of the XML".

    Disclaimer, I quit doing Java about 2 years ago, and I am now a full-time Ruby/Rails developer. I agree that XML is a horrible travesty. Take a look at YAML sometime, or even a good Domain Specific Language like Rake or RSpec. Spring is awesome, but XML sucks. If you remove all the angle brackets, forward slashes, quotes, and other boiler plate, you end up with raw data structures: arrays and hashes describing how things fit together. So, don't be fooled by "more concise Java wiring of the components." The components MUST be wired together SOMEHOW. If you do this in the Standard Swing Tutorial (tm) way, you are defining this wiring by hardcoding and directly instantiating dependency classes directly in the dependent classes. This, by definition is TIGHT COUPLING. If you move this same wiring into an external location (like the Spring config), you are achiving LOOSE COUPLING and facilitate polymorphism and reuse. This is better OO. The fact that Java and Spring use a horrible language like XML to describe data structures is an unfortunate fact, but that still doesn't mean that tight coupling is good.

    Finally, lets talk about "moving errors from compile time to runtime". As I said, I now work with Ruby/Rails, where there is NO COMPILATION. Ruby is interpreted, and in the Rails development environment, ALL CHANGES ARE REFLECTED INSTANTLY. Everything is runtime. Modify code, hit refresh. Wait - scratch that - modify code, run unit test, then refresh and see it work the first time. This is a glorious and blessed environment to work in, as long as you have a thick, tightly-woven safety net of multi-layered tests which are run via Continuous Integration (and if you don't then you are screwed anyway). I give thanks every day that I never have to compile anything. Anybody who sees compilation as a GOOD thing is in desperate need of salvation.

    Well, there you go Geertjan. I chimed in. I'm probably talking out of my ass, but that never stopped me :) Good article, regardless.

    Thanks,
    -- Chad

    [1] http://www.ibm.com/developerworks/edu/j-dw-java-springswing-i.html

    Collin Fagan replied on Wed, 2008/04/09 - 1:05pm in response to: Chad Woolley

    Chad,

    I'm sure you were able to do all sorts of impressive things by accessing Swing components from outside the EDT. It's still bad practice, and there is no "magic bullet" that makes these issues go away. No matter how well you implement your listeners or threads eventually you will be forced to deal with multiple threads accessing swing components or models simultaneously. While you have complete control over any thread in your code base the reality is that at any given moment repaint() can come along and access your components. The only other way to deal with these type of situations besides the EventQueue system is synchronization or locking. This is frowned upon because it's bad for performance and a deadlock can lock up the entire GUI.

    I understand that you are no longer a Swing/Java developer and that you never claimed to be a Swing expert, but your EDT comments are dead wrong and that needs to be stated explicitly for the young and impressionable minds out there who might be tempted to believe you.

    It sounds like Rails is more your thing anyway. Everyone should get to use the platform they most enjoy.

    vincent cobra replied on Wed, 2008/04/09 - 6:04pm

    I've been using Spring in lots of Swing applications and I think it's not such a good idea to create decoupled Swing components with Spring. The article is good though, I don't think much people use Spring in standard Swing programs(ie not involving Hibernate).

    • If you have a simple Swing application, you probably won't be using Spring
    • If you need to use Spring for some reasons(probably not a hello world) creating decoupled components makes your code difficult to maintain....

    What I would suggest to someone using Spring Framework in a Swing application is to only register actions or actionlisteners as beans in the Spring XML or properties file configuration.

    Mark Unknown replied on Wed, 2008/04/09 - 9:17pm in response to: vincent cobra

    Have you used Eclipse RCP or Netbeans Platform or Spring RCP?  Decoupling increases maintainability.  Of course, everthing in moderation.

    Mark Unknown replied on Wed, 2008/04/09 - 9:23pm in response to: Chad Woolley

    Chad, I was pretty much with you till this  - "Anybody who sees compilation as a GOOD thing is in desperate need of salvation.".  Having had to deal with applications written in things like Quickjob and VB and no option explicit, I'll take whatever "pain" compilation brings and let the compiler be my "tests" for those things it is good at.  ;)

     Well, that and the EDT thing. 

    Chad Woolley replied on Wed, 2008/04/09 - 11:00pm

    Hi,

    Thanks for the responses. Good points all - I was just trying to help Geertjan stir up the thread, play devil's advocate and float some alternate views. Take everything I said with a couple hundred grains of salt.

    @Collin & Mark - I'm really interested in what you said, and have wondered where the approach of not using the Event Dispatching Thread would fall down in a larger or more sophisticated app. If you know of any links to examples or tutorials that specifically show the types of problems you can have if you do not use the event dispatch thread, and how deadlocks can occur, please share them. It would be an interesting discussion.

     

    -- Chad

    oxbow_ lakes replied on Thu, 2008/04/10 - 3:32am in response to: Chad Woolley

    [quote=thewoolleyman]
    As I said, I'm not a Swing expert, but in my application, I did not use the EventQueue AT ALL.
    [/quote]

    So, let me get this straight. You have no understanding of how Swing works, but you've written an article on how to do stuff in Swing? I can't believe that you've never had deadlock problems in the GUIs! Whilst some Swing components (JTextField) for example are safe to access/update off the event thread, most are definitely not.

    You can perfectly well design an MVC-style GUI which uses Spring to take care of dependency-injection (wiring a Controller and injecting this into your GUI classes), in such a way that your GUI classes are purely display components which delegate all of their actions to the controller. This is easy. No need to have reams of XML just to put a text field on a JPanel. No need to use a MethodInvokingFactoryBean just because you want to call Box.createHorizontalGlue().

    Dan Hinojosa replied on Thu, 2008/04/10 - 4:05pm

    Chris,

    Where on Wolleyman's post did he say "I have no understanding of how Swing works"?

    Mark Unknown replied on Thu, 2008/04/10 - 8:35pm in response to: oxbow_ lakes

    [quote=cm38280]

    No need to have reams of XML just to put a text field on a JPanel. 

    [/quote]

    I can't see why this would take reams of XML.  I can see why one might need to do it with Spring. 

    oxbow_ lakes replied on Fri, 2008/04/11 - 11:47am in response to: Dan Hinojosa

    [quote=dh109205]

    Chris,

    Where on Wolleyman's post did he say "I have no understanding of how Swing works"?

    [/quote]

    It was this bit:

    "Take a look at some java swing tutorials, it is written everywhere : swing is not thread safe and to avoid problems, use EDT via SwingUtilities or EventQueue. As I said, I'm not a Swing expert, but in my application, I did not use the EventQueue AT ALL."

    To paraphrase: "I decided to ignore the documentation about how things work. I didn't code the app properly at all"

    For example, I have never actually seen a definitive case of thread-local memory access missing the value in main memory but I know that when I want to access data from more than one thread, I need to synchronize or use the concurrency classes. I don't go around saying "Hey, I've not seen any problems this far, I'm not going to bother with listening to the language designers"

    Dan Hinojosa replied on Fri, 2008/04/11 - 1:45pm in response to: oxbow_ lakes

    Haha. You took a lot of liberties with your statement. ;)

    Another perspective is that he was a advocate of YAGNI. If he did do functional testing and he and his customers were satisfied with the result. Then good for him. Doesn't necessarily mean he has no understanding how Swing works. I guess you can make the argument that you need to know everything about how an API works in order to use it. That's not realistic though. I do agree with that more caution should be made with threads and memory access when developing Swing apps (I got burned a few times). I just disagreed with your broad-brushed statement that he "had no understanding of how Swing works".

     

     

     

    Chad Woolley replied on Sat, 2008/04/12 - 4:38am in response to: Dan Hinojosa

    Well, to avoid argumement, I'll say it myself. I don't know Swing that well, at least not anymore. After not using it for years, I'm sure I have less knowledge than most people on this forum, and I have not done a lot of multithreaded apps either, mostly web development.

    But, last I heard, the app I wrote with the approach under discussion (manual java/spring TDD'd thread/concurrency handling) was still in production use by end-users, untouched, a couple years after I left it, and the only reason they were touching it is because the back-end SOAP API was changing.

    Anyway, I'd still love to see an in-depth tutorial or blog post about these supposed dangers and trade-offs which are being debated. Bottom line, if you TDD and follow YAGNI, and the app does what your users want, then what else matters? If the approach in Geertjan's and my tutorial is BS, or unscalable, or not applicable to some scenarios, then show me the code to prove it. Otherwise, it's just talk. No offense, just speaking as a humble hacker, if there is such a thing :)

    -- Chad

    Collin Fagan replied on Sat, 2008/04/12 - 8:09am in response to: Chad Woolley

    Chad,

    I accept your challenge. While not seeking to dispute the merits of spring I will post a blog entry outlining the pitfalls of Non-EDT Swing interaction and the reasons behind the EventQueue system.

    Collin 

    Chad Woolley replied on Sat, 2008/04/12 - 12:52pm in response to: Collin Fagan

    That would be great Collin.  I really have wanted to see someone explore this topic in detail for a while.

    There's also getting to be more and more frameworks that allow you to write Swing apps in Ruby and/or JRuby.  It will also be interesting to see if the same underlying issues and motivations apply to those environments as well.

    Thanks!

    -- Chad 

    Peter Karussell replied on Sun, 2008/04/13 - 5:49pm in response to: Chad Woolley

    Hi Chad,

    I think you had luck. Here are some sites about the EDT-problem (just google 'swing thread'):

    • http://java.sun.com/docs/books/tutorial/uiswing/concurrency/index.html
    • http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html
    • Shannon Hickey on this site: http://java.sun.com/developer/community/askxprt/sessions/2006/jl1016.jsp

    Where I got this phrase:

    "Programs that ignore this rule [all thread should be executed on the EDT] may function correctly most of the time, but are subject to unpredictable errors that are difficult to reproduce."

    In my application I had the 'luck' to get such errors: dead locks!!

    And please notice this post here: http://weblogs.java.net/blog/kgh/archive/2004/10/multithreaded_t.html

    where the swing team explains why they implemented thatway.

    Peter.

    Susanta Dash replied on Sat, 2008/06/21 - 10:11am

    "

    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).

    "

    I would like to know where is the next part.

    Developer Dude replied on Mon, 2009/08/24 - 2:00pm

    I am coming way late to the discussion (over a year late), but I will weigh in with some insights based on almost ten years of Java dev work, much of it with Swing. I only say that to lend some weight to the assertion that manipulation of 'realized' Swing components should only be done on the EDT thread. It is a well known rule in the Swing world - ignore it at your peril. Lots of authoritative docs out there on this, both hard and soft copy. Of late, the now strongly recommended practice is to only manipulate Swing components, 'realized' or not, on the EDT thread due to the way some components behave. This is one question I ask people I interview to determine if they really know Swing or not.

    'Realized' means components that have been drawn to the screen, layed out, etc.

    If you ignore this rule, you will not only have possible problems with deadlocks, but you may also possibly see components that intermittently don't paint correctly, or that have the wrong state, and a myriad of other intermittent problems that are hard to diagnose/reproduce. Often these problems show up on multiple core machines, which are now predominant.

    As for using Spring with Swing. I can think of multiple use cases where I would not want to hard wire what component is used for a particular purpose into code - where I would want to be able reuse and configure a component via a configuration file. This is especially true for plugin architectures where you have no idea what the component may be beyond a particular interface. Spring excels at this kind of problem - as anybody who has used it knows.

    As already said, nobody is advocating using Spring to configure all Swing components, just saying that it can be useful for some and giving examples.

    Comment viewing options

    Select your preferred way to display the comments and click "Save settings" to activate your changes.