获取序列化的JFrame以上传到MySQL。

huangapple go评论110阅读模式
英文:

Retrive serialized JFrame to upload in MySql

问题

I'll provide a brief translation of the key points from your text:

  1. 如何使用Jython序列化JFrame(假设序列化是将填充的JFrame“打包”到数据库的最佳方式,如果有更好的方法,请告诉我)
  2. 在Mysql上设置什么类型的数据(假设Mysql是执行此操作的完美DBMS,如果有更好的技术,请告诉我!)以及是否需要进行特殊查询
  3. 如何反序列化以查看它与离开时完全相同(假设反序列化是检索JFrame的最佳方式)

请注意,Jython和Java之间的对象序列化通常是可能的,但涉及到复杂的Swing组件可能会更加复杂。解决此问题可能需要自定义序列化和反序列化过程。

如有需要,请继续提出您的具体问题或要求。

英文:

I have an object in Jython that extends a Java Swing JFrame. My goal is to serialize it in order to save it on MySql, query the database, deserialize it and review the JFrame exactly as it was before it was deserialized (with all fields filled in).<br><br>
I honestly don't know where to start. I can't imagine serialization - saving to database.
I guess the serialized JFrame could be blob, longblob or bit type on MySql. <br><br>
For now I have done a local experiment using my old and little academic knowledge on the serialization of objects in java, with poor results:

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

What I did was just put the frame in a Java vector and save it to the file, however I got the following error:

Exception in thread &quot;AWT-EventQueue-0&quot;  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

This experiment is of little importance, because it is certainly not the final goal. It was just to figure out if I could serialize it locally.<br><br>
The final goal is to save it on the MySql database and extract it exactly as it was saved. <br><br>
So I need to understand 3 things:

  1. how to serialize JFrame with Jython (assuming serialization is the best way to "package" a filled JFrame for a database, if there's a better way don't hesitate to say so)
  2. what kind of data to set on Mysql (assuming MySql is the perfect dbms to do this, if there are better technologies, don't hesitate to say it!) and if you need to make a particular query
  3. how to deserialize it to see it exactly as I left it (assuming deserialization is the best way to retrieve the JFrame)

Thank you so much in advance my saviors (if there are any)

答案1

得分: 3

Sure, here's the translated content:

首先,无论何时,Java序列化都不是一个好主意。Java SE的安全编码准则表示:“注意:对不受信任的数据进行反序列化本质上是危险的,应避免使用。” 不幸的是,该文本不再是红色的。

在这种情况下,问题更加复杂,因为该数据将只是数据库中的一个二进制大对象(blob),而Swing不能保证在不同版本(甚至更新?)之间的串行化兼容性。

既然问题已经解决:从堆栈跟踪中可以看出,问题对象是一个SysPackageManager,位于ConcurrentHashMap本身内部,而你可能不希望保留它。

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

显然JFrame有点过于复杂了。有更好的方法来存储数据。

英文:

Firstly, Java Serialization is a bad idea at the best of times. The Secure Coding Guidelines for Java SE says "Note: Deserialization of untrusted data is inherently dangerous and should be avoided." Unfortunately that text is no longer in red.

It is even more problematic in this case as that data will just be in a blob in the database, and Swing doesn't guarantee serialisation compatibility between versions (perhaps even updates?).

That out of the way: From the stracktrace, the problem object is a SysPackageManager somewhere within ConcurrentHashMap itself within ConcurrentHashMap itself, which you probably don't want to keep.

Setting the system property sun.io.serialization.extendedDebugInfo (may change) to true will give some more information as to how the object is referenced.

Clearly JFrame is too much. There are better ways to store data.

答案2

得分: 0

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

我将尝试详细回答您提出的3个问题,使用Java代码:

  1. 如何序列化? - 下面已经回答了
  2. 用哪种数据类型来创建MySQL列以存储这些数据? - 对于MySQL,我建议使用mediumblob,blob可能太小,longblob可能太大。我也使用了longtext,它可以正常工作而没有任何问题,但要解释为什么选择blob而不是文本字段会有一个非常长的答案。也许这个StackOverflow答案会更清晰:https://stackoverflow.com/questions/5544749/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();
  1. 从MySQL数据库反序列化Java对象并将其转换为JFrame对象 - 这并不是那么直接,但也不是那么复杂,我的方法将分为4个步骤,如下所示:

    3.a. 仅将列值读取为字节数组
    3.b. 创建一个字节数组的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();
  1. 现在,我们已经准备好了反序列化的对象供我们使用(来自3.d),您可以轻松将其解析为JFrame对象并按需要使用它
Jframe deSerializedObject = (JFrame) objectIn.readObject();

以下是我完整的Java实现代码,这是一个与MySQL数据库一起使用的简单JFrame工作代码。请按照我在代码中作为注释写的步骤1到步骤5进行操作,还请阅读我在deSerializeJavaObjectFromDB方法中提到的注意事项。

// 代码太长,请查看原文

注意1:我没有设置Jython,所以无法提供Python/Jython代码片段。但我正在尝试用纯Java来回答这个问题,我认为您可以很容易地将其与您在Jython中的需求联系起来(因为我使用的类不会变化)。

注意2:我不想辩论序列化的持久性是对还是错,这取决于应用程序的类型、用户类型、项目类型和许多其他情况。您是对您的情况有更好的判断力。

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

希望这有助于您!如果您有其他问题或需要进一步的帮助,请随时告诉我。
1: https://stackoverflow.com/questions/5544749/what-column-type-should-be-used-to-store-serialized-data-in-a-mysql-db
2: https://javapapers.com/core-java/serialize-de-serialize-java-object-from-database/

英文:

Tom has covered reasons of error and possible ways to debug further

I will try to address the 3 things you asked in detail with java code:

  1. How to serialize ? - Answered below
  2. Which datatype to use to create mysql column to store this data ? - I would say mediumblob in case of mysql, blob might to too small and longblob might be too big. I used longtext as well and it works as expected without any issues, but its really long answer to explain why blob and not text fields. May be this stackoverflow answer will throw more light - https://stackoverflow.com/questions/5544749/what-column-type-should-be-used-to-store-serialized-data-in-a-mysql-db
  3. How to de-serialize and use ? - Answered below

<br>
Moving to answer:
You can achieve this in few steps

  1. create JFrame

  2. serializing java object to mysql database - this is as simple as

    preparedStatement.setObject(jframe_object_to_save_to_database);
    pstmt.executeUpdate();
    
  3. de-serializing java object from mysql database and converting it into JFrame object - this is not that straight forward, but not that complicate too, my approch will be of 4 steps like below

    3.a. Just read your column value as bytes array <br>
    3.b. create a ByteArrayInputStream object of the bytes array we got from database <br>
    3.c. create ObjectInputStream from ByteArrayInputStream <br>
    3.d. use ObjectInputStream.readObject() method to get de-serialized object <br>

    These steps are covered in the below code snippet

        byte[] buf = rs.getBytes(1);
    	ObjectInputStream objectIn = null;
    	if (buf != null)
    		objectIn = new ObjectInputStream(new ByteArrayInputStream(buf));
    
    	Object deSerializedObject = objectIn.readObject();
    
  4. Now as we have the de-serialized object ready for our use (from 3.d), you can parse it into a JFrame object easily and use it as you need

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

<br>
Below is the complete java implementation that I have, it is a simple JFrame working code with mysql database, please follow Step 1 thru Step 5 which I wrote as comments in the code and also read the Note that I mentioned in deSerializeJavaObjectFromDB method
<br>
<br>

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 = &quot;create table if not exists serialized_java_objects (object_name varchar(1000), serialized_object blob)&quot;;
	private static final String SQL_SERIALIZE_OBJECT = &quot;INSERT INTO serialized_java_objects(object_name, serialized_object) VALUES (?, ?)&quot;;
	private static final String SQL_DESERIALIZE_OBJECT = &quot;SELECT serialized_object FROM serialized_java_objects limit 1&quot;;

	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(&quot;Java object serialized to database. Object: &quot; + 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(&quot;Java object de-serialized from database. Object: &quot;
				+ deSerializedObject + &quot; Classname: &quot;
				+ 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(&quot;user&quot;, userName);
		properties.put(&quot;password&quot;, password);
		
		mysqlConn = DriverManager.getConnection(&quot;jdbc:mysql://&quot;+ipAddr+&quot;:&quot;+portNumber+&quot;/&quot;+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(&quot;192.168.1.119&quot;, &quot;3306&quot;, &quot;xxx&quot;, &quot;xxx&quot;, &quot;xxx&quot;);

		//step 2 - create JFrame
		JFrame frame = new JFrame(&quot;JFrame Example&quot;);  
        JPanel panel = new JPanel();  
        panel.setLayout(new FlowLayout());  
        JLabel label = new JLabel(&quot;JFrame By Example&quot;);  
        JButton button = new JButton();  
        button.setText(&quot;Button&quot;);  
        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();
	}
}

Note1: I have no jython setup, so I am unable to provide python/jython code snippet here. But I am trying to answer this in pure java, I think you can relate it easily to your need in jython (as the classes that I've used do not vary)

Note2: I did not want to debate if persistence of serialization is right or wrong, that depends on type of application, type of users, type of project and many other scenarios. You are better judge for your case

Note3: This post helped me to answer this question better - https://javapapers.com/core-java/serialize-de-serialize-java-object-from-database/

huangapple
  • 本文由 发表于 2020年8月12日 18:34:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/63374708.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定