[c#] Fully support uint64 in JSON when possible

Use Newtonsoft's JSON.NET BigInteger support -- when available -- to
handle the full range of uint64 values in the SimpleJson protocol (.NET
4.5 or greater, .NET Standard 1.6 or greater).
This commit is contained in:
Chad Walters 2017-07-12 18:50:58 -07:00 коммит произвёл Christopher Warrington
Родитель d80983ac3f
Коммит 350e0d7bb0
17 изменённых файлов: 96 добавлений и 35 удалений

Просмотреть файл

@ -31,6 +31,9 @@ different versioning scheme, following the Haskell community's
### C# ###
* Reflection.IsBonded now recognizes custom IBonded implementations.
* Use Newtonsoft's JSON.NET BigInteger support -- when available -- to
handle the full range of uint64 values in the SimpleJson protocol (.NET
4.5 or greater, .NET Standard 1.6 or greater).
## 6.0.0: 2017-06-29 ##
* `gbc` & compiler library: 0.10.0.0

Просмотреть файл

@ -298,6 +298,9 @@
nunit-console-x86 /framework:net-4.5 /labels "cs\test\core\bin\debug\net45\${env:BOND_OUTPUT}\Bond.UnitTest.dll" cs\test\internal\bin\debug\net45\Bond.InternalTest.dll
if (-not $?) { throw "tests failed" }
nunit-console-x86 /framework:net-4.5 /labels "cs\test\core\bin\debug\net45-nonportable\${env:BOND_OUTPUT}\Bond.UnitTest.dll"
if (-not $?) { throw "tests failed" }
& examples\cs\grpc\pingpong\bin\Debug\pingpong.exe
if (-not $?) { throw "tests failed" }

Просмотреть файл

@ -33,8 +33,6 @@ call cmake $(ProjectDir)\..\compiler -Wno-dev
if %errorlevel% neq 0 goto :cmEnd
call cmake --build $(OutDir) --target gbc
if %errorlevel% neq 0 goto :cmEnd
copy $(OutDir)\build\gbc\gbc.exe $(ProjectDir)\tools\
if %errorlevel% neq 0 goto :cmEnd
:cmEnd
endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
:cmErrorLevel
@ -81,4 +79,7 @@ if %errorlevel% neq 0 goto :VCEnd
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cs\Grpc_cs.hs" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Target Name="AfterBuild">
<Copy SourceFiles="$(OutDir)\build\gbc\gbc.exe" DestinationFolder="$(ProjectDir)\tools\" />
</Target>
</Project>

Просмотреть файл

@ -10,10 +10,10 @@
</PropertyGroup>
<Import Project="..\nuget\Common.props" />
<PropertyGroup Condition="'$(BuildFramework)' == ''">
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<BuildFramework>net45</BuildFramework>
</PropertyGroup>
<PropertyGroup>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<OutputPath>bin\$(BuildType)\$(BuildFramework)</OutputPath>
<IntermediateOutputPath>obj\$(BuildType)\$(BuildFramework)</IntermediateOutputPath>
<FileAlignment>512</FileAlignment>

Просмотреть файл

@ -18,5 +18,6 @@
</ItemGroup>
<Target Name="AfterBuild">
<Copy SourceFiles="$(TargetPath);@(FileToCopy)" DestinationFolder="$(BOND_BINARY_PATH)\$(BuildFramework)" Condition="'$(BondRedistributable)' == 'true'" />
<MSBuild Condition="'$(BuildFramework)' == 'net45' and ('$(HasNonportableVersion)' == 'true')" Projects="$(MSBuildProjectFile)" Properties="BuildNonportable=true" RunEachTargetSeparately="true" />
</Target>
</Project>

Просмотреть файл

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildThisFileDirectory)\Common.Internal.props" />
<PropertyGroup Condition="'$(BuildFramework)' == 'net45'">
<PropertyGroup>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile78</TargetFrameworkProfile>
</PropertyGroup>

Просмотреть файл

@ -37,10 +37,10 @@
"dependencies": {
"attributes": "1.0.0-*",
"core": "1.0.0-*",
"reflection": "1.0.0-*",
"Newtonsoft.Json": {
"version": "9.0.1"
},
"reflection": "1.0.0-*"
}
},
"frameworks": {
"netstandard1.0": {
@ -49,6 +49,11 @@
}
},
"netstandard1.6": {
"buildOptions": {
"define": [
"SUPPORTS_BIGINTEGER"
]
},
"dependencies": {
"NETStandard.Library": "1.6.0"
}

Просмотреть файл

@ -9,7 +9,7 @@
"gen/*.cs"
]
},
"debugType": "portable",
"debugType": "net45",
"nowarn": [
"CS1591"
],
@ -39,7 +39,10 @@
"io": "1.0.0-*",
"json": "1.0.0-*",
"NUnit": "3.4.0",
"reflection": "1.0.0-*"
"reflection": "1.0.0-*",
"Newtonsoft.Json": {
"version": "10.0.1"
}
},
"frameworks": {
"netcoreapp1.0": {
@ -47,6 +50,11 @@
"netcoreapp1.0",
"portable-net45+win8"
],
"buildOptions": {
"define": [
"SUPPORTS_BIGINTEGER"
]
},
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0-*",

Просмотреть файл

@ -121,7 +121,7 @@
</ItemGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\portable-net45+wp80+win8+wpa81\Newtonsoft.Json.dll</HintPath>
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>

Просмотреть файл

@ -28,9 +28,9 @@
</dependencies>
</metadata>
<files>
<file target="lib\net45" src="net45\Bond.JSON.dll" />
<file target="lib\net45" src="net45\Bond.JSON.pdb" />
<file target="lib\net45" src="net45\Bond.JSON.xml" />
<file target="lib\net45" src="net45-nonportable\Bond.JSON.dll" />
<file target="lib\net45" src="net45-nonportable\Bond.JSON.pdb" />
<file target="lib\net45" src="net45-nonportable\Bond.JSON.xml" />
<file target="lib\netstandard1.0" src="netstandard1.0\Bond.JSON.dll" />
<file target="lib\netstandard1.0" src="netstandard1.0\Bond.JSON.pdb" />

Просмотреть файл

@ -3,7 +3,7 @@
<package id="Bond.Core.CSharp" version="6.0.0" targetFramework="net45" />
<package id="Bond.CSharp" version="6.0.0" targetFramework="net45" />
<package id="Bond.Runtime.CSharp" version="6.0.0" targetFramework="net45" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="portable-net45+wp80+win8+wpa81" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
<package id="NUnit" version="2.6.4" targetFramework="portable-net45+wp80+win" />
<package id="NUnitTestAdapter" version="2.0.0" targetFramework="net45" />
</packages>

Просмотреть файл

@ -1,7 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath32)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath32)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildThisFileDirectory)\..\..\build\internal\Portable.Internal.props" />
<PropertyGroup Condition="'$(BuildNonportable)' == 'true'">
<BuildFramework>net45-nonportable</BuildFramework>
<DefineConstants>$(DefineConstants);SUPPORTS_BIGINTEGER</DefineConstants>
</PropertyGroup>
<Import Condition="'$(BuildNonportable)' == 'true'" Project="$(MSBuildThisFileDirectory)\..\..\build\internal\Common.Internal.props" />
<Import Condition="'$(BuildNonportable)' != 'true'" Project="$(MSBuildThisFileDirectory)\..\..\build\internal\Portable.Internal.props" />
<PropertyGroup>
<ProjectGuid>{C001C79F-D289-4CF3-BB59-5F5A72F70D0E}</ProjectGuid>
<OutputType>Library</OutputType>
@ -9,6 +14,8 @@
<RootNamespace>Bond</RootNamespace>
<AssemblyName>Bond.JSON</AssemblyName>
<BondRedistributable>true</BondRedistributable>
<DependentOutputPath>bin\$(BuildType)\net45</DependentOutputPath>
<HasNonportableVersion>true</HasNonportableVersion>
</PropertyGroup>
<ItemGroup>
<Compile Include="expressions\json\JsonParser.cs" />
@ -20,15 +27,19 @@
<Compile Include="protocols\SimpleJsonWriter.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Numerics" Condition="'$(BuildFramework)' == 'net45-nonportable'" />
<Reference Include="Bond">
<HintPath>..\core\$(OutputPath)\Bond.dll</HintPath>
<HintPath>..\core\$(DependentOutputPath)\Bond.dll</HintPath>
</Reference>
<Reference Include="Bond.Attributes">
<HintPath>..\attributes\$(OutputPath)\Bond.Attributes.dll</HintPath>
<HintPath>..\attributes\$(DependentOutputPath)\Bond.Attributes.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json" Condition="'$(TargetFrameworkVersion)' == 'v4.5'">
<Reference Include="Newtonsoft.Json" Condition="'$(BuildFramework)' == 'net45'">
<HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\portable-net45+wp80+win8+wpa81\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json" Condition="'$(BuildFramework)' == 'net45-nonportable'">
<HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

Просмотреть файл

@ -9,6 +9,10 @@ namespace Bond.Expressions.Json
using System.Globalization;
using System.Linq.Expressions;
#if SUPPORTS_BIGINTEGER
using System.Numerics;
#endif
using Bond.Expressions.Pull;
using Bond.Protocols;
@ -120,17 +124,30 @@ namespace Bond.Expressions.Json
{
convertedValue = Reader.Value;
}
var errorMessage =
StringExpression.Format(
"Invalid input, expected JSON token of type {0}, encountered {1}",
Expression.Constant(scalarTokenType, typeof(object)),
Expression.Convert(Reader.TokenType, typeof(object)));
Expression embeddedExpression = handler(convertedValue);
#if SUPPORTS_BIGINTEGER
if (expectedType == BondDataType.BT_UINT64 && scalarTokenType == JsonToken.Integer)
{
embeddedExpression =
Expression.IfThenElse(
Expression.TypeIs(Reader.Value, typeof(long)),
embeddedExpression,
handler(Expression.Convert(Reader.Value, typeof(BigInteger))));
}
#endif
var handleValue =
Expression.IfThenElse(
JsonTokenEquals(scalarTokenType),
handler(convertedValue),
embeddedExpression,
ThrowUnexpectedInput(errorMessage));
// If a floating point value is expected also accept an integer
@ -138,7 +155,7 @@ namespace Bond.Expressions.Json
{
handleValue = Expression.IfThenElse(
JsonTokenEquals(JsonToken.Integer),
handler(Expression.Convert(Reader.Value, typeof (long))),
handler(Expression.Convert(Reader.Value, typeof(long))),
handleValue);
}

Просмотреть файл

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildFramework Condition="'$(Configuration)' == 'Net45'">net45</BuildFramework>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath32)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath32)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup Condition="'$(BuildNonportable)' == 'true'">
<BuildFramework>net45-nonportable</BuildFramework>
<DefineConstants>$(DefineConstants);SUPPORTS_BIGINTEGER</DefineConstants>
</PropertyGroup>
<Import Project="$(MSBuildThisFileDirectory)\..\..\build\internal\Common.Internal.props" />
<PropertyGroup>
<ProjectGuid>{FF056B62-225A-47BC-B177-550FADDA4B41}</ProjectGuid>
@ -14,14 +15,14 @@
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
<DependentOutputPath>$(OutputPath)</DependentOutputPath>
<OrigOutputPath>$(OutputPath)</OrigOutputPath>
<DependentOutputPath>bin\$(BuildType)\net45</DependentOutputPath>
<HasNonportableVersion>true</HasNonportableVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<IntermediateOutputPath>$(IntermediateOutputPath)\Properties\</IntermediateOutputPath>
<OutputPath>$(OutputPath)\Properties\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Net45' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Fields' ">
<IntermediateOutputPath>$(IntermediateOutputPath)\Fields\</IntermediateOutputPath>
<OutputPath>$(OutputPath)\Fields\</OutputPath>
@ -91,9 +92,12 @@
<Reference Include="nunit.framework">
<HintPath>..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json" Condition="'$(TargetFrameworkVersion)' == 'v4.5'">
<Reference Include="Newtonsoft.Json" Condition="'$(BuildFramework)' == 'net45'">
<HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\portable-net45+wp80+win8+wpa81\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json" Condition="'$(BuildFramework)' == 'net45-nonportable'">
<HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Reference Include="Bond.Attributes">
@ -109,7 +113,7 @@
<HintPath>..\..\src\io\$(DependentOutputPath)\Bond.IO.dll</HintPath>
</Reference>
<Reference Include="Bond.JSON">
<HintPath>..\..\src\json\$(DependentOutputPath)\Bond.JSON.dll</HintPath>
<HintPath>..\..\src\json\$(OrigOutputPath)\Bond.JSON.dll</HintPath> <!-- Intentionally not DependentOutputPath to match BuildFramework-->
</Reference>
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -49,7 +49,7 @@
_uint8 = byte.MaxValue,
_uint16 = ushort.MaxValue,
_uint32 = uint.MaxValue,
// Note: not ulong.MaxValue because NewtonSoft JSON doesn't support it
// Note: not ulong.MaxValue because NewtonSoft JSON doesn't support it in portable profile
_uint64 = long.MaxValue
});

Просмотреть файл

@ -976,6 +976,12 @@ namespace UnitTest
return DeserializeTagged<To>(reader);
});
#if SUPPORTS_BIGINTEGER
const bool hasBigInteger = true;
#else
const bool hasBigInteger = false;
#endif
// Simple doesn't support omitting fields
if (typeof(From) != typeof(Nothing) && typeof(From) != typeof(GenericsWithNothing))
{
@ -999,9 +1005,10 @@ namespace UnitTest
if (!AnyField<From>(Reflection.IsBonded))
{
streamTranscode(SerializeSP, TranscodeSPXml<From>, DeserializeXml<To>);
// NewtonSoft JSON doesn't support uint64
if (typeof (From) != typeof (MaxUInt64))
// NewtonSoft JSON doesn't fully support uint64 in portable profile, so we skip
// MaxUInt64 type where BigInteger isn't avaiable
if (hasBigInteger || (typeof(From) != typeof (MaxUInt64)))
{
streamTranscode(SerializeSP, TranscodeSPJson<From>, DeserializeJson<To>);
}
@ -1024,8 +1031,9 @@ namespace UnitTest
streamTranscode(SerializeCB, TranscodeCBXml<From>, DeserializeXml<To>);
streamTranscode(SerializeFB, TranscodeFBXml<From>, DeserializeXml<To>);
// NewtonSoft JSON doesn't support uint64
if (typeof (From) != typeof (MaxUInt64))
// NewtonSoft JSON doesn't fully support uint64 in portable profile, so we skip
// MaxUInt64 type where BigInteger isn't avaiable
if (hasBigInteger || (typeof (From) != typeof (MaxUInt64)))
{
streamRoundtrip(SerializeJson, DeserializeJson<To>);
streamTranscode(SerializeCB, TranscodeCBJson<From>, DeserializeJson<To>);

Просмотреть файл

@ -58,7 +58,7 @@
<HintPath>$(BOND_BINARY_PATH)\net45\Bond.JSON.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\..\..\..\cs\packages\Newtonsoft.Json.9.0.1\lib\portable-net45+wp80+win8+wpa81\Newtonsoft.Json.dll</HintPath>
<HintPath>..\..\..\..\cs\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />