Open jasonmead opened 10 years ago
this issue is not working in the current version. working on a fix to the code.
public virtual object DeserializeObject(object value, Type type)
{
if (type == null) throw new ArgumentNullException("type");
string str = value as string;
if (type == typeof (Guid) && string.IsNullOrEmpty(str))
return default(Guid);
if (value == null)
return null;
object obj = null;
if (str != null)
{
if (str.Length != 0) // We know it can't be null now.
{
if (type == typeof(DateTime) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(DateTime)))
return DateTime.ParseExact(str, Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
if (type == typeof(DateTimeOffset) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(DateTimeOffset)))
return DateTimeOffset.ParseExact(str, Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
if (type == typeof(Guid) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid)))
return new Guid(str);
if (type == typeof(Uri))
{
bool isValid = Uri.IsWellFormedUriString(str, UriKind.RelativeOrAbsolute);
Uri result;
if (isValid && Uri.TryCreate(str, UriKind.RelativeOrAbsolute, out result))
return result;
return null;
}
if (type == typeof(string))
return str;
return Convert.ChangeType(str, type, CultureInfo.InvariantCulture);
}
else
{
if (type == typeof(Guid))
obj = default(Guid);
else if (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid))
obj = null;
else
obj = str;
}
// Empty string case
if (!ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid))
return str;
}
else if (value is bool)
return value;
bool valueIsLong = value is long;
bool valueIsDouble = value is double;
if (type.IsEnum)
{
if (value is double || value is int || value is long)
{
return Enum.ToObject(type, Convert.ToInt32(value.ToString()));
}
else if (value is string)
{
return Enum.Parse(type, value.ToString());
}
}
if ((valueIsLong && type == typeof(long)) || (valueIsDouble && type == typeof(double)))
return value;
if ((valueIsDouble && type != typeof(double)) || (valueIsLong && type != typeof(long)))
{
obj = type == typeof(int) || type == typeof(long) || type == typeof(double) || type == typeof(float) || type == typeof(bool) || type == typeof(decimal) || type == typeof(byte) || type == typeof(short)
? Convert.ChangeType(value, type, CultureInfo.InvariantCulture)
: value;
}
else
{
IDictionary<string, object> objects = value as IDictionary<string, object>;
if (objects != null)
{
IDictionary<string, object> jsonObject = objects;
if (ReflectionUtils.IsTypeDictionary(type))
{
// if dictionary then
Type[] types = ReflectionUtils.GetGenericTypeArguments(type);
Type keyType = types[0];
Type valueType = types[1];
Type genericType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);
IDictionary dict = (IDictionary)ConstructorCache[genericType]();
foreach (KeyValuePair<string, object> kvp in jsonObject)
dict.Add(kvp.Key, DeserializeObject(kvp.Value, valueType));
obj = dict;
}
else
{
if (type == typeof(object))
obj = value;
else
{
obj = ConstructorCache[type]();
foreach (KeyValuePair<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> setter in SetCache[type])
{
object jsonValue;
if (jsonObject.TryGetValue(setter.Key, out jsonValue))
{
jsonValue = DeserializeObject(jsonValue, setter.Value.Key);
setter.Value.Value(obj, jsonValue);
}
}
}
}
}
else
{
IList<object> valueAsList = value as IList<object>;
if (valueAsList != null)
{
IList<object> jsonObject = valueAsList;
IList list = null;
if (type.IsArray)
{
list = (IList)ConstructorCache[type](jsonObject.Count);
int i = 0;
foreach (object o in jsonObject)
list[i++] = DeserializeObject(o, type.GetElementType());
}
else if (ReflectionUtils.IsTypeGenericeCollectionInterface(type) || ReflectionUtils.IsAssignableFrom(typeof(IList), type))
{
Type innerType = ReflectionUtils.GetGenericListElementType(type);
list = (IList)(ConstructorCache[type] ?? ConstructorCache[typeof(List<>).MakeGenericType(innerType)])(jsonObject.Count);
foreach (object o in jsonObject)
list.Add(DeserializeObject(o, innerType));
}
obj = list;
}
}
return obj;
}
if (ReflectionUtils.IsNullableType(type))
return ReflectionUtils.ToNullableType(obj, type);
return obj;
}
Here the code change:
\ public virtual object DeserializeObject(object value, Type type)**
Current version at time of change is 0.38.0 or copy method above and replace. tested with 4 enums.
if (type.IsEnum)
{
if (value is double || value is int || value is long)
{
return Enum.ToObject(type, Convert.ToInt32(value.ToString()));
}
else if (value is string)
{
return Enum.Parse(type, value.ToString());
}
}
Submit a PR with tests, please.
I have never done a PR request. reading up on google and going try it.
I followed this: https://guides.github.com/activities/contributing-to-open-source/
I did the fork. made a branch (enumfix). compiled solution. updated source. committed branch. added tests (EnumTest). unsure what do to next. the code been committed to the branch.
Everything compiles. test worked ok. checked in.
The next step would be to open a pull request from your forked branch.
@jasonmead this is great, i'm not sure what the diff between your PR and @amccorma PR #72 although that PR I think has line ending issues as the whole simplejson file has changed. I'd like to get this into Nancy https://github.com/NancyFx/Nancy for the JSON work you did.
Including @prabirshrestha in this too.
What needs to be done to get this feature in ASAP?
This will have to be implemented in Nancy directly. Unfortunately, we had to modify SimpleJson.cs in Nancy to get it to work correctly.
@jchannon I will be out of town. will have to look at this next week.
What is the status? I need enum support to use SimpleJson in a Unity game (last stable version of which sadly provides us, programmers, with C# 4 and .NET 2.0-3.5 at the time of writing which don't make much of choise when handling json). It's the only thing, that stops me from using SimpleJson. I need something like this to work:
[DataContract]
public enum Keeper
{
[DataMember(Name = "no keeper")]
None,
[DataMember(Name = "Mary Rose")]
Mary,
[DataMember(Name = "Tom The Third")]
Tom,
[DataMember(Name = "Simply, Todd")]
Todd
}
[DataContract]
public class Animal : JsonResponse
{
[NotNull]
[DataMember(Name = "animal color")] // works ok
public string Color { get; private set; }
[DataMember(Name = "animal keeper")] // fails, enum serialized as number ( 0 for None, 1 for Mary and so on)
public Keeper Keeper { get; private set; }
}
So, needed serialized example of animal: { "animal color" : "red", "animal keeper" : "Mary Rose" }
Actual serialized example of animal: { "animal color" : "red", "animal keeper" : 1 }
I came from java and there we successfully used (for example) com.google.api.client.util.Value attribute to specify [de]serialized string value for each enum member:
public enum CardStatus {
@Value("active")
ACTIVE,
@Value("expired")
EXPIRED,
@Value("blocked")
BLOCKED
}
public class Card {
@Key("card id")
private String id;
@Key("status")
private CardStatus status;
}
So, serialized example of Card: { "card id" : "101010", "status" : "expired" }
PS com.google.api.client.util.Value is in com.google.http-client:google-http-client-android:1.22.0 or com.google.http-client:google-http-client-jackson2:1.22.0 - don't remember exactly, allways imported both at the same time
PS I tested code of that merge request and it gave me: { "animal color" : "red", "animal keeper" : "Mary" } As you see, sadly, DataMember attribute ignored
Fixes #15