Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand literals by default #8

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions paket.dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@ nuget Costura.Fody
nuget Rdf.Vocabularies
nuget OpenCover
nuget Newtonsoft.Json ~> 9
nuget JsonDiffPatch.Net
nuget NodaTime.Serialization.JsonNet

gist tpluscode/a285267d2543466fc35c3a168c846f9f
8 changes: 7 additions & 1 deletion paket.lock
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,17 @@ NUGET
ImpromptuInterface (6.2.2)
InfoOf.Fody (1.0.4)
Fody (>= 1.29.2)
JsonDiffPatch.Net (1.0.5)
Newtonsoft.Json (>= 8.0.2)
json-ld.net (1.0.5)
Newtonsoft.Json (>= 6.0.4)
MethodTimer.Fody (1.16)
Fody (>= 1.29.2)
Newtonsoft.Json (9.0.1)
NodaTime (1.3.2)
NodaTime.Serialization.JsonNet (1.3.2)
Newtonsoft.Json (>= 4.5.11)
NodaTime (>= 1.3)
NullGuard.Fody (1.4.6)
Fody (>= 1.29.2)
NUnit (2.6.4)
Expand All @@ -32,4 +38,4 @@ NUGET
VDS.Common (1.6.4)
GIST
remote: tpluscode/a285267d2543466fc35c3a168c846f9f
FULLPROJECT (eac8af5adfdcfc43b63a5d5edf88c082e83761e0)
FULLPROJECT (c9b7a831e53e929f2ecce09b14a61e28007b669f)
2 changes: 1 addition & 1 deletion src/Documentation/CreatingContext/FluentContext/Readme.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void BuildComplexContextSimply()
// when
var context = new JObject(
Base.Is("http://example.com/"),
Vocab.Is(new Uri("http://schema.org/")),
JsonLD.Entities.Context.Vocab.Is(new Uri("http://schema.org/")),
"dcterms".IsPrefixOf("http://purl.org/dc/terms/"),
"xsd".IsPrefixOf(new Uri("http://www.w3.org/2001/XMLSchema#")),
"title".IsProperty("dcterms:title"),
Expand Down
2 changes: 1 addition & 1 deletion src/Documentation/CreatingContext/FluentContext/Readme.mkd
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void BuildComplexContextSimply()
// when
var context = new JObject(
Base.Is("http://example.com/"),
Vocab.Is(new Uri("http://schema.org/")),
JsonLD.Entities.Context.Vocab.Is(new Uri("http://schema.org/")),
"dcterms".IsPrefixOf("http://purl.org/dc/terms/"),
"xsd".IsPrefixOf(new Uri("http://www.w3.org/2001/XMLSchema#")),
"title".IsProperty("dcterms:title"),
Expand Down
16 changes: 11 additions & 5 deletions src/Documentation/Deserializing/LiteralValues/Readme.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
# Documentation

## Working with literal values
## Deserializing literal values

As always, here are the required namespace imports.
**/
Expand Down Expand Up @@ -114,12 +114,17 @@ derived from the deafult `JsonConverter` it would fail to deserialize such liter

public class IPAddressConverter : JsonLdLiteralConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
protected override bool ShouldSerializeAsCompactLiteral(object value)
{
return true;
}

protected override void WriteJsonLdValue(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(value.ToString());
}

protected override object DeserializeLiteral(JsonReader reader, Type objectType, JsonSerializer serializer)
protected override object ReadJsonLdLiteral(JsonReader reader, Type objectType, JsonSerializer serializer)
{
return IPAddress.Parse((string)reader.Value);
}
Expand Down Expand Up @@ -179,8 +184,9 @@ public void Can_deserialize_class_from_expanded_literal()
}

/**
And lastly it is possible to serialize such an object to literal. Note that compacted value will always be produced, so it's important to
create a fitting `@context` so that the JSON-LD document is valid and correct.
And lastly it is possible to serialize such an object to literal. Note that the converter implementation
always produces compacted value, so it's important to create a fitting `@context` so that the JSON-LD
document is valid and correct.
**/

[Test]
Expand Down
16 changes: 11 additions & 5 deletions src/Documentation/Deserializing/LiteralValues/Readme.mkd
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Documentation

## Working with literal values
## Deserializing literal values

As always, here are the required namespace imports.

Expand Down Expand Up @@ -113,12 +113,17 @@ derived from the deafult `JsonConverter` it would fail to deserialize such liter
``` c#
public class IPAddressConverter : JsonLdLiteralConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
protected override bool ShouldSerializeAsCompactLiteral(object value)
{
return true;
}

protected override void WriteJsonLdValue(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(value.ToString());
}

protected override object DeserializeLiteral(JsonReader reader, Type objectType, JsonSerializer serializer)
protected override object ReadJsonLdLiteral(JsonReader reader, Type objectType, JsonSerializer serializer)
{
return IPAddress.Parse((string)reader.Value);
}
Expand Down Expand Up @@ -178,8 +183,9 @@ public void Can_deserialize_class_from_expanded_literal()
}
```

And lastly it is possible to serialize such an object to literal. Note that compacted value will always be produced, so it's important to
create a fitting `@context` so that the JSON-LD document is valid and correct.
And lastly it is possible to serialize such an object to literal. Note that the converter implementation
always produces compacted value, so it's important to create a fitting `@context` so that the JSON-LD
document is valid and correct.

``` c#
[Test]
Expand Down
37 changes: 37 additions & 0 deletions src/Documentation/Documentation.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<RunCodeAnalysis>true</RunCodeAnalysis>
<CodeAnalysisRuleSet>..\..\paket-files\tpluscode\a285267d2543466fc35c3a168c846f9f\UnitTests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
Expand All @@ -31,6 +32,8 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<RunCodeAnalysis>true</RunCodeAnalysis>
<CodeAnalysisRuleSet>..\..\paket-files\tpluscode\a285267d2543466fc35c3a168c846f9f\UnitTests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
Expand All @@ -52,6 +55,7 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="ResolvingContext\Readme.cs" />
<Compile Include="Serializing\LiteralValues\Readme.cs" />
<Compile Include="Serializing\WorkingWithURIs\Readme.cs" />
<None Include="app.config" />
<None Include="paket.references" />
Expand Down Expand Up @@ -108,6 +112,28 @@
</ItemGroup>
</When>
</Choose>
<Choose>
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.5')">
<ItemGroup>
<Reference Include="NodaTime">
<HintPath>..\..\packages\NodaTime\lib\net35-Client\NodaTime.dll</HintPath>
<Private>True</Private>
<Paket>True</Paket>
</Reference>
</ItemGroup>
</When>
</Choose>
<Choose>
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.5')">
<ItemGroup>
<Reference Include="NodaTime.Serialization.JsonNet">
<HintPath>..\..\packages\NodaTime.Serialization.JsonNet\lib\net35-Client\NodaTime.Serialization.JsonNet.dll</HintPath>
<Private>True</Private>
<Paket>True</Paket>
</Reference>
</ItemGroup>
</When>
</Choose>
<Choose>
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.5')">
<ItemGroup>
Expand All @@ -119,5 +145,16 @@
</ItemGroup>
</When>
</Choose>
<Choose>
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.5')">
<ItemGroup>
<Reference Include="Rdf.Vocabularies">
<HintPath>..\..\packages\Rdf.Vocabularies\lib\portable-net4+sl5+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\Rdf.Vocabularies.dll</HintPath>
<Private>True</Private>
<Paket>True</Paket>
</Reference>
</ItemGroup>
</When>
</Choose>
<Import Project="..\..\packages\GitVersionTask\build\$(__paket__GitVersionTask_targets).targets" Condition="Exists('..\..\packages\GitVersionTask\build\$(__paket__GitVersionTask_targets).targets')" Label="Paket" />
</Project>
128 changes: 128 additions & 0 deletions src/Documentation/Serializing/LiteralValues/Readme.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
using JsonLD.Entities.Converters;
using Newtonsoft.Json;
using NodaTime.Serialization.JsonNet;
using NUnit.Framework;

/**
# Documentation

Related topic: [deserializing literals][deserialize-literals]

## Serializing literal values

In JSON-LD a literal value (ie. not a URI) are represented as JS objects, which
contains the value as string and that value's type URI. For example a date
would be represented as:

``` json
{
"@context": "http://example.com/vocab/",
"arrivalDate": {
"@value": "2017-01-14T14:50Z",
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
}
}
```

### Serializing framework types

JsonLd.Entities serializer will choose an appropriate [XSD data type][xsd] for
matching .NET Framework primitive types and will output a JSON-LD object like the one
shown above.

**/

public class SerializingFrameworkTypes
{
private class TrainSchedule
{
public System.DateTime ArrivalDate => new System.DateTime(2017, 1, 14, 14, 50, 0);
}

[Test]
public void Serializes_builtin_types_as_expanded_literal()
{
// given
var serializer = new JsonLD.Entities.EntitySerializer();

// when
dynamic schedule = serializer.Serialize(new TrainSchedule());

// then
Assert.That((string)schedule.arrivalDate["@value"], Is.EqualTo("2017-01-14T14:50:00"));
Assert.That((string)schedule.arrivalDate["@type"], Is.EqualTo("http://www.w3.org/2001/XMLSchema#dateTime"));
}
}

/**

The above works for all .NET numeric types, `DateTime`, `DateTimeOffset` and `TimeSpan`.

The exceptions are `double` and `string` which all have their implicit typing in JSON and
so they are serialized accoring to their default JavaScript rules while retaining the
correct RDF typing (`xsd:double`, `xsd:boolean` and `xsd:string` accordingly). See the
[JSON-LD spec](https://www.w3.org/TR/json-ld/#conversion-of-native-data-types).

Note that integers are excempt from this rule, because as a generic term for all integral
numbers, such datatype does not exist in .NET.

### Serializing other types as literal

It may be required to serialize instances of other classes as JSON-LD literals.
Sticking to dates, one may prefer to use the `Instant` type from Jon Skeet's [NodaTime library][noda].

To serialize any arbitrary type as an expanded literal one has to derive from
`JsonLdLiteralConverter` and set it as the coverter for [property][prop-conv] or [class][class-conv].

The converter class has one abstract and a number of virtual methods, which control
the serialization output. In this example we use NodaTime's converter to write the `Instant` to
JSON and set the `@type` to `xsd:dateTime`. Do have a look at this [deserialization page][deserialize-literals]
for more examples.

**/

public class SerializingCustomTypesAsLiterals
{
public class JsonLdNodaInstantConverter : JsonLdLiteralConverter
{
protected override void WriteJsonLdValue(JsonWriter writer, object value, JsonSerializer serializer)
{
NodaConverters.InstantConverter.WriteJson(writer, value, serializer);
}

protected override string GetJsonLdType(object value)
{
return Vocab.Xsd.dateTime;
}
}

public class NodaTimeTrainSchedule
{
[JsonConverter(typeof(JsonLdNodaInstantConverter))]
public NodaTime.Instant ArrivalDate => NodaTime.Instant.FromUtc(2017, 1, 14, 14, 50);
}

[Test]
public void Serializes_NodaTime_as_expanded_literal()
{
// given
var serializer = new JsonLD.Entities.EntitySerializer();

// when
dynamic schedule = serializer.Serialize(new NodaTimeTrainSchedule());

// then
Assert.That((string)schedule.arrivalDate["@value"], Is.EqualTo("2017-01-14T14:50:00Z"));
Assert.That((string)schedule.arrivalDate["@type"], Is.EqualTo("http://www.w3.org/2001/XMLSchema#dateTime"));
}
}

/**

[deserialize-literals]: /wikibus/JsonLD.Entities/tree/master/src/Documentation/Deserializing/LiteralValues
[xsd]: https://www.w3.org/TR/xmlschema-2/#built-in-datatypes
[noda]: https://www.nuget.org/packages/NodaTime
[class-conv]: http://www.newtonsoft.com/json/help/html/JsonConverterAttributeClass.htm
[prop-conv]: http://www.newtonsoft.com/json/help/html/JsonConverterAttributeProperty.htm

**/
Loading