Automated and programmable refactoring in Java - java

I came across a task to internationalise the project which including the code (now 80% of the variable names are in Italian, which need to be changed to English). The translation part is fine, but how to find a way to refactor the code is driving me nuts. Almost every IDE in the market has such refactoring function, but none of them work automatically or programmably.
My question is, do they just use the regex to scan through all the files in the project and then refactor them or follow some sophisticated rules?

I have used a combination of JavaParser and another tool I forget the name of which allowed me to trace usages of all variables in classes from the compiled .class/.jar file.
The JavaParser is certainly a tool that could do the job. I will take a look tomorrow what the other componnet was. Could have been Class Dependency Analyser.

OP appears to want to do mass renaming.
While not the tool you might expect, you can use our Java obfuscator to achieve this.
This solution does mass renaming ignoring scopes, but I suspect that works fine for this.
Many source obfuscators take identifiers and scramble them in a consistent fashion. This means somewhere in the obfuscator, there is map from legacy identifiers to obfuscated identifiers, e.g., "foo" -> "bar" meaning "replace 'foo' by 'bar'".
Our obfuscator reads such a map before it starts (and that's the key to a solution). This map was presumably generated by a previous obfuscation step; reading and reusing such a map ensures that any incremental/additional obfuscation is done in the same way as as the original.
If what you do is run our obfuscator on a set of source files, you get a complete map of every identifier and what it was mapped to (randomly), in a text file looking like (as above):
foo -> i3718234
fas -> h823478
...
If you then run the obfuscator again and feed it the same souces and this map file,
it will (by design) map the identifiers the same way, producing the same result
as the first time.
To do OPs task, one could run our obfuscator on his code to get:
italianID1 -> i23432
italianID2 -> g232343
...
Using a text editor, he could modify this file to:
italianID1 -> englishID1
italianID2 -> englishID2
...
Names he doesnt want touched are edited (obviously) to this form:
foo -> foo
bar -> bar
(A shorthand for this, is to simply leave off the "-> id" part. "foo" by itself is
interpreted as "foo -> foo").
Now running the obfuscator will rename all the italian IDs to englishIDs.
Check out my bio for a link. Its a commercial tool, but its probably cheaper
than a day of OP's labor and I think it solves his problem, waaaaay easier
than building his own refactoring tool.
A downside: I think he'll be forced to reformat his code. That's OK,
the obfuscator includes a reformatter.

Related

Removal of a block of code during runtime

I need to remove a particular function or a class from my Java code when it is being converted into .jar file using Maven. But the caveat is the function or class should stay inside the source code.
Is there any such way in which I can achieve this using Maven and/or any Java utilities?
(there are a lot of functions ~400 and their implementations are very large as well therefore commenting the code is not an option)
Okay, so the real problem is this:
We have a code base which includes certain parts that are not currently being used, but they may be used in the future, so we want to keep them in the code base, but we do not want them to be shipped to customers. (Due to, uhm, reasons.) What are the best practices for achieving this? Note that commenting them out would be impractical.
The proper way to achieve this is to extract all those parts into a separate module, and refrain from shipping that module.
The hacky way is to use a hard-coded feature flag.
A normal (non-hard-coded) feature flag is a boolean which controls a certain aspect of the behavior of our software. For example, if you build an mp3 player application, and you want to add support for the aac file format, but you do not want to ship support for it yet, then you might want to create a boolean supportAacFeatureFlag() method, and have all code that pertains to the aac file format invoke that method and check the return value before doing anything. It is important to note that this must be a method, not a constant, so that its value is not known at compilation time, because every single if statement that checks the value of a constant is bound to yield a "condition is always true" or "condition is always false" warning. The great benefit of feature flags over commenting-out code is that the code controlled by a feature flag must still compile, so it must be semantically correct. The problem with feature flags is that they do not eliminate the code; the code still gets shipped, it just does not get executed.
A hard-coded feature flag is a feature flag which is implemented using a constant. The constant condition warning will be issued in every single use of that flag, so it will have to be globally disabled. (That's why this approach is hacky: we normally want all warnings enabled.) The benefit of using a constant is that its value is known at compilation time, so even though the compiler will still compile the controlled code, it will refrain from emitting any bytecode for it, so the code essentially does not get shipped to customers. Only empty functions get shipped.
Note that this is documented behavior of the Java compiler. In other languages like C++ and C# the compiler always emits all code, and you have to use other means of controlling code generation, like #defined symbols, which, in my opinion, are also very hacky.
An alternative way which I am sure some people will opt for but I would strongly advice against is to keep the unused code in a separate feature branch and remove it from the master branch. I would strongly advise against this, because any refactorings applied to the master branch will not affect the feature branch, so the code will diverge, so it will be a nightmare to integrate it in the future.

Eclipse: Replace multiple, different regexes simultaneously

I'm currently trying to replace an old (java) testing framework with a different, although similar, one. Therefore, as most occurences of old framework code are the same 90% of the time (in the sense of identic variable names, parameter types etc.), replacing them is pretty straightforward and rather repetitive.
Therefore, I wrote myself a few regex matches (which work just fine, they are not the focus of this question).
However, I have a rather large number of different test files, and I already at this point - just having started - have 6 different match/replacement-pairs that I would like to apply.
Now obviously, being a computer scientist, I would love to automate this, instead of going through every file, pressing Ctrl+F, pasting the matching regex, pasting the replacement regex, pressing the replace button, repeating this cycle 5 more time, and then moving to the next file.
So, let's say for the sake of simplicity, that these are my regexes:
//matches the existing framework
OldClass (.*?) = new OldClass("string");
//replacement regex:
NewClass $1 = new NewClass("string");
//example replacement:
OldClass foo = new OldClass("string");
//becomes:
NewClass foo = new NewClass("string");
So, If I want to replace several of these match/replace-pairs in lots of different files - can I use any built-in eclipse function, or is there an extension that provides this functionality?
Note that I'm aware that I could write a simply java program that just skims through all my source code and applies the regexes as desired.
I'd much rather avoid spending that time, though, and especially would also like to get a chance to apply them individually to each file, so I can re-run the tests afterwards and make sure nothing is broken - which will happen, as not all of the old framework code can be replaced automatically, due to too complex & specific cases. Since I'm also removing the old imports, though, this will break any still existing non-replaced code relying on now-no-longer-existing imports.
Eclipse should have a simple file search option with a "Replace.." button at the bottom. You can search as you would normally specifying the file endings that you'd like to search (probably in this case you'd want *.java). The replace button lets you replace each search result with a replacement using regular expressions.
Granted, this will change your source one replace at a time and that is awkward I know, but my recommendation is to perform small steps, minimizing time in which your code is broken. For instance if you move your class to a new location with a new name, just focus on renaming the class first (verifying that the code then works afterwards), and only then focus on changing its package.
Word to the wise, click Preview first!
Alternatively, consider using ctrl+shift+R to rename methods/variables/classes. Assuming the code is under a source folder, it will automatically rename everywhere it is used. Generally it is preferable to using regular expressions. But again, you can't perform multiple changes at the same time. Though this is probably for the best. Just make a backup of the project and organize the changes that need to be made before starting.
Good luck!

How do I stop IDEA from reformatting my code when refactoring?

When refactoring code (e.g.: Refactor -> Rename), IntelliJ IDEA 14.x also rewraps (reformats) my code to fit into the 80 column limit.
Example: here's the code before the refactoring:
Refactoring in progress:
... and the code is re-wrapped once I press Enter:
What's most annoying about that, even Java classes which aren't currently open in the editor (but are affected by the refactoring) are reformatted, increasing the chance that formatting changes get propagated into my VCS unnoticed.
What I want to achieve is:
keep the original print margin at 80 columns, but still
have IDEA preserve my original formatting when renaming variables/classes/methods.
How do I achieve this?
Since I don't use any automatic formatting and mostly wrap my long lines manually, I figured out another solution.
Under "File -> Settings -> Editor -> Code Style -> Java -> Wrapping and Braces", I've disabled automatic wrapping entirely (i.e. set everything to "Do not wrap" where appropriate, except for class, method and field annotations, which are set to "Wrap always" by default).
The downside of this approach is that now IDEA sometimes unwraps long lines during refactoring, but those are easier to spot.
If you are doing an actual "Refactoring -> Rename", for example with SHIFT + F6 you are editing every file that has a reference to that variable name whether or not they are currently open in the editor is irrelevant if you change something all the files that are affected are edited and any VCS will consider them changed.
The behavior of reformatting the entire file on refactoring is been in Idea a long time and all bugs that have been filed against that behavior have been setting in an unassigned state forever. Here is one example.
I doubt that this behavior is going to change, I for one hope it does not.
If you want ridiculously long variable names then you need to either turn off the right margin or make it ridiculously long as well. Or change whatever configuration is causing things to be formatted differently.
Personally I set all the relevant things to ALWAYS whatever so I do not have somethings formatted one way and somethings formatted a different way. Consistency is more important than anything else in a large code base.
The VCS tools in Idea are extremely powerful and unmatched in any other IDE. You can easily see what has changed and exclude them from any commits or fix them up how you want.
Idea has a format on commit checkbox for all the various version control systems it supports as well.

Eclipse: Fulltext autocompletion for Java?

can I has fulltext autocompletion for Java # Eclipse? Let's demonstrate:
Final piece of code:
getVariants().add(new Variant(MediaType.TEXT_XML));
How do I code now:
getv[ctrl+space].a[Enter]new
V[ctrl+space, down arrow,
Enter]M[Ctrl+Space, Enter].text_x
Basically, Eclipse completes word "TEXT_XML" when I provide letters "TEXT_X".
How would I like to code:
getv[ctrl+space].a[Enter]new
V[ctrl+space, down arrow,
Enter]M[Ctrl+Space, Enter].xml
and Eclipse should realise I meant "TEXT_XML" (fulltext autocompletion).
As far as I'm aware, there is no way of enabling a full-text code completion in the Eclipse preferences view. This has been bugging me for a while, too. I did quite a bit of digging and I'm pretty certain there is no easy way of achieving this.
However,
there are two ways of implementing the desired, but I assume both of which are way to much work for fixing this little nuisance.
There is an Eclipse plug-in extension point for the JDT Java Completion Proposal Computer - reference page
A sample project which implements this extension point can be found in this repository.
This is fairly convenient, but still a lot of boilerplate and tedious coding.
You can change the findKeywords method in the internal org.eclipse.jdt.internal.codeassist.CompletionEngine class and compile your own JDT fork. But this is discouraged for so many reasons. First of all, this class is a 12000 line monster and hard to just jump in. And of course, if you'd only hack a kludge in, there is little chance of this becoming an official contribution, so you'd need to worry about every eclipse release.
Additionally, there might be a very chillaxed way in the future. Although this might exceed your requirements a bit.
Have a look at the Code Recommenders project. This blog has an outline of the project objectives
It doesn't mention full-text auto-completion specifically, but I'd assume its matching algorithms go even beyond that.
Edit: In the proper SO-spirit, I'll keep this answer up to date:
Apparently the feature is now implemented in the Code Recommenders plug-in. See this blog post and this forum thread. I'm quite surprised it only took 10 locs. To me the extension point appeared more complex.
If your MediaType class does not contain a large number of accessible fields/methods you could simply use
getv[ctrl+space].a[Enter]new V[ctrl+space, down arrow, Enter]M[Ctrl+Space, Enter].[Ctrl+Space, down arrow, Enter]
you may need to press the down arrow more than once, though to select the desired field.
Yes, you can using Templates. (Window -> Preferences -> Java -> Editor -> Templates)
The basic usage is you set the name to what you want to type and you set the pattern to what you want to appear.
In my testing I set the name to xml, the Context to Java, the Pattern to TEXT_XML and Automatically insert turned on. Then when I typed out your example I was able to follow a pattern like...
getv[ctrl+space].a[enter]new V[ctrl+space, down arrow, Enter]M[ctrl+Space, Enter].xml[ctrl+space]
and since Automatically insert was turned on poof TEXT_XML was inserted.
Templates have much more functionality than that and the one source I used for this answer was Effective Eclipse.
I hope this helps!

How can I set globals to JSLint to ignore for a whole set of files?

I'd like to run JSLint4Java as part of my build process. I have about 1000 JS files in a library, and don't really want to add a
/*globals foo, bar, baz */
header to each of them -- especially since many of them are from an external library (Dojo). If I don't add the header, though, JSLint complains about the same five globals on nearly every single file. Is there a way to tell JSLint to ignore them? Some things I've thought of so far:
Some sort of AntFileMap task that creates a virtual directory hierarchy that's an exact copy of another hierarchy, but has a filter applied to each file (in this case, prepend with a /*globals */ header).
Hack JSLint4Java to accept a set of globals which it prepends as a comment to the beginning of every file it processes.
I've never seen anything like (1). (2) seems relatively easy, but I'd prefer to use original tools if possible. Any better suggestions?
From http://www.ohloh.net/p/jslint4java
News 2009-12-02. jslint4java 1.3.3 is
released. Noteworthy alterations: Add
support for the predef option, to
allow specifying a list of predefined
global variables.
Sounds like what you might be looking for. Try the --help option to get the syntax, maybe?
You can also use LintRoller - a Node.js utility for checking entire directories or projects against JSLint, JSHint and other validations.

Categories