All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jobrunr.utils.mapper.gson.GsonJsonMapper Maven / Gradle / Ivy

Go to download

An easy way to perform background processing on the JVM. Backed by persistent storage. Open and free for commercial use.

There is a newer version: 7.3.1
Show newest version
package org.jobrunr.utils.mapper.gson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapterFactory;
import org.jobrunr.JobRunrException;
import org.jobrunr.jobs.JobParameter;
import org.jobrunr.jobs.context.JobContext;
import org.jobrunr.jobs.states.JobState;
import org.jobrunr.utils.JarUtils;
import org.jobrunr.utils.mapper.JobParameterJsonMapperException;
import org.jobrunr.utils.mapper.JsonMapper;
import org.jobrunr.utils.reflection.ReflectionUtils;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import static java.util.Collections.unmodifiableList;

public class GsonJsonMapper implements JsonMapper {

    private final Gson gson;

    public GsonJsonMapper() {
        this(new GsonBuilder());
    }

    public GsonJsonMapper(GsonBuilder gsonBuilder) {
        this.gson = initGson(gsonBuilder);
        fixGsonNotBeingExtensible(gson);
    }

    public GsonJsonMapper(Gson gson) {
        this.gson = gson;
        fixGsonNotBeingExtensible(gson);
    }

    protected Gson initGson(GsonBuilder gsonBuilder) {
        return gsonBuilder
                .registerTypeAdapterFactory(RuntimeClassNameTypeAdapterFactory.of(JobState.class))
                .registerTypeAdapterFactory(RuntimeClassNameTypeAdapterFactory.of(Map.class))
                .registerTypeAdapterFactory(RuntimeClassNameTypeAdapterFactory.of(JobContext.Metadata.class))
                .registerTypeHierarchyAdapter(Path.class, new PathAdapter().nullSafe())
                .registerTypeAdapter(File.class, new FileAdapter().nullSafe())
                .registerTypeAdapter(Instant.class, new InstantAdapter().nullSafe())
                .registerTypeAdapter(LocalDate.class, new LocalDateAdapter().nullSafe())
                .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeAdapter().nullSafe())
                .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeAdapter().nullSafe())
                .registerTypeAdapter(Duration.class, new DurationAdapter())
                .registerTypeAdapter(JobParameter.class, new JobParameterDeserializer())
                .create();
    }

    @Override
    public String serialize(Object object) {
        try {
            return gson.toJson(object);
        } catch (Exception e) {
            throw new JobParameterJsonMapperException("The job parameters are not serializable.", e);
        }
    }

    @Override
    public void serialize(OutputStream outputStream, Object object) {
        try (final OutputStreamWriter writer = new OutputStreamWriter(outputStream)) {
            gson.toJson(object, writer);
        } catch (IOException e) {
            throw JobRunrException.shouldNotHappenException(e);
        }
    }

    @Override
    public  T deserialize(String serializedObjectAsString, Class clazz) {
        return gson.fromJson(serializedObjectAsString, clazz);
    }

    // I'm really sorry for this
    // see https://github.com/google/gson/issues/1177
    // when deserializing, GSON does not create correct types for items in collections
    private void fixGsonNotBeingExtensible(Gson gson) {
        try {
            final Field factories = ReflectionUtils.getField(Gson.class, "factories");
            ReflectionUtils.makeAccessible(factories);
            final List o = new ArrayList((Collection) factories.get(gson));
            if (!o.get(1).getClass().getName().contains("ObjectTypeAdapter"))
                throw JobRunrException.shouldNotHappenException(String.format("It looks like you are running a Gson version (%s) which is not compatible with JobRunr", JarUtils.getVersion(Gson.class)));
            o.set(1, ClassNameObjectTypeAdapter.FACTORY);
            factories.set(gson, unmodifiableList(o));
        } catch (ReflectiveOperationException e) {
            throw JobRunrException.shouldNotHappenException(e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy