facebook-csharp-sdk / simple-json

JSON library for .NET 2.0+/SL4+/WP7/WindowsStore with optional support for dynamic and DataContract
MIT License
380 stars 143 forks source link

Deserialize Enums #15

Open danielwertheim opened 12 years ago

danielwertheim commented 12 years ago

Tried Serializing with Enums and it worked. Deserializing does not work with Enum. The only option I made available was use Emits.

The model being used is located here: https://github.com/danielwertheim/CompareJsonSerializers/tree/master/Source/CompareJsonSerializers/Model/Customer.cs

//Daniel

JanWosnitza commented 11 years ago

There are 2 problems:

I changed PocoJsonSerializerStrategy.SerializeEnum( Enum p ) to

return p.ToString();

and changed the beginning of PocoJsonSerializerStrategy.DeserializeObject( object value, Type type ) to

object obj = null;
if ( value is string )
{
    string str = value as string;
    if ( type.IsEnum )
        obj = Enum.Parse( type, str );
    else if ( !string.IsNullOrEmpty( str ) && .....

This will serialize enums as strings and is able to deserialize them from strings.

prabirshrestha commented 11 years ago

@JanWosnitza could you send a PR with unit tests.

JanWosnitza commented 11 years ago

@prabirshrestha I will definitely do it! But may take same time.. :) (I am not used to Git(Hub) and [Fags]Enums and nullable ones would be nice to (in case the enum value is not available))

prabirshrestha commented 11 years ago

you could use ReflectionUtils to check for nullable

if (type == typeof(Guid) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid)))
                        obj = new Guid(str);
jamesiq commented 11 years ago

I struggled to make this work as described, but was able to borrow from it after dropping the latest build into my project.

Starting around line 1285: I simply inserted part of the above solution at line 1301: as demonstrated below. Hopefully this helps someone!!! Thanks again rock stars of awesome sauce, -James

1285: [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] 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.
            {

1301: if (type.IsEnum) return Enum.Parse(type, str);

prabirshrestha commented 11 years ago

would be great if you can send a PR with unit tests.

agillesp commented 11 years ago

I did this instead:

public class EnumSupportedStrategy : PocoJsonSerializerStrategy
{
    public override object DeserializeObject(object value, Type type)
    {
        object obj;
        if (type.IsEnum && value is string)
            obj = Enum.Parse(type, (string)value);
        else
            obj = base.DeserializeObject(value, type);
        return obj;
    }
}
prabirshrestha commented 11 years ago

@agillesp does that handle nullables?

agillesp commented 11 years ago

Almost certainly not - I doubt the "type.IsEnum" will report true if it's a nullable. My usecase doesn't have any nullable enum properties to serialize so I didn't bother. However, it should be easy to fix. You'll have to do a little more inspection into the type and then handle a null "value" argument appropriately.

prabirshrestha commented 11 years ago

if you can write a unit test and send us a pull request it would be great.

agillesp commented 11 years ago

Well, unfortunately, I'm not too plugged into github's workflow and am not even sure how to do a pull request. I guess I fork, add my code, then do something? Also, this is not a platform fix, this is an additional serialization policy; right now the onus is on the developer whether to use the EnumSupportedStrategy. Though I suppose I could fix PocoJsonSerializerStrategy directly.

prabirshrestha commented 11 years ago

fork the repo and create a new branch. I would love this to go in PocoJsonSerializerStrategy. and It should work with the DataContract one too.

NancyFX has a good guidelines on contributing. https://github.com/NancyFx/Nancy/blob/master/CONTRIBUTING.md You might want to look there.

Also remember the unit tests. Try sending the PR to our "dev" branch if possible.

agillesp commented 11 years ago

Well I'm happy to give back when I can. Just like everyone else who's a developer I'm plenty busy. But if I find the time this weekend I'll give it a shot.

JanWosnitza commented 11 years ago

I had some thoughts on this issue again. In the case you don't know all possible (enum-)values, it would be best to deserialize the enum as a string and make a wrapping property that is able to indicate an unknown value. This would allow you to output the actual value even though you didn't know it exists but also have the convenience of an enum.

enum MyEnum
{
    _UnknownValue,
    Ok,
    Error1,
    Error2,
};

class DataClass
{
    // Serialized field
    public string State;

    // Wrapping field
    public MyEnum_State
    {
        get
        {
            MyEnumval;
            if ( Enum.TryParse( this.State, out val ) )
                return value;
            return MyEnum._UnknownValue;
        }
        set { this.State = value.ToSring(); }
    }
}

@prabirshrestha I would love to extend this at home, but unfortunately I only have the VS-Express version. Express does not support portable DLLs which is a problem because the UnitTest Project references the portable DLL-Project. Any ideas? :)

prabirshrestha commented 11 years ago

@JanWosnitza try it with normal non-portable reference. I don't think there will be much difference. Before I merge, I can test if it works with portable lib.

agillesp commented 11 years ago

@JanWosnitza I really can't understand what you're driving at here? From the perspective of the deserializer, aren't ALL enum values unknown (it has no knowledge of your model)? Now if you're speaking about a case where a value exists in the serial string, say "FakeValue", and this doesn't exist in the enum:

public enum MyEnum { RealValue };

Is this what you're talking about? In this case, wouldn't it just be best to throw? - your model can't consume this value and I'd expect an exception.

JanWosnitza commented 11 years ago

@prabirshrestha k, will try so. Next week.. ;)

@agillesp yes, that was my intended situation (forgot to give an example with e.g. "UnexpectedError"). And yes an exception should be thrown if you deserialize the enum directly. Nevertheless if you want to know if a value has value1 or value2 and don't care with all other values, you really want to let the serializer finish and get your model returned. (Imagine a bad/wirred documented third party server, e.g. facebook gg) I think it depends on your case..

jonnii commented 11 years ago

I know this thread is seriously old, but if someone comes along and wants support for enums the following has worked for me:

    public class EnumSupportedStrategy : PocoJsonSerializerStrategy
    {
        protected override object SerializeEnum(Enum p)
        {
            return p.ToString();
        }

        public override object DeserializeObject(object value, Type type)
        {
            var stringValue = value as string;
            if (stringValue != null)
            {
                if (type.IsEnum)
                {
                    return Enum.Parse(type, stringValue);
                }

                if (ReflectionUtils.IsNullableType(type))
                {
                    var underlyingType = Nullable.GetUnderlyingType(type);
                    if (underlyingType.IsEnum)
                    {
                        return Enum.Parse(underlyingType, stringValue);
                    }
                }
            }

            return base.DeserializeObject(value, type);
        }
    }
Kordonme commented 9 years ago

To repeat @jonnii. This is way too old now. But I managed to build enum support. I'm not really sure how to write the tests. Honestly, I only forked. Haven't opened sln yet. But is this fixed in the SimpleJson.cs? Is it still a wanted feature?

prabirshrestha commented 9 years ago

@Kordonme send a PR for at least the SimpleJson.cs and I will have a look at it.

lostmsu commented 7 years ago

All the suggested solutions ignore https://msdn.microsoft.com/en-us/library/system.runtime.serialization.enummemberattribute