package org.molgenis.data.mapper.mapping.model; import com.google.auto.value.AutoValue; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import javax.annotation.Nullable; import java.lang.reflect.Type; import java.util.Collections; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @AutoValue public abstract class CategoryMapping<S, T> { private static Gson gson = new GsonBuilder().serializeNulls().create(); public abstract String getSourceAttributeName(); public abstract Map<S, T> getMap(); @Nullable public abstract T getDefaultValue(); public abstract boolean isDefaultValueUndefined(); @Nullable public abstract T getNullValue(); public abstract boolean isNullValueUndefined(); public static <S, T> CategoryMapping<S, T> create(String sourceAttributeName, Map<S, T> map) { return new AutoValue_CategoryMapping<S, T>(sourceAttributeName, map, null, true, null, true); } public static <S, T> CategoryMapping<S, T> create(String sourceAttributeName, Map<S, T> map, T defaultValue) { return new AutoValue_CategoryMapping<S, T>(sourceAttributeName, map, defaultValue, false, null, true); } public static <S, T> CategoryMapping<S, T> create(String sourceAttributeName, Map<S, T> map, T defaultValue, T nullValue) { return new AutoValue_CategoryMapping<S, T>(sourceAttributeName, map, defaultValue, false, nullValue, false); } public String getAlgorithm() { if (!isNullValueUndefined()) { return String.format("$('%s').map(%s, %s, %s).value();", getSourceAttributeName(), gson.toJson(getMap()), gson.toJson(getDefaultValue()), gson.toJson(getNullValue())); } if (!isDefaultValueUndefined()) { return String.format("$('%s').map(%s, %s).value();", getSourceAttributeName(), gson.toJson(getMap()), gson.toJson(getDefaultValue())); } return String.format("$('%s').map(%s).value();", getSourceAttributeName(), gson.toJson(getMap())); } public static <S, T> CategoryMapping<S, T> createEmpty(String attributeName) { return create(attributeName, Collections.emptyMap()); } public static <S, T> CategoryMapping<S, T> create(String algorithm) { Pattern p = Pattern.compile( "\\$\\('(?<attr>.+)'\\)\\.map\\((?<map>\\{.+\\})(,?(?<default>[^,]+)(,(?<null>.+))?)?\\).value\\(\\);?"); Matcher m = p.matcher(algorithm.replace("\\s", "")); if (!m.matches()) { return null; } // cannot instantiate generic types due to type erasure, so must create them using a TypeToken Type mapType = new TypeToken<Map<S, T>>() { }.getType(); Type tType = new TypeToken<T>() { }.getType(); String attr = m.group("attr"); Map<S, T> map = gson.fromJson(m.group("map"), mapType); String defaultValueString = m.group("default"); if (defaultValueString == null) { return CategoryMapping.<S, T>create(attr, map); } T defaultValue = gson.fromJson(defaultValueString, tType); String nullValueString = m.group("null"); if (nullValueString == null) { return CategoryMapping.<S, T>create(attr, map, defaultValue); } else { T nullValueJson = gson.fromJson(nullValueString, tType); return CategoryMapping.<S, T>create(attr, map, defaultValue, nullValueJson); } } }