Package com.envoisolutions.sxc.jaxb

Source Code of com.envoisolutions.sxc.jaxb.UnmarshallerImpl

/**
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package com.envoisolutions.sxc.jaxb;

import java.util.HashMap;
import java.util.Map;
import java.io.File;
import java.io.InputStream;
import java.io.Reader;
import java.net.URL;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.UnmarshalException;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.PropertyException;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.attachment.AttachmentUnmarshaller;
import javax.xml.bind.helpers.ValidationEventImpl;
import javax.xml.bind.helpers.DefaultValidationEventHandler;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.validation.Schema;

import com.envoisolutions.sxc.util.XoXMLStreamReader;
import com.envoisolutions.sxc.util.XoXMLStreamReaderImpl;
import com.envoisolutions.sxc.util.RuntimeXMLStreamException;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

@SuppressWarnings({"unchecked"})
public class UnmarshallerImpl implements Unmarshaller {
    private final JAXBIntrospectorImpl introspector;

    private final XMLInputFactory xif = XMLInputFactory.newInstance();
    private final DatatypeFactory dtFactory;

    private final Map<Class<?>, ? super XmlAdapter> adapters = new HashMap<Class<?>, XmlAdapter>();
    private Listener listener;
    private Schema schema;
    private AttachmentUnmarshaller attachmentUnmarshaller;
    private ValidationEventHandler handler;

    public UnmarshallerImpl(JAXBIntrospectorImpl introspector) throws JAXBException {
        this.introspector = introspector;
        try {
            dtFactory = DatatypeFactory.newInstance();
        } catch (DatatypeConfigurationException e) {
            throw new JAXBException("Could not create datatype factory.", e);
        }
    }

    private XMLStreamReader createXMLStreamReader(InputSource source) throws UnmarshalException {
        StreamSource streamSource = new StreamSource();
        streamSource.setSystemId(source.getSystemId());
        streamSource.setPublicId(source.getPublicId());
        streamSource.setInputStream(source.getByteStream());
        streamSource.setReader(source.getCharacterStream());
        XMLStreamReader streamReader = createXMLStreamReader(streamSource);
        return streamReader;
    }

    private XMLStreamReader createXMLStreamReader(Source source) throws UnmarshalException {
        if (source == null) throw new IllegalArgumentException("source is null");

        XMLStreamReader streamReader;
        try {
            streamReader = xif.createXMLStreamReader(source);
        } catch (XMLStreamException e) {
            throw new UnmarshalException(e);
        }
        return streamReader;
    }

    public Object unmarshal(File file) throws JAXBException {
        if (file == null) throw new IllegalArgumentException("file is null");

        XMLStreamReader streamReader = createXMLStreamReader(new StreamSource(file));
        return unmarshal(streamReader);
    }

    public Object unmarshal(InputStream inputStream) throws JAXBException {
        if (inputStream == null) throw new IllegalArgumentException("inputStream is null");

        XMLStreamReader streamReader = createXMLStreamReader(new StreamSource(inputStream));
        return unmarshal(streamReader);
    }

    public Object unmarshal(Reader reader) throws JAXBException {
        if (reader == null) throw new IllegalArgumentException("reader is null");

        XMLStreamReader streamReader = createXMLStreamReader(new StreamSource(reader));
        return unmarshal(streamReader);
    }

    public Object unmarshal(URL url) throws JAXBException {
        if (url == null) throw new IllegalArgumentException("url is null");

        XMLStreamReader streamReader = createXMLStreamReader(new StreamSource(url.toExternalForm()));
        return unmarshal(streamReader);
    }

    public <T> JAXBElement<T>  unmarshal(InputSource inputSource, Class<T> declaredType) throws JAXBException {
        if (inputSource == null) throw new IllegalArgumentException("inputSource is null");

        XMLStreamReader streamReader = createXMLStreamReader(inputSource);
        return unmarshal(streamReader, declaredType);
    }

    public Object unmarshal(InputSource inputSource) throws JAXBException {
        if (inputSource == null) throw new IllegalArgumentException("inputSource is null");

        XMLStreamReader streamReader = createXMLStreamReader(inputSource);
        return unmarshal(streamReader);
    }

    public <T> JAXBElement<T> unmarshal(Node node, Class<T> declaredType) throws JAXBException {
        if (node == null) throw new IllegalArgumentException("node is null");
        if (declaredType == null) throw new IllegalArgumentException("declaredType is null");

        XMLStreamReader streamReader = createXMLStreamReader(new DOMSource(node));
        return unmarshal(streamReader, declaredType);
    }

    public Object unmarshal(Node node) throws JAXBException {
        if (node == null) throw new IllegalArgumentException("node is null");

        XMLStreamReader streamReader = createXMLStreamReader(new DOMSource(node));
        return unmarshal(streamReader);
    }

    public <T> JAXBElement<T> unmarshal(Source source, Class<T> declaredType) throws JAXBException {
        if (source == null) throw new IllegalArgumentException("source is null");
        if (declaredType == null) throw new IllegalArgumentException("declaredType is null");

        if (source instanceof SAXSource) {
            SAXSource saxSource = (SAXSource) source;
            return (JAXBElement<T>) unmarshal2(saxSource, declaredType);
        } else {
            XMLStreamReader streamReader = createXMLStreamReader(source);
            return unmarshal(streamReader, declaredType);
        }
    }

    public Object unmarshal(Source source) throws JAXBException {
        if (source == null) throw new IllegalArgumentException("source is null");

        if (source instanceof SAXSource) {
            SAXSource saxSource = (SAXSource) source;
            return unmarshal(saxSource, null);
        } else {
            XMLStreamReader streamReader = createXMLStreamReader(source);
            return unmarshal(streamReader);
        }
    }

    private Object unmarshal2(SAXSource saxSource, Class<?> declaredType) throws JAXBException {
        if (saxSource == null) throw new IllegalArgumentException("saxSource is null");

        InputSource inputSource = saxSource.getInputSource();
        if (inputSource == null) {
            throw new UnmarshalException("source.getInputSource() is null");
        }

        XMLReader xmlReader = saxSource.getXMLReader();
        if (xmlReader == null) {
            // no Sax parser specified so we can just use Stax
            if (declaredType != null) {
                return unmarshal(inputSource, declaredType);
            } else {
                return unmarshal(inputSource);
            }
        }

        UnmarshallerHandlerImpl unmarshallerHandler = getUnmarshallerHandler();
        unmarshallerHandler.setType(declaredType);
        xmlReader.setContentHandler(unmarshallerHandler);
        try {
            xmlReader.parse(inputSource);
        } catch (Exception e) {
            throw new JAXBException("Error reading XML stream.", e);
        }
        return unmarshallerHandler.getResult();
    }

    public <T> JAXBElement<T> unmarshal(XMLEventReader xmlEventReader, Class<T> declaredType) throws JAXBException {
        if (xmlEventReader == null) throw new IllegalArgumentException("xmlEventReader is null");
        if (declaredType == null) throw new IllegalArgumentException("declaredType is null");

        XMLEventStreamReader streamReader = new XMLEventStreamReader(xmlEventReader);
        return unmarshal(streamReader, declaredType);
    }

    public Object unmarshal(XMLEventReader xmlEventReader) throws JAXBException {
        if (xmlEventReader == null) throw new IllegalArgumentException("xmlEventReader is null");

        XMLEventStreamReader streamReader = new XMLEventStreamReader(xmlEventReader);
        return unmarshal(streamReader);
    }

    public <T> JAXBElement<T> unmarshal(XMLStreamReader xmlStreamReader, Class<T> declaredType) throws JAXBException {
        if (xmlStreamReader == null) throw new IllegalArgumentException("xmlStreamReader is null");
        if (declaredType == null) throw new IllegalArgumentException("declaredType is null");

        RuntimeContext runtimeContext = new RuntimeContext(this);
        JAXBElement<T> element = (JAXBElement<T>) read(xmlStreamReader, declaredType, true, runtimeContext);
        runtimeContext.resolveXmlIdRefs();
        return element;
    }

    public Object unmarshal(XMLStreamReader xmlStreamReader) throws JAXBException {
        if (xmlStreamReader == null) throw new IllegalArgumentException("xmlStreamReader is null");

        RuntimeContext runtimeContext = new RuntimeContext(this);
        Object value = read(xmlStreamReader, null, null, runtimeContext);
        runtimeContext.resolveXmlIdRefs();       
        return value;
    }

    public Object read(XMLStreamReader xmlStreamReader, Class<?> declaredType, Boolean jaxbElementWrap, RuntimeContext runtimeContext) throws JAXBException {
        if (xmlStreamReader == null) throw new IllegalArgumentException("xmlStreamReader is null");
        if (runtimeContext == null) throw new IllegalArgumentException("runtimeContext is null");

        XoXMLStreamReader reader = new XoXMLStreamReaderImpl(xmlStreamReader);
        try {
            int event = reader.getEventType();
            while (event != XMLStreamConstants.START_ELEMENT && reader.hasNext()) {
                event = reader.next();
            }

            if (event != XMLStreamConstants.START_ELEMENT) {
                // TODO: empty document - figure out what is appropriate per spec
                return null;
            }

            // read and save element name before stream advances
            QName name = reader.getName();

            Object o = null;
            if (reader.isXsiNil()) {
                // was xsi:nil
                return null;
            } else if (reader.getXsiType() != null) {
                // find the marshaller by xsi:type
                JAXBObject instance = introspector.getJaxbMarshallerBySchemaType(reader.getXsiType());
                if (instance != null) {
                    if (declaredType == null) declaredType = Object.class;
                    if (jaxbElementWrap == nulljaxbElementWrap =  instance.getXmlRootElement() == null;

                    // check assignment is possible
                    if (declaredType.isAssignableFrom(instance.getType())) {
                        // read the object
                        o = instance.read(reader, runtimeContext);
                    } else {
                        String message = "Expected instance of " + declaredType.getName() + ", but found xsi:type " + reader.getXsiType() + " which is mapped to " + instance.getType().getName();
                        if (getEventHandler() == null || !getEventHandler().handleEvent(new ValidationEventImpl(ValidationEvent.ERROR, message, new ValidationEventLocatorImpl(reader.getLocation())))) {
                            throw new UnmarshalException(message);
                        }
                        jaxbElementWrap = false;
                    }
                } else {
                    String message = "No JAXB object for XML type " + reader.getXsiType();
                    if (getEventHandler() == null || !getEventHandler().handleEvent(new ValidationEventImpl(ValidationEvent.ERROR, message, new ValidationEventLocatorImpl(reader.getLocation())))) {
                        throw new UnmarshalException(message);
                    }
                    jaxbElementWrap = false;
                }
            } else if (declaredType != null && !Object.class.equals(declaredType)) {
                // check built in types first
                if (String.class.equals(declaredType)) {
                    o = reader.getElementAsString();
                } else if (Boolean.class.equals(declaredType)) {
                    o = reader.getElementAsBoolean();
                } else if (Double.class.equals(declaredType)) {
                    o = reader.getElementAsDouble();
                } else if (Long.class.equals(declaredType)) {
                    o = reader.getElementAsLong();
                } else if (Float.class.equals(declaredType)) {
                    o = reader.getElementAsFloat();
                } else if (Short.class.equals(declaredType)) {
                    o = reader.getElementAsShort();
                } else if (QName.class.equals(declaredType)) {
                    o = reader.getElementAsQName();
                } else if (byte[].class.equals(declaredType)) {
                    o = BinaryUtils.decodeAsBytes(reader);
                } else if (XMLGregorianCalendar.class.equals(declaredType)) {
                    String s = reader.getElementAsString();
                    o = dtFactory.newXMLGregorianCalendar(s);
                } else if (Duration.class.equals(declaredType)) {
                    String s = reader.getElementAsString();
                    o = dtFactory.newDuration(s);
                } else if (Node.class.equals(declaredType)) {
                    Element element = reader.getElementAsDomElement();
                    o = element;
                } else {
                    // find marshaller by expected type
                    JAXBObject instance = introspector.getJaxbMarshaller(declaredType);
                    if (instance != null) {
                        if (declaredType == null) {
                            declaredType = Object.class;
                        }
                        if (jaxbElementWrap == nulljaxbElementWrap =  instance.getXmlRootElement() == null;

                        // read the object
                        o = instance.read(reader, runtimeContext);
                    } else {
                        String message = declaredType.getName() + " is not a JAXB object";
                        if (getEventHandler() == null || !getEventHandler().handleEvent(new ValidationEventImpl(ValidationEvent.ERROR, message, new ValidationEventLocatorImpl(reader.getLocation())))) {
                            throw new UnmarshalException(message);
                        }
                        jaxbElementWrap = false;
                    }
                }
            } else {
                // find the marshaller by root element name
                JAXBObject instance = introspector.getJaxbMarshallerByElementName(name);
                if (instance != null) {
                    if (jaxbElementWrap == nulljaxbElementWrap =  instance.getXmlRootElement() == null;
                    declaredType = Object.class;

                    // read the object
                    o = instance.read(reader, runtimeContext);
                } else if (Object.class.equals(declaredType)) {
                    // @XmlAnyType(lax = true)
                    Element element = reader.getElementAsDomElement();
                    o = element;
                } else {
                    String message = "No JAXB object mapped to root element " + name + "; known root elemnts are " + introspector.getElementNames();
                    if (getEventHandler() == null || !getEventHandler().handleEvent(new ValidationEventImpl(ValidationEvent.ERROR, message, new ValidationEventLocatorImpl(reader.getLocation())))) {
                        throw new UnmarshalException(message);
                    }
                    jaxbElementWrap = false;
                }
            }

            // wrap if necessary
            if (jaxbElementWrap != null && jaxbElementWrap) {
                return new JAXBElement(name, declaredType, o);
            } else {
                return o;
            }
        } catch (Exception e) {
            if (e instanceof RuntimeXMLStreamException) {
                e = ((RuntimeXMLStreamException) e).getCause();
            }
            if (e instanceof XMLStreamException) {
                Throwable cause = e.getCause();
                if (cause instanceof JAXBException) {
                    throw (JAXBException) e;
                }
                throw new UnmarshalException(cause == null ? e : cause);
            }
            if (e instanceof JAXBException) {
                throw (JAXBException) e;
            }

            // report fatal error
            if (getEventHandler() != null) {
                getEventHandler().handleEvent(new ValidationEventImpl(ValidationEvent.FATAL_ERROR, "Fatal error", new ValidationEventLocatorImpl(reader.getLocation()), e));
            }
            throw new UnmarshalException(e);
        }
    }

    public Listener getListener() {
        return listener;
    }

    public void setListener(Listener listener) {
        this.listener = listener;
    }

    public ValidationEventHandler getEventHandler() throws JAXBException {
        return handler;
    }

    public void setEventHandler(ValidationEventHandler handler) throws JAXBException {
        if (handler == null) {
            handler = new DefaultValidationEventHandler();
        }
        this.handler = handler;
    }

    @SuppressWarnings({"unchecked"})
    public <A extends XmlAdapter> A getAdapter(Class<A> type) {
        return (A) adapters.get(type);
    }

    public void setAdapter(XmlAdapter adapter) {
        if (adapter == null) throw new IllegalArgumentException("adapter is null");
        setAdapter((Class<XmlAdapter>) adapter.getClass(), adapter);
    }

    public <A extends XmlAdapter> void setAdapter(Class<A> type, A adapter) {
        if (type == null) throw new IllegalArgumentException("type is null");
        if (adapter != null) {
            adapters.put(type, adapter);
        } else {
            adapters.remove(type);
        }
    }

    public AttachmentUnmarshaller getAttachmentUnmarshaller() {
        return attachmentUnmarshaller;
    }

    public void setAttachmentUnmarshaller(AttachmentUnmarshaller attachmentUnmarshaller) {
        this.attachmentUnmarshaller = attachmentUnmarshaller;
    }

    public Schema getSchema() {
        return schema;
    }

    public void setSchema(Schema schema) {
        this.schema = schema;
    }

    public UnmarshallerHandlerImpl getUnmarshallerHandler() {
        return new UnmarshallerHandlerImpl(this);
    }

    //
    // Unused methods
    //

    public Object getProperty(String name) throws PropertyException {
        if (name == null) throw new IllegalArgumentException("name is null");
        throw new PropertyException(name);
    }

    public void setProperty(String name, Object value) throws PropertyException {
        if (name == null) throw new IllegalArgumentException("name is null");
        throw new PropertyException(name, value);
    }

    public boolean isValidating() throws JAXBException {
        return false;
    }

    public void setValidating(boolean validating) throws JAXBException {
    }

}
TOP

Related Classes of com.envoisolutions.sxc.jaxb.UnmarshallerImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.