blob: ccf503b3bb511f714c7dd5460a0fbbc58dddbedb [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 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 v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// 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;
}
}