Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit 4708869

Browse files
committed
Resolve scoped TypeAttr
1 parent eac56b5 commit 4708869

File tree

5 files changed

+53
-15
lines changed

5 files changed

+53
-15
lines changed

src/ServiceStack.Text/Common/DeserializeTypeRefJson.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ internal static class DeserializeTypeRefJson
88
{
99
private static readonly JsonTypeSerializer Serializer = (JsonTypeSerializer)JsonTypeSerializer.Instance;
1010

11-
static readonly ReadOnlyMemory<char> typeAttr = JsWriter.TypeAttr.AsMemory();
12-
1311
internal static object StringToType(ReadOnlySpan<char> strType,
1412
TypeConfig typeConfig,
1513
EmptyCtorDelegate ctorFn,
@@ -34,6 +32,7 @@ internal static object StringToType(ReadOnlySpan<char> strType,
3432
return ctorFn();
3533

3634
var config = JsConfig.GetConfig();
35+
var typeAttr = config.TypeAttrMemory;
3736

3837
object instance = null;
3938
var lenient = config.PropertyConvention == PropertyConvention.Lenient;

src/ServiceStack.Text/JsConfig.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -406,21 +406,17 @@ public static string TypeAttr
406406
{
407407
var config = Config.AssertNotInit();
408408
config.TypeAttr = value;
409-
config.JsonTypeAttrInObject = JsonTypeSerializer.GetTypeAttrInObject(value);
410-
config.JsvTypeAttrInObject = JsvTypeSerializer.GetTypeAttrInObject(value);
411409
}
412410
}
413411

414412
internal static string JsonTypeAttrInObject
415413
{
416414
get => JsConfigScope.Current != null ? JsConfigScope.Current.JsonTypeAttrInObject : Config.Instance.JsonTypeAttrInObject;
417-
set => Config.AssertNotInit().JsonTypeAttrInObject = value;
418415
}
419416

420417
internal static string JsvTypeAttrInObject
421418
{
422419
get => JsConfigScope.Current != null ? JsConfigScope.Current.JsvTypeAttrInObject : Config.Instance.JsvTypeAttrInObject;
423-
set => Config.AssertNotInit().JsvTypeAttrInObject = value;
424420
}
425421

426422
public static Func<Type, string> TypeWriter

src/ServiceStack.Text/JsConfigScope.cs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,27 @@ private Config(Config config)
120120
public bool TreatEnumAsInteger { get; set; }
121121
public bool ExcludeTypeInfo { get; set; }
122122
public bool IncludeTypeInfo { get; set; }
123-
public string TypeAttr { get; set; }
123+
124+
private string typeAttr;
125+
public string TypeAttr
126+
{
127+
get => typeAttr;
128+
set
129+
{
130+
typeAttrSpan = null;
131+
jsonTypeAttrInObject = null;
132+
jsvTypeAttrInObject = null;
133+
typeAttr = value;
134+
}
135+
}
136+
ReadOnlyMemory<char>? typeAttrSpan = null;
137+
public ReadOnlyMemory<char> TypeAttrMemory => typeAttrSpan ??= TypeAttr.AsMemory();
124138
public string DateTimeFormat { get; set; }
125-
internal string JsonTypeAttrInObject { get; set; }
126-
internal string JsvTypeAttrInObject { get; set; }
139+
private string jsonTypeAttrInObject;
140+
internal string JsonTypeAttrInObject => jsonTypeAttrInObject ??= JsonTypeSerializer.GetTypeAttrInObject(TypeAttr);
141+
private string jsvTypeAttrInObject;
142+
internal string JsvTypeAttrInObject => jsvTypeAttrInObject ??= JsvTypeSerializer.GetTypeAttrInObject(TypeAttr);
143+
127144
public Func<Type, string> TypeWriter { get; set; }
128145
public Func<string, Type> TypeFinder { get; set; }
129146
public Func<string, object> ParsePrimitiveFn { get; set; }
@@ -180,8 +197,6 @@ public bool EmitLowercaseUnderscoreNames
180197
IncludeTypeInfo = false,
181198
TypeAttr = JsWriter.TypeAttr,
182199
DateTimeFormat = null,
183-
JsonTypeAttrInObject = JsonTypeSerializer.GetTypeAttrInObject(JsWriter.TypeAttr),
184-
JsvTypeAttrInObject = JsvTypeSerializer.GetTypeAttrInObject(JsWriter.TypeAttr),
185200
TypeWriter = AssemblyUtils.WriteType,
186201
TypeFinder = AssemblyUtils.FindType,
187202
ParsePrimitiveFn = null,
@@ -222,8 +237,6 @@ public Config Populate(Config config)
222237
IncludeTypeInfo = config.IncludeTypeInfo;
223238
TypeAttr = config.TypeAttr;
224239
DateTimeFormat = config.DateTimeFormat;
225-
JsonTypeAttrInObject = config.JsonTypeAttrInObject;
226-
JsvTypeAttrInObject = config.JsvTypeAttrInObject;
227240
TypeWriter = config.TypeWriter;
228241
TypeFinder = config.TypeFinder;
229242
ParsePrimitiveFn = config.ParsePrimitiveFn;

src/ServiceStack.Text/TypeConfig.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ public static class TypeConfig<T>
3030
{
3131
internal static TypeConfig config;
3232

33-
static TypeConfig Config =>
34-
config ?? (config = Create());
33+
static TypeConfig Config => config ??= Create();
3534

3635
public static PropertyInfo[] Properties
3736
{

tests/ServiceStack.Text.Tests/RuntimeSerializationTests.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,37 @@ public void Can_serialize_JS_literal_into_DTO()
300300
JS.UnConfigure();
301301
}
302302

303+
[Test]
304+
public void ServiceStack_AllowRuntimeType()
305+
{
306+
// Initialize static delegate to allow all types to be deserialized with the type attribute
307+
JsConfig.AllowRuntimeType = _ => true;
308+
JsConfig.TypeAttr = "$type";
309+
var example = new Example { Property = new MyProperty { Value = "Hello serializer" } };
310+
311+
var serialized = JsonSerializer.SerializeToString(example);
312+
var deserialized = JsonSerializer.DeserializeFromString<Example>(serialized);
313+
Assert.IsNotNull(deserialized?.Property);
314+
315+
// Now the same process with a config scope that has a TypeAttr that differs from the global TypeAttr value
316+
using var scope = JsConfig.With(new Config { TypeAttr = "_type" });
317+
serialized = JsonSerializer.SerializeToString(example);
318+
deserialized = JsonSerializer.DeserializeFromString<Example>(serialized);
319+
Assert.IsNotNull(deserialized?.Property);
320+
321+
JsConfig.Reset();
322+
}
303323

324+
private class Example
325+
{
326+
public IProperty Property { get; set; }
327+
}
328+
private interface IProperty
329+
{
330+
}
331+
private class MyProperty : IProperty
332+
{
333+
public string Value { get; set; }
334+
}
304335
}
305336
}

0 commit comments

Comments
 (0)