由于 IScanner 和 IBuffer 修改源码比较麻烦,功能也不是很强大,需要编写大量的代码。
所以这里谢了一个辅助类,来改善代码。
接下来,我们看一下具体的应用:
描述: 判断一个类是否已经实现 Java.io.Serializable, 如果没有实现,那么加入实现代码
所以这里谢了一个辅助类,来改善代码。
package
com.humpic.plugins.helper.utils;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jdt.core. * ;
import org.eclipse.jdt.core.compiler.IScanner;
import org.eclipse.jdt.core.compiler.InvalidInputException;
public class ObjectScanBuffer {
private Offset offset = new Offset();
private IBuffer buffer;
private IScanner scanner;
public ObjectScanBuffer(IType objectClass) {
try {
ICompilationUnit cu = objectClass.getCompilationUnit();
this .buffer = cu.getBuffer();
this .scanner = ToolFactory.createScanner( false , false , false , false );
this .scanner.setSource( this .buffer.getCharacters());
// 不扫描 package 和 import 部分
ISourceRange sr = objectClass.getSourceRange();
this .scanner.resetTo(sr.getOffset(), sr.getOffset() + sr.getLength() - 1 );
} catch (JavaModelException e) {
throw new RuntimeException(e);
}
}
/**
* 返回下一个 Token
*/
public int getNextToken() throws InvalidInputException {
return this .scanner.getNextToken();
}
/**
* 查找 Token
*
* @param reset
* 为 true,那么如果没有找到,则会重置 scan 位置
*/
public boolean findToken( int token, boolean reset) throws InvalidInputException {
int [] savepoint = this .savePoint();
int t = this .scanner.getNextToken();
while (t != token) {
if (t <= 0 )
break ;
t = this .scanner.getNextToken();
}
if (t != token && reset) {
this .resetPoint(savepoint);
}
return t == token;
}
/**
* 查找 Token, 如果碰到 stopToken,则停止.
*
* @param reset
* 为 true,那么如果没有找到,则会重置 scan 位置
*/
public boolean findToken( int token, int stopToken, boolean reset) throws InvalidInputException {
int [] savepoint = this .savePoint();
int t = this .scanner.getNextToken();
while (t != token) {
if (t <= 0 )
break ;
if (t == stopToken)
break ;
t = this .scanner.getNextToken();
}
if (t != token && reset) {
this .resetPoint(savepoint);
}
return t == token;
}
/**
* 查找从 startToken 到 endToken 中间的所有 Tokens
*
* @param reset
* 为 true,那么如果没有找到,则会重置 scan 位置 (如果 startToken 找到,重置到 startToken)
* @return new Object[] { new Integer(token), tokenText }
*/
public List findTokensBetween( int startToken, int endToken, boolean reset) throws InvalidInputException {
List tokens = new ArrayList();
if ( this .findToken(startToken, reset)) {
int [] savepoint = this .savePoint();
int t = this .scanner.getNextToken();
while (t != endToken) {
if (t <= 0 )
break ;
tokens.add( new Object[] { new Integer(t), this .getTokenText() });
t = this .scanner.getNextToken();
}
if (t != endToken) {
tokens.clear();
if (reset) {
this .resetPoint(savepoint);
}
}
}
return tokens;
}
/**
* 在 findTokensBetween 返回中查找 是否存在 token
*/
public boolean existToken(List tokens, int token) {
for ( int i = 0 ; i < tokens.size(); i ++ ) {
Object[] t = (Object[]) tokens.get(i);
if (((Integer) t[ 0 ]).intValue() == token) {
return true ;
}
}
return false ;
}
/**
* 在 findTokensBetween 返回中查找 是否存在 tokenText
*/
public boolean existToken(List tokens, String tokenText) {
for ( int i = 0 ; i < tokens.size(); i ++ ) {
Object[] t = (Object[]) tokens.get(i);
if (StringUtils.equals((String) t[ 1 ], tokenText)) {
return true ;
}
}
return false ;
}
/**
* 返回当前的 Token 文本内容
*/
public String getTokenText() {
return new String( this .scanner.getCurrentTokenSource());
}
/**
* 返回下一个 Token 文本内容
*/
public String getNextTokenText() throws InvalidInputException {
this .scanner.getNextToken();
return this .getTokenText();
}
/**
* 当前 Token 前面是否存在 空格,或者回车符
*/
public boolean skipSpaces() {
int pos = this .offset.getNewPos( this .scanner.getCurrentTokenStartPosition() - 1 );
if (pos < 0 )
throw new RuntimeException( " 该Token所在的位置已经被删除或者修改过了 " );
String s = this .buffer.getText(pos, 1 );
char c = (s.length() == 1 ? s.charAt( 0 ) : ' /0' );
return c == ' ' || c == ' ' || c == ' ' ;
}
/**
* 用 text 替换 当前的 Token
*/
public void replaceText(String text) {
int pos = this .offset.getNewPos( this .scanner.getCurrentTokenStartPosition());
if (pos < 0 )
throw new RuntimeException( " 该Token所在的位置已经被删除或者修改过了 " );
int size = this .scanner.getCurrentTokenEndPosition() - this .scanner.getCurrentTokenStartPosition() + 1 ;
this .buffer.replace(pos, size, text);
this .offset.addChange(pos, 0 - size);
this .offset.addChange(pos, text.length());
}
/**
* 在当前 token 位置添加文本
*/
public void appendText(String text) {
this .appendText(text, 0 );
}
/**
* 在距离当前 token 位置Offset距离的地方添加文本(offset可以为负数)
*/
public void appendText(String text, int offset) {
int pos = this .offset.getNewPos( this .scanner.getCurrentTokenStartPosition() + offset);
if (pos < 0 )
throw new RuntimeException( " 该Token所在的位置已经被删除或者修改过了 " );
int size = 0 ;
this .buffer.replace(pos, size, text);
this .offset.addChange(pos, 0 - size);
this .offset.addChange(pos, text.length());
}
/**
* 保存当前位置
*/
public int [] savePoint() {
return new int [] { this .scanner.getCurrentTokenStartPosition(), this .scanner.getCurrentTokenEndPosition() };
}
/**
* 恢复到保存的位置
*/
public void resetPoint( int [] savepoint) {
this .scanner.resetTo(savepoint[ 0 ], savepoint[ 1 ]);
}
/**
* 有2个相同的字符串Buffer,对一个Buffer进行Scan,然后在另外一个Buffer进行修改。
* 这个类就是将用来Scan的原始Buffer的原始位置,映射到新的被修改过的字符串位置
*/
private static class Offset {
private List changes = new ArrayList();
// 在新的位置修改(newsize < 0 代表删除)
protected void addChange( int newpos, int newsize) {
if (newsize == 0 )
return ;
this .changes.add( new int [] { newpos, newsize });
System.out.println( " changes: " + newpos + " " + newsize);
}
// 从老位置计算新位置 (返回 -1 代表已经被删除)
protected int getNewPos( int oldpos) {
int newpos = oldpos;
for ( int i = 0 ; i < this .changes.size(); i ++ ) {
int [] pos = ( int []) this .changes.get(i);
if (newpos >= pos[ 0 ]) {
if (pos[ 1 ] < 0 ) {
if (newpos + pos[ 1 ] < pos[ 0 ]) {
return - 1 ; // return pos[0]; ??? // 已经被删除
}
}
newpos += pos[ 1 ];
}
}
System.out.println( " pos: " + oldpos + " => " + newpos);
return newpos;
}
}
public static void main(String[] args) {
String s1 = " 0123456789012345678901234567890123456789012345678901234567890123456789 " ;
// "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
String s2 = s1;
Offset offset = new Offset();
s2 = testReplaceText(offset, s2, 4 , 5 , " @@@ " );
s2 = testAppendText(offset, s2, 10 , " %%%%%% " );
s2 = testReplaceText(offset, s2, 14 , 0 , " $$ " );
s2 = testAppendText(offset, s2, 32 , " ###### " );
s2 = testReplaceText(offset, s2, 44 , 3 , " ******** " );
s2 = testReplaceText(offset, s2, 24 , 5 , " @@@ " );
System.out.println(s2);
System.out.println("result = " + (s2.equals("0123@@@9%%%%%%0123$$4567890123@@@901######234567890123********78901234567890123456789")));
}
private static String testReplaceText(Offset offset, String s, int start, int size, String text) {
int pos = offset.getNewPos(start);
offset.addChange(pos, 0 - size);
offset.addChange(pos, text.length());
return StringUtils.left(s, pos) + text + StringUtils.right(s, s.length() - pos - size);
}
private static String testAppendText(Offset offset, String s, int start, String text) {
int pos = offset.getNewPos(start);
offset.addChange(pos, text.length());
return StringUtils.left(s, pos) + text + StringUtils.right(s, s.length() - pos);
}
}
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jdt.core. * ;
import org.eclipse.jdt.core.compiler.IScanner;
import org.eclipse.jdt.core.compiler.InvalidInputException;
public class ObjectScanBuffer {
private Offset offset = new Offset();
private IBuffer buffer;
private IScanner scanner;
public ObjectScanBuffer(IType objectClass) {
try {
ICompilationUnit cu = objectClass.getCompilationUnit();
this .buffer = cu.getBuffer();
this .scanner = ToolFactory.createScanner( false , false , false , false );
this .scanner.setSource( this .buffer.getCharacters());
// 不扫描 package 和 import 部分
ISourceRange sr = objectClass.getSourceRange();
this .scanner.resetTo(sr.getOffset(), sr.getOffset() + sr.getLength() - 1 );
} catch (JavaModelException e) {
throw new RuntimeException(e);
}
}
/**
* 返回下一个 Token
*/
public int getNextToken() throws InvalidInputException {
return this .scanner.getNextToken();
}
/**
* 查找 Token
*
* @param reset
* 为 true,那么如果没有找到,则会重置 scan 位置
*/
public boolean findToken( int token, boolean reset) throws InvalidInputException {
int [] savepoint = this .savePoint();
int t = this .scanner.getNextToken();
while (t != token) {
if (t <= 0 )
break ;
t = this .scanner.getNextToken();
}
if (t != token && reset) {
this .resetPoint(savepoint);
}
return t == token;
}
/**
* 查找 Token, 如果碰到 stopToken,则停止.
*
* @param reset
* 为 true,那么如果没有找到,则会重置 scan 位置
*/
public boolean findToken( int token, int stopToken, boolean reset) throws InvalidInputException {
int [] savepoint = this .savePoint();
int t = this .scanner.getNextToken();
while (t != token) {
if (t <= 0 )
break ;
if (t == stopToken)
break ;
t = this .scanner.getNextToken();
}
if (t != token && reset) {
this .resetPoint(savepoint);
}
return t == token;
}
/**
* 查找从 startToken 到 endToken 中间的所有 Tokens
*
* @param reset
* 为 true,那么如果没有找到,则会重置 scan 位置 (如果 startToken 找到,重置到 startToken)
* @return new Object[] { new Integer(token), tokenText }
*/
public List findTokensBetween( int startToken, int endToken, boolean reset) throws InvalidInputException {
List tokens = new ArrayList();
if ( this .findToken(startToken, reset)) {
int [] savepoint = this .savePoint();
int t = this .scanner.getNextToken();
while (t != endToken) {
if (t <= 0 )
break ;
tokens.add( new Object[] { new Integer(t), this .getTokenText() });
t = this .scanner.getNextToken();
}
if (t != endToken) {
tokens.clear();
if (reset) {
this .resetPoint(savepoint);
}
}
}
return tokens;
}
/**
* 在 findTokensBetween 返回中查找 是否存在 token
*/
public boolean existToken(List tokens, int token) {
for ( int i = 0 ; i < tokens.size(); i ++ ) {
Object[] t = (Object[]) tokens.get(i);
if (((Integer) t[ 0 ]).intValue() == token) {
return true ;
}
}
return false ;
}
/**
* 在 findTokensBetween 返回中查找 是否存在 tokenText
*/
public boolean existToken(List tokens, String tokenText) {
for ( int i = 0 ; i < tokens.size(); i ++ ) {
Object[] t = (Object[]) tokens.get(i);
if (StringUtils.equals((String) t[ 1 ], tokenText)) {
return true ;
}
}
return false ;
}
/**
* 返回当前的 Token 文本内容
*/
public String getTokenText() {
return new String( this .scanner.getCurrentTokenSource());
}
/**
* 返回下一个 Token 文本内容
*/
public String getNextTokenText() throws InvalidInputException {
this .scanner.getNextToken();
return this .getTokenText();
}
/**
* 当前 Token 前面是否存在 空格,或者回车符
*/
public boolean skipSpaces() {
int pos = this .offset.getNewPos( this .scanner.getCurrentTokenStartPosition() - 1 );
if (pos < 0 )
throw new RuntimeException( " 该Token所在的位置已经被删除或者修改过了 " );
String s = this .buffer.getText(pos, 1 );
char c = (s.length() == 1 ? s.charAt( 0 ) : ' /0' );
return c == ' ' || c == ' ' || c == ' ' ;
}
/**
* 用 text 替换 当前的 Token
*/
public void replaceText(String text) {
int pos = this .offset.getNewPos( this .scanner.getCurrentTokenStartPosition());
if (pos < 0 )
throw new RuntimeException( " 该Token所在的位置已经被删除或者修改过了 " );
int size = this .scanner.getCurrentTokenEndPosition() - this .scanner.getCurrentTokenStartPosition() + 1 ;
this .buffer.replace(pos, size, text);
this .offset.addChange(pos, 0 - size);
this .offset.addChange(pos, text.length());
}
/**
* 在当前 token 位置添加文本
*/
public void appendText(String text) {
this .appendText(text, 0 );
}
/**
* 在距离当前 token 位置Offset距离的地方添加文本(offset可以为负数)
*/
public void appendText(String text, int offset) {
int pos = this .offset.getNewPos( this .scanner.getCurrentTokenStartPosition() + offset);
if (pos < 0 )
throw new RuntimeException( " 该Token所在的位置已经被删除或者修改过了 " );
int size = 0 ;
this .buffer.replace(pos, size, text);
this .offset.addChange(pos, 0 - size);
this .offset.addChange(pos, text.length());
}
/**
* 保存当前位置
*/
public int [] savePoint() {
return new int [] { this .scanner.getCurrentTokenStartPosition(), this .scanner.getCurrentTokenEndPosition() };
}
/**
* 恢复到保存的位置
*/
public void resetPoint( int [] savepoint) {
this .scanner.resetTo(savepoint[ 0 ], savepoint[ 1 ]);
}
/**
* 有2个相同的字符串Buffer,对一个Buffer进行Scan,然后在另外一个Buffer进行修改。
* 这个类就是将用来Scan的原始Buffer的原始位置,映射到新的被修改过的字符串位置
*/
private static class Offset {
private List changes = new ArrayList();
// 在新的位置修改(newsize < 0 代表删除)
protected void addChange( int newpos, int newsize) {
if (newsize == 0 )
return ;
this .changes.add( new int [] { newpos, newsize });
System.out.println( " changes: " + newpos + " " + newsize);
}
// 从老位置计算新位置 (返回 -1 代表已经被删除)
protected int getNewPos( int oldpos) {
int newpos = oldpos;
for ( int i = 0 ; i < this .changes.size(); i ++ ) {
int [] pos = ( int []) this .changes.get(i);
if (newpos >= pos[ 0 ]) {
if (pos[ 1 ] < 0 ) {
if (newpos + pos[ 1 ] < pos[ 0 ]) {
return - 1 ; // return pos[0]; ??? // 已经被删除
}
}
newpos += pos[ 1 ];
}
}
System.out.println( " pos: " + oldpos + " => " + newpos);
return newpos;
}
}
public static void main(String[] args) {
String s1 = " 0123456789012345678901234567890123456789012345678901234567890123456789 " ;
// "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
String s2 = s1;
Offset offset = new Offset();
s2 = testReplaceText(offset, s2, 4 , 5 , " @@@ " );
s2 = testAppendText(offset, s2, 10 , " %%%%%% " );
s2 = testReplaceText(offset, s2, 14 , 0 , " $$ " );
s2 = testAppendText(offset, s2, 32 , " ###### " );
s2 = testReplaceText(offset, s2, 44 , 3 , " ******** " );
s2 = testReplaceText(offset, s2, 24 , 5 , " @@@ " );
System.out.println(s2);
System.out.println("result = " + (s2.equals("0123@@@9%%%%%%0123$$4567890123@@@901######234567890123********78901234567890123456789")));
}
private static String testReplaceText(Offset offset, String s, int start, int size, String text) {
int pos = offset.getNewPos(start);
offset.addChange(pos, 0 - size);
offset.addChange(pos, text.length());
return StringUtils.left(s, pos) + text + StringUtils.right(s, s.length() - pos - size);
}
private static String testAppendText(Offset offset, String s, int start, String text) {
int pos = offset.getNewPos(start);
offset.addChange(pos, text.length());
return StringUtils.left(s, pos) + text + StringUtils.right(s, s.length() - pos);
}
}
接下来,我们看一下具体的应用:
描述: 判断一个类是否已经实现 Java.io.Serializable, 如果没有实现,那么加入实现代码
public
void
generate(Shell parentShell, IType objectClass) {
System.out.println( " AddSerializableGenerator " );
IField existingFields = objectClass.getField( " serialVersionUID " );
try {
// import
ICompilationUnit cu = objectClass.getCompilationUnit();
cu.createImport( " java.io.Serializable " , null , null );
// field
if ( ! existingFields.exists()) {
IJavaElement insertPosition = null ;
if (objectClass.getMethods().length > 0 )
insertPosition = objectClass.getMethods()[ 0 ];
if (objectClass.getFields().length > 0 )
insertPosition = objectClass.getFields()[ 0 ];
String formattedContent = " private static final long serialVersionUID = " + RandomStringUtils.randomNumeric( 19 ) + " L; " ;
objectClass.createField(formattedContent, insertPosition, true , null );
}
// implements
if (cu.isWorkingCopy()) {
ObjectScanBuffer sb = new ObjectScanBuffer(objectClass);
List tokens = sb.findTokensBetween(ITerminalSymbols.TokenNameclass, ITerminalSymbols.TokenNameLBRACE, false );
if (sb.existToken(tokens, "Serializable")) {
System.out.println("Serializable interface has been implements");
return ;
}
if (sb.existToken(tokens, ITerminalSymbols.TokenNameimplements)) {
sb.appendText(", Serializable ");
} else {
if (!sb.skipSpaces())
sb.appendText(" ");
sb.appendText("implements Serializable " );
}
}
} catch (Exception e) {
MessageDialog.openError(parentShell, "Generation Failed " , e.getMessage());
}
}
System.out.println( " AddSerializableGenerator " );
IField existingFields = objectClass.getField( " serialVersionUID " );
try {
// import
ICompilationUnit cu = objectClass.getCompilationUnit();
cu.createImport( " java.io.Serializable " , null , null );
// field
if ( ! existingFields.exists()) {
IJavaElement insertPosition = null ;
if (objectClass.getMethods().length > 0 )
insertPosition = objectClass.getMethods()[ 0 ];
if (objectClass.getFields().length > 0 )
insertPosition = objectClass.getFields()[ 0 ];
String formattedContent = " private static final long serialVersionUID = " + RandomStringUtils.randomNumeric( 19 ) + " L; " ;
objectClass.createField(formattedContent, insertPosition, true , null );
}
// implements
if (cu.isWorkingCopy()) {
ObjectScanBuffer sb = new ObjectScanBuffer(objectClass);
List tokens = sb.findTokensBetween(ITerminalSymbols.TokenNameclass, ITerminalSymbols.TokenNameLBRACE, false );
if (sb.existToken(tokens, "Serializable")) {
System.out.println("Serializable interface has been implements");
return ;
}
if (sb.existToken(tokens, ITerminalSymbols.TokenNameimplements)) {
sb.appendText(", Serializable ");
} else {
if (!sb.skipSpaces())
sb.appendText(" ");
sb.appendText("implements Serializable " );
}
}
} catch (Exception e) {
MessageDialog.openError(parentShell, "Generation Failed " , e.getMessage());
}
}