Skip to content

Commit 7a6fd8d

Browse files
piasteroji
authored andcommitted
Add optional settings to JSON.NET plugin
1 parent b38b713 commit 7a6fd8d

4 files changed

Lines changed: 84 additions & 15 deletions

File tree

src/Npgsql.Json.NET/JsonHandler.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,19 @@ namespace Npgsql.Json.NET
3333
{
3434
public class JsonHandlerFactory : NpgsqlTypeHandlerFactory<string>
3535
{
36+
readonly JsonSerializerSettings _settings;
37+
38+
public JsonHandlerFactory(JsonSerializerSettings settings) => _settings = settings;
39+
3640
protected override NpgsqlTypeHandler<string> Create(NpgsqlConnection conn)
37-
=> new JsonHandler(conn);
41+
=> new JsonHandler(conn, _settings);
3842
}
3943

4044
class JsonHandler : Npgsql.TypeHandlers.TextHandler
4145
{
42-
public JsonHandler(NpgsqlConnection connection)
43-
: base(connection) {}
46+
readonly JsonSerializerSettings _settings;
47+
48+
public JsonHandler(NpgsqlConnection connection, JsonSerializerSettings settings) : base(connection) => _settings = settings;
4449

4550
protected override async ValueTask<T> Read<T>(NpgsqlReadBuffer buf, int len, bool async, FieldDescription fieldDescription = null)
4651
{
@@ -49,7 +54,7 @@ protected override async ValueTask<T> Read<T>(NpgsqlReadBuffer buf, int len, boo
4954
return (T)(object)s;
5055
try
5156
{
52-
return JsonConvert.DeserializeObject<T>(s);
57+
return JsonConvert.DeserializeObject<T>(s, _settings);
5358
}
5459
catch (Exception e)
5560
{
@@ -73,7 +78,7 @@ protected override int ValidateObjectAndGetLength(object value, ref NpgsqlLength
7378
var s = value as string;
7479
if (s == null)
7580
{
76-
s = JsonConvert.SerializeObject(value);
81+
s = JsonConvert.SerializeObject(value, _settings);
7782
if (parameter != null)
7883
parameter.ConvertedValue = s;
7984
}
@@ -84,7 +89,7 @@ protected override Task WriteObjectWithLength(object value, NpgsqlWriteBuffer bu
8489
{
8590
if (parameter?.ConvertedValue != null)
8691
value = parameter.ConvertedValue;
87-
var s = value as string ?? JsonConvert.SerializeObject(value);
92+
var s = value as string ?? JsonConvert.SerializeObject(value, _settings);
8893
return base.WriteObjectWithLength(s, buf, lengthCache, parameter, async);
8994
}
9095
}

src/Npgsql.Json.NET/JsonbHandler.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,19 @@ namespace Npgsql.Json.NET
3333
{
3434
public class JsonbHandlerFactory : NpgsqlTypeHandlerFactory<string>
3535
{
36+
readonly JsonSerializerSettings _settings;
37+
38+
public JsonbHandlerFactory(JsonSerializerSettings settings) => _settings = settings;
39+
3640
protected override NpgsqlTypeHandler<string> Create(NpgsqlConnection conn)
37-
=> new JsonbHandler(conn);
41+
=> new JsonbHandler(conn, _settings);
3842
}
3943

4044
class JsonbHandler : Npgsql.TypeHandlers.JsonbHandler
4145
{
42-
public JsonbHandler(NpgsqlConnection connection)
43-
: base(connection) {}
46+
readonly JsonSerializerSettings _settings;
47+
48+
public JsonbHandler(NpgsqlConnection connection, JsonSerializerSettings settings) : base(connection) => _settings = settings;
4449

4550
protected override async ValueTask<T> Read<T>(NpgsqlReadBuffer buf, int len, bool async, FieldDescription fieldDescription = null)
4651
{
@@ -49,7 +54,7 @@ protected override async ValueTask<T> Read<T>(NpgsqlReadBuffer buf, int len, boo
4954
return (T)(object)s;
5055
try
5156
{
52-
return JsonConvert.DeserializeObject<T>(s);
57+
return JsonConvert.DeserializeObject<T>(s, _settings);
5358
}
5459
catch (Exception e)
5560
{
@@ -73,7 +78,7 @@ protected override int ValidateObjectAndGetLength(object value, ref NpgsqlLength
7378
var s = value as string;
7479
if (s == null)
7580
{
76-
s = JsonConvert.SerializeObject(value);
81+
s = JsonConvert.SerializeObject(value, _settings);
7782
if (parameter != null)
7883
parameter.ConvertedValue = s;
7984
}
@@ -84,7 +89,7 @@ protected override Task WriteObjectWithLength(object value, NpgsqlWriteBuffer bu
8489
{
8590
if (parameter?.ConvertedValue != null)
8691
value = parameter.ConvertedValue;
87-
var s = value as string ?? JsonConvert.SerializeObject(value);
92+
var s = value as string ?? JsonConvert.SerializeObject(value, _settings);
8893
return base.WriteObjectWithLength(s, buf, lengthCache, parameter, async);
8994
}
9095
}

src/Npgsql.Json.NET/NpgsqlJsonNetExtensions.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
using Npgsql.Json.NET;
2626
using Npgsql.TypeMapping;
2727
using NpgsqlTypes;
28+
using Newtonsoft.Json;
2829

2930
// ReSharper disable once CheckNamespace
3031
namespace Npgsql
@@ -40,22 +41,28 @@ public static class NpgsqlJsonNetExtensions
4041
/// <param name="mapper">The type mapper to set up (global or connection-specific)</param>
4142
/// <param name="jsonbClrTypes">A list of CLR types to map to PostgreSQL jsonb (no need to specify NpgsqlDbType.Jsonb)</param>
4243
/// <param name="jsonClrTypes">A list of CLR types to map to PostgreSQL json (no need to specify NpgsqlDbType.Json)</param>
43-
public static INpgsqlTypeMapper UseJsonNet(this INpgsqlTypeMapper mapper, Type[] jsonbClrTypes = null, Type[] jsonClrTypes = null)
44+
/// <param name="settings">Optional settings to customize JSON serialization</param>
45+
public static INpgsqlTypeMapper UseJsonNet(
46+
this INpgsqlTypeMapper mapper,
47+
Type[] jsonbClrTypes = null,
48+
Type[] jsonClrTypes = null,
49+
JsonSerializerSettings settings = null
50+
)
4451
{
4552
mapper.AddMapping(new NpgsqlTypeMappingBuilder
4653
{
4754
PgTypeName = "jsonb",
4855
NpgsqlDbType = NpgsqlDbType.Jsonb,
4956
ClrTypes = jsonbClrTypes,
50-
TypeHandlerFactory = new JsonbHandlerFactory()
57+
TypeHandlerFactory = new JsonbHandlerFactory(settings)
5158
}.Build());
5259

5360
mapper.AddMapping(new NpgsqlTypeMappingBuilder
5461
{
5562
PgTypeName = "json",
5663
NpgsqlDbType = NpgsqlDbType.Json,
5764
ClrTypes = jsonClrTypes,
58-
TypeHandlerFactory = new JsonHandlerFactory()
65+
TypeHandlerFactory = new JsonHandlerFactory(settings)
5966
}.Build());
6067

6168
return mapper;

test/Npgsql.PluginTests/JsonNetTests.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,58 @@ public void RoundtripClrArray()
161161
}
162162
}
163163

164+
class DateWrapper
165+
{
166+
public System.DateTime Date;
167+
public override bool Equals(object obj) => (obj as DateWrapper)?.Date == Date;
168+
public override int GetHashCode() => Date.GetHashCode();
169+
}
170+
171+
void RoundtripCustomSerializerSettings(bool asJsonb)
172+
{
173+
var expected = new DateWrapper() { Date = new System.DateTime(2018, 04, 20) };
174+
175+
var settings = new JsonSerializerSettings()
176+
{
177+
DateFormatString = @"T\he d\t\h o\f MMMM, yyyy"
178+
};
179+
180+
// If we serialize to JSONB, Postgres will not store the Json.NET formatting, and will add a space after ':'
181+
var expectedString = asJsonb ? "{\"Date\": \"The 20th of April, 2018\"}"
182+
: "{\"Date\":\"The 20th of April, 2018\"}";
183+
184+
using (var conn = OpenConnection())
185+
{
186+
if (asJsonb)
187+
{
188+
conn.TypeMapper.UseJsonNet(jsonbClrTypes : new[] { typeof(DateWrapper) }, settings : settings);
189+
}
190+
else
191+
{
192+
conn.TypeMapper.UseJsonNet(jsonClrTypes : new[] { typeof(DateWrapper) }, settings : settings);
193+
}
194+
195+
using (var cmd = new NpgsqlCommand($@"SELECT @p::{_pgTypeName}, @p::text", conn))
196+
{
197+
cmd.Parameters.AddWithValue("p", expected);
198+
using (var reader = cmd.ExecuteReader())
199+
{
200+
reader.Read();
201+
var actual = reader.GetFieldValue<DateWrapper>(0);
202+
var actualString = reader.GetFieldValue<string>(1);
203+
Assert.That(actual, Is.EqualTo(expected));
204+
Assert.That(actualString, Is.EqualTo(expectedString));
205+
}
206+
}
207+
}
208+
}
209+
210+
[Test]
211+
public void RoundtripJsonbCustomSerializerSettings() => RoundtripCustomSerializerSettings(asJsonb : true);
212+
213+
[Test]
214+
public void RoundtripJsonCustomSerializerSettings() => RoundtripCustomSerializerSettings(asJsonb : false);
215+
164216
protected override NpgsqlConnection OpenConnection(string connectionString = null)
165217
{
166218
var conn = base.OpenConnection(connectionString);

0 commit comments

Comments
 (0)