From a4c2f291d986ccf988f37af5466265a7f534c16a Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 21 May 2024 11:16:19 +0200 Subject: [PATCH 1/2] Avoid creation of SAXParserFactory for every read operation Includes JAXBContext locking revision (avoiding synchronization) and consistent treatment of DocumentBuilderFactory (in terms of caching as well as locking). Closes gh-32851 --- .../oxm/jaxb/Jaxb2Marshaller.java | 47 +++++++++--- .../oxm/support/AbstractMarshaller.java | 46 ++++++----- .../Jaxb2RootElementHttpMessageConverter.java | 23 ++++-- .../xml/SourceHttpMessageConverter.java | 76 +++++++++++++------ 4 files changed, 133 insertions(+), 59 deletions(-) diff --git a/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java b/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java index 9ed4a30a7c..2d903c092c 100644 --- a/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java +++ b/spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java @@ -37,6 +37,8 @@ import java.util.Calendar; import java.util.Date; import java.util.Map; import java.util.UUID; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import javax.xml.XMLConstants; import javax.xml.datatype.Duration; @@ -192,7 +194,7 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi @Nullable private ClassLoader beanClassLoader; - private final Object jaxbContextMonitor = new Object(); + private final Lock jaxbContextLock = new ReentrantLock(); @Nullable private volatile JAXBContext jaxbContext; @@ -204,6 +206,12 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi private boolean processExternalEntities = false; + @Nullable + private volatile SAXParserFactory schemaParserFactory; + + @Nullable + private volatile SAXParserFactory sourceParserFactory; + /** * Set multiple JAXB context paths. The given array of context paths gets @@ -426,6 +434,7 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi */ public void setSupportDtd(boolean supportDtd) { this.supportDtd = supportDtd; + this.sourceParserFactory = null; } /** @@ -450,6 +459,7 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi if (processExternalEntities) { this.supportDtd = true; } + this.sourceParserFactory = null; } /** @@ -497,7 +507,9 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi if (context != null) { return context; } - synchronized (this.jaxbContextMonitor) { + + this.jaxbContextLock.lock(); + try { context = this.jaxbContext; if (context == null) { try { @@ -521,6 +533,9 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi } return context; } + finally { + this.jaxbContextLock.unlock(); + } } private JAXBContext createJaxbContextFromContextPath(String contextPath) throws JAXBException { @@ -587,17 +602,24 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi Assert.notEmpty(resources, "No resources given"); Assert.hasLength(schemaLanguage, "No schema language provided"); Source[] schemaSources = new Source[resources.length]; - SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); - saxParserFactory.setNamespaceAware(true); - saxParserFactory.setFeature("http://xml.org/sax/features/namespace-prefixes", true); + + SAXParserFactory saxParserFactory = this.schemaParserFactory; + if (saxParserFactory == null) { + saxParserFactory = SAXParserFactory.newInstance(); + saxParserFactory.setNamespaceAware(true); + saxParserFactory.setFeature("http://xml.org/sax/features/namespace-prefixes", true); + this.schemaParserFactory = saxParserFactory; + } SAXParser saxParser = saxParserFactory.newSAXParser(); XMLReader xmlReader = saxParser.getXMLReader(); + for (int i = 0; i < resources.length; i++) { Resource resource = resources[i]; Assert.isTrue(resource != null && resource.exists(), () -> "Resource does not exist: " + resource); InputSource inputSource = SaxResourceUtils.createInputSource(resource); schemaSources[i] = new SAXSource(xmlReader, inputSource); } + SchemaFactory schemaFactory = SchemaFactory.newInstance(schemaLanguage); if (this.schemaResourceResolver != null) { schemaFactory.setResourceResolver(this.schemaResourceResolver); @@ -886,11 +908,16 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi try { if (xmlReader == null) { - SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); - saxParserFactory.setNamespaceAware(true); - saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); - String name = "http://xml.org/sax/features/external-general-entities"; - saxParserFactory.setFeature(name, isProcessExternalEntities()); + SAXParserFactory saxParserFactory = this.sourceParserFactory; + if (saxParserFactory == null) { + saxParserFactory = SAXParserFactory.newInstance(); + saxParserFactory.setNamespaceAware(true); + saxParserFactory.setFeature( + "http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); + saxParserFactory.setFeature( + "http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); + this.sourceParserFactory = saxParserFactory; + } SAXParser saxParser = saxParserFactory.newSAXParser(); xmlReader = saxParser.getXMLReader(); } diff --git a/spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java b/spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java index 7c6182c4a7..a3925acb50 100644 --- a/spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java +++ b/spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -83,9 +83,10 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { private boolean processExternalEntities = false; @Nullable - private DocumentBuilderFactory documentBuilderFactory; + private volatile DocumentBuilderFactory documentBuilderFactory; - private final Object documentBuilderFactoryMonitor = new Object(); + @Nullable + private volatile SAXParserFactory saxParserFactory; /** @@ -94,6 +95,8 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { */ public void setSupportDtd(boolean supportDtd) { this.supportDtd = supportDtd; + this.documentBuilderFactory = null; + this.saxParserFactory = null; } /** @@ -118,6 +121,8 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { if (processExternalEntities) { this.supportDtd = true; } + this.documentBuilderFactory = null; + this.saxParserFactory = null; } /** @@ -137,14 +142,13 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { */ protected Document buildDocument() { try { - DocumentBuilder documentBuilder; - synchronized (this.documentBuilderFactoryMonitor) { - if (this.documentBuilderFactory == null) { - this.documentBuilderFactory = createDocumentBuilderFactory(); - } - documentBuilder = createDocumentBuilder(this.documentBuilderFactory); + DocumentBuilderFactory builderFactory = this.documentBuilderFactory; + if (builderFactory == null) { + builderFactory = createDocumentBuilderFactory(); + this.documentBuilderFactory = builderFactory; } - return documentBuilder.newDocument(); + DocumentBuilder builder = createDocumentBuilder(builderFactory); + return builder.newDocument(); } catch (ParserConfigurationException ex) { throw new UnmarshallingFailureException("Could not create document placeholder: " + ex.getMessage(), ex); @@ -179,11 +183,11 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory) throws ParserConfigurationException { - DocumentBuilder documentBuilder = factory.newDocumentBuilder(); + DocumentBuilder builder = factory.newDocumentBuilder(); if (!isProcessExternalEntities()) { - documentBuilder.setEntityResolver(NO_OP_ENTITY_RESOLVER); + builder.setEntityResolver(NO_OP_ENTITY_RESOLVER); } - return documentBuilder; + return builder; } /** @@ -193,11 +197,17 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { * @throws ParserConfigurationException if thrown by JAXP methods */ protected XMLReader createXmlReader() throws SAXException, ParserConfigurationException { - SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); - saxParserFactory.setNamespaceAware(true); - saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); - saxParserFactory.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); - SAXParser saxParser = saxParserFactory.newSAXParser(); + SAXParserFactory parserFactory = this.saxParserFactory; + if (parserFactory == null) { + parserFactory = SAXParserFactory.newInstance(); + parserFactory.setNamespaceAware(true); + parserFactory.setFeature( + "http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); + parserFactory.setFeature( + "http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); + this.saxParserFactory = parserFactory; + } + SAXParser saxParser = parserFactory.newSAXParser(); XMLReader xmlReader = saxParser.getXMLReader(); if (!isProcessExternalEntities()) { xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER); diff --git a/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java index a08e1d2172..dda603995a 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,6 +61,7 @@ import org.springframework.util.ClassUtils; * @author Arjen Poutsma * @author Sebastien Deleuze * @author Rossen Stoyanchev + * @author Juergen Hoeller * @since 3.0 * @see MarshallingHttpMessageConverter */ @@ -70,6 +71,9 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa private boolean processExternalEntities = false; + @Nullable + private volatile SAXParserFactory sourceParserFactory; + /** * Indicate whether DTD parsing should be supported. @@ -77,6 +81,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa */ public void setSupportDtd(boolean supportDtd) { this.supportDtd = supportDtd; + this.sourceParserFactory = null; } /** @@ -97,6 +102,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa if (processExternalEntities) { this.supportDtd = true; } + this.sourceParserFactory = null; } /** @@ -156,11 +162,16 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa if (source instanceof StreamSource streamSource) { InputSource inputSource = new InputSource(streamSource.getInputStream()); try { - SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); - saxParserFactory.setNamespaceAware(true); - saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); - String featureName = "http://xml.org/sax/features/external-general-entities"; - saxParserFactory.setFeature(featureName, isProcessExternalEntities()); + SAXParserFactory saxParserFactory = this.sourceParserFactory; + if (saxParserFactory == null) { + saxParserFactory = SAXParserFactory.newInstance(); + saxParserFactory.setNamespaceAware(true); + saxParserFactory.setFeature( + "http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); + saxParserFactory.setFeature( + "http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); + this.sourceParserFactory = saxParserFactory; + } SAXParser saxParser = saxParserFactory.newSAXParser(); XMLReader xmlReader = saxParser.getXMLReader(); if (!isProcessExternalEntities()) { diff --git a/spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java index d835522776..c99d0bb033 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java @@ -63,6 +63,7 @@ import org.springframework.util.StreamUtils; * * @author Arjen Poutsma * @author Rossen Stoyanchev + * @author Juergen Hoeller * @since 3.0 * @param the converted object type */ @@ -75,11 +76,7 @@ public class SourceHttpMessageConverter extends AbstractHttpMe (publicID, systemID, base, ns) -> InputStream.nullInputStream(); private static final Set> SUPPORTED_CLASSES = Set.of( - DOMSource.class, - SAXSource.class, - StAXSource.class, - StreamSource.class, - Source.class); + DOMSource.class, SAXSource.class, StAXSource.class, StreamSource.class, Source.class); private final TransformerFactory transformerFactory = TransformerFactory.newInstance(); @@ -88,6 +85,15 @@ public class SourceHttpMessageConverter extends AbstractHttpMe private boolean processExternalEntities = false; + @Nullable + private volatile DocumentBuilderFactory documentBuilderFactory; + + @Nullable + private volatile SAXParserFactory saxParserFactory; + + @Nullable + private volatile XMLInputFactory xmlInputFactory; + /** * Sets the {@link #setSupportedMediaTypes(java.util.List) supportedMediaTypes} @@ -104,6 +110,9 @@ public class SourceHttpMessageConverter extends AbstractHttpMe */ public void setSupportDtd(boolean supportDtd) { this.supportDtd = supportDtd; + this.documentBuilderFactory = null; + this.saxParserFactory = null; + this.xmlInputFactory = null; } /** @@ -124,6 +133,9 @@ public class SourceHttpMessageConverter extends AbstractHttpMe if (processExternalEntities) { this.supportDtd = true; } + this.documentBuilderFactory = null; + this.saxParserFactory = null; + this.xmlInputFactory = null; } /** @@ -165,17 +177,21 @@ public class SourceHttpMessageConverter extends AbstractHttpMe private DOMSource readDOMSource(InputStream body, HttpInputMessage inputMessage) throws IOException { try { - DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); - documentBuilderFactory.setNamespaceAware(true); - documentBuilderFactory.setFeature( - "http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); - documentBuilderFactory.setFeature( - "http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); - DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); - if (!isProcessExternalEntities()) { - documentBuilder.setEntityResolver(NO_OP_ENTITY_RESOLVER); + DocumentBuilderFactory builderFactory = this.documentBuilderFactory; + if (builderFactory == null) { + builderFactory = DocumentBuilderFactory.newInstance(); + builderFactory.setNamespaceAware(true); + builderFactory.setFeature( + "http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); + builderFactory.setFeature( + "http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); + this.documentBuilderFactory = builderFactory; } - Document document = documentBuilder.parse(body); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + if (!isProcessExternalEntities()) { + builder.setEntityResolver(NO_OP_ENTITY_RESOLVER); + } + Document document = builder.parse(body); return new DOMSource(document); } catch (NullPointerException ex) { @@ -197,11 +213,17 @@ public class SourceHttpMessageConverter extends AbstractHttpMe private SAXSource readSAXSource(InputStream body, HttpInputMessage inputMessage) throws IOException { try { - SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); - saxParserFactory.setNamespaceAware(true); - saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); - saxParserFactory.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); - SAXParser saxParser = saxParserFactory.newSAXParser(); + SAXParserFactory parserFactory = this.saxParserFactory; + if (parserFactory == null) { + parserFactory = SAXParserFactory.newInstance(); + parserFactory.setNamespaceAware(true); + parserFactory.setFeature( + "http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); + parserFactory.setFeature( + "http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); + this.saxParserFactory = parserFactory; + } + SAXParser saxParser = parserFactory.newSAXParser(); XMLReader xmlReader = saxParser.getXMLReader(); if (!isProcessExternalEntities()) { xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER); @@ -217,11 +239,15 @@ public class SourceHttpMessageConverter extends AbstractHttpMe private Source readStAXSource(InputStream body, HttpInputMessage inputMessage) { try { - XMLInputFactory inputFactory = XMLInputFactory.newInstance(); - inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, isSupportDtd()); - inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, isProcessExternalEntities()); - if (!isProcessExternalEntities()) { - inputFactory.setXMLResolver(NO_OP_XML_RESOLVER); + XMLInputFactory inputFactory = this.xmlInputFactory; + if (inputFactory == null) { + inputFactory = XMLInputFactory.newInstance(); + inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, isSupportDtd()); + inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, isProcessExternalEntities()); + if (!isProcessExternalEntities()) { + inputFactory.setXMLResolver(NO_OP_XML_RESOLVER); + } + this.xmlInputFactory = inputFactory; } XMLStreamReader streamReader = inputFactory.createXMLStreamReader(body); return new StAXSource(streamReader); From 65e1337d35cf7aa398798b8a7a8034518943940e Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 21 May 2024 11:16:25 +0200 Subject: [PATCH 2/2] Polishing --- ...SpringConfiguredWithAutoProxyingTests.java | 7 +++++-- .../PersistenceUnitReader.java | 20 ++++++++----------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/spring-aspects/src/test/java/org/springframework/beans/factory/aspectj/SpringConfiguredWithAutoProxyingTests.java b/spring-aspects/src/test/java/org/springframework/beans/factory/aspectj/SpringConfiguredWithAutoProxyingTests.java index 9be725fa8c..f47eb7ba3c 100644 --- a/spring-aspects/src/test/java/org/springframework/beans/factory/aspectj/SpringConfiguredWithAutoProxyingTests.java +++ b/spring-aspects/src/test/java/org/springframework/beans/factory/aspectj/SpringConfiguredWithAutoProxyingTests.java @@ -20,11 +20,14 @@ import org.junit.jupiter.api.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; -public class SpringConfiguredWithAutoProxyingTests { +/** + * @author Ramnivas Laddad + * @author Juergen Hoeller + */ +class SpringConfiguredWithAutoProxyingTests { @Test void springConfiguredAndAutoProxyUsedTogether() { - // instantiation is sufficient to trigger failure if this is going to fail... new ClassPathXmlApplicationContext("org/springframework/beans/factory/aspectj/springConfigured.xml"); } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java index 00a167f8d5..ddd74f1923 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -154,7 +154,7 @@ final class PersistenceUnitReader { /** * Validate the given stream and return a valid DOM document for parsing. */ - protected Document buildDocument(ErrorHandler handler, InputStream stream) + Document buildDocument(ErrorHandler handler, InputStream stream) throws ParserConfigurationException, SAXException, IOException { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); @@ -168,9 +168,7 @@ final class PersistenceUnitReader { /** * Parse the validated document and add entries to the given unit info list. */ - protected List parseDocument( - Resource resource, Document document, List infos) throws IOException { - + void parseDocument(Resource resource, Document document, List infos) throws IOException { Element persistence = document.getDocumentElement(); String version = persistence.getAttribute(PERSISTENCE_VERSION); URL rootUrl = determinePersistenceUnitRootUrl(resource); @@ -179,14 +177,12 @@ final class PersistenceUnitReader { for (Element unit : units) { infos.add(parsePersistenceUnitInfo(unit, version, rootUrl)); } - - return infos; } /** * Parse the unit info DOM element. */ - protected SpringPersistenceUnitInfo parsePersistenceUnitInfo( + SpringPersistenceUnitInfo parsePersistenceUnitInfo( Element persistenceUnit, String version, @Nullable URL rootUrl) throws IOException { SpringPersistenceUnitInfo unitInfo = new SpringPersistenceUnitInfo(); @@ -253,7 +249,7 @@ final class PersistenceUnitReader { /** * Parse the {@code property} XML elements. */ - protected void parseProperties(Element persistenceUnit, SpringPersistenceUnitInfo unitInfo) { + void parseProperties(Element persistenceUnit, SpringPersistenceUnitInfo unitInfo) { Element propRoot = DomUtils.getChildElementByTagName(persistenceUnit, PROPERTIES); if (propRoot == null) { return; @@ -269,7 +265,7 @@ final class PersistenceUnitReader { /** * Parse the {@code class} XML elements. */ - protected void parseManagedClasses(Element persistenceUnit, SpringPersistenceUnitInfo unitInfo) { + void parseManagedClasses(Element persistenceUnit, SpringPersistenceUnitInfo unitInfo) { List classes = DomUtils.getChildElementsByTagName(persistenceUnit, MANAGED_CLASS_NAME); for (Element element : classes) { String value = DomUtils.getTextValue(element).trim(); @@ -282,7 +278,7 @@ final class PersistenceUnitReader { /** * Parse the {@code mapping-file} XML elements. */ - protected void parseMappingFiles(Element persistenceUnit, SpringPersistenceUnitInfo unitInfo) { + void parseMappingFiles(Element persistenceUnit, SpringPersistenceUnitInfo unitInfo) { List files = DomUtils.getChildElementsByTagName(persistenceUnit, MAPPING_FILE_NAME); for (Element element : files) { String value = DomUtils.getTextValue(element).trim(); @@ -295,7 +291,7 @@ final class PersistenceUnitReader { /** * Parse the {@code jar-file} XML elements. */ - protected void parseJarFiles(Element persistenceUnit, SpringPersistenceUnitInfo unitInfo) throws IOException { + void parseJarFiles(Element persistenceUnit, SpringPersistenceUnitInfo unitInfo) throws IOException { List jars = DomUtils.getChildElementsByTagName(persistenceUnit, JAR_FILE_URL); for (Element element : jars) { String value = DomUtils.getTextValue(element).trim();