91 lines
4.1 KiB
Java
91 lines
4.1 KiB
Java
package io.gitlab.jfronny.commons.serialize.databind.impl.adapter;
|
|
|
|
import io.gitlab.jfronny.commons.serialize.annotations.SerializedName;
|
|
import io.gitlab.jfronny.commons.serialize.databind.ObjectMapper;
|
|
import io.gitlab.jfronny.commons.serialize.databind.api.TypeAdapter;
|
|
import io.gitlab.jfronny.commons.serialize.databind.TypeAdapterFactory;
|
|
import io.gitlab.jfronny.commons.serialize.databind.api.TypeToken;
|
|
import io.gitlab.jfronny.commons.serialize.MalformedDataException;
|
|
import io.gitlab.jfronny.commons.serialize.SerializeReader;
|
|
import io.gitlab.jfronny.commons.serialize.SerializeWriter;
|
|
|
|
import java.lang.reflect.AccessibleObject;
|
|
import java.lang.reflect.Field;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
|
|
public class EnumTypeAdapterFactory implements TypeAdapterFactory {
|
|
@Override
|
|
public <T> TypeAdapter<T> create(ObjectMapper mapper, TypeToken<T> type) {
|
|
Class<? super T> rawRype = type.getRawType();
|
|
if (!Enum.class.isAssignableFrom(rawRype) || rawRype == Enum.class) {
|
|
return null;
|
|
}
|
|
if (!rawRype.isEnum()) {
|
|
rawRype = rawRype.getSuperclass();
|
|
}
|
|
return new EnumTypeAdapter(rawRype);
|
|
}
|
|
|
|
private static class EnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {
|
|
private final Map<String, T> nameToConstant = new HashMap<>();
|
|
private final Map<String, T> stringToConstant = new HashMap<>();
|
|
private final Map<T, String> constantToName = new HashMap<>();
|
|
|
|
public EnumTypeAdapter(final Class<T> classOfT) {
|
|
try {
|
|
// Uses reflection to find enum constants to work around name mismatches for obfuscated
|
|
// classes
|
|
// Reflection access might throw SecurityException, therefore run this in privileged
|
|
// context; should be acceptable because this only retrieves enum constants, but does not
|
|
// expose anything else
|
|
Field[] constantFields;
|
|
{
|
|
Field[] fields = classOfT.getDeclaredFields();
|
|
ArrayList<Field> constantFieldsList = new ArrayList<>(fields.length);
|
|
for (Field f : fields) {
|
|
if (f.isEnumConstant()) {
|
|
constantFieldsList.add(f);
|
|
}
|
|
}
|
|
|
|
constantFields = constantFieldsList.toArray(new Field[0]);
|
|
AccessibleObject.setAccessible(constantFields, true);
|
|
}
|
|
for (Field constantField : constantFields) {
|
|
@SuppressWarnings("unchecked")
|
|
T constant = (T) constantField.get(null);
|
|
String name = constant.name();
|
|
String toStringVal = constant.toString();
|
|
|
|
SerializedName annotation = constantField.getAnnotation(SerializedName.class);
|
|
if (annotation != null) {
|
|
name = annotation.value();
|
|
for (String alternate : annotation.alternate()) {
|
|
nameToConstant.put(alternate, constant);
|
|
}
|
|
}
|
|
nameToConstant.put(name, constant);
|
|
stringToConstant.put(toStringVal, constant);
|
|
constantToName.put(constant, name);
|
|
}
|
|
} catch (IllegalAccessException e) {
|
|
throw new AssertionError(e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public <TEx extends Exception, Writer extends SerializeWriter<TEx, Writer>> void serialize(T value, Writer writer) throws TEx, MalformedDataException {
|
|
writer.value(value == null ? null : constantToName.get(value));
|
|
}
|
|
|
|
@Override
|
|
public <TEx extends Exception, Reader extends SerializeReader<TEx, Reader>> T deserialize(Reader reader) throws TEx, MalformedDataException {
|
|
String key = reader.nextString();
|
|
T constant = nameToConstant.get(key);
|
|
return (constant == null) ? stringToConstant.get(key) : constant;
|
|
}
|
|
}
|
|
}
|