How to use the protostuff schema for a class for an object contains in a Map<String, Object>

728 views
Skip to first unread message

Olivier Martin

unread,
Mar 15, 2017, 4:43:10 PM3/15/17
to protostuff
Hello

i was not able to figure how to have my protostuff schema used for a class named B when this type of object is saved in a Map containing any kind of Object
My schema is working for a field of type B.
When i am looking on how the map is saved, i can see that the object was saved using the Java serialization and not the protostuff serialization.

I have tried many solutions including the one below which seems to me the good one but none have been succesfull:
- using a wrapper around the Map and runtime schema
- register the schema of B  with RuntimeSchema.register(BSchema.class)

Thanks for you help

David Yu

unread,
Mar 16, 2017, 8:31:49 AM3/16/17
to protostuff
Can you put up a small example?
You need to call the ProtostuffIOUtil methods to serialize with protostuff. 

Thanks for you help

--
You received this message because you are subscribed to the Google Groups "protostuff" group.
To unsubscribe from this group and stop receiving emails from it, send an email to protostuff+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
When the cat is away, the mouse is alone.
- David Yu

Olivier Martin

unread,
Mar 16, 2017, 10:34:28 AM3/16/17
to protostuff
Hi

I have uploaded an example on github: https://github.com/PixelDuck/TestProtostuff

The code use a Map<String,B> and a Map<String, Object> containing only B objects
The map of B classes is saved using protostuff but the map of object use serialization.
I dont know how to fix this...

Olivier

David Yu

unread,
Mar 16, 2017, 11:28:15 AM3/16/17
to protostuff
Your register calls should be something like: 
RuntimeSchema.register(A.class, new ASchema()); 

Olivier

--
You received this message because you are subscribed to the Google Groups "protostuff" group.
To unsubscribe from this group and stop receiving emails from it, send an email to protostuff+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Olivier Martin

unread,
Mar 16, 2017, 11:49:51 AM3/16/17
to protostuff
I have tested to regist schema for A abd B with
static {
RuntimeSchema.register(A.class, new ASchema());
RuntimeSchema.register(B.class, new BSchema());
}
but i still see data from java serialization in the file for the map of object

David Yu

unread,
Mar 16, 2017, 3:56:23 PM3/16/17
to protostuff
I just serialized it to json (add protostuff-json as dependency and use JsonIOUtil)

```
{"name":"A-name","mapOfB":{"mapBByString":{"e":[{"k":"second-key","v":{"name":"second"}},{"k":"first-key","v":{"name":"first"}}]}},"mapOfObject":{"mapObjectByString":{"e":[{"k":"third-key","v":{"_":"pixelduck.TestProtostuff$B","name":"third"}},{"k":"fourth-key","v":{"_":"pixelduck.TestProtostuff$B","name":"fourth"}}]}}}
```

That data means your A's schema was used as well as B's. 

I don't see a problem here.

--
You received this message because you are subscribed to the Google Groups "protostuff" group.
To unsubscribe from this group and stop receiving emails from it, send an email to protostuff+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Olivier Martin

unread,
Mar 16, 2017, 4:39:11 PM3/16/17
to protostuff
My issue is with the Map of Objects which contains B objects: the java serialization is used.
See {"name":"A-name","mapOfB":{"mapBByString":{"e":[{"k":"second-key","v":{"name":"second"}},{"k":"first-key","v":{"name":"first"}}]}},"mapOfObject":{"mapObjectByString":{"e":[{"k":"third-key","v":{"_":"pixelduck.TestProtostuff$B","name":"third"}},{"k":"fourth-key","v":{"_":"pixelduck.TestProtostuff$B","name":"fourth"}}]}}}

Olivier Martin

unread,
Mar 16, 2017, 4:50:41 PM3/16/17
to protostuff
I just understand that indeed protostuff is used: you are saving the class  name in order to understand which class was saved in the map. And as we registered the schema for this class, you re able to read it.
What is sad is when you are using generic or a field, you can understand the data even if the class has changed as soon as the schema is using the same identifier (name and LongName)
but for collection using Object, you dont support anymore this feature.
Am I right?
It could be cool to registered a schema without the target class, use the Longname as the metadata for the map. When reading the serialized data, read this metadata, retrieve the schema registered and they create the object with the newMessage() method. with this method you dont need to save the real classname (and allow changing the classname or move the class to another package) with no impact

David Yu

unread,
Mar 17, 2017, 12:21:22 AM3/17/17
to protostuff
On Fri, Mar 17, 2017 at 4:50 AM, Olivier Martin <ekk...@gmail.com> wrote:
I just understand that indeed protostuff is used: you are saving the class  name in order to understand which class was saved in the map. And as we registered the schema for this class, you re able to read it.
What is sad is when you are using generic or a field, you can understand the data even if the class has changed as soon as the schema is using the same identifier (name and LongName)
It is wrong to change the type of the field unless it is an int changed to a long.
You have to think carefully how you evolve your schema.
It is advisable to use @Tag annotations on all your classes.
if you really have to change the type of the field, you can simply change the tag id:
@Tag(value = newNumber, alias = newName)
but for collection using Object, you dont support anymore this feature.
Am I right?
It could be cool to registered a schema without the target class, use the Longname as the metadata for the map. When reading the serialized data, read this metadata, retrieve the schema registered and they create the object with the newMessage() method. with this method you dont need to save the real classname (and allow changing the classname or move the class to another package) with no impact
If you do not want to include the fqcn, take a look at ExplicitIdStrategy.

If you still want the id to be a String rather than int, you can copy ExplicitIdStrategy and change the keys of the maps to String.

--
You received this message because you are subscribed to the Google Groups "protostuff" group.
To unsubscribe from this group and stop receiving emails from it, send an email to protostuff+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Olivier Martin

unread,
Mar 17, 2017, 10:10:45 AM3/17/17
to protostuff
I dont want to change the type, i want to support a class rename or a class move but you can view this as a field class change. In my case, i keep the same schema but the new schema use the new class. If the map was using the schema long name from method messageFullName() as a metadata, supporting renaming would work.
Let me explain this with an example:

You have a Map<String, Object>
You have a class A with a schema named SchemaA where the method messageFullName() returns "SchemaA"
You would registered the schema SchemaA using this full name somewhere. When saving the map, instead of using the long class name, you would save the messageFullName().

Imagine now you Rename your class A as NewA. The SchemaA is still returning "SchemaA" when calling messageFullName(), but now the newMessage() method create a NewA instance.
When reading the map from protostuff serialization, you see "SchemaA" as the metadata class, you can now retrieved the right schema and read the data in a NewA instance. You are able to support class renaming and class package 

David Yu

unread,
Mar 17, 2017, 10:18:00 AM3/17/17
to protostuff
On Fri, Mar 17, 2017 at 10:10 PM, Olivier Martin <ekk...@gmail.com> wrote:
I dont want to change the type, i want to support a class rename or a class move but you can view this as a field class change. In my case, i keep the same schema but the new schema use the new class.
Use ExplicitIdStrategy like I said in my last reply. 
If the map was using the schema long name from method messageFullName() as a metadata, supporting renaming would work.
If you prefer that, you can, with a custom IdStrategy (ExplicitIdStrategy as a guidline)
Let me explain this with an example:

You have a Map<String, Object>
You have a class A with a schema named SchemaA where the method messageFullName() returns "SchemaA"
You would registered the schema SchemaA using this full name somewhere. When saving the map, instead of using the long class name, you would save the messageFullName().

Imagine now you Rename your class A as NewA. The SchemaA is still returning "SchemaA" when calling messageFullName(), but now the newMessage() method create a NewA instance.
When reading the map from protostuff serialization, you see "SchemaA" as the metadata class, you can now retrieved the right schema and read the data in a NewA instance. You are able to support class renaming and class package 

--
You received this message because you are subscribed to the Google Groups "protostuff" group.
To unsubscribe from this group and stop receiving emails from it, send an email to protostuff+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Olivier Martin

unread,
Mar 17, 2017, 12:24:34 PM3/17/17
to protostuff
Ok i will have a look !
Thanks a lot for your help !
To unsubscribe from this group and stop receiving emails from it, send an email to protostuff+...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages