Skip to content

Indexing JToken objects ignores DefaultFieldNameInferrer #2224

@LordMike

Description

@LordMike

NEST/Elasticsearch.Net version:
2.4.4

Elasticsearch version:
2.3.3

Description of the problem including expected versus actual behavior:
When we Index any object, we normally run through the DefaultFieldNameInferrer - using that we can control the property names in ES. We've used this to fix all names to be lowercase in our project.

But when we index anything containing a JToken, the DefaultFieldNameInferrer is ignored.

Steps to reproduce:

Use the following code.
class Program
{
    static void Main(string[] args)
    {
        ConnectionSettings settings = new ConnectionSettings(new SingleNodeConnectionPool(new Uri("http://127.0.0.1:9200/")));
        settings.DefaultFieldNameInferrer(s => s.ToLower());
        settings.DefaultIndex("testindex");
        settings.ThrowExceptions();

        ElasticClient client = new ElasticClient(settings);
        var item = new MyClass { MyInteger = 5, MyString = "Hello world" };
        var itemAsJtoken = JToken.FromObject(item);

        client.Index(itemAsJtoken);
    }
}

public class MyClass
{
    public string MyString { get; set; }

    public int MyInteger { get; set; }
}
Observe that the auto-created mapping on testindex is as follows:
{
  "testindex" : {
    "mappings" : {
      "jtoken" : {
        "properties" : {
          "MyInteger" : {
            "type" : "long"
          },
          "MyString" : {
            "type" : "string"
          }
        }
      }
    }
  }
}

If we index the item instead of itemAsJtoken, we get the following map:

{
  "testindex" : {
    "mappings" : {
      "myclass" : {
        "properties" : {
          "myinteger" : {
            "type" : "long"
          },
          "mystring" : {
            "type" : "string"
          }
        }
      }
    }
  }
}

Relevant sources:
We found an issue in Newtonsoft.NET, where they've changed the way the contract resolvers are called. It seems that the DefaultContractResolver in Newtonsoft no longer calls its ResolvePropertyName method, which is used internally by NEST. The issue for that is here:

JamesNK/Newtonsoft.Json/issues/950

We can reproduce this by creating the following code:

class Program
{
    static void Main(string[] args)
    {
        var item = new MyClass { MyInteger = 5, MyString = "Hello world" };
        var itemAsJtoken = JToken.FromObject(item);

        var serializerSettings = new JsonSerializerSettings();
        serializerSettings.ContractResolver = new MyContractResolver();

        var serializer = JsonSerializer.Create(serializerSettings);

        StringBuilder sb = new StringBuilder();
        using (var sw = new StringWriter(sb))
            serializer.Serialize(sw, itemAsJtoken);

        Console.WriteLine(sb.ToString());
    }
}

public class MyClass
{
    public string MyString { get; set; }

    public int MyInteger { get; set; }
}

internal class MyContractResolver : DefaultContractResolver
{
    protected override string ResolvePropertyName(string propertyName)
    {
        return propertyName.ToLower();
    }
}

Relevant people (on my end): @Genbox

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions