检索要在MySql中上传的序列化JFrame

问题描述

我在Jython中有一个扩展Java Swing JFrame的对象。我的目标是对其进行序列化,以便将其保存在MysqL上,查询数据库,对其进行反序列化,并与对其进行反序列化之前的JFrame完全一样(填充所有字段)。 >
老实说,我不知道从哪里开始。我无法想象序列化-保存到数据库。 我猜想序列化的JFrame可能是MysqL上的bloblongblobbit类型。

到目前为止,我已经利用我对Java中对象序列化的一点点学术知识进行了一次本地实验,结果很差:

def saveArt(self,e):
   v = Vector()
   v.add(self) # self = JFrame in question
   out = ObjectOutputStream(bufferedoutputstream(FileOutputStream("prova.dat")))
   out.writeObject(v)
   out.close()

我所做的只是将框架放入Java向量中并将其保存到文件中,但是出现以下错误

Exception in thread "AWT-EventQueue-0"  at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.defaultWriteFields(UnkNown Source)
        at java.io.ObjectOutputStream.writeSerialData(UnkNown Source)
        at java.io.ObjectOutputStream.writeOrdinaryObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject(UnkNown Source)
        at java.util.concurrent.ConcurrentHashMap.writeObject(UnkNown Source)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(UnkNown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(UnkNown Source)
        at java.lang.reflect.Method.invoke(UnkNown Source)
        at java.io.ObjectStreamClass.invokeWriteObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeSerialData(UnkNown Source)
        at java.io.ObjectOutputStream.writeOrdinaryObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.defaultWriteFields(UnkNown Source)
        at java.io.ObjectOutputStream.writeSerialData(UnkNown Source)
        at java.io.ObjectOutputStream.writeOrdinaryObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.defaultWriteFields(UnkNown Source)
        at java.io.ObjectOutputStream.writeSerialData(UnkNown Source)
        at java.io.ObjectOutputStream.writeOrdinaryObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject(UnkNown Source)
        at java.util.concurrent.ConcurrentHashMap.writeObject(UnkNown Source)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(UnkNown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(UnkNown Source)
        at java.lang.reflect.Method.invoke(UnkNown Source)
        at java.io.ObjectStreamClass.invokeWriteObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeSerialData(UnkNown Source)
        at java.io.ObjectOutputStream.writeOrdinaryObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.defaultWriteFields(UnkNown Source)
        at java.io.ObjectOutputStream.writeSerialData(UnkNown Source)
        at java.io.ObjectOutputStream.writeOrdinaryObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.defaultWriteFields(UnkNown Source)
        at java.io.ObjectOutputStream.writeSerialData(UnkNown Source)
        at java.io.ObjectOutputStream.writeOrdinaryObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.defaultWriteFields(UnkNown Source)
        at java.io.ObjectOutputStream.writeSerialData(UnkNown Source)
        at java.io.ObjectOutputStream.writeOrdinaryObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.defaultWriteFields(UnkNown Source)
        at java.io.ObjectOutputStream.writeSerialData(UnkNown Source)
        at java.io.ObjectOutputStream.writeOrdinaryObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject(UnkNown Source)
        at javax.swing.event.EventListenerList.writeObject(UnkNown Source)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(UnkNown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(UnkNown Source)
        at java.lang.reflect.Method.invoke(UnkNown Source)
        at java.io.ObjectStreamClass.invokeWriteObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeSerialData(UnkNown Source)
        at java.io.ObjectOutputStream.writeOrdinaryObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.defaultWriteFields(UnkNown Source)
        at java.io.ObjectOutputStream.defaultWriteObject(UnkNown Source)
        at javax.swing.JComponent.writeObject(UnkNown Source)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(UnkNown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(UnkNown Source)
        at java.lang.reflect.Method.invoke(UnkNown Source)
        at java.io.ObjectStreamClass.invokeWriteObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeSerialData(UnkNown Source)
        at java.io.ObjectOutputStream.writeOrdinaryObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.defaultWriteFields(UnkNown Source)
        at java.io.ObjectOutputStream.writeSerialData(UnkNown Source)
        at java.io.ObjectOutputStream.writeOrdinaryObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject(UnkNown Source)
        at java.awt.AWTEventMulticaster.saveInternal(UnkNown Source)
        at java.awt.AWTEventMulticaster.saveInternal(UnkNown Source)
        at java.awt.AWTEventMulticaster.saveInternal(UnkNown Source)
        at java.awt.AWTEventMulticaster.saveInternal(UnkNown Source)
        at java.awt.AWTEventMulticaster.saveInternal(UnkNown Source)
        at java.awt.AWTEventMulticaster.saveInternal(UnkNown Source)
        at java.awt.AWTEventMulticaster.saveInternal(UnkNown Source)
        at java.awt.AWTEventMulticaster.saveInternal(UnkNown Source)
        at java.awt.AWTEventMulticaster.save(UnkNown Source)
        at java.awt.Component.writeObject(UnkNown Source)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(UnkNown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(UnkNown Source)
        at java.lang.reflect.Method.invoke(UnkNown Source)
        at java.io.ObjectStreamClass.invokeWriteObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeSerialData(UnkNown Source)
        at java.io.ObjectOutputStream.writeOrdinaryObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.writeArray(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.access$300(UnkNown Source)
        at java.io.ObjectOutputStream$PutFieldImpl.writeFields(UnkNown Source)
        at java.io.ObjectOutputStream.writeFields(UnkNown Source)
        at java.util.Vector.writeObject(UnkNown Source)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(UnkNown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(UnkNown Source)
        at java.lang.reflect.Method.invoke(UnkNown Source)
        at java.io.ObjectStreamClass.invokeWriteObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeSerialData(UnkNown Source)
        at java.io.ObjectOutputStream.writeOrdinaryObject(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject0(UnkNown Source)
        at java.io.ObjectOutputStream.writeObject(UnkNown Source)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(UnkNown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(UnkNown Source)
        at java.lang.reflect.Method.invoke(UnkNown Source)
java.io.NotSerializableException: java.io.NotSerializableException: org.python.core.packagecache.SysPackageManager

该实验的重要性不高,因为它当然不是最终目标。只是想弄清楚是否可以在本地序列化它。

最终目标是将其保存在MysqL数据库上并完全按照保存的方式提取

所以我需要了解三件事:

  1. 如何使用Jython序列化JFrame(假设序列化是将打包的JFrame“打包”到数据库的最佳方法,如果有更好的方法,请不要犹豫地说)
  2. 要在MysqL上设置什么样的数据(假设MysqL是执行此操作的理想dbms,如果有更好的技术,请不要犹豫!)并且如果您需要进行特定的查询
  3. 如何对其进行反序列化以使其完全像我离开时一样(假设反序列化是检索JFrame的最佳方法

非常感谢您的救世主(如果有的话)

解决方法

首先,在最佳情况下,Java序列化是一个坏主意。 Java SE的安全编码指南说“ Note: Deserialization of untrusted data is inherently dangerous and should be avoided.”,不幸的是,文本不再是红色的。

在这种情况下,问题甚至更加严重,因为数据将仅位于数据库的blob中,并且Swing不保证版本之间的序列化兼容性(甚至可能是更新吗?)。

这没什么问题:从stracktrace来看,问题对象是SysPackageManager本身内ConcurrentHashMap内某个地方的ConcurrentHashMap,您可能不想保留它。 / p>

将系统属性sun.io.serialization.extendedDebugInfo设置为true(可能会更改)将提供有关如何引用对象的更多信息。

显然JFrame太多了。有更好的数据存储方式。

,

Tom涵盖了错误原因以及进一步调试的可能方法

我将尝试用Java代码解决您详细询问的3件事:

  1. 如何序列化? -在下面回答
  2. 哪个数据类型用于创建mysql列来存储此数据? -如果是mysql,我会说mediumblob,blob可能太小而longblob可能太大。我也使用了longtext,它可以按预期工作,没有任何问题,但是它的答案很长,无法解释为什么blob而不是text字段。也许这个stackoverflow答案会带来更多启示-What column type should be used to store serialized data in a mysql db?
  3. 如何反序列化和使用? -在下面回答

回答: 您可以通过几个步骤来实现
  1. 创建JFrame

  2. 将Java对象序列化到mysql数据库-这很简单

    preparedStatement.setObject(jframe_object_to_save_to_database);
    pstmt.executeUpdate();
    
  3. 从mysql数据库中反序列化Java对象并将其转换为JFrame对象-这不是那么简单,但是也没有那么复杂,我的方法将是以下4个步骤

    3.a。只需将您的列值读取为字节数组
    3.b.创建从数据库
    获得的bytes数组的ByteArrayInputStream对象 3.c.从ByteArrayInputStream创建ObjectInputStream
    3.d.使用ObjectInputStream.readObject()方法获取反序列化的对象

    下面的代码段涵盖了这些步骤

        byte[] buf = rs.getBytes(1);
        ObjectInputStream objectIn = null;
        if (buf != null)
            objectIn = new ObjectInputStream(new ByteArrayInputStream(buf));
    
        Object deSerializedObject = objectIn.readObject();
    
  4. 现在,由于已经准备好使用反序列化的对象(来自3.d),因此您可以轻松地将其解析为JFrame对象,并根据需要使用它

Jframe deSerializedObject = (JFrame) objectIn.readObject();

以下是我拥有的完整Java实现,它是一个带有mysql数据库的简单JFrame工作代码,请按照步骤1到步骤5(我在代码中以注释的形式编写)进行操作,并阅读我在deSerializeJavaObjectFromDB方法中提到的注释

import java.awt.FlowLayout;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class SerializeToDatabase {

    private static final String SQL_CREATE_TABLE = "create table if not exists serialized_java_objects (object_name varchar(1000),serialized_object blob)";
    private static final String SQL_SERIALIZE_OBJECT = "INSERT INTO serialized_java_objects(object_name,serialized_object) VALUES (?,?)";
    private static final String SQL_DESERIALIZE_OBJECT = "SELECT serialized_object FROM serialized_java_objects limit 1";

    public static void createTable(Connection connection) throws SQLException {
        connection.createStatement().executeUpdate(SQL_CREATE_TABLE);
    }
    
    public static void serializeJavaObjectToDB(Connection connection,Object objectToSerialize) throws SQLException {

        PreparedStatement pstmt = connection
                .prepareStatement(SQL_SERIALIZE_OBJECT);

        // just setting the class name
        pstmt.setString(1,objectToSerialize.getClass().getName());
        pstmt.setObject(2,objectToSerialize);
        pstmt.executeUpdate();
        pstmt.close();
        
        System.out.println("Java object serialized to database. Object: " + objectToSerialize);

    }

    /**
     * To de-serialize a java object from database
     *
     * @throws SQLException
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static Object deSerializeJavaObjectFromDB(Connection connection) throws SQLException,IOException,ClassNotFoundException {
        PreparedStatement pstmt = connection.prepareStatement(SQL_DESERIALIZE_OBJECT);
        ResultSet rs = pstmt.executeQuery();
        rs.next();

        //NOTE - below is the most basic way of retrieving data from result set,works perfect for general data 
        //Object object = rs.getObject(1);

        //NOTE - below is the way how we need to implement to retrieve serialized objects from resultset
        byte[] buf = rs.getBytes(1);
        ObjectInputStream objectIn = null;
        if (buf != null)
            objectIn = new ObjectInputStream(new ByteArrayInputStream(buf));

        Object deSerializedObject = objectIn.readObject();

        rs.close();
        pstmt.close();

        System.out.println("Java object de-serialized from database. Object: "
                + deSerializedObject + " Classname: "
                + deSerializedObject.getClass().getName());
        
        return deSerializedObject;
    }

    public static Connection getMySqlConnection(String ipAddr,String portNumber,String db,String userName,String password) throws SQLException {
        
        Connection mysqlConn = null;
        
        Properties properties = new Properties();
        properties.put("user",userName);
        properties.put("password",password);
        
        mysqlConn = DriverManager.getConnection("jdbc:mysql://"+ipAddr+":"+portNumber+"/"+db,properties);
        return mysqlConn;
    }
    
    /**
     * Serialization and de-serialization of java object from mysql
     *
     * @throws ClassNotFoundException
     * @throws SQLException
     * @throws IOException
     */
    public static void main(String args[]) throws ClassNotFoundException,SQLException,IOException {
    
        //step 1 - create mysql connection
        Connection connection = getMySqlConnection("192.168.1.119","3306","xxx","xxx");

        //step 2 - create JFrame
        JFrame frame = new JFrame("JFrame Example");  
        JPanel panel = new JPanel();  
        panel.setLayout(new FlowLayout());  
        JLabel label = new JLabel("JFrame By Example");  
        JButton button = new JButton();  
        button.setText("Button");  
        panel.add(label);  
        panel.add(button);  
        frame.add(panel);  
        frame.setSize(200,300);  
        frame.setLocationRelativeTo(null);  
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //uncomment below line if you want to see the JFrame before persisting data
        //frame.setVisible(true);

        //step 3 - create table
        createTable(connection);
        
        //step 4 - serializing java object to mysql database
        serializeJavaObjectToDB(connection,frame);

        //step 5 - de-serializing java object from mysql database and converting it into JFrame object
        JFrame objFromDatabase = (JFrame) deSerializeJavaObjectFromDB(connection);
        //setVisible(true) will show the JFrame as is,what ever we have persisted
        objFromDatabase.setVisible(true);
        
        //finally close the connection
        connection.close();
    }
}

注意1:我没有jython设置,因此我无法在此处提供python / jython代码段。但是我想用纯Java来回答这个问题,我想您可以轻松地将它与jython中的需求相关联(因为我使用的类没有变化)

注2:我不想争论序列化的持久性是对还是错,这取决于应用程序类型,用户类型,项目类型以及许多其他情况。您最好对您的情况进行判断

Note3:这篇文章帮助我更好地回答了这个问题-https://javapapers.com/core-java/serialize-de-serialize-java-object-from-database/