java-commons/commons-serialize-databind/src/main/java/io/gitlab/jfronny/commons/serialize/databind/impl/adapter/ArrayTypeAdapterFactory.java

94 lines
3.9 KiB
Java

package io.gitlab.jfronny.commons.serialize.databind.impl.adapter;
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.databind.api.TypeUtils;
import io.gitlab.jfronny.commons.serialize.MalformedDataException;
import io.gitlab.jfronny.commons.serialize.SerializeReader;
import io.gitlab.jfronny.commons.serialize.SerializeWriter;
import io.gitlab.jfronny.commons.serialize.Token;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Type;
import java.util.ArrayList;
public class ArrayTypeAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(ObjectMapper mapper, TypeToken<T> typeToken) {
Type type = typeToken.getType();
if (!(type instanceof GenericArrayType || (type instanceof Class<?> cl && cl.isArray()))) {
return null;
}
Type componentType = TypeUtils.getArrayComponentType(type);
TypeAdapter<?> componentTypeAdapter = mapper.getAdapter(TypeToken.get(componentType));
//noinspection rawtypes,unchecked
return new ArrayTypeAdapter(mapper, componentTypeAdapter, TypeUtils.getRawType(componentType));
}
private static class ArrayTypeAdapter<E> extends TypeAdapter<Object> {
private final Class<E> componentType;
private final TypeAdapter<E> componentTypeAdapter;
public ArrayTypeAdapter(ObjectMapper context, TypeAdapter<E> componentTypeAdapter, Class<E> componentType) {
this.componentTypeAdapter = new TypeAdapterRuntimeTypeWrapper<>(context, componentTypeAdapter, componentType);
this.componentType = componentType;
}
@Override
public <TEx extends Exception, Writer extends SerializeWriter<TEx, Writer>> void serialize(Object value, Writer writer) throws TEx, MalformedDataException {
if (value == null) {
writer.nullValue();
return;
}
writer.beginArray();
int length = Array.getLength(value);
for (int i = 0; i < length; i++) {
E element = (E) Array.get(value, i);
componentTypeAdapter.serialize(element, writer);
}
writer.endArray();
}
@Override
public <TEx extends Exception, Reader extends SerializeReader<TEx, Reader>> Object deserialize(Reader reader) throws TEx, MalformedDataException {
if (reader.peek() == Token.NULL) {
reader.nextNull();
return null;
}
if (reader.isLenient() && reader.peek() != Token.BEGIN_ARRAY) {
// Coerce
Object array = Array.newInstance(componentType, 1);
Array.set(array, 0, componentTypeAdapter.deserialize(reader));
return array;
}
ArrayList<E> list = new ArrayList<>();
reader.beginArray();
while (reader.hasNext()) {
E instance = componentTypeAdapter.deserialize(reader);
list.add(instance);
}
reader.endArray();
int size = list.size();
// Have to copy primitives one by one to primitive array
if (componentType.isPrimitive()) {
Object array = Array.newInstance(componentType, size);
for (int i = 0; i < size; i++) {
Array.set(array, i, list.get(i));
}
return array;
}
// But for Object[] can use ArrayList.toArray
else {
@SuppressWarnings("unchecked")
E[] array = (E[]) Array.newInstance(componentType, size);
return list.toArray(array);
}
}
}
}