How to Use a Reserved Keyword as an Identifier in My JSON Model Class

How can I use a reserved keyword as an identifier in my JSON model class?

I would suggest to go different way. Keep your C# object model as much standard as possible (I wouldn't use @ sign and C# keywords as property name).

We can separate the serialized (JSON) world and C# objects - just by using the Json.NET features.

One of the simpliest to use is decoration with Attribute:

[JsonProperty(PropertyName = "default")]
public string DefaultValue { get; set; }

In this case we have to reference Newtonsoft.Json in the project. If it must be POCO, we can introduce CustomResolver derrived from DefaultContractResolver and define these conversions there...

But separation of concern in this case is a bit more pure solution, I would say

EDIT: JSON Contract Resolver draft (see comments)

Important NOTE: Newtonsoft.Json is part of the Web API. Not only it is an open source, but even MS team bet on that as a core JSON serializer.

1) Newtonsoft.Json (as a part of the Web.API) is already installed in your solution. So you do not have to downloaded (nuget) separately. It would always be in your packages folder. So, to use the attribute is just adding the reference. It is there...

2) There is a small draft how to do the attribute stuff, while keeping the POCO. As I've tried explain here: POCO's, behavior and Peristance Igorance, to keep POCO (e.g. we do profit from layered Architecture with NHibernate on a data layer), we can replace attributes with a Contract Resolver. Our POCO library does not have to reference anything

We just have to do extend the service layer:

public class MyResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(
MemberInfo member,
MemberSerialization memberSerialization)
{

var jProperty = base.CreateProperty(member, memberSerialization);

var propertyInfo = member as PropertyInfo;
if (propertyInfo == null)
{
return jProperty;
}

// just adjust in case if Property name is DefaultValue
var isDefaultValueProeprty =
propertyInfo.Name.Equals("DefaultValue");

if(isDefaultValueProeprty)
{
jProperty.PropertyName = "default";
}

return jProperty;
}
...

This way we've provided the same information to serailizer as with the [JsonPropertyAttribute].

Now, we just have to use it. There are many ways (e.g. global) but we can do it for a controller only:

protected override void Initialize(HttpControllerContext context)
{
base.Initialize(context);

var jSettings = context.Configuration.Formatters.JsonFormatter.SerializerSettings;
jSettings.ContractResolver = MyResolver;
}

Access to an attribute of a class when the name is a reserved keyword- Python

Peeking through the code of the API you are referencing, it looks like reserved words the convention for their classes is to prefix it with a leading _ (looking here)

So try using item.via._from, the _from is a valid identifier.

Could also be best to call the to_dict or even actual lower-level __dict__ on the object and access it by string, but I think the first should work:


x = item.via._from.id

x = item.to_dict()["via"]["from"]["id"]

# or worst case…

x = item.via.__dict__["from"].id

Creating Java Object with reserved keywords as variable name

If you use GSON for parsing you can name your members as you want and annotate them for mapping.

@SerializedName("abstract")
private String abstractText;

Using reserved words as property names, revisited

In ECMAScript, starting from ES5, reserved words may be used as object property names "in the buff". This means that they don't need to be "clothed" in quotes when defining object literals, and they can be dereferenced (for accessing, assigning, and deleting) on objects without having to use square bracket indexing notation.

That said, reserved words may still NOT be used as identifier names. This is stated quite unambiguously in the spec and is stated somewhat emphatically here (if you don't want your eyes to bleed by having to read the actual language spec)...

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words

The following are keywords and may not be used as variables,
functions, methods, or object identifiers, because ECMAScript
specifies special behavior for them:

Do reserved words need to be quoted when set as property names of JavaScript objects?

ECMAScript 5+

No, quotes were not needed since ECMAScript 5. Here's why:

As mentioned in your post, from the ECMAScript® 5.1 Language Specification:

7.6 Identifier Names and Identifiers


Identifier Names are tokens that are interpreted according to the grammar given in the “Identifiers” section of chapter 5 of the Unicode standard, with some small modifications. An Identifier is an IdentifierName that is not a ReservedWord (see 7.6.1).

[...]

Syntax

Identifier ::
IdentifierName but not ReservedWord

By specification, a ReservedWord is:

7.6.1 Reserved Words


A reserved word is an IdentifierName that cannot be used as an Identifier.

Syntax

ReservedWord :: 
Keyword
FutureReservedWord
NullLiteral
BooleanLiteral

This includes keywords, future keywords, null, and boolean literals. The full list is as follows:

7.6.1.1 Keywords

break    do       instanceof typeof
case else new var
catch finally return void
continue for switch while
debugger function this with
default if throw
delete in try

7.6.1.2 Future Reserved Words

class enum   extends super
const export import

7.8.1 Null Literals

null

7.8.2 Boolean Literals

true
false

The above (Section 7.6) implies that IdentifierNames can be ReservedWords, and from the specification for object initializers:

11.1.5 Object Initialiser


[...]

Syntax

ObjectLiteral :
{ }
{ PropertyNameAndValueList }
{ PropertyNameAndValueList , }

Where PropertyName is, by specification:

PropertyName :
IdentifierName
StringLiteral
NumericLiteral

As you can see, a PropertyName may be an IdentifierName, thus allowing ReservedWords to be PropertyNames. That conclusively tells us that, by specification, it is allowed to have ReservedWords such as class and var as PropertyNames unquoted just like string literals or numeric literals.


ECMAScript <5

To go more in depth as to why this wasn't allowed in previous versions before ES5, you have to look at how PropertyName was defined. Per the ECMAScript® 3 Language Specification:

PropertyName :
Identifier
StringLiteral
NumericLiteral

As you can see, PropertyName was an Identifer - not an IdentifierName, thus leading to the inability for ReservedWords as PropertyNames.

How is this Java project using the language reserved words as identifiers?

While reserved words may not occur in Java source code, they are permitted in compiled Java code. Some code obfuscation tools can make use of this to make decompiling harder. For instance, ProGuard provides the following option:

-obfuscationdictionary filename

Specifies a text file from which all valid words are used as obfuscated field and method names. By default, short names like 'a', 'b', etc. are used as obfuscated names. With an obfuscation dictionary, you can specify a list of reserved key words, or identifiers with foreign characters, for instance. White space, punctuation characters, duplicate words, and comments after a# sign are ignored. Note that an obfuscation dictionary hardly improves the obfuscation. Decent compilers can automatically replace them, and the effect can fairly simply be undone by obfuscating again with simpler names. The most useful application is specifying strings that are typically already present in class files (such as 'Code'), thus reducing the class file sizes just a little bit more. Only applicable when obfuscating.

So if you feed this a list with Java identifiers (such as this one) you end up with a class file that causes syntax errors if decompiled. Of course, you can simply rename the variables to fix these compilation errors (for instance by using ProGuard yourself before decompiling), so this is only a minor inconvenience.

Deserializing url-encoded-form-data with reserved word as variable name

The trick is to tell the compiler to not treat that name as the reserved keyword event, and you do that with an at-sign, like this:

public string @event { get; set; }

Now, you might think this will be similar to using an underscore but that is not correct. The at-sign will actually not become part of the event name, it's just there to tell the compiler to not treat the next word as a reserved keyword, and instead treat it as an identifier.

Also note that everywhere you want to refer to this property, you likely have to keep using the at-sign prefix or that reference will not compile either.

Here's an example:

void Main()
{
Console.WriteLine(nameof(@event));
Console.WriteLine(nameof(_event));
}

public string @event { get; set; }
public string _event { get; set; }

Will output:

event
_event

object to deserialize has a C# keyword

Try using the [DataContract(Name = "@event")] attribute on the relevant property. Then it will (de)serialize correctly, and you can rename the property so that it compiles.



Related Topics



Leave a reply



Submit