Nate is now most likely laying on his bed, crying his eyes out.
I missed the start of the thread but the important thing is that people are getting stuff done, whatever tool they choose to use. However, there is a difference between a tool that can
possibly get a job done and a good
tool for the same job. That is what I see we are discussing here. We could all go write everything in COBOL, but we don't.
Such kind of programers avoid Dependency hell. Using a library to solve something that is *already* solved is quite frankly, silly.
Avoiding a dependency is fine if the built-in alternative is sufficient. The built-in Java serialization is certainly not the end all solution. Not even close. It has many problems, more than I could list here. Josh Bloch's Effective Java goes into detail. If you understand all the issues and it still meets your needs, by all means, use it if you want. I'll mention a couple issues.
Java serialization uses an extralinguistic mechanism to create objects without invoking constructors. Objects not designed to be constructed this way can easily have inconsistent state. This is a nasty gotcha and (among other reasons) causes serialization code to permeate classes.
Java serialization is slow and the output is large. Externalizable is the usual rebuttal, but then you have to hand write serialization (time consuming, error prone, difficult to support forward/backward compatibility), and that code has to go inside each of your classes. At that point, all Java serialization is really doing is giving you a stream to write to.
Key style difference -we don't explicitly register data to serialize with some subsystem
4. Code pollution versus "transportability" (being mingled with the classes to be serialized, Java Serialization makes your serializable objects highly transportable to other projects; and as a counterexample Kryonet requires you to set all serialization up for objects before you can use them)
Kryo's class registration is an optional optimization to greatly reduce output size. It is not required. Note that Kryo is the serialization library and KryoNet is Kryo + networking. Class registration is
required for KryoNet, but not for Kryo. Other setup, such as customizing serialization for a particular class, can be done inside or outside the class when using Kryo.
if this is really all you need to serialize:
then its really easy.
I would like to try what happens if the classes have changes -> incompatible save game problem
It is that easy, though the example you gave is old, the docs have an update to date example
. Forward and backward compatibility aren't always important, but when they are, you must think about it before choosing how to do your serialization. Kryo can do it multiple ways. You can have none, which is most efficient. You can use TaggedFieldSerializer (where you can add fields but can't remove them, only deprecate them), which has very minimal overhead. You can use CompatibleFieldSerializer (where you can add and remove fields), which has a bit of overhead. I use TaggedFieldSerializer for my save games and other binary files that may be loaded across versions of my app.
"Horses for courses" as we say in England. You must evaluate what you need from serialization to make an informed choice about what to use.
Agreed. There are many factors to consider, even more than you listed. I suggest reviewing the jvm-serializers
project. Even then, your own real data should be used to have meaningful comparisons. It is still very difficult to compare individual features of the different libraries.
For my own usage, there are two libraries I use for serialization, one for binary and one for human readable. I'm the author of both, so I may be biased.
I'll go ahead and ramble on about them.
Many years ago I wanted to make a quick multiplayer networked Rampart clone. I found the JGN (Java Game Networking) lib by darkfrog and used that. I contributed code to do POJO serialization using reflection. This code is now used by jMonkeyEngine. Eventually I decided to write my own networking lib for my personal use. Later I rewrote the serialization a third time and separated it from the networking, and this is how Kryo and KryoNet was born. About 4 months ago I rewrote Kryo again and I'm quite happy with the current incarnation. The code is very nice, the API easy to use, and it compares well against the alternatives. It has a nice little community (143 members on the mailing list) with active members that provide quality contributions (this is unheard of!
) and is used by a number of projects
In a nutshell, Kryo does what you would do if you were hand writing serialization code, only it does it automatically. POJOs need no interface or annotation and can be serialized automatically. When a class does need serialization code, it can go in the class or can be kept separate. Kryo output is very small. Kryo is very fast. Various features, such as object references, can turned on and off to custom serialization for your needs to increase performance and reduce output size. Bytecode generation
is used for speed when possible. Soon Kryo will be able to take advantage of Unsafe when possible, which can be up to 20 times faster at the cost of increased output size (details
). This will be pretty sweet, considering Kryo is already one of the fastest libs.
The other serialization I'd like to mention is related to JSON, but first some background. I had previously toyed with making a YAML serialization library, called YamlBeans
. I wanted human friendly serialization, and I wanted it to be as easy to use as Kryo. It turns out YAML is totally f**ked to parse. YamlBeans is fine for POJOs, but does not have the flexibility for more complex usage. Doing that would have required exposing the YAML parsing/emitting, which is just too complicated. I can only recommend YamlBeans for the most simple object graphs, or where you just have to parse YAML into maps/lists/strings.
About a year ago, I wanted to use JSON as my human readable serialization format. Jackson seems to be the leading library in this area, but it didn't have the simple API and the output flexibility that I wanted. I had been playing with Ragel
, a sweet FSM compiler, so I felt like taking a crack at parsing JSON myself. Here
is the result. I also created a class to emit JSON using a super simple, stack based API (here
). With those, I wrote a class similar to YamlBeans and Kryo that uses reflection to serialize and deserialize. Unlike YamlBeans, it exposes the JSON pasring/emitting so the output is very customizable.
The result is the Json class in libgdx. I also ripped it out of libgdx for use in other apps, calling it JsonBeans
While easy to use for basic operations, the Json class is also very flexible which allows for some neat tricks. JSON parsing can be hooked to do fancy stuff. Here
I intercept reading an object and if a string was found in the JSON where an object was expected, I look up the object by name. This is used for scene2d skin file parsing, so objects previously defined in the JSON can be referenced later by name. Another example, it can deserialize into an existing object. For the libgdx texture packer, here
I have a JSON file in each directory, and a child directory inherits the settings from the parent directory. Values set in the child directory JSON override those in the parent directory JSON.
In closing :p, Java serialization can be fine. When it is not fine, it is horrible. There are other worthwhile alternatives, probably even some not written by yours truly.