Sunday, October 18, 2009

Amending Code Style & Templates Programmatically via Eclipse PDE


Having a common code style and template in a development team is a good software development practice. Fromatting source code with identical style and template reduces synchronizing issues (such as merge, compare, check-in or check-out from a version controller, SVN/CVS) between developers. Many modern IDE's provide custom code format and template functionalities. In eclipse, under Java > Code Style>Formatter and Code Templates menu, you can amend or create code styles and templates for your wish.

In eclipse, once a template or code formatter is created, it can be exported and then distributed among team members. Then, each developer has to manually import the code style and formatter.
This is a manual task.

In this blog, i will give source code examples how to apply a code style or template programmatically with Eclipse plug-in development (PDE).

Code Style (Formatter)

Let's assume that we have sample code style and template files (exported manually from eclipse and in xml format). For applying code style, we obtains default code style options with JavaCore.getDefaultOptions() function and then ammend or insert new code style with their new/updated values. And finally save back options.

// Get the default options
Hashtable options = JavaCore.getDefaultOptions();
// Amend the value of an option
options.put(JavaCore.COMPILER_PB_DEPRECATION, JavaCore.ERROR);
// Save the new options
JavaCore.setOptions(options);

Following source code shows how a code format file in xml format is applied programmatically with eclipse plug-in. Please note, xmltools.jar library from mycila is used for parsing xml file.

 package com.denizstij.plugins.settings.codeformatter;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.core.JavaCore;
import com.mycila.xmltool.XMLDoc;
import com.mycila.xmltool.XMLTag;
/**
* Programmatically apply code styles via eclipse pde
*
* @author deniz.turan (http://denizstij.blogspot.com/)
* Oct-2009
*/
public class CodeFormatter {
private String CODESTYLE_FILE_REL_PATH="configs/CodeStyle.xml";
private Map <String, String> codeStylesMap= new HashMap<String, String>();
private static CodeFormatter instance = new CodeFormatter();
private CodeFormatter() {
}
public static CodeFormatter getInstance() {
return instance;
}
public void populateCodeStyle() throws Exception{
codeStylesMap.clear();
InputStream is= CodeFormatter.class.getResourceAsStream(CODESTYLE_FILE_REL_PATH);
if (is==null){
return ;
}
// xmltool-3.0.jar from mycila needs to be class path
XMLTag from = XMLDoc.from(is, false);
if (from==null){
return;
}
XMLTag profileNode = from.gotoChild("profile");
Iterable<XMLTag> settings = profileNode.getChilds();
Iterator<XMLTag> iterator = settings.iterator();
while (iterator.hasNext()){
XMLTag next = iterator.next();
String id = next.getAttribute("id");
String value = next.getAttribute("value");
codeStylesMap.put(id, value);
}
}
public void applyCodeFormatter() throws Exception {
populateCodeStyle();
Hashtable options = JavaCore.getDefaultOptions();
Set<String> keySet = codeStylesMap.keySet();
for (String id:keySet){
String value= codeStylesMap.get(id);
options.put(id, value);
}
JavaCore.setOptions(options);
}
}

Code Template


Similar to code style, code template can be applied by using TemplateStore and TemplatePersistenceData classes. We can use JavaPlugin.getDefault().getCodeTemplateStore() to obtain current TemplateStore. Please note, these classes are in internal package, therefore, in further version of eclipse pde, it would cause issues (tested on eclipse 3.5)

 package com.denizstij.plugins.settings.codeformatter;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jface.text.templates.persistence.TemplatePersistenceData;
import org.eclipse.jface.text.templates.persistence.TemplateReaderWriter;
import org.eclipse.jface.text.templates.persistence.TemplateStore;
/**
* Programmatically apply code templates via eclipse pde
*
* @author deniz.turan (http://denizstij.blogspot.com/)
* Oct-2009
*
*/
public class CodeTemplate {
private String CODE_TEMPLATE_FILE_REL_PATH = "configs/CodeTemplate.xml";
private TemplatePersistenceData[] templateData;
private TemplateStore codeTemplateStore;
private static CodeTemplate instance = new CodeTemplate();
private CodeTemplate() {
init();
}
public static CodeTemplate getInstance() {
return instance;
}
public void applyCodeTemplates() throws Exception {
importCodeTemplate();
}
private void init() {
codeTemplateStore = JavaPlugin.getDefault().getCodeTemplateStore();
templateData = codeTemplateStore.getTemplateData(true);
}
private void importCodeTemplate() throws Exception {
InputStream input = CodeTemplate.class.getResourceAsStream(CODE_TEMPLATE_FILE_REL_PATH) ;
if (input == null) {
return;
}
TemplateReaderWriter reader = new TemplateReaderWriter();
TemplatePersistenceData[] datas = reader.read(input, null);
for (int i = 0; i < datas.length; i++) {
updateTemplate(datas[i]);
}
codeTemplateStore.save();
}
private void updateTemplate(TemplatePersistenceData data) {
for (int i = 0; i < templateData.length; i++) {
String id = templateData[i].getId();
if (id != null && id.equals(data.getId())) {
templateData[i].setTemplate(data.getTemplate());
break;
}
}
}
}

No comments: