You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have a maven project where I use jaxb2-maven-plugin 2.5.0. I'm using that version because I need something that works with both Java 8 and Java 11. It has a project structure like this:
Here, I'm just showing one application module. But in the real situation I have, there are many applications that use the "shared" module, which uses jaxb2-maven-plugin's xjc goal. The key characteristic here is that "shared" isn't a child directory of "application", it is a sibling. application/pom.xml refers to shared with an entry like this: ../shared. I've attached jaxb2-maven-plugin-bug.tar.gz that shows this structure and that can be used to reproduce the problem I'll describe -- just cd into the "application" directory and run "mvn clean verify".
When I run maven in the application directory, it fails because it tries to use a mangled path to the example.xsd file. The path it looks for is file:/myprojects/jaxb2-maven-plugin-bug/application/myprojects/jaxb2-maven-plugin-bug/shared/src/main/resources/xsd/example.xsd which incorrectly has /myprojects/jaxb2-maven-plugin-bug/application prepended to it. The correct URL would be file:/myprojects/jaxb2-maven-plugin-bug/shared/src/main/resources/xsd/example.xsd. The exception is
org.xml.sax.SAXParseException: schema_reference.4: Failed to read schema document 'file:/myprojects/jaxb2-maven-plugin-bug/application/myprojects/jaxb2-maven-plugin-bug/shared/src/main/resources/xsd/example.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
This doesn't happen on Windows, but it fails like this on Linux. My example project uses a relative path to the xsd (<source>src/main/resources/xsd/example.xsd</source>) but the same problem happens if I use an absolute path, because it seems that before the code that introduces the bad path runs, the path has been canonicalized to a (correct) absolute path, but then later gets mangled.
Here's a complete log of running "mvn clean verify" when cd'd into the "application" directory:
I tracked the problem down to an error in src/main/java/org/codehaus/mojo/jaxb2/shared/FileSystemUtilities.java, in the relativize method. Here's the original 2.5.0 code for that:
/**
* If the supplied path refers to a file or directory below the supplied basedir, the returned
* path is identical to the part below the basedir.
*
* @param path The path to strip off basedir path from, and return.
* @param parentDir The maven project basedir.
* @param removeInitialFileSep If true, an initial {@code File#separator} is removed before returning.
* @return The path relative to basedir, if it is situated below the basedir. Otherwise the supplied path.
*/
public static String relativize(final String path,
final File parentDir,
final boolean removeInitialFileSep) {
// Check sanity
Validate.notNull(path, "path");
Validate.notNull(parentDir, "parentDir");
final String basedirPath = FileSystemUtilities.getCanonicalPath(parentDir);
String toReturn = path;
// Compare case insensitive
if (path.toLowerCase().startsWith(basedirPath.toLowerCase())) {
toReturn = path.substring(basedirPath.length());
}
// Handle whitespace in the argument.
return removeInitialFileSep && toReturn.startsWith(File.separator)
? toReturn.substring(File.separator.length())
: toReturn;
}
The problem is that when the application maven module is a sibling of the module that invokes xjc, the path startsWith test is false, so by the javadoc (@return The path relative to basedir, if it is situated below the basedir. Otherwise the supplied path.) it should return the path argument as-is, which will be an absolute path. But then it removes the initial slash in the return statement, resulting in a relative path that isn't actually correctly relative to the "parentDir" -- that would only be the right relativized path if parentDir was "/", which it isn't.
The fix to make it behave as the javadoc specifies is simple, moving the return statement into the if, and otherwise just returning the supplied path, as the "@return" javadoc specifies. With just that change, my project builds correctly.
Here's my modified code:
/**
* If the supplied path refers to a file or directory below the supplied basedir, the returned
* path is identical to the part below the basedir.
*
* @param path The path to strip off basedir path from, and return.
* @param parentDir The maven project basedir.
* @param removeInitialFileSep If true, an initial {@code File#separator} is removed before returning.
* @return The path relative to basedir, if it is situated below the basedir. Otherwise the supplied path.
*/
public static String relativize(final String path,
final File parentDir,
final boolean removeInitialFileSep) {
// Check sanity
Validate.notNull(path, "path");
Validate.notNull(parentDir, "parentDir");
final String basedirPath = FileSystemUtilities.getCanonicalPath(parentDir);
String toReturn = path;
// Compare case insensitive
if (path.toLowerCase().startsWith(basedirPath.toLowerCase())) {
toReturn = path.substring(basedirPath.length());
// Handle whitespace in the argument.
return removeInitialFileSep && toReturn.startsWith(File.separator)
? toReturn.substring(File.separator.length())
: toReturn;
}
return toReturn;
}
I ran all of the tests, and all of them pass except validateRelativizingPaths in FileSystemUtilitiesTest. That test calls relativize with path set to /project/backend/foobar/my-schema.xsd with various values of parentDir. Two of the five verifications there fail, these ones:
In both cases, the tests fail because the specified expected result in the test isn't actually a correct relative path from the parentDir to the path. In the first one, it passes in "" as the parentDir, which the test then passes to relativize as new File(""). So the actual parent path passed to the method isn't "" but is the jaxb2-maven-plugin project directory, and "project/backend/foobar/my-schema.xsd" isn't the correct relative path from the plugin project directory. The problem in the /not/a/path case is the same -- the indicated expected relativized path from /not/a/path to /project/backend/foobar/my-schema.xsd isn't project/backend/foobar/my-schema.xsd but would be ../../../project/backend/foobar/my-schema.xsd.
But, the javadoc says that when the path isn't a child of parentDir, just return the path argument as-is rather than returning a relative path, and the code seems to work correctly with my modified code that does that. All of the tests passed including all of the integration tests after I retrained those two cases to be these:
That pull request does look like the equivalent of my proposed fix. But my fix is for the 2.5 version of the relativize method while the pull request is for the 3.1 version of that method.
I would love to see both 2.5 and 3.1 patched because as I mentioned earlier I am not yet in a position where I can use 3.1. What are the prospects for picking up the fix?
I have a maven project where I use jaxb2-maven-plugin 2.5.0. I'm using that version because I need something that works with both Java 8 and Java 11. It has a project structure like this:
application
pom.xml
shared
pom.xml
src/main/resources/xsd/example.xsd
Here, I'm just showing one application module. But in the real situation I have, there are many applications that use the "shared" module, which uses jaxb2-maven-plugin's xjc goal. The key characteristic here is that "shared" isn't a child directory of "application", it is a sibling. application/pom.xml refers to shared with an entry like this: ../shared. I've attached jaxb2-maven-plugin-bug.tar.gz that shows this structure and that can be used to reproduce the problem I'll describe -- just cd into the "application" directory and run "mvn clean verify".
jaxb2-maven-plugin-bug.tar.gz
shared/pom.xml has this invocation of the xjc goal:
When I run maven in the application directory, it fails because it tries to use a mangled path to the example.xsd file. The path it looks for is
file:/myprojects/jaxb2-maven-plugin-bug/application/myprojects/jaxb2-maven-plugin-bug/shared/src/main/resources/xsd/example.xsd
which incorrectly has/myprojects/jaxb2-maven-plugin-bug/application
prepended to it. The correct URL would befile:/myprojects/jaxb2-maven-plugin-bug/shared/src/main/resources/xsd/example.xsd
. The exception isThis doesn't happen on Windows, but it fails like this on Linux. My example project uses a relative path to the xsd (
<source>src/main/resources/xsd/example.xsd</source>
) but the same problem happens if I use an absolute path, because it seems that before the code that introduces the bad path runs, the path has been canonicalized to a (correct) absolute path, but then later gets mangled.Here's a complete log of running "mvn clean verify" when cd'd into the "application" directory:
jaxb2-maven-plugin-bug.log
I tracked the problem down to an error in src/main/java/org/codehaus/mojo/jaxb2/shared/FileSystemUtilities.java, in the relativize method. Here's the original 2.5.0 code for that:
The problem is that when the application maven module is a sibling of the module that invokes xjc, the path startsWith test is false, so by the javadoc (
@return The path relative to basedir, if it is situated below the basedir. Otherwise the supplied path.
) it should return the path argument as-is, which will be an absolute path. But then it removes the initial slash in the return statement, resulting in a relative path that isn't actually correctly relative to the "parentDir" -- that would only be the right relativized path if parentDir was "/", which it isn't.The fix to make it behave as the javadoc specifies is simple, moving the return statement into the if, and otherwise just returning the supplied path, as the "@return" javadoc specifies. With just that change, my project builds correctly.
Here's my modified code:
I ran all of the tests, and all of them pass except validateRelativizingPaths in FileSystemUtilitiesTest. That test calls relativize with path set to
/project/backend/foobar/my-schema.xsd
with various values of parentDir. Two of the five verifications there fail, these ones:In both cases, the tests fail because the specified expected result in the test isn't actually a correct relative path from the parentDir to the path. In the first one, it passes in "" as the parentDir, which the test then passes to relativize as
new File("")
. So the actual parent path passed to the method isn't "" but is the jaxb2-maven-plugin project directory, and "project/backend/foobar/my-schema.xsd" isn't the correct relative path from the plugin project directory. The problem in the /not/a/path case is the same -- the indicated expected relativized path from /not/a/path to /project/backend/foobar/my-schema.xsd isn't project/backend/foobar/my-schema.xsd but would be ../../../project/backend/foobar/my-schema.xsd.But, the javadoc says that when the path isn't a child of parentDir, just return the path argument as-is rather than returning a relative path, and the code seems to work correctly with my modified code that does that. All of the tests passed including all of the integration tests after I retrained those two cases to be these:
It would be great if this could be fixed and released as a 2.5.1 update, since I can't yet use the 3.1.0 release that relies on the jakarta classes.
The text was updated successfully, but these errors were encountered: