What I\'m trying to do is to send a JFrame through sockets. The problem is after I send the form and press the button to view it I get the below exception.
What I'm trying to do is to send a JFrame through sockets
Why? From the Javadoc for JFrame:
Warning: Serialized objects of this class will not be compatible with future Swing releases. The current serialization support is appropriate for short term storage or RMI between applications running the same version of Swing. As of 1.4, support for long term storage of all JavaBeansTM has been added to the java.beans package. Please see XMLEncoder.
Don't just ignore these warnings. They are there for a reason.
I did it something similar years ago and I ended up sending a JPanel
instead that a frame itself.
I think that the problem in this situation is the fact that the frame is somewhat attached to a Graphics
which is not, of course, serialized and sent over network becuse it's really near to the host OS in the implementation (at AWT Window
level)
I suggest you to try sending just a panel (which in the end is just the content pane of the frame that you are trying to send) a try again. If you really need to attach frame properties you could encapsulate them in a custom object and attach them by serialization (eg title or whatever).
JPanel
implementation
Following @Jack advices sending a JPanel
instead of a JFrame
seems to work.
Below is the implementation.
package ds3;
import java.awt.Container;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class SerializationApp extends JFrame {
private DataPanel dataPanel = new DataPanel();
private JFrame frPanel = new JFrame();
private int serverPort = 15000;
private ServerSocket serverSocket;
public SerializationApp() {
try {
serverSocket = new ServerSocket(serverPort);
initComponents();
setLocationRelativeTo(null);
frPanel.add(dataPanel);
frPanel.pack();
frPanel.setLocationRelativeTo(this);
frPanel.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Socket socket = serverSocket.accept();
ObjectInputStream objectinputstream = new ObjectInputStream(socket.getInputStream());
JPanel container = (JPanel) objectinputstream.readObject();
JFrame frame = new JFrame(socket.getInetAddress().getHostAddress());
frame.add(container);
frame.pack();
frame.setLocationRelativeTo(null);
setVibility(frame);
socket.close();
} catch (ClassNotFoundException ex) {
Logger.getLogger(SerializationApp.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(SerializationApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}).start();
} catch (IOException ex) {
Logger.getLogger(SerializationApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jPanel1 = new javax.swing.JPanel();
iptextfield = new javax.swing.JTextField();
jPanel2 = new javax.swing.JPanel();
viewButton = new javax.swing.JButton();
sendButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Receiver IP Address", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Dialog", 0, 12), new java.awt.Color(0, 0, 204))); // NOI18N
jPanel1.setLayout(new java.awt.BorderLayout());
jPanel1.add(iptextfield, java.awt.BorderLayout.CENTER);
getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER);
viewButton.setText("View Form");
viewButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
viewButtonActionPerformed(evt);
}
});
jPanel2.add(viewButton);
sendButton.setText("Send Form");
sendButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
sendButtonActionPerformed(evt);
}
});
jPanel2.add(sendButton);
getContentPane().add(jPanel2, java.awt.BorderLayout.SOUTH);
pack();
}// </editor-fold>
private void setVibility(final JFrame dataform) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
dataform.setVisible(!dataform.isVisible());
}
});
}
private void viewButtonActionPerformed(java.awt.event.ActionEvent evt) {
setVibility(frPanel);
}
private void sendButtonActionPerformed(java.awt.event.ActionEvent evt) {
try {
Socket clientsocket = new Socket(iptextfield.getText(), 15000);
ObjectOutputStream oout = new ObjectOutputStream(clientsocket.getOutputStream());
oout.writeObject(dataPanel);
oout.reset();
oout.flush();
clientsocket.close();
} catch (UnknownHostException ex) {
Logger.getLogger(SerializationApp.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(SerializationApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String args[]) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ignored) {
ignored.printStackTrace();
}
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new SerializationApp().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JTextField iptextfield;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JButton sendButton;
private javax.swing.JButton viewButton;
// End of variables declaration
}
The JPanel
On the received JPanel
only the second one ActionListener
works.
package ds3;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Serializable;
public class DataPanel extends javax.swing.JPanel implements Serializable,ActionListener {
public DataPanel() {
initComponents();
jButton1.addActionListener(this);
}
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
jLabel3 = new javax.swing.JLabel();
jLabel4 = new javax.swing.JLabel();
jTextField1 = new javax.swing.JTextField();
jTextField2 = new javax.swing.JTextField();
jTextField3 = new javax.swing.JTextField();
jTextField4 = new javax.swing.JTextField();
jButton1 = new javax.swing.JButton();
jLabel1.setText("jLabel1");
add(jLabel1);
jLabel2.setText("jLabel1");
add(jLabel2);
jLabel3.setText("jLabel1");
add(jLabel3);
jLabel4.setText("jLabel1");
add(jLabel4);
jTextField1.setText("jTextField1");
add(jTextField1);
jTextField2.setText("jTextField1");
add(jTextField2);
jTextField3.setText("jTextField1");
add(jTextField3);
jTextField4.setText("jTextField1");
add(jTextField4);
jButton1.setText("jButton1");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
add(jButton1);
}// </editor-fold>
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
System.out.println("The label");
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JLabel jLabel4;
private javax.swing.JTextField jTextField1;
private javax.swing.JTextField jTextField2;
private javax.swing.JTextField jTextField3;
private javax.swing.JTextField jTextField4;
// End of variables declaration
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Print");
}
}
XMLEncoder
implementation
As for the XMLEncoder
if I encode the whole class the inputs on the fields are not transferred.
The main class
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.XMLEncoder;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.UIManager;
public final class MainClass extends JFrame {
private TheFRameForm x;
public MainClass() {
x = new TheFRameForm();
initComponents();
TheServer theServer = new TheServer();
theServer.start();
}
void initComponents() {
setTitle("Look At Me Now");
setLayout(new FlowLayout());
JButton b = new JButton("Show Form");
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
x.setVisible(true);
}
});
add(b);
JButton s = new JButton("Send Form");
s.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
sendForm();
}
});
add(s);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}
private void sendForm() {
try {
Socket clientsocket = new Socket("localhost", 15000);
XMLEncoder encoder = new XMLEncoder(clientsocket.getOutputStream());
encoder.writeObject(x); //.getContentPane()
encoder.close();
OutputStream memStream = new ByteArrayOutputStream();
XMLEncoder mencoder = new XMLEncoder(memStream);
mencoder.writeObject(x);//.getContentPane()
mencoder.close();
String xmlString = memStream.toString();
System.out.println(xmlString);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ignored) {
ignored.printStackTrace();
}
MainClass theMainclass = new MainClass();
}
}
The Server class
import java.beans.XMLDecoder;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
public class TheServer extends Thread {
private static final int serverPort = 15000;
private ServerSocket serverSocket;
public TheServer() {
try {
serverSocket = new ServerSocket(serverPort);
} catch (IOException ex) {
Logger.getLogger(TheServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void run() {
try {
while (true) {
Socket socket = serverSocket.accept();
System.out.println("Server is running");
XMLDecoder decoder = new XMLDecoder(socket.getInputStream());
JFrame frame = (JFrame) decoder.readObject();
frame.setVisible(true);
socket.close();
}
} catch (IOException ex) {
Logger.getLogger(TheServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
And the JFrame
public class TheFRameForm extends javax.swing.JFrame {
public TheFRameForm() {
initComponents();
}
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jButton1 = new javax.swing.JButton();
jLabel1 = new javax.swing.JLabel();
jTextField1 = new javax.swing.JTextField();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
jButton1.setText("jButton1");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
jLabel1.setText("jLabel1");
jTextField1.setText("jTextField1");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(123, Short.MAX_VALUE)
.addComponent(jButton1)
.addGap(54, 54, 54)
.addComponent(jLabel1)
.addGap(102, 102, 102))
.addGroup(layout.createSequentialGroup()
.addGap(149, 149, 149)
.addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(120, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
.addComponent(jButton1))
.addGap(57, 57, 57)
.addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(65, 65, 65))
);
pack();
}// </editor-fold>
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
System.out.println("Print");
}
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(TheFRameForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(TheFRameForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(TheFRameForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(TheFRameForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new TheFRameForm().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JLabel jLabel1;
private javax.swing.JTextField jTextField1;
// End of variables declaration
}
It looks like the L&F isn't serializing well, but regardless, my advice again is to instead serialize the GUI's model and send its state through. You can then easily re-create your view with this state, and the amount of data sent will be orders of magnitude less.
Edit 1: For example, in the code you've posted, you'd create a PersonalData class as your model, that has three String fields for first name, last name, and email, and a boolean (or better enum) field for gender.
Then the information sent across the socket would be objects of this "model" class, not the whole Swing GUI. You could reproduce the GUI filling in the data from the objects that were passed.