--- old/src/java.xml.bind/share/classes/com/sun/xml/internal/bind/v2/runtime/property/SingleMapNodeProperty.java 2018-01-30 20:34:05.000000000 -0500 +++ /dev/null 2018-01-30 20:34:05.000000000 -0500 @@ -1,321 +0,0 @@ -/* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.xml.internal.bind.v2.runtime.property; - -import java.io.IOException; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.TreeMap; -import java.util.Collection; -import java.util.Collections; -import java.util.Arrays; -import java.util.Set; - -import javax.xml.stream.XMLStreamException; -import javax.xml.namespace.QName; - -import com.sun.xml.internal.bind.api.AccessorException; -import com.sun.xml.internal.bind.v2.ClassFactory; -import com.sun.xml.internal.bind.v2.util.QNameMap; -import com.sun.xml.internal.bind.v2.model.core.PropertyKind; -import com.sun.xml.internal.bind.v2.model.runtime.RuntimeMapPropertyInfo; -import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl; -import com.sun.xml.internal.bind.v2.runtime.JaxBeanInfo; -import com.sun.xml.internal.bind.v2.runtime.Name; -import com.sun.xml.internal.bind.v2.runtime.XMLSerializer; -import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; -import com.sun.xml.internal.bind.v2.runtime.unmarshaller.ChildLoader; -import com.sun.xml.internal.bind.v2.runtime.unmarshaller.TagName; -import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader; -import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Receiver; -import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext; -import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.State; - -import org.xml.sax.SAXException; - -/** - * @author Kohsuke Kawaguchi - */ -final class SingleMapNodeProperty extends PropertyImpl { - - private final Accessor acc; - /** - * The tag name that surrounds the whole property. - */ - private final Name tagName; - /** - * The tag name that corresponds to the 'entry' element. - */ - private final Name entryTag; - private final Name keyTag; - private final Name valueTag; - - private final boolean nillable; - - private JaxBeanInfo keyBeanInfo; - private JaxBeanInfo valueBeanInfo; - - /** - * The implementation class for this property. - * If the property is null, we create an instance of this class. - */ - private final Class mapImplClass; - - public SingleMapNodeProperty(JAXBContextImpl context, RuntimeMapPropertyInfo prop) { - super(context, prop); - acc = prop.getAccessor().optimize(context); - this.tagName = context.nameBuilder.createElementName(prop.getXmlName()); - this.entryTag = context.nameBuilder.createElementName("","entry"); - this.keyTag = context.nameBuilder.createElementName("","key"); - this.valueTag = context.nameBuilder.createElementName("","value"); - this.nillable = prop.isCollectionNillable(); - this.keyBeanInfo = context.getOrCreate(prop.getKeyType()); - this.valueBeanInfo = context.getOrCreate(prop.getValueType()); - - // infer the implementation class - //noinspection unchecked - Class sig = (Class) Utils.REFLECTION_NAVIGATOR.erasure(prop.getRawType()); - mapImplClass = ClassFactory.inferImplClass(sig,knownImplClasses); - // TODO: error check for mapImplClass==null - // what is the error reporting path for this part of the code? - } - - private static final Class[] knownImplClasses = { - HashMap.class, TreeMap.class, LinkedHashMap.class - }; - - public void reset(BeanT bean) throws AccessorException { - acc.set(bean,null); - } - - - /** - * A Map property can never be ID. - */ - public String getIdValue(BeanT bean) { - return null; - } - - public PropertyKind getKind() { - return PropertyKind.MAP; - } - - public void buildChildElementUnmarshallers(UnmarshallerChain chain, QNameMap handlers) { - keyLoader = keyBeanInfo.getLoader(chain.context,true); - valueLoader = valueBeanInfo.getLoader(chain.context,true); - handlers.put(tagName,new ChildLoader(itemsLoader,null)); - } - - private Loader keyLoader; - private Loader valueLoader; - - /** - * Handles {@code } and {@code }. - * - * The target will be set to a {@link Map}. - */ - private final Loader itemsLoader = new Loader(false) { - - private ThreadLocal> target = new ThreadLocal>(); - private ThreadLocal> map = new ThreadLocal>(); - - @Override - public void startElement(UnmarshallingContext.State state, TagName ea) throws SAXException { - // create or obtain the Map object - try { - BeanT target = (BeanT) state.getPrev().getTarget(); - ValueT mapValue = acc.get(target); - if(mapValue == null) - mapValue = ClassFactory.create(mapImplClass); - else - mapValue.clear(); - - Stack.push(this.target, target); - Stack.push(map, mapValue); - state.setTarget(mapValue); - } catch (AccessorException e) { - // recover from error by setting a dummy Map that receives and discards the values - handleGenericException(e,true); - state.setTarget(new HashMap()); - } - } - - @Override - public void leaveElement(State state, TagName ea) throws SAXException { - super.leaveElement(state, ea); - try { - acc.set(Stack.pop(target), Stack.pop(map)); - } catch (AccessorException ex) { - handleGenericException(ex,true); - } - } - - @Override - public void childElement(UnmarshallingContext.State state, TagName ea) throws SAXException { - if(ea.matches(entryTag)) { - state.setLoader(entryLoader); - } else { - super.childElement(state,ea); - } - } - - @Override - public Collection getExpectedChildElements() { - return Collections.singleton(entryTag.toQName()); - } - }; - - /** - * Handles {@code } and {@code }. - * - * The target will be set to a {@link Map}. - */ - private final Loader entryLoader = new Loader(false) { - @Override - public void startElement(UnmarshallingContext.State state, TagName ea) { - state.setTarget(new Object[2]); // this is inefficient - } - - @Override - public void leaveElement(UnmarshallingContext.State state, TagName ea) { - Object[] keyValue = (Object[])state.getTarget(); - Map map = (Map) state.getPrev().getTarget(); - map.put(keyValue[0],keyValue[1]); - } - - @Override - public void childElement(UnmarshallingContext.State state, TagName ea) throws SAXException { - if(ea.matches(keyTag)) { - state.setLoader(keyLoader); - state.setReceiver(keyReceiver); - return; - } - if(ea.matches(valueTag)) { - state.setLoader(valueLoader); - state.setReceiver(valueReceiver); - return; - } - super.childElement(state,ea); - } - - @Override - public Collection getExpectedChildElements() { - return Arrays.asList(keyTag.toQName(),valueTag.toQName()); - } - }; - - private static final class ReceiverImpl implements Receiver { - private final int index; - public ReceiverImpl(int index) { - this.index = index; - } - public void receive(UnmarshallingContext.State state, Object o) { - ((Object[])state.getTarget())[index] = o; - } - } - - private static final Receiver keyReceiver = new ReceiverImpl(0); - private static final Receiver valueReceiver = new ReceiverImpl(1); - - @Override - public void serializeBody(BeanT o, XMLSerializer w, Object outerPeer) throws SAXException, AccessorException, IOException, XMLStreamException { - ValueT v = acc.get(o); - if(v!=null) { - bareStartTag(w,tagName,v); - for( Map.Entry e : (Set)v.entrySet() ) { - bareStartTag(w,entryTag,null); - - Object key = e.getKey(); - if(key!=null) { - w.startElement(keyTag,key); - w.childAsXsiType(key,fieldName,keyBeanInfo, false); - w.endElement(); - } - - Object value = e.getValue(); - if(value!=null) { - w.startElement(valueTag,value); - w.childAsXsiType(value,fieldName,valueBeanInfo, false); - w.endElement(); - } - - w.endElement(); - } - w.endElement(); - } else - if(nillable) { - w.startElement(tagName,null); - w.writeXsiNilTrue(); - w.endElement(); - } - } - - private void bareStartTag(XMLSerializer w, Name tagName, Object peer) throws IOException, XMLStreamException, SAXException { - w.startElement(tagName,peer); - w.endNamespaceDecls(peer); - w.endAttributes(); - } - - @Override - public Accessor getElementPropertyAccessor(String nsUri, String localName) { - if(tagName.equals(nsUri,localName)) - return acc; - return null; - } - - private static final class Stack { - private Stack parent; - private T value; - - private Stack(Stack parent, T value) { - this.parent = parent; - this.value = value; - } - - private Stack(T value) { - this.value = value; - } - - private static void push(ThreadLocal> holder, T value) { - Stack parent = holder.get(); - if (parent == null) - holder.set(new Stack(value)); - else - holder.set(new Stack(parent, value)); - } - - private static T pop(ThreadLocal> holder) { - Stack current = holder.get(); - if (current.parent == null) - holder.remove(); - else - holder.set(current.parent); - return current.value; - } - - } -}