Sequential default serialization _jsp programming in J2SE

Source: Internet
Author: User
Tags object serialization prepare serialization
What is to be saved is also preserved. In general, we just need to save the logical data. Data that you do not need to save can be marked with the keyword transient.

Here is an example:

Import java.io.*;

public class serial implements Serializable {
int company_id;
String company_addr;

Transient Boolean company_flag;
}

The Company_flag field will not participate in serialization and deserialization, but at the same time you have added responsibility for his initial value. This is also one of the problems that serialization often causes. Because serialization is equivalent to a public constructor that accepts only data streams, this object construction method is outside of the language. But he is still a formal constructor. If your class cannot be guaranteed to initialize in other ways, you need to provide an additional ReadObject method, first normal deserialization, and then initialize the fields marked with transient.

When not appropriate, the use of Java default serialization behavior can have a speed impact and, worst of all, may result in an overflow. In some data structure implementations, often filled with a variety of circular references, and Java default serialization behavior, do not understand your object structure, the result is that Java is trying to pass an expensive "graph traversal" to save the object state. It is conceivable that not only slow but also possible overflow. At this point you will provide your own readobject instead of the default behavior.

compatibility issues

Compatibility has always been a complex and troublesome issue.

Do not compatibility:

First take a look at what we should be aware of if our goal is not to be compatible. There are many situations where compatibility is not possible, such as WAR3 can not read previous replays whenever the version is upgraded.

Compatibility is also version control, Java through a named UID (Stream unique identifier) to control, this UID is implicit, it through the class name, method name and many other factors are calculated, theoretically one by one mapping relationship, that is, the only. If the UID is not the same, deserialization cannot be implemented and will get invalidclassexception.

When we want to artificially produce a new version (the implementation does not change), and discard the previous version, you can achieve by the explicit reputation UID:

Private static final long serialversionuid=????;

You can fabricate a version number, but be careful not to repeat it. So that the old version will get invalidclassexception at the time of deserialization, we can catch the exception in the old version and prompt the user to upgrade the new version.

Maintain compatibility when little changes are made (a special case of backward compatibility):

Sometimes your class adds some irrelevant, private methods, and when the logical fields don't change, you certainly want the old version to be compatible with the new version, which is also achieved by an explicit reputation uid. Let's verify it below.

Old version:

Import java.io.*;

public class serial implements Serializable {

int company_id;
String company_addr;

Public Serial1 (int company_id, String company_addr) {
this.company_id = company_id;
THIS.COMPANY_ADDR = company_addr;
}

Public String toString () {
Return "DATA:" +company_id+ "" +
COMPANY_ADDR;
}
}

New version

Import java.io.*;

public class serial implements Serializable {

int company_id;
String company_addr;
Public Serial1 (int company_id, String company_addr) {
this.company_id = company_id;
THIS.COMPANY_ADDR = company_addr;
}

Public String toString () {
Return "DATA:" +company_id+ "" + company_addr;
}
public void Todo () {}//trivial method
}

The old version is serialized first, then read out with a new version, and an error occurs:

Java.io.InvalidClassException:Serial.Serial1; Local class Incompatible:stream Classdesc serialversionuid = 762508508425139227, local class Serialversionuid = 118716993 5661445676

Next we add an explicit reputation UID:

Private static final long serialversionuid=762508508425139227l;


Run again and successfully generate new objects

data:1001 COM1

How to keep up compatibility:

Upward compatibility refers to the fact that older versions can read new versions of serialized data streams. Often appearing on our server's data updates, we still want older clients to be able to support deserialization of new data streams until they are updated to the new version. It can be said that this is semi-automatic thing.

In general, because Serialversionuid is the only flag in Java that controls the ability to deserialize successfully, as long as this value is different, it cannot be deserialized successfully. But as long as this value is the same, it will be deserialized anyway, in this process, the extra content in the new data stream is ignored for upward compatibility, and all content contained in the old data stream will be restored to the backward, and the parts that are not covered in the new version of the class will remain in the default value. Using this feature, it can be said that as long as we believe that the serialversionuid remain unchanged, the upward compatibility is automatically realized.

Of course, once we take the old content out of the new version, the situation is different, and even if the UID stays the same, it throws an exception. It is precisely because of this that we have to remember that once a class realizes serialization and maintains the upper and lower compatibility, it can not casually modify the!!!

The test also proves this, and interested readers can try it on their own.
How to maintain backward compatibility:

As noted above, you will take it for granted that backward compatibility is automatically achieved as long as the serialversionuid remains unchanged. But in reality, backward compatibility is a bit more complicated. This is because we have to be responsible for those fields that are not initialized. Make sure they can be used.

So we have to use

private void ReadObject (Java.io.ObjectInputStream in)
Throws IOException, classnotfoundexception{
In.defaultreadobject ()//Deserialize object first
if (ver=5552) {
Previous version 5552
... Initializing other fields
}else if (ver=5550) {
Previous version 5550
... Initializing other fields
}else{
Too old version does not support
throw new Invalidclassexception ();
}
}

Careful readers will notice that to ensure in.defaultreadobject (), to be able to execute smoothly, you must require SERIALVERSIONUID consistency, so the ver here can not use Serialversionuid. The ver here is a final long ver=xxxx that we have arranged in advance, and it cannot be modified by transient. So there are at least three points required to keep down compatibility:

1.serialVersionUID Stay Consistent

2. Final long ver=xxxx with our own version identification logo in advance;

3. Ensure initialization of all domains

   discuss the compatibility strategy:

Here we can see that it's troublesome to keep the compatibility down. And as the number of versions increases. Maintenance can become difficult and cumbersome. It is beyond the scope of this article to discuss what programs should use the compatibility serialization strategy, but the requirement for a game to be saved is certainly different from that for a word processing software document. For the RPG game's Save function, the general requirements to be able to maintain backward compatibility, here if the use of Java serialization method, can be based on the above analysis of three points to prepare. It is still possible to use the object serialization method for such a scenario. For a word processing software document compatibility requirements are very high, in general, the strategy is to require good backward compatibility, and as far as possible to the up-compatible. Object serialization techniques, a well-designed document structure, are generally not used to solve the problem.

   data consistency problem, constraint problem

To know that serialization is another form of "public constructor", but he only constructs objects without any checks, so people are very uncomfortable, so the necessary checks are required, which utilizes the readobject ()

private void ReadObject (Java.io.ObjectInputStream in)
Throws IOException, classnotfoundexception{
In.defaultreadobject ()//Deserialize object first
... To check and initialize
}

For structural reasons, a function called Initialize is typically used to check and initialize if the failure throws an exception. It's easy to forget to keep checking and initializing, which often leads to problems. Another problem is that subclasses can easily forget to invoke the corresponding initialize function when the parent class is not joined to the ReadObject (). This seems to go back to the question of why the constructor was introduced in the first place, because preventing subclasses from forgetting to invoke the initialization function raises various problems. Therefore, if you want to maintain data consistency, be sure to join ReadObject ().

Security Issues

The topic of security is beyond the scope of this article, but you should know that it is possible for an attacker to prepare a malicious stream of data for your class in an attempt to generate an incorrect class. When you need to ensure that your object data is secure, you can generally use the above methods to check and initialize, but for some references it is not good to check. The solution is to make a protective copy of the important parts. A good way to do this is to use a protected copy of the individual domain instead of protecting the entire object directly. This is:

Object Readresolve () throws objectstreamexception;

The use of this method is that he will immediately invoke ReadObject (). It will take advantage of the returned object instead of the original deserialized object. That is, the original ReadObject () deserialized object will be discarded immediately.

Object Readresolve () throws objectstreamexception{
return new Serial2 (THIS.XXX1,THIS.XXX2);//xxx1, xxx2 is just deserialized, this is a protective copy
}

This is a waste of time, but you can use this method for particularly important and secure classes. This approach can be leveraged if data consistency issues, constraint problems are solved by checking each, but consider the cost and the limitations below. The obvious disadvantage of using readresolve () is that when the parent class implements the Readresolve (), subclasses will become free. If the Readresolve () of a protected or publicly-owned parent class exists, and the subclass does not overwrite it, it will eventually get the object of a parent class when deserialized, which is neither a result nor an easy error to discover. Having subclasses rewrite Readresolve () is undoubtedly a burden. That is to say, it is not a good way to implement Readresolve () to protect classes for classes to be inherited. We can only use the first method to write a protective readobject ().

So my advice is: In general, only the final class with Readresolve () to protect.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.