Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Strange runtime error: AbstractMethodError

Reply
Thread Tools

Strange runtime error: AbstractMethodError

 
 
Oliver Wong
Guest
Posts: n/a
 
      02-07-2007
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


 
Reply With Quote
 
 
 
 
Mike Schilling
Guest
Posts: n/a
 
      02-07-2007
"Oliver Wong" <(E-Mail Removed)> wrote in message
news:kwqyh.94077$(E-Mail Removed). ..
> 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


 
Reply With Quote
 
 
 
 
opalpa opalpa@gmail.com http://opalpa.info
Guest
Posts: n/a
 
      02-07-2007
On Feb 7, 4:20 pm, "Oliver Wong" <(E-Mail Removed)> 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://www.velocityreviews.com/forums/(E-Mail Removed)
http://opalpa.info/

 
Reply With Quote
 
Oliver Wong
Guest
Posts: n/a
 
      02-07-2007
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


 
Reply With Quote
 
Oliver Wong
Guest
Posts: n/a
 
      02-07-2007
"Mike Schilling" <(E-Mail Removed)> wrote in message
newsWqyh.25398$(E-Mail Removed) et...
>
> 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


 
Reply With Quote
 
Oliver Wong
Guest
Posts: n/a
 
      02-07-2007
<(E-Mail Removed)> wrote in message
news:(E-Mail Removed) oups.com...
[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


 
Reply With Quote
 
Lew
Guest
Posts: n/a
 
      02-07-2007
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 -Xlintverrides.

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
 
Reply With Quote
 
Mike Schilling
Guest
Posts: n/a
 
      02-07-2007

"Oliver Wong" <(E-Mail Removed)> wrote in message
news:7Oryh.94111$(E-Mail Removed). ..
> 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.


 
Reply With Quote
 
Chris Uppal
Guest
Posts: n/a
 
      02-08-2007
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



 
Reply With Quote
 
Oliver Wong
Guest
Posts: n/a
 
      02-08-2007
"Oliver Wong" <(E-Mail Removed)> wrote in message
news:7Oryh.94111$(E-Mail Removed). ..
> 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.printlnLjava/lang/StringV
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.printlnLjava/lang/StringV
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


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
java.lang.AbstractMethodError: at the org.apache.xerces.dom.DOMImplementationImpl.createLSOutput() poorichard@gmail.com Java 2 09-18-2006 02:08 AM
Runtime.exec(String[]) Doesn't Always Work, bBut Runtime.exec(String) Does Hal Vaughan Java 11 05-22-2006 04:49 PM
JDBC issues with setBinaryStream an AbstractMethodError and a cast gimme_this_gimme_that@yahoo.com Java 1 05-19-2005 08:40 PM
JNI -- getting AbstractMethodError Jeff Gaynor Java 1 05-25-2004 02:47 PM
debugging java AbstractMethodError Bin Xin Java 3 08-18-2003 03:23 PM



Advertisments