Bug 529435 - [launch] Deprecation of of getClasspath and instead getClasspathAndModulepath to be used in LaunchDelegate
Summary: [launch] Deprecation of of getClasspath and instead getClasspathAndModulepath...
Status: REOPENED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Debug (show other bugs)
Version: 4.8   Edit
Hardware: PC Windows 7
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Sarika Sinha CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords:
Depends on:
Blocks:
 
Reported: 2018-01-05 01:33 EST by Sarika Sinha CLA
Modified: 2022-06-07 15:43 EDT (History)
8 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sarika Sinha CLA 2018-01-05 01:33:43 EST
After Bug 525948 and Bug 522333, Launching needs to come up with a wiki/guideline for adopters to follow the rules to support their launch configuration for Java 9.

Now thinking about generalizing, currently launcher is calling getClasspath() to get classpath and getClasspathAndModulepath to get the modulepath which is totally unnecessary as getClasspathAndModulepath gives both. I think we can have a constant to define if getClasspathAndModulepath can be used for both. 
This is beacuse of the various ways of combination of inheritance. Like Junit has it's own launch delegate and getClasspath but it was calling super.getClasspath where as m2e uses JavaLaunchDelegate but has a totally overridden getClasspath and PDE again has a different combination. Because of m2e failures we had to continue using getClasspath Bug 522333.
So for a launch Configuration, suppose IJavaLaunchConfigurationConstants.ATTR_USE_CLASSPATH_AND_MODULEPATH is set to true, Java launcher can use getClasspathAndModule path only. if false it can use getClasspath.
Comment 1 Sarika Sinha CLA 2018-01-17 23:09:36 EST
I am planning to do this early M6, any objections ?
Comment 2 Sarika Sinha CLA 2018-03-01 03:20:36 EST
Looking at JUnit and Maven Implementation (org.eclipse.m2e.internal.launch.MavenLaunchDelegate)

Rather than introducing a new attribute and make things complicated I think it will be better to @Deprecate getClasspath() method so that slowly people start moving to getClasspathAndModulepath()
Comment 3 Sarika Sinha CLA 2018-03-05 03:27:50 EST
Will do it in Early 4.9
Comment 4 Eclipse Genie CLA 2019-01-11 05:00:28 EST
New Gerrit change created: https://git.eclipse.org/r/134950
Comment 5 Christian Dietrich CLA 2019-01-11 05:24:41 EST
created https://github.com/eclipse/mwe/issues/60 to address deprecation in MWE
Comment 6 Dani Megert CLA 2019-01-11 05:25:15 EST
Please also add it to the porting guide.
Comment 8 Sarika Sinha CLA 2019-01-17 23:16:03 EST
Will resolve after updating Porting guide.
Comment 9 Dani Megert CLA 2019-01-29 11:17:03 EST
Increasing the minor version was wrong. There was no API addition. Unfortunately we can't change the version back, so please add an API Tools filter to get rid of the error.

NOTE: It is now visible as an error since I changed the project settings.
Comment 10 Eclipse Genie CLA 2019-01-30 10:45:12 EST
New Gerrit change created: https://git.eclipse.org/r/136024
Comment 12 Peter Kriens CLA 2019-02-11 09:15:31 EST
This change breaks bndtools since the classpath entries for the project are not by definition the same as the ones we need for launching.

I find this a very inelegant solution for what is only a unmeasurable small performance improvement.

Sadly, I need to support old Eclipse's and new Eclipses and I do not see a clean way to support both without keeping getClasspath()
Comment 13 Sarika Sinha CLA 2019-02-11 23:48:56 EST
(In reply to Peter Kriens from comment #12)
> This change breaks bndtools since the classpath entries for the project are
> not by definition the same as the ones we need for launching.
> 
> I find this a very inelegant solution for what is only a unmeasurable small
> performance improvement.
> 
> Sadly, I need to support old Eclipse's and new Eclipses and I do not see a
> clean way to support both without keeping getClasspath()

Performance has a big impact in big workspaces with Projects having a lot of dependencies. With Java 9 breaking changes, we are not left with many options.
Comment 14 Peter Kriens CLA 2019-02-12 06:38:44 EST
It used to be first correct, then performance. This is a breaking change of public API. I do not think it is correct to make such breaking changes in a point release?

You could let the getClasspath() return  an empty array. Then call it from getClasspathAndModulePath if it is non-empty, use the single loop to extract the module path and classpath.

Anyway, breaking performance improvements should at least have some metrics to show that they actually improve performance? In this case, I've serious doubts it can be measured even for very large builds. The iteration is over a list of at a low number of entries (between 10-100) that are in memory.
Comment 15 Sarika Sinha CLA 2019-02-12 06:50:47 EST
(In reply to Peter Kriens from comment #14)
> It used to be first correct, then performance. This is a breaking change of
> public API. I do not think it is correct to make such breaking changes in a
> point release?
> 
> You could let the getClasspath() return  an empty array. Then call it from
> getClasspathAndModulePath if it is non-empty, use the single loop to extract
> the module path and classpath.
> 
> Anyway, breaking performance improvements should at least have some metrics
> to show that they actually improve performance? In this case, I've serious
> doubts it can be measured even for very large builds. The iteration is over
> a list of at a low number of entries (between 10-100) that are in memory.

The implementations of this and the Launch Delegates are very different in all the implementors like maven JDT UI, PDE etc. 

It might actually return a valid empty list so we can assume based on that.
And beyond java 8 getClasspath() will be incorrect without modulepath.
Comment 16 Till Brychcy CLA 2019-02-12 07:58:24 EST
Shouldn't org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate.supportsModule
return false by default, and subclasses that are moduleaware would override it
and return true?

Then org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate.getClasspathAndModulepath could check this and if it returns false invoke org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate.getClasspath
Comment 17 Sarika Sinha CLA 2019-02-12 08:28:11 EST
(In reply to Till Brychcy from comment #16)
> Shouldn't
> org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate.
> supportsModule
> return false by default, and subclasses that are moduleaware would override
> it
> and return true?
> 
> Then
> org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate.
> getClasspathAndModulepath could check this and if it returns false invoke
> org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate.
> getClasspath

Ideally yes, but the problem is the combination state like now, where Ant, JUnit and PDE have not supported it yet but sometime they just use (rather than overriding) the default Java one which supports, so we cannot rely on that as well.
Comment 18 Till Brychcy CLA 2019-02-12 08:44:00 EST
(In reply to Sarika Sinha from comment #17)
> (In reply to Till Brychcy from comment #16)
> > Shouldn't
> > org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate.
> > supportsModule
> > return false by default, and subclasses that are moduleaware would override
> > it
> > and return true?
> > 
> > Then
> > org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate.
> > getClasspathAndModulepath could check this and if it returns false invoke
> > org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate.
> > getClasspath
> 
> Ideally yes, but the problem is the combination state like now, where Ant,
> JUnit and PDE have not supported it yet but sometime they just use (rather
> than overriding) the default Java one which supports, so we cannot rely on
> that as well.

Another idea: maybe a check could be done in getClasspathAndModulepath whether the concrete instance class has overridden getClasspath but not getClasspathAndModulepath and use the getClasspath result in this case.
Comment 19 Sarika Sinha CLA 2019-02-12 09:00:57 EST
(In reply to Till Brychcy from comment #18)
> 
> Another idea: maybe a check could be done in getClasspathAndModulepath
> whether the concrete instance class has overridden getClasspath but not
> getClasspathAndModulepath and use the getClasspath result in this case.

Do we have a way other than reflection to find it out?
Comment 20 Till Brychcy CLA 2019-02-12 09:08:53 EST
(In reply to Sarika Sinha from comment #19)
> (In reply to Till Brychcy from comment #18)
> > 
> > Another idea: maybe a check could be done in getClasspathAndModulepath
> > whether the concrete instance class has overridden getClasspath but not
> > getClasspathAndModulepath and use the getClasspath result in this case.
> 
> Do we have a way other than reflection to find it out?

I don't think so. But is there any problem with that?

Maybe this could be done in the body of the default supportsModule() implementation - I don't really expect anybody to explicitly override it to return false (rather than implement module support). But existing and new classes that do support modules could override it to explicitly return true to skip the reflection based check.
Then getClasspathAndModulepath could check supportsModule as written above.
Comment 21 Sarika Sinha CLA 2019-02-13 03:22:35 EST
We did think about this previously but rejected because of reflection.
Comment 22 Till Brychcy CLA 2019-02-13 03:44:45 EST
(In reply to Sarika Sinha from comment #21)
> We did think about this previously but rejected because of reflection.

And using reflection is worse than breaking the API?
Comment 23 Sarika Sinha CLA 2019-02-13 03:52:05 EST
(In reply to Till Brychcy from comment #22)
> (In reply to Sarika Sinha from comment #21)
> > We did think about this previously but rejected because of reflection.
> 
> And using reflection is worse than breaking the API?

No, but because the user has to finally add getClasspathAndModulepath with Java 9 onward and it will give just an interim relief with reflection.
Comment 24 Till Brychcy CLA 2019-02-13 04:02:54 EST
(In reply to Sarika Sinha from comment #23)
> No, but because the user has to finally add getClasspathAndModulepath with
> Java 9 onward and it will give just an interim relief with reflection.

That is true, but many users still do use java 8 and with this change:

https://git.eclipse.org/r/#/c/134950/2/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaLaunchDelegate.java

getClasspath is not called even when the user uses Java 8 or earlier, so old implementations that used to work with java 8 are broken.

Or am I overlooking something?
Comment 25 Dani Megert CLA 2019-02-13 08:39:34 EST
Sarika, this needs a fix. Reflection is not nice, so, if you can find another solution, e.g. by adding a new API, that would be preferred. But as a last resort you'll have to use reflection in this particular case.
Comment 26 Eclipse Genie CLA 2019-02-15 06:26:06 EST
New Gerrit change created: https://git.eclipse.org/r/136998
Comment 27 Sarika Sinha CLA 2019-02-15 06:27:25 EST
(In reply to Dani Megert from comment #25)
> Sarika, this needs a fix. Reflection is not nice, so, if you can find
> another solution, e.g. by adding a new API, that would be preferred. But as
> a last resort you'll have to use reflection in this particular case.

API will not help here, Using reflection and use the getClasspathAndModulepath if found else use the deprecated getClasspath method.
Comment 29 Till Brychcy CLA 2019-02-18 02:35:52 EST
I've just looked at the patch but not tried it, but I don't understand how it works.
Just invoking getMethod should always return a non-null result for both methods (namely the implementations in AbstractJavaLaunchConfigurationDelegate.

So I'd expect a check if java.lang.reflect.Method.getDeclaringClass() for "getClasspathAndModulepath" is AbstractJavaLaunchConfigurationDelegate.class but the result for "getClasspath" is not.
Comment 30 Till Brychcy CLA 2019-02-18 02:44:08 EST
Reopening, see Comment 29
Comment 31 Eclipse Genie CLA 2019-02-18 02:57:29 EST
New Gerrit change created: https://git.eclipse.org/r/137107
Comment 32 Sarika Sinha CLA 2019-02-18 03:06:28 EST
(In reply to Till Brychcy from comment #29)
> I've just looked at the patch but not tried it, but I don't understand how
> it works.
> Just invoking getMethod should always return a non-null result for both
> methods (namely the implementations in
> AbstractJavaLaunchConfigurationDelegate.
> 
> So I'd expect a check if java.lang.reflect.Method.getDeclaringClass() for
> "getClasspathAndModulepath" is AbstractJavaLaunchConfigurationDelegate.class
> but the result for "getClasspath" is not.

I don't think we can even rely on that.

If we want to support getClasspath, Let us use the deprecated method till Java 8 is sunset and the remove it then and only use getClasspathAndModulepath after Java 8.

Is it ok?
Comment 33 Till Brychcy CLA 2019-02-18 03:41:28 EST
(In reply to Sarika Sinha from comment #32)
> > So I'd expect a check if java.lang.reflect.Method.getDeclaringClass() for
> > "getClasspathAndModulepath" is AbstractJavaLaunchConfigurationDelegate.class
> > but the result for "getClasspath" is not.
> 
> I don't think we can even rely on that.

You mean in case somebody has subclassed a subclass that gets upgraded to implement both? Not sure if this really an issue. But a more paranoid solution would be to simply check if the declaring class of getClasspath is the same as the declaring class of getClasspathAndModulepath and if not, use getClasspath. Disadvantage is that subclasses will have to continue overriding "getClasspath" to trigger usage of the new method.

> 
> If we want to support getClasspath, Let us use the deprecated method till
> Java 8 is sunset and the remove it then and only use
> getClasspathAndModulepath after Java 8.

Unfortunately Java 9 broke too much old code, so I expect Java 8 to be used for a very long time (even if Oracle stops supporting it, others will).

Maybe a compromise would be to always use "getClasspath" if the actual runtime is Java 8 or older and getClasspathAndModulepath if it is Java 9 or newer.
Comment 34 Eclipse Genie CLA 2019-02-18 04:01:44 EST
New Gerrit change created: https://git.eclipse.org/r/137112
Comment 35 Sarika Sinha CLA 2019-02-18 04:09:34 EST
We can run with java 9 without having any modulepath definition like we do in Ant also, so can't rely on that as well.

For 4.11 I think it is better to go  by using both methods approach and then decide in 4.12.
Comment 37 Sarika Sinha CLA 2019-05-17 05:37:20 EDT
Moving to 4.13.
Comment 38 Sarika Sinha CLA 2019-11-19 00:53:18 EST
Hopefully, will be able to take this up soon.
Comment 39 Sarika Sinha CLA 2020-01-05 23:58:46 EST
I have not been able to derive a good solution for this.
Comment 40 Eclipse Genie CLA 2022-06-07 15:43:04 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.