tags:

views:

682

answers:

8

If I have a constant BAR in Foo, which I will use in a class C I'll have to write

Object o = Foo.BAR + "...";

which I can use Ctrl-Shift-M in Eclipse to create a static import for like:

import static Foo.BAR;

Object o = BAR + "....";

I am current updating legacy code with literaly thousands of these I'd like to convert to static imports. Ctrl-Shift-O / Organize imports does not do it. Is there a trick I've missed?


EDIT: Actually, what I would prefer is a way to tell Eclipse that I want to have Ctrl-Shift-M do its magic on ALL instances in this particular class instead of just the single instance I have the cursor placed at. (It is legacy code so this actually IMPROVES readability :) )

+5  A: 

One cautionary note: excessive use of static imports can actually make your code less readable (imho), particularly if the constant name doesn't clearly indicate the class or enum from which it belongs. You can also get constant names from different classes/enums that sound similar or even have the same name.

So what you're forcing the reader to do is hope his IDE will tell him the class (via, say, a tool tip) or they have to navigate to it to find out what it is. Printouts and code snippets become that much less reeadable.

Honestly I use static imports extremely rarely for these reasons.

cletus
I am aware of these things. In this particular case I have a keyholder class with key constants used everywhere - hence your concern is not an issue, rather the contrary :D
Thorbjørn Ravn Andersen
When the question is "how do I do this with static imports", I don't think that "don't use static imports" is an answer worth up-voting.
skaffman
Protecting people from well-intentioned but misguided ends is a time-honoured technique in answering questions.
cletus
I believe this is also the reason why the Pascal construction "with" is not a part of Java. You lose context.
Thorbjørn Ravn Andersen
@Thorbjørn Ravn Andersen: does that mean you don't gonna change this anymore? does cletus convinced you?
Tim Büthe
@Tim, no I was not convinced, but all other answers suggested running external programs which is _worse_...
Thorbjørn Ravn Andersen
+3  A: 

Regular expression was invented to solve problems like these! =)

you will need to write a small script (or use the IDE regex search/replace). The only problem is that if there are lots of classes that needs to be statically imported, then its just as much work. Otherwise, if its just one class like FOO.BLAH, then you can use a regex like

(\bFOO\.(\w+)\b) -> replace with group 2 ($2 or \2 or however your regex searcher does capture replaces).

you can try it here : http://www.gskinner.com/RegExr/ . Select the replace tab and type in $2

A problem might arise if you have expressions like this though: FOO f = FOO.blah + "FOO.blah" , so watch out for that.

As for the import statement at the top of the file, eclipse has an auto import feature where it does autoimport on format, and it works as long as the name of the import is unique enough. Or, if you cant use it because the name is too common, you can just use a perl script to do the regex instead, and prepend the static imports.

Chii
And now you have two problems ;-)
Robert Munteanu
Not using the refactoring tools inside Eclipse means that you disregard the knowledge that Eclipse has of your code, and only work on the textual representation of the raw source. Sigh.
Thorbjørn Ravn Andersen
Well, sometimes the refactoring you want to do isnt supported inside eclipse (although i feel this particular usecase you have here ought to be supported)
Chii
+3  A: 

I don't know any other automated refactorings to do what you're looking for, but there are two key aspects to doing this - one is adding the imports and the other is removing the class name from the constants.

For adding the imports, I recommend pasting import static application.KeyHolder.*; after the package on every file which uses them.

For removing the class name, in eclipse do a Java search for KeyHolder.* and search for a field. You can then do a find/replace for "KeyHolder." and replace with "". In order to prevent mismatches make sure the replaced item count is equal to the number of matches for that file. Also, make sure you search down and start after the imports.

deterb
If you import static application.KeyHolder.* and then press ctrl-shift-O that will convert your import to a number of lines, 1 for each constant you use in your code.
Jack
Actually it's a configurable option in eclispe. You can state the number of static imports you want before it uses a "star" import. I think the default is 8. I have lowered it to 3 for my use.
Pablojim
+1  A: 

If I were faced with such a challenge, I'd probably write a small program to do it for me. Ruby and Python (JRuby and Jython?) are pretty well suited for the task, although you could do it in Java too.

OK, so that'll probably take you at least the same amout of time as doing it by hand, but at least you'll be having fun :).

jqno
A: 

Well something which pops in as a solution. I would recommend using a simple groovy script. Basically the semantics are related to parsing the import statements and the files they refer to. Some basic steps could be like

  1. Recurse each file inside directory.Check whether the file extension is .java
  2. Match any line which starts with import
  3. For each such line open the relevant source file(you already know the path from the import statement).
  4. Match the field/method declaration for a static modifier using reflection
  5. Add static after the import statement for matches found in step 5.

If i get some time i will try and post a small groovy script for doing the same.

+1  A: 

Eclipse can do a global search and replace with regular expression over all files in the project.

To add the static import at the beginning of all files you could replace the package declaration by itself plus the static import.

Then do a project wide organize imports, and you're all set.

Be careful, though, this could also make a big mess if you do it wrong.

starblue
A: 

I don't know if it would fit your needs, but you can always have these constants defined in an interface and have all your classes just implement this interface. Then using some smart RegExp as others suggest you could get rid of all Foo. occurences.

Example:

public interface Foo {
   static final String constant1 = "Some";
   static final String constant2 = "Value";
   //...
}

And then

public class YourClass implements Foo {
   public YourClass() {
      System.out.println("Hello " + constant1);
   }
}
Grzegorz Oledzki
that would be a horrible way to code - do not create and implement interfaces just to access static final constants.
Chii
I know it. I was just following OP's idea. Thanks anyway.
Grzegorz Oledzki
+1  A: 

Sounds like a nice idea, but after you have changed all the files, how much better will they be? Perhaps you should think about only changing the files which you are working on for other reasons already.

Peter Lawrey