Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / Databases / October 2007

Tip: Looking for answers? Try searching our database.

com.mysql.jdbc.UpdatableResultSet.updateBlob gives AbstractMethodError

Thread view: 
pjvleeuwen@gmail.com - 02 Oct 2007 16:25 GMT
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 - 02 Oct 2007 17:54 GMT
> Googling for UpdatableResultset updateBlob AbstractMethodError gets me
> lost. Any help is well appreciated.

> ### stderr output ###
> Exception in thread "main" java.lang.AbstractMethodError:
[quoted text clipped - 3 lines]
> 52)
> ######

What version of the MySQL JDBC driver are you using ?

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

Arne
Dyreatnews@sun.com - 02 Oct 2007 18:00 GMT
> Hi all,
>
[quoted text clipped - 11 lines]
> 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...?

Signature

dt

pjvleeuwen@gmail.com - 02 Oct 2007 19:29 GMT
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...)
Lew - 02 Oct 2007 22:05 GMT
> 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`,
[quoted text clipped - 10 lines]
>     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.
[quoted text clipped - 5 lines]
>         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`,
[quoted text clipped - 14 lines]
>                 + "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();
[quoted text clipped - 16 lines]
>
> 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".

Signature

Lew

David Harper - 02 Oct 2007 20:23 GMT
[SNIP]
> ### stderr output ###
> Exception in thread "main" java.lang.AbstractMethodError:
[quoted text clipped - 3 lines]
> 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
pjvleeuwen@gmail.com - 02 Oct 2007 20:41 GMT
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
David Harper - 03 Oct 2007 07:27 GMT
> David
>>    Thrown when an application tries to call an abstract method. Normally,
[quoted text clipped - 5 lines]
> 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
pjvleeuwen@gmail.com - 03 Oct 2007 13:06 GMT
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));

       // 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);
   }
Lew - 03 Oct 2007 16:17 GMT
>     public static void main(String[] args)
>             throws MalformedURLException,
>             IOException, SQLException {
 ...
>         // write to DB
>         Connection con = null;
[quoted text clipped - 3 lines]
>                             "com.mysql.jdbc.Driver")
>                     .newInstance();

Why are you creating a throwaway instance here?

Signature

Lew

Arne Vajhøj - 05 Oct 2007 02:37 GMT
>>     public static void main(String[] args)
>>             throws MalformedURLException,
[quoted text clipped - 9 lines]
>
> Why are you creating a throwaway instance here?

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
Lew - 03 Oct 2007 16:23 GMT
>         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?

Signature

Lew



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.