背景
<student Id="1" ClassId="2">小王八</studuent>
@XStreamAlias("student")
public class Student {
@XStreamAlias("Id")
@XStreamAsAttribute
private String id;
@XStreamAlias("ClassId")
@XStreamAsAttribute
private String classId;
private String value;
// omit setters and getters
}
像这种把bean的某个属性当成value值得,目前的XStream还没找到解决方法
实现Converter接口
public class StudentXStreamConverter implements Converter {
@Override
public void marshal(Object o, HierarchicalStreamWriter hierarchicalStreamWriter, MarshallingContext marshallingContext) {
final Student student = (Student ) o;
hierarchicalStreamWriter.addAttribute("id",student.getId());
hierarchicalStreamWriter.addAttribute("classId",student.getClassId());
hierarchicalStreamWriter.setValue(student.getValue());
}
@Override
public Object unmarshal(HierarchicalStreamReader hierarchicalStreamReader, UnmarshallingContext unmarshallingContext) {
final Student stduent = new Student ();// 在解析attribute元素时,先创建一个对象
stduent.setId(hierarchicalStreamReader.getAttritute("id));
stduent.setClassId(hierarchicalStreamReader.getAttritute("classId));
stduent.setVaue(hierarchicalStreamReader.getValue();
return stduent ;
}
@Override
public boolean canConvert(Class clazz) {
return clazz == Student.class;
}
}
这种写法100个bean就要写100份差不多的代码,显然不合适
重复功能抽象到父类
/**
* @param <T> 支持的转换类型,T 必须有一个无参构造函数 {@link #newInstance()}
* @author len
*/
public abstract class AbstractXStreamConverter<T> implements Converter {
protected final Class<T> clazz;
public AbstractXStreamConverter() {
clazz = parseClazz();
}
@SuppressWarnings("unchecked")
private Class<T> parseClazz() {
val genericSuperclass = getClass().getGenericSuperclass();
ParameterizedType superclass = (ParameterizedType) genericSuperclass;
return (Class<T>) superclass.getActualTypeArguments()[0];
}
@Override
@SuppressWarnings("unchecked")
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
doMarshal((T) source, writer, context);
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
final T instance = newInstance();
doUnmarshal(instance, reader, context);
return instance;
}
protected abstract void doMarshal(T source, HierarchicalStreamWriter writer, MarshallingContext context);
protected abstract void doUnmarshal(T instance, HierarchicalStreamReader reader, UnmarshallingContext context);
@Override
public boolean canConvert(Class type) {
return type == clazz;
}
protected T newInstance() {
try {
Constructor<T> constructor = clazz.getConstructor();
if (constructor == null) {
throw new IllegalArgumentException("必须提供无参构造器");
}
return constructor.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
基于反射,抽取了canConvert,类型转化以及创建实例的过程
进一步特性化,使用元数据反射序列化和反序列化
/**
* 元数据收集器接口
*
* @author len
*/
@FunctionalInterface
public interface MetaInfoCollector<T> {
T collect(Class<?> clazz);
}
/**
* 元数据
* @author len
*/
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true)
@Getter
public class PropertyManager {
private Method reader;
private Method writer;
private String name;
}
/**
* @author len
*/
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@Getter
public class PropertyManagers {
@Nullable
PropertyManager value;
@Nullable
List<PropertyManager> attributes;
}
/**
* @param <T> {@link AbstractXStreamConverter} T 必须是一个叶子元素,必须符合java bean规范,且所有的属性必须是{@code String }类型
* @author len
*/
public abstract class BaseMetaLeafElementXStreamConverter<T> extends AbstractXStreamConverter<T> implements MetaInfoCollector<PropertyManagers> {
private static final Map<Class<?>, PropertyManagers> CACHE = new ConcurrentHashMap<>(64);
public BaseMetaLeafElementXStreamConverter() {
initMetaInfo();
}
private void initMetaInfo() {
PropertyManagers propertyManagers = CACHE.get(clazz);
if (propertyManagers == null) {
synchronized (clazz) {
// noinspection ConstantConditions
if (propertyManagers == null) {
CACHE.put(clazz, collect(clazz));
}
}
}
}
@Override
protected void doMarshal(T source, HierarchicalStreamWriter writer, MarshallingContext context) {
val propertyManagers = CACHE.get(clazz);
try {
val attributes = propertyManagers.getAttributes();
if (!CollectionUtils.isEmpty(attributes)) {
for (PropertyManager attribute : attributes) {
writer.addAttribute(attribute.getName(), toEmptyStringIfNull(attribute.getReader().invoke(source)));
}
}
val value = propertyManagers.getValue();
if (value != null) {
writer.setValue(toEmptyStringIfNull(value.getReader().invoke(source)));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
protected void doUnmarshal(T instance, HierarchicalStreamReader reader, UnmarshallingContext context) {
val propertyManagers = CACHE.get(clazz);
val attributes = propertyManagers.getAttributes();
try {
if (!CollectionUtils.isEmpty(attributes)) {
for (PropertyManager attribute : attributes) {
val attributeValue = reader.getAttribute(attribute.getName());
attribute.getWriter().invoke(instance, attributeValue);
}
}
val value = propertyManagers.getValue();
if (value != null) {
value.getWriter().invoke(instance, reader.getValue());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static String toEmptyStringIfNull(Object object) {
return object == null ? "" : object.toString();
}
}
使用XStream原生注解作为元数据源
/**
* 基于XStream原生注解的实现
* @param <T> T {@link BaseMetaLeafElementXStreamConverter}
* @author len
*/
public abstract class XStreamAnnotationLeafElementConverter<T> extends BaseMetaLeafElementXStreamConverter<T> {
@Override
public PropertyManagers collect(Class<?> clazz) {
try {
val beanInfo = Introspector.getBeanInfo(clazz);
val propertyDescriptors = beanInfo.getPropertyDescriptors();
val propertyManagers = new ArrayList<PropertyManager>();
PropertyManager valuePropertyManager = null;
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
String name = propertyDescriptor.getName();
if (name.equals("class")) {
continue;
}
if (name.equals("value")) {
valuePropertyManager = new PropertyManager(propertyDescriptor.getReadMethod(), propertyDescriptor.getWriteMethod(), "value");
continue;
}
val field = clazz.getDeclaredField(name) != null ? clazz.getDeclaredField(name) : clazz.getField(name);
if (field != null) {
val attribute = field.getAnnotation(XStreamAsAttribute.class);
if (attribute != null) {
String value = name;
val alias = field.getAnnotation(XStreamAlias.class);
if (alias != null) {
value = alias.value();
}
propertyManagers.add(new PropertyManager(propertyDescriptor.getReadMethod(), propertyDescriptor.getWriteMethod(), StringUtils.isEmpty(value) ? name : value));
}
}
}
return new PropertyManagers(valuePropertyManager, propertyManagers);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
demo
public class StudentConverter extends XStreamAnnotationLeafElementConverter<Student> {
}