serialazy icon indicating copy to clipboard operation
serialazy copied to clipboard

Is it possible to serialize/deserialize array?

Open nguyenbathanh opened this issue 5 years ago • 4 comments

class Topping {
  @Serialize() public type: string;
}

class Book {
  @Serialize() public name: string;
  @Serialize() public topping: Topping[];
}

I tried and see it doesn't work.

nguyenbathanh avatar Dec 21 '18 02:12 nguyenbathanh

class Topping {
  @Serialize() public type: string;
}

class Book {
  @Serialize() public name: string;
  @Serialize() public topping: Topping[];
}

I tried and see it doesn't work.

class Book {
  @Serialize() public name: string;
  @Serialize.Custom({down: (a: Array<any>) => a, up: b => b})
  public topping: Topping[];
}

You can use this workaround

DudaevAR avatar Dec 22 '18 16:12 DudaevAR

@nguyenbathanh @DudaevAR

Automatic serialization of container types (like Map and Array) is not supported because reflection methods (reflect-metadata polyfill) do not allow to extract types of contained items. It is impossible to deserialize (inflate) new instances without knowledge about their types.

If Topping is seriablizable and you want to have recursive serialization/deserialization, then you can use something like this:

class Book {
  @Serialize.Custom({
    down: (instances: Array<Topping>) => instances.map(instance => deflate(instance)),
    up: (jsonObjs: Array<any>) => jsonObjs.map(jsonObj => inflate(Topping, jsonObj))
  })
  public topping: Topping[];
}

teq avatar Dec 24 '18 14:12 teq

I tried something like this:

function getObjectArraySerializer (type) {
    return {
        down: (instances: Array<any>) => { 
            if (!instances) { return; }
            return instances.map(instance => deflate(instance)) 
        },
        up: (jsonObjs: Array<any>) => { 
            if (!jsonObjs) { return; }
            return jsonObjs.map(jsonObj => inflate(type, jsonObj)) 
        }
    }

}

function getArraySerializer () {
    return {down: (a: Array<any>) => a, up: b => b};
}

and then

@Serialize.Custom(getObjectArraySerializer(Tag)) tags: Tag[];
@Serialize.Custom(getArraySerializer()) content_ids: string[];

So I don`t have to copy and paste the long code there everytime. What do you think, is this a good solution?

Schwankenson avatar Apr 20 '19 14:04 Schwankenson

@Schwankenson I think it is fine.

You can take one step further and reduce it to:

type Constructor<T> = new (...args: any[]) => T;

function SerializeAnArrayOf<Type>(ctor: Constructor<Type>) {
  return Serialize.Custom({
        down: (instances: Array<Type>) => { 
            if (!instances) { return; }
            return instances.map(instance => deflate(instance)) 
        },
        up: (jsonObjs: Array<any>) => { 
            if (!jsonObjs) { return; }
            return jsonObjs.map(jsonObj => inflate(ctor, jsonObj)) 
        }
  })
}

And then:

@SerializeAnArrayOf(Tag) tags: Tag[];

Eventually I will add some form of helper to construct serializers for built-in containers like Array and Map. Probably in v3.0.

teq avatar Jun 24 '19 06:06 teq