Skip to content

Commit

Permalink
Auto stash before merge of "develop" and "origin/develop" (#26)
Browse files Browse the repository at this point in the history
* Auto stash before merge of "develop" and "origin/develop"

* unify namespaces & put different converters in different files

* must not reuse the current reader here. still not fully understand.

* fix smaller bugs, deactivate outdated tests

* fix null value handling once more.

Co-authored-by: Konstantin Klein <[email protected]>
  • Loading branch information
hamidd30 and hf-kklein authored Mar 26, 2020
1 parent 1828ad6 commit ff0c219
Show file tree
Hide file tree
Showing 20 changed files with 872 additions and 586 deletions.
1 change: 1 addition & 0 deletions BO4E-dotnet.Encryption/Anonymizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using BO4E.BO;
using BO4E.Extensions.BusinessObjects;
using BO4E.meta;
using BO4E.meta.LenientParsing;
using Microsoft.CSharp.RuntimeBinder;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
Expand Down
29 changes: 27 additions & 2 deletions BO4E-dotnet/BO/BusinessObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;

using BO4E.meta;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;
using Newtonsoft.Json.Schema.Generation;
using Newtonsoft.Json.Serialization;

using ProtoBuf;

namespace BO4E.BO
Expand Down Expand Up @@ -512,12 +515,34 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
throw new NotImplementedException($"The type '{jo["boTyp"].Value<string>()}' does not exist in the BO4E standard.");
}
}
return JsonConvert.DeserializeObject(jo.ToString(), boType);
var deserializationMethod = serializer.GetType() // https://stackoverflow.com/a/5218492/10009545
.GetMethods()
.Where(m => m.Name == nameof(serializer.Deserialize))
.Select(m => new
{
Method = m,
Params = m.GetParameters(),
Args = m.GetGenericArguments()
})
.Where(x => x.Params.Length == 1
&& x.Args.Length == 1)
.Select(x => x.Method)
.First()
.GetGenericMethodDefinition()
.MakeGenericMethod(new Type[] { boType });
try
{
return deserializationMethod.Invoke(serializer, new object[] { jo.CreateReader() });
}
catch (TargetInvocationException tie) when (tie.InnerException != null)
{
throw tie.InnerException; // to hide the reflection to the outside.
}
}
else
{
serializer.ContractResolver.ResolveContract(objectType).Converter = null;
return serializer.Deserialize(reader, objectType);
return serializer.Deserialize(JObject.Load(reader).CreateReader(), objectType);
}
}

Expand Down
2 changes: 1 addition & 1 deletion BO4E-dotnet/BO/Marktlokation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public class Marktlokation : BusinessObject
public Gasqualitaet? gasqualitaet;

/// <summary>Link zum Geschäftspartner, dem diese Marktlokation gehört.</summary>
[JsonProperty(Required = Required.Default, Order = 17)]
[JsonProperty(Required = Required.Default, Order = 17, NullValueHandling = NullValueHandling.Ignore)]
[ProtoMember(17)]
public Geschaeftspartner endkunde;

Expand Down
3 changes: 3 additions & 0 deletions BO4E-dotnet/BO/Rechnung.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System;
using System.Collections.Generic;
using System.Globalization;

using BO4E.COM;
using BO4E.ENUM;
using BO4E.meta;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using ProtoBuf;

namespace BO4E.BO
Expand Down
2 changes: 1 addition & 1 deletion BO4E-dotnet/BO/Zaehler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public class Zaehler : BusinessObject
public List<Zaehlwerk> zaehlwerke;

/// <summary>Der Hersteller des Zählers. Details <see cref="Geschaeftspartner" /></summary>
[JsonProperty(Required = Required.Default, Order = 13)]
[JsonProperty(Required = Required.Default, Order = 13, NullValueHandling =NullValueHandling.Ignore)]
[ProtoMember(13)]
public Geschaeftspartner zaehlerhersteller;

Expand Down
2 changes: 1 addition & 1 deletion BO4E-dotnet/BO4E-dotnet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile></DocumentationFile>
<Optimize>true</Optimize>
<Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>DEBUG</DefineConstants>
Expand Down
199 changes: 10 additions & 189 deletions BO4E-dotnet/BoMapper.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;

using BO4E.BO;
using BO4E.meta;
using BO4E.meta.LenientParsing;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;
using Newtonsoft.Json.Serialization;


namespace BO4E
{
/// <summary>
Expand Down Expand Up @@ -150,6 +151,9 @@ public static BusinessObject MapObject(Type businessObjectType, JObject jobject,
break;
case LenientParsing.Bo4eUri:
converters.Add(new LenientBo4eUriConverter());
break;
case LenientParsing.StringToInt:
converters.Add(new LenientStringToIntConverter());
break;
// case LenientParsing.EmptyLists:
// converters.Add(new LenientRequiredListConverter());
Expand Down Expand Up @@ -213,6 +217,9 @@ public static JsonSerializerSettings GetJsonSerializerSettings(HashSet<string> u
case LenientParsing.Bo4eUri:
converters.Add(new LenientBo4eUriConverter());
break;
case LenientParsing.StringToInt:
converters.Add(new LenientStringToIntConverter());
break;
// case LenientParsing.EmptyLists:
// converters.Add(new LenientRequiredListConverter());
// break;
Expand Down Expand Up @@ -403,192 +410,6 @@ public static FieldInfo[] GetAnnotatedFields(string boName, Type attributeType)
.ToArray<FieldInfo>();
}

private class LenientEnumListConverter : JsonConverter
{

public override bool CanConvert(Type objectType)
{
if (!objectType.IsGenericType)
{
return false;
}
if (objectType.GetGenericTypeDefinition() != typeof(List<>))
{
return false;
}
Type expectedListElementType = objectType.GetGenericArguments()[0];
return expectedListElementType.ToString().StartsWith("BO4E.ENUM");
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader); // https://stackoverflow.com/a/47864946/10009545
List<object> rawList = token.ToObject<List<object>>();
Type expectedListElementType = objectType.GetGenericArguments()[0];
Type expectedListType = typeof(List<>).MakeGenericType(expectedListElementType);
object result = Activator.CreateInstance(expectedListType);
if (rawList == null || rawList.Count == 0)
{
return result;
}
// First try to parse the List normally, in case it's formatted as expected
foreach (var rawItem in rawList)
{
if (rawItem.GetType() == typeof(string) && Enum.IsDefined(expectedListElementType, rawItem.ToString()))
{
// default. everything is as it should be :-)
object enumValue = Enum.Parse(expectedListElementType, rawItem.ToString());
((IList)result).Add(enumValue);
}
else if (rawItem.GetType() == typeof(JObject))
{
Dictionary<string, object> rawDict = ((JObject)rawItem).ToObject<Dictionary<string, object>>();
object rawObject = rawDict.Values.FirstOrDefault<object>();
object enumValue = Enum.Parse(expectedListElementType, rawObject.ToString());
((IList)result).Add(enumValue);
}
else
{
((IList)result).Add(rawItem);
}
}
return result;
}

public override bool CanWrite
{
get { return false; }
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}

/// <summary>
/// The lenient DateTimeConverter allows for transforming strings into (nullable) DateTime(?) objects,
/// even if their formatting is somehow weird.
/// </summary>
public class LenientDateTimeConverter : JsonConverter
{
// basic structure copied from https://stackoverflow.com/a/33172735/10009545

private readonly DateTime? _defaultDateTime;

public LenientDateTimeConverter(DateTime? defaultDateTime = null)
{
this._defaultDateTime = defaultDateTime;
}

public LenientDateTimeConverter() : this(null)
{

}

private readonly List<string> ALLOWED_DATETIME_FORMATS = new List<string>()
{
"yyyyMMddHHmm",
"yyyyMMddHHmmss",
@"yyyyMMddHHmmss'--T::zzzz'", // ToDo: remove again. this is just a buggy, nasty workaround
};

public override bool CanConvert(Type objectType)
{
return (objectType == typeof(DateTime) || objectType == typeof(DateTime?));
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
string rawDate;
if (reader.Value == null)
{
return null;
}
else if (reader.Value as string != null)
{
rawDate = (string)reader.Value;
}
else if (reader.Value.GetType() == typeof(DateTime))
{
return (DateTime)reader.Value;
}
else
{
rawDate = reader.Value.ToString();
}
// First try to parse the date string as is (in case it is correctly formatted)
if (DateTime.TryParse(rawDate, out DateTime date))
{
return date;
}

foreach (string dtf in ALLOWED_DATETIME_FORMATS)
{
if (DateTime.TryParseExact(rawDate, dtf, CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
{
return date;
}
}

// It's not a date after all, so just return the default value
if (objectType == typeof(DateTime?))
{
return null;
}
if (this._defaultDateTime.HasValue)
{
return _defaultDateTime;
}
else
{
throw new JsonReaderException($"Couldn't convert {rawDate} to any of the allowed date time formats: {String.Join(";", ALLOWED_DATETIME_FORMATS)})");
}
}

public override bool CanWrite
{
get { return false; }
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}

private class LenientBo4eUriConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Bo4eUri));
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.Value == null)
{
return null;
}
string rawString = (string)reader.Value;
if (rawString.Trim() == String.Empty)
{
return null;
}
return new Bo4eUri(rawString);
}

public override bool CanWrite
{
get { return false; }
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}

/// <summary>
/// The UserPropertiesContractResolver allows to put non-BO4E-standard/custom fields/properties into a "userProperties" object.
/// </summary>
Expand Down
Loading

0 comments on commit ff0c219

Please sign in to comment.