package com.cwa.util.automsg.codec;
import com.cwa.gamecore.io.GameInput;
import com.cwa.gamecore.io.GameOutput;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
/**
* 这个类封装Java的Field,不过也提供了Field缓存功能,可以提高性能。
*/
public class ReflectiveField {
private final Field field;
private final Class<?> fieldClass;
private final Class<?> elemClass; // 仅对List字段有效
// 该字段依赖的字段,目前只能依赖boolean类型的字段
private ReflectiveField dependency;
public ReflectiveField(Field field) {
this.field = field;
this.fieldClass = field.getType();
this.field.setAccessible(true);
if (List.class.isAssignableFrom(fieldClass)) {
elemClass = getListElemType(field);
} else {
elemClass = null;
}
}
private static Class<?> getListElemType(Field listField) {
Type type = listField.getGenericType();
if (type instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) type;
Type[] types = paramType.getActualTypeArguments();
return (Class<?>) types[0];
}
throw new RuntimeException("Can not get element's type of list " + listField.getName());
}
public ReflectiveField getDependency() {
return dependency;
}
public void setDependency(ReflectiveField dependency) {
this.dependency = dependency;
}
public boolean getBoolean(Object msg) {
try {
return field.getBoolean(msg);
} catch (Exception e) {
throw new RuntimeException("Fail to read " + field.getName() + " from GameInput.", e);
}
}
// 从输入流中读一个对象
public void get(GameInput in, Object msg) {
try {
if (fieldClass == boolean.class) {
field.setBoolean(msg, in.getBoolean());
} else if (fieldClass == byte.class) {
field.setByte(msg, in.get());
} else if (fieldClass == short.class) {
field.setShort(msg, in.getShort());
} else if (fieldClass == int.class) {
field.setInt(msg, in.getInt());
} else if (fieldClass == long.class) {
field.setLong(msg, in.getLong());
} else if (fieldClass == String.class) {
field.set(msg, in.getString());
} else if (fieldClass == byte[].class) {
field.set(msg, in.getBytes());
} else if (List.class.isAssignableFrom(fieldClass)) {
field.set(msg, getList(in));
} else {
throw new RuntimeException("Unknown field type: " + fieldClass);
}
} catch (InstantiationException e) {
throw new RuntimeException("Fail to read " + field.getName() + " from GameInput.", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Fail to read " + field.getName() + " from GameInput.", e);
}
}
// 往输出流中写一个对象
public void put(GameOutput out, Object msg) {
try {
if (fieldClass == boolean.class) {
out.putBoolean(field.getBoolean(msg));
} else if (fieldClass == byte.class) {
out.put(field.getByte(msg));
} else if (fieldClass == short.class) {
out.putShort(field.getShort(msg));
} else if (fieldClass == int.class) {
out.putInt(field.getInt(msg));
} else if (fieldClass == long.class) {
out.putLong(field.getLong(msg));
} else if (fieldClass == String.class) {
out.putString((String) field.get(msg));
} else if (fieldClass == byte[].class) {
out.putBytes((byte[]) field.get(msg));
} else if (List.class.isAssignableFrom(fieldClass)) {
putList(out, (List<?>) field.get(msg));
} else {
throw new RuntimeException("Unknown field type: " + fieldClass);
}
} catch (IllegalAccessException e) {
throw new RuntimeException("Fail to write " + field.getName() + " into GameOutput.", e);
}
}
// 从输入流中读一个List
public List<?> getList(GameInput in) throws InstantiationException, IllegalAccessException {
int size = in.getShort();
List<Object> list = new ArrayList<Object>(size);
if (size > 0) {
ReflectiveCodec codec = ReflectiveCodecRepository.getCodec(elemClass);
for (int i = 0; i < size; i++) {
Object obj = elemClass.newInstance();
codec.decodeBody(in, obj);
list.add(obj);
}
}
return list;
}
// 往输出流中写一个List
public void putList(GameOutput out, List<?> list) {
out.putShort((short) list.size());
if (list.size() > 0) {
ReflectiveCodec codec = ReflectiveCodecRepository.getCodec(elemClass);
for (Object obj : list) {
codec.encodeBody(out, obj);
}
}
}
@Override
public String toString() {
return "AutoMsgField{" + "field=" + field.getName() + '}';
}
}