Whenever you serialize and say “Hey’ let’s use polymorphism", you are pretty much bound to fail.
Use something like a command pattern identifying what you are doing so you can pick the de-serializer. > On Aug 20, 2016, at 11:32 PM, David Leangen <[email protected]> wrote: > > > I had a few thoughts about this topic. > > In order to properly deserialise, we would need the schema. Since the DTO > type *is* the schema, then somehow the schema needs to be serialised as well, > or at least known upon serialisation. > > If the API were to have a toSchema() method, that would simplify things a > lot. A client should also be able to do something like this: > > SomeDTO dto = ... > codec.encode( dto ).serializeTo( out ); > > Or maybe: > > codec.withSchema( SomeDTO.class).encode( dto ).to( out ); > > The SomeDTO schema would also be serialised (perhaps simply using the > fully-qualified class name as an alias?), so then the client could do this: > > Object o = codec.deserializeFrom( in ) > > Since the schema is included in the input data, the serializer will behind > the scene do something like: > > > Map<String, Object> map = codec.decode( Map.class ).from( in ); > // Get the schema type, which is SomeDTO.class > ... > Object o = converter.convert( map.get(“data”) ).to( SomeDTO.class ); > > > wdyt? > > =David > > > >> On Aug 20, 2016, at 3:23 PM, David Leangen <[email protected]> wrote: >> >> >> Hi, >> >> I am trying to use the Convert/Codec as a serializer, but it has been a bit >> of a struggle so far. >> >> I have a “deep” object structure (i.e. at least one level of embedded >> objects). Writing the data as a JSON string works just fine. However, when >> deserialising, I am having trouble. The data object uses generics, so it is >> not possible to determine the type at runtime. My embedded objects end up >> being deserialised as Maps, which of course causes a ClassCastException >> later on in the code. >> >> I have tried adding a Rule using an adapter, and setting the >> codec.with(thatAdapter), but that didn’t work out so well, either. >> >> Here is an example of my attempt so far. I am working with Prevayler, so I >> need to serialize/deserialze a command object, which contains some data. >> >> I think that this code _should_ work, which means that there is likely a bug >> in the code. Even so… >> >> This is a very convoluted way of working, which doesn’t seem right to me. Am >> I missing some concept? >> >> >> Example below. >> >> Cheers, >> =David >> >> >> public class DTOSerializer<E> >> implements Serializer // This is the interface provided by Prevayler >> { >> private final Converter converter; >> private final Codec codec; >> private final Class<E> type; >> >> public DTOSerializer( Converter aConverter, Codec aCodec, Class<E> aType ) >> { >> // Very convoluted attempt at adding a rule to try to make the >> conversion of my “PutCommand” work during deserialization >> converter = aConverter.getAdapter() >> .rule( >> PutCommand.class, >> Map.class, >> dto -> { Map map = new HashMap<>(); map.put( "key", >> dto.key ); map.put( "entity", dto.entity ); return map; }, >> map -> { PutCommand c = new PutCommand(); c.key = >> (String)map.get( "key" ); c.entity = aConverter.convert( map.get( "entity" ) >> ).to( aType ); return c; } ); >> codec = aCodec.with( converter ); >> } >> >> @Override >> public Object readObject( InputStream in ) >> throws Exception >> { >> // This is the raw data >> final Map<String, Object> map = codec.decode( Map.class ).from( in ); >> // The name of the object type to cast to >> final String commandTypeName = (String)map.get( "command" ); >> final Class<?> commandType = Class.forName( commandTypeName ); >> // This indeed returns an object of the correct type, >> // HOWEVER, the embedded objects are not of the correct type, they are >> of type Map >> final Object command = converter.convert( map.get( "payload" ) ).to( >> commandType ); >> return command; >> } >> >> @Override >> public void writeObject( OutputStream out, Object object ) >> throws Exception >> { >> final Map<String, Object> map = new HashMap<>(); >> // Serialize the name of the command so I know what to cast it do when >> deserializing >> map.put( "command", object.getClass().getName() ); >> // This is the actual payload, which is nothing more than the command >> object >> map.put( "payload", object ); >> codec.encode( map ).to( out ); >> } >> } >> >
