Microsoft KB Archive/202600

= BUG: ClassCastException Calling from Java to Java via COM =

Article ID: 202600

Article Last Modified on 6/14/2006

-

APPLIES TO


 * Microsoft Visual J++ 6.0 Standard Edition
 * Microsoft Java Virtual Machine

-



This article was previously published under Q202600



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 that this is a bug in the Microsoft products that are listed at the beginning of this article.



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.

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

}

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

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

}

}                       </li> 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.</li> 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.</li> 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.</li> Run the project under the debugger.</li></ol>

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.

<div class="references_section">