com.feilong.lib.xstream.converters.javabean.JavaBeanConverter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of feilong Show documentation
Show all versions of feilong Show documentation
feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.
/*
* Copyright (C) 2005 Joe Walnes.
* Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
* style license a copy of which has been included with this distribution in
* the LICENSE.txt file.
*
* Created on 12. April 2005 by Joe Walnes
*/
package com.feilong.lib.xstream.converters.javabean;
import java.util.HashSet;
import java.util.Set;
import com.feilong.lib.xstream.converters.ConversionException;
import com.feilong.lib.xstream.converters.Converter;
import com.feilong.lib.xstream.converters.MarshallingContext;
import com.feilong.lib.xstream.converters.UnmarshallingContext;
import com.feilong.lib.xstream.converters.reflection.MissingFieldException;
import com.feilong.lib.xstream.core.util.FastField;
import com.feilong.lib.xstream.io.ExtendedHierarchicalStreamWriterHelper;
import com.feilong.lib.xstream.io.HierarchicalStreamReader;
import com.feilong.lib.xstream.io.HierarchicalStreamWriter;
import com.feilong.lib.xstream.mapper.Mapper;
/**
* Can convert any bean with a public default constructor. The {@link BeanProvider} used as default is based on
* {@link java.beans.BeanInfo}. Indexed properties are currently not supported.
*/
public class JavaBeanConverter implements Converter{
/*
* TODO:
* - support indexed properties
* - support attributes (XSTR-620)
* - support local converters (XSTR-601)
* Problem: Mappers take definitions based on reflection, they don't know about bean info
*/
protected final Mapper mapper;
protected final JavaBeanProvider beanProvider;
private final Class type;
/**
* @deprecated As of 1.3, no necessity for field anymore.
*/
@Deprecated
private String classAttributeIdentifier;
public JavaBeanConverter(Mapper mapper){
this(mapper, (Class) null);
}
public JavaBeanConverter(Mapper mapper, Class type){
this(mapper, new BeanProvider(), type);
}
public JavaBeanConverter(Mapper mapper, JavaBeanProvider beanProvider){
this(mapper, beanProvider, null);
}
public JavaBeanConverter(Mapper mapper, JavaBeanProvider beanProvider, Class type){
this.mapper = mapper;
this.beanProvider = beanProvider;
this.type = type;
}
/**
* @deprecated As of 1.3, use {@link #JavaBeanConverter(Mapper)} and
* {@link com.feilong.lib.xstream.XStream#aliasAttribute(String, String)}
*/
@Deprecated
public JavaBeanConverter(Mapper mapper, String classAttributeIdentifier){
this(mapper, new BeanProvider());
this.classAttributeIdentifier = classAttributeIdentifier;
}
/**
* Checks if the bean provider can instantiate this type.
* If you need less strict checks, subclass JavaBeanConverter
*/
@Override
public boolean canConvert(Class type){
return (this.type == null || this.type == type) && beanProvider.canInstantiate(type);
}
@Override
public void marshal(final Object source,final HierarchicalStreamWriter writer,final MarshallingContext context){
final String classAttributeName = mapper.aliasForSystemAttribute("class");
beanProvider.visitSerializableProperties(source, new JavaBeanProvider.Visitor(){
@Override
public boolean shouldVisit(String name,Class definedIn){
return mapper.shouldSerializeMember(definedIn, name);
}
@Override
public void visit(String propertyName,Class fieldType,Class definedIn,Object newObj){
if (newObj != null){
writeField(propertyName, fieldType, newObj);
}else{
writeNullField(propertyName);
}
}
private void writeField(String propertyName,Class fieldType,Object newObj){
Class actualType = newObj.getClass();
Class defaultType = mapper.defaultImplementationOf(fieldType);
String serializedMember = mapper.serializedMember(source.getClass(), propertyName);
ExtendedHierarchicalStreamWriterHelper.startNode(writer, serializedMember, actualType);
if (!actualType.equals(defaultType) && classAttributeName != null){
writer.addAttribute(classAttributeName, mapper.serializedClass(actualType));
}
context.convertAnother(newObj);
writer.endNode();
}
private void writeNullField(final String propertyName){
final String serializedMember = mapper.serializedMember(source.getClass(), propertyName);
ExtendedHierarchicalStreamWriterHelper.startNode(writer, serializedMember, Mapper.Null.class);
writer.addAttribute(classAttributeName, mapper.serializedClass(Mapper.Null.class));
writer.endNode();
}
});
}
@Override
public Object unmarshal(final HierarchicalStreamReader reader,final UnmarshallingContext context){
final Object result = instantiateNewInstance(context);
final Set seenProperties = new HashSet(){
/**
*
*/
private static final long serialVersionUID = -4204717529055942619L;
@Override
public boolean add(Object e){
if (!super.add(e)){
throw new DuplicatePropertyException(((FastField) e).getName());
}
return true;
}
};
Class resultType = result.getClass();
while (reader.hasMoreChildren()){
reader.moveDown();
String propertyName = mapper.realMember(resultType, reader.getNodeName());
if (mapper.shouldSerializeMember(resultType, propertyName)){
boolean propertyExistsInClass = beanProvider.propertyDefinedInClass(propertyName, resultType);
if (propertyExistsInClass){
Class type = determineType(reader, result, propertyName);
Object value = context.convertAnother(result, type);
beanProvider.writeProperty(result, propertyName, value);
seenProperties.add(new FastField(resultType, propertyName));
}else if (!mapper.isIgnoredElement(propertyName)){
throw new MissingFieldException(resultType.getName(), propertyName);
}
}
reader.moveUp();
}
return result;
}
private Object instantiateNewInstance(UnmarshallingContext context){
Object result = context.currentObject();
if (result == null){
result = beanProvider.newInstance(context.getRequiredType());
}
return result;
}
private Class determineType(HierarchicalStreamReader reader,Object result,String fieldName){
final String classAttributeName = classAttributeIdentifier != null ? classAttributeIdentifier
: mapper.aliasForSystemAttribute("class");
String classAttribute = classAttributeName == null ? null : reader.getAttribute(classAttributeName);
if (classAttribute != null){
return mapper.realClass(classAttribute);
}else{
return mapper.defaultImplementationOf(beanProvider.getPropertyType(result, fieldName));
}
}
/**
* @deprecated As of 1.3
*/
@Deprecated
public static class DuplicateFieldException extends ConversionException{
/**
*
*/
private static final long serialVersionUID = 5193033042061884931L;
public DuplicateFieldException(String msg){
super(msg);
}
}
/**
* Exception to indicate double processing of a property to avoid silent clobbering.
*
* @author Jörg Schaible
* @since 1.4.2
*/
public static class DuplicatePropertyException extends ConversionException{
/**
*
*/
private static final long serialVersionUID = 1649950004602558210L;
public DuplicatePropertyException(String msg){
super("Duplicate property " + msg);
add("property", msg);
}
}
}