Details
-
Bug
-
Status: Verified
-
Resolution: Unresolved
-
7.0.0 DXP FP32, 7.0.X
-
None
-
3
-
3
Description
Issue Overview
For Spring MVC portlets whose JARs (in WEB-INF/lib) contain properties files, such as these ...
- WEB-INF/src/META-INF/spring.handlers
- WEB-INF/src/META-INF/spring.schemas
- WEB-INF/src/META-INF/spring.tooling
... the ones from the last JAR listed are the only properties files put in the classpath.
As a result, properties in files in the other JARs aren't available in the classpath.
Steps to Reproduce
- Update gradle/apps/service-builder/basic/basic-service/build.gradle to include a compile-time dependency on cxf-core
compile group: "org.apache.cxf", name: "cxf-core", version: "3.2.5"
- Update gradle/apps/service-builder/basic/basic-service/bnd.bnd to embed the .jar, but make all of its imports optional
Import-Package: *;resolution:="optional" -includeresource: lib/cxf-core.jar=cxf-core-[0-9]*.jar;lib:=true
- Unplug your internet connection, to enforce using the spring.schemas file for loading schemas locally
- Deploy basic-api and the updated basic-service
Expected behavior is that Liferay doesn't have any trouble loading the Spring configuration files. Actual behavior is that the spring.schemas provided by the cxf-core.jar overrides the one that will be used by the portal Spring extender, because Liferay is using only the spring.schemas file from cxf-core.jar and ignoring all others, including the one that should be visible via the portal Spring extender. As a result, you get the following exceptions:
Caused by: org.xml.sax.SAXParseException; lineNumber: 9; columnNumber: 2; cvc-elt.1.a: Cannot find the declaration of element 'beans'. at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source) at org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown Source) at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source) at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source) at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
Workaround 1
Run a shell script, such as the one below, to combine the properties files from the JARs and add the combined properties files to WEB-INF/src. Here's the script:
cat /dev/null > docroot/WEB-INF/src/META-INF/spring.handlers cat /dev/null > docroot/WEB-INF/src/META-INF/spring.schemas cat /dev/null > docroot/WEB-INF/src/META-INF/spring.tooling for jar in $(find docroot/WEB-INF/lib/ -name '*.jar'); do for file in $(unzip -l $jar | grep -F META-INF/spring. | awk '{ print $4 }'); do if [ "META-INF/spring.tld" != "$file" ]; then unzip -p $jar $file >> docroot/WEB-INF/src/$file echo >> docroot/WEB-INF/src/$file fi done done
Workaround 2
If this is a module project, add the following to each build.gradle that has any dependencies on Spring-related .jars in order to have it scan for spring.handlers, spring.schemas, and spring.tooling at build time to re-generate the file.
import java.util.jar.JarEntry import java.util.jar.JarFile task writeSpringSchemas processResources { finalizedBy writeSpringSchemas } writeSpringSchemas { doLast { List<String> entryNames = ["META-INF/spring.handlers", "META-INF/spring.schemas", "META-INF/spring.tooling"] Map<String, Properties> springProperties = new HashMap<String, Properties>() for (String entryName in entryNames) { springProperties.put(entryName, new Properties()) } for (File dependencyFile in configurations.compile + configurations.compileOnly) { JarFile jarFile = new JarFile(dependencyFile) jarFile.withCloseable { for (String entryName in entryNames) { JarEntry jarEntry = jarFile.getEntry(entryName) if (jarEntry) { InputStream inputStream = jarFile.getInputStream(jarEntry) Properties properties = new Properties() inputStream.withStream { properties.load it } println '###' + properties springProperties.get(entryName).putAll properties } } } } for (String entryName in entryNames) { File springFile = new File(processResources.destinationDir, entryName) springFile.withOutputStream { springProperties.get(entryName).store it, null } } } }
If the module is a service builder service, also add the following dependency.
compileOnly group: "com.liferay", name: "com.liferay.portal.spring.extender", version: "2.0.0"