BUG: ClassCastException Calling from Java to Java via COM

ID: Q202600


The information in this article applies to:


SYMPTOMS

When you make a Java to Java call through COM using a user-defined or Visual J++ 6.0 generated class type, you might experience a ClassCastException when you do type casts.


CAUSE

This is a known limitation of the Java-COM support in current Microsoft Java Virtual Machines.


STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article.


MORE INFORMATION

Steps to Reproduce Behavior

The following steps demonstrate the ClassCastException when you try to cast to a disp interface generated by Visual J++ 6.0. A workaround for the problem is also included.

This example uses two separate Visual J++ 6.0 solutions, not two projects in one solution. The first solution contains two Java source files that represent the Java COM object you are building.
  1. Create a new Visual J++ 6.0 project solution by clicking the Components folder in the New Project dialog box and clicking the COM DLL project template. Call the project JavaCOMClass. NOTE: The project name is not crucial (the COM DLL is given the same name as the Project by default).


  2. Click Add Item, click the Class folder, click the Class template, and create the following two separate source files into the JavaCOMClass project, called JavaCOMClassA.java and JavaCOMClassB.java. NOTE: you can delete the default Class1.java file that the Project template creates for you):

    Source File 1: JavaCOMClassA.java
    
    //JavaCOMClassA.java
    /**
     * @com.register ( clsid=39E0D51C-A704-11D1-9BAC-00A0C905438F, typelib=39E0D51A-A704-11D1-9BAC-00A0C905438F )
     */ 
    public class JavaCOMClassA 
    {
       public JavaCOMClassB GetB() 
       {
          return new JavaCOMClassB();
       }
    
    } 
    Source File 2: JavaCOMClassB.java
    
    //JavaCOMClassB.java
    
    /**
     * @com.register (clsid=39E0D51B-A704-11D1-9BAC-00A0C905438F,typelib=39E0D51A-A704-11D1-9BAC-00A0C905438F )
     */ 
    
    
    public class JavaCOMClassB 
    {
    
       private int m_iData = 5;
    
       public void SetData(int iData) 
       {
       m_iData = iData;
       }
    
       public int GetData()   
       {
         return m_iData;
    
       }
    
    
    } 


  3. On the Build menu, click Build to build the JavaCOMClass project.


RESULT: This should generate a COM type library called JavaCOMCLass.tlb, as well as a COM DLL called JavaCOMClass.DLL
Now you need to create a second project solution to test the Java COM object you created in the first solution.
  1. On the File menu, click New Project, click the Applications folder in the New Project dialog box, and click the Console Application project type. Make sure that the Close current solution is selected so that you create a second solution with this project. In this example, name the second project Main.


  2. Click Add Item, click the Class folder, click the Class template, and create the following source file in the Main project, called Main.java. NOTE: you can delete the default Class1.java file that the Project template creates for you):
    
    //Main.java
    
    import com.ms.com.*;
    import javacomclass.*;
    
    public class Main
    {
    
       public static void main(String[] args) 
       {
          int data;
    
          try 
          {
             JavaCOMClassA_Dispatch A = new JavaCOMClassA();
    
    
             /**
              * First, return a JavaCOMClassB user-defined COM object
              * directly from JavaCOMClassA.GetB(). This should cause a
              * ClassCastException when casting the Object to its appropriate
              * disp interface.
              */ 
             try {
                Object obj = A.GetB();
    
                JavaCOMClassB_Dispatch b = (JavaCOMClassB_Dispatch)obj;
             }
             catch(ClassCastException cce) 
             {
               com.ms.wfc.util.Debug.println("ClassCastException calling JavaCOMClassA.GetB() directly");                           
             }
    
             /**
              * This workaround uses the Object class returned from GetB() and
              * the Static Dispatch class to invoke COM methods through  
              * IDispatch.
              */ 
             Object B = A.GetB();
             Variant V = Dispatch.call(B,"GetData");
             data = V.getInt();
             com.ms.wfc.util.Debug.println(new Integer(data).toString());
    
             V = Dispatch.call(B,"SetData", new Integer(10));
             V = Dispatch.call(B,"GetData");
             data = V.getInt();
             com.ms.wfc.util.Debug.println(new Integer(data).toString());
    
          } catch(ClassCastException e) {
             e.printStackTrace();
             System.out.println(e.toString());
             System.out.println(e.getMessage());
             }
    
       }
    
    } 


  3. Now you need to add the Java-COM wrapper classes for the COM object created in the JavaCOMClass project. With the Main project open, go to the Project menu and click Add COM Wrapper to open the COM Wrappers dialog box.


  4. In the COM Wrappers dialog box, click Browse and go to the JavaCOMClass project directory in the Select COM Component dialog box that appears. Double-click JavaCOMClass.dll to add the COM wrappers for the JavaCOMClass COM object to your Main project, and click OK. This creates a javacomclass directory in your Main project.


  5. On the Build menu, click Build to build the Main project. If you get a compiler error stating that Main class is not found at this stage, go to the Project menu, click Main Properties, click the Launch tab, select the Main class in the When project runs, load list box, and click Apply.


  6. Run the project under the debugger.


RESULT: If you set a breakpoint on the first executable line in Main and single step through Main, you should see that the ClassCastException is thrown when you call A.GetB() in the first try block. If you look at the Java COM wrappers generated for JavaCOMClassA(javacomclass.JavaCOMClassA.java) you should see that JavaCOMClassA.GetB() returns an Object type. The casting of this to JavaCOMClassB type is what generates the exception.

The second try block demonstrates a suggested workaround that uses the static Dispatch class to call the COM methods of JavaCOMClassB through the disp interface generated for the JavaCOMClassB object.

© Microsoft Corporation 1999, All Rights Reserved.
Contributions by Stephen L. Horne, Microsoft Corporation


REFERENCES

For the latest Knowledge Base articles and other support information on Visual J++ and the SDK for Java, please see the following pages on the Microsoft Technical Support site:

http://support.microsoft.com/support/visualj/

http://support.microsoft.com/support/java/

Additional query words:


Keywords          : kbCOMt kbJava kbJavaVM kbVJ600 kbGrpJava 
Version           : WINDOWS:6.0
Platform          : WINDOWS 
Issue type        : kbbug 

Last Reviewed: February 24, 1999