| /* |
| * 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: |
| // Denise Smith - November, 2009 |
| package org.eclipse.persistence.testing.jaxb.typemappinginfo; |
| |
| import java.awt.Image; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.StringReader; |
| import java.io.StringWriter; |
| import java.io.Writer; |
| import java.lang.reflect.Array; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import jakarta.activation.DataHandler; |
| import jakarta.xml.bind.JAXBContext; |
| import jakarta.xml.bind.JAXBElement; |
| import jakarta.xml.bind.Marshaller; |
| import jakarta.xml.bind.SchemaOutputResolver; |
| import jakarta.xml.bind.Unmarshaller; |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.stream.XMLEventWriter; |
| import javax.xml.stream.XMLOutputFactory; |
| import javax.xml.stream.XMLStreamReader; |
| import javax.xml.stream.XMLStreamWriter; |
| import javax.xml.transform.Result; |
| import javax.xml.transform.Source; |
| import javax.xml.transform.stream.StreamResult; |
| import javax.xml.transform.stream.StreamSource; |
| import javax.xml.validation.Schema; |
| import javax.xml.validation.SchemaFactory; |
| import javax.xml.validation.Validator; |
| |
| import org.eclipse.persistence.internal.helper.ClassConstants; |
| import org.eclipse.persistence.jaxb.*; |
| |
| import org.eclipse.persistence.oxm.NamespaceResolver; |
| import org.eclipse.persistence.oxm.XMLConstants; |
| import org.eclipse.persistence.oxm.XMLDescriptor; |
| import org.eclipse.persistence.oxm.XMLRoot; |
| import org.eclipse.persistence.testing.jaxb.JAXBXMLComparer; |
| import org.eclipse.persistence.testing.oxm.OXTestCase; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.xml.sax.InputSource; |
| |
| import static org.eclipse.persistence.testing.jaxb.JAXBTestCases.ECLIPSELINK_OXM_XSD; |
| |
| public abstract class TypeMappingInfoTestCases extends OXTestCase { |
| protected JAXBContext jaxbContext; |
| protected Marshaller jaxbMarshaller; |
| protected Unmarshaller jaxbUnmarshaller; |
| public String resourceName; |
| protected Document controlDocument; |
| protected Document writeControlDocument; |
| |
| protected DocumentBuilder parser; |
| protected Source bindingsFileXSDSource; |
| protected String controlDocumentLocation; |
| protected String writeControlDocumentLocation; |
| |
| protected TypeMappingInfo[] typeMappingInfos; |
| |
| public TypeMappingInfoTestCases(String name) throws Exception { |
| super(name); |
| } |
| |
| @Override |
| public void setUp() throws Exception { |
| setupParser(); |
| setupControlDocs(); |
| |
| InputStream bindingsFileXSDInputStream = getClass().getClassLoader().getResourceAsStream(ECLIPSELINK_OXM_XSD); |
| if(bindingsFileXSDInputStream == null){ |
| bindingsFileXSDInputStream = getClass().getClassLoader().getResourceAsStream("org/eclipse/persistence/jaxb/" + ECLIPSELINK_OXM_XSD); |
| } |
| if(bindingsFileXSDInputStream == null){ |
| fail("ERROR LOADING " + ECLIPSELINK_OXM_XSD); |
| } |
| bindingsFileXSDSource = new StreamSource(bindingsFileXSDInputStream); |
| } |
| |
| @Override |
| public void tearDown() throws Exception{ |
| super.tearDown(); |
| jaxbContext = null; |
| jaxbMarshaller = null; |
| jaxbUnmarshaller = null; |
| } |
| |
| |
| public void setTypeMappingInfos(TypeMappingInfo[] newTypes) throws Exception { |
| typeMappingInfos = newTypes; |
| |
| Map props = getProperties(); |
| if(props != null){ |
| Map overrides = (Map) props.get(JAXBContextProperties.OXM_METADATA_SOURCE); |
| if(overrides != null){ |
| Iterator valuesIter = overrides.values().iterator(); |
| while(valuesIter.hasNext()){ |
| Source theSource = (Source) valuesIter.next(); |
| validateBindingsFileAgainstSchema(theSource); |
| } |
| } |
| } |
| |
| jaxbContext = org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(newTypes, props, Thread.currentThread().getContextClassLoader()); |
| jaxbMarshaller = jaxbContext.createMarshaller(); |
| jaxbUnmarshaller = jaxbContext.createUnmarshaller(); |
| } |
| public TypeMappingInfo getTypeMappingInfo(){ |
| return typeMappingInfos[0]; |
| } |
| |
| protected Map getProperties() { |
| return null; |
| } |
| |
| public void testXMLToObjectFromXMLEventReaderWithTypeMappingInfo() throws Exception { |
| if(null != XML_INPUT_FACTORY) { |
| InputStream instream = ClassLoader.getSystemResourceAsStream(resourceName); |
| javax.xml.stream.XMLEventReader reader = XML_INPUT_FACTORY.createXMLEventReader(instream); |
| Object obj = ((org.eclipse.persistence.jaxb.JAXBUnmarshaller)jaxbUnmarshaller).unmarshal(reader, getTypeMappingInfo()); |
| |
| Object controlObj = getReadControlObject(); |
| xmlToObjectTest(obj, controlObj); |
| } |
| } |
| |
| public void testXMLToObjectFromXMLStreamReaderWithTypeMappingInfo() throws Exception { |
| if(null != XML_INPUT_FACTORY) { |
| InputStream instream = ClassLoader.getSystemResourceAsStream(resourceName); |
| XMLStreamReader xmlStreamReader = XML_INPUT_FACTORY.createXMLStreamReader(instream); |
| Object testObject = ((JAXBUnmarshaller)jaxbUnmarshaller).unmarshal(xmlStreamReader, getTypeMappingInfo()); |
| instream.close(); |
| |
| Object controlObj = getReadControlObject(); |
| xmlToObjectTest(testObject, controlObj); |
| } |
| } |
| |
| public void testXMLToObjectFromSourceWithTypeMappingInfoXML() throws Exception { |
| InputStream instream = ClassLoader.getSystemResourceAsStream(resourceName); |
| StreamSource ss = new StreamSource(instream); |
| Object testObject = ((JAXBUnmarshaller)jaxbUnmarshaller).unmarshal(ss, getTypeMappingInfo()); |
| instream.close(); |
| |
| Object controlObj = getReadControlObject(); |
| xmlToObjectTest(testObject, controlObj); |
| } |
| |
| public void testObjectToResultWithTypeMappingInfoXML() throws Exception { |
| |
| Object objectToWrite = getWriteControlObject(); |
| XMLDescriptor desc = null; |
| if (objectToWrite instanceof XMLRoot) { |
| desc = (XMLDescriptor)((org.eclipse.persistence.jaxb.JAXBContext)jaxbContext).getXMLContext().getSession(0).getProject().getDescriptor(((XMLRoot)objectToWrite).getObject().getClass()); |
| } else { |
| desc = (XMLDescriptor)((org.eclipse.persistence.jaxb.JAXBContext)jaxbContext).getXMLContext().getSession(0).getProject().getDescriptor(objectToWrite.getClass()); |
| } |
| |
| int sizeBefore = getNamespaceResolverSize(desc); |
| StringWriter stringWriter = new StringWriter(); |
| StreamResult result = new StreamResult(stringWriter); |
| jaxbMarshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/xml"); |
| |
| ((JAXBMarshaller)jaxbMarshaller).marshal(objectToWrite, result, getTypeMappingInfo()); |
| |
| int sizeAfter = getNamespaceResolverSize(desc); |
| |
| assertEquals(sizeBefore, sizeAfter); |
| StringReader reader = new StringReader(stringWriter.toString()); |
| InputSource inputSource = new InputSource(reader); |
| Document testDocument = parser.parse(inputSource); |
| stringWriter.close(); |
| reader.close(); |
| objectToXMLDocumentTest(testDocument); |
| } |
| |
| public void testObjectToXMLStreamWriterWithTypeMappingInfo() throws Exception { |
| if(XML_OUTPUT_FACTORY != null) { |
| StringWriter writer = new StringWriter(); |
| |
| XMLOutputFactory factory = XMLOutputFactory.newInstance(); |
| factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.FALSE); |
| XMLStreamWriter streamWriter= factory.createXMLStreamWriter(writer); |
| |
| Object objectToWrite = getWriteControlObject(); |
| XMLDescriptor desc = null; |
| if (objectToWrite instanceof XMLRoot) { |
| |
| desc = (XMLDescriptor)((org.eclipse.persistence.jaxb.JAXBContext)jaxbContext).getXMLContext().getSession(0).getProject().getDescriptor(((XMLRoot)objectToWrite).getObject().getClass()); |
| } else { |
| desc = (XMLDescriptor)((org.eclipse.persistence.jaxb.JAXBContext)jaxbContext).getXMLContext().getSession(0).getProject().getDescriptor(objectToWrite.getClass()); |
| } |
| |
| int sizeBefore = getNamespaceResolverSize(desc); |
| ((JAXBMarshaller)jaxbMarshaller).marshal(objectToWrite, streamWriter, getTypeMappingInfo()); |
| |
| streamWriter.flush(); |
| int sizeAfter = getNamespaceResolverSize(desc); |
| |
| assertEquals(sizeBefore, sizeAfter); |
| StringReader reader = new StringReader(writer.toString()); |
| InputSource inputSource = new InputSource(reader); |
| Document testDocument = parser.parse(inputSource); |
| writer.close(); |
| reader.close(); |
| objectToXMLDocumentTest(testDocument); |
| } |
| } |
| |
| public void testObjectToXMLEventWriterWithTypeMappingInfo() throws Exception { |
| if(XML_OUTPUT_FACTORY != null) { |
| StringWriter writer = new StringWriter(); |
| |
| XMLOutputFactory factory = XMLOutputFactory.newInstance(); |
| factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.FALSE); |
| XMLEventWriter eventWriter= factory.createXMLEventWriter(writer); |
| |
| Object objectToWrite = getWriteControlObject(); |
| XMLDescriptor desc = null; |
| if (objectToWrite instanceof XMLRoot) { |
| desc = (XMLDescriptor)((org.eclipse.persistence.jaxb.JAXBContext)jaxbContext).getXMLContext().getSession(0).getProject().getDescriptor(((XMLRoot)objectToWrite).getObject().getClass()); |
| } else { |
| desc = (XMLDescriptor)((org.eclipse.persistence.jaxb.JAXBContext)jaxbContext).getXMLContext().getSession(0).getProject().getDescriptor(objectToWrite.getClass()); |
| } |
| |
| int sizeBefore = getNamespaceResolverSize(desc); |
| ((JAXBMarshaller)jaxbMarshaller).marshal(objectToWrite, eventWriter, getTypeMappingInfo()); |
| |
| eventWriter.flush(); |
| int sizeAfter = getNamespaceResolverSize(desc); |
| |
| assertEquals(sizeBefore, sizeAfter); |
| StringReader reader = new StringReader(writer.toString()); |
| InputSource inputSource = new InputSource(reader); |
| Document testDocument = parser.parse(inputSource); |
| writer.close(); |
| reader.close(); |
| objectToXMLDocumentTest(testDocument); |
| } |
| } |
| |
| public void xmlToObjectTest(Object testObject, Object controlObject) throws Exception { |
| log("\n**xmlToObjectTest**"); |
| log("Expected:"); |
| log(controlObject.toString()); |
| log("Actual:"); |
| log(testObject.toString()); |
| |
| JAXBElement controlObj = (JAXBElement)controlObject; |
| JAXBElement testObj = (JAXBElement)testObject; |
| compareJAXBElementObjects(controlObj, testObj); |
| } |
| |
| public abstract Map<String, InputStream> getControlSchemaFiles(); |
| |
| public void testSchemaGen() throws Exception { |
| testSchemaGen(getControlSchemaFiles()); |
| } |
| |
| @Override |
| protected void compareValues(Object controlValue, Object testValue){ |
| if(controlValue instanceof Node && testValue instanceof Node) { |
| assertXMLIdentical(((Node)controlValue).getOwnerDocument(), ((Node)testValue).getOwnerDocument()); |
| } else if(controlValue instanceof DataHandler && testValue instanceof DataHandler){ |
| compareDataHandlers((DataHandler)controlValue, (DataHandler)testValue); |
| } else if(controlValue instanceof Image && testValue instanceof Image) { |
| compareImages((Image)controlValue, (Image) testValue); |
| } else if (controlValue instanceof Byte[] && testValue instanceof Byte[]){ |
| compareByteArrays((Byte[])controlValue, (Byte[])testValue); |
| } else if (controlValue instanceof byte[] && testValue instanceof byte[]){ |
| compareByteArrays((byte[])controlValue, (byte[])testValue); |
| } else { |
| assertEquals(controlValue, testValue); |
| } |
| } |
| |
| private void compareDataHandlers(DataHandler controlValue, DataHandler testValue){ |
| assertEquals(controlValue.getContentType(), testValue.getContentType()); |
| try{ |
| assertEquals(controlValue.getContent(), testValue.getContent()); |
| }catch(Exception e){ |
| e.printStackTrace(); |
| fail(); |
| } |
| } |
| |
| private void compareImages(Image controlImage, Image testImage) { |
| assertEquals(controlImage.getWidth(null), testImage.getWidth(null)); |
| assertEquals(controlImage.getHeight(null), testImage.getHeight(null)); |
| } |
| protected void setupParser() { |
| try { |
| DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); |
| builderFactory.setNamespaceAware(true); |
| builderFactory.setIgnoringElementContentWhitespace(true); |
| parser = builderFactory.newDocumentBuilder(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| fail("An exception occurred during setup"); |
| } |
| } |
| |
| public void setupControlDocs() throws Exception{ |
| if(this.controlDocumentLocation != null) { |
| InputStream inputStream = ClassLoader.getSystemResourceAsStream(controlDocumentLocation); |
| resourceName = controlDocumentLocation; |
| controlDocument = parser.parse(inputStream); |
| removeEmptyTextNodes(controlDocument); |
| |
| inputStream.close(); |
| } |
| |
| if(this.writeControlDocumentLocation != null) { |
| InputStream inputStream = ClassLoader.getSystemResourceAsStream(writeControlDocumentLocation); |
| writeControlDocument = parser.parse(inputStream); |
| removeEmptyTextNodes(writeControlDocument); |
| |
| inputStream.close(); |
| } |
| } |
| protected int getNamespaceResolverSize(XMLDescriptor desc){ |
| int size = -1; |
| if (desc != null) { |
| NamespaceResolver nr = desc.getNamespaceResolver(); |
| if (nr != null) { |
| size = nr.getNamespaces().size(); |
| }else{ |
| size =0; |
| } |
| } |
| return size; |
| } |
| |
| protected Document getControlDocument() { |
| return controlDocument; |
| } |
| |
| /** |
| * Override this function to implement different read/write control documents. |
| */ |
| protected Document getWriteControlDocument() throws Exception { |
| if(writeControlDocument != null){ |
| return writeControlDocument; |
| } |
| return getControlDocument(); |
| } |
| |
| protected void setControlDocument(String xmlResource) throws Exception { |
| this.controlDocumentLocation = xmlResource; |
| } |
| |
| /** |
| * Provide an alternative write version of the control document when rountrip is not enabled. |
| * If this function is not called and getWriteControlDocument() is not overridden then the write and read control documents are the same. |
| */ |
| protected void setWriteControlDocument(String xmlResource) throws Exception { |
| writeControlDocumentLocation = xmlResource; |
| } |
| |
| abstract protected Object getControlObject(); |
| /* |
| * Returns the object to be used in a comparison on a read |
| * This will typically be the same object used to write |
| */ |
| public Object getReadControlObject() { |
| return getControlObject(); |
| } |
| |
| /* |
| * Returns the object to be written to XML which will be compared |
| * to the control document. |
| */ |
| public Object getWriteControlObject() { |
| return getControlObject(); |
| } |
| |
| public void objectToXMLDocumentTest(Document testDocument) throws Exception { |
| log("**objectToXMLDocumentTest**"); |
| log("Expected:"); |
| log(getWriteControlDocument()); |
| log("\nActual:"); |
| log(testDocument); |
| assertXMLIdentical(getWriteControlDocument(), testDocument); |
| } |
| |
| @Override |
| public void compareJAXBElementObjects(JAXBElement controlObj, JAXBElement testObj) { |
| assertEquals(controlObj.getName().getLocalPart(), testObj.getName().getLocalPart()); |
| assertEquals(controlObj.getName().getNamespaceURI(), testObj.getName().getNamespaceURI()); |
| assertEquals(controlObj.getDeclaredType(), testObj.getDeclaredType()); |
| |
| Object controlValue = controlObj.getValue(); |
| Object testValue = testObj.getValue(); |
| |
| if(controlValue == null) { |
| if(testValue == null){ |
| return; |
| } |
| fail("Test value should have been null"); |
| }else{ |
| if(testValue == null){ |
| fail("Test value should not have been null"); |
| } |
| } |
| |
| if(controlValue.getClass() == ClassConstants.ABYTE && testValue.getClass() == ClassConstants.ABYTE || |
| controlValue.getClass() == ClassConstants.APBYTE && testValue.getClass() == ClassConstants.APBYTE){ |
| compareValues(controlValue, testValue); |
| }else if(controlValue.getClass().isArray()){ |
| if(testValue.getClass().isArray()){ |
| if(controlValue.getClass().getComponentType().isPrimitive()){ |
| comparePrimitiveArrays(controlValue, testValue); |
| }else{ |
| compareObjectArrays(controlValue, testValue); |
| } |
| }else{ |
| fail("Expected an array value but was an " + testValue.getClass().getName()); |
| } |
| } |
| else if (controlValue instanceof Collection){ |
| Collection controlCollection = (Collection)controlValue; |
| Collection testCollection = (Collection)testValue; |
| Iterator<Object> controlIter = controlCollection.iterator(); |
| Iterator<Object> testIter = testCollection.iterator(); |
| assertEquals(controlCollection.size(), testCollection.size()); |
| while(controlIter.hasNext()){ |
| Object nextControl = controlIter.next(); |
| Object nextTest = testIter.next(); |
| compareValues(nextControl, nextTest); |
| } |
| }else{ |
| compareValues(controlValue, testValue); |
| } |
| } |
| |
| protected void comparePrimitiveArrays(Object controlValue, Object testValue) { |
| if (controlValue == null && testValue == null) { |
| // equal |
| return; |
| } |
| |
| assertEquals(controlValue.getClass(), testValue.getClass()); |
| |
| assertNotNull(controlValue); |
| assertNotNull(testValue); |
| |
| int controlLength = Array.getLength(controlValue); |
| int testLength = Array.getLength(controlValue); |
| assertEquals(controlLength, testLength); |
| |
| for (int i = 0; i < controlLength; i++) { |
| Object controlObject = Array.get(controlValue, i); |
| Object testObject = Array.get(testValue, i); |
| assertEquals(controlObject, testObject); |
| } |
| } |
| |
| protected void compareObjectArrays(Object controlValue, Object testValue){ |
| assertEquals(((Object[])controlValue).length,((Object[])testValue).length); |
| for(int i=0; i<((Object[])controlValue).length-1; i++){ |
| assertEquals(((Object[])controlValue)[i], ((Object[])testValue)[i]); |
| } |
| } |
| |
| public void testSchemaGen(Map<String, InputStream> controlSchemas) throws Exception { |
| MyStreamSchemaOutputResolver outputResolver = new MyStreamSchemaOutputResolver(); |
| jaxbContext.generateSchema(outputResolver); |
| |
| Map<String, Writer> generatedSchemas = outputResolver.schemaFiles; |
| assertEquals(controlSchemas.size(), generatedSchemas.size()); |
| |
| for(String next:controlSchemas.keySet()){ |
| InputStream nextControlValue = controlSchemas.get(next); |
| |
| Writer sw = generatedSchemas.get(next); |
| InputSource nextGeneratedValue = new InputSource(new StringReader(sw.toString())); |
| |
| assertNotNull("Generated Schema not found.", nextGeneratedValue); |
| |
| Document control = parser.parse(nextControlValue); |
| Document test = parser.parse(nextGeneratedValue); |
| |
| JAXBXMLComparer xmlComparer = new JAXBXMLComparer(); |
| boolean isEqual = xmlComparer.isSchemaEqual(control, test); |
| if(!isEqual){ |
| log("Expected Schema\n"); |
| log(control); |
| log("ActualSchema\n"); |
| log(test); |
| } |
| assertTrue("generated schema did not match control schema", isEqual); |
| } |
| } |
| |
| /** |
| * Return an Element for a given xml-element snippet. |
| * |
| */ |
| protected Element getXmlElement(String xmlelement) throws Exception { |
| StringReader str = new StringReader(xmlelement); |
| InputSource is = new InputSource(str); |
| try { |
| return parser.parse(is).getDocumentElement(); |
| } catch (Exception e) { |
| throw e; |
| } |
| } |
| |
| private boolean compareByteArrays(Byte[] first, Byte[] second){ |
| if(first.length != second.length){ |
| return false; |
| } |
| |
| for(int i=0; i<first.length; i++){ |
| if (first[i] != second[i]){ |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| private boolean compareByteArrays(byte[] first, byte[] second){ |
| if(first.length != second.length){ |
| return false; |
| } |
| |
| for(int i=0; i<first.length; i++){ |
| if (first[i] != second[i]){ |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| protected void validateBindingsFileAgainstSchema(Source src) { |
| String result = null; |
| SchemaFactory sFact = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI); |
| Schema theSchema; |
| try { |
| theSchema = sFact.newSchema(bindingsFileXSDSource); |
| Validator validator = theSchema.newValidator(); |
| |
| validator.validate(src); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| if (e.getMessage() == null) { |
| result = "An unknown exception occurred."; |
| } |
| result = e.getMessage(); |
| } |
| assertTrue("Schema validation failed unxepectedly: " + result, result == null); |
| } |
| |
| public static class MyStreamSchemaOutputResolver extends SchemaOutputResolver { |
| // keep a list of processed schemas for the validation phase of the test(s) |
| public Map<String, Writer> schemaFiles; |
| |
| public MyStreamSchemaOutputResolver() { |
| schemaFiles = new HashMap<String, Writer>(); |
| } |
| |
| @Override |
| public Result createOutput(String namespaceURI, String suggestedFileName) throws IOException { |
| //return new StreamResult(System.out); |
| if (namespaceURI == null) { |
| namespaceURI = ""; |
| } |
| |
| StringWriter sw = new StringWriter(); |
| schemaFiles.put(namespaceURI, sw); |
| Result res = new StreamResult(sw); |
| res.setSystemId(suggestedFileName); |
| return res; |
| } |
| } |
| } |
| |
| |
| |
| |
| |