Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom serializers for KV reducible maps #68

Open
bsless opened this issue Dec 20, 2022 · 1 comment
Open

Add custom serializers for KV reducible maps #68

bsless opened this issue Dec 20, 2022 · 1 comment

Comments

@bsless
Copy link
Contributor

bsless commented Dec 20, 2022

Currently, jsonista uses the default Map serializer which iterates over map entries, causing an allocation of an entry each iteration.
Using the kv reduce API should be faster.

@bsless
Copy link
Contributor Author

bsless commented Dec 20, 2022

This sketch implementation compiles, I haven't checked it yet:

package jsonista.jackson;

import java.util.Map;
import java.util.Set;
import clojure.lang.PersistentArrayMap;
import clojure.lang.IKVReduce;
import clojure.lang.IFn;
import clojure.lang.AFn;
import clojure.lang.Util;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.MapSerializer;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;


import java.io.IOException;

public class PersistentArrayMapSerializer extends MapSerializer {

    @SuppressWarnings("unchecked")
    protected PersistentArrayMapSerializer
        (Set<String> ignoredEntries, Set<String> includedEntries,
         JavaType keyType, JavaType valueType, boolean valueTypeIsStatic,
         TypeSerializer vts,
         JsonSerializer<?> keySerializer, JsonSerializer<?> valueSerializer)
    {
        super(ignoredEntries, includedEntries, keyType, valueType, valueTypeIsStatic, vts, keySerializer, valueSerializer);
    }


    public final JsonSerializer<Object> _findSerializer(SerializerProvider provider,
                                                         Object value)
        throws JsonMappingException
    {
        final Class<?> cc = value.getClass();
        JsonSerializer<Object> valueSer = _dynamicValueSerializers.serializerFor(cc);
        if (valueSer != null) {
            return valueSer;
        }
        if (_valueType.hasGenericTypes()) {
            return _findAndAddDynamic(_dynamicValueSerializers,
                                      provider.constructSpecializedType(_valueType, cc), provider);
        }
        return _findAndAddDynamic(_dynamicValueSerializers, cc, provider);
    }

    @Override
    public void serializeFields(Map<?,?> m, JsonGenerator gen, SerializerProvider provider)
        throws IOException
    {
        final IKVReduce value = (IKVReduce) m;
        // If value type needs polymorphic type handling, some more work needed:
        if (_valueTypeSerializer != null) {
            serializeTypedFields(m, gen, provider, null);
            return;
        }
        final JsonSerializer<Object> keySerializer = _keySerializer;
        Object keyElem = null;


        try {
            value.kvreduce(new AFn ()
                {
                    public Object invoke(Object init, Object keyElem, Object valueElem) {
                        try
                            {
                                // First, serialize key
                                if (keyElem == null) {
                                    provider.findNullKeySerializer(_keyType, _property).serialize(null, gen, provider);
                                } else {
                                    // One twist: is entry ignorable? If so, skip
                                    if ((_inclusionChecker != null) && _inclusionChecker.shouldIgnore(keyElem)) {
                                        return null;
                                    }
                                    keySerializer.serialize(keyElem, gen, provider);
                                }
                                // And then value
                                if (valueElem == null) {
                                    provider.defaultSerializeNull(gen);
                                    return null;
                                }
                                JsonSerializer<Object> serializer = _valueSerializer;
                                if (serializer == null) {
                                    serializer = _findSerializer(provider, valueElem);
                                }
                                serializer.serialize(valueElem, gen, provider);
                                return null;
                            }
                        catch (Exception e) {throw Util.sneakyThrow(e);}
                    }
                },
                null);
        }
        catch (Exception e) { // Add reference information
            wrapAndThrow(provider, e, m, String.valueOf(keyElem));
        }
    }

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant