Elasticsearch-net: Customer Serializer in 6.0.1 NEST

Created on 22 Feb 2018  路  6Comments  路  Source: elastic/elasticsearch-net

NEST/Elasticsearch.Net version: NEST 6.0.1

Description of the problem including expected versus actual behavior:
After update of the NEST to 6.0.1 I have lost possibility to use ContractConverters for my custom deserealization.

I have MyBaseType and a lot of types inherited from it. JsonCreationConverter is needed to convert records of MyBaseType to type written in "ObjType" field.
Unfortunately now there is no method ContractConverters in JsonNetSerealizer moved to another package. Now I can only make list of static contract converters.
List>() was replaced by List()

Is there any way to port the functionality correctly to new 6.0.1 version?

```c#
public class CreationJsonNetSerializer : JsonNetSerializer
{
public CreationJsonNetSerializer(IConnectionSettingsValues settings) : base(settings) { }

    private IList<Func<Type, JsonConverter>> m_ContractConverters =
        new List<Func<Type, JsonConverter>>() { t => t.IsAssignableFrom(typeof(MyBaseType)) ? new JsonCreationConverter() : null };

    protected override IList<Func<Type, JsonConverter>> ContractConverters
    {
        get
        {
            return m_ContractConverters;
        }
    }
}

public class JsonCreationConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (from x in objectType.GetFields()
                where x.Name == "ObjType"
                select x).Count() > 0;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // Load JObject from stream
        JObject jObject = JObject.Load(reader);

        if (FieldExists("ObjType", jObject))
        {
            String objType = jObject["ObjType"].ToString();
            Type resolvedType = GetType(objType);
            Object createdType = Activator.CreateInstance(resolvedType);

            // Populate the object properties
            serializer.Populate(jObject.CreateReader(), createdType);
            return createdType;
        }

        return null;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    private bool FieldExists(string fieldName, JObject jObject)
    {
        return jObject[fieldName] != null;
    }

    public Type GetType(string typeName)
    {
        var type = Type.GetType(typeName);
        if (type != null) return type;
        foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
        {
            type = a.GetType(typeName);
            if (type != null)
                return type;
        }
        return null;
    }
}

```

Most helpful comment

Hi @zabykrinich ,
You can add the Nuget package for Nest.JsonNetSerializer, and pass it to the connection settings like this:

(b, s) => new JsonNetSerializer(b, s, contractJsonConverters: new[] { new JsonCreationConverter() })

I suggest adding that t.IsAssignableFrom(typeof(MyBaseType) to the CanConvert method so it won't iterate countless types.
Be sure to read those docs too as @russcam suggested 馃槈

All 6 comments

@zabykrinich take a look at the documentation on custom serializers.

Hi @zabykrinich ,
You can add the Nuget package for Nest.JsonNetSerializer, and pass it to the connection settings like this:

(b, s) => new JsonNetSerializer(b, s, contractJsonConverters: new[] { new JsonCreationConverter() })

I suggest adding that t.IsAssignableFrom(typeof(MyBaseType) to the CanConvert method so it won't iterate countless types.
Be sure to read those docs too as @russcam suggested 馃槈

Thank you a lot guys! It is working for me.

I found one strange thing with the new way of implementation. Now it enters to CanConvert for every field type in the MyBaseType then for MyBaseType. It is annoying since it takes forever to index even 10000 records. For example when I take bulk index request with 10000 records it starts to call CanConvert for every field and it takes more than 10 minutes to index them.
Is there any way to use JsonCreationConverter only for MyBaseType but not for its fields?

I found one strange thing with the new way of implementation. Now it enters to CanConvert for every field type in the MyBaseType then for MyBaseType.

This is how Json.NET determines if a JsonConverter applies to a given type, by calling CanConvert() for each type. It _may_ do some caching here, not sure.

The converter JsonCreationConverter is a very generic converter though which does a fair amount of reflection and doesn't cache the results. It looks like it achieves something similar to TypeNameHandling; would enabling that work better for your needs?

@zabykrinich I'm going to close this issue as it hasn't had a response for a few months, Feel free to reopen if you believe there's still an issue here :+1:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Mpdreamz picture Mpdreamz  路  5Comments

fredeil picture fredeil  路  4Comments

foleta-developers picture foleta-developers  路  5Comments

jhellemann picture jhellemann  路  4Comments

niemyjski picture niemyjski  路  4Comments