I was wondering if I could use the Eclipse Code Formatter from inside my code … so, the logical thing to do was to ask on stackoverflow, and see if anyone knew how to do that. Thanks to VonC‘s answer, I found out about the CodeFormatter class … and 10 jars and 2 hours later, I’ve got it working.
Here’s how I did it.
CodeFormatter is an abstract class, which means you can’t instantiate it directly. So, I started to search about classes derived from it, and so I found out about DefaultCodeFormatter, which I presumed was what I was looking for. I was right.
DefaultCodeFormatter implements the method :
public abstract TextEdit format(int kind,
String source,
int offset,
int length,
int indentationLevel,
String lineSeparator)
Method documentation can be read here.
I wrote the following code to test it :
... main(String[] args) {
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);
System.out.println(te);
}
I used the CodeFormatter.K_UNKNOWN constant for the formatting, because I was thinking that the CodeFormatter will “deduce” the type of code I’ve passed it. I’m not really sure what K_UNKNOWN does, but it seems to work well with the code I’ve tried.
So … the DefaultCodeFormatter returned a TextEdit object as the result of the code formatting.
I was kind of hoping that it’s toString method would give me the code. Instead, I found out it had several ReplaceEdit children nodes. I tried to iterate over each of the children and print their text using their getText, but they wouldn’t “show me the code” 🙂 . I thought “TextEdit’s apply method sounds interesting. Let’s see what it does”. Checking it’s method signature :
apply(IDocument document)
revealed a IDocument parameter. I was hoping it would be easy to create a Document object, and that I wouldn’t need any other “eclipse objects”. Turns out it was easy. There is a Document implementation, that has a String constructor :
Document(String initialContent)
I applied the TextEdit to the document, and hoped for the best. The eclipse console printed out nicely formatted code. WIN !
Here’s the full code for the class I used to test the CodeFormatter :
import org.eclipse.jdt.core.formatter.CodeFormatter;
import org.eclipse.jdt.internal.formatter.DefaultCodeFormatter;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;
public class FormatterTest {
public static void main(String[] args)
{
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();
}
}
}
Here’s the list of jars I had to add to the classpath to get the code formatter to work :
- org.eclipse.jdt.core_3.4.4.v_894_R34x.jar
- org.eclipse.text_3.4.0.v20080605-1800.jar
- org.eclipse.core.runtime_3.4.0.v20080512.jar
- org.eclipse.osgi_3.4.3.R34x_v20081215-1030.jar
- org.eclipse.equinox.common_3.4.0.v20080421-2006.jar
- org.eclipse.core.resources_3.4.2.R34x_v20090126.jar
- org.eclipse.core.jobs_3.4.1.R34x_v20081128.jar
- org.eclipse.core.contenttype_3.3.0.v20080604-1400.jar
- org.eclipse.osgi.services_3.1.200.v20071203.jar
- org.eclipse.equinox.preferences_3.2.201.R34x_v20080709.jar
They may have different versions on your eclipse installation. They worked for my eclipse installation :
Version: 3.4.2
Build id: M20090211-1700
One of those jars isn’t needed, but I can’t remember which. Sorry for the extra classes.
Hope this helps anyone!
Hi
Just my 2 cents:
– DefaultCodeFormatter is internal, see org.eclipse.jdt.core.ToolFactory.createCodeFormatter
– K_UNKNOWN does probe the type to format, see DefaultCodeFormatter.probeFormatting, of course this has a performance impact.
Thanks for the additional information Benno!
I like the eclipse source code formatter, but I do not like the idea of include a lot of libraries, so I suggest to try the open source project jastyle, a 100% pure java port of the astyle. It is very small (<70Kb) and it could be integrated easily. http://sourceforge.net/projects/jastyle/ . It does not use any additional library.
It is not the most sophisticated library, but It works pretty well.
Best regards,
Barenca.
Cool! I know the Eclipse formatter uses a lot of libs, which can become pretty hard to manage. The simpler the better!
I’m definitely going to try it out!
Thanks!
Hi
Your article has inspired me to create a maven plugin. Can I put a link to this page in my project page?
Thanks,
Jecki
Of course! No problem.
I’m glad you found the article helpful!
I’ve just added the link in the main page. You can check it here [http://code.google.com/p/maven-java-formatter-plugin/].
Great! Keep up the good work 🙂
thanks alot! for java 1.5 and greater, this worked for me.
Map options=new TreeMap();
options.put(org.eclipse.jdt.core.JavaCore.COMPILER_SOURCE, “1.5”);
options.put(org.eclipse.jdt.core.JavaCore.COMPILER_COMPLIANCE, “1.5”);
options.put(org.eclipse.jdt.core.JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, “1.5”);
CodeFormatter formatter = org.eclipse.jdt.core.ToolFactory.createCodeFormatter(options);
of course you could read your eclipse props in too.
Thanks for the feeback!
It’s also nice to see new snippets of code showing new options.