views:

291

answers:

5

I'm refactoring some Java code to be more decoupled by changing some static method calls to non-static calls, for example:

// Before:
DAO.doSomething(dataSource, arg1, ..., argN)

// After:
dao.doSomething(arg1, ..., argN)

My problem is that in a large project, it can be hard to find where static method calls are being made. Is there an easy way to do this, either from the command line or in Eclipse?

Such a tool would need to let me ignore "benign" static method calls such as these (either by not finding them in the first place, or by allowing them to be easily deleted from the search results):

String.valueOf(...)
Integer.parseInt(...)
MyClass.someBenignStaticMethod(...)

Some clarifications:

  • I'm not interested in finding method calls made via reflection
  • I don't know what static methods currently exist in this project, so it's not as simple as searching for their callers using Eclipse's "Open Call Hierarchy" command (Ctrl-Alt-H), although an easy way to search for non-private static methods would let me use this approach
  • I'm also interested in finding calls to static methods located outside my project, e.g. javax.mail.Transport#send
  • I'm looking for a free (as in beer) solution
+1  A: 

I'd use grep (-R on Linux) to search for initial caps-dot-camel case-open (I don't use it enough to give you the full command line). And then grep -v to get rid of some of the rubbish.

Well, really what I'd do is refactor incrementally. Changes a method, and see what breaks (if nothing breaks, delete the code).

Theoretically you could search through the class files looking for invokestatic. The FindBugs infrastructure would probably help out here (there may be better starting points).

Tom Hawtin - tackline
I considered FindBugs too, but presumably I would have to write my own checker module (or whatever their plugins are called)?
Andrew Swan
Yes. It's two and a half years since I've used it, but I think in this case it'll just be a implementing a couple visitor methods and registering the plugin.
Tom Hawtin - tackline
You'd want something like \b[A-Z][\w\.]+\.[a-z]\w+\(I think.
wds
+3  A: 

Do you really need to search? Why not comment out the static method calls one by one? When you compile it then it will flush out the references.

BrianLy
This works. However, when using an IDE, searching might be faster than recompiling for every method.
notnoop
This method could miss some call points if static methods are invoked reflectively.
Greg Mattes
Yes, but there is almost nothing static analysis do to detect reflection.
notnoop
I also want to find any calls made to methods outside my project, for example the infamous javax.mail.Transport#send methods. Also your answer suggests that I already know where the static methods are, so that I can comment them out in the first place.
Andrew Swan
I agree with this method. Reflection is an end-case which cannot be solved easily with any other method.
Yuval A
Reflection can usually be found statically by grepping for `"java.lang.reflect."` (and then eliminating it).
Tom Hawtin - tackline
+1  A: 

Some IDEs provide support for refactoring. You can refactor every static method one-by-one.

In Eclipse, you can view the call hierarchy to see all the callers of such method. To view the call hierarchy you can select the method name and press Command-Alt-H, or Right-Click on symbol and choose 'Open Call Hierarchy).

notnoop
The problem is that I don't know where the static method are. So your answer would first require me to search for them; I was hoping to search directly for the static method calls themselves, if possible, as it would be more direct.
Andrew Swan
+1  A: 

We have a product called nWire for Java which might just help. nWire analyzes your code and builds a database of your code components and associations. You can see a brief demo on our web site.

We plan to have reporting capabilities added in the future. In the mean while, if you have some basic experience with databases, you can tap into the nWire repository and, with a simple SQL query, get a list of all your static methods (you can also see the invocations there). nWire uses the H2 database engine which is open-source and free.

I can assist in accessing the database. Drop me a line to support [at] nwiresoftware.com.

zvikico
Thanks, but I'm looking for a non-commerical solution; I've updated the question accordingly.
Andrew Swan
Cool. Putting the price sticker on your time is up to you :-)
zvikico
A: 

I've written a small Java program that uses the excellent ASM library. It lets you exclude packages like java.lang, and produces output that looks like this:

+ java
  + io
    - File
      # createTempFile(java.lang.String, java.lang.String)
+ javax
  + imageio
    - ImageIO
      # read(java.io.InputStream)
      # write(java.awt.image.RenderedImage, java.lang.String, java.io.File)
  + mail
    - Transport
      # send(javax.mail.Message)
    + internet
      - InternetAddress
        # parse(java.lang.String, boolean)
  + xml
    + parsers
      - DocumentBuilderFactory
        # newInstance()

I'd prefer something that's more easily built into my existing build process, which uses CheckStyle, but this is the best solution I've come up with so far.

Andrew Swan