Login  Register

Re: Strange ClassCastException: A puzzle for Java/ImageJ experts to help me wit?.

Posted by Bill Mohler on Apr 29, 2009; 3:57pm
URL: http://imagej.273.s1.nabble.com/Strange-ClassCastException-A-puzzle-for-Java-ImageJ-experts-to-help-me-wit-tp3692688p3692694.html

Thanks, Curtis.  Here's what I get

MultiQTVirtualStack1
stack class = MultiQTVirtualStack
MultiQTVirtualStack class = MultiQTVirtualStack
Classes equal? false/false
path to MultiQTVirtualStack class =
file:/Applications/ImageJ/plugins/QuickTime_Plugins_MMRD041109/MultiQTVirtualStack.class
path to stack class =
file:/Applications/ImageJ/plugins/QuickTime_Plugins_MMRD041109/MultiQTVirtualStack.class
beforetheloop imp[3-Movie Overlay #1 : see Log window for details
600x411x38961]
stack[600x411x38961]
intheloop j= 0 imp[3-Movie Overlay #1 : see Log window for details
600x411x38961]
stack[600x411x38961]
MultiQTVirtualStack2
MultiQTVirtualStack3


So, mysteriously to me, the code you sent reports that they are NOT
equal classes.  However both paths point to the same class file!
Could it be that they are each actually derived from a different
constructor in the class?

   public MultiQTVirtualStack(QTFile[] mqtf, boolean eightBit) {

   public MultiQTVirtualStack(QTFile[] mqtf, boolean eightBit,
ImagePlus imp, boolean stretchToFitOverlay) {

I didn't think that imp.getStack() would call the constructor....

Still baffled, but with a bit more data!

Bill

>Hi Bill,
>
>That's a devilish problem. Normally, the message printed in the
>ClassCastException is the actual (incompatible) class of the object in
>question. So it would appear that your object's class is
>MultiQTVirtualStack, but somehow a different MultiQTVirtualStack than the
>one you are referencing in code.
>
>The only way I know for that to happen would be if the two classes have
>different packages, which would happen if you have an import statement at
>the top of your class. For example, let's say there's a
>foo.bar.MultiQTVirtualStack in your classpath. If your code has a line
>"import foo.bar.*;" on top, you might have the problem you're seeing.
>
>Try adding the following debugging code:
>
>Class stackClass = stack.getClass();
>Class mqtvsClass = MultiQTVirtualStack.class;
>IJ.log("stack class = " + stackClass.getName());
>IJ.log("MultiQTVirtualStack class = " + mqtvsClass.getName());
>IJ.log("Classes equal? " + (stackClass == mqtvsClass) + "/" +
>stackClass.equals(mqtvsClass));
>IJ.log("path to MultiQTVirtualStack class = " +
>mqtvsClass.getResource(mqtvsClass.getName() + ".class"));
>IJ.log("path to stack class = " +
>stackClass.getResource(stackClass.getName() + ".class"));
>
>Let us know what you find out!
>
>-Curtis
>
>On Wed, Apr 29, 2009 at 9:50 AM, Bill Mohler <[hidden email]>wrote:
>
>>  I hope that some of you with time and experience can help me with a
>>  suggestion.  Please take some time, if you have a chance, to work through
>>  the details I'm providing below:
>>
>>  I have created a new class called MultiQTVirtualStack (MQTVS for short
>>  here), spinning off of the success of Jeffrey Woodard's QTVirtualStack (QTVS
>>  for short here, which makes working with QuickTime movies in a true ImageJ
>>  StackWindow a delight).
>>
>>  MQTVS extends VirtualStack (and therefore ImageStack) and allows the user
>>  to open a collection of QTVSs into a single Virtual HyperStack window, in
>>  which each QTVS plays as a separate channel, but all the QTVS-derived
>>  channels are navigated synchronously in the Z and T dimensions.  The window
>>  can be viewed in either Composite (color overlay), Color (separate channel),
>>  or Grayscale (separate channel) modes that are available for HyperStacks.
>>   This all works nicely now for me.  Happy to share the code, but it's not
>>  cleaned up pretty yet.
>>
>>  Now I am trying to create a PluginFrame with which the user can shift the
>>  registration of the Z and T dimensions of the various QTVS channels of the
>>  MQTVS window, so as to better synchronize movies that were collected
>>  separately and may start at different relative times during an event of
>>  interest that needs to be compared.
>>
>>  I have previously created methods MQTVS.adjustSingleMovieZ(int channel,
>>  boolean forward) and MQTVS.adjustSingleMovieT(int channel, boolean forward),
>  > which in turn call methods in my modified version of QTVS to rearrange the
>>  order of elements in the ArrayList, frameLocations, pointing to movie frames
>>  by a single position in either Z or T.  This interaction of methods has
>  > worked well for me when I code "for" loops that make a fixed
>number of calls
>>  to the MQTVS.adjustSingleMovie...() methods from within the constructor of
>>  MQTVS (an experimental proof of principal that works very nicely). Here are
>>  the methods themselves, isolated from the rest of their classes for
>>  simplicity.  The problems I'm having in calling these methods via a
>>  PluginFrame are described below.
>>
>>  From MQTVS:
>>   /*These methods allow viewer to shift the Z or T positions of a given
>>  channel to better synchronize movies.*/
>>         public void adjustSingleMovieZ(int channel, boolean forward) {
>>                 this.forward = forward;
>>                 ((QTVirtualStack) stack[channel]).shiftMovieZ(forward);
>>                 IJ.log("got to MQTVS.ASMZ");
>>
>>         }
>>
>>         public void adjustSingleMovieT(int channel, boolean forward) {
>>                 this.forward = forward;
>>                 ((QTVirtualStack) stack[channel]).shiftMovieT(forward);
>>
>>         }
>>
>>
>>  From QTVS:
>>   /*These methods allow viewer to shift the Z or T positions of a given
>>  channel to better synchronize movies.*/
>>         public void shiftMovieT(boolean forward) {
>>                 this.forward = forward;
>>                 if (!forward) {
>>                         for (int z = 0; z < maxSlicesSingleMovie ; z++) {
>>                                 this.frameLocations.add( (z*
>>  maxTimesSingleMovie) , this.frameLocations.get( ((z+1)* maxTimesSingleMovie)
>>  -1) );
>>                                 this.frameLocations.remove(  ((z+1)*
>>  maxTimesSingleMovie) -1 );
>>                         }
>>                 } else {
>>                         for (int z = maxSlicesSingleMovie-1 ; z >= 0  ; z--)
>>  {
>>                                 this.frameLocations.add( ((z+1)*
>>  maxTimesSingleMovie-1) , this.frameLocations.get( (z)* maxTimesSingleMovie
>>  ));
>>                                 this.frameLocations.remove( ((z)*
>>  maxTimesSingleMovie ) );
>>                         }
>>                 }
>>         }
>>
>>         public void shiftMovieZ(boolean forward) {
>>
>>                 this.forward = forward;
>>                 ArrayList copyFrames = new ArrayList();
>>                 IJ.log("Got to the QTVS.SMZ");
>>
>>                 if (forward) {
>>                         for (int t= 0; t < maxTimesSingleMovie; t++) {
>>                                 copyFrames.add(
>>  this.frameLocations.get(((maxSlicesSingleMovie-1)*maxTimesSingleMovie) ) );
>>
>>
>>   this.frameLocations.remove(((maxSlicesSingleMovie-1)*maxTimesSingleMovie)
>>  );
>>                         }
>>                         this.frameLocations.addAll(0, copyFrames);
>>                 } else {
>>                         for (int t= 0; t < maxTimesSingleMovie; t++) {
>>                                 copyFrames.add( this.frameLocations.get(0)
>>  );
>>                                 this.frameLocations.remove(0);
>>                         }
>>                         this.frameLocations.addAll(copyFrames);
>>                 }
>>
>>         }
>>
>>
>>
>>  **Now to the problems I am having (apparently at the level of the JVM??).
>>  Here I try to call the public method MQTVS.adjustSingleMovieZ(int channel,
>>  boolean forward), sending parameters set by the user in the slider of the
>>  PluginFrame.  I have no problems compiling, and get no exceptions reported
>>  in the log window of ImageJ.  But (thanks to help from Wayne), I find a
>>  ClassCastException from the event dispatch thread in the console.  The
>>  confusion comes in the apparent correctness of the type of a variable that I
>>  assign with the ImagePlus.getStack() command, but the wrongness of how the
>>  event dispatch thread deals with the variable when I try to cast it to its
>>  true type (I think). First I show the code from the method in the
>>  PluginFrame that reads the value of sliders and should call
>>  MQTVS.adjustSingleMovieZ(int channel, boolean forward) to change a specific
>  > QTVS's frame position being displayed.  Then below the code, I show the
>>  IJ.log output from several lines in the method, and then the
>>  ClassCastException from the console.
>>
>>  The key method from my PluginFrame MovieAlignFrameMOD:
>  >    public synchronized void adjustmentValueChanged(AdjustmentEvent e) {
>>         ImagePlus imp = WindowManager.getCurrentImage();
>>
>>         ImageStack stack = imp.getStack();
>>         IJ.log(""+stack.getClass().getName() + "1");
>>
>>         ImageWindow win = imp.getWindow();
>>         int zImpPos = imp.getSlice();
>>         int tImpPos = imp.getFrame();
>>         IJ.log("beforetheloop " +  imp+" \n" + imp.getStack()) ;
>>         boolean forward = false;
>>
>>         if (imp==null) return;
>>                 for (int i=0; i< imp.getNChannels(); i++){
>>                         if (e.getSource()==sliceShifter[i]) {
>>                                 int zShiftLive = sliceShifter[i].getValue();
>>                                 int zShiftNet = zShiftLive -
>>  previousShiftZ[i];
>>                                 int zShiftNetAbs = zShiftNet;
>>                                 if (zShiftNet < 0) {
>>                                         zShiftNetAbs = -zShiftNet;
>>                                         forward = true;
>>                                 }
>>                                 previousShiftZ[i] = previousShiftZ[i] +
>>  zShiftNet;
>>
>>                                 for(int j = 0; j < zShiftNetAbs; j++){
>>                                         IJ.log("intheloop j= " + j + " " +
>>  imp+" \n" + imp.getStack()) ;
>>         IJ.log(""+stack.getClass().getName() + "2");
>>
>>                         /** THIS DOES NOT REPORT, SO IT'S CLEAR THAT stack
>>  IS NOT reporting as instanceof MultiQTVirtualStack,
>>                         even though it reports as one using
>>  stack.getClass().getName() **/
>>                                         if (stack instanceof
>>  MultiQTVirtualStack ) IJ.log("MultiQTVirtualStack? Yes!!!!");
>>
>>                         /*** ...But THIS STILL READS OUT AS
>>  MultiQTVirtualStack  ******/
>>
>>         IJ.log(""+stack.getClass().getName() + "3");
>>
>>                         /**** THIS GIVES A "SILENT" ClassCastException ON
>>  THE EVENT DISPATCH THREAD, CAN SEE IN CONSOLE *****/
>>         /* LINE 289 */                  ((MultiQTVirtualStack)
>>  stack).adjustSingleMovieZ(i, forward);
>>
>>                         /***** Once the exception has been thrown, this next
>>  log statement fails to run ***********/
>>
>>         IJ.log(""+stack.getClass().getName() + "4");
>>
>>                                 }
>>
>>                         }
>>                         else if (e.getSource()==frameShifter[i]) {
>>                                 int tShiftLive = frameShifter[i].getValue();
>>                                 int tShiftNet = tShiftLive -
>>  previousShiftT[i];
>>                                 previousShiftT[i] = tShiftNet;
>>                         /****** THE ACTIONS OF THIS IF CONDITION WILL BE
>>  FILLED IN LATER ONCE I FIGURE OUT OTHER PROBLEMS ********/
>>
>>                         }
>>                         notify();
>>                 }
>>         }
>>     }
>>
>>
>>
>>  Here's what is logged by the IJ.log() statements above during a slider
>>  adjustment:
>>
>>  MultiQTVirtualStack1
>>  beforetheloop imp[3-Movie Overlay #1 : see Log window for details
>>  600x411x38961]
>>  stack[600x411x38961]
>>  intheloop j= 0 imp[3-Movie Overlay #1 : see Log window for details
>>  600x411x38961]
>>  stack[600x411x38961]
>>  MultiQTVirtualStack2
>>  MultiQTVirtualStack3
>>
>>
>>  !!Note that I did not leave out the 4th log statement in copying. The CCE
>>  apparently blocks the ability to run the 4th IJ.log statement after line
>>  289.  Also, the instanceof test fails (even before line 289), because I
>>  don't get the "MultiQTVirtualStack? Yes!!!" log printed.
>>
>>
>>  Finally, this is the exception from the event dispatch thread at the
>>  critical line 289:
>>
>>  4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748] Exception in
>>  thread "AWT-EventQueue-0" java.lang.ClassCastException: MultiQTVirtualStack
>>  4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748]  at
>  > MovieAlignFrameMOD.adjustmentValueChanged(MovieAlignFrameMOD.java:289)
>>  4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748]  at
>>  java.awt.Scrollbar.processAdjustmentEvent(Scrollbar.java:1094)
>>  4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748]  at
>  > java.awt.Scrollbar.processEvent(Scrollbar.java:1061)
>>  4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748]  at
>>  java.awt.Component.dispatchEventImpl(Component.java:4068)
>>  4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748]  at
>>  java.awt.Component.dispatchEvent(Component.java:3903)
>>  4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748]  at
>>  java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
>>  4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748]  at
>>
>>java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:269)
>>  4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748]  at
>>
>>java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
>>  4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748]  at
>>  java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:184)
>>  4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748]  at
>>  java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:176)
>>
>>
>>
>>  In summary, I seem to have an object called stack returned to me by
>>  ImagePlus.getStack() which both is a MultiQTVirtualStack by some tests and
>>  is NOT a MultiQTVirtualStack by others, and these other criteria are what I
>>  really need to make my PluginFrame work.
>>
>>  Can anyone give me a hint of an explanation of what is going on here?
>>


--
-----------------
William A. Mohler
Associate Professor
Dept. of Genetics and Developmental Biology
University of Connecticut Health Center
MC-3301
263 Farmington Ave.
Farmington, CT   06030-3301

[hidden email]
Mobile: (860) 985-2719
alt. mobile: (860) 331-8514
skype: wmohler

Office: (860) 679-1833, room E2029
Lab: (860) 679-1834, room E2032
Fax: (314) 689-1833

G&DB dept. ofc.: (860) 679-8350
G&DB dept. fax : (860) 679-8345
http://genetics.uchc.edu/Faculty/Mohler/Mohler.html