This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 215544 - Find Usages should never use version as a match criteria, it should find matches based on the Java specification, not on the maven dependency resolution scheme.
Summary: Find Usages should never use version as a match criteria, it should find matc...
Status: RESOLVED WONTFIX
Alias: None
Product: java
Classification: Unclassified
Component: Refactoring (show other bugs)
Version: 7.3
Hardware: PC Linux
: P3 normal (vote)
Assignee: Ralph Ruijs
URL:
Keywords: REGRESSION
Depends on:
Blocks:
 
Reported: 2012-07-14 15:40 UTC by myshkin
Modified: 2013-06-04 12:35 UTC (History)
3 users (show)

See Also:
Issue Type: DEFECT
Exception Reporter:


Attachments
Test Case (1.73 KB, application/x-gzip)
2012-07-14 15:43 UTC, myshkin
Details
2nd set of test cases showing failure to find usages needed to compile (11.07 KB, application/octet-stream)
2013-01-21 19:35 UTC, myshkin
Details

Note You need to log in before you can comment on or make changes to this bug.
Description myshkin 2012-07-14 15:40:32 UTC
Product Version = NetBeans IDE 7.2 Beta (Build 201205031832)
Operating System = Linux version 3.2.0-25-generic-pae running on i386
Java; VM; Vendor = 1.7.0_04
Runtime = Java HotSpot(TM) Client VM 23.0-b21

Use Case:  If a developer has a library maven project open, and performs a maven release (updating the artifact version), Find Usages should not return different (empty) results from before the release.

If I have a maven project called Project-A and do a find usages on a class in that project, it will only find usages in other open maven projects if they have a declared dependency on that artifact, and have the same version.

I have attached a test case with 5 projects:
Project-A: Is at version 1.0-SNAPSHOT contains com.mycompany.projecta.App

The other 4 projects all use com.mycompany.projecta.App in the exact same way
Project-B: declares a dependency on Project-A version 1.0-SNAPSHOT
Project-BeforeVersion: declares a dependency on Project-A version 0.9-SNAPSHOT
Project-AfterVersion: declares a dependency on Project-A version 1.1-SNAPSHOT
Project-NoDep: has no declared dependency on Project-A.

Find Usages only returns a match for Project-B, but should return a match for all 4 projects.
Comment 1 myshkin 2012-07-14 15:43:01 UTC
Created attachment 122025 [details]
Test Case
Comment 2 Milos Kleint 2012-07-17 09:32:20 UTC
appears to be invalid to me.

by having a different version in the dependency, you are effectively using a different binary. So the shown results are those that in fact use the type from the given binary and not those that use a different type from elsewhere that only has the same name as the one in question.
Comment 3 myshkin 2012-07-17 19:01:13 UTC
The binary release is actually just one usage of a class. In fact a specific version of the class may  be used in multiple binary artifact releases.  I can see far more uses for returning all of the binaries packaging the class than I can see uses of searching for uses of the class as packaged in a particular binary 

Maven is a big help, but it is not the entire universe. There are concerns that transcend a specific version, as well as workflow issues and diagnostic activities that need to query more than a specific version. If I have 20 projects that depend on a library, I shouldn't have to modify the version in the Pom just to be able to find out if they reference a class.  I also shouldn't have to check out different versions of the library just to find usages.

Another aspect not considered is major and minor releases. If a released version of an application uses a specific release of a library, there is the potential that it could also be used with other minor releases of the library at runtime.  So, the maven dependency is far from sacrosanct. 
Or what about different versions referenced in different profiles, or properties files?  

There is also a major functional disconnect between the artifact version, and the class version.  If a class doesn't change over a dozen different artifact releases, is it really a dozen different classes that each have separate usages?  

And, there is no reason given for why the final test case fails.  If there is no maven dependency declared, but it still uses the class, it should be found. 

Suppressing matches like this is extremely confusing and generates unpredictable results.  When I search for usages of a class, that is what I want to search for, not the class as it may be compiled and packaged and versioned should the Pom file stay the way it happens to be at the moment. 


(In reply to comment #2)
> appears to be invalid to me.
> 
> by having a different version in the dependency, you are effectively using a
> different binary. So the shown results are those that in fact use the type from
> the given binary and not those that use a different type from elsewhere that
> only has the same name as the one in question.
Comment 4 myshkin 2012-07-19 00:25:19 UTC
Just to clarify the poorly put together first paragraph in my prior message:

I can see more utility in searching the different versions of the artifact for references to the class than I can see uses for searching for usage of a single packaging of the class.
Comment 5 Milos Kleint 2013-01-10 13:05:57 UTC
according to jbecicka current behaviour works as intended, at some point in the past we were showing non-exact matches for selected type, but that was later considered a bug. 

Consider the case of Find usages across these 5 projects versus a Rename refactoring that changes a method signature, only the usages specific to the exact version have to be changed, nothing else. Changing other usage would result in broken sources, compilation errors.
Comment 6 myshkin 2013-01-13 14:09:36 UTC
(In reply to comment #5)
> according to jbecicka current behaviour works as intended, at some point in the
> past we were showing non-exact matches for selected type, but that was later
> considered a bug. 

That makes this a regression, not invalid.  I can understand how this new behavior may seem like a 'feature' at first glance, but in general it just serves as a source of surprising behavior.  When I ask netbeans to find usages, and I am explicitly asking it to find usages in 'SCOPE: OPEN PROJECTS' that is what I expect netbeans to do.  If there was a scope for maven dependencies, then the current functionality would be appropriate.
 
> Consider the case of Find usages across these 5 projects versus a Rename
> refactoring that changes a method signature, only the usages specific to the
> exact version have to be changed, nothing else. Changing other usage would
> result in broken sources, compilation errors.

This is precisely the problem, there are different use cases, but only one solution that is very different from historic functionality, and completely silent about it.  THIS bug is about find usages, not refactoring.  

No matter the use case, silently excluding matches is never the right thing to do.  Explicitly calling out the version mismatch and allowing the user to choose to proceed without regard for the maven version numbers currently in the pom, exclude matches based on dependency version, or update the dependency with the maven version plugin would be much more civilized.
Comment 7 Jan Becicka 2013-01-14 08:56:16 UTC
> 
> This is precisely the problem, there are different use cases, but only one
> solution that is very different from historic functionality, and completely
> silent about it.  THIS bug is about find usages, not refactoring.  

Let's clarify what the usage is and what is not (according NetBeans).
Let me ask you a question:
What happens, if you delete for instance method "a" in 1.0-SNAPSHOT, which usages are you looking for. Method "a" usages (in the NetBeans IDE) are all those places, where compilation fails...
Comment 8 myshkin 2013-01-19 17:35:03 UTC
> > This is precisely the problem, there are different use cases, but only one
> > solution that is very different from historic functionality, and completely
> > silent about it.  THIS bug is about find usages, not refactoring.  
> Let's clarify what the usage is and what is not (according NetBeans).
> Let me ask you a question:
> What happens, if you delete for instance method "a" in 1.0-SNAPSHOT, which usages are you looking for. Method "a" usages (in the NetBeans IDE) are all those places, where compilation fails...


*** I think refactoring keeps being brought into the question, which has a less clear answer.  I think with find usages, when you are selecting the Open Projects scope, the answer is straight forward. ***

When it comes to deleting method 'a', I am looking for all the usages of method 'a' in the currently open projects.  I guess I don't even understand what the alternative to searching open projects would be.  Would it go refactor repository artifacts, or projects that were _not_ open in netbeans?  Or is this functionality that is only useful if you have multiple versions of the same project open at the same time?  

What is the delete method 'a' workflow if you are blindly following pom version relationships?
  *) You search for usages and find some in the repository artifacts.  What good is that?  You can continue, and your build is broken, and the IDE has provided zero assistance.  Or, cancel and stop what you are doing to go figure out dependencies so you can continue with your refactor, also with zero assistance from the IDE.  What you want to do is find that method in an open project, so you can see how its used, and how the consumer might be changed.
  *) if method 'a' doesn't exist in the repository artifact for 1.0-SNAPSHOT, would you find any usages?  Or do you take into account what projects will have the non-repository build of the artifact in their reactor.  That's the only way to achieve the compilation goal, and how many users will find that intuitive?
  *) What about dependency managed projects.  If you have project 'b' using method 'a' with a dependency on 0.9 what happens if project 'c' comes along with a managed dependency on 1.0-SNAPSHOT?

I suspect that the design goal of preventing compilation failure is well intentioned, but it is having the effect of artificially restricting the programming process to maintaining build meta-data instead of enhancing your ability to work with your classes and sources.  While I am editing source code, it is going to go from compilable to uncompilable hundreds of times a day.  I don't think the question is one of compilability per-se, but one of predictability and intent.  For a long time, I had just assumed that this was related to some buggy behavior I had seen with the Go to Type/File dialogs that happened after netbeans had been open for a long time, and was running out of memory.

The ultimate behavior is that the IDE helps you and provides valuable contextual information.  When I search for usages, first and foremost, I want to find all usages of the source artifact and then additional context would be *how* that particular source artifact is being used in the pom dependency hierarchies that netbeans knows about.  The same is true with regards to refactoring.  I want to see the complete set of matches for the source artifact and have that list enhanced with context about the dependency relationships.

One concept that I think is critical to respect is that of a class, or method being a first class entity that exists and evolves through many, many different pom releases.  When I program, I am building classes and implementing methods.  Pom versions and jars and maven artifacts are just individual snapshots of some specific collection of these classes.  While I am editing my classes, nothing could be further from my mind than the pom file, I don't even have it open, I'm not even looking at it.  If the IDE can add that information to my searches, or the work I am doing, that is great, but if the IDE starts hiding the classes and methods I'm trying to work on because I haven't gone through and changed how I want to make snapshots and builds, it is getting in the way.  Until I have found all the usages, and how they relate, I may not even have enough information to determine how the dependencies *should* be.
Comment 9 Ralph Ruijs 2013-01-20 19:20:10 UTC
(In reply to comment #7)
> > 
> > This is precisely the problem, there are different use cases, but only one
> > solution that is very different from historic functionality, and completely
> > silent about it.  THIS bug is about find usages, not refactoring.  
> 
> Let's clarify what the usage is and what is not (according NetBeans).
> Let me ask you a question:
> What happens, if you delete for instance method "a" in 1.0-SNAPSHOT, which
> usages are you looking for. Method "a" usages (in the NetBeans IDE) are all
> those places, where compilation fails...

I think this is correct for most module systems, but sadly maven is not that strict.

When declaring a "normal" version such as 3.8.2 for Junit, internally this is represented as "allow anything, but prefer 3.8.2." [1]

So, unless there is a dependency range specified, I do agree with myshkin that this is a bug.



[1] http://www.sonatype.com/books/mvnref-book/reference/pom-relationships-sect-project-dependencies.html#ex-dep-range-2
Comment 10 Milos Kleint 2013-01-20 19:37:31 UTC
(In reply to comment #9)
> (In reply to comment #7)
> I think this is correct for most module systems, but sadly maven is not that
> strict.
> 
> When declaring a "normal" version such as 3.8.2 for Junit, internally this is
> represented as "allow anything, but prefer 3.8.2." [1]
> 

not really everything,  3.8.2 basically mean 3.8.2 or bigger, equivalent to [3.8.2,) when declared as range.


> So, unless there is a dependency range specified, I do agree with myshkin that
> this is a bug.
> 

that's just theoretical. Multiple artifacts within the build state their dependency version ranges but then exactly one is specified. That's the one you use, the one that gets resolved from the dependency tree. Direct dependencies win. So the range movement only occurs for transitive dependencies. I cannot find the place in the book or docs but the users are encouraged to always declare dependencies they compile against (maven-enforcer plugin maybe checks that or maven-dependencies plugin)

Please note that maven itself will only download the pom files for potencial other version of the given library (maybe) but never the actual binary. 

My previous analysis stands, surely not implementable in maven support, maybe in refactoring as option.. If not, please close as wontfix
Comment 11 Ralph Ruijs 2013-01-20 19:49:04 UTC
(In reply to comment #10)
> My previous analysis stands, surely not implementable in maven support, maybe
> in refactoring as option.. If not, please close as wontfix

Not implementable, closing as wontfix.
Comment 12 myshkin 2013-01-21 15:39:20 UTC
What is not implementable about restoring past behavior?

If I search for uses of class com.example.Foo in 'Currently Open Projects', and it can't find uses *because of* the maven artifact versions, that is a bug.  A class is more than a build artifact, and its life-cycle extends beyond that of a single build.
Comment 13 myshkin 2013-01-21 19:35:41 UTC
I've attached another set of test case that showcases just how fragile find usages has become because of this bug.

Here are 2 simple cases where classes are being used by maven at build time but find usages fails to find them. 

First and simplest is a simple systemPath dependency.  This has always worked in the past, what compelling reason is there that it should become broken now?
Second is a very simple DependencyManagement declaration.

These are very simple cases.  I never use systemPaths, but I don't find that a convincing reason why they should remain broken.
The dep mgmt example is simpler than any real-life multi-module project I've come across.

How should this work if you have version numbers as properties set from the environement?  Or different dependency versions in different profiles?
What about poms that use maven-invoker-plugin to run builds with different dependency profiles enabled?

Why should basic IDE features stop working now for anyone who is leveraging any of this core functionality?
Comment 14 myshkin 2013-01-21 19:35:44 UTC
Created attachment 130467 [details]
2nd set of test cases showing failure to find usages needed to compile
Comment 15 myshkin 2013-01-21 20:12:16 UTC
Another odd behavior exhibited in this test case.

After building and installing all the projects in the test case, find usages on com.mycompany.projecta.App doesn't find its use in the open project DependsOnA1.1, but it does find it in the installed maven artifact.
Comment 16 myshkin 2013-01-24 15:34:44 UTC
How should dependencies in profiles that are activated by jdk version effect search scope?  Can I only find usages/refactor code for the jdk version I am using with my IDE?
How should dependencies in profiles that are activated by OS effect search scope?  Is the intended workflow that the developer get up from the mac and walk over to the windows box in order to find usages of the windows dependency, and then get up and go over to the linux box and find usages of the linux dependency?