Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / November 2005

Tip: Looking for answers? Try searching our database.

Help with Swing threading!

Thread view: 
buunguyen@psv.com.vn - 29 Nov 2005 16:28 GMT
I've got an interesting problem and cannot understand why it happens
this way.

I have a class to encapsulate the set "waiting" cursor.
public class CursorAction {
  public CursorAction() {
     Cursor currentCursor = getCursor();
     setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
     execute();
     setCursor(currentCursor);
  }

  protected void execute(){}
}

I use it as follows:
handleForButtonClick() {
  new CursorAction() {
     protected void execute() {
        server.start();
     }
  };
}

The above code always throws an exception at the line server.start().
The exception is:

AWT-EventQueue-0Exception in thread "AWT-EventQueue-0"
java.lang.NullPointerException

But if I do this then it's always fine:

handleForButtonClick() {
   Cursor currentCursor = getCursor();
   setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
   server.start();
   setCursor(currentCursor);
}

This is really strange because I believe that the 2 code segments do
the same thing. With my understand about threading in Swing/Awt and
anonymous class, I really don't understand why it happens this way.
Anyone has any idea?
NullBock - 29 Nov 2005 16:42 GMT
I don't think you've posted enough code.  What is "server"--it has to
be a field, but of which class?

In any case, it appears that you're running into a problem with a
partially-constructed object.  An object is only complete once its
constructor returns, and yet your base class is calling a method, meant
to be overridden, *before* the ctor returns.  This is typically
dangerous to do--ctors should almost never call methods that will be
overridden--probably never.

Walter Gildersleeve
Freiburg, Germany

______________________________________________________
http://linkfrog.net
URL Shortening
Free and easy, small and green.
buunguyen@psv.com.vn - 29 Nov 2005 18:19 GMT
Walter, I look at the generated code for the anonymous class and I'm
sure you're right, the 'server' instanced passed to the subclass is not
yet initialized. Thanks for pointing out.
Roedy Green - 29 Nov 2005 17:33 GMT
> server.start();
The key to all this is how and where is server defined.  You left
that out.
Signature

Canadian Mind Products, Roedy Green.
http://mindprod.com Java custom programming, consulting and coaching.

Roedy Green - 29 Nov 2005 17:36 GMT
>    Cursor currentCursor = getCursor();
>    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
>    server.start();
>    setCursor(currentCursor);

I presume server.start is not just starting a thread. It is some
action that takes noticeably time and you are willing to freeze the
entire gui during the time it runs.

Normally you would not use a wait cursor, but instead would do that
work on a separate worker thread so that gui could remain responsive.
Signature

Canadian Mind Products, Roedy Green.
http://mindprod.com Java custom programming, consulting and coaching.

buunguyen@psv.com.vn - 29 Nov 2005 17:40 GMT
'server' is an instance field of the class which has the posted code,
it is not a Runnable, the start() simply performs some kind of heavy
calculation.
Thomas Hawtin - 29 Nov 2005 18:40 GMT
> I've got an interesting problem and cannot understand why it happens
> this way.
[quoted text clipped - 5 lines]
>       setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
>       execute();

It's usually a very bad idea to call overridable methods (on this) from
a constructor.

>       setCursor(currentCursor);
>    }
[quoted text clipped - 7 lines]
>       protected void execute() {
>          server.start();

Even System.out.println(server); should NPE!.
System.out.println(MyOuterClass$this); should print "null".

>       }
>    };
> }

I think I see what is going on. It's a bit subtle. Using -target 1.4
should cure the problems.

When an object is created, the constructor must be called before any
other methods. A constructor must call a constructor of the superclass
before any accesses to this. For the implementation of inner classes,
that means the outer this cannot be set before calling the
superconstructor. In your example the superconstructor calls a method
that uses the subclass outer this, which is at that point null. Oops.

In 1.4 a small change was made to the JVM spec to allow for setting the
outer this before calling the constructor (in most situations). For
backward compatibility javac will only generate code to do this if the
target is set to at least 1.4.

Tom Hawtin
Signature

Unemployed English Java programmer
http://jroller.com/page/tackline/

buunguyen@psv.com.vn - 29 Nov 2005 20:23 GMT
Tom, it works when "-target 1.4". Do you know how it works under the
hood? I look at the decompiled code but I cannot get any sense out of
it.
Thomas Hawtin - 29 Nov 2005 21:07 GMT
> Tom, it works when "-target 1.4". Do you know how it works under the
> hood? I look at the decompiled code but I cannot get any sense out of
> it.

Consider a simplified source file:
class Outer {
    {
        new Object() { };
    }
}

To see what's in the source use javap -c, rather the a to Java source
decompiler. aload_0 refers to this (in a non-static method). aload_1 is
initially the first argument. "<init>" with angles is the internal name
given to all constructors.

The pre 1.4 version:

Compiled from "Outer.java"
final class Outer$1 extends java.lang.Object{
Outer$1(Outer);
  Code:
First it calls the superconstructor, this.Object().
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
Now it stores the argument in this.this$0 (i.e. Outer.this).
   4:   aload_0
   5:   aload_1
   6:   putfield        #2; //Field this$0:LOuter;
And returns.
   9:   return

}

The 1.4+ version:

Compiled from "Outer.java"
final class Outer$1 extends java.lang.Object{
final Outer this$0;

Outer$1(Outer);
  Code:
First it stores the argument in this.this$0 (i.e. Outer.this), despite
previously not being allowed to access this before calling super. 'this'
is unitialised.
   0:   aload_0
   1:   aload_1
   2:   putfield        #1; //Field this$0:LOuter;
Now, with this.this$0 in place, it calls the superconstructor,
this.Object().
   5:   aload_0
   6:   invokespecial   #2; //Method java/lang/Object."<init>":()V
And returns.
   9:   return

}

Tom Hawtin
Signature

Unemployed English Java programmer
http://jroller.com/page/tackline/

buunguyen@psv.com.vn - 30 Nov 2005 19:15 GMT
That makes sense. Thanks so much Tom.


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.