Strange runtime error: AbstractMethodError

Discussion in 'Java' started by Oliver Wong, Feb 7, 2007.

  1. Oliver Wong

    Oliver Wong Guest

    Here's my code:

    <SSCCE>
    package com.castortech.tests;

    import net.sf.saxon.om.SiblingCountingNode;

    import com.castortech.common.parser.tokenstreaming.Token;

    public class BugTest {
    public static void main(String[] args) {
    Token t = new Token();
    t.getParent();
    SiblingCountingNode scn = t;
    scn.getParent(); /*<-- line 12*/
    }
    }
    </SSCCE>

    It compiles fine, and Token does indeed implement SiblingCountingNode
    (although indirectly), which is why no cast is required. However, when I try
    to run this program, I get the following runtime error:

    <error>
    Exception in thread "main" java.lang.AbstractMethodError:
    com.castortech.common.parser.tokenstreaming.Token.getParent()Lnet/sf/saxon/om/NodeInfo;
    at com.castortech.tests.BugTest.main(BugTest.java:12)
    </error>

    In case this is useful, the hierarchy is:

    class Token extends class BaseNode
    class BaseNode extends class ElementNode
    class ElementNode extends class AbstractNode and implements interface
    IElementNode
    class AbstractNode implements interface INode
    interface IElementNode extends interface INode
    interface INode extends interfaces IAdaptable, NodeInfo and
    SiblingCountingNode

    Token, BaseNode, ElementNode, AbstractNode, IElementNode and INode are from
    our internal codebase.
    IAdaptable is from Eclipse's API
    NodeInfo and SiblingCountingNode are from Saxon
    (http://saxon.sourceforge.net/)

    And in case this is a bug in the Eclipse compiler, I've tried it with 3.3M4
    and I20070206-0010 and get the same error on both.

    The baffling part, for me, is that the call to getParent() (which is NOT a
    static method) works if the reference is Token, but not if the reference is
    SiblingCountingNode.

    Any hints on how to fix this error?

    - Oliver
     
    Oliver Wong, Feb 7, 2007
    #1
    1. Advertising

  2. "Oliver Wong" <> wrote in message
    news:kwqyh.94077$...
    > Here's my code:
    >
    > <SSCCE>
    > package com.castortech.tests;
    >
    > import net.sf.saxon.om.SiblingCountingNode;
    >
    > import com.castortech.common.parser.tokenstreaming.Token;
    >
    > public class BugTest {
    > public static void main(String[] args) {
    > Token t = new Token();
    > t.getParent();
    > SiblingCountingNode scn = t;
    > scn.getParent(); /*<-- line 12*/
    > }
    > }
    > </SSCCE>
    >
    > It compiles fine, and Token does indeed implement SiblingCountingNode
    > (although indirectly), which is why no cast is required. However, when I
    > try to run this program, I get the following runtime error:
    >
    > <error>
    > Exception in thread "main" java.lang.AbstractMethodError:
    > com.castortech.common.parser.tokenstreaming.Token.getParent()Lnet/sf/saxon/om/NodeInfo;
    > at com.castortech.tests.BugTest.main(BugTest.java:12)
    > </error>
    >
    > In case this is useful, the hierarchy is:
    >
    > class Token extends class BaseNode
    > class BaseNode extends class ElementNode
    > class ElementNode extends class AbstractNode and implements interface
    > IElementNode
    > class AbstractNode implements interface INode
    > interface IElementNode extends interface INode
    > interface INode extends interfaces IAdaptable, NodeInfo and
    > SiblingCountingNode
    >
    > Token, BaseNode, ElementNode, AbstractNode, IElementNode and INode are
    > from our internal codebase.
    > IAdaptable is from Eclipse's API
    > NodeInfo and SiblingCountingNode are from Saxon
    > (http://saxon.sourceforge.net/)
    >
    > And in case this is a bug in the Eclipse compiler, I've tried it with
    > 3.3M4 and I20070206-0010 and get the same error on both.
    >
    > The baffling part, for me, is that the call to getParent() (which is NOT a
    > static method) works if the reference is Token, but not if the reference
    > is SiblingCountingNode.
    >
    > Any hints on how to fix this error?


    It is axiomatic that AbstractMethodError means that something changed
    between compilation time and runtime. If you could recompile the whole
    thing from source, then either your problem would go away or you'd see a
    compilation error that explains the problem.

    My guess is that some of the definitions of getParent() are incompatible
    (i.e. return different types), but that's just a guess. It's a place to
    start though: what type does Token.getParent return? The overload that
    can't be found returns net.sf.saxon.om.NodeInfo
     
    Mike Schilling, Feb 7, 2007
    #2
    1. Advertising

  3. On Feb 7, 4:20 pm, "Oliver Wong" <> wrote:
    > Here's my code:
    >
    > <SSCCE>
    > package com.castortech.tests;
    >
    > import net.sf.saxon.om.SiblingCountingNode;
    >
    > import com.castortech.common.parser.tokenstreaming.Token;
    >
    > public class BugTest {
    > public static void main(String[] args) {
    > Token t = new Token();
    > t.getParent();
    > SiblingCountingNode scn = t;
    > scn.getParent(); /*<-- line 12*/
    > }}
    >
    > </SSCCE>
    >
    > It compiles fine, and Token does indeed implement SiblingCountingNode
    > (although indirectly), which is why no cast is required. However, when I try
    > to run this program, I get the following runtime error:
    >
    > <error>
    > Exception in thread "main" java.lang.AbstractMethodError:
    > com.castortech.common.parser.tokenstreaming.Token.getParent()Lnet/sf/saxon/om/NodeInfo;
    > at com.castortech.tests.BugTest.main(BugTest.java:12)
    > </error>
    >
    > In case this is useful, the hierarchy is:
    >
    > class Token extends class BaseNode
    > class BaseNode extends class ElementNode
    > class ElementNode extends class AbstractNode and implements interface
    > IElementNode
    > class AbstractNode implements interface INode
    > interface IElementNode extends interface INode
    > interface INode extends interfaces IAdaptable, NodeInfo and
    > SiblingCountingNode
    >
    > Token, BaseNode, ElementNode, AbstractNode, IElementNode and INode are from
    > our internal codebase.
    > IAdaptable is from Eclipse's API
    > NodeInfo and SiblingCountingNode are from Saxon
    > (http://saxon.sourceforge.net/)
    >
    > And in case this is a bug in the Eclipse compiler, I've tried it with 3.3M4
    > and I20070206-0010 and get the same error on both.
    >
    > The baffling part, for me, is that the call to getParent() (which is NOT a
    > static method) works if the reference is Token, but not if the reference is
    > SiblingCountingNode.
    >
    > Any hints on how to fix this error?
    >
    > - Oliver



    That's quite confounding. What does the end of the this line mean?
    com.castortech.common.parser.tokenstreaming.Token.getParent()Lnet/sf/
    saxon/om/NodeInfo

    Why is the end NodeInfo instead of SiblingCountingNode?

    Do multiple interfaces have the same method signature in them?

    Does the same method name have different signatures? That is: is
    there a getParent with parameters along with the parameterless
    getParent?

    These are just a couple of thoughts. It appears that you've found a
    fault in Java.

    Will write if any other thoughts come to mind. Good luck Oliver.

    opalpa

    http://opalpa.info/
     
    opalpa http://opalpa.info, Feb 7, 2007
    #3
  4. Oliver Wong

    Oliver Wong Guest

    After a bit for trimming, I've formed an SSCCE that doesn't require any
    external libraries:

    <SSCCE>
    interface Root {
    public Root someMethod();
    }

    interface Intermediary extends Root {
    public Leaf someMethod();
    }

    class Leaf implements Intermediary {
    @Override
    public Leaf someMethod() {
    return null;
    }
    }

    public class BugTest {
    public static void main(String[] args) {
    Leaf leafReference = new Leaf();
    leafReference.someMethod();
    Root rootReference = leafReference;
    rootReference.someMethod(); /* throws error */
    }
    }
    </SSCCE>

    <output>
    Exception in thread "main" java.lang.AbstractMethodError:
    Leaf.someMethod()LRoot;
    at BugTest.main(BugTest.java:21)
    </output>

    But I'm still unsure if this is a bug in the JVM, the compiler, or if this
    is the correct behaviour of the Java language, using some rule I'm not
    familiar with.

    - Oliver
     
    Oliver Wong, Feb 7, 2007
    #4
  5. Oliver Wong

    Oliver Wong Guest

    "Mike Schilling" <> wrote in message
    news:pWqyh.25398$...
    >
    > It is axiomatic that AbstractMethodError means that something changed
    > between compilation time and runtime. If you could recompile the whole
    > thing from source, then either your problem would go away or you'd see a
    > compilation error that explains the problem.


    Or that there's a bug in the compiler/JVM? ;) Elsewhere in this thread,
    I've posted an SSCCE that doesn't require the Saxon JAR, compiled it
    completely from scratch, and got the same error message.

    >
    > My guess is that some of the definitions of getParent() are incompatible
    > (i.e. return different types), but that's just a guess. It's a place to
    > start though: what type does Token.getParent return? The overload that
    > can't be found returns net.sf.saxon.om.NodeInfo


    Right. If you take a look at the new SSCCE, getParent() (now renamed
    "someMethod") is defined twice, each one with a different return type. But I
    thought this was legal in Java... "Return Type Covariance", it's called, or
    something like that, right?

    - Oliver
     
    Oliver Wong, Feb 7, 2007
    #5
  6. Oliver Wong

    Oliver Wong Guest

    <> wrote in message
    news:...
    [details of my original problem snipped]
    >
    > That's quite confounding. What does the end of the this line mean?
    > com.castortech.common.parser.tokenstreaming.Token.getParent()Lnet/sf/
    > saxon/om/NodeInfo
    >
    > Why is the end NodeInfo instead of SiblingCountingNode?
    >
    > Do multiple interfaces have the same method signature in them?
    >
    > Does the same method name have different signatures? That is: is
    > there a getParent with parameters along with the parameterless
    > getParent?
    >
    > These are just a couple of thoughts. It appears that you've found a
    > fault in Java.
    >
    > Will write if any other thoughts come to mind. Good luck Oliver.


    Thanks. It looks like you were on the right track: I posted a second
    SSCCE that doesn't require any external libraries, and it does seem to
    involve multiple interfaces with the same method, but with different
    signatures. However, I still don't know whether this is a problem with the
    JVM, compiler, or my understanding of Java, so I'm not yet able to fix the
    "real" code where this problem is occurring.

    - Oliver
     
    Oliver Wong, Feb 7, 2007
    #6
  7. Oliver Wong

    Lew Guest

    Oliver Wong wrote:
    > After a bit for trimming, I've formed an SSCCE that doesn't require any
    > external libraries:
    >
    > <SSCCE>
    > interface Root {
    > public Root someMethod();
    > }
    >
    > interface Intermediary extends Root {
    > public Leaf someMethod();
    > }
    >
    > class Leaf implements Intermediary {
    > @Override
    > public Leaf someMethod() {
    > return null;
    > }
    > }
    >
    > public class BugTest {
    > public static void main(String[] args) {
    > Leaf leafReference = new Leaf();
    > leafReference.someMethod();
    > Root rootReference = leafReference;
    > rootReference.someMethod(); /* throws error */
    > }
    > }
    > </SSCCE>
    >
    > <output>
    > Exception in thread "main" java.lang.AbstractMethodError:
    > Leaf.someMethod()LRoot;
    > at BugTest.main(BugTest.java:21)
    > </output>
    >
    > But I'm still unsure if this is a bug in the JVM, the compiler, or if this
    > is the correct behaviour of the Java language, using some rule I'm not
    > familiar with.


    I think we're dealing with
    <http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.8.4>

    When I try your example I immediately but not consistently get an error from
    Netbeans on the @Override,

    "method does not override a method from its superclass"

    but javac doesn't show me this, not even with -Xlint:eek:verrides.

    Now, try adding these two classes to the source:

    interface Othif extends Root
    {
    public String someMethod(); // String is not a subtype of Root
    }

    class OthImpl implements Othif
    {
    @Override
    public String someMethod()
    {
    return null;
    }
    }

    These give the expected compilation errors:

    src/testit/BugTest.java:30: someMethod() in testit.Othif clashes with
    someMethod() in testit.Root; attempting to use incompatible return type
    found : java.lang.String
    required: testit.Root
    public String someMethod();

    src/testit/BugTest.java:33: testit.OthImpl is not abstract and does not
    override abstract method someMethod() in testit.Root
    class OthImpl implements Othif

    src/testit/BugTest.java:36: someMethod() in testit.OthImpl cannot implement
    someMethod() in testit.Root; attempting to use incompatible return type
    found : java.lang.String
    required: testit.Root
    public String someMethod()


    - Lew
     
    Lew, Feb 7, 2007
    #7
  8. "Oliver Wong" <> wrote in message
    news:7Oryh.94111$...
    > After a bit for trimming, I've formed an SSCCE that doesn't require any
    > external libraries:
    >
    > <SSCCE>
    > interface Root {
    > public Root someMethod();
    > }
    >
    > interface Intermediary extends Root {
    > public Leaf someMethod();
    > }
    >
    > class Leaf implements Intermediary {
    > @Override
    > public Leaf someMethod() {
    > return null;
    > }
    > }
    >
    > public class BugTest {
    > public static void main(String[] args) {
    > Leaf leafReference = new Leaf();
    > leafReference.someMethod();
    > Root rootReference = leafReference;
    > rootReference.someMethod(); /* throws error */
    > }
    > }
    > </SSCCE>
    >
    > <output>
    > Exception in thread "main" java.lang.AbstractMethodError:
    > Leaf.someMethod()LRoot;
    > at BugTest.main(BugTest.java:21)
    > </output>


    Using JDK 1.4, this won't compile. Which makes sense, since covariant
    return types were introduced in 1.5. In case anyone's interested, the
    errors are:

    Intermediary.java:2: someMethod() in Intermediary clashes with someMethod()
    in Root; attempting to use incompatible return type
    found : Leaf
    required: Root
    public Leaf someMethod();
    ^
    Leaf.java:4: someMethod() in Leaf cannot implement someMethod() in Root;
    attempting to use incompatible return type
    found : Leaf
    required: Root
    public Leaf someMethod() {
    ^

    Using jdk1.5.0_05's javac, I get the error:

    Leaf.java:3: method does not override a method from its superclass
    @Override

    Which is true, I suppose. Commenting out the annotation, it all compiles
    correctly and runs successfully as well (still using jdk1.5.0_05) . Since
    javap shows that the overload being called is Root.someMethod:()LRoot;,
    there must be some logic in the JVM to realize that someMethod:()LLeaf; is
    "close enough".

    So it appears that the problem (in your SSCCE, at least) is a JVM bug.
     
    Mike Schilling, Feb 7, 2007
    #8
  9. Oliver Wong

    Chris Uppal Guest

    Oliver Wong wrote:

    > After a bit for trimming, I've formed an SSCCE that doesn't require any
    > external libraries:


    I can't repeat this using Sun's javac (JDK1.5 or JDK1.6), nor with Eclipse's
    own
    compiler (3.2.1 targeting "5.0 compliance level").

    I changed the example slightly, so that:

    class Leaf implements Intermediary {
    public Leaf someMethod() {
    System.out.println("Yup, we're here as expected");
    return null;
    }
    }

    and it prints out the message twice, as expected.

    I suspect that the (original) problem you are seeing is directly connected with
    the godawful covariate returns hack. I presume that somewhere in the complex
    inheritance of Token from SiblingCountInfo, the Eclipse compiler has
    "forgotten" to generate the necessary bridging method (or methods) to adapt the
    return-type(s) of whatever overrides of getParent() there may be.

    Possibly the (perfectly legitimate) duplicate inheritance of NodeInfo in INode
    (both directly and via SiblingCountingNode), has confused it.

    If you can be bothered it would be interesting to see what actual
    implementations of getParent() from each of the classes (not interfaces) there
    are in the chain. Not their contents, just which ones define them and how they
    are declared. Also (there's no point without this too) use javap to see what
    /actual/ implementations have been defined in each of those classes (again, not
    the bytecode, just the declarations).

    -- chris
     
    Chris Uppal, Feb 8, 2007
    #9
  10. Oliver Wong

    Oliver Wong Guest

    "Oliver Wong" <> wrote in message
    news:7Oryh.94111$...
    > After a bit for trimming, I've formed an SSCCE that doesn't require any
    > external libraries:
    >
    > <SSCCE>
    > interface Root {
    > public Root someMethod();
    > }
    >
    > interface Intermediary extends Root {
    > public Leaf someMethod();
    > }
    >
    > class Leaf implements Intermediary {
    > @Override
    > public Leaf someMethod() {
    > return null;
    > }
    > }
    >
    > public class BugTest {
    > public static void main(String[] args) {
    > Leaf leafReference = new Leaf();
    > leafReference.someMethod();
    > Root rootReference = leafReference;
    > rootReference.someMethod(); /* throws error */
    > }
    > }
    > </SSCCE>


    Thank you, everyone, for your help.

    I made the change Chris suggested, and added a System.out.println("Got
    here") to Leaf for debugging purposes.

    If I take out the @Override annotation, I get the exact same result with
    Eclipse's compiler: No compile errors, but the AbstractMethodError at
    runtime. However if I compile the original source code (with the @Override
    annotation, and with the system.out.println) using Sun's javac compiler, it
    compiles fine, and runs fine (the message is printed out twice as expected).

    So it sounds like this is a bug in Eclipse's compiler. I did a
    disassembly of both the javac classes and the eclipsec classes, and all the
    files are identical except for Leaf.class.

    Here's the javac version:

    <disassembly>
    Compiled from "BugTest.java"
    class Leaf extends java.lang.Object implements Intermediary{
    Leaf();
    Code:
    0: aload_0
    1: invokespecial #1; //Method java/lang/Object."<init>":()V
    4: return

    public Leaf someMethod();
    Code:
    0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
    3: ldc #3; //String Yup, we're here.
    5: invokevirtual #4; //Method
    java/io/PrintStream.println:(Ljava/lang/String;)V
    8: aconst_null
    9: areturn

    public Root someMethod();
    Code:
    0: aload_0
    1: invokevirtual #5; //Method someMethod:()LLeaf;
    4: areturn

    }
    </disassembly>

    And here's the Eclipse version:

    <disassembly>
    Compiled from "BugTest.java"
    class Leaf extends java.lang.Object implements Intermediary{
    Leaf();
    Code:
    0: aload_0
    1: invokespecial #10; //Method java/lang/Object."<init>":()V
    4: return

    public Leaf someMethod();
    Code:
    0: getstatic #18; //Field
    java/lang/System.out:Ljava/io/PrintStream;
    3: ldc #24; //String Yup, we're here.
    5: invokevirtual #26; //Method
    java/io/PrintStream.println:(Ljava/lang/String;)V
    8: aconst_null
    9: areturn

    }
    </disassembly>

    The main difference being the lack of "public Root someMethod();" within
    Eclipse's version.

    I filed this as a bug with Eclipse:
    https://bugs.eclipse.org/bugs/show_bug.cgi?id=173477

    - Oliver
     
    Oliver Wong, Feb 8, 2007
    #10
  11. "Mike Schilling" <> wrote in message
    news:2Qsyh.74355$...

    >
    > Which is true, I suppose. Commenting out the annotation, it all compiles
    > correctly and runs successfully as well (still using jdk1.5.0_05) . Since
    > javap shows that the overload being called is Root.someMethod:()LRoot;,
    > there must be some logic in the JVM to realize that someMethod:()LLeaf; is
    > "close enough".


    Actually, I'm wrong here. javap on Leaf shows that it contains both
    someMethod:()LRoot and someMethod:()LLeaf, where someMethod:()LRoot is
    automatically generated as if you'd coded

    public Root someMethod()
    {
    return someMethod(); // someMethod:()LLeaf
    }

    This is javac's usual trick for implementing covariant return types.

    So, more likely than a JVM bug is that Eclipse's compiler isn't generating
    this extra method.
     
    Mike Schilling, Feb 8, 2007
    #11
  12. Oliver Wong

    Lew Guest

    Oliver Wong wrote:
    > So it sounds like this is a bug in Eclipse's compiler. I did a
    > disassembly of both the javac classes and the eclipsec classes, and all the
    > files are identical except for Leaf.class.

    ....
    > The main difference being the lack of "public Root someMethod();" within
    > Eclipse's version.
    >
    > I filed this as a bug with Eclipse:
    > https://bugs.eclipse.org/bugs/show_bug.cgi?id=173477


    That explains why I only saw behavior in keeping with the JLS. I used Netbeans
    and command-line javac. (JDK 6)

    - Lew
     
    Lew, Feb 9, 2007
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Bin Xin
    Replies:
    3
    Views:
    4,562
    John C. Bollinger
    Aug 18, 2003
  2. Jeff Gaynor

    JNI -- getting AbstractMethodError

    Jeff Gaynor, May 25, 2004, in forum: Java
    Replies:
    1
    Views:
    848
    Gordon Beaton
    May 25, 2004
  3. Replies:
    1
    Views:
    959
    Lee Fesperman
    May 19, 2005
  4. cppaddict
    Replies:
    7
    Views:
    373
    cppaddict
    Jul 14, 2004
  5. Replies:
    2
    Views:
    5,618
Loading...

Share This Page