Skip to content
Snippets Groups Projects
Commit ce51dea2 authored by Richard Marcus's avatar Richard Marcus
Browse files

added jsonsubtypes as plain folder

parent 6d214b6e
No related branches found
No related tags found
No related merge requests found
Showing
with 530 additions and 0 deletions
fileFormatVersion: 2
guid: c0b2e769528947b4ea1d7135b59c1050
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace JsonSubTypes
{
public class JsonSubtypesWithPropertyConverterBuilder
{
private readonly Type _baseType;
private readonly Dictionary<string, Type> _subTypeMapping = new Dictionary<string, Type>();
private Type _fallbackSubtype;
private JsonSubtypesWithPropertyConverterBuilder(Type baseType)
{
_baseType = baseType;
}
public static JsonSubtypesWithPropertyConverterBuilder Of(Type baseType)
{
return new JsonSubtypesWithPropertyConverterBuilder(baseType);
}
public static JsonSubtypesWithPropertyConverterBuilder Of<T>()
{
return Of(typeof(T));
}
public JsonSubtypesWithPropertyConverterBuilder RegisterSubtypeWithProperty(Type subtype, string jsonPropertyName)
{
_subTypeMapping.Add(jsonPropertyName, subtype);
return this;
}
public JsonSubtypesWithPropertyConverterBuilder RegisterSubtypeWithProperty<T>(string jsonPropertyName)
{
return RegisterSubtypeWithProperty(typeof(T), jsonPropertyName);
}
public JsonSubtypesWithPropertyConverterBuilder SetFallbackSubtype(Type fallbackSubtype)
{
_fallbackSubtype = fallbackSubtype;
return this;
}
public JsonSubtypesWithPropertyConverterBuilder SetFallbackSubtype<T>()
{
return SetFallbackSubtype(typeof(T));
}
public JsonConverter Build()
{
return new JsonSubtypesByPropertyPresenceConverter(_baseType, _subTypeMapping, _fallbackSubtype);
}
}
}
fileFormatVersion: 2
guid: 2898a10da3eecb7488d8007210c2349f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
using System;
using System.Collections.Generic;
namespace JsonSubTypes
{
public class NullableDictionary<TKey, TValue>
{
private bool _hasNullKey;
private TValue _nullKeyValue;
private readonly Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();
public bool TryGetValue(TKey key, out TValue value)
{
if (Equals(key, default(TKey)))
{
if (!_hasNullKey)
{
value = default(TValue);
return false;
}
value = _nullKeyValue;
return true;
}
return _dictionary.TryGetValue(key, out value);
}
public void Add(TKey key, TValue value)
{
if (Equals(key, default(TKey)))
{
if (_hasNullKey)
{
throw new ArgumentException();
}
_hasNullKey = true;
_nullKeyValue = value;
}
else
{
_dictionary.Add(key, value);
}
}
public IEnumerable<TKey> NotNullKeys()
{
return _dictionary.Keys;
}
public IEnumerable<KeyValuePair<TKey, TValue>> Entries()
{
if (_hasNullKey)
{
yield return new KeyValuePair<TKey, TValue>(default(TKey), _nullKeyValue);
}
foreach (var value in _dictionary)
{
yield return value;
}
}
}
}
fileFormatVersion: 2
guid: 44161e4db554878499ec521f2cb410af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net47" allowedVersions="[10.0.0, 13.0.0)" />
</packages>
fileFormatVersion: 2
guid: d16d099b804bc914982bbbd303b30755
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 1
settings: {}
userData:
assetBundleName:
assetBundleVariant:
MIT License
Copyright (c) 2017 Emmanuel Counasse
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
fileFormatVersion: 2
guid: 1a118c93a66a64e41ac1b53833cd5d3c
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
# __JsonSubTypes__
__JsonSubTypes__ is a discriminated Json sub-type Converter implementation for .NET
[![Build status](https://ci.appveyor.com/api/projects/status/g11crbl037en6rkq/branch/master?svg=true)](https://ci.appveyor.com/project/manuc66/jsonsubtypes/branch/master)
[![Code Coverage](https://codecov.io/gh/manuc66/JsonSubTypes/branch/master/graph/badge.svg)](https://codecov.io/gh/manuc66/JsonSubTypes)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=manuc66%3AJsonSubtypes&metric=alert_status)](https://sonarcloud.io/dashboard?id=manuc66%3AJsonSubtypes)
[![NuGet](https://img.shields.io/nuget/v/JsonSubTypes.svg)](https://www.nuget.org/packages/JsonSubTypes/)
[![NuGet](https://img.shields.io/nuget/dt/JsonSubTypes.svg)](https://www.nuget.org/packages/JsonSubTypes)
[![CodeFactor](https://www.codefactor.io/repository/github/manuc66/JsonSubTypes/badge)](https://www.codefactor.io/repository/github/manuc66/JsonSubTypes)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmanuc66%2FJsonSubTypes.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fmanuc66%2FJsonSubTypes?ref=badge_shield)
## DeserializeObject with custom type property name
```csharp
[JsonConverter(typeof(JsonSubtypes), "Kind")]
public interface IAnimal
{
string Kind { get; }
}
public class Dog : IAnimal
{
public string Kind { get; } = "Dog";
public string Breed { get; set; }
}
public class Cat : IAnimal {
public string Kind { get; } = "Cat";
public bool Declawed { get; set;}
}
```
The second parameter of the `JsonConverter` attribute is the JSON property name that will be use to retreive the type information from JSON.
```csharp
var animal = JsonConvert.DeserializeObject<IAnimal>("{\"Kind\":\"Dog\",\"Breed\":\"Jack Russell Terrier\"}");
Assert.AreEqual("Jack Russell Terrier", (animal as Dog)?.Breed);
```
N.B.: This only works for types in the same assembly as the base type/interface and either in the same namespace or with a fully qualified type name.
## DeserializeObject with custom type mapping
```csharp
[JsonConverter(typeof(JsonSubtypes), "Sound")]
[JsonSubtypes.KnownSubType(typeof(Dog), "Bark")]
[JsonSubtypes.KnownSubType(typeof(Cat), "Meow")]
public class Animal
{
public virtual string Sound { get; }
public string Color { get; set; }
}
public class Dog : Animal
{
public override string Sound { get; } = "Bark";
public string Breed { get; set; }
}
public class Cat : Animal
{
public override string Sound { get; } = "Meow";
public bool Declawed { get; set; }
}
```
```csharp
var animal = JsonConvert.DeserializeObject<IAnimal>("{\"Sound\":\"Bark\",\"Breed\":\"Jack Russell Terrier\"}");
Assert.AreEqual("Jack Russell Terrier", (animal as Dog)?.Breed);
```
N.B.: Also works with other kind of value than string, i.e.: enums, int, ...
## SerializeObject and DeserializeObject with custom type property only present in JSON
This mode of operation only works when JsonSubTypes is explicitely registered in JSON.NET's serializer settings, and not through the ``[JsonConverter]`` attribute.
```csharp
public abstract class Animal
{
public int Age { get; set; }
}
public class Dog : Animal
{
public bool CanBark { get; set; } = true;
}
public class Cat : Animal
{
public int Lives { get; set; } = 7;
}
public enum AnimalType
{
Dog = 1,
Cat = 2
}
```
### Registration:
```csharp
var settings = new JsonSerializerSettings();
settings.Converters.Add(JsonSubtypesConverterBuilder
.Of(typeof(Animal), "Type") // type property is only defined here
.RegisterSubtype(typeof(Cat), AnimalType.Cat)
.RegisterSubtype(typeof(Dog), AnimalType.Dog)
.SerializeDiscriminatorProperty() // ask to serialize the type property
.Build());
```
or using syntax with generics:
```csharp
var settings = new JsonSerializerSettings();
settings.Converters.Add(JsonSubtypesConverterBuilder
.Of<Animal>("Type") // type property is only defined here
.RegisterSubtype<Cat>(AnimalType.Cat)
.RegisterSubtype<Dog>(AnimalType.Dog)
.SerializeDiscriminatorProperty() // ask to serialize the type property
.Build());
```
### De-/Serialization:
```csharp
var cat = new Cat { Age = 11, Lives = 6 }
var json = JsonConvert.SerializeObject(cat, settings);
Assert.Equal("{\"Lives\":6,\"Age\":11,\"Type\":2}", json);
var result = JsonConvert.DeserializeObject<Animal>(json, settings);
Assert.Equal(typeof(Cat), result.GetType());
Assert.Equal(11, result.Age);
Assert.Equal(6, (result as Cat)?.Lives);
```
## DeserializeObject mapping by property presence
```csharp
[JsonConverter(typeof(JsonSubtypes))]
[JsonSubtypes.KnownSubTypeWithProperty(typeof(Employee), "JobTitle")]
[JsonSubtypes.KnownSubTypeWithProperty(typeof(Artist), "Skill")]
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Employee : Person
{
public string Department { get; set; }
public string JobTitle { get; set; }
}
public class Artist : Person
{
public string Skill { get; set; }
}
```
or using syntax with generics:
```csharp
string json = "[{\"Department\":\"Department1\",\"JobTitle\":\"JobTitle1\",\"FirstName\":\"FirstName1\",\"LastName\":\"LastName1\"}," +
"{\"Department\":\"Department1\",\"JobTitle\":\"JobTitle1\",\"FirstName\":\"FirstName1\",\"LastName\":\"LastName1\"}," +
"{\"Skill\":\"Painter\",\"FirstName\":\"FirstName1\",\"LastName\":\"LastName1\"}]";
var persons = JsonConvert.DeserializeObject<IReadOnlyCollection<Person>>(json);
Assert.AreEqual("Painter", (persons.Last() as Artist)?.Skill);
```
### Registration:
```cs
settings.Converters.Add(JsonSubtypesWithPropertyConverterBuilder
.Of(typeof(Person))
.RegisterSubtypeWithProperty(typeof(Employee), "JobTitle")
.RegisterSubtypeWithProperty(typeof(Artist), "Skill")
.Build());
```
or
```cs
settings.Converters.Add(JsonSubtypesWithPropertyConverterBuilder
.Of<Person>()
.RegisterSubtypeWithProperty<Employee>("JobTitle")
.RegisterSubtypeWithProperty<Artist>("Skill")
.Build());
```
## A default class other than the base type can be defined
```cs
[JsonConverter(typeof(JsonSubtypes))]
[JsonSubtypes.KnownSubType(typeof(ConstantExpression), "Constant")]
[JsonSubtypes.FallBackSubType(typeof(UnknownExpression))]
public interface IExpression
{
string Type { get; }
}
```
Or with code configuration:
```cs
settings.Converters.Add(JsonSubtypesConverterBuilder
.Of(typeof(IExpression), "Type")
.SetFallbackSubtype(typeof(UnknownExpression))
.RegisterSubtype(typeof(ConstantExpression), "Constant")
.Build());
```
```cs
settings.Converters.Add(JsonSubtypesWithPropertyConverterBuilder
.Of(typeof(IExpression))
.SetFallbackSubtype(typeof(UnknownExpression))
.RegisterSubtype(typeof(ConstantExpression), "Value")
.Build());
```
## 💖 Support this project
If this project helped you save money or time or simply makes your life also easier, you can give me a cup of coffee =)
- [![Support via PayPal](https://cdn.rawgit.com/twolfson/paypal-github-button/1.0.0/dist/button.svg)](https://www.paypal.me/manuc66)
- Bitcoin — You can send me bitcoins at this address: `33gxVjey6g4Beha26fSQZLFfWWndT1oY3F`
## License
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmanuc66%2FJsonSubTypes.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fmanuc66%2FJsonSubTypes?ref=badge_large)
\ No newline at end of file
fileFormatVersion: 2
guid: ca5ac66561eb3414baa24690951449ad
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
theme: jekyll-theme-leap-day
\ No newline at end of file
fileFormatVersion: 2
guid: fbec9b4469d2fab4b9aab435aeb78e29
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
image: Visual Studio 2017
environment:
sonar_token:
secure: 4M8z89LHqy9Rho8Mi4i7V0Ajz/7kvDYolVFH2V0GjK5VO5dseuv2Dja/qmKbio1I
github_auth_token:
secure: XUib5rF8Uxwk7S2umtsFEQ9t5G0p/J3G3PNpWLZuNIyw/zNufLDCge8C6QJRTzQw
init:
- choco install opencover.portable
- choco install codecov
- choco install "sonarscanner-msbuild-net46" -y
before_build:
- nuget restore
- ps: >-
if ($env:APPVEYOR_PULL_REQUEST_NUMBER) {
SonarScanner.MSBuild.exe begin /k:"manuc66:JsonSubtypes" /d:"sonar.host.url=https://sonarcloud.io" /o:"manuc66-github" /d:"sonar.login=$env:sonar_token" /d:sonar.cs.opencover.reportsPaths=".\MyProject_coverage.xml" /d:sonar.cs.nunit.reportsPaths="nunitTestResult.xml" /d:"sonar.cpd.exclusions=**/*Tests.cs" /d:"sonar.language=cs" /d:"sonar.pullrequest.base=master" /d:"sonar.pullrequest.branch=$env:APPVEYOR_REPO_BRANCH" /d:"sonar.pullrequest.key=$env:APPVEYOR_PULL_REQUEST_NUMBER" /d:"sonar.pullrequest.provider=GitHub" /d:"sonar.pullrequest.github.repository=$env:APPVEYOR_REPO_NAME" /d:"sonar.github.oauth=$env:github_auth_token"
}
elseif ($env:APPVEYOR_REPO_BRANCH -eq "master") {
SonarScanner.MSBuild.exe begin /k:"manuc66:JsonSubtypes" /d:"sonar.host.url=https://sonarcloud.io" /o:"manuc66-github" /d:"sonar.login=$env:sonar_token" /d:sonar.cs.opencover.reportsPaths=".\MyProject_coverage.xml" /d:sonar.cs.nunit.reportsPaths="nunitTestResult.xml" /d:"sonar.cpd.exclusions=**/*Tests.cs" /d:"sonar.language=cs"
}
else {
SonarScanner.MSBuild.exe begin /k:"manuc66:JsonSubtypes" /d:"sonar.host.url=https://sonarcloud.io" /o:"manuc66-github" /d:"sonar.login=$env:sonar_token" /d:"sonar.branch.name=$env:APPVEYOR_REPO_BRANCH" /d:"sonar.branch.target=master" /d:sonar.cs.opencover.reportsPaths=".\MyProject_coverage.xml" /d:sonar.cs.nunit.reportsPaths="nunitTestResult.xml" /d:"sonar.cpd.exclusions=**/*Tests.cs" /d:"sonar.language=cs"
}
configuration: Release
nuget:
disable_publish_on_pr: true
build:
project: JsonSubTypes.sln
verbosity: minimal
test_script:
- dir /S JsonSubTypes\bin\Release
- dir /S JsonSubTypes.Tests\bin\Release
- OpenCover.Console.exe -register:admin -target:"nunit3-console.exe" -targetargs:".\JsonSubTypes.Tests\bin\Release\net46\JsonSubTypes.Tests.dll --result:nunitTestResult.xml" -filter:"+[JsonSubTypes*]* -[JsonSubTypes.Tests]*" -output:".\MyProject_coverage.xml"
- codecov -f "MyProject_coverage.xml"
after_test:
- ps: SonarScanner.MSBuild.exe end /d:"sonar.login=$env:sonar_token"
artifacts:
# pushing all *.nupkg files in build directory recursively
- path: 'JsonSubTypes\**\*.nupkg'
deploy:
- provider: NuGet
name: NuGet
server: https://www.nuget.org/api/v2/package
api_key:
secure: I8mGPBaVaAK9e3mBzOBoqQLdPckvVYvSJqFc2BE7/P7UF3P3OqHkxUAa1/PAARuy
artifact: /JsonSubTypes.*\.nupkg/
on:
branch: master
fileFormatVersion: 2
guid: 2ac5533b3a05efc48b47585a01cec60b
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment