Is there any Eclipse refactoring API that I can call programmatically? - java

I need to refactor code in a wide term. I know that from inside the Eclipse IDE I can refactor my classes. But is there any API that I can use in a java project so that I can refactor projects dynamically through code?
I need some idea on how to achieve the following: a program that calls all the Eclipse refactorings for renaming and moving in a loop to refactoring the entire project in one shot!
I don't want to introduce new refactoring types by extending the refactoring classes. I just want to call them programmatically.

Something like this?
Anyone who supports a programming language in an Eclipse-based IDE
will be asked sooner or later to offer automated refactorings -
similar to what is provided by the Java Development Tools (JDT). Since
the release of Eclipse 3.1, at least part of this task (which is by no
means simple) is supported by a language neutral API: the Language
Toolkit (LTK). But how is this API used?
EDIT:
If you want to programmatically run refactorings without using the UI, RefactoringDescriptors (see article) can be used to fill in the parameters and execute the refactoring programmatically. If you create a plugin that depends on org.eclipse.core.runtime and add the org.eclipse.core.runtime.applications extension, you will be able to run an IApplication class from eclipse similar to a main(String[]) class in plain java apps. An example of calling the API can be found on the post.
ICompilationUnit cu = ... // an ICompilationUnit to rename
RefactoringContribution contribution =
RefactoringCore.getRefactoringContribution(IJavaRefactorings .RENAME_COMPILATION_UNIT);
RenameJavaElementDescriptor descriptor =
(RenameJavaElementDescriptor) contribution.createDescriptor();
descriptor.setProject(cu.getResource().getProject().getName( ));
descriptor.setNewName("NewClass"); // new name for a Class
descriptor.setJavaElement(cu);
RefactoringStatus status = new RefactoringStatus();
try {
Refactoring refactoring = descriptor.createRefactoring(status);
IProgressMonitor monitor = new NullProgressMonitor();
refactoring.checkInitialConditions(monitor);
refactoring.checkFinalConditions(monitor);
Change change = refactoring.createChange(monitor);
change.perform(monitor);
} catch (CoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
If you have more detailed questions about using the JDT APIs (AST, Refactoring, etc) I'd suggest you ask on the JDT Forum.

The answer below is great, but I answered with a wider perspective for the people who need a more bulky and tasty crunch of this wonderful cake:
RefactoringStatus status = new RefactoringStatus();
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot root = workspace.getRoot();
IProject[] projects = root.getProjects();
then:
for (ICompilationUnit unit : mypackage.getCompilationUnits()) {
IType primary = unit.findPrimaryType();
IMethod[] methods = primary.getMethods();
int i = 1;
for (IMethod method : methods) {
if (method.isConstructor()) {
continue;
}
makeChangetoMethods(status, method,"changedMethodVersion_" + i);
++i;
}
}
After that:
IProgressMonitor monitor = new NullProgressMonitor();
status = new RefactoringStatus();
Refactoring refactoring = performMethodsRefactoring(status, methodToRename, newName);
then:
Change change = refactoring.createChange(monitor);
change.perform(monitor);
find below the code for setting the descriptor:
String id = IJavaRefactorings.RENAME_METHOD;
RefactoringContribution contrib = RefactoringCore.getRefactoringContribution(id);
RenameJavaElementDescriptor desc = contrib.createDescriptor();
desc.setUpdateReferences(true);
desc.setJavaElement(methodToRename);
desc.setNewName(newName);
desc.createRefactoring(status);

Related

How to generate getters and setters in eclipse for mutable objects?

one of the sonar issue that I recently found was that
"Malicious code vulnerability - May expose internal representation by incorporating reference to mutable object"
For example ideally Eclipse should generate setter for date like following
public void setBillDate(Date billDate) {
this.billDate = (Date)billDate.clone();
}
How can I force Eclipse to generate code like this?
Window -> Preferences -> Java -> Code Style -> Code Templates
Enable project specific settings
You'll see "Setter Body", Edit:
${field} = ${param};
The code you need might be written as
try {
${field} = ${param}.getClass().cast( ${param}.clone() );
} catch( CloneNotSupportedException cnse ){
// whatever
}
I admit that I don't know whether there is a template variable for the parameter class. Investigating...

guava-testlib future version JAR

Today, the current Guava version seems to be:
release is 13.0.1, August 3, 2012.
but I checked out the source off of:
git clone https://code.google.com/p/guava-libraries/
and got intrigued by what seems like an extremely useful testing tool to me:
http://code.google.com/p/guava-libraries/source/browse/guava-testlib/src/com/google/common/testing/NullPointerTester.java
I am trying to verify that all of my methods detest null just as much as Doug Lea ( http://gee.cs.oswego.edu/dl/html/vita.html ) seems to do, unless Joshua Bloch misquotes him ( http://www.youtube.com/watch?v=ZeO_J2OcHYM#t=26m35s ) in being "null-hostile".
Anyway, NullPointerTester.java seems to be just perfect so I am trying to build it into my project.
Following the dependencies (NullPointerTester -> Invokable<?, ?>, -> ... for example) is tedious as I run into classes that are #since 14.0, basically belong to a future version.
What's the best way to build a self-contained JAR of the next/future version of Guava, with all dependencies being taken care of for me? Note: the sources seem to be "all" on git...
You can stop reading here.
I can't wait to be doing stuff like this, which is really cool I think:
http://www.massapi.com/class/nu/NullPointerTester.html
Note: what's missing are "security checks", as in "if the constructor has been made private, check that I cannot reflect-invoke it anyway...
If I were a better coder I'd contribute, but this is all I can do and it's very poor, although the intent should be clear?
static boolean isDefaultConstructorDisabled(Class<?> type) {
boolean isDefaultConstructorDisabled = false;
Constructor<?>[] declaredConstructors = type.getDeclaredConstructors();
Constructor<?> defaultContructor = declaredConstructors[0];
defaultContructor.setAccessible(true);
try {
defaultContructor.newInstance();
} catch (InvocationTargetException invocationTargetException) {
Throwable cause = invocationTargetException.getCause();
if (cause instanceof UnsupportedOperationException
&& cause.getMessage().contains(
ErrorMessage.DefaultConstructor.DISABLED)) {
isDefaultConstructorDisabled = true;
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return isDefaultConstructorDisabled;
}
Did you try looking in Maven?
http://search.maven.org/#browse%7C-723200679
I think guava-testlib is what contains NullPointerTester. You could grab the 13.0.1 jar.
http://search.maven.org/#browse%7C1590928164
If you cloned the whole Guava repository, then the v13.0.1 tag will have guava-testlib, and specifically NullPointerTester, as of 13.0.1, which should work -- no?

Testing if Quicktime and Java are installed?

In Javascript how can I test if the user has the quicktime plugin and java plugins installed?
For Java, you can use navigator.javaEnabled(). Or you can look here: http://www.pinlady.net/PluginDetect/JavaDetect.htm
For QuickTime, you can do:
var QtPlugin = navigator.plugins["Quicktime"];
if (QtPlugin) {//QuickTime is installed}
See here: http://javascript.internet.com/miscellaneous/check-plugins.html
This of course does not work in IE. The only way to check plugins in IE is using VB script, and it is very strange and messy. You can only test for specific plugin versions, for example, "quicktime" won't cut it. You have to specify the version, which is not published for versions older than 5, and I can't find a reference for version 7
The above examples haven't got the answer to the QuickTime part of your question, so here's what I'm writing right now even though the question has been closed and is a little old.
var p = navigator.plugins;
var qtcheck = 0;
for (i=0;i<p.length;i++) {
if (p[i].name.match(/QuickTime/) != null) {
qtcheck++
}
}
if (qtcheck > 0) { // do nothing, QuickTime is intalled }
else {
videos = document.querySelectorAll('object[type="video/quicktime"]')
// use .getElementById instead if there are multiple videos
// replace them with document.createElement('img')
For a more comprehensive and foolproof method i.e. without worry of a plug-in being renamed for whatever reason, you can check within the array of MimeTypes for type="video/quicktime" which is the ultimate answer of whether the object will be supported (or if you're not using the QT video, whatever else you're using it for instead).
This means creating a loop inside the loop through the plugins instead, but is a more firm verification than just a string match:
function checkQT() {
var p = navigator.plugins;
var QT = false; // assume you don't have it
for (i=0;i<p.length;i++) {
for (j=0;j<p[i].length;j++) {
if (p[i][j].type == "video/quicktime") {
QT = true;
return true;
}
else continue;
return false;
}
}
}
I searched around online and found a bunch of great IE fallback scripts here (not sure if this paste service code is going to persist so I gisted it for posterity), from which I took the QuickTime one:
function IEhasQT() {
if (!window.ActiveXObject) return false;
try { if(new ActiveXObject("QuickTime.QuickTime")) return true; }
catch (e) {}
try { if (new ActiveXObject('QuickTimeCheckObject.QuickTimeCheck')) return true; }
catch (e) {}
return false;
}
I tested some others and they just didn't work - catching the exceptions is important.
If you're doing what I'm doing (QuickTime fallback to a gif animation) you might want to take the attributes of the video to provide to the image (or whatever else you're using). The downside to this is that you have to couple it to an onscroll as well as onload (or use Jquery) as the browser is liable to try and find the element before the DOM has loaded no matter how you try and avoid it.
If anyone else reading this is looking for a similar answer, the code to do so is
function noQTfallback() {
var vid1 = document.getElementById("<insert your object id>");
var vid1gif = document.createElement('img');
vid1gif.setAttribute("src","<insert your URL source>");
vid1gif.setAttribute("style",vid1.getAttribute("style"));
document.getElementById("<...>").replaceChild(vid1gif, vid1);
}
function IEhasQT() {
// as above
}
function checkQT() {
// as above
}
function QTbackup(){
if (!checkQT() && !IEhasQT()) {
noQTfallback();
}
}
window.document.body.onload = QTbackup;
window.onscroll = QTbackup;
Oddly, you can have multiple versions of QuickTime installed, my Chrome browser on Windows has 7 copies... Luckily I have a Chromebook which doesn't have QT plug-in either installed or available, so I'm checking and seeing what works to distinguish it, this is the best I've come up with.
I never understood why testing was so important until looking at everyone's awful code on this online, incredible. I know no one cares about IE but basic things like || instead of && are just bad to leave lying around for other developers to reuse.
I've checked this on Windows, Linux and Android (IE and Chrome). The onscroll gives a bit of a jump but without Jquery or some other framework it's unavoidable I guess (and beats "plug-in not supported" !

How can I use the eclipse indenter from my code?

I noticed the eclipse indenter has support for the latest version of java, and it would be nice if I could use that class to indent generated java source code. Is there a way of integrating it ?
EDIT: I need to be able to include the code formatter in my code. No external calls.
EDIT2: I've managed to get it working. You can read the story here. Thanks VonC !
You can try running the formatter as a standalone application (also detailed here).
eclipse -vm <path to virtual machine> -application org.eclipse.jdt.core.JavaCodeFormatter [ OPTIONS ] <files>
Try first to define formatting settings with eclipse IDE in order to achieve the right result, then export those settings, and use that configuration file in the eclipse.exe parameters.
Or see also "Generating a Config File for the Formatter Application"
eclipse [...] -config <myExportedSettings>
In a java program, you can try to directly format by:
Creating an instance of CodeFormatter
Using the method void format(aString) on this instance to format aString. It will return the formatted string.
Thanks to Geo himself and his report in his blog entry, I now know you need to use DefaultCodeFormatter
String code = "public class geo{public static void main(String[] args){System.out.println(\"geo\");}}";
CodeFormatter cf = new DefaultCodeFormatter();
TextEdit te = cf.format(CodeFormatter.K_UNKNOWN, code, 0,code.length(),0,null);
IDocument dc = new Document(code);
try {
te.apply(dc);
System.out.println(dc.get());
} catch (MalformedTreeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Again, full details in the blog entry. Thank you Geo for that feedback!
Thorbjørn Ravn Andersen mentions in the comments:
Maven2 Java Formatter Plugin v0.4 describes a maven plugin that allows Maven to invoke the Eclipse formatter.
As of 0.4 it invokes Eclipse 3.5 which does not support Java 8.
Actually, there is one problem with VonC's answer: DefaultCodeFormatter is in an 'internal' package, and therefore should not be be used by clients!
I recently asked the same question here on stackoverflow, and came up with the answer a little while later.
In short, you need to use ToolFactory, as in
ToolFactory.createCodeFormatter(null);
I was using the CodeFormatter in an Eclipse-independent project. The default options used by calling ToolFactory.createCodeFormatter(null); could not handle the source code - the result of the format() call being null.
A minimal working options setup is the following:
Hashtable<String, String> options = new Hashtable<>();
options.put("org.eclipse.jdt.core.compiler.codegen.targetPlatform", "1.8");
options.put("org.eclipse.jdt.core.compiler.compliance", "1.8");
options.put("org.eclipse.jdt.core.compiler.source", "1.8");
CodeFormatter codeFormatter = ToolFactory.createCodeFormatter(options);

jBPM Standalone App with SWT

According to the whitepaper on the jBPM page [1], jBMP can be easily used in a standalone app. However I could not find any information about how to actually do this. I want to create a simple java app (maybe with SWT), which displays a process with jBPM. The user should then be able to modify the applications behavior, by modifying the jBPM diagram. For this purpose I also have to integrate some eclipse components I think.. any ideas how this works?
[1] http://www.jboss.com/pdf/jbpm_whitepaper.pdf
Before you start, you may want also to see if Roamflow meets your needs as it seems to be a standalone jBPM Eclipse/RCP based viewer/editor.
Otherwise you should know how to build eclipse plug-ins, or get the book I found useful for most eclipse plugin/SWT development needs, "Eclipse Building Commercial-Quality Plug-ins", published by eclipse and Addison-Wesley. Also, I am not going to sit down and write you a test app, you need to understand the fundamentals anyhow.
By stand alone they mean run in any old JVM with the right libraries. It does need to be deployed in a J2EE container, viewed through the web, etc.
Look at the source code for the jBPM eclipse plug-in as it has the features you are looking for right? An SWT/eclipse based to that displays jBPM. This includes checking for extension points that jBPM may install which you can use to build your eclipse plug-in with quickly. For example: The jBPM editor code, here. Or how to serialize, here, re-use.
Here is the critical SWT/drawing, a critical line is converting the jBPM into and SWT thing "g = new SWTGraphics(gc);". This seems to generate an image from a jBPM model.
protected void writeImage() {
SWTGraphics g = null;
GC gc = null;
Image image = null;
LayerManager lm = (LayerManager)getGraphicalViewer().getEditPartRegistry().get(LayerManager.ID);
IFigure figure = lm.getLayer(LayerConstants.PRINTABLE_LAYERS);
try {
Rectangle r = figure.getBounds();
image = new Image(Display.getDefault(), r.width, r.height);
gc = new GC(image);
g = new SWTGraphics(gc);
g.translate(r.x * -1, r.y * -1);
figure.paint(g);
ImageLoader imageLoader = new ImageLoader();
imageLoader.data = new ImageData[] {image.getImageData()};
imageLoader.save(getImageSavePath(), SWT.IMAGE_JPEG);
refreshProcessFolder();
} finally {
//SNIP
}
}
Learn from the plug-in's plugin.xml, src located here in this case. For example, here is the jBPM adding it's view to eclipse:
point="org.eclipse.ui.views" ... view class="org.jboss.tools.flow.jpdl4.view.DetailsView"...
This may be one extension you want to copy as it seems to stand up the "view".
This will help you understand how they construct the pieces of their eclipse based app. You can search for these classes in your work space and view the source code if you installed the developer versions on the JBPM plug-ins.
Decide if you need to hack apart the app parts built as GMF (Graphical Modeling Framework) stuff, like the model, behavior of the view/diagram and the different edit/drawing parts. Don't mess with this unless you have too. However, understanding GMF plug-ins or looking that the examples will help you understand what jBPM plug-in pieces you might need to use, especially if editing is needed.
Roll the pieces into a plug-in, remembering to reuse what pieces (plugins/pluglets) you can from the jBPM project. May sure to build your eclipse plugin as an RCP or Rich Client... (Note jBPM does not currently have a RCP, per post) so that it can as a eclipse standalone application for easier deployment to people who do not have eclipse tool knowledge.
Let me know if this gets you headed down the correct path.
Yes it's possible to run the jbpm process engine completely standalone, as a simple java program.
No J2EE container needed. At least this is the case with jbpm 4.4
As far as the code requirement goes,
setup your jbpm database schema
add the following jars from the jbpm distribution library to the applications classpath:
antlr-runtime.jar
antlr.jar
dom4j.jar
hibernate-core.jar
javassist.jar
jbpm.jar
slf4j-api.jar
slf4j-jdk14.jar
slf4j-log4j12.jar
commons-collections.jar
jta.jar
juel-api.jar
juel-engine.jar
juel-impl.jar
mail.jar
AND the necessary JDBC drivers for the DB that you are using.
and your standalone class looks like this:
package test.ayusman;
import java.util.HashMap;
import java.util.Map;
import org.jbpm.api.Configuration;
import org.jbpm.api.ExecutionService;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.RepositoryService;
public class ProcessDeployer {
// Create a process engine that can be used for all other work...
// ProcessEngine is starting point for all other application.
private static ProcessEngine jbpmProcessEngine = new Configuration()
.setResource("jbpm.cfg.xml").buildProcessEngine();
// private static Logger logger = Logger.getLogger(JBPMDao.class);
private static RepositoryService repositoryService = null;
private static ExecutionService executionService = null;
private static ProcessInstance pi = null;
private static String processInstanceState;
private static String processInstanceId;
public static void main(String[] args) {
try {
ProcessDeployer ejm = new ProcessDeployer();
//Start the process...
ejm.startProcess();
//Analyze process... just a small fancy method
ejm.analyzeProcess();
} catch (Exception e) {
e.printStackTrace();
}
}// End of main()
void startProcess() throws Exception
{
repositoryService = jbpmProcessEngine.getRepositoryService();
executionService = jbpmProcessEngine.getExecutionService();
//NOTE: The example assumes that the process definition file name is: your_process.jpdl.xml
processInstanceId = repositoryService.createDeployment().addResourceFromClasspath("your_process.jpdl.xml").deploy();
//NOTE: The jpdl file has key name as "Java"
pi = executionService.startProcessInstanceByKey("Java");
System.out.println("Obtained processInstanceId is: "+processInstanceId);
}
void analyzeProcess() throws Exception
{
processInstanceState = pi.getState();
System.out.println("processInstanceState is: "+processInstanceState);
System.out.println("processInstanceId is: "+processInstanceId);
}
}// End of class ProcessDeployer
Note that when you are running the process engine from with in the SWT application, the process engine resides on the same JVM as the SWT, so make sure that you allocate enough space.
Hope this helps :-)

Categories