/******************************************************************************* * Copyright (c) 1998, 2016 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.internal.oxm.record; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.net.MalformedURLException; import java.net.URL; import java.util.Map; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.ValidatorHandler; import org.eclipse.persistence.exceptions.EclipseLinkException; import org.eclipse.persistence.exceptions.XMLMarshalException; import org.eclipse.persistence.internal.core.helper.CoreClassConstants; import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession; import org.eclipse.persistence.internal.helper.XMLHelper; import org.eclipse.persistence.internal.oxm.Constants; import org.eclipse.persistence.internal.oxm.Context; import org.eclipse.persistence.internal.oxm.ConversionManager; import org.eclipse.persistence.internal.oxm.MediaType; import org.eclipse.persistence.internal.oxm.Root; import org.eclipse.persistence.internal.oxm.Unmarshaller; import org.eclipse.persistence.internal.oxm.UnmarshallerHandler; import org.eclipse.persistence.internal.oxm.mappings.Descriptor; import org.eclipse.persistence.internal.oxm.mappings.UnmarshalKeepAsElementPolicy; import org.eclipse.persistence.internal.oxm.record.json.JsonStructureReader; import org.eclipse.persistence.platform.xml.DefaultErrorHandler; import org.eclipse.persistence.platform.xml.SAXDocumentBuilder; import org.eclipse.persistence.platform.xml.XMLParser; import org.eclipse.persistence.platform.xml.XMLPlatform; import org.eclipse.persistence.platform.xml.XMLPlatformFactory; import org.eclipse.persistence.platform.xml.XMLTransformer; import org.w3c.dom.Node; import org.xml.sax.ContentHandler; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * INTERNAL: * <p><b>Purpose:</b>Provide an implementation of PlatformUnmarshaller that makes use of the SAX parser * to build Java Objects from SAX Events. * <p><b>Responsibilities:</b><ul> * <li>Implement the required unmarshal methods from PlatformUnmarshaller</li> * <li>Check to see if document preservation is enabled, and if so, always unmarshal from a node</li> * </ul> * * @author bdoughan * @see org.eclipse.persistence.oxm.platform.SAXPlatform */ public class SAXUnmarshaller implements PlatformUnmarshaller { private static final String VALIDATING = "http://xml.org/sax/features/validation"; private static final String SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; private static final String SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource"; private static final String XML_SCHEMA = "http://www.w3.org/2001/XMLSchema"; private static final UnmarshalKeepAsElementPolicy KEEP_UNKNOWN_AS_ELEMENT = new UnmarshalKeepAsElementPolicy() { @Override public boolean isKeepAllAsElement() { return false; } @Override public boolean isKeepNoneAsElement() { return false; } @Override public boolean isKeepUnknownAsElement() { return true; } }; private int validationMode = XMLParser.NONVALIDATING; private Schema schema; private Object[] schemas; private EntityResolver entityResolver; private ErrorHandler errorHandler = DefaultErrorHandler.getInstance(); private SAXParser saxParser; private XMLReader xmlReader; private Unmarshaller xmlUnmarshaller; private XMLParser xmlParser; private boolean isResultAlwaysXMLRoot, isWhitespacePreserving; private SAXParserFactory saxParserFactory; private String systemId = null; private Map<String, Boolean> parserFeatures; private boolean disableSecureProcessing = false; private boolean shouldReset = true; private XMLPlatform xmlPLatform; public SAXUnmarshaller(Unmarshaller xmlUnmarshaller, Map<String, Boolean> parserFeatures) throws XMLMarshalException { super(); this.parserFeatures = parserFeatures; try { this.xmlUnmarshaller = xmlUnmarshaller; } catch (Exception e) { throw XMLMarshalException.errorInstantiatingSchemaPlatform(e); } } private SAXParserFactory getSAXParserFactory() throws XMLMarshalException { if (null == saxParserFactory || shouldReset) { try { saxParserFactory = XMLHelper.createParserFactory(isSecureProcessingDisabled());; saxParserFactory.setFeature(XMLReader.NAMESPACE_PREFIXES_FEATURE, true); try { saxParserFactory.setFeature(XMLReader.REPORT_IGNORED_ELEMENT_CONTENT_WHITESPACE_FEATURE, true); } catch (org.xml.sax.SAXNotRecognizedException ex) { // ignore if the parser doesn't recognize or support this feature } catch (org.xml.sax.SAXNotSupportedException ex) { } if (null != parserFeatures) { for (Map.Entry<String, Boolean> parserFeature : parserFeatures.entrySet()) { try { saxParserFactory.setFeature(parserFeature.getKey(), parserFeature.getValue()); } catch (org.xml.sax.SAXNotRecognizedException ex) { // ignore if the parser doesn't recognize or support this feature } catch (org.xml.sax.SAXNotSupportedException ex) { } } } return saxParserFactory; } catch (Exception e) { throw XMLMarshalException.errorInstantiatingSchemaPlatform(e); } } return saxParserFactory; } private SAXParser getSAXParser() { if (null == saxParser) { try { saxParser = getSAXParserFactory().newSAXParser(); } catch (Exception e) { throw XMLMarshalException.errorInstantiatingSchemaPlatform(e); } } return saxParser; } private XMLParser getXMLParser() { if (xmlParser == null || shouldReset) { XMLPlatform xmlPlatform = XMLPlatformFactory.getInstance().getXMLPlatform(); xmlPlatform.setDisableSecureProcessing(isSecureProcessingDisabled()); xmlParser = xmlPlatform.newXMLParser(); xmlParser.setNamespaceAware(true); if (null != errorHandler) { xmlParser.setErrorHandler(errorHandler); } if (null != entityResolver) { xmlParser.setEntityResolver(entityResolver); } xmlParser.setValidationMode(validationMode); xmlParser.setWhitespacePreserving(isWhitespacePreserving); shouldReset = false; } return xmlParser; } private XMLReader getXMLReader() { return getXMLReader(null); } private XMLReader getXMLReader(Class clazz) { if (null == xmlReader) { xmlReader = getNewXMLReader(clazz, xmlUnmarshaller.getMediaType()); } return xmlReader; } private XMLReader getNewXMLReader(MediaType mediaType) { return getNewXMLReader(null, mediaType); } private XMLReader getNewXMLReader(Class clazz, MediaType mediaType) { if (null != mediaType && mediaType.isApplicationJSON()) { return new JsonStructureReader(xmlUnmarshaller, clazz); } try { XMLReader xmlReader = new XMLReader(getSAXParser().getXMLReader()); if (null != errorHandler) { xmlReader.setErrorHandler(errorHandler); } if (null != entityResolver) { xmlReader.setEntityResolver(entityResolver); } setValidationMode(xmlReader, getValidationMode()); if (null != getSchema()) { xmlReader.setFeature(VALIDATING, xmlReader.getFeature(VALIDATING)); } return xmlReader; } catch (Exception e) { throw XMLMarshalException.errorInstantiatingSchemaPlatform(e); } } @Override public EntityResolver getEntityResolver() { return entityResolver; } @Override public void setEntityResolver(EntityResolver entityResolver) { if (null != xmlReader) { xmlReader.setEntityResolver(entityResolver); } if (null != xmlParser) { xmlParser.setEntityResolver(entityResolver); } this.entityResolver = entityResolver; } @Override public ErrorHandler getErrorHandler() { return errorHandler; } @Override public void setErrorHandler(ErrorHandler errorHandler) { if (null != xmlReader) { xmlReader.setErrorHandler(errorHandler); } if (null != xmlParser) { xmlParser.setErrorHandler(errorHandler); } this.errorHandler = errorHandler; } @Override public int getValidationMode() { return validationMode; } @Override public void setValidationMode(int validationMode) { setValidationMode(xmlReader, validationMode); } public void setValidationMode(XMLReader xmlReader, int validationMode) { try { this.validationMode = validationMode; if (null != xmlParser) { xmlParser.setValidationMode(validationMode); } if (null == xmlReader) { return; } switch (validationMode) { case XMLParser.NONVALIDATING: { xmlReader.setFeature(VALIDATING, false); break; } case XMLParser.DTD_VALIDATION: { xmlReader.setFeature(VALIDATING, true); XMLHelper.allowExternalDTDAccess(xmlReader, "all", false); break; } case XMLParser.SCHEMA_VALIDATION: { try { xmlReader.setFeature(VALIDATING, true); XMLHelper.allowExternalAccess(xmlReader, "all", false); saxParser.setProperty(SCHEMA_LANGUAGE, XML_SCHEMA); saxParser.setProperty(SCHEMA_SOURCE, schemas); } catch (Exception e) { xmlReader.setFeature(VALIDATING, false); } break; } } } catch (Exception e) { // Don't change the validation mode. } } @Override public void setWhitespacePreserving(boolean isWhitespacePreserving) { this.isWhitespacePreserving = isWhitespacePreserving; if (null != xmlParser) { xmlParser.setWhitespacePreserving(isWhitespacePreserving); } } @Override public void setSchemas(Object[] schemas) { this.schemas = schemas; } @Override public void setSchema(Schema schema) { this.schema = schema; if (null != xmlParser) { xmlParser.setXMLSchema(schema); } } @Override public Schema getSchema() { return schema; } @Override public Object unmarshal(File file) { try { if (xmlUnmarshaller.getContext().hasDocumentPreservation()) { Node domElement = getXMLParser().parse(file).getDocumentElement(); return unmarshal(domElement); } this.systemId = file.toURI().toURL().toExternalForm(); FileInputStream inputStream = new FileInputStream(file); try { return unmarshal(inputStream); } finally { inputStream.close(); } } catch (FileNotFoundException e) { throw XMLMarshalException.unmarshalException(e); } catch (IOException e) { throw XMLMarshalException.unmarshalException(e); } finally { xmlUnmarshaller.getStringBuffer().reset(); } } @Override public Object unmarshal(File file, Class clazz) { try { if (xmlUnmarshaller.getContext().hasDocumentPreservation()) { Node domElement = getXMLParser().parse(file).getDocumentElement(); return unmarshal(domElement, clazz); } this.systemId = file.toURI().toURL().toExternalForm(); FileInputStream inputStream = new FileInputStream(file); try { return unmarshal(inputStream, clazz); } finally { inputStream.close(); } } catch (FileNotFoundException e) { throw XMLMarshalException.unmarshalException(e); } catch (IOException e) { throw XMLMarshalException.unmarshalException(e); } finally { xmlUnmarshaller.getStringBuffer().reset(); } } @Override public Object unmarshal(InputStream inputStream) { if (xmlUnmarshaller.getContext().hasDocumentPreservation()) { Node domElement = getXMLParser().parse(inputStream).getDocumentElement(); return unmarshal(domElement); } InputSource inputSource = new InputSource(inputStream); return unmarshal(inputSource); } @Override public Object unmarshal(InputStream inputStream, Class clazz) { if (xmlUnmarshaller.getContext().hasDocumentPreservation()) { Node domElement = getXMLParser().parse(inputStream).getDocumentElement(); return unmarshal(domElement, clazz); } InputSource inputSource = new InputSource(inputStream); return unmarshal(inputSource, clazz); } @Override public Object unmarshal(InputSource inputSource) { if (inputSource != null && null == inputSource.getSystemId()) { inputSource.setSystemId(this.systemId); } if (xmlUnmarshaller.isAutoDetectMediaType()) { BufferedReader bufferedReader = getBufferedReaderForInputSource(inputSource); MediaType mediaType = getMediaType(bufferedReader); return unmarshal(getNewXMLReader(mediaType), new InputSource(bufferedReader)); } return unmarshal(getXMLReader(), inputSource); } public Object unmarshal(InputSource inputSource, XMLReader xmlReader) { try { if (inputSource != null && null == inputSource.getSystemId()) { inputSource.setSystemId(this.systemId); } SAXUnmarshallerHandler saxUnmarshallerHandler = new SAXUnmarshallerHandler(xmlUnmarshaller.getContext()); saxUnmarshallerHandler.setXMLReader(xmlReader); saxUnmarshallerHandler.setUnmarshaller(xmlUnmarshaller); setContentHandler(xmlReader, saxUnmarshallerHandler); xmlReader.parse(inputSource); // resolve any mapping references saxUnmarshallerHandler.resolveReferences(); return saxUnmarshallerHandler.getObject(); } catch (IOException e) { throw XMLMarshalException.unmarshalException(e); } catch (SAXException e) { throw convertSAXException(e); } finally { xmlUnmarshaller.getStringBuffer().reset(); } } @Override public Object unmarshal(InputSource inputSource, Class clazz) { if (inputSource != null && null == inputSource.getSystemId()) { inputSource.setSystemId(this.systemId); } if (xmlUnmarshaller.isAutoDetectMediaType()) { BufferedReader bufferedReader = getBufferedReaderForInputSource(inputSource); MediaType mediaType = getMediaType(bufferedReader); return unmarshal(getNewXMLReader(clazz, mediaType), new InputSource(bufferedReader), clazz); } return unmarshal(getXMLReader(clazz), inputSource, clazz); } public Object unmarshal(InputSource inputSource, Class clazz, XMLReader xmlReader) { if (inputSource != null && null == inputSource.getSystemId()) { inputSource.setSystemId(this.systemId); } UnmarshalRecord unmarshalRecord = null; Descriptor xmlDescriptor = null; // for XMLObjectReferenceMappings we need a non-shared cache, so // try and get a Unit Of Work from the XMLContext CoreAbstractSession session = null; // check for case where the reference class is a primitive wrapper - in this case, we // need to use the conversion manager to convert the node's value to the primitive // wrapper class, then create, populate and return an XMLRoot. This will be done // via XMLRootRecord. boolean isPrimitiveWrapper = false; if (clazz == CoreClassConstants.OBJECT) { try { SAXUnmarshallerHandler saxUnmarshallerHandler = new SAXUnmarshallerHandler(xmlUnmarshaller.getContext()); saxUnmarshallerHandler.setXMLReader(xmlReader); saxUnmarshallerHandler.setUnmarshaller(xmlUnmarshaller); saxUnmarshallerHandler.setKeepAsElementPolicy(KEEP_UNKNOWN_AS_ELEMENT); setContentHandler(xmlReader, saxUnmarshallerHandler); xmlReader.parse(inputSource); // resolve any mapping references saxUnmarshallerHandler.resolveReferences(); return saxUnmarshallerHandler.getObject(); } catch (IOException e) { throw XMLMarshalException.unmarshalException(e); } catch (SAXException e) { throw convertSAXException(e); } } else { // for XMLObjectReferenceMappings we need a non-shared cache, so // try and get a Unit Of Work from the XMLContext try { session = xmlUnmarshaller.getContext().getSession(clazz); xmlDescriptor = (Descriptor) session.getDescriptor(clazz); unmarshalRecord = xmlUnmarshaller.createUnmarshalRecord(xmlDescriptor, session); } catch (XMLMarshalException xme) { if (xme.getErrorCode() == XMLMarshalException.DESCRIPTOR_NOT_FOUND_IN_PROJECT) { isPrimitiveWrapper = isPrimitiveWrapper(clazz); if (isPrimitiveWrapper) { unmarshalRecord = xmlUnmarshaller.createRootUnmarshalRecord(clazz); } else { throw xme; } } else { throw xme; } } } try { unmarshalRecord.setXMLReader(xmlReader); unmarshalRecord.setUnmarshaller(xmlUnmarshaller); setContentHandler(xmlReader, unmarshalRecord); xmlReader.setLexicalHandler(unmarshalRecord); xmlReader.parse(inputSource); } catch (IOException e) { throw XMLMarshalException.unmarshalException(e); } catch (SAXException e) { throw convertSAXException(e); } finally { xmlUnmarshaller.getStringBuffer().reset(); } // resolve mapping references unmarshalRecord.resolveReferences(session, xmlUnmarshaller.getIDResolver()); if (isPrimitiveWrapper) { return unmarshalRecord.getCurrentObject(); } return xmlDescriptor.wrapObjectInXMLRoot(unmarshalRecord, this.isResultAlwaysXMLRoot); } @Override public Object unmarshal(Node node) { DOMReader reader = new DOMReader(xmlUnmarshaller); return unmarshal(reader, node); } public Object unmarshal(DOMReader reader, Node node) { try { SAXUnmarshallerHandler handler = new SAXUnmarshallerHandler(xmlUnmarshaller.getContext()); setContentHandler(reader, handler); handler.setXMLReader(reader); handler.setUnmarshaller(xmlUnmarshaller); reader.parse(node); handler.resolveReferences(); return handler.getObject(); } catch (SAXException e) { throw convertSAXException(e); } finally { xmlUnmarshaller.getStringBuffer().reset(); } } @Override public Object unmarshal(Node node, Class clazz) { DOMReader reader = new DOMReader(xmlUnmarshaller); return unmarshal(reader, node, clazz); } public Object unmarshal(DOMReader domReader, Node node, Class clazz) { UnmarshalRecord unmarshalRecord = null; Descriptor xmlDescriptor = null; CoreAbstractSession session = null; // check for case where the reference class is a primitive wrapper - in this case, we // need to use the conversion manager to convert the node's value to the primitive // wrapper class, then create, populate and return an XMLRoot. This will be done // via XMLRootRecord. boolean isPrimitiveWrapper = false; if (clazz == CoreClassConstants.OBJECT) { SAXUnmarshallerHandler saxUnmarshallerHandler = new SAXUnmarshallerHandler(xmlUnmarshaller.getContext()); saxUnmarshallerHandler.setXMLReader(domReader); saxUnmarshallerHandler.setUnmarshaller(xmlUnmarshaller); saxUnmarshallerHandler.setKeepAsElementPolicy(KEEP_UNKNOWN_AS_ELEMENT); setContentHandler(domReader, saxUnmarshallerHandler); try { domReader.parse(node); } catch (SAXException e) { throw convertSAXException(e); } // resolve any mapping references saxUnmarshallerHandler.resolveReferences(); return saxUnmarshallerHandler.getObject(); } else { // for XMLObjectReferenceMappings we need a non-shared cache, so // try and get a Unit Of Work from the XMLContext try { session = xmlUnmarshaller.getContext().getSession(clazz); xmlDescriptor = (Descriptor) session.getDescriptor(clazz); unmarshalRecord = xmlUnmarshaller.createUnmarshalRecord(xmlDescriptor, session); } catch (XMLMarshalException xme) { if (xme.getErrorCode() == XMLMarshalException.DESCRIPTOR_NOT_FOUND_IN_PROJECT) { isPrimitiveWrapper = isPrimitiveWrapper(clazz); if (isPrimitiveWrapper) { unmarshalRecord = xmlUnmarshaller.createRootUnmarshalRecord(clazz); } else if (Node.class.isAssignableFrom(clazz)) { return createXMLRootForNode(node); } else { throw xme; } } else { throw xme; } } } try { unmarshalRecord.setXMLReader(domReader); unmarshalRecord.setUnmarshaller(xmlUnmarshaller); setContentHandler(domReader, unmarshalRecord); domReader.setLexicalHandler(unmarshalRecord); domReader.parse(node); } catch (SAXException e) { throw convertSAXException(e); } finally { xmlUnmarshaller.getStringBuffer().reset(); } // resolve mapping references unmarshalRecord.resolveReferences(session, xmlUnmarshaller.getIDResolver()); if (isPrimitiveWrapper) { return unmarshalRecord.getCurrentObject(); } return xmlDescriptor.wrapObjectInXMLRoot(unmarshalRecord, this.isResultAlwaysXMLRoot); } private Object createXMLRootForNode(Node node) { Root xmlRoot = xmlUnmarshaller.createRoot(); xmlRoot.setObject(node); if (node != null) { xmlRoot.setLocalName(node.getLocalName()); xmlRoot.setNamespaceURI(node.getNamespaceURI()); } return xmlRoot; } @Override public Object unmarshal(Reader reader) { if (xmlUnmarshaller.getContext().hasDocumentPreservation()) { Node domElement = getXMLParser().parse(reader).getDocumentElement(); return unmarshal(domElement); } InputSource inputSource = new InputSource(reader); return unmarshal(inputSource); } @Override public Object unmarshal(Reader reader, Class clazz) { if (xmlUnmarshaller.getContext().hasDocumentPreservation()) { Node domElement = getXMLParser().parse(reader).getDocumentElement(); return unmarshal(domElement, clazz); } InputSource inputSource = new InputSource(reader); return unmarshal(inputSource, clazz); } @Override public Object unmarshal(Source source) { try { if (source instanceof SAXSource) { SAXSource saxSource = (SAXSource) source; XMLReader xmlReader = null; if (saxSource.getXMLReader() != null) { if (saxSource.getXMLReader() instanceof XMLReader) { xmlReader = (XMLReader) saxSource.getXMLReader(); } else { xmlReader = new XMLReader(saxSource.getXMLReader()); } setValidatorHandler(xmlReader); } if (null == xmlReader) { return unmarshal(saxSource.getInputSource()); } else { return unmarshal(saxSource.getInputSource(), xmlReader); } } else if (source instanceof DOMSource) { DOMSource domSource = (DOMSource) source; return unmarshal(domSource.getNode()); } else if (source instanceof StreamSource) { StreamSource streamSource = (StreamSource) source; if (null != streamSource.getReader()) { return unmarshal(streamSource.getReader()); } else if (null != streamSource.getInputStream()) { return unmarshal(streamSource.getInputStream()); } else { return unmarshal(streamSource.getSystemId()); } } else if (source instanceof ExtendedSource) { ExtendedSource extendedSource = (ExtendedSource) source; return unmarshal(null, extendedSource.createReader(xmlUnmarshaller)); } else { UnmarshallerHandler handler = this.xmlUnmarshaller.getUnmarshallerHandler(); XMLPlatform xmlPlat = XMLPlatformFactory.getInstance().getXMLPlatform(); xmlPlat.setDisableSecureProcessing(isSecureProcessingDisabled()); XMLTransformer transformer = xmlPLatform.newXMLTransformer(); SAXResult result = new SAXResult(handler); transformer.transform(source, result); return handler.getResult(); } } finally { xmlUnmarshaller.getStringBuffer().reset(); } } @Override public Object unmarshal(Source source, Class clazz) { if (source instanceof SAXSource) { SAXSource saxSource = (SAXSource) source; XMLReader xmlReader = null; if (saxSource.getXMLReader() != null) { if (saxSource.getXMLReader() instanceof XMLReader) { xmlReader = (XMLReader) saxSource.getXMLReader(); } else { xmlReader = new XMLReader(saxSource.getXMLReader()); } setValidatorHandler(xmlReader); } if (null == saxSource.getXMLReader()) { return unmarshal(saxSource.getInputSource(), clazz); } else { return unmarshal(saxSource.getInputSource(), clazz, xmlReader); } } else if (source instanceof DOMSource) { DOMSource domSource = (DOMSource) source; return unmarshal(domSource.getNode(), clazz); } else if (source instanceof StreamSource) { StreamSource streamSource = (StreamSource) source; if (null != streamSource.getReader()) { return unmarshal(streamSource.getReader(), clazz); } else if (null != streamSource.getInputStream()) { return unmarshal(streamSource.getInputStream(), clazz); } else { return unmarshal(streamSource.getSystemId(), clazz); } } else if (source instanceof ExtendedSource) { ExtendedSource extendedSource = (ExtendedSource) source; return unmarshal(null, clazz, extendedSource.createReader(xmlUnmarshaller, clazz)); } else { DOMResult result = new DOMResult(); XMLPlatform xmlPlat = XMLPlatformFactory.getInstance().getXMLPlatform(); xmlPlat.setDisableSecureProcessing(isSecureProcessingDisabled()); XMLTransformer transformer = xmlPLatform.newXMLTransformer(); transformer.transform(source, result); return unmarshal(result.getNode(), clazz); } } @Override public Object unmarshal(URL url) { InputStream inputStream = null; try { inputStream = url.openStream(); } catch (Exception e) { throw XMLMarshalException.unmarshalException(e); } this.systemId = url.toExternalForm(); boolean hasThrownException = false; try { return unmarshal(inputStream); } catch (RuntimeException runtimeException) { hasThrownException = true; throw runtimeException; } finally { xmlUnmarshaller.getStringBuffer().reset(); try { inputStream.close(); } catch (IOException e) { if (!hasThrownException) { throw XMLMarshalException.unmarshalException(e); } } } } @Override public Object unmarshal(URL url, Class clazz) { InputStream inputStream = null; try { inputStream = url.openStream(); } catch (IOException e) { throw XMLMarshalException.unmarshalException(e); } this.systemId = url.toExternalForm(); try { return unmarshal(inputStream, clazz); } finally { xmlUnmarshaller.getStringBuffer().reset(); try { inputStream.close(); } catch (IOException e) { throw XMLMarshalException.unmarshalException(e); } } } public Object unmarshal(String systemId) { try { if (xmlUnmarshaller.isAutoDetectMediaType()) { InputSource inputSource = new InputSource(systemId); return unmarshal(inputSource); } XMLReader xmlReader = getXMLReader(); SAXUnmarshallerHandler saxUnmarshallerHandler = new SAXUnmarshallerHandler(xmlUnmarshaller.getContext()); saxUnmarshallerHandler.setXMLReader(xmlReader); saxUnmarshallerHandler.setUnmarshaller(xmlUnmarshaller); setContentHandler(xmlReader, saxUnmarshallerHandler); xmlReader.parse(systemId); // resolve mapping references saxUnmarshallerHandler.resolveReferences(); return saxUnmarshallerHandler.getObject(); } catch (IOException e) { throw XMLMarshalException.unmarshalException(e); } catch (SAXException e) { throw convertSAXException(e); } finally { xmlUnmarshaller.getStringBuffer().reset(); } } public Object unmarshal(String systemId, Class clazz) { if (xmlUnmarshaller.isAutoDetectMediaType()) { return unmarshal(new InputSource(systemId), clazz); } UnmarshalRecord unmarshalRecord = null; boolean isPrimitiveWrapper = false; Descriptor xmlDescriptor = null; CoreAbstractSession session = null; // check for case where the reference class is a primitive wrapper - in this case, we // need to use the conversion manager to convert the node's value to the primitive // wrapper class, then create, populate and return an XMLRoot. This will be done // via XMLRootRecord. if (clazz == CoreClassConstants.OBJECT) { SAXUnmarshallerHandler saxUnmarshallerHandler = new SAXUnmarshallerHandler(xmlUnmarshaller.getContext()); try { XMLReader xmlReader = getXMLReader(clazz); saxUnmarshallerHandler.setXMLReader(xmlReader); saxUnmarshallerHandler.setUnmarshaller(xmlUnmarshaller); saxUnmarshallerHandler.setKeepAsElementPolicy(KEEP_UNKNOWN_AS_ELEMENT); setContentHandler(xmlReader, saxUnmarshallerHandler); xmlReader.parse(systemId); } catch (IOException e) { throw XMLMarshalException.unmarshalException(e); } catch (SAXException e) { throw convertSAXException(e); } finally { xmlUnmarshaller.getStringBuffer().reset(); } // resolve any mapping references saxUnmarshallerHandler.resolveReferences(); return saxUnmarshallerHandler.getObject(); } else { // for XMLObjectReferenceMappings we need a non-shared cache, so // try and get a Unit Of Work from the XMLContext try { session = xmlUnmarshaller.getContext().getSession(clazz); xmlDescriptor = (Descriptor) session.getDescriptor(clazz); unmarshalRecord = xmlUnmarshaller.createUnmarshalRecord(xmlDescriptor, session); } catch (XMLMarshalException xme) { if (xme.getErrorCode() == XMLMarshalException.DESCRIPTOR_NOT_FOUND_IN_PROJECT) { isPrimitiveWrapper = isPrimitiveWrapper(clazz); if (isPrimitiveWrapper) { unmarshalRecord = xmlUnmarshaller.createRootUnmarshalRecord(clazz); } else { throw xme; } } else { throw xme; } } } try { XMLReader xmlReader = getXMLReader(clazz); unmarshalRecord.setXMLReader(xmlReader); unmarshalRecord.setUnmarshaller(xmlUnmarshaller); setContentHandler(xmlReader, unmarshalRecord); xmlReader.setLexicalHandler(unmarshalRecord); xmlReader.parse(systemId); } catch (IOException e) { throw XMLMarshalException.unmarshalException(e); } catch (SAXException e) { throw convertSAXException(e); } finally { xmlUnmarshaller.getStringBuffer().reset(); } // resolve mapping references unmarshalRecord.resolveReferences(session, xmlUnmarshaller.getIDResolver()); if (isPrimitiveWrapper) { return unmarshalRecord.getCurrentObject(); } return xmlDescriptor.wrapObjectInXMLRoot(unmarshalRecord, this.isResultAlwaysXMLRoot); } @Override public Object unmarshal(org.xml.sax.XMLReader xmlReader, InputSource inputSource) { try { Context xmlContext = xmlUnmarshaller.getContext(); if (xmlContext.hasDocumentPreservation()) { SAXDocumentBuilder saxDocumentBuilder = new SAXDocumentBuilder(); xmlReader.setContentHandler(saxDocumentBuilder); xmlReader.parse(inputSource); return unmarshal(saxDocumentBuilder.getDocument().getDocumentElement()); } XMLReader extendedXMLReader; if (xmlReader instanceof XMLReader) { extendedXMLReader = (XMLReader) xmlReader; } else { extendedXMLReader = new XMLReader(xmlReader); } SAXUnmarshallerHandler saxUnmarshallerHandler = new SAXUnmarshallerHandler(xmlContext); saxUnmarshallerHandler.setXMLReader(extendedXMLReader); saxUnmarshallerHandler.setUnmarshaller(xmlUnmarshaller); setContentHandler(extendedXMLReader, saxUnmarshallerHandler); extendedXMLReader.parse(inputSource); // resolve any mapping references saxUnmarshallerHandler.resolveReferences(); return saxUnmarshallerHandler.getObject(); } catch (IOException e) { throw XMLMarshalException.unmarshalException(e); } catch (SAXException e) { throw convertSAXException(e); } finally { xmlUnmarshaller.getStringBuffer().reset(); } } @Override public Object unmarshal(org.xml.sax.XMLReader xmlReader, InputSource inputSource, Class clazz) { try { Context xmlContext = xmlUnmarshaller.getContext(); if (xmlContext.hasDocumentPreservation() || (Node.class.isAssignableFrom(clazz) && xmlUnmarshaller.isApplicationXML())) { SAXDocumentBuilder saxDocumentBuilder = new SAXDocumentBuilder(); xmlReader.setContentHandler(saxDocumentBuilder); xmlReader.parse(inputSource); return unmarshal(saxDocumentBuilder.getDocument().getDocumentElement(), clazz); } UnmarshalRecord unmarshalRecord = null; Descriptor xmlDescriptor = null; CoreAbstractSession session = null; boolean isPrimitiveWrapper = false; // check for case where the reference class is a primitive wrapper - in this case, we // need to use the conversion manager to convert the node's value to the primitive // wrapper class, then create, populate and return an XMLRoot. This will be done // via XMLRootRecord. if (clazz == CoreClassConstants.OBJECT) { SAXUnmarshallerHandler saxUnmarshallerHandler = new SAXUnmarshallerHandler(xmlUnmarshaller.getContext()); saxUnmarshallerHandler.setXMLReader((XMLReader) xmlReader); saxUnmarshallerHandler.setUnmarshaller(xmlUnmarshaller); saxUnmarshallerHandler.setKeepAsElementPolicy(KEEP_UNKNOWN_AS_ELEMENT); xmlReader.setContentHandler(saxUnmarshallerHandler); xmlReader.parse(inputSource); // resolve any mapping references saxUnmarshallerHandler.resolveReferences(); return saxUnmarshallerHandler.getObject(); } else { // for XMLObjectReferenceMappings we need a non-shared cache, so // try and get a Unit Of Work from the XMLContext try { session = xmlContext.getSession(clazz); xmlDescriptor = (Descriptor) session.getDescriptor(clazz); unmarshalRecord = xmlUnmarshaller.createUnmarshalRecord(xmlDescriptor, session); } catch (XMLMarshalException xme) { if (xme.getErrorCode() == XMLMarshalException.DESCRIPTOR_NOT_FOUND_IN_PROJECT) { isPrimitiveWrapper = isPrimitiveWrapper(clazz); if (isPrimitiveWrapper) { unmarshalRecord = xmlUnmarshaller.createRootUnmarshalRecord(clazz); } else { throw xme; } } else { throw xme; } } } XMLReader extendedXMLReader; if (xmlReader instanceof XMLReader) { extendedXMLReader = (XMLReader) xmlReader; } else { extendedXMLReader = new XMLReader(xmlReader); } unmarshalRecord.setXMLReader(extendedXMLReader); unmarshalRecord.setUnmarshaller(xmlUnmarshaller); setContentHandler(extendedXMLReader, unmarshalRecord); extendedXMLReader.setLexicalHandler(unmarshalRecord); extendedXMLReader.parse(inputSource); // resolve mapping references unmarshalRecord.resolveReferences(session, xmlUnmarshaller.getIDResolver()); if (isPrimitiveWrapper || clazz == CoreClassConstants.OBJECT) { return unmarshalRecord.getCurrentObject(); } return xmlDescriptor.wrapObjectInXMLRoot(unmarshalRecord, this.isResultAlwaysXMLRoot); } catch (IOException e) { throw XMLMarshalException.unmarshalException(e); } catch (SAXException e) { throw convertSAXException(e); } finally { xmlUnmarshaller.getStringBuffer().reset(); } } private EclipseLinkException convertSAXException(SAXException saxException) { Exception internalException = saxException.getException(); if (internalException != null) { if (EclipseLinkException.class.isAssignableFrom(internalException.getClass())) { return (EclipseLinkException) internalException; } else { return XMLMarshalException.unmarshalException(internalException); } } return XMLMarshalException.unmarshalException(saxException); } @Override public boolean isResultAlwaysXMLRoot() { return this.isResultAlwaysXMLRoot; } @Override public void setResultAlwaysXMLRoot(boolean alwaysReturnRoot) { this.isResultAlwaysXMLRoot = alwaysReturnRoot; } private boolean isPrimitiveWrapper(Class clazz) { return ((ConversionManager) xmlUnmarshaller.getContext().getSession().getDatasourcePlatform().getConversionManager()).schemaType(clazz) != null || CoreClassConstants.XML_GREGORIAN_CALENDAR.isAssignableFrom(clazz) || CoreClassConstants.DURATION.isAssignableFrom(clazz); } /** * If a Schema was set on the unmarshaller then wrap the ContentHandler in * a ValidatorHandler. */ private void setContentHandler(XMLReader xmlReader, ContentHandler contentHandler) { setValidatorHandler(xmlReader); xmlReader.setContentHandler(contentHandler); } private void setValidatorHandler(XMLReader xmlReader) { Schema schema = getSchema(); if (null != schema) { ValidatorHandler validatorHandler = schema.newValidatorHandler(); xmlReader.setValidatorHandler(validatorHandler); validatorHandler.setErrorHandler(getErrorHandler()); } } @Override public void mediaTypeChanged() { xmlReader = null; } private InputStream getInputStreamFromString(String stringValue) { if (stringValue.length() == 0) { throw org.eclipse.persistence.exceptions.XMLMarshalException.unmarshalFromStringException(stringValue, null); } URL url = null; try { url = new URL(stringValue); if (url != null) { try { return url.openStream(); } catch (IOException e) { throw org.eclipse.persistence.exceptions.XMLMarshalException.unmarshalFromStringException(stringValue, e); } } } catch (MalformedURLException ex) { try { return new FileInputStream(stringValue); } catch (FileNotFoundException e) { throw org.eclipse.persistence.exceptions.XMLMarshalException.unmarshalFromStringException(stringValue, e); } } throw org.eclipse.persistence.exceptions.XMLMarshalException.unmarshalFromStringException(stringValue, null); } private BufferedReader getBufferedReaderForInputSource(InputSource inputSource) { if (inputSource.getByteStream() != null) { return new BufferedReader(new InputStreamReader(inputSource.getByteStream())); } else if (inputSource.getCharacterStream() != null) { return new BufferedReader(inputSource.getCharacterStream()); } else if (inputSource.getSystemId() != null) { InputStream is = getInputStreamFromString(inputSource.getSystemId()); return new BufferedReader(new InputStreamReader(is)); } throw XMLMarshalException.unmarshalException(); } private MediaType getMediaType(BufferedReader br) { int READ_AHEAD_LIMIT = 25; try { br.mark(READ_AHEAD_LIMIT); try { char c = 0; for (int i = 0; c != -1 && i < READ_AHEAD_LIMIT; i++) { c = (char) br.read(); if (c == '[' || c == '{') { return Constants.APPLICATION_JSON; } else if (c == '<') { return Constants.APPLICATION_XML; } } } finally { br.reset(); } } catch (IOException ioException) { throw XMLMarshalException.unmarshalException(ioException); } return xmlUnmarshaller.getMediaType(); } @Override public final boolean isSecureProcessingDisabled() { return disableSecureProcessing; } @Override public final void setDisableSecureProcessing(boolean disableSecureProcessing) { shouldReset = this.disableSecureProcessing ^ disableSecureProcessing; this.disableSecureProcessing = disableSecureProcessing; } }