1
votes

I'm changing the jta-data-source value of a persistence.xml as follows:

JavaArchive jarArchive = Maven.configureResolver().workOffline().resolve("richtercloud:project1-jar:jar:1.0-SNAPSHOT").withoutTransitivity().asSingle(JavaArchive.class);
Node persistenceXml = jarArchive.get("META-INF/persistence.xml");
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document persistenceXmlDocument = documentBuilder.parse(persistenceXml.getAsset().openStream());
    //asked
    //https://stackguides.com/questions/46771622/how-to-create-a-shrinkwrap-persistencedescriptor-from-an-existing-persistence-xm
    //for how to manipulate persistence.xml more easily with
    //ShrinkWrap's PersistenceDescriptor
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("//persistence-unit/jta-data-source");
org.w3c.dom.Node persistenceXmlDataSourceNode = (org.w3c.dom.Node) expr.evaluate(persistenceXmlDocument,
        XPathConstants.NODE);
persistenceXmlDataSourceNode.setTextContent("jdbc/project1-test-db");

TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
//transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
//was there before, but unclear why
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(persistenceXmlDocument), new StreamResult(writer));
String persistenceUnit = writer.toString();

(since How to create a ShrinkWrap PersistenceDescriptor from an existing persistence.xml? has not been answered, yet).

That works fine, except for a xmlns="" attribute added to the persistence-unit under the root persistence element which seems to cause:

java.io.IOException: org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 108; Deployment descriptor file META-INF/persistence.xml in archive [project1-jar-1.0-SNAPSHOT.jar]. cvc-complex-type.2.4.a: Invalid content was found starting with element 'persistence-unit'. One of '{"http://xmlns.jcp.org/xml/ns/persistence":persistence-unit}' is expected.

I'm not adhering to the idea to use Transformer and related classes.

1
Could you please post the input file to be able to see and reproduce the problem?Sergey Vyacheslavovich Brunov
@SergeyBrunov I just realized that this only happens in the @Deployment method of an Arquillian Drone test method and is not reproducible in a Java SE program.Karl Richter

1 Answers

1
votes

No idea why I can't reproduce this in Java SE, but the problem is that javax.xml.parsers.DocumentBuilder by default isn't namespace aware so that the namespace information gets lost during manipulation of the document and consequently an empty xmlns is added by Transformer.

Now that DocumentBuilder is namespace aware, XPath resolution doesn't work and queries return null, see XPath returning null for "Node" when isNameSpaceAware and isValidating are "true" for a detailed description and more details on the XPath namespace awareness issue (I couldn't get the solution to build a custom NamespaceContext to work).

In order to avoid this I finally adjusted my XPath query to use the local-name function as described at How to ignore namespace when selecting XML nodes with XPath. i.e. //*[local-name()='jta-data-source'].

It's still necessary to use Document.createElementNS instead of createElement in order to avoid empty xmlns attribute on newly created elements, see Empty default XML namespace xmlns="" attribute being added? for an explanation.