/* * Copyright (C) 2004, 2005, 2006 Joe Walnes. * Copyright (C) 2006, 2007, 2008 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 15. March 2004 by Joe Walnes */ package com.thoughtworks.xstream.core; import com.thoughtworks.xstream.alias.ClassMapper; import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.ConverterLookup; import com.thoughtworks.xstream.converters.DataHolder; import com.thoughtworks.xstream.converters.ErrorWriter; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.core.util.FastStack; import com.thoughtworks.xstream.core.util.HierarchicalStreams; import com.thoughtworks.xstream.core.util.PrioritizedList; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.mapper.Mapper; import java.util.Iterator; public class TreeUnmarshaller implements UnmarshallingContext { private Object root; protected HierarchicalStreamReader reader; private ConverterLookup converterLookup; private Mapper mapper; private FastStack types = new FastStack(16); private DataHolder dataHolder; private final PrioritizedList validationList = new PrioritizedList(); public TreeUnmarshaller( Object root, HierarchicalStreamReader reader, ConverterLookup converterLookup, Mapper mapper) { this.root = root; this.reader = reader; this.converterLookup = converterLookup; this.mapper = mapper; } /** * @deprecated As of 1.2, use * {@link #TreeUnmarshaller(Object, HierarchicalStreamReader, ConverterLookup, Mapper)} */ public TreeUnmarshaller( Object root, HierarchicalStreamReader reader, ConverterLookup converterLookup, ClassMapper classMapper) { this(root, reader, converterLookup, (Mapper)classMapper); } public Object convertAnother(Object parent, Class type) { return convertAnother(parent, type, null); } public Object convertAnother(Object parent, Class type, Converter converter) { type = mapper.defaultImplementationOf(type); if (converter == null) { converter = converterLookup.lookupConverterForType(type); } else { if (!converter.canConvert(type)) { ConversionException e = new ConversionException( "Explicit selected converter cannot handle type"); e.add("item-type", type.getName()); e.add("converter-type", converter.getClass().getName()); throw e; } } return convert(parent, type, converter); } protected Object convert(Object parent, Class type, Converter converter) { try { types.push(type); Object result = converter.unmarshal(reader, this); types.popSilently(); return result; } catch (ConversionException conversionException) { addInformationTo(conversionException, type); throw conversionException; } catch (RuntimeException e) { ConversionException conversionException = new ConversionException(e); addInformationTo(conversionException, type); throw conversionException; } } private void addInformationTo(ErrorWriter errorWriter, Class type) { errorWriter.add("class", type.getName()); errorWriter.add("required-type", getRequiredType().getName()); reader.appendErrors(errorWriter); } public void addCompletionCallback(Runnable work, int priority) { validationList.add(work, priority); } public Object currentObject() { return types.size() == 1 ? root : null; } public Class getRequiredType() { return (Class)types.peek(); } public Object get(Object key) { lazilyCreateDataHolder(); return dataHolder.get(key); } public void put(Object key, Object value) { lazilyCreateDataHolder(); dataHolder.put(key, value); } public Iterator keys() { lazilyCreateDataHolder(); return dataHolder.keys(); } private void lazilyCreateDataHolder() { if (dataHolder == null) { dataHolder = new MapBackedDataHolder(); } } public Object start(DataHolder dataHolder) { this.dataHolder = dataHolder; Class type = HierarchicalStreams.readClassType(reader, mapper); Object result = convertAnother(null, type); Iterator validations = validationList.iterator(); while (validations.hasNext()) { Runnable runnable = (Runnable)validations.next(); runnable.run(); } return result; } protected Mapper getMapper() { return this.mapper; } }