Blog-Archiv

Mittwoch, 21. September 2016

Useless Java @SuppressWarnings("serial") Annotation

You see it everywhere in Java code, mostly in classes that are near to persistence layer:

@SuppressWarnings("serial")
public class XXX implements Serializable ....

We are used to overlook such noise, also called "boilerplate code". The more noise, the higher the risk that something is NOT noise and we miss it. Can we avoid it, and produce source code that is written for humans and not for compilers?

Just to be clear: we do not want to write less code (that does more). We want to write less boilerplate code.

Yes, we can. At least for @SuppressWarnings("serial"). Don't write it, simply leave it out. Tell your IDE or compiler to ignore such warnings.

It is really time to produce code that reads like a novel, not like a video recorder manual. You do yourself a favor, and all your colleagues that need to read your code at some time. It is not a risk to disable @SuppressWarnings("serial"). This Blog will try to explain why.

Serializable

Serializable is a Java core interface that you must implement when you intend to write instances of your class to a disk file, or into a database BLOB, or when you need to drag & drop one of your Java objects. The serial representation of the object is unreadable ("binary"). It also contains all member field objects, recursively. Just transient and static fields are not serialized.

When you serialize an object that doesn't implement Serializable, or one of its fields' types does not, you'll get a NotSerializableException at runtime. So the compiler does not check this!

Here is a serialization / deserialization demo, using just java.io classes:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class SerializableConfiguration implements Serializable
{
    public static final String configurationExtension = ".config";
    
    private Long customerId;
    private transient String state;
    
    public void setCustomerId(Long customerId) {
        this.customerId = customerId;
    }
    
    public void setState(String state) {
        this.state = state;
    }
    
    @Override
    public String toString() {
        return "customerId="+customerId+", state="+state;
    }
    
    
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        final Long customerId = 12345L;
        final String state = "running";
        
        final SerializableConfiguration configuration = new SerializableConfiguration();
        configuration.setCustomerId(customerId);
        configuration.setState(state);
        
        System.out.println("Expecting: "+configuration);
        
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        final ObjectOutputStream objectOut = new ObjectOutputStream(out);
        objectOut.writeObject(configuration);
        objectOut.close();
        
        final InputStream in = new ByteArrayInputStream(out.toByteArray());
        final ObjectInputStream objectIn = new ObjectInputStream(in);
        final Object deserializedObject = objectIn.readObject();
        
        System.out.println("Result: "+deserializedObject);
    }
}

This test class contains a static, a normal, and a transient field. The static field is connected to the class and does not appear in the serialized object, also the transient field is ignored. Just the customerId gets serialized. The main() procedure demonstrates this by serializing into and deserializing from a byte array. Most JDK classes like String, Integer, Date ... are Serializable, even the Swing classes.

When you run this demo class, it will output:

Expecting: customerId=12345, state=running
Result: customerId=12345, state=null

... proving that transient fields are not serialized.

The Compiler Warning

Eclipse gives me following warning about the class above:

The serializable class SerializableConfiguration does not declare a static final serialVersionUID field of type long

Reason is that it assumes that I will care about the version-id of this class, and change it as soon as the class gets incompatible with its previous version. That will take place when I remove a property, or change the name of a property, or do that in any class contained in it.

Because then the new class could not match the objects stored at customer site any more. An exception would be thrown when loading a serialized object into a class that is different from the one it was created from. This will not be detected by the compiler, and maybe all unit tests would be green before shipping that runtime-bug to the customer. I really should care about that. But not by writing @SuppressWarnings("serial"), and not by manually maintaining all these serialVersionUID fields.

Makes No Sense

I admit that, in limited cases, maintaining the serialVersionUID could be useful. But I doubt that developers can cope with that, and change the serialVersionUID at the right time. But even when they succeed in doing so, they would not prevent the customer crash by that, because the incompatible stored objects would need to be converted. And when they do not care, it also crashes when the class gets incompatible, although it always has the same serialVersionUID.

Consider not caring about the serialVersionUID. The compiler would automatically generate a new serialVersionUID for that class any time it was actually changed. No developer needs to know and take care of the version compatibility. At the customer site, of course, it will crash when the new serialVersionUID does not match the stored one. Like above.

So what is the difference? Why does the compiler recommend to maintain the serialVersionUID? There is a very small difference, for a very high price:

  • the application upgrade could survive the incompatible serialized class when properties were just added, not changed or removed
  • the price is additional expert work for developers, and a high risk that this goes wrong anyway.

I'm really tired of seeing this useless annotation everywhere. Better use XML serialization, this is more readable, and take adequate actions when catching a deserialization-exception (e.g. resetting to defaults).




Donnerstag, 8. September 2016

JS Promises

HTML-5 browsers provide a natively implemented JavaScript Promise. That means, you don't need a JS library any more to use Promises, they are now built into the language like String and Date.

Do we need promises? No, we don't. What Promises do has been done by JS programmers for more than 15 years now. It is just a single deferred callback with explicit error handling. Another toy, or a best practice that hopefully will not cause too many abuses and misunderstandings.

I searched the web for a short and concise tutorial about Promise (or Future, or Deferred) that just explains when and how to use it, but I didn't find any. So here is mine.

Try Out




Characterizing a Promise

You could use a Promise when following characterization applies to your use-case.

  • A promise is something that will happen in future, and we don't know when, it is asynchronous, we can not retrieve an immediate result from a promise
  • as nobody can know what future brings, the promise could fail
  • a promise fulfills (or fails) when something asynchronous happens, it hangs until then, thus a Promise is "stateful"
  • a promise fulfills (or fails) just once, not several times

For example, a Promise could perfectly perform an AJAX call. The processing of something that an HTML page fetches from its server asynchronously.

But a Promise is not a background-thread. Until now we don't have threads in JavaScript.

Promise Building Blocks

Following is needed to build a Promise:

  • an executor function (promise body), the AJAX call, executed synchronously, initiating something asynchronous
  • a resolve function (fulfill), what should be done when the call succeeds, executed asynchronously
  • a reject function (fail), what should be done when the call fails, executed asynchronously

Just the resolve and reject functions can return a value. This value would be passed to the next Promise, created by the promise's then() function.

The promise's then() function should be called with two parameters, both functions, both could be undefined:

  • promise.then(resolveFunction, rejectFunction)

The then() function returns another Promise instance, so that you can chain promises together. (If you can't get enough of them:-)

Mind that the Promise itself is NOT asynchronous, it is the executor function that initiates something asynchronous. The executor also must make sure that this asynchronous thing calls the resolveFunction on success. The Promise will call the rejectFunction on any exception thrown, but it won't call the resolveFunction automatically when NO exception happens.

How to Promise

You need to implement the executor function, and at least one of resolve or reject.

  • The executor function receives two parameters, the first being the resolve function, the second reject. These will be the functions passed to promise.then(). The asynchronous part of the executor needs to call at least resolve(). It also can call reject() explicitly instead of throwing an exception, this is useful when needing more than one reject-parameters.

  • The resolve function normally receives one parameter, being what the executor function passes to it, or what the preceding promise's resolve or reject returned.

  • The reject function normally receives one parameter, being what the executor function passes to it, or the exception thrown by executor.

The executor function is passed to the Promise constructor. That function is executed immediately by the constructor, it is NOT the then() function which starts it. On the constructed Promise you must call then(), passing the concrete implementations for resolve and reject as parameters. One of these functions will be called in any case, be it that the asynchronous callback already arrived or not.

In case you get back a Promise from somewhere, call promise.then(resolve, reject), and that's it.

Promise Chaining

Chaining is something like promise.then(a, b).then(c, d).then(e, f). I am not sure whether this is really useful, it could easily result in hard-to-read monolithic implementations.

Copy & paste following code into the text-area above and run it. This demonstrates how the return values are passed to the follower-promise.

var makePromise = function(executor, resolve, reject) {
    return new Promise(executor).then(resolve, reject);
};

var followerPromise = makePromise(
    function(resolve, reject) {
        if (confirm("Do you want to keep the promise?"))
            resolve("User decided to keep the promise!");
        else
            reject("Sorry, user decided to NOT keep the promise!");
    },
    function(resolveParameter) {
        alert("I am the resolve function: "+resolveParameter);
        return "This resolve goes to the follower promise";
    },
    function(error) {
        alert("I'm the reject function: "+error);
        return "This reject goes to the follower promise";
    }
);

followerPromise.then(
    function(resolveParameter2) {
        alert("I'm the second resolve function: "+resolveParameter2); 
    },
    function(error2) {
        alert("I'm the second reject function: "+error2); 
    }
);

In this implementation, both resolve and reject return a value. The follower promise is used to process these return values, by giving again resolve and reject implementations.

But as we can see when pressing "Cancel", the return of first reject is passed to second resolve, not to second reject - ?


That's the moment where we want to know more about standard behaviour of promises. Being courageous we could trust the A+ specification, but I would recommend to use just the basic features of promises. As I said, we do not always need them. It is just a shortcut. And it could happen that they make life harder, not easier.