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

[OnSerializing] / [OnDeserialized] request #785

Closed
mjshin82 opened this issue Mar 7, 2023 · 6 comments
Closed

[OnSerializing] / [OnDeserialized] request #785

mjshin82 opened this issue Mar 7, 2023 · 6 comments

Comments

@mjshin82
Copy link

mjshin82 commented Mar 7, 2023

Is your feature request related to a problem? Please describe.
The code below is the part that receives a callback when Serializing / Deserializing an object with Newtonsoft.Json.

If I can get a callback, I can easily process the data without a custom converter. It could be solved by creating a custom type converter, but it seems difficult to manage, such as having to create a separate class and adding it every time when initializing all serializers.

public class BluePrint {
    public int width;
    public int height;
    public string serializedMap = "";
    // ...
    
    [JsonIgnore] public BpTile[,] map;
    // ...

    [OnSerializing]
    private void OnSerializing(StreamingContext context) {
        var writer = new ByteWriter(100);
        writer.PutUShortLe((ushort)width);
        writer.PutUShortLe((ushort)height);
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                writer.PutUIntLe(map[y, x].Serialize());
            }
        }

        serializedMap = Convert.ToBase64String(writer.ToBytes());
    }
    
    [OnDeserialized]
    private void OnDeserialized(StreamingContext context) {
        var bytes = Convert.FromBase64String(serializedMap);
        var reader = new ByteReader(bytes);
        var w = reader.ReadUShortLe();
        var h = reader.ReadUShortLe();
        map = new BpTile[h, w];
        
        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {
                var tile = new BpTile();
                tile.Deserialize(reader.ReadUIntLe());
                map[y, x] = tile;
            }
        }
    }
}

Describe the solution you'd like

Describe alternatives you've considered

Additional context

@EdwardCooke
Copy link
Collaborator

To rephrase what I think you’re asking for is to have an optional method called on the object during different phases of the serialization and deserialization of the object? Something like when the object is first created/start of serialization, before and after the property is serialiszed/deserialized and after it is done with serialization and desreialization of the onject? Maybe even a custom method to use for construction of the object?

@cyraid
Copy link

cyraid commented Apr 18, 2023

To rephrase what I think you’re asking for is to have an optional method called on the object during different phases of the serialization and deserialization of the object? Something like when the object is first created/start of serialization, before and after the property is serialiszed/deserialized and after it is done with serialization and desreialization of the onject? Maybe even a custom method to use for construction of the object?

Like other libraries, a method that is called after deserialize for an instance of an object, and before serialization.

@cyraid
Copy link

cyraid commented Apr 19, 2023

Workaround for now would be:

var deserializer = new DeserializerBuilder()
  .WithNodeDeserializer(inner => new MyNodeDeserializer(inner), s => s.InsteadOf<ObjectNodeDeserializer>())
  .Build();

// The Interface to put on your Instance that will be called when done Deserialize //

public interface IYamlDeserializeObject {
  public void YamlDeserialize();
} // Interface //

// The Node Deserializer Class to call the Interface after Deserialize //

public class MyNodeDeserializer : INodeDeserializer {

  private INodeDeserializer nodeDeserializer;

  public MyNodeDeserializer(INodeDeserializer nodeDeserializer) {
    this.nodeDeserializer = nodeDeserializer;
  } // Constructor //

  public bool Deserialize(IParser reader, Type expectedType, Func<IParser, Type, object?> nestedObjectDeserializer, out object? value) {

    if (!nodeDeserializer.Deserialize(reader, expectedType, nestedObjectDeserializer, out value))
      return false;

    if (value is IYamlDeserializeObject ydObj)
      ydObj.YamlDeserialize();

    return true;

  } // Function //

} // Class //

You can of course do anything else at that point, like get the method that has your attribute, etc.

@mikhail-barg
Copy link

mikhail-barg commented Jul 5, 2023

While it's possible to simulate the callback behaviors with INodeDeserializer as you explained, it's kinda weird to not have it out of the box.

I've spent quite some time to find this ticket while searching for a solution

@EdwardCooke
Copy link
Collaborator

I going to put something together for this. It will probably be an interface that you can implement so it’s not a breaking change in some of the other classes and interfaces due to reflection uses to find the attributes. I’m going to do 4 methods. Onserializing, onserialized, and same for deserialized. I’ll also try and use default implementations of the methods on that interface so you will only need to implement the ones you want. Hopefully that works in the older frameworks. If not I’ll need to come up with something different, might be multiple interfaces or something.

@EdwardCooke
Copy link
Collaborator

This will go out in the next release. That's about just over a week away.

Put the attribute you want from the YamlDotNet.Serialization.Callbacks namespace on a method in the class with no arguments and it will be called. I put in onserialized, onserializing, ondeserialized and ondeserializing.

The ing ones get called before anything is done with the object. The ed ones are called after it is done with that object.

I'm closing this since the work is done and just waiting to go out.

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

No branches or pull requests

4 participants