编写一个不错的开源项目至少有3个好处:
(1)练技术,长经验
(2)面试时展现自己的Coding能力
(3)获取成就感
练技术,长经验是最实在的,不过如果自己有一个好的开源项目,还可以在开源中国或github上开源,让更多人受益,也许能获得许多的Star,让自已获得满足,激励自己完善项目功能。在面试时,也可以在简历显眼的位置给出开源项目名称和Git地址。面试官一般都会去查看,这是程序员实力的最好见证,是自己Coding能力的最好见证。所以如果要编写一个面试时拿的出手的项目,首先需要做到“规范”,下面谈一下我眼中规范的开源项目。
1 项目规范
1.1 规范编写README.md
README.md文件是一个项目的入门手册,里面介绍了整个项目的使用、功能等等。所以README文件写得好不好,关系到这个项目能不能更容易的被其他人了解和使用。
首先最起码要做到的就是格式要清晰,让人一眼能看出层次感,例如分几个大标题对项目进行介绍,最简单的就是分为如下的4部分:
- 项目名及简介:简单介绍一下这个项目是做什么的。有的话最好加上demo地址;
- 功能:你这个项目可以实现的功能;
- 用法:这可以说是最重要的,一定要让别人看得懂你这项目是怎么使用的;
- 其他:作者或者是维护人列表、版权、鸣谢、贡献、logo、联系方式等等,这些有的话当然会更加高大上。
1.2 使用版本管理工具
1.3 好的代码书写习惯
1.4 有完整的测试用例
2 Javac AST View插件的开发
2.1 项目介绍
开发一个类似Eclipse AST View的插件,安装的过程见如下博文:
https://www.cnblogs.com/nettee/p/4463841.html
这个插件的详细使用说明的链接如下:
https://www.eclipse.org/jdt/ui/astview/
安装后就可以直观地查看抽象语法树了,举个例子,如下:
package com.compiler;
import java.util.List;
public class C {
public void test(List<String> list){
list.add("a");
}
}
语法树如下:
不过这个插件显示的是基于Eclipse JDT中的增量式编译器ECJ的抽象语法树,而我们经常使用的OpenJDK中的Javac编译器的抽象语法树与ECJ的抽象语法树并不相同,不过绝大多数的语法树节点划分是一样的,但是有少量的节点划分不一样,我打算开发一个类似Eclipse AST View的插件,用来显示Javac编译器的抽象语法树。
2.2 项目知识储备
开发这样的插件需要了解JDT编译器和Javac编译器的抽象语法树,同时还需要掌握Eclipse下的插件开发,参考的相关资源如下:
第一本就是《Eclipse插件开发学习笔记》,开发Eclipse插件必须要有插件开发相关基础,这本书发版时间很早,但是插件开发的基本思想是不会变的。另外官方的Eclipse API也是开发中必不可少的资料。
Eclipse JDT中的增量式编译器ECJ的抽象语法树可以通过博文Eclipse AST抽象语法树API来了解,没有相关的书籍。不过由于是在Eclipse中开发插件,所以直接调用Eclipse相关API来获取抽象语法树就可以了,不需要自已编写Java源代码转换为抽象语法树的代码实现。所以Eclipse AST View整个项目的实现也相对简单。
不得不说,阅读别人的代码也是学习的最好方式之一。
2.3 编写项目框架
编写的插件中主要使用了树插件,JFace为树控件提供了查看器Viewer。在查看器框架中,将模型称为输入,查看器本身充当控制器的角色,而树控件本身作为视图,当输入改变时,查看器负责相应地改变控件的内容。
查看器框架主要由以下几部分构成。
(1)模型和元素-存储着要显示在控件中的数据模型,我们编写的抽象语法树节点模型如下:
package astview;
import java.util.ArrayList;
import java.util.List;
public class JavacASTNode {
private int id;
private String name;
private List<JavacASTNode> children;
private JavacASTNode parent = null;
public JavacASTNode() {
children = new ArrayList<JavacASTNode>();
}
public List<JavacASTNode> getChildren() {
return children;
}
public void setChildren(List<JavacASTNode> children) {
this.children = children;
}
public JavacASTNode getParent() {
return parent;
}
public void setParent(JavacASTNode parent) {
this.parent = parent;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
(2)内容提供者和标签提供者-负责将数据模型转化成可以显示的图片和文字。我编写的内容提供者如下:
class ViewContentProvider extends ArrayContentProvider implements ITreeContentProvider {
public Object[] getChildren(Object parentElement) {
JavacASTNode node = (JavacASTNode) parentElement;
return node.getChildren().toArray();
}
public Object getParent(Object element) {
JavacASTNode node = (JavacASTNode) element;
return node.getParent();
}
public boolean hasChildren(Object element) {
JavacASTNode node = (JavacASTNode) element;
return node.getChildren().size() > 0 ? true : false;
}
public Object[] getElements(Object inputElement) {
JavacASTNode compilatinUnitNode = new JavacASTNode();
compilatinUnitNode.setId(001);
compilatinUnitNode.setName("JCCompilationUnit");
JavacASTNode importNode = new JavacASTNode();
importNode.setId(002);
importNode.setName("JCImport");
JavacASTNode classNode = new JavacASTNode();
classNode.setId(003);
classNode.setName("JCClassDecl");
compilatinUnitNode.getChildren().add(importNode);
compilatinUnitNode.getChildren().add(classNode);
importNode.setParent(compilatinUnitNode);
classNode.setParent(compilatinUnitNode);
return new JavacASTNode[] {compilatinUnitNode};
}
}
这个类是JavacTreeViewer的内部类。我们只简单写了一些测试用的数据,其实这些数据都是要从Javac编译器中读取的,而Javac编译器分析的Java源代码又需要从当前激活的编辑器中获取,后面我会不断完善更新这些功能。
编写的标签提供者如下:
class ViewLabelProvider extends LabelProvider {
public Image getColumnImage(Object element) {
return null;
}
public String getColumnText(Object element) {
return ((JavacASTNode) element).toString();
}
}
这个类也同样是JavacTreeViewer的内部类。
(3)控件,用来显示内容,这里用到的为树控件TreeViewer
(4)查看器
模型和元素以及内容提供者和标签提供者需要自己编写,控件和查看器不需要开发者自己编写。
编写JavacTreeViewer类,如下:
package astview;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
public class JavacASTViewer extends ViewPart {
public static final String ID = "javacastviewer";
private TreeViewer fViewer;
public void createPartControl(Composite parent) {
fViewer = new TreeViewer(parent, SWT.SINGLE);
fViewer.setLabelProvider(new ViewLabelProvider());
fViewer.setContentProvider(new ViewContentProvider());
fViewer.setInput(getSite());
}
public void setFocus() {
// not supported
}
...
}
最后运行后,查看JavacTreeViewer视图,显示效果如下:
最后就是上传到github了,我的github仓库地址为:
https://gitee.com/mazhimazh/JavacASTViewer
接下来我会不断开发完善这个项目,如果各位能给个“Star”是最好了,你的支持是我继续开发的最大动力。