Eclipse plugins 插件开发学习 - IScanner 和 IBuffer 封装的高级应用类

Java Serializable辅助生成工具
本文介绍了一款用于Java项目的辅助工具,旨在简化Serializable接口的添加过程。通过此工具,开发者可以轻松地为类添加实现Serializable所需的 serialVersionUID 字段,并确保类声明实现Serializable接口。
由于 IScanner 和 IBuffer 修改源码比较麻烦,功能也不是很强大,需要编写大量的代码。

所以这里谢了一个辅助类,来改善代码。

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(falsefalsefalsefalse);
            
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, 45"@@@");
        s2 
= testAppendText(offset, s2, 10"%%%%%%");
        s2 
= testReplaceText(offset, s2, 140"$$");
        s2 
= testAppendText(offset, s2, 32"######");
        s2 
= testReplaceText(offset, s2, 443"********");
        s2 
= testReplaceText(offset, s2, 245"@@@");
        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"nullnull);

            
// 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, 
truenull);
            }

            
// 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());
        }
    }

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值