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).
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.
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("prova.dat")))
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 "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
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.
The final goal is to save it on the MySql database and extract it exactly as it was saved.
So I need to understand 3 things:
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)
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
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)
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.
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:
How to serialize ? - Answered below
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 - What column type should be used to store serialized data in a mysql db?
How to de-serialize and use ? - Answered below
Moving to answer:
You can achieve this in few steps
create JFrame
serializing java object to mysql database - this is as simple as
preparedStatement.setObject(jframe_object_to_save_to_database);
pstmt.executeUpdate();
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
3.b. create a ByteArrayInputStream object of the bytes array we got from database
3.c. create ObjectInputStream from ByteArrayInputStream
3.d. use ObjectInputStream.readObject() method to get de-serialized object
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();
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();
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
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", "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();
}
}
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/
Related
First of all, please do not mark this question as duplicate & close it without going through the whole problem. I have searched for problems similar to mine, but couldn't find any. So I request that you kindly direct me to the post that has a similar problem & then close it.
Now the problem.
I have created a popup window in a JavaFX application. I have two buttons on the main window/stage, pressing either of which generates a new window/stage. However when I close the newly generated popup window and press those buttons on the original window again, it results in JavaFX application thread exception.
Here is the code for the buttons & the action associated with them & it is in the MAIN WINDOW:
public class FirstScene
{
//.....usual code.....//
//Creating the buttons
Button leftClick = new Button("",lftIcon);
Button rightClick = new Button("", rghtIcon);
//Adding ACTION to the buttons
add.setOnAction(ae->LoginFunc.loginHandler("add"));
remove.setOnAction(ae ->LoginFunc.loginHandler("remove"));
Here's the code for LoginFunc that handles the event & it is in the popup window
public class LoginFunc
{
private static String userID, password, button;
private static Stage loginStage = new Stage();
static Button login = new Button("Login");
Scene addScene, removeScene;
public static void loginHandler(String bttn)
{
button = bttn;
loginStage.setTitle("Movie Database Login");
loginStage.setMaxHeight(400);
loginStage.setMaxWidth(400);
GridPane loginLayout = new GridPane();
loginLayout.getChildren().add(login);
Scene loginScene = new Scene(loginLayout,400,400);
login.setOnAction(eh -> ButtonClicked(eh));
loginStage.setScene(loginScene);
loginStage.initStyle(StageStyle.UTILITY);
loginStage.initModality(Modality.APPLICATION_MODAL);
loginStage.show();
}
private static void ButtonClicked (ActionEvent eh)
{
if(button == "add")
{
FirstScene.mainStage.setTitle("Add Window");
loginStage.close();
}
if(button == "remove")
{
FirstScene.mainStage.setTitle("Remove Window");
loginStage.close();
}
}
}
THE PROBLEM IS, once I close the newly generated popup window & press any of the buttons again, it results in the following exception:
Exception in thread "JavaFX Application Thread" java.lang.IllegalStateException: Cannot set style once stage has been set visible
at javafx.stage.Stage.initStyle(Unknown Source)
at MovieDataBase.LoginFunc.loginHandler(LoginFunc.java:34)
at MovieDataBase.FirstScene.lambda$0(FirstScene.java:101)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.Node.fireEvent(Unknown Source)
at javafx.scene.control.Button.fire(Unknown Source)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(Unknown Source)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(Unknown Source)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.Scene$MouseHandler.process(Unknown Source)
at javafx.scene.Scene$MouseHandler.access$1500(Unknown Source)
at javafx.scene.Scene.impl_processMouseEvent(Unknown Source)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.notifyMouse(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(Unknown Source)
at java.lang.Thread.run(Unknown Source)
I want to be able to repeat the same window every time the button is pressed.
I'm sorry if this is a very simple problem & a solution already exists, I'm a beginner in Java & what my search resulted in, I couldn't find a single problem that related to mine.
Thank you for your valuable time & input
Your method call to LoginFunc is static and it uses static members of the class. That means that they are initialized and setup when you run through the method for the first time. The second time you call the method, they are already initialized. There are some methods (initStyle is one of them) that can only be called once in the lifecycle of the object.
However there is an easy solution to that: Remove the static modifiers from LoginFunc and create an instance in the event handler before you call the method loginHandler, however retain a reference to it, so you can pass it on the remove method.
Or even better separate the logic for adding and removing out of LoginFunc as it is not good decision to trigger behavior upon an input parameter.
You can have a factory method that will provide the event handlers for add and remove and use a boolean to decide which event handler the factory method should return.
public EventHandler<MouseEvent> createButtonClickEventHandler(boolean add) {
...
}
Then you can implement the buttons like this:
EventHandler<MouseEvent> addEventHandler = creatButtonClickEventHandler(true);
add.setOnAction(ae->new LoginFunc().loginHandler(addEventHandler));
EventHandler<MouseEvent> removeEventHandler = creatButtonClickEventHandler(false);
remove.setOnAction(ae->new LoginFunc().loginHandler(removeEventHandler));
In my PhoneBook applcation after sorting by a column , when i remove a row and cal updateUI() i got a java.lang.IndexOutOfBoundsException in my model . But if not sorting there is no exeption
I guess the object has removed but in updateUI procedure it doesnt know that and somewhere return old getRowCount() ,according to stacktrace.
private void delete(int[] selectedIndexes) {
ArrayList<Contact> arlDeleting = new ArrayList<Contact>();
for (int i = selectedIndexes.length - 1; i >= 0; i--) {
int realIndex = tblPhonebook.convertRowIndexToModel(selectedIndexes[i]);
tblMdlAllContacts.getData().remove(realIndex);
}
tblPhonebook.updateUI();
}
here is stacktrace:
Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 6, Size: 6
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at com.TableModelPhoneBook.getValueAt(TableModelPhoneBook.java:73) ***
at javax.swing.JTable.getValueAt(Unknown Source)
at javax.swing.JTable.prepareRenderer(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paintCell(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paintCells(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paint(Unknown Source) *** i think getRowCount called here
at javax.swing.plaf.ComponentUI.update(Unknown Source)
at javax.swing.JComponent.paintComponent(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JViewport.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent._paintImmediately(Unknown Source)
at javax.swing.JComponent.paintImmediately(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.access$700(Unknown Source)
at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$000(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
and model.getvalueat:
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Contact temp = data.get(rowIndex); // here is where error occurs
switch (columnIndex) {
case 0:
return temp.getFirstName();
case 1:
return temp.getLastName();
case 2:
return temp.getMobile();
case 3:
return temp.getHome();
case 4:
return temp.getAddress();
default:
break;
}
return null;
}
Don't call updateUI() as this should only be called when L&F is changed. Your delete row method is part of your model right? Are you firing the model's fireXXX() notification methods after deleting? You should be. Also, I wonder if you should be using an iterator to do your deleting.
Edit
You state:
No delet method is part of my controller (is it wrong?).
Wrong. The method should be part of your table model, and controller can call this method on the model, but shouldn't have this method. The table model should extend AbstractTableModel and should call the proper fireXXX method when data is removed, added, or changed. For delete, call fireTableRowsDeleted method, and definitely check the AbstractTableModel API for the details on all such available notification methods.
I removed 'updateUI()' line ,its ok until i click on a cell of table ,when i do this he exeption thrwon . means that actually 'firexxx()' cuase it ,right?
No. I have no idea what your code is doing or the cause of your exceptions right now. Consider creating and posting an sscce.
Oh youre right . but Why when i call 'table.getModel()' i dont see fireXXX()'but by with a refernce to model instance it will be seen. 'mymodel.fireTableDataChanged()'
Outside classes should not call the fire methods. The model itself should be the only object calling its own notification methods.
If you haven't gone through the JTable tutorial, I suggest that you consider doing this without delay. It will help you a great deal.
I've written a JApplet that that connects to a server. On connecting it receives an ImageIcon. On receipt it send a String "I" to the server to confirm. This signals the server to send the next imageIcon.
while(noExceptions){
try{
Object something = in.readObject();
if(something instanceof ImageIcon){
camDisplay.setIcon( (ImageIcon)something );
validate();
sendMessage("I");
}else{
System.out.println("What the hell was that?!");
}
Runtime rt = Runtime.getRuntime();
rt.gc();
}catch(Exception e){
noExceptions=false;
...
}
}
I added the call to the garbage collector when I first got the exception but it didn't help. I put in some printlns and it always crashes on the 128th image. Exception is thrown at Object something = in.readObject();
camDisplay is a JLabel that is shown in the applet.
Exception in thread "Thread-12" java.lang.OutOfMemoryError: Java heap space
at java.lang.reflect.Array.newArray(Native Method)
at java.lang.reflect.Array.newInstance(Unknown Source)
at java.io.ObjectInputStream.readArray(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at javax.swing.ImageIcon.readObject(Unknown Source)
at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at RoboClient.run(RoboClient.java:226)
at java.lang.Thread.run(Unknown Source)
FIX:
System.out.println((sendImageCount++)+" send image");
out.writeUnshared( new ImageIcon(_image) );
out.flush();
if(sendImageCount>100){
out.reset();
sendImageCount=0;
}
See ObjectOutputStream.reset() and ObjectOutputStream.writeUnshared().
One crude way to address this problem is to flush the inputstream after retrieving every x(say 50 in this case) ImageIcons and close the inputStream and reOpen to get the remaining ImageIcons. Now the GC will be able to garbage the earlier retrived imageicons.
Looks like the Inputstream holds the references of the ImageIcons which is preventing from Gced.
I have created a jar file which throws the below error, it's a simple swing app which inserts a row when I press a button, not sure where I am going wrong please advise.
private void jButton20ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
setatmid(jTextField2.getText());
setaa10(Integer.parseInt(jTextField3.getText()));
setaa20(Integer.parseInt(jTextField4.getText()));
setaa50(Integer.parseInt(jTextField5.getText()));
setaa100(Integer.parseInt(jTextField6.getText()));
try{
System.err.println("Inserting values in Mysql database table!");
Connection con = null;
String url = "jdbc:mysql://localhost:3306/";
String db = "agents";
String driver = "com.mysql.jdbc.Driver";
Class.forName(driver);
con = DriverManager.getConnection(url+db,"root","");
Statement st = con.createStatement();
String query="INSERT INTO schedule_data (`s_ID`, `schedule_date`, `atmID`, `notification`) VALUES ('"+System.currentTimeMillis()+"','2010-09-15','"+getatmid()+"','null')";
st.executeUpdate(query);
System.err.println("1 row affected");
} catch(Exception e) {
e.printStackTrace();
}
}
Error:
java.lang.IllegalStateException: zip file closed
at java.util.zip.ZipFile.ensureOpen(Unknown Source)
at java.util.zip.ZipFile.getEntry(Unknown Source)
at java.util.jar.JarFile.getEntry(Unknown Source)
at java.util.jar.JarFile.getJarEntry(Unknown Source)
at sun.misc.URLClassPath$JarLoader.getResource(Unknown Source)
at sun.misc.URLClassPath.getResource(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at atmguis.atm.jButton20ActionPerformed(atm.java:588)
at atmguis.atm.access$1600(atm.java:25)
at atmguis.atm$17.actionPerformed(atm.java:226)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
The method involved is being called from the Event Dispatch Thread. I'm sure this is a part of the problem. You are trying to access the JAR file containing the com.mysql.jdbc.Driver class from this thread. This is where the error is being thrown. I have to wonder if there is some sort of concurrency issue here. Here are a couple of general notes, things that should be addressed. Once you have addressed these issues, see if you are still having a problem.
You should not be doing a database query from inside the EDT. You should collect the information you need from the swing components and then use a Runnable object to execute the SQL query on a different thread. Do a search on SO for executing code on or off the EDT to find examples of how to do this. This will ensure that your UI doesn't lock up while you wait for your SQL results.
Opening and closing a database connection every time you need one is something better left to the SQL driver and its built-in connection pooling abilities. This method should be declared on some sort of controller object which already has a reference to the SQL connection. Then, when this method is called, you call your thread as in the last step, and that thread uses the reference to the SQL connection that it already has.
This will take the line that's throwing the exception and move it out of the EDT into some sort of setup phase, presumably where you will have better luck accessing the class file. Certainly it will be a much more controlled environment than within the EDT. If there continues to be a problem accessing it, it will be easier to debug in the more controlled environment.
As an added bonus, you will also be designing your application in much more robust way.
I've tried using the standard serializing type things, stuff like:
FileOutputStream f_out;
try {
f_out = new FileOutputStream("MAOS.data");
ObjectOutputStream obj_out = new ObjectOutputStream (f_out);
obj_out.writeObject(s);
obj_out.flush();
obj_out.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} ;
But the problem seems to be that if my object s contains any recursion at ALL I get a stack overflow. If s is a graph that contains nodes and edges (with nodes knowing about edges for purposes of spreading activation, and edges knowing about nodes for the same reason) then it stack overflows. If I take edges out entirely, and just have nodes that know about which nodes they're supposed to spread activation too, the same thing happens! I can even just try to save the ArrayList of nodes that the graph knows about, and the stack overflows again!
I'm so frustrated!
Graphs aren't exactly strange and mysterious, surely SOMEONE has wanted to save one before me. I'm seeing something about saving them as XML files here...but if my problem is the recursiveness, wouldn't I still be having the same problems even if I saved it differently? I just can't think of how you could make a graph without there being connections!
Am I just doing things wrong, or is this object serialization less powerful than I thought? Or do I need to just abandon the idea of saving a graph?
-Jenny
Edit, part of the HUGE stack trace:
Exception in thread "main" java.lang.StackOverflowError
at java.io.ObjectStreamClass.getPrimFieldValues(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.ArrayList.writeObject(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.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.util.ArrayList.writeObject(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.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.util.ArrayList.writeObject(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.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.util.ArrayList.writeObject(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.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)
These sort of structures are best saved like this:
collection of nodes, each node has a unique ID
collection of edges, each edge has two node IDs (or however many nodes an edge connects to)
without using any recursion. On reading the nodes, create a dictionary of nodes indexed by their ID. Then use the dictionary to fix up the edges when they're read. The IDs do not need to be part of the objects' run time structure, they only need to be unique within the data stream when the stream is written/read.
You could use the JGraphT library which supports serializing graphs into a text file with the ML format. GraphMLExporter Javadoc.
Java serialisation can cope with arbitrary graphs (although not necessarily very efficiently). Probably the problem lies with a custom implementation of writeObject. Perhaps a section of stack trace might help.
A useful serialization format you should consider is JSON, where dictionaries (as suggested by #Skizz) are easily represented:
A JSONObject is an unordered collection of name/value pairs. Its external form is a string wrapped in curly braces with colons between the names and values, and commas between the values and names. The internal form is an object having get() and opt() methods for accessing the values by name, and put() methods for adding or replacing values by name. The values can be any of these types: Boolean, JSONArray, JSONObject, Number, and String, or the JSONObject.NULL object.
Java serialization is capable of handling cyclic references (I assume this is what you mean by recursion), but there is a known problem with large graphs that is described here.
Don't let the date of the article throw you off, just follow chain of comments after it.
It seems you will have to use another serialization technique to accomplish this. Several have been mentioned, and some performance metrics give JSON high marks.
Hmmm. One solution would be to make it into a java bean and use XMLEncoder/XMLDecoder. This is a solution I've used in the past to save and load classes.