001: /*
002: * Copyright (C) 2004, 2005, 2006 Joe Walnes.
003: * Copyright (C) 2006, 2007 XStream Committers.
004: * All rights reserved.
005: *
006: * The software in this package is published under the terms of the BSD
007: * style license a copy of which has been included with this distribution in
008: * the LICENSE.txt file.
009: *
010: * Created on 15. March 2004 by Joe Walnes
011: */
012: package com.thoughtworks.xstream.core;
013:
014: import com.thoughtworks.xstream.alias.ClassMapper;
015: import com.thoughtworks.xstream.converters.ConversionException;
016: import com.thoughtworks.xstream.converters.Converter;
017: import com.thoughtworks.xstream.converters.ConverterLookup;
018: import com.thoughtworks.xstream.converters.DataHolder;
019: import com.thoughtworks.xstream.converters.ErrorWriter;
020: import com.thoughtworks.xstream.converters.UnmarshallingContext;
021: import com.thoughtworks.xstream.core.util.FastStack;
022: import com.thoughtworks.xstream.core.util.PrioritizedList;
023: import com.thoughtworks.xstream.io.HierarchicalStreamReader;
024: import com.thoughtworks.xstream.mapper.Mapper;
025:
026: import java.util.Iterator;
027:
028: public class TreeUnmarshaller implements UnmarshallingContext {
029:
030: private Object root;
031: protected HierarchicalStreamReader reader;
032: private ConverterLookup converterLookup;
033: private Mapper mapper;
034: private FastStack types = new FastStack(16);
035: private DataHolder dataHolder;
036: private final PrioritizedList validationList = new PrioritizedList();
037:
038: public TreeUnmarshaller(Object root,
039: HierarchicalStreamReader reader,
040: ConverterLookup converterLookup, Mapper mapper) {
041: this .root = root;
042: this .reader = reader;
043: this .converterLookup = converterLookup;
044: this .mapper = mapper;
045: }
046:
047: /**
048: * @deprecated As of 1.2, use
049: * {@link #TreeUnmarshaller(Object, HierarchicalStreamReader, ConverterLookup, Mapper)}
050: */
051: public TreeUnmarshaller(Object root,
052: HierarchicalStreamReader reader,
053: ConverterLookup converterLookup, ClassMapper classMapper) {
054: this (root, reader, converterLookup, (Mapper) classMapper);
055: }
056:
057: public Object convertAnother(Object parent, Class type) {
058: return convertAnother(parent, type, null);
059: }
060:
061: public Object convertAnother(Object parent, Class type,
062: Converter converter) {
063: type = mapper.defaultImplementationOf(type);
064: if (converter == null) {
065: converter = converterLookup.lookupConverterForType(type);
066: } else {
067: if (!converter.canConvert(type)) {
068: ConversionException e = new ConversionException(
069: "Explicit selected converter cannot handle type");
070: e.add("item-type", type.getName());
071: e.add("converter-type", converter.getClass().getName());
072: throw e;
073: }
074: }
075: return convert(parent, type, converter);
076: }
077:
078: protected Object convert(Object parent, Class type,
079: Converter converter) {
080: try {
081: types.push(type);
082: Object result = converter.unmarshal(reader, this );
083: types.popSilently();
084: return result;
085: } catch (ConversionException conversionException) {
086: addInformationTo(conversionException, type);
087: throw conversionException;
088: } catch (RuntimeException e) {
089: ConversionException conversionException = new ConversionException(
090: e);
091: addInformationTo(conversionException, type);
092: throw conversionException;
093: }
094: }
095:
096: private void addInformationTo(ErrorWriter errorWriter, Class type) {
097: errorWriter.add("class", type.getName());
098: errorWriter.add("required-type", getRequiredType().getName());
099: reader.appendErrors(errorWriter);
100: }
101:
102: public void addCompletionCallback(Runnable work, int priority) {
103: validationList.add(work, priority);
104: }
105:
106: public Object currentObject() {
107: return types.size() == 1 ? root : null;
108: }
109:
110: public Class getRequiredType() {
111: return (Class) types.peek();
112: }
113:
114: public Object get(Object key) {
115: lazilyCreateDataHolder();
116: return dataHolder.get(key);
117: }
118:
119: public void put(Object key, Object value) {
120: lazilyCreateDataHolder();
121: dataHolder.put(key, value);
122: }
123:
124: public Iterator keys() {
125: lazilyCreateDataHolder();
126: return dataHolder.keys();
127: }
128:
129: private void lazilyCreateDataHolder() {
130: if (dataHolder == null) {
131: dataHolder = new MapBackedDataHolder();
132: }
133: }
134:
135: public Object start(DataHolder dataHolder) {
136: this .dataHolder = dataHolder;
137: String classAttribute = reader.getAttribute(mapper
138: .aliasForAttribute("class"));
139: Class type;
140: if (classAttribute == null) {
141: type = mapper.realClass(reader.getNodeName());
142: } else {
143: type = mapper.realClass(classAttribute);
144: }
145: Object result = convertAnother(null, type);
146: Iterator validations = validationList.iterator();
147: while (validations.hasNext()) {
148: Runnable runnable = (Runnable) validations.next();
149: runnable.run();
150: }
151: return result;
152: }
153:
154: protected Mapper getMapper() {
155: return this.mapper;
156: }
157:
158: }
|