Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MNG-6437] Better support for path and uri in property interpolation #812

Merged
merged 4 commits into from Oct 17, 2023

Conversation

gnodet
Copy link
Contributor

@gnodet gnodet commented Oct 5, 2022

See #808

Copy link
Member

@michael-o michael-o left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yet another problem with URIs is to get a decent string representation URI#toString() is not suited since it does not encode unsafe characters. Can this address this problem to invoke URI#toASCIIString() instead?

@gnodet
Copy link
Contributor Author

gnodet commented Oct 9, 2022

Yet another problem with URIs is to get a decent string representation URI#toString() is not suited since it does not encode unsafe characters. Can this address this problem to invoke URI#toASCIIString() instead?

${session.multiModuleProjectDirectory.uri} returns a URI object. If you interpolate it, the toString() method will be used by default. But one could also use ${session.multiModuleProjectDirectory.uri.ASCIIString} I think, as all toXxx methods are supported.
There may be a way to intercept URI -> String conversion, I'll look into it.

@gnodet
Copy link
Contributor Author

gnodet commented Oct 9, 2022

Yet another problem with URIs is to get a decent string representation URI#toString() is not suited since it does not encode unsafe characters. Can this address this problem to invoke URI#toASCIIString() instead?

${session.multiModuleProjectDirectory.uri} returns a URI object. If you interpolate it, the toString() method will be used by default. But one could also use ${session.multiModuleProjectDirectory.uri.aSCIIString} I think, as all toXxx methods are supported. There may be a way to intercept URI -> String conversion, I'll look into it.

Fwiw, injecting a URI into a String property is forbidden because of the following code:
https://github.com/apache/maven/blob/master/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4.java#L376-L387
This means that plugins need to be injected with a URI field or use an explicit conversion.

Also, I just discovered that Path.toUri() is actually different than Path.toFile().toURI() as Path.toUri() actually encodes the path, so that the URI.toString() will actually return an encoded uri, i.e. the same as URI.toASCIIString():

Paths.get( "rép➜α" ).toUri().toString() -> "file:///Users/gnodet/work/git/maven4/maven-core/re%CC%81p%E2%9E%9C%CE%B1"
Paths.get( "rép➜α" ).toFile().toURI().toASCIIString() -> "file:///Users/gnodet/work/git/maven4/maven-core/re%CC%81p%E2%9E%9C%CE%B1"
Paths.get( "rép➜α" ).toFile().toURI().toString() -> "file:/Users/gnodet/work/git/maven4/maven-core/rép➜α"

In short, there's no need to go through the toASCIIString() method from a Path.

However, this PR only tackles plugin injection and not model interpolation. The toXxx and asXxx are currently not supported during interpolation. For this to work, the original plexus ReflectionValueExtractor would have to be modified instead of being copied/modified like in this PR.

@gnodet
Copy link
Contributor Author

gnodet commented Oct 9, 2022

As shown by the tests failing on windows, my assumption that Path.toUri().toString() and Path.toUri().toASCIIString() are the same (i.e. the uri path is already encoded) seems only valid on unix platforms and not on windows...

@michael-o
Copy link
Member

As shown by the tests failing on windows, my assumption that Path.toUri().toString() and Path.toUri().toASCIIString() are the same (i.e. the uri path is already encoded) seems only valid on unix platforms and not on windows...

Let me try to replicate, that is total BS.

Method method = classMap.findMethod(prefix + methodBase);
if (method != null) {
return method.invoke(value, OBJECT_ARGS);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be a separate, preceding PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, that's one of the important change to support toXxx and asXxx.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know, but can be logically done before this change, no? But anyway, let's leave this hunk as-is.

@gnodet
Copy link
Contributor Author

gnodet commented Sep 22, 2023

@michael-o fancy another look ?

@michael-o
Copy link
Member

Well, built your branch and tested on:

osipovmi@deblndw011x:/tmp/ма вен (MNG-6437 =)
$ ../apache-maven-4.0.0-alpha-8-SNAPSHOT/bin/mvn -v
Apache Maven 4.0.0-alpha-8-SNAPSHOT (521a57d768f1aab6dc792ee1a234c9b70267f3a2)
Maven home: /tmp/apache-maven-4.0.0-alpha-8-SNAPSHOT
Java version: 1.8.0_372, vendor: OpenJDK BSD Porting Team, runtime: /usr/local/openjdk8/jre
Default locale: de_DE, platform encoding: UTF-8
OS name: "freebsd", version: "12.4-stable", arch: "amd64", family: "unix"

It fails in mid-air:

[ERROR] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.041 s <<< FAILURE! -- in org.apache.maven.model.building.DefaultModelBuilderTest
[ERROR] org.apache.maven.model.building.DefaultModelBuilderTest.testBuildRawModel -- Time elapsed: 0.005 s <<< FAILURE!
org.opentest4j.AssertionFailedError: expected: not <null>
        at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:152)
        at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
        at org.junit.jupiter.api.AssertNotNull.failNull(AssertNotNull.java:49)
        at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:35)
        at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:30)
        at org.junit.jupiter.api.Assertions.assertNotNull(Assertions.java:301)
        at org.apache.maven.model.building.DefaultModelBuilderTest.testBuildRawModel(DefaultModelBuilderTest.java:164)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727)
        at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
        at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
        at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
        at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
        at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
        at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)

I have tried help:evaluate, but all I get is null. I have found another issue: if an object contains #isFile() and #toFile(), the array will determine which to call.

See:

[INFO] Enter the Maven expression i.e. ${project.groupId} or 0 to exit?:
${session.multiModuleProjectDirectory.uri}
[INFO]
null object or invalid expression
[INFO] Enter the Maven expression i.e. ${project.groupId} or 0 to exit?:
${session.multiModuleProjectDirectory.uri.string}

What am I doing wrong?

@gnodet
Copy link
Contributor Author

gnodet commented Sep 22, 2023

Well, built your branch and tested on:

osipovmi@deblndw011x:/tmp/ма вен (MNG-6437 =)
$ ../apache-maven-4.0.0-alpha-8-SNAPSHOT/bin/mvn -v
Apache Maven 4.0.0-alpha-8-SNAPSHOT (521a57d768f1aab6dc792ee1a234c9b70267f3a2)
Maven home: /tmp/apache-maven-4.0.0-alpha-8-SNAPSHOT
Java version: 1.8.0_372, vendor: OpenJDK BSD Porting Team, runtime: /usr/local/openjdk8/jre
Default locale: de_DE, platform encoding: UTF-8
OS name: "freebsd", version: "12.4-stable", arch: "amd64", family: "unix"

It fails in mid-air:

[ERROR] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.041 s <<< FAILURE! -- in org.apache.maven.model.building.DefaultModelBuilderTest
[ERROR] org.apache.maven.model.building.DefaultModelBuilderTest.testBuildRawModel -- Time elapsed: 0.005 s <<< FAILURE!
org.opentest4j.AssertionFailedError: expected: not <null>
        at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:152)
        at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
        at org.junit.jupiter.api.AssertNotNull.failNull(AssertNotNull.java:49)
        at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:35)
        at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:30)
        at org.junit.jupiter.api.Assertions.assertNotNull(Assertions.java:301)
        at org.apache.maven.model.building.DefaultModelBuilderTest.testBuildRawModel(DefaultModelBuilderTest.java:164)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727)
        at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
        at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
        at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
        at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
        at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
        at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)

I have tried help:evaluate, but all I get is null. I have found another issue: if an object contains #isFile() and #toFile(), the array will determine which to call.

See:

[INFO] Enter the Maven expression i.e. ${project.groupId} or 0 to exit?:
${session.multiModuleProjectDirectory.uri}
[INFO]
null object or invalid expression
[INFO] Enter the Maven expression i.e. ${project.groupId} or 0 to exit?:
${session.multiModuleProjectDirectory.uri.string}

What am I doing wrong?

The PR only tackles plugin configuration injection, not model interpolation.
I'll see if/how that can be done...

@michael-o
Copy link
Member

Well, built your branch and tested on:

osipovmi@deblndw011x:/tmp/ма вен (MNG-6437 =)
$ ../apache-maven-4.0.0-alpha-8-SNAPSHOT/bin/mvn -v
Apache Maven 4.0.0-alpha-8-SNAPSHOT (521a57d768f1aab6dc792ee1a234c9b70267f3a2)
Maven home: /tmp/apache-maven-4.0.0-alpha-8-SNAPSHOT
Java version: 1.8.0_372, vendor: OpenJDK BSD Porting Team, runtime: /usr/local/openjdk8/jre
Default locale: de_DE, platform encoding: UTF-8
OS name: "freebsd", version: "12.4-stable", arch: "amd64", family: "unix"

It fails in mid-air:

[ERROR] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.041 s <<< FAILURE! -- in org.apache.maven.model.building.DefaultModelBuilderTest
[ERROR] org.apache.maven.model.building.DefaultModelBuilderTest.testBuildRawModel -- Time elapsed: 0.005 s <<< FAILURE!
org.opentest4j.AssertionFailedError: expected: not <null>
        at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:152)
        at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
        at org.junit.jupiter.api.AssertNotNull.failNull(AssertNotNull.java:49)
        at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:35)
        at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:30)
        at org.junit.jupiter.api.Assertions.assertNotNull(Assertions.java:301)
        at org.apache.maven.model.building.DefaultModelBuilderTest.testBuildRawModel(DefaultModelBuilderTest.java:164)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727)
        at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
        at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
        at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
        at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
        at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
        at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)

I have tried help:evaluate, but all I get is null. I have found another issue: if an object contains #isFile() and #toFile(), the array will determine which to call.
See:

[INFO] Enter the Maven expression i.e. ${project.groupId} or 0 to exit?:
${session.multiModuleProjectDirectory.uri}
[INFO]
null object or invalid expression
[INFO] Enter the Maven expression i.e. ${project.groupId} or 0 to exit?:
${session.multiModuleProjectDirectory.uri.string}

What am I doing wrong?

The PR only tackles plugin configuration injection, not model interpolation. I'll see if/how that can be done...

Darn, then I will retry next week.

@gnodet
Copy link
Contributor Author

gnodet commented Sep 22, 2023

What am I doing wrong?

The PR only tackles plugin configuration injection, not model interpolation. I'll see if/how that can be done...

Actually, this is not the problem. The problem is that the maven-help-plugin is using the PluginParameterExpressionEvaluator and not the PluginParameterExpressionEvaluatorV4. However, after also enhancing the PluginParameterExpressionEvaluator class, the next problem is that ${session.multiModuleProjectDirectory} only works on the v4 api, as the MavenSession does not have the multiModuleProjectDirectory, which is deprecated.
After fixing everything that, I do have

[INFO] Enter the Maven expression i.e. ${project.groupId} or 0 to exit?:
${session.rootDirectory.uri}
[INFO] 
<uri>file:///Users/gnodet/work/git/maven/</uri>

@michael-o
Copy link
Member

I will take a good at it again next week, thanks for the hard work @gnodet.

@gnodet gnodet merged commit 92a82dc into apache:master Oct 17, 2023
18 checks passed
@gnodet gnodet deleted the MNG-6437 branch October 18, 2023 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants