3 Replies Latest reply on Mar 8, 2006 10:11 PM by Jeremy Hall

    Incompatible object argument for function call

    Caleb Troughton Newbie

      Hello,

      I am generating classes at runtime that implement a common interface that contains only one method:

      public interface DynamicTranslation {
      public Object translate(Map m, Map v);
      }


      One such class has the following generated code for its translate method:

      public Object translate(Map m, Map v) {
      return new Integer((($2.get("Quantity")!= null) ? $2.get("Quantity") : "1").toString());
      }


      The method is made and added to the class and toClass() is called all without a hitch. Let's say that this new class is held as a member datum called "trClass" and I try to perform the following:

      Method m = trClass.getMethod("translate", new Class[] {Map.class, Map.class});

      I receive the following stack trace from doing this call:

      Exception in thread "main" java.lang.VerifyError: (class: **********************, method: translate signature: (Ljava/util/Map;Ljava/util/Map;)Ljava/lang/Object;) Incompatible object argument for function call
      at java.lang.Class.getDeclaredMethods0(Native Method)
      at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
      at java.lang.Class.getMethod0(Unknown Source)
      at java.lang.Class.getMethod(Unknown Source)
      at (The Line I Performed getMethod)


      By contrast, if I change the generated code for this class' "translate" method to the following (in which I switch the second ($2.get("Quantity")) with the literal "4"):

      return new Integer((($2.get("Quantity")!= null) ? "4" : "1").toString());

      ...everything works fine. Am I missing something or is this a bug in javassist itself? If it helps, the context in which these methods and classes are generated works, as hundreds of others very similar are generated and working correctly using the same procedures.

      Whatever insight or help could be given into this situation would be appreciated.

        • 1. Re: Incompatible object argument for function call
          Caleb Troughton Newbie

          For the record, this can be simplified further and still not work.

          public Object translate(Map m, Map v) {
          return (($2.get("Quantity")!= null) ? $2.get("Quantity") : "1").toString();
          }


          Same error.

          Has anybody ran into this same thing or have any explanation for the error?

          • 2. Re: Incompatible object argument for function call
            Caleb Troughton Newbie

            Sorry to post small insights into my own problem, but I thought I should add this as well:

            return $2.get("Quantity") != null ? $2.get("Quantity") : "1";

            This works fine. It is only when using the return value of the conditional operator as a parameter or context object for some function call that I get the Verify Error. I thought it may be because I was using illegal arguments for the conditional operator, but according to the Java Language Spec what I did above should be fine because the second and third arguments are both references. If I've misunderstood that part to be true, then please correct me, but it seems that since the above code works, then I assume my code is valid.

            Chiba, considering Verify Error is essentially "this didn't pass language spec" can I consider this a bug within Javassist in dealing with the return type of the conditional operator? If not I'm still very curious what is wrong within my code.

            (BTW, I would just stop using the conditional operator, but the code that could be potentially generated in this program genuinely calls for only one line without intermediate variable storage.)

            • 3. Re: Incompatible object argument for function call
              Jeremy Hall Newbie

              I ran some tests and was getting the same error as you. I believe that the problem lies in the fact that new Integer() expects a String or an int. When you use your original line:

              return new Integer((($2.get("Quantity")!= null) ? $2.get("Quantity") : "1").toString());


              you leave the possibility of returning $2.get("Quantity"), which returns an Object (as opposed to a String or an int). If I change the return statement to:

              return new Integer((($2.get("Quantity")!= null) ? $2.get("Quantity").toString() : "1").toString());


              then the error went away.

              For reference, here is example code that compiles without errors:

              package quicktest;
              
              import javassist.*;
              import java.lang.reflect.*;
              import java.util.*;
              
              public class Main {
              
               public Main() {
               }
              
               public static void main(String[] args) {
               ClassPool pool = ClassPool.getDefault();
               CtClass newCtClass = pool.makeClass( "TestClass" );
               String body = "public Object translate(java.util.Map m, java.util.Map v) {" +
               "return new Integer((($2.get(\"Quantity\").equals(null)) ? $2.get(\"Quantity\").toString() : \"1\").toString());}";
              
               try
               {
               CtMethod testCtMethod = CtNewMethod.make( body, newCtClass );
               newCtClass.addMethod( testCtMethod );
              
               Class newCreatedClass = newCtClass.toClass();
              
               Method testMethod = newCreatedClass.getDeclaredMethod( "translate", new Class[] { Map.class, Map.class } );
               Object testObject = newCreatedClass.newInstance();
              
              
               }catch( Exception e )
               {
               e.printStackTrace( System.err );
               }
               }
              }