| /* |
| * Copyright (c) 2011, 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: |
| // rbarkhouse - 2011 March 21 - 2.3 - Initial implementation |
| package org.eclipse.persistence.testing.jaxb.xmlvirtualaccessmethods; |
| |
| import java.io.*; |
| import java.math.*; |
| import java.util.*; |
| |
| import jakarta.xml.bind.*; |
| import jakarta.xml.bind.util.JAXBSource; |
| import javax.xml.namespace.QName; |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| 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.*; |
| import javax.xml.validation.Validator; |
| |
| import org.eclipse.persistence.internal.oxm.XMLConversionManager; |
| import org.eclipse.persistence.jaxb.JAXBContextFactory; |
| import org.eclipse.persistence.jaxb.JAXBContextProperties; |
| import org.eclipse.persistence.oxm.XMLConstants; |
| import org.eclipse.persistence.testing.oxm.XMLTestCase; |
| import org.w3c.dom.*; |
| import org.w3c.dom.Element; |
| import org.xml.sax.*; |
| |
| public class XmlVirtualAccessMethodsTestCases extends XMLTestCase { |
| |
| private static boolean DEBUG = false; |
| private static boolean THROW_VALIDATION_ERRORS = false; |
| |
| private JAXBContext ctx; |
| |
| private byte[] bytes = new byte[] {23,1,112,12,1,64,1,14,3,2}; |
| private Byte[] bigBytes = new Byte[] {23,1,112,12,1,64,1,14,3,2}; |
| |
| public XmlVirtualAccessMethodsTestCases(String name) { |
| super(name); |
| } |
| |
| @Override |
| public String getName() { |
| return "XML Virtual Access Methods: " + super.getName(); |
| } |
| |
| public void testBasicModel() throws Exception { |
| InputStream oxm = ClassLoader.getSystemClassLoader().getResourceAsStream( |
| "org/eclipse/persistence/testing/jaxb/xmlvirtualaccessmethods/basic-eclipselink-oxm.xml"); |
| |
| Map<String, Object> ctxProperties = new HashMap<String, Object>(); |
| ctxProperties.put(JAXBContextProperties.OXM_METADATA_SOURCE, oxm); |
| |
| /** |
| * Employee extensions: |
| * - salary (BigDecimal) |
| * - age (Integer) |
| * - batphone (PhoneNumber) |
| * |
| * PhoneNumber extensions: |
| * - ext (String) |
| * - countryCode (String) |
| * - forwards (LinkedList of PhoneNumber) |
| */ |
| |
| ctx = JAXBContextFactory.createContext(new Class[] {Employee.class, PhoneNumber.class}, ctxProperties); |
| |
| Document marshalDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); |
| |
| Marshaller m = ctx.createMarshaller(); |
| m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); |
| m.marshal(getControlObjectBasic(), marshalDoc); |
| |
| if (DEBUG) { |
| System.out.println("*** TEST BASIC MODEL ***"); |
| m.marshal(getControlObjectBasic(), System.out); |
| } |
| |
| String[] extensions = new String[] { |
| "salary", "age", "batphone", "ext", "country-code", "forwards" |
| }; |
| |
| for (int i = 0; i < extensions.length; i++) { |
| // Test that Extensions appear in the marshalled document |
| NodeList nodeList = marshalDoc.getDocumentElement().getElementsByTagName(extensions[i]); |
| boolean found = nodeList != null && nodeList.getLength() > 0; |
| assertTrue("'" + extensions[i] + "' extension not found.", found); |
| } |
| |
| // Test that all 'forwards' PhoneNumbers were marshalled |
| NodeList nodeList = marshalDoc.getDocumentElement().getElementsByTagName("forwards"); |
| Node forwadsNode = nodeList.item(0); |
| |
| assertEquals("Incorrect number of 'forwards'.", 3, forwadsNode.getChildNodes().getLength()); |
| } |
| |
| public void testCompleteModel() throws Exception { |
| InputStream oxm = ClassLoader.getSystemClassLoader().getResourceAsStream( |
| "org/eclipse/persistence/testing/jaxb/xmlvirtualaccessmethods/eclipselink-oxm.xml"); |
| |
| Map<String, Object> ctxProperties = new HashMap<String, Object>(); |
| ctxProperties.put(JAXBContextProperties.OXM_METADATA_SOURCE, oxm); |
| |
| /** |
| * Extensions: |
| * - @directatt |
| * - directelem |
| * - nullpol |
| * - join |
| * - idref |
| * - xmllist |
| * - references |
| * - base64 |
| * - hex |
| * - bigByteArray |
| * - myStringArray |
| */ |
| |
| ctx = JAXBContextFactory.createContext(new Class[] {ExtObjectRoot.class, ExtObjectA.class, |
| ExtObjectB.class, ExtObjectC.class}, ctxProperties); |
| |
| Document marshalDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); |
| |
| Marshaller m = ctx.createMarshaller(); |
| m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); |
| m.marshal(getControlObjectComplete(), marshalDoc); |
| |
| if (DEBUG) { |
| System.out.println("*** TEST COMPLETE MODEL ***"); |
| m.marshal(getControlObjectComplete(), System.out); |
| } |
| |
| String[] extensions = new String[] { |
| "directelem", "nullpol", "join", "idref", "xmllist", "references", "base64", "hex", /*"bigByteArray",*/ "myStringArray" |
| }; |
| |
| Node attNode = marshalDoc.getDocumentElement().getChildNodes().item(0).getChildNodes().item(0).getAttributes().getNamedItem("directatt"); |
| assertNotNull("'directatt' extension not found.", attNode); |
| |
| for (int i = 0; i < extensions.length; i++) { |
| // Test that Extensions appear in the marshalled document |
| NodeList nodeList = marshalDoc.getDocumentElement().getElementsByTagName(extensions[i]); |
| boolean found = nodeList != null && nodeList.getLength() > 0; |
| assertTrue("'" + extensions[i] + "' extension not found.", found); |
| } |
| |
| Unmarshaller u = ctx.createUnmarshaller(); |
| ExtObjectRoot root = (ExtObjectRoot) u.unmarshal(marshalDoc); |
| |
| // Check that the Inverse Reference was set |
| try { |
| ExtObjectA a = root.flexObjectAs.get(0); |
| ExtObjectB b = (ExtObjectB) a.get("join"); |
| List refs = (List) b.get("references"); |
| ExtObjectC c = (ExtObjectC) refs.get(0); |
| assertTrue("Inverse Reference not set correctly.", c.get("inverse") == b); |
| } catch (Exception e) { |
| fail("Error testing inverse reference."); |
| } |
| |
| // Check Binary formats |
| String base64Str = |
| XMLConversionManager.getDefaultXMLManager().convertObject(bytes, String.class, XMLConstants.BASE_64_BINARY_QNAME).toString(); |
| String hexStr = |
| XMLConversionManager.getDefaultXMLManager().convertObject(bytes, String.class, XMLConstants.HEX_BINARY_QNAME).toString(); |
| |
| Element docElement = marshalDoc.getDocumentElement(); |
| Element flexObjectAsElem = (Element) docElement.getChildNodes().item(0); |
| Element base64Elem = (Element) flexObjectAsElem.getElementsByTagName("base64").item(0); |
| Element hexElem = (Element) flexObjectAsElem.getElementsByTagName("hex").item(0); |
| |
| assertEquals(base64Str, base64Elem.getFirstChild().getNodeValue()); |
| assertEquals(hexStr, hexElem.getFirstChild().getNodeValue()); |
| } |
| |
| public void testSchemaValidationBasic() throws Exception { |
| InputStream oxm = ClassLoader.getSystemClassLoader().getResourceAsStream( |
| "org/eclipse/persistence/testing/jaxb/xmlvirtualaccessmethods/basic-eclipselink-oxm.xml"); |
| |
| Map<String, Object> ctxProperties = new HashMap<String, Object>(); |
| ctxProperties.put(JAXBContextProperties.OXM_METADATA_SOURCE, oxm); |
| |
| ctx = JAXBContextFactory.createContext(new Class[] {Employee.class, PhoneNumber.class}, ctxProperties); |
| |
| validateAgainstSchema(ctx, getControlObjectBasic()); |
| } |
| |
| public void testSchemaValidationComplete() throws Exception { |
| InputStream oxm = ClassLoader.getSystemClassLoader().getResourceAsStream( |
| "org/eclipse/persistence/testing/jaxb/xmlvirtualaccessmethods/eclipselink-oxm.xml"); |
| |
| Map<String, Object> ctxProperties = new HashMap<String, Object>(); |
| ctxProperties.put(JAXBContextProperties.OXM_METADATA_SOURCE, oxm); |
| |
| ctx = JAXBContextFactory.createContext(new Class[] {ExtObjectRoot.class, ExtObjectA.class, |
| ExtObjectB.class, ExtObjectC.class}, ctxProperties); |
| |
| validateAgainstSchema(ctx, getControlObjectComplete()); |
| } |
| |
| private void validateAgainstSchema(JAXBContext ctx, Object obj) throws Exception { |
| JAXBSource source = new JAXBSource(ctx, obj); |
| |
| // Generate Schemas |
| StringOutputResolver sor = new StringOutputResolver(); |
| ctx.generateSchema(sor); |
| |
| if (DEBUG) { |
| System.out.println("*** VALIDATE SCHEMA " + obj.getClass()); |
| System.out.println(sor.getSchemas()); |
| Marshaller m = ctx.createMarshaller(); |
| m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); |
| m.marshal(obj, System.out); |
| } |
| |
| // Build javax.xml.validation.Schema |
| Schema schema; |
| Source[] schemaSources = new StreamSource[sor.getSchemas().size()]; |
| SchemaFactory schemaFactory = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI); |
| for (int i = 0; i < sor.getSchemas().size() ; i++) { |
| StringReader r = new StringReader(sor.getSchemas().get(i)); |
| schemaSources[i] = new StreamSource(r); |
| } |
| schema = schemaFactory.newSchema(schemaSources); |
| |
| |
| LogErrorHandler handler = new LogErrorHandler(); |
| Validator validator = schema.newValidator(); |
| validator.setErrorHandler(handler); |
| validator.validate(source); |
| |
| assertEquals("Unexpected number of validation errors thrown.", 0, handler.getErrorCount()); |
| } |
| |
| // ======================================================================== |
| |
| private Object getControlObjectBasic() { |
| PhoneNumber p1 = new PhoneNumber(); |
| p1.setId(1); |
| p1.setAreaCode(613); |
| p1.setNumber(2832684); |
| p1.setType("H"); |
| |
| PhoneNumber p2 = new PhoneNumber(); |
| p2.setId(2); |
| p2.setAreaCode(613); |
| p2.setNumber(2884613); |
| p2.setType("W"); |
| |
| PhoneNumber p3 = new PhoneNumber(); |
| p3.setId(3); |
| p3.setAreaCode(613); |
| p3.setNumber(8500210); |
| p3.setType("C"); |
| |
| Employee e = new Employee(); |
| e.id = 1; |
| e.firstName = "Rick"; |
| e.lastName = "Barkhouse"; |
| e.phoneNumbers.add(p1); |
| e.phoneNumbers.add(p2); |
| e.phoneNumbers.add(p3); |
| |
| e.extensions.put("salary", new BigDecimal(151755.75)); |
| e.setInt("age", 35); |
| e.setInt("dept", 14113); |
| |
| PhoneNumber p4 = new PhoneNumber(); |
| p4.setId(4); |
| p4.setAreaCode(555); |
| p4.setNumber(8884441); |
| p4.setType("Secret"); |
| p4.putExt("ext", "666"); |
| p4.putExt("countryCode", "GOTHAM"); |
| |
| e.extensions.put("batphone", p4); |
| |
| LinkedList<PhoneNumber> forwards = new LinkedList<PhoneNumber>(); |
| forwards.add(p1); |
| forwards.add(p2); |
| forwards.add(p3); |
| p4.putExt("forwards", forwards); |
| |
| return e; |
| } |
| |
| private Object getControlObjectComplete() { |
| ExtObjectC objC = new ExtObjectC(); |
| objC.set("directatt", "456"); |
| objC.set("directelem", "Baz1"); |
| |
| ExtObjectC objC2 = new ExtObjectC(); |
| objC2.set("directatt", "457"); |
| objC2.set("directelem", "Baz2"); |
| |
| ExtObjectB objB = new ExtObjectB(); |
| objB.set("directatt", "z123"); |
| objB.set("directelem", "Bar"); |
| |
| ArrayList<ExtObjectC> references = new ArrayList<ExtObjectC>(); |
| references.add(objC); |
| references.add(objC2); |
| objB.set("references", references); |
| objC.set("inverse", objB); |
| objC2.set("inverse", objB); |
| |
| ExtObjectA objA = new ExtObjectA(); |
| objA.set("directatt", "888"); |
| objA.set("directelem", "Foo"); |
| objA.set("nullpol", null); |
| objA.set("join", objB); |
| objA.set("idref", objB); |
| objA.set("anEnum", "N"); |
| |
| ArrayList<String> xmllist = new ArrayList<String>(); |
| xmllist.add("ONE"); xmllist.add("TWO"); xmllist.add("THREE"); |
| objA.set("xmllist", xmllist); |
| |
| ArrayList elements = new ArrayList(); |
| DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); |
| factory.setNamespaceAware(true); |
| factory.setIgnoringElementContentWhitespace(true); |
| try { |
| DocumentBuilder builder = factory.newDocumentBuilder(); |
| InputStream xml = ClassLoader.getSystemClassLoader().getResourceAsStream( |
| "org/eclipse/persistence/testing/jaxb/xmlvirtualaccessmethods/basic-eclipselink-oxm.xml"); |
| Document doc = builder.parse(xml); |
| Element rootElem = doc.getDocumentElement(); |
| NodeList children = rootElem.getChildNodes(); |
| for(int i = 0; i < children.getLength(); i++) { |
| if(children.item(i).getNodeType() == Element.ELEMENT_NODE) { |
| elements.add(children.item(i)); |
| } |
| } |
| } catch(Exception ex) {} |
| objA.set("mixed", elements); |
| |
| objA.set("base64", bytes); |
| objA.set("hex", bytes); |
| objA.set("bigByteArray", bigBytes); |
| |
| String[] s = new String[] {"one", "two", "three", "for"}; |
| objA.set("myStringArray", s); |
| |
| ExtObjectRoot root = new ExtObjectRoot(); |
| root.flexObjectAs.add(objA); |
| root.flexObjectBs.add(objB); |
| |
| return root; |
| } |
| |
| private class LogErrorHandler implements ErrorHandler { |
| private int errorCount = 0; |
| |
| @Override |
| public void warning(SAXParseException exception) throws SAXException { |
| errorCount++; |
| if (DEBUG) { |
| System.out.println("\nWARNING"); |
| System.out.println(exception.getMessage()); |
| } |
| if (THROW_VALIDATION_ERRORS) throw exception; |
| } |
| |
| @Override |
| public void error(SAXParseException exception) throws SAXException { |
| errorCount++; |
| if (DEBUG) { |
| System.out.println("\nERROR"); |
| System.out.println(exception.getMessage()); |
| } |
| if (THROW_VALIDATION_ERRORS) throw exception; |
| } |
| |
| @Override |
| public void fatalError(SAXParseException exception) throws SAXException { |
| errorCount++; |
| if (DEBUG) { |
| System.out.println("\nFATAL ERROR"); |
| exception.printStackTrace(); |
| } |
| if (THROW_VALIDATION_ERRORS) throw exception; |
| } |
| |
| public int getErrorCount() { |
| return errorCount; |
| } |
| } |
| |
| private class StringOutputResolver extends SchemaOutputResolver { |
| private HashMap<String, StringWriter> stringWriters; |
| |
| public StringOutputResolver() { |
| stringWriters = new HashMap<String, StringWriter>(); |
| } |
| |
| @Override |
| public Result createOutput(String arg0, String arg1) throws IOException { |
| StringWriter sw = stringWriters.get(arg1); |
| if (sw == null) { |
| sw = new StringWriter(); |
| stringWriters.put(arg1, sw); |
| } |
| StreamResult sr = new StreamResult(sw); |
| sr.setSystemId(arg1); |
| return sr; |
| } |
| |
| private List<String> getSchemas() { |
| List<String> schemas = new ArrayList<String>(); |
| Iterator<StringWriter> it = stringWriters.values().iterator(); |
| while (it.hasNext()) { |
| StringWriter sw = it.next(); |
| schemas.add(sw.toString()); |
| } |
| return schemas; |
| } |
| } |
| |
| } |