DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Data Engineering
  3. Data
  4. Loud Failures are Better than Silent, Faulty Behavior

Loud Failures are Better than Silent, Faulty Behavior

Johannes Brodwall user avatar by
Johannes Brodwall
·
Oct. 23, 12 · Interview
Like (0)
Save
Tweet
Share
4.97K Views

Join the DZone community and get the full member experience.

Join For Free

Sometimes, small questions lead to big answers. Sometimes these answers are controversial. One such question is “What does this warning about serialVersionUID mean”? All the advice out there basically is for developers who don’t know what’s going on to write code that will ignore errors when something unexpected happens. In my view – this is exactly the wrong approach. The safe way to act is to make sure that your program crashes if you don’t have control.

Java programmers usually get this warning when they write code that looks like this:

public class MyServlet extends HttpServlet {
 
  public void doGet(HttpRequest req, HttpResponse resp) {
    // Some logic goes here
  }
}

On stackoverflow this question has an answer that is extensive, well-written, accepted and, in my opinion, wrong. In short, the answer just recommends to implement something like the following:

public class MyServlet extends HttpServlet {
 
  private static final long serialVersionUID = 123L;

Let’s dig deeper.

The reason we get this warning is that HttpServlet implements the interface Serializable. This was a design flaw in the first version of the servlet-api, and now we’re stuck with it. A serialized object can be written to and read from byte streams, such as a file. Here is an example:

  ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(file));
        outputStream.writeObject(new Person("Johannes", "Brodwall"));
 
        ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(file));
        Object object = inputStream.readObject();
        System.out.println(object);

In this case, everything is fine. But let’s imagine that some time passes between the write and the read. For example, what if we try to read the file with the next version of the program. A version in which the Person class is changed? For example, what if we changed the implementation of Person to store the name as a single field fullName, instead of two fields firstName and lastName?

In this case, we would get an error message like the following:

java.io.InvalidClassException: Person; local class incompatible:
                             stream classdesc serialVersionUID = -4897183855179110397,
                             local class serialVersionUID = -1928642322738440913

In other words: If we had set the serialVersionUID, we could still have read the file. Now we’re stuck.

This is why the stackoverflow answer recommends putting a serialVersionUID field in the class.

But wait, there’s another option. Let’s say we found this problem when we tested if our new version was backwards compatible. Now, we could just cut and paste the serialVersionUID from the stack trace. If we do test our software, this is just as easy as putting the serialVersionUID there in the first place. So, let’s fix the Person class:

public class Person implements Serializable {
 
    private static final long serialVersionUID = -4897183855179110397L;
    private final String fullName;
 
    public Person(String firstName, String lastName) {
        this.fullName = firstName + " " + lastName;
    }
 
    @Override
    public String toString() {
        return getClass().getSimpleName() + "[name=" + fullName + "]";
    }
}

Voila! Problem fixed. Our code will run again. Here’s the output of printing the object:

Person[name=null]

Whoops! By forcing different versions of class Person to have the same serialVersionUID, the code now has bug. FullName should never be null (especially since it’s final!). And what’s worse, the bug is a silent one. If we don’t examine the contents of System.out (in this case), we might not catch it before it escapes into the wild.

When you’re not sure, the correct behavior should be to fail, not to silently do the wrong thing.

TL;DR

If you omit a serialVersionUID field from your class, many changes will cause serialized objects to no longer be readable. Even for trivial changes.

Sadly, classes like HttpServlet, AbstractAction and JFrame which are meant to be subclassed implements Serializable, even though they are almost never serialized in practice. Adding serialVersionUID to these classes would only be noise.

The serialVersionUID field can be added to a class afterward if you actually want to read old objects in a new version of the program. This leaves you no worse off than if you added the serialVersionUID field in the first place.

If the old and the new version of the class are deeply incompatible, giving the class a serialVersionUID when you first create it will cause silent faulty behavior.

I prefer loud, failing behavior that is easy to detect during testing to quiet, faulty behavior that may escape into production. I think you do, too.

Object (computer science) Error message Data Types Printing Dig (command) Testing

Published at DZone with permission of Johannes Brodwall, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How Elasticsearch Works
  • Strategies for Kubernetes Cluster Administrators: Understanding Pod Scheduling
  • Multi-Tenant Architecture for a SaaS Application on AWS
  • Unlock the Power of Terragrunt’s Hierarchy

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: