Is there a way to apply a refactoring script just for its side-effects?
I've got a li开发者_如何转开发brary that was changed to introduce a factory method to replace a constructor (the reasons aren't important right now, in the current case it was for improved type inference mostly).
Assuming that there is an Eclipse refactoring script for it (so I pretty much have a nice computer-readable description of the change), is there some way to apply that script to a project that only uses that library (i.e. it only has a reference to a compiled version of the library)?
For example, I start with this simple class:
public class MyContainer<T> {
private final T content;
public MyContainer(final T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
Now I introduce a factory (without making the constructor private, but that isn't really relevant right now), the factory method looks like this:
public static <T> MyContainer<T> holding(T content) {
return new MyContainer<T>(content);
}
When I now export a migration script it looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<session version="1.0">
<refactoring comment="Introduce factory 'holding' in 'scratch.MyContainer' for constructor 'scratch.MyContainer.MyContainer()'
- Original project: 'scratch'
- Original element: 'scratch.MyContainer.MyContainer()'
- Factory name: 'holding'
- Owner class: 'scratch.MyContainer'"
description="Introduce factory for 'MyContainer'"
element1="/src<scratch{MyContainer.java[MyContainer"
flags="589830" id="org.eclipse.jdt.ui.introduce.factory"
input="/src<scratch{MyContainer.java"
name="holding" project="scratch" protect="false"
selection="89 0" version="1.0"/>
</session>
This should hold enough information to apply the refactoring to another project that references (a current version) of the class via a jar file.
But trying to apply the refactoring gives me this error:
The refatoring 'Introduce Factory' (org.eclipse.jdt.ui.introduce.factory) cannot be performed, since its input 'scratch.MyContainer.java' does not exist.
Note that it explicitly mentions .java
, so it's looking for a source file and isn't content with applying the refactoring to the binary type.
Note: I don't want to patch the binary library. I just want the callers of the original constructor to be converted to calling the factory method instead.
Note 2: Search-and-replace won't help in my specific case. The reason is that I have two constructors, one taking an Object
and the other takes a String
. They should be mapped on two different factory methods, so I'd need the search-and-replace function to look at the type information of the argument as well.
Note 3: even a way to manually specify "replace instantiations of object X
with this constructor with calls to this method instead" would be appreciated.
Update: There is a bugzilla entry on the Eclipse bugzilla that is about adding a replace invocation refactoring. An implementation of that feature might be able to solve my problem, if "invocation" includes object instantiation via a given constructor. Unfortunately it saw no activity in the last few years (although it was planned for 3.2).
This is not a way to apply refactoring to callers only but it may get you past your problem.
Would it be possible to add to your project a fake MyContainer.java
file that has the same signatures as that in the library, apply your refactoring and then discard the java file? You could even use decompiled soure, though you might have to generify it yourself.
I think you will have to write your own refactoring plugin. The tests for org.eclipse.jdt.ui.tests.refactoring are an interesting place to start.
Some interesting reads on the topic:
- http://www.eclipse.org/articles/article.php?file=Article-Unleashing-the-Power-of-Refactoring/index.html
- http://www.eclipse.org/articles/Article-LTK/ltk.html
精彩评论