-
-
Notifications
You must be signed in to change notification settings - Fork 352
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
fix: more resilient wrt to errors during shadow class building #3655
Conversation
With the recent change you mean #3454 or? Could you provide an example where a shadow class can't be built? |
I can't reproduce it on the test yet =(( I'll show you one of the examples we already have. Let's have a look at the 'dspace' project. And we get the following:
When improting class, Spoon tries to intialize static context for this class as if code was launched with JVM at the 'dspace' app startup. This indicates the following:
Eventually, while doing static initialization, IllegalStateException arises -> thus ExceptionInInitializerError does as well. |
Added a test. At windows 10 I have a test pass. Not in CI. Sort it out. |
I added test that causes the problem of creating shadow class. If our importing class contains public static primitive field, we try to get its value through Reflection API mechanism. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for the test case (it's very important, we always specify bugs with test cases in Spoon).
It's better to avoid return null
(there are NPE time bombs).
What about using the null object design pattern here and returning a specific object that represents the failed class?
|
||
@Test | ||
public void testExpectedExceptionInInitializerError() { | ||
try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you add a comment "contract: ..." in natural language where you describe the intention of the test? Thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
Hi everyone! In JavaReflectionTreeBuilder#visitField(Field), I extended the exceptions that we can catch (up to Throwable). This way, we won't interrupt when creating a shadow class (we won't only set defaultExpression for public static primitive) In TypeFactory#get(Class), if by some reasons it's not possible to create a shadow class, a CtType with brief information on the package and the class name will be returned. In accordance with the edits, I changed the test. |
I looked through all the projects crashes caused by java.lang.reflect.Field.get() and found out the following exceptions: ExceptionInInitializerError, UnsatisfiedLinkError. Therefore, all the crashes for some reason will lead to logging and building stub classes in TypeFactory#get(Class) |
Thanks a lot. LGTM, will merge. |
Thanks a lot for your contribution. |
Hello everyone,
We develop a static code analyzer and to do it we need to build models using Spoon for a lot of projects.
Some background information.
This is how it was before:
JDTImportBuilder::getOrLoadClass tried to get imported class through getClass().getClassLoader().loadClass(className) ... it didn't manage to find anything ('null', ClassNotFoundException, ...).
This led to the situation when JDTImportBuilder::getOrLoadClass returned 'null'. We couldn't get it and that was OK.
This is how it is now:
Recently JDTImportBuilder::getOrLoadClass tries to load class using JDTImportBuilder::loadClass.
That is, if 'factory.getEnvironment().getInputClassLoader' existed, we tried to get it from there, otherwise we got class, same as before.
So through the factory environment you are able to get classes that, before the change, thrown with ClassNotFoundException.
But this modification led to the situation when TypeFactory::get(Class) couldn't get the shadowClass using JavaReflectionTreeBuilder (probably because reflection has not enough information). This leads to the SpoonClassNotFoundException exception that interrupts model building. Therefore we can't start the analysis niether.
There are a lot of reasons of program crash when launching JavaReflectionTreeBuilder:
PR details:
I added logging 'cannot create shadow class' (just in case).
I think, returning 'null' makes more sense, as it was before. If you couldn't get it, that's OK (alas, something's missing).