I am reading Thinking in Java 4th Edition.
There described a strange workaround for serialization of transient fields:
import java.io.*;
public class SerializationTest implements Serializable {
private String firstData;
//transient field, shouldn't be serialized.
transient private String secondData;
public SerializationTest(String firstData, String test2) {
this.firstData = firstData;
this.secondData = test2;
}
/**
* Private method, same signature as in Serializable interface
*
* #param stream
* #throws IOException
*/
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.defaultWriteObject();
stream.writeObject(secondData);
}
/**
* Private method, same signature as in Serializable interface
*
* #param stream
* #throws IOException
*/
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
secondData = (String) stream.readObject();
}
#Override
public String toString() {
return "SerializationTest{" +
"firstData='" + firstData + '\'' +
", secondData='" + secondData + '\'' +
'}';
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = new FileOutputStream("object.out");
oos = new ObjectOutputStream(fos);
SerializationTest sTest = new SerializationTest("First Data", "Second data");
oos.writeObject(sTest);
} finally {
oos.close();
fos.close();
}
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream("object.out");
ois = new ObjectInputStream(fis);
SerializationTest sTest = (SerializationTest) ois.readObject();
System.out.println(sTest);
} finally {
ois.close();
fis.close();
}
//Output:
//SerializationTest{firstData='First Data', secondData='Second data'}
}
}
As you can see, there are implemented private methods writeObject and readObject.
The questions are:
For what ObjectOutputStream and ObjectInputStream are using Reflection for accessing private methods ?
How many back doors like this are included in the Java ?
Backdoor? It's always been in the spec. It is the only way to implement non-default serialization of an object.
Non-default serialization puts you in the serialization driver's seat. You can write whatever to the output stream and as long as you can read it back and construct your object on the other end of the stream, you'll be ok.
The fact that this person decided to serialize transient fields is just not the issue, the point is that you can do whatever you want if you are implementing your own serialization scheme.
Erm, it isn't a "backdoor" ... you implemented a custom serialization that output the transient fields to the output stream after calling the default serialization which ignored them.
The Serializable interface is marker interface. So its like a tag to explain the java compiler. There are other marker interfaces like Clonable, etc. See here for more.
However now a days #annotations are used more.
Related
I need reading data from database(MySQL) and transfer to client.
Can i somehow transfer the Object of type TopickOfVote to the client or only through String?
Writer and reader:
writer = new PrintWriter(new OutputStreamWriter(clientAPP.getWriter()));
reader = new BufferedReader(new InputStreamReader(clientAPP.getReader()));
Server:
private void LoadOfTopics() throws SQLException {
resultSet = statement.executeQuery("SELECT * FROM kursach.TopicOfVote");
StringBuffer id;
StringBuffer topic;
while(resultSet.next()){
TopicOfVote topicOfVote = new TopicOfVote();
topicOfVote.setId(Integer.parseInt(resultSet.getString("idVote")));
topicOfVote.setTopic(resultSet.getString("topic"));
ResultSet ans = statement.executeQuery("SELECT * FROM kursach.Answers_vote WHERE idVote=" + topicOfVote.getId());
ArrayList<Answer> answers = new ArrayList<>();
while (ans.next()){
Answer answer = new Answer();
answer.setId(Integer.parseInt(ans.getString("idAnswer")));
answer.setAnswer(ans.getString("answer"));
answer.setIdOfTopic(Integer.parseInt(ans.getString("idVote")));
answers.add(answer);
}
topicOfVote.setAnswers(answers);
writer.println(topicOfVote); // ???
writer.flush();
ans.close();
}
}
Client:
private void createPanelTopics(){
try {
writer.println(HandlerQueries.GET_VOTES + "?");
writer.flush();
reader.readLine();//?????
} catch (IOException e) {
e.printStackTrace();
}
}
Can i somehow transfer the Object of type TopickOfVote to the client
Yes, with Object Serialization, provided TopickOfVote implements Serializable and does all the other right things associated, such as defining a private static final long serialVersionUID, and doesn't evolve incompatibly.
or only through String? Writer and reader:
Yes, with XML, JSON, ...
I used this code to verify a digital sign of a file, the constructor prints the context of the file but I wanted to know how to save the print as a variable , since a constructor uses only to "build" objects, this is the code:
public class VerifyMessage {
private List<byte[]> list;
#SuppressWarnings("unchecked")
// The constructor of VerifyMessage class retrieves the byte arrays from the File and prints the message only if the signature is verified.
public VerifyMessage(String filename, String keyFile) throws Exception {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));
this.list = (List<byte[]>) in.readObject();
in.close();
System.out.println(verifySignature(list.get(0), list.get(1), keyFile) ? "VERIFIED MESSAGE" + "\n----------------\n" + new String(list.get(0)) : "Could not verify the signature.");
}
How can I "save" the System.out.println as a global member String variable outside of the constructor?
thanks ahead
Your class already contains a list field.
Similar to that, you declare a string field- and then you simply assign the value you are currently printing to that field.
public class VerifyMessage {
private List<byte[]> list;
Object variable = null;
public VerifyMessage(String filename, String keyFile) throws Exception {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));
this.list = (List<byte[]>) in.readObject();
in.close();
this.variable = this.verifySignature(list.get(0), list.get(1), keyFile);
}
private Object verifySignature(byte[] bs, byte[] bs2, String keyFile) {
//
return null;
}
}
Greetings to the community, I recently came up with an issue in serialization and deserialization in my java project. I have an object of a class containing other objects as fields.
I would like to store the state of the object into a byte array and then deserialize the byte array and get back the original object.However,the objects consisting my object's fields are not Serializable(came from third party library) so had to declare them as transient in first place.
Now my object is serialized and deserialized but as was to be expected it's fields are null because of the transient declaration i mentioned before.I have tried to create locally into my Serialization class all the elements and assign to them the original ones values and continue the process but it didnt had any difference. I quote below part of my code, Any ideas ? Thanks beforehand :)
Here is the class of my object with it's fields
public class AbePublicKey implements java.io.Serializable{
private static final long serialVersionUID = 7526472295622776147L;
public transient Element g;
public transient Element h;
public transient Element f;
public transient Element e_g_g_hat_alpha;
}
Here is my Serializer function
public byte[] PublicKeytoByteArray(AbePublicKey publickey) throws IOException {
KeyAuthority keyauthority = new KeyAuthority();
byte[] bytes = null;
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
publickey.setElements(g, h, f, e_g_g_hat_alpha);
try {
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(publickey);
oos.flush();
bytes = bos.toByteArray();
} finally {
if (oos != null)
oos.close();
}
if (bos != null) {
bos.close();
}
}
return bytes;
}
Here is my Deserializer function
public static AbePublicKey PublicKeyBytestoObject(byte[] publickeybytes) throws IOException, ClassNotFoundException {
AbePublicKey obj = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
bis = new ByteArrayInputStream(publickeybytes);
ois = new ObjectInputStream(bis);
obj = (AbePublicKey) ois.readObject();
} finally {
if (bis != null) {
bis.close();
}
if (ois != null) {
ois.close();
}
}
return obj;
}
If you want control over how an object is Serialized, implement the Externalizable interface and the associated readExternal and writeExternal methods. This gives you full control over how an object is serialized.
Clearly you can't serialize a class that contains fields that are not serializable. But you can perhaps write enough data to recreate the objects on your own.
If you are able to copy the values needed into new Serializable CustomElement objects inside your class, it should make a difference. Use copy constructors ( if available), or even reflection if you have enough information available.
You could wrap your Element fields in a class that is Serializable so that you can write them. This solution assumes you're able to call the necessary setters or constructor to recreate the Element after you read it.
Here is an example:
Very basic Element that is not Serializable
public class Element {
private String value;
public Element(){
value = null;
}
public Element(String value){
setValue(value);
}
public void setValue(String value){
this.value = value;
}
public String getValue(){
return value;
}
}
Now a very basic wrapper class that is Serializable
import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.Serializable;
public class SerializableElement implements Serializable{
// Generated ID
private static final long serialVersionUID = -6751688345227423403L;
private transient Element element;
public SerializableElement(Element el)
{
element = el;
}
private void writeObject(java.io.ObjectOutputStream out)
throws IOException{
out.writeObject(element.getValue());
}
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException{
String elementValue = (String)in.readObject();
element = new Element(elementValue);
}
private void readObjectNoData()
throws ObjectStreamException{
element = null;
}
public Element getElement(){
return element;
}
}
Finally a main class to run the serializing and deserializing logic (slightly modified from what you posted) :
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializeMain {
public static void main(String[] args) {
SerializableElement serializableElement = new SerializableElement(
new Element("test value"));
try {
byte[] serializedData = storeElement(serializableElement);
SerializableElement loadedElement = loadElement(serializedData);
System.out.println("loadedElement.element.value: "
+ loadedElement.getElement().getValue());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static byte[] storeElement(SerializableElement sElement)
throws IOException {
byte[] bytes = null;
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
try {
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(sElement);
oos.flush();
bytes = bos.toByteArray();
} finally {
if (oos != null) {
oos.close();
}
if (bos != null) {
bos.close();
}
}
return bytes;
}
public static SerializableElement loadElement(byte[] byteData)
throws IOException, ClassNotFoundException {
SerializableElement obj = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
bis = new ByteArrayInputStream(byteData);
ois = new ObjectInputStream(bis);
obj = (SerializableElement) ois.readObject();
} finally {
if (bis != null) {
bis.close();
}
if (ois != null) {
ois.close();
}
}
return obj;
}
}
I have written a java program that needs to save a list of an Object I created called User. This is my code for saving and loading the list:
/**
* Save list to file
* #param saveList list to be saved
*/
public void saveUsers(List<User> saveList){
try{
FileOutputStream fileOut = new FileOutputStream("data/userlist.ser", true);
OutputStream out = new BufferedOutputStream(fileOut);
ObjectOutput output = new ObjectOutputStream(out);
output.writeObject(saveList);;
out.close();
fileOut.close();
output.close();
for(User u : saveList){
System.out.println(u.getUsername());
}
System.out.println("List written to file");
}catch(IOException e){
e.printStackTrace();
}
}
/**
*
* #return list of all users in system.
*/
#SuppressWarnings({ "resource", "unchecked" })
public static List<User> loadUsers(){
try{
InputStream saveFile = new FileInputStream("data/userlist.ser");
InputStream buffer = new BufferedInputStream(saveFile);
ObjectInput input= new ObjectInputStream(buffer);
LinkedList<User> loadList = (LinkedList<User>) input.readObject();
System.out.println(loadList.size());
for(User u : loadList){
u.reload();
System.out.println(u.getUsername());
}
return loadList;
}catch(Exception e){
e.printStackTrace();
}
List<User> l = new LinkedList<User>();
return l;
}
And my code seems to work for save because the output each time it is called shows all the users being added to the list, however on the load it only loads the first User. This is my user class:
public class User implements Serializable{
/**
* Variables
*/
private transient StringProperty usernameProperty;
private String username;
private List<Album> albums = new LinkedList<Album>();
private List<Photo> photos = new LinkedList<Photo>();;
private List<Tag> tags = new LinkedList<Tag>();;
private static final long serialVersionUID = 1738L;
/**
* public constructor to create a user
* #param username
*/
public User(String username){
this.username = username;
this.usernameProperty = new SimpleStringProperty(username);
}
And all of my other classes are implementing the Serializable as well. Is there any reason the list is being saved to the file but not loading fully?
I figured out the answer, apparently every time I was calling the save class, I was not overwritting the file but appending to it, so I was only reading the first array list being stored, pretty simple fix I just added the lines
File file = new File("data/userlist.ser");
file.delete();
to the beginning of my saveUsers function to clear the file, now it works perfectly.
Change LinkedList loadList = (LinkedList) input.readObject(); to ArrayList. Edit the file userlist.ser delete the contents or create a new file and use it in your code. It works fine for me.
Finding the error in your code is for me more complex than testing my own solution, so I have made a quick model for you, using a the same classes you use, but using a custom class (car) for this...
the Code:
public static void main(String[] args) throws Exception {
final Car c0 = new Car("bmw", 1990);
final Car c1 = new Car("VW", 2000);
final Car c2 = new Car("Audi", 2010);
final Car c3 = new Car("Mini", 2015);
final LinkedList<Car> lisCar = new LinkedList<Car>();
lisCar.add(c0);
lisCar.add(c1);
lisCar.add(c2);
lisCar.add(c3);
serialThis(lisCar);
deserializeFileToList();
}
Serialize to file:
private static void serialThis(LinkedList<Car> lisCar) throws Exception {
final FileOutputStream fos = new FileOutputStream("serialized.txt");
final ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(lisCar);
oos.close();
}
Deserialize from file:
private static void deserializeFileToList() throws Exception {
final FileInputStream fis = new FileInputStream("serialized.txt");
final ObjectInputStream ois = new ObjectInputStream(fis);
final LinkedList<Car> ds = (LinkedList<Car>) ois.readObject();
ois.close();
System.out.println(ds);
}
The Car class:
private static final long serialVersionUID = -427928246789764110L;
#Override
public String toString() {
return "Car [year=" + year + ", type=" + type + "]";
}
private final int year;
private final String type;
public Car(String type, int year) {
this.type = type;
this.year = year;
}
I have succeeded in writing and reading a string to a file on my android app's internal storage, but I want to write an object and it's not working. I've read Oracle's documentation on the matter, which says for object fields to be transmitted over the stream the object needs to implement serializable, or something. I added imports serializable and implements serializable to the cat class but it threw an error. Without it "oos.writeObject(myCat);" causes an error too. I'm very confused.
The below code exists in a java activity class tied to a layout.xml. The user presses a button and the object is saved or loaded. As stated writing and reading a string seems to work fine, but objects less so.
private void writeFile()
{
try
{
String myFile = "myFile";
cat myCat = new cat("Harry", "blue", 11);
FileOutputStream fos = openFileOutput(myFile,MODE_WORLD_READABLE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(myCat);
oos.close();
fos.close();
Toast.makeText(getBaseContext(),"object saved",Toast.LENGTH_SHORT).show();
}
catch (Exception e)
{
e.printStackTrace();
}
}
And
private void readFile()
{
try
{
String myFile = "myFile";
FileInputStream fis = openFileInput(myFile);
ObjectInputStream ois = new ObjectInputStream(fis);
cat yourCat = (cat) ois.readObject();
ois.close();
fis.close();
String output = yourCat.name + " the " + yourCat.colour + " cat";
Toast.makeText(getBaseContext(),output,Toast.LENGTH_SHORT).show();
}
catch (Exception e)
{
}
}
The cat object
public class cat
{
public String name = "";
public String colour = "black";
public int age = 0;
public cat(String pName, String pColour, int pAge)
{
name = pName;
colour = pColour;
age = pAge;
}
}
Adding "implements Serializable" to the cat class works. I'm not sure why it didn't in the first place. Sorry for the fuss.
Try using:
MODE_PRIVATE
In the openFileOutput() method.