Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

com.mysql.jdbc.UpdatableResultSet.updateBlob gives AbstractMethodError

148 views
Skip to first unread message

pjvle...@gmail.com

unread,
Oct 2, 2007, 11:25:46 AM10/2/07
to
Hi all,

I'm quite new to all jdbc, but so far working with resultset's over
SQL seemed easy so far, but I'm having some problems writing a blob to
the database.
What I try to do is two steps:
1. read an image from the web and write it to a blob
2. read the blob and display it as an image

I did the same thing before without trying to write to the blob, but I
want to store the images in DB because the only stay on the web for a
couple of weeks.

Googling for UpdatableResultset updateBlob AbstractMethodError gets me
lost. Any help is well appreciated.

By the way: the image is 18257 bytes and max_allowed_packet of MySQL
is 1048576

Anyone? thanx

### stderr output ###
Exception in thread "main" java.lang.AbstractMethodError:
com.mysql.jdbc.UpdatableResultSet.updateBlob(Ljava/lang/String;Ljava/
io/InputStream;)V
at nl.vanleeuwenwilmot.housing.search.woonnet.app.Test.main(Test.java:
52)
######


### java class ###
package nl.vanleeuwenwilmot.housing.search.woonnet.app;

import java.awt.BorderLayout;
import java.awt.Image;
import java.io.IOException;
import java.io.InputStream;

import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class Test {

/**
* @param args
* @throws IOException
* @throws SQLException
*/
public static void main(String[] args) throws IOException,
SQLException {

Connection con = null;
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
con = DriverManager.getConnection("jdbc:mysql:///woonnet",
"root",
"<A2Cc|4w");
} catch (InstantiationException e) {
e.printStackTrace();
System.exit(1);
} catch (IllegalAccessException e) {
e.printStackTrace();
System.exit(1);
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.exit(1);
}

Statement updatestmt =
con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);

ResultSet resultset = updatestmt
.executeQuery("SELECT * FROM `image` WHERE `house_id`
= 1");
resultset.first();
// fine till here
resultset.updateBlob("image", new URL( // <==== line 52
"http://www.woonnet-haaglanden.nl/library/fotos/
18/12845.jpg")
.openStream());
resultset.updateRow();
resultset.close();
updatestmt.close();

Statement readstmt = null;
readstmt =
con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);

resultset = readstmt.executeQuery("SELECT * FROM `image` " //
+ "WHERE `house_id` = 1;");
resultset.first();
InputStream theimage =
resultset.getBlob("image").getBinaryStream();

Image image = ImageIO.read(theimage);

// Use a label to display the image
JFrame frame = new JFrame();
JLabel label = new JLabel(new ImageIcon(image));
frame.getContentPane().add(label, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
######

Arne Vajhøj

unread,
Oct 2, 2007, 12:54:26 PM10/2/07
to
pjvle...@gmail.com wrote:
> Googling for UpdatableResultset updateBlob AbstractMethodError gets me
> lost. Any help is well appreciated.

> ### stderr output ###


> Exception in thread "main" java.lang.AbstractMethodError:
> com.mysql.jdbc.UpdatableResultSet.updateBlob(Ljava/lang/String;Ljava/
> io/InputStream;)V
> at nl.vanleeuwenwilmot.housing.search.woonnet.app.Test.main(Test.java:
> 52)
> ######

What version of the MySQL JDBC driver are you using ?

I suspect an old version that does not have this method.

Arne

Dyrea...@sun.com

unread,
Oct 2, 2007, 1:00:56 PM10/2/07
to
"pjvle...@gmail.com" <pjvle...@gmail.com> writes:

> Hi all,
>
> I'm quite new to all jdbc, but so far working with resultset's over
> SQL seemed easy so far, but I'm having some problems writing a blob to
> the database.
> What I try to do is two steps:
> 1. read an image from the web and write it to a blob
> 2. read the blob and display it as an image
>
> I did the same thing before without trying to write to the blob, but I
> want to store the images in DB because the only stay on the web for a
> couple of weeks.
>
> Googling for UpdatableResultset updateBlob AbstractMethodError gets me
> lost. Any help is well appreciated.

Why do you have to use an updatable result set to store the blob? Why
can't you use an ordnary update statment?

I don't know if MySQL supports updatable result sets with blobs, (it
probably does) but why make things more complicated than necessary...?

--
dt

pjvle...@gmail.com

unread,
Oct 2, 2007, 2:29:57 PM10/2/07
to
Sorry for the late response, just back from diner.

Arne


> What version of the MySQL JDBC driver are you using ?

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.3</version>
</dependency>
And MySQL monitor informed me that I have 5.0.26-community-nt...

Dt


> Why do you have to use an updatable result set to store the blob? Why
> can't you use an ordnary update statment?

Since I wouldn't know the answer to that question I also tried the
following

PreparedStatement pstmt = con
.prepareStatement("INSERT INTO `image` (`house_id`,
`image`) "
+ "VALUES(1, ?)");
pstmt.setBlob(1, new URL( // <===============line 51


"http://www.woonnet-haaglanden.nl/library/fotos/
18/12845.jpg")
.openStream());

pstmt.executeUpdate();

Exception in thread "main" java.lang.AbstractMethodError:

com.mysql.jdbc.ServerPreparedStatement.setBlob(ILjava/io/
InputStream;)V
at nl.vanleeuwenwilmot.housing.search.woonnet.app.Test.main(Test.java:
51)

And if I try setObject like the following I get no error at 51, but a
null-pointer exception after reading it.

public static void main(String[] args) throws IOException,
SQLException {

Connection con = null;
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
con = DriverManager.getConnection("jdbc:mysql:///woonnet",
"root",
"<A2Cc|4w");
} catch (InstantiationException e) {
e.printStackTrace();
System.exit(1);
} catch (IllegalAccessException e) {
e.printStackTrace();
System.exit(1);
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.exit(1);
}

PreparedStatement pstmt = con
.prepareStatement("INSERT INTO `image` (`house_id`,
`image`) "
+ "VALUES(1, ?)");
pstmt.setObject(1, new URL(


"http://www.woonnet-haaglanden.nl/library/fotos/
18/12845.jpg")
.openStream());

pstmt.executeUpdate();

Statement readstmt = null;
readstmt =
con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);

ResultSet resultset = readstmt.executeQuery("SELECT * FROM


`image` " //
+ "WHERE `house_id` = 1;");
resultset.first();
InputStream theimage =
resultset.getBlob("image").getBinaryStream();

Image image = ImageIO.read(theimage);

// Use a label to display the image
JFrame frame = new JFrame();

JLabel label = new JLabel(new ImageIcon(image)); // <=== line
69
frame.getContentPane().add(label, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}

Exception in thread "main" java.lang.NullPointerException
at javax.swing.ImageIcon.<init>(ImageIcon.java:161)
at nl.vanleeuwenwilmot.housing.search.woonnet.app.Test.main(Test.java:
69)


Further more I tried reading the inputstream to a string (and play
ignorant on charset headaches), but I couldn't get that to work...
(furthermore, it doesn't seem the right way to go).

*Any* suggestions are warmly welcome. I stay tuned..
(oh and off topic suggestions on coding like dt.'s are also welcome,
there's just a lot that I don't know...)

David Harper

unread,
Oct 2, 2007, 3:23:44 PM10/2/07
to
pjvle...@gmail.com wrote:
[SNIP]

> ### stderr output ###
> Exception in thread "main" java.lang.AbstractMethodError:
> com.mysql.jdbc.UpdatableResultSet.updateBlob(Ljava/lang/String;Ljava/
> io/InputStream;)V
> at nl.vanleeuwenwilmot.housing.search.woonnet.app.Test.main(Test.java:
> 52)
> ######
[SNIP]

The Java API documentation for java.lang.AbstractMethodError explains:

public class AbstractMethodError
extends IncompatibleClassChangeError

Thrown when an application tries to call an abstract method. Normally,
this error is caught by the compiler; this error can only occur at run
time if the definition of some class has incompatibly changed since
the currently executing method was last compiled.

This can happen if you have two versions of the Connector/J JAR file,
and you are using the newer one when compiling your code but an older
version when running it. Check your compile-time and run-time
classpaths to ensure that they both reference the newer version of the
JAR file.

David Harper
Cambridge, England

pjvle...@gmail.com

unread,
Oct 2, 2007, 3:41:50 PM10/2/07
to
David

> Thrown when an application tries to call an abstract method. Normally,
> this error is caught by the compiler; this error can only occur at run

> version when running it. Check your compile-time and run-time


> classpaths to ensure that they both reference the newer version of the
> JAR file.

Thanks, but I only *have* one version. I guess the MySQL Connection\J
guys felt that the next "*Normally* this error..." was optional. :)

$ ls -R .m2/repository/mysql/
.m2/repository/mysql/:
mysql-connector-java

.m2/repository/mysql/mysql-connector-java:
5.0.3

.m2/repository/mysql/mysql-connector-java/5.0.3:
mysql-connector-java-5.0.3.jar mysql-connector-java-5.0.3.jar.sha1
mysql-connector-java-5.0.3.pom mysql-connector-java-5.0.3.pom.sha1

Lew

unread,
Oct 2, 2007, 5:05:24 PM10/2/07
to
pjvle...@gmail.com wrote:
> ResultSet.TYPE_FORWARD_ONLY,
...
> resultset.first();
<http://java.sun.com/javase/6/docs/api/java/sql/ResultSet.html#first()>
> Returns:
> true if the cursor is on a valid row; false if there are no rows in the result set

You don't check the return code. This might not matter here, but you should
be aware of it.

> Throws:
> SQLException - if ... this method is called on a ... result set type ... TYPE_FORWARD_ONLY

Which is what you typed your ResultSet.

>
> PreparedStatement pstmt = con
> .prepareStatement("INSERT INTO `image` (`house_id`,
> `image`) "
> + "VALUES(1, ?)");
> pstmt.setBlob(1, new URL( // <===============line 51

> "http://www.woonnet-haaglanden.nl/library/fotos/18/12845.jpg" )


> .openStream());
> pstmt.executeUpdate();
>
> Exception in thread "main" java.lang.AbstractMethodError:
> com.mysql.jdbc.ServerPreparedStatement.setBlob(ILjava/io/
> InputStream;)V
> at nl.vanleeuwenwilmot.housing.search.woonnet.app.Test.main(Test.java:
> 51)

This is pretty much the same error you got with the ResultSet.

> And if I try setObject like the following I get no error at 51, but a
> null-pointer exception after reading it.
>
> public static void main(String[] args) throws IOException,
> SQLException {
>
> Connection con = null;
> try {
> Class.forName("com.mysql.jdbc.Driver").newInstance();

You don't need the newInstance(). You could also do the forName() call in a
static initializer.

...

> PreparedStatement pstmt = con
> .prepareStatement("INSERT INTO `image` (`house_id`,
> `image`) "
> + "VALUES(1, ?)");
> pstmt.setObject(1, new URL(

> "http://www.woonnet-haaglanden.nl/library/fotos/18/12845.jpg")


> .openStream());
> pstmt.executeUpdate();
>
> Statement readstmt = null;
> readstmt =
> con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
> ResultSet.CONCUR_READ_ONLY);
>
> ResultSet resultset = readstmt.executeQuery("SELECT * FROM
> `image` " //
> + "WHERE `house_id` = 1;");
> resultset.first();

This time it's with a ResultSet.TYPE_SCROLL_INSENSITIVE, but you still should
consider using next() instead, and you must check the return code!

> InputStream theimage =
> resultset.getBlob("image").getBinaryStream();
>
> Image image = ImageIO.read(theimage);
>
> // Use a label to display the image
> JFrame frame = new JFrame();
> JLabel label = new JLabel(new ImageIcon(image)); // <=== line
> 69
> frame.getContentPane().add(label, BorderLayout.CENTER);
> frame.pack();
> frame.setVisible(true);
> }
>
> Exception in thread "main" java.lang.NullPointerException
> at javax.swing.ImageIcon.<init>(ImageIcon.java:161)
> at nl.vanleeuwenwilmot.housing.search.woonnet.app.Test.main(Test.java:
> 69)
>
>
> Further more I tried reading the inputstream

That's "InputStream".

> to a string (and playignorant on charset headaches), but I couldn't get that to work...


> (furthermore, it doesn't seem the right way to go).

It isn't, but byte[] would be all right.

The AbstractMethodError only occurs if the implementing class for the abstract
call is not available or incompatible at run time. Something isn't finding
the MySQL-specific implementation of these methods. I'd review how you have
the MySQL JAR located in your classpath.

It's a weird one, because a classpath issue shows up at compile time, or worst
case, at runtime when the Class.forName() fails. How you could get to the
MySQL Driver class and not have access to its implementation classes is a mystery.

There's a clue, however, at the MySQL web site:
<http://dev.mysql.com/doc/refman/5.0/en/connector-j-installing-classpath.html>
where the tell you to put the JAR

mysql-connector-java-[version]-bin.jar

in your classpath, but you've got

mysql-connector-java-5.0.3.jar

I downloaded the latest Connector/J (version 5.0.7) and there was only the
*-bin.jar version, not the version without the "-bin".

--
Lew

David Harper

unread,
Oct 3, 2007, 2:27:27 AM10/3/07
to
pjvle...@gmail.com wrote:
> David
>> Thrown when an application tries to call an abstract method. Normally,
>> this error is caught by the compiler; this error can only occur at run
>
>> version when running it. Check your compile-time and run-time
>> classpaths to ensure that they both reference the newer version of the
>> JAR file.
> Thanks, but I only *have* one version. I guess the MySQL Connection\J
> guys felt that the next "*Normally* this error..." was optional. :)

I suspect that I wasn't thinking clearly last night. Sorry. Here's a
more likely explanation.

Your code never refers directly to the concrete implementation classes
in the Connector/J JAR file (such as com.mysql.jdbc.Driver) but only to
the classes (actually, mostly interfaces, like java.sql.Driver) in
java.sql.* and javax.sql.*

Therefore, your compiler will have no reason to check any of the classes
in the Connector/J JAR file, and the abstract method problem is not
detected at compile time. Remember that java.sql.ResultSet, like
java.sql.Driver, is an interface, not a class.

You only hit the abstract method problem when you actually run your
code, and the Java virtual machine needs to load the concrete classes
such as com.mysql.jdbc.Driver, which implements the java.sql.Driver
interface.

When your program reaches the call to ResultSet.updateBlob at line 52,
the JVM attempts to call the method updateBlob on a concrete
com.mysql.jdbc.UpdatableResultSet object. That method is apparently
abstract, and you get the mysterious AbstractMethodError.

I hope this makes better sense :-)

David Harper
Cambridge, England

pjvle...@gmail.com

unread,
Oct 3, 2007, 8:06:50 AM10/3/07
to
David

> When your program reaches the call to ResultSet.updateBlob at line 52,
> the JVM attempts to call the method updateBlob on a concrete
> com.mysql.jdbc.UpdatableResultSet object. That method is apparently
> abstract, and you get the mysterious AbstractMethodError.
So MySQL Connector/J doesn't implement any code for handling blobs
here. Makes the most sence to me. Forget about the nice blob interface
then.

Lew


> > to a string (and playignorant on charset headaches), but I couldn't get that to work...
> > (furthermore, it doesn't seem the right way to go).
> It isn't, but byte[] would be all right.

You are very right there. I liked the Blob's because they work with
streams, but the following code below works! With byte[].


I'll just wrap it in an URL2Bytes utility class and all is done.
Thanks for all your tips! Ciao

public static void main(String[] args)

throws MalformedURLException,
IOException, SQLException {
// download photo to byte[]
URL fileurl = new URL(
"http://www.woonnet-haaglanden.nl/"
+ "library/fotos/18/12845.jpg");
int length = fileurl.openConnection()
.getContentLength();
byte[] bytebuf = new byte[length];
InputStream is = fileurl.openStream();
byte[] b = new byte[1];
for (int i = 0; is.read(b) > -1; i++) {
bytebuf[i] = b[0];
}

// write to DB


Connection con = null;
try {
Class
.forName(
"com.mysql.jdbc.Driver")
.newInstance();
con = DriverManager.getConnection(
"jdbc:mysql:///woonnet",
"root", "<A2Cc|4w");
} catch (InstantiationException e) {
e.printStackTrace();
System.exit(1);
} catch (IllegalAccessException e) {
e.printStackTrace();
System.exit(1);
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.exit(1);
}

PreparedStatement pstmt = con
.prepareStatement("INSERT INTO `image` "

+ "(`house_id`, `image`) "
+ "VALUES(4, ?)");
pstmt.setBytes(1, bytebuf);
pstmt.executeUpdate();

// read from DB
Statement readstmt = con
.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet resultset = readstmt


.executeQuery("SELECT * FROM `image` " //

+ "WHERE `house_id` = 4;");
resultset.first();
byte[] readbytes = resultset
.getBytes("image");
Image image = ImageIO
.read(new ByteArrayInputStream(
readbytes));

Lew

unread,
Oct 3, 2007, 11:17:48 AM10/3/07
to
pjvle...@gmail.com wrote:
> public static void main(String[] args)
> throws MalformedURLException,
> IOException, SQLException {
...

> // write to DB
> Connection con = null;
> try {
> Class
> .forName(
> "com.mysql.jdbc.Driver")
> .newInstance();

Why are you creating a throwaway instance here?

--
Lew

Lew

unread,
Oct 3, 2007, 11:23:56 AM10/3/07
to
pjvle...@gmail.com wrote:
> PreparedStatement pstmt = con
> .prepareStatement("INSERT INTO `image` "
> + "(`house_id`, `image`) "
> + "VALUES(4, ?)");

Remember, prepareStatement() "[t]hrows ... SQLException ... if a database
access error occurs or this method is called on a closed connection."

> pstmt.executeUpdate();

This method call returns a value that you should not ignore, nor should you
ignore the possible SQLException.

> // read from DB
> Statement readstmt = con
> .createStatement(
> ResultSet.TYPE_SCROLL_INSENSITIVE,
> ResultSet.CONCUR_READ_ONLY);

"Throws ... SQLException ... if a database access error occurs or this method
is called on a closed connection"

> ResultSet resultset = readstmt
> .executeQuery("SELECT * FROM `image` " //
> + "WHERE `house_id` = 4;");

possible SQLException

> resultset.first();

Why not call next(), and why, oh, why do you disregard the returned value?

--
Lew

Arne Vajhøj

unread,
Oct 4, 2007, 9:38:17 PM10/4/07
to

That is a common practice when loading the MySQL JDBC
driver.

My guess is that some very old version of the driver
registered itself with DriverManager in the constructor,
so that it was necessary.

It is not necessary today and has not been for many years,
but you will see that code all the time.

The MySQL docs even use it even though they blame Java:

<quote>
Example 3.1. Registering the Driver With the DriverManager

The following section of Java code shows how you might register MySQL
Connector/J from the main() method of your application.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

// Notice, do not import com.mysql.jdbc.*
// or you will have problems!

public class LoadDriver {
public static void main(String[] args) {
try {
// The newInstance() call is a work around for some
// broken Java implementations

Class.forName("com.mysql.jdbc.Driver").newInstance();
} catch (Exception ex) {
// handle the error
}
</quote>

Arne

0 new messages