System.enqueueJob
, Database.executeBatch
, System.schedule
, and System.scheduleBatch
, all take their Queueable
, Database.Batchable
, or Schedulable
parameter and serializes it for later execution. You cannot include any non-serializable properties in such a class, or you'll end up with this error. This includes things like Database.SavePoint
and Version
. These exceptions will be thrown at the moment any of those methods are called.
To be clear, the problem is simply that Version
itself is not serializable. Here's a unit test to demonstrate this.
public class InstallQ implements Queueable {
Version version;
public InstallQ(Version version) {
this.version = version;
}
public void execute(QueueableContext context) {
}
}
global class OnInstallB implements InstallHandler {
global void onInstall(InstallContext context) {
// Just using a plain Version object
InstallQ q = new InstallQ(new Version(1,0));
System.enqueueJob(q);
}
}
@isTest public class InstallQTest {
@isTest public static void test() {
Test.startTest();
Test.testInstall(new OnInstallB(), null);
Test.stopTest();
}
}
System.SerializationException: Not Serializable: System.Version
Sometimes, when you run into situations like this, is best to try to isolate the actual cause. In the future, you should remember that Version cannot be serialized. If you need to track the previous version, you will need to provide the version data in some other kind of object (even a simple Map<String, Integer>
would do just fine).
As proof that it's not the Queueable's fault, or even the InstallHandler's fault, you can try to serialize a Version directly:
JSON.serialize(new Version(1,0));
System.JSONException: Apex Type unsupported in JSON: System.Version
In general, if JSON.serialize
can't serialize an object, there's a possibility that you can't include it in a Batchable
, Queueable
, or Schedulable
class, either. Note that this isn't 100% accurate: You can't JSON.serialize
an sObjectField
, but you can include such a field in the state of asynchronous code.
Another test would be to set up a quick Visualforce page to see if you get any errors:
public class VersionControl {
public version versionData { get; set; }
public VersionControl() {
versionData = new Version(1,1);
}
}
<apex:page controller="versionControl">
<apex:form>
</apex:form>
</apex:page>
Not Serializable: System.Version
Odds are, if Visualforce can't serialize the data, neither can asynchronous code.
I find Version
to be kind of an odd exception, because it seems that there shouldn't be anything special about why it can't be serialized. However, most classes like this are either blocked because they would be useless outside of the original context (like Database.Savepoint
), or because their internal state has special properties that must be set, and serialization support would imply deserialization support, which could cause data to be injected.
Ultimately, while your solution was correct, the understanding of the problem was not. Hopefully, I've been able to provide some clarification on the general subject of the Not Serializable error, including System.SerializationException
and System.JSONException
, which both have the same common root cause: you cannot serialize some kinds of data because their internal state would be exposed, or because they would be useless outside of the current transaction context.