Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Serializer / Deserialiser caching does not work with Generic Classes / minimised bundles #2

Closed
ironchimp opened this issue Mar 14, 2017 · 4 comments
Assignees

Comments

@ironchimp
Copy link
Contributor

Hi,

firstly, thanks for the library - it fits my needs perfectly, however I have encountered a couple of blockers related to the caching of custom de/serializer objects.

From my debugging, it seems that the caching logic uses a function over the string representation of the instantiation method of de/serializer. Under the following circumstances, this results in the incorrect de/serializer being used:

1. Generic classes as custom de/serializers

As I use a lot of ES6 Maps / Sets in my project, I wrote a generic marshalling class to deal with the de/serialisation of the collection. However, the identifier used for the entry into the cache map does not include the generic type specifier.

Example:
Given the following generic Set deserializer definition:

export class SetMarshaller<EntryType> implements Deserializer, Serializer {
  type: {new (): EntryType};

  public constructor(type: {new (): EntryType}) {
    this.type = type;
  }

  public deserialize(values: string[]): Set<EntryType> {
    const setToReturn: Set<EntryType> = new Set();
    if (values) {
      values.forEach(entry => {
        setToReturn.add(ObjectMapper.deserialize(this.type, entry));
      });
    }
    return setToReturn;
  }

  public serialize(value: Set<EntryType>): string {
    const results = [];
    value.forEach(entry => {
      let obj: any = entry;
      if (isObject(entry)) {
        obj = ObjectMapper.serialize(entry).toString();
      }
      results.push(JSON.parse(obj));
    });
    return JSON.stringify(results);
  }

}

Both of the following instantiations will result in the same identifier being used in the cache map:

SetMarshaller<MyCusomObject1>;  // identifier: 'SetMarshaller'
SetMarshaller<YetAnotherCustomObject>; // identifier: 'SetMarshaller'

This will result in every set marshaller using the instanced used for the first encountered SetMashaller during execution of the app.

2. Production builds under Angular CLI

The identity mechanism shows interesting behaviour when running a production build generated by angular-cli.

Specifically, the minification and uglification mechanism replaces the named constructors with generated functions, which obscures the actual name of the construction function, resulting in more frequent clashes in the caching mechanism.

Request

Is it possible to implement some way to allow my de/serializer implementations to specify their own identify function?

Thanks,
Paul Wallace

@shakilsiraj shakilsiraj self-assigned this Mar 17, 2017
@shakilsiraj
Copy link
Owner

Hi there,

I see what you mean. I can give you two options - I can either add a class decorator or add an optional entry into @JsonProperty decorator. Either of which will not result in a breaking build. What's your thoughts on that?

Thanks, Shakil

@ironchimp
Copy link
Contributor Author

ironchimp commented Mar 19, 2017 via email

@shakilsiraj
Copy link
Owner

shakilsiraj commented Mar 24, 2017

Hi Paul,

Can you please upgrade to v 1.4.0 to test out the class decorator @Cachekey? This should solve the problem. Here is an example:

@CacheKey("TestSerializerDeserializerCacheKey")
class TestSerializerDeserializer implements Serializer, Deserializer {
  deserialize = (value: any): any => {

            }
            serialize = (value: any): any => {

            }
        }

        let instance: TestSerializerDeserializer = getOrCreateDeserializer(TestSerializerDeserializer);
        expect(deserializers["TestSerializerDeserializerCacheKey"]).toBeDefined();
        expect(deserializers["TestSerializerDeserializerCacheKey"]).toBe(instance);

        instance = getOrCreateSerializer(TestSerializerDeserializer);
        expect(serializers["TestSerializerDeserializerCacheKey"]).toBeDefined();
        expect(serializers["TestSerializerDeserializerCacheKey"]).toBe(instance);

Thanks, Shakil

@ironchimp
Copy link
Contributor Author

Hi,

The decorator function works well, thanks!

Paul

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants