RejectedSoftware Forums

Sign up

How to deserialize enum by name but with case insensitive way?

I'm accessing the API which have uppercase enum values, but I don't like them and so want to be able to deserialize them with case insensitive way.

This does not work:

enum Color {
	red,
	green,
	blue
}
	
struct Test {
	@byName Color color;
}

assert(deserializeJson!Test(Json(["color":Json("RED")])).color == Color.red);


I tried to implement custom policy, like this (there is not much documentation about it):

template UpperCasePolicy(S) {
	import std.conv, std.string : toLower, toUpper;

	S fromRepresentation(string value) {
		return value.toLower.to!S;
	}

	string toRepresentation(S value) {
		return to!string(value).toUpper;
	}
}
	
struct Test {
	@byName!UpperCasePolicy Color color;
}

But it ends up with the strange error: Got JSON of type string, expected int_, bigInt

I can't figure out what I'm doing wrong :(

Re: How to deserialize enum by name but with case insensitive way?

Am 21.05.2016 um 23:33 schrieb Tomáš Chaloupka:

I'm accessing the API which have uppercase enum values, but I don't like them and so want to be able to deserialize them with case insensitive way.

This does not work:

enum Color {
	red,
	green,
	blue
}
	
struct Test {
	@byName Color color;
}

assert(deserializeJson!Test(Json(["color":Json("RED")])).color == Color.red);


I tried to implement custom policy, like this (there is not much documentation about it):

template UpperCasePolicy(S) {
	import std.conv, std.string : toLower, toUpper;

	S fromRepresentation(string value) {
		return value.toLower.to!S;
	}

	string toRepresentation(S value) {
		return to!string(value).toUpper;
	}
}
	
struct Test {
	@byName!UpperCasePolicy Color color;
}

But it ends up with the strange error: Got JSON of type string, expected int_, bigInt

I can't figure out what I'm doing wrong :(

Policy based serialization definitely needs a proper introduction. So
the right way to use it is to pass the policy to the
serializeWithPolicy function (which has the downside that this doesn't
always work in high-level scenarios, e.g. in the web/REST generators).
It would look similar to this:

template UpperCasePolicy(T) if (T == Color) {
     import std.conv, std.string : toLower, toUpper;

     Color fromRepresentation(string value) {
         return value.toLower.to!Color;
     }

     string toRepresentation(Color value) {
         return to!string(value).toUpper;
     }
}

struct Test {
     Color color;
}

Test test = {Color.red};

assert(test.serializeWithPolicy!(JsonStringSerializer, UpperCasePolicy)
     == `{"color":"RED"}`);
assert(`{"color": "GREEN"}`
     .deserializeWithPolity!(JsonStringSerializer, UpperCasePolicy, Test)
     == Test(Color.green));

Re: How to deserialize enum by name but with case insensitive way?

On Sun, 22 May 2016 08:26:10 +0200, Sönke Ludwig wrote:

Am 21.05.2016 um 23:33 schrieb Tomáš Chaloupka:

I'm accessing the API which have uppercase enum values, but I don't like them and so want to be able to deserialize them with case insensitive way.

This does not work:

enum Color {
	red,
	green,
	blue
}
	
struct Test {
	@byName Color color;
}

assert(deserializeJson!Test(Json(["color":Json("RED")])).color == Color.red);


I tried to implement custom policy, like this (there is not much documentation about it):

template UpperCasePolicy(S) {
	import std.conv, std.string : toLower, toUpper;

	S fromRepresentation(string value) {
		return value.toLower.to!S;
	}

	string toRepresentation(S value) {
		return to!string(value).toUpper;
	}
}
	
struct Test {
	@byName!UpperCasePolicy Color color;
}

But it ends up with the strange error: Got JSON of type string, expected int_, bigInt

I can't figure out what I'm doing wrong :(

Policy based serialization definitely needs a proper introduction. So
the right way to use it is to pass the policy to the
serializeWithPolicy function (which has the downside that this doesn't
always work in high-level scenarios, e.g. in the web/REST generators).
It would look similar to this:

template UpperCasePolicy(T) if (T == Color) {
     import std.conv, std.string : toLower, toUpper;

     Color fromRepresentation(string value) {
         return value.toLower.to!Color;
     }

     string toRepresentation(Color value) {
         return to!string(value).toUpper;
     }
}

struct Test {
     Color color;
}

Test test = {Color.red};

assert(test.serializeWithPolicy!(JsonStringSerializer, UpperCasePolicy)
     == `{"color":"RED"}`);
assert(`{"color": "GREEN"}`
     .deserializeWithPolity!(JsonStringSerializer, UpperCasePolicy, Test)
     == Test(Color.green));

Thanks Sönke. I very apprecitiate your work.

Tried this, but it wont compile:
source/app.d(30,13): Error: template vibe.data.serialization.serializeWithPolicy cannot deduce function from argument types !(JsonStringSerializer, UpperCasePolicy)(Test), candidates are:
../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/serialization.d(163,6): vibe.data.serialization.serializeWithPolicy(Serializer, alias Policy, T, ARGS...)(T value, ARGS args)
../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/serialization.d(170,6): vibe.data.serialization.serializeWithPolicy(Serializer, alias Policy, T)(ref Serializer serializer, T value)
source/app.d(33,7): Error: template vibe.data.serialization.deserializeWithPolicy cannot deduce function from argument types !(JsonStringSerializer, UpperCasePolicy, Test)(string), candidates are:
../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/serialization.d(260,3): vibe.data.serialization.deserializeWithPolicy(Serializer, alias Policy, T, ARGS...)(ARGS args)

Tried with:

assert(Json(["color": Json("GREEN")])
     .deserializeWithPolicy!(JsonSerializer, UpperCasePolicy, Test)
     == Test(Color.green));

which compiles, but ends up with:
std.json.JSONException@std/json.d(1205): Got JSON of type string, expected int_, bigInt.

../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/json.d:1049 const(pure @safe void function(immutable(char)[])) vibe.data.json.Json.checkType!(long, std.bigint.BigInt).checkType [0x710363]
../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/json.d:481 vibe.data.json.Json.get!(int).getinout(@property @trusted inout(int) function()) [0x7100bf]
../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/json.d:1643 @safe int vibe.data.json.JsonSerializer.readValue!(int).readValue() [0x710060]
../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/serialization.d:469 @safe int vibe.data.serialization.T15deserializeImplTiS213app15UpperCasePolicyTS4vibe4data4json14JsonSerializerZ.deserializeImpl(ref vibe.data.json.JsonSerializer) [0x710014]
../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/serialization.d:466 @safe app.Color vibe.data.serialization.
T15deserializeImplTE3app5ColorS213app15UpperCasePolicyTS4vibe4data4json14JsonSerializerZ.deserializeImpl(ref vibe.data.json.JsonSerializer) [0x70fffc]
../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/serialization.d:563 @safe void vibe.data.serialization.T15deserializeImplTS3app4TestS213app15UpperCasePolicyTS4vibe4data4json14JsonSerializerZ.deserializeImpl(ref vibe.data.json.JsonSerializer).lambda2!(immutable(char)[]).lambda2(immutable(char)[]) [0x70cef7]
../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/json.d:1613 _D4vibe4data4json14JsonSerializer31
T14readDictionaryTS3app4TestZ14readDictionaryMFMDFAyaZvZ14foreachbody3MFKAyaKS4vibe4data4json4JsonZi [0x70d0bf]
../../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/json.d:444 _D4vibe4data4json4Json7opApplyMFNeDFKAyaKS4vibe4data4json4JsonZiZ14
foreachbody2MFNeKAyaKS4vibe4data4json4JsonZi [0x87f160]
??:? aaApply2 [0x89ff40]
../../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/json.d:442 @trusted int vibe.data.json.Json.opApply(int delegate(ref immutable(char)[], ref vibe.data.json.Json)) [0x87f0eb]
../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/json.d:1611 void vibe.data.json.JsonSerializer.readDictionary!(app.Test).readDictionary(scope void delegate(immutable(char)[])) [0x70cfc0]
../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/serialization.d:551 app.Test vibe.data.serialization.
T15deserializeImplTS3app4TestS213app15UpperCasePolicyTS4vibe4data4json14JsonSerializerZ.deserializeImpl(ref vibe.data.json.JsonSerializer) [0x70ce6d]
../../../.dub/packages/vibe-d-0.7.30-alpha.1/vibe-d/source/vibe/data/serialization.d:262 app.Test vibe.data.serialization.
T21deserializeWithPolicyTS4vibe4data4json14JsonSerializerS213app15UpperCasePolicyTS3app4TestTS4vibe4data4json4JsonZ.deserializeWithPolicy(vibe.data.json.Json) [0x70ce1c]
source/app.d:32
Dmain [0x701f81]

I'm triing this with latest vibe-d alpha and dmd-2.071.0

Also what use has the policy wit the byNameAttribute? Can't find any info about this within documentation.

Thanks, Tom

Re: How to deserialize enum by name but with case insensitive way?

Okay with the PR merged, this works for me now:

template P(T) if (is(T == enum)) {
    static string toRepresentation(T v) { return v.to!string.toLower(); }
    static T fromRepresentation(string str) { return str.toUpper().to!T; }
}

enum E {
    RED,
    GREEN
}

assert(serializeWithPolicy!(JsonSerializer, P)(E.RED) == Json("red"));

Using JsonStringSerializer directly is a little ugly, as it expects an output range. I'll probably add a serializeToJsonWithPolicy kind of function to mitigate that.