Deserialize a transient field with kryoserialization

706 views
Skip to first unread message

rdp

unread,
Jul 25, 2017, 4:52:53 PM7/25/17
to kryo-users
Hi All,

I am using kryoserialization with memcached session manager

I have a class which has a transient field , a Map with list of same class and LinkedHashMap.

Serialization works fine but when I deserialize the transient field in null. I want to initialise this field.

This worked perfectly fine when i use default Java Serialization with memcached session manager as I added readObject method to my class which gets called on deserialization and I initialise the transient field.

But I am unable to do this with Kryo Serialization.

I decided to implement KryoSerializable as shown below.(Its sample code similar to my original class)

My transient field gets initialized by the read method  but map1 and map2 dont serialise correctly so when deserialization happens map1 and map2 are empty.


Class MyClass implements KryoSerializable{
  
   
  protected Map<String, List<MyClass>> map1;

  protected Map<String,String> map2 = new LinkedHashMap<String, String>();

   private transient Manager manager;

  @Override
public void read(Kryo kryo, Input input) {
        //  Initialize transient manager 
manager = (Manager) SomeUtilities.get(Manager.class);
}

@Override
public void write(Kryo kryo, Output output) {
// I do nothing here
}
}

Can you please help me solving above issue

Thanks

Joachim Durchholz

unread,
Jul 26, 2017, 3:19:58 AM7/26/17
to kryo-...@googlegroups.com
Am 25.07.2017 um 22:52 schrieb rdp:
> Serialization works fine but when I deserialize the transient field in
> null. I want to initialise this field.
>
> This worked perfectly fine when i use default Java Serialization with
> memcached session manager as I added readObject method to my class which
> gets called on deserialization and I initialise the transient field.
>
> But I am unable to do this with Kryo Serialization.

Yes, that's standard behaviour for transient fields: They don't get
serialized or deserialized.
Different frameworks offer different ways to add initialization code,
but this tends to be difficult anyway - during deserialization, fields
may not yet be filled, object graphs may not yet be fully there, so any
code that runs during deserialization is pretty fragile and dependent on
internals of the deserialization framework (such as object
deserialization order).

The best way around this is to design your transient fields to be
initialized on demand. On-demand means that anything that's needed to
populate that fields is already there, or at least subject to on-demand
initialization.
The only thing you have to worry about in this scenario is circular
on-demand initialization dependencies, but at least that's entirely
within your own code and does not involve library code from third parties.

Since Kryo uses the default constructor, you can initialize the
transient field there, that's even easier.

> I decided to implement KryoSerializable as shown below.(Its sample code
> similar to my original class)
>
> My transient field gets initialized by the read method but map1 and
> map2 dont serialise correctly so when deserialization happens map1 and
> map2 are empty.

Yeah, the KryoSerializable Javadoc says you need to implement read() and
write() yourself, but you don't do it so the nontransient fields don't
get (de)serialized.

I don't know the best way to do that though; maybe somebody else can
give a hint.

rohit phuge

unread,
Jul 26, 2017, 5:10:28 AM7/26/17
to kryo-...@googlegroups.com
Thanks a lot Joachim for your quick response.

I like the idea of using default constructor to initialise my transient field as Kryo calls it.

I got below two solutions working 

Solution 1 

  I used following annotation  for my class @DefaultSerializer(JavaSerializer.class) which allows you to tell kryo that for this class use JavaSerialization , than i added readObject method and worked fine.
   But then again this is java serialization which is slower than kryo.
   
   @DefaultSerializer(JavaSerializer.class)
   Class MyClass implements Serializable{
      private static final long serialVersionUID = -47478099345403771432L;

    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
// initialise my transient feild here
// continue with default java deserialise
in.defaultReadObject();
}
   }


Solution 2

This is almost similar to "on demand approach" what you suggested , I removed transient field manager and used a static utility class to get transient field where I needed it.
    manager = SomeUtilitiesToGetTransientField.get(Manager.class) 








--
You received this message because you are subscribed to the "kryo-users" group.
http://groups.google.com/group/kryo-users
--- You received this message because you are subscribed to a topic in the Google Groups "kryo-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/kryo-users/nQFBF9z_epM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to kryo-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages