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

refactor(classloader): reduces to the maximum the use of classloaders #897

Merged
merged 1 commit into from
Nov 7, 2016

Conversation

monperrus
Copy link
Collaborator

should simplify debug when Maven classloaders, JDT classloaders, IDE classloaders
interplay.

throw new SpoonClassNotFoundException("cannot load class: " + getQualifiedName() + " with class loader "
+ Thread.currentThread().getContextClassLoader(), cnfe);
+ Thread.currentThread().getContextClassLoader(), e);
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't it misleading to say "with class loader " Thread.currentThread().getContextClassLoader()? This is not this one that is in cause in here, but rather the URLClassLoader with class paths. Shouldn't you better say "in class paths ...".

@tdurieux
Copy link
Collaborator

@monperrus Are you aware that this PR will broke Nopol and NPEFix?

@monperrus
Copy link
Collaborator Author

Then a test case is missing because nothing is broken currently.

@tdurieux
Copy link
Collaborator

How does a not merged pull request can currently broke two external projects?
Nopol and NPEFix use getClassloader(), no need of test the projects will not compile.

/**
* Sets the class loader used to compile/process the input source code.
*/
void setInputClassLoader(ClassLoader classLoader);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm a bit concerned about removing this method that I'm using. The idea is that when you embedded this Spoon as a third-party framework in another framework, you need a simple and direct way to instruct Spoon the class loader that you want to use and not bother about some complicated stuff with class paths and thread context class loader. So I would vote against removing this method.

@monperrus
Copy link
Collaborator Author

Hi Lionel,
Since there is no related test case, I don't see yet why this method is
essential and does not overlap with the sourceClassPath option.

Could you propose a test case showing the behavior you rely on?

@seintur
Copy link
Contributor

seintur commented Oct 19, 2016

Because not all class loader are sourceClassPath oriented. You can build a customer class loader that does at all rely on class paths. Building a test case for that is obvious: I want to be able to call setCallItWhateverYouWant(myCustomClassLoader) where myCustomClassLoader is an instance of class that extends ClassLoader (not URLClassLoader, neither something which is in relation with class paths).

@monperrus
Copy link
Collaborator Author

I understand your use case.

Bbut what the Spoon code does is then simply

Thread.currentThread().setContextClassLoader(myCustomClassLoader);

so to me, it looks more meaningful that you call this directly instead of an implicit, poorly documented and untested:

*.getEnvironment().setInputClassLoader(myCustomClassLoader)

Am I missing something?

--Martin

@seintur
Copy link
Contributor

seintur commented Oct 20, 2016

I agree that Thread.currentThread().setContextClassLoader(myCustomClassLoader) does the job. I just a bit concern about the fact that this "contract" (i.e. what to do when one wants to instruct Spoon to use a custom, non-classpath oriented, classloader) should be documented somewhere. setInputClassloader() was the easy obvious place for that: the developer that is embedding Spoon in her/his framework directly and easily bumps into the method when using code completion for instance. Now I have the feeling that this will be fuzzier to find this information. But when one knows... Just my €0.02.

@monperrus
Copy link
Collaborator Author

Basically, the contract with the Spoon-specific classloader is twofold:

  1. getTypeDeclaration uses it to build shadow classes

  2. JDT uses it it to compile.

With a classpath-based classloader (aka URLClassLoader) as supported by
addSourceClassPath/getClassLoader it works.

With a custom classloader, only 2) works easily. 1) is impossible
because JDT only accepts classpaths options.

So the only way to suport 1) and 2) with a custom class loader is to do
with Thread.currentThread().setContextClassLoader.

That said, we can do this in Spoon (+ documentation + test). But we
would still have only one method:

setClassLoader (instead of the current two setClassLoader and
setInputClassLoader)

OK for you ?

--Martin

@monperrus monperrus force-pushed the simpler-classloader branch 3 times, most recently from 9932cde to f0b698d Compare October 29, 2016 22:07
@monperrus monperrus force-pushed the simpler-classloader branch 5 times, most recently from 4f795b5 to bd6e987 Compare November 7, 2016 10:38
should simplify debug when Maven classloaders, JDT classloaders, IDE classloaders interplay.
@monperrus monperrus force-pushed the simpler-classloader branch from bd6e987 to 811f7a7 Compare November 7, 2016 10:45
@tdurieux tdurieux merged commit cd3d1f1 into INRIA:master Nov 7, 2016
@seintur
Copy link
Contributor

seintur commented Nov 9, 2016

Dear all,

I managed to get rid of setInputClassLoader in my projects that use Spoon. I no longer need to transmit any class loader to Spoon. So as far as I am concerned, this is ok for me to deprecate/remove this method.

Lionel.

@pvojtechovsky
Copy link
Collaborator

just one note to the class loader usage in spoon. The class loader is set thread locally and therefore influences all the code which is called in that thread later after setInputClassLoader is called. It can be quite dangerous, in some environments with pools of threads, etc. I do not know if it is the case how spoon will be used.
The design problem is that you can be never sure what classloader you are actually using. May be some method somewhere inside asks different classloader?
I just wanted to suggest to set class loaded always localy in scope of run of some functions

spoon.runWithClassLoader(()->{
//  only code  in scope of this function will use that class loader. 
//When we leave the function, then it should use origin class loader again.
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants