using Amazon.Lambda.Serialization.SystemTextJson.Converters;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Amazon.Lambda.Serialization.SystemTextJson
{
///
/// Base class of serializers using System.Text.Json
///
public abstract class AbstractLambdaJsonSerializer
{
private const string DEBUG_ENVIRONMENT_VARIABLE_NAME = "LAMBDA_NET_SERIALIZER_DEBUG";
private readonly bool _debug;
///
/// Options settings used for the JSON writer
///
protected JsonWriterOptions WriterOptions { get; }
///
/// Create instance
///
///
protected AbstractLambdaJsonSerializer(Action jsonWriterCustomizer)
{
WriterOptions = new JsonWriterOptions()
{
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
jsonWriterCustomizer?.Invoke(this.WriterOptions);
this._debug = string.Equals(Environment.GetEnvironmentVariable(DEBUG_ENVIRONMENT_VARIABLE_NAME), "true",
StringComparison.OrdinalIgnoreCase);
}
///
/// Serializes a particular object to a stream.
///
/// Type of object to serialize.
/// Object to serialize.
/// Output stream.
public void Serialize(T response, Stream responseStream)
{
try
{
if (_debug)
{
using (var debugStream = new MemoryStream())
using (var utf8Writer = new Utf8JsonWriter(debugStream, WriterOptions))
{
InternalSerialize(utf8Writer, response);
debugStream.Position = 0;
using var debugReader = new StreamReader(debugStream);
var jsonDocument = debugReader.ReadToEnd();
Console.WriteLine($"Lambda Serialize {response.GetType().FullName}: {jsonDocument}");
var writer = new StreamWriter(responseStream);
writer.Write(jsonDocument);
writer.Flush();
}
}
else
{
using (var writer = new Utf8JsonWriter(responseStream, WriterOptions))
{
InternalSerialize(writer, response);
}
}
}
catch (Exception e)
{
throw new JsonSerializerException($"Error converting the response object of type {typeof(T).FullName} from the Lambda function to JSON: {e.Message}", e);
}
}
///
/// Deserializes a stream to a particular type.
///
/// Type of object to deserialize to.
/// Stream to serialize.
/// Deserialized object from stream.
public T Deserialize(Stream requestStream)
{
try
{
byte[] utf8Json = null;
if (_debug)
{
var json = new StreamReader(requestStream).ReadToEnd();
Console.WriteLine($"Lambda Deserialize {typeof(T).FullName}: {json}");
utf8Json = UTF8Encoding.UTF8.GetBytes(json);
}
if (utf8Json == null)
{
if (requestStream is MemoryStream ms)
{
utf8Json = ms.ToArray();
}
else
{
using (var copy = new MemoryStream())
{
requestStream.CopyTo(copy);
utf8Json = copy.ToArray();
}
}
}
return InternalDeserialize(utf8Json);
}
catch (Exception e)
{
throw new JsonSerializerException($"Error converting the Lambda event JSON payload to type {typeof(T).FullName}: {e.Message}", e);
}
}
///
/// Create the default instance of JsonSerializerOptions used in serializer
///
///
protected virtual JsonSerializerOptions CreateDefaultJsonSerializationOptions()
{
var serializer = new JsonSerializerOptions()
{
#if NET6_0_OR_GREATER
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
#else
IgnoreNullValues = true,
#endif
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = new AwsNamingPolicy(),
Converters =
{
new DateTimeConverter(),
new MemoryStreamConverter(),
new ConstantClassConverter(),
new ByteArrayConverter()
}
};
return serializer;
}
///
/// Perform the actual serialization after the public method had done the safety checks.
///
///
///
///
protected abstract void InternalSerialize(Utf8JsonWriter writer, T response);
///
/// Perform the actual deserialization after the public method had done the safety checks.
///
///
///
///
protected abstract T InternalDeserialize(byte[] utf8Json);
}
}