Java是一个开放的平台,对于除发布编译器/解释器/基础类库之外,该语言的负责机构更多的是制定一系列标准,任何符合标准的厂商产品均可用于市场投放。甚至包括其编译器及解释器。

  (比如Hibernate提供了JPA实现;Tomcat实现了Java EE服务器标准,其Servlet容器通过了Java认证;各数据库或中间件厂商也根据JDBC接口开发驱动。说白了,Java基本就是都提供接口,然后让厂商开发实现,因此有时候我会骂,边骂边编码!)

  GCC有java编译器,可以看看。

  我们主要主要介绍Eclipse自己开发和使用的针对Java的编译器:(ecj) the Eclipse Compiler for Java。Eclipse没有使用JDK自带的编译器,而是自己开发的,ecj也通过了java的验证。

  除了Eclipse之外,Tomcat也用到了Ecj,用于动态编译jsp文件。我们安装Tomcat后可在lib文件夹下找到ecj:

  

  现在问题来了:怎么取得ecj源码呢?

  别急,我们从tomcat源码中查看一下:

  

  

  虽然我不熟ant,但我也能知道,Tomcat6.0.37中使用的ecj下载路径是:

  http://archive.eclipse.org/eclipse/downloads/drops4/R-4.2.2-201302041200/ecj-4.2.2.jar

  这个还是class文件,刚开始我也没辙,不过后来我灵机一动:在ecj后面加个src竟然成了!-_-

  http://archive.eclipse.org/eclipse/downloads/drops4/R-4.2.2-201302041200/ecjsrc-4.2.2.jar

  下面是我下载好后倒入项目文件后截图:

  

  

  这个文件报错,不过可以把他删除了看,我先没有删除,因为这个文件是ecj与ant的桥梁。从源码可以看出这个JDTCompilerAdapter是继承自ant的DefaultCompilerAdapter,用于ant的编译器适配器。个人感觉ecj从代码(技术)上并没有耦合任何一个调用者,这里的ant也只是一个适配器,你删除或者留着没有任何影响。Tomcat里也没有使用ant。

  我从这里主要是想看看高层怎么调用ecj来编译代码,我们看看关键代码:

  

 private static String compilerClass = "org.eclipse.jdt.internal.compiler.batch.Main"; //$NON-NLS-1$

 /**
* Performs a compile using the JDT batch compiler
* @throws BuildException if anything wrong happen during the compilation
* @return boolean true if the compilation is ok, false otherwise
*/
public boolean execute() throws BuildException {
this.attributes.log(AntAdapterMessages.getString("ant.jdtadapter.info.usingJDTCompiler"), Project.MSG_VERBOSE); //$NON-NLS-1$
Commandline cmd = setupJavacCommand(); try {
Class c = Class.forName(compilerClass);
Constructor batchCompilerConstructor =
c.getConstructor(new Class[] {
PrintWriter.class,
PrintWriter.class,
Boolean.TYPE,
Map.class});
Object batchCompilerInstance =
batchCompilerConstructor.newInstance(new Object[] {
new PrintWriter(System.out),
new PrintWriter(System.err),
Boolean.TRUE,
this.customDefaultOptions});
Method compile =
c.getMethod("compile", new Class[] {String[].class}); //$NON-NLS-1$
Object result =
compile.invoke(batchCompilerInstance, new Object[] {
cmd.getArguments()});
final boolean resultValue = ((Boolean) result).booleanValue();
if (!resultValue && this.logFileName != null) {
this.attributes.log(AntAdapterMessages.getString("ant.jdtadapter.error.compilationFailed", this.logFileName)); //$NON-NLS-1$
}
return resultValue;
} catch (ClassNotFoundException cnfe) {
throw new BuildException(AntAdapterMessages.getString("ant.jdtadapter.error.cannotFindJDTCompiler")); //$NON-NLS-1$
} catch (Exception ex) {
throw new BuildException(ex);
}
}

  我把代码换了下行,大家看13和26行,可以看出这里使用了

  org.eclipse.jdt.internal.compiler.batch.Main#compile(String[])方法来进行编译,我们可以稍微看看:

  从源码上来看1664是配置,1684可能是编译,不过我们先不细看。

  我们再看看Tomcat怎么使用ecj的,我们查看org.apache.jasper.compiler.JDTCompiler源码(我贴出了源码,不过有点长):

  

 /*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.apache.jasper.compiler; import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer; import org.apache.jasper.JasperException;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.ClassFile;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.Compiler;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
import org.eclipse.jdt.internal.compiler.IProblemFactory;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; /**
* JDT class compiler. This compiler will load source dependencies from the
* context classloader, reducing dramatically disk access during
* the compilation process.
*
* @author Cocoon2
* @author Remy Maucherat
*/
public class JDTCompiler extends org.apache.jasper.compiler.Compiler { /**
* Compile the servlet from .java file to .class file
*/
protected void generateClass(String[] smap)
throws FileNotFoundException, JasperException, Exception { long t1 = 0;
if (log.isDebugEnabled()) {
t1 = System.currentTimeMillis();
} final String sourceFile = ctxt.getServletJavaFileName();
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
String packageName = ctxt.getServletPackageName();
final String targetClassName =
((packageName.length() != 0) ? (packageName + ".") : "")
+ ctxt.getServletClassName();
final ClassLoader classLoader = ctxt.getJspLoader();
String[] fileNames = new String[] {sourceFile};
String[] classNames = new String[] {targetClassName};
final ArrayList problemList = new ArrayList(); class CompilationUnit implements ICompilationUnit { String className;
String sourceFile; CompilationUnit(String sourceFile, String className) {
this.className = className;
this.sourceFile = sourceFile;
} public char[] getFileName() {
return sourceFile.toCharArray();
} public char[] getContents() {
char[] result = null;
FileInputStream is = null;
try {
is = new FileInputStream(sourceFile);
Reader reader =
new BufferedReader(new InputStreamReader(is, ctxt.getOptions().getJavaEncoding()));
if (reader != null) {
char[] chars = new char[8192];
StringBuffer buf = new StringBuffer();
int count;
while ((count = reader.read(chars, 0,
chars.length)) > 0) {
buf.append(chars, 0, count);
}
result = new char[buf.length()];
buf.getChars(0, result.length, result, 0);
}
} catch (IOException e) {
log.error("Compilation error", e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException exc) {
// Ignore
}
}
}
return result;
} public char[] getMainTypeName() {
int dot = className.lastIndexOf('.');
if (dot > 0) {
return className.substring(dot + 1).toCharArray();
}
return className.toCharArray();
} public char[][] getPackageName() {
StringTokenizer izer =
new StringTokenizer(className, ".");
char[][] result = new char[izer.countTokens()-1][];
for (int i = 0; i < result.length; i++) {
String tok = izer.nextToken();
result[i] = tok.toCharArray();
}
return result;
} public boolean ignoreOptionalProblems() {
return false;
}
} final INameEnvironment env = new INameEnvironment() { public NameEnvironmentAnswer
findType(char[][] compoundTypeName) {
String result = "";
String sep = "";
for (int i = 0; i < compoundTypeName.length; i++) {
result += sep;
result += new String(compoundTypeName[i]);
sep = ".";
}
return findType(result);
} public NameEnvironmentAnswer
findType(char[] typeName,
char[][] packageName) {
String result = "";
String sep = "";
for (int i = 0; i < packageName.length; i++) {
result += sep;
result += new String(packageName[i]);
sep = ".";
}
result += sep;
result += new String(typeName);
return findType(result);
} private NameEnvironmentAnswer findType(String className) { InputStream is = null;
try {
if (className.equals(targetClassName)) {
ICompilationUnit compilationUnit =
new CompilationUnit(sourceFile, className);
return
new NameEnvironmentAnswer(compilationUnit, null);
}
String resourceName =
className.replace('.', '/') + ".class";
is = classLoader.getResourceAsStream(resourceName);
if (is != null) {
byte[] classBytes;
byte[] buf = new byte[8192];
ByteArrayOutputStream baos =
new ByteArrayOutputStream(buf.length);
int count;
while ((count = is.read(buf, 0, buf.length)) > 0) {
baos.write(buf, 0, count);
}
baos.flush();
classBytes = baos.toByteArray();
char[] fileName = className.toCharArray();
ClassFileReader classFileReader =
new ClassFileReader(classBytes, fileName,
true);
return
new NameEnvironmentAnswer(classFileReader, null);
}
} catch (IOException exc) {
log.error("Compilation error", exc);
} catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException exc) {
log.error("Compilation error", exc);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException exc) {
// Ignore
}
}
}
return null;
} private boolean isPackage(String result) {
if (result.equals(targetClassName)) {
return false;
}
String resourceName = result.replace('.', '/') + ".class";
InputStream is =
classLoader.getResourceAsStream(resourceName);
return is == null;
} public boolean isPackage(char[][] parentPackageName,
char[] packageName) {
String result = "";
String sep = "";
if (parentPackageName != null) {
for (int i = 0; i < parentPackageName.length; i++) {
result += sep;
String str = new String(parentPackageName[i]);
result += str;
sep = ".";
}
}
String str = new String(packageName);
if (Character.isUpperCase(str.charAt(0))) {
if (!isPackage(result)) {
return false;
}
}
result += sep;
result += str;
return isPackage(result);
} public void cleanup() {
} }; final IErrorHandlingPolicy policy =
DefaultErrorHandlingPolicies.proceedWithAllProblems(); final Map settings = new HashMap();
settings.put(CompilerOptions.OPTION_LineNumberAttribute,
CompilerOptions.GENERATE);
settings.put(CompilerOptions.OPTION_SourceFileAttribute,
CompilerOptions.GENERATE);
settings.put(CompilerOptions.OPTION_ReportDeprecation,
CompilerOptions.IGNORE);
if (ctxt.getOptions().getJavaEncoding() != null) {
settings.put(CompilerOptions.OPTION_Encoding,
ctxt.getOptions().getJavaEncoding());
}
if (ctxt.getOptions().getClassDebugInfo()) {
settings.put(CompilerOptions.OPTION_LocalVariableAttribute,
CompilerOptions.GENERATE);
} // Source JVM
if(ctxt.getOptions().getCompilerSourceVM() != null) {
String opt = ctxt.getOptions().getCompilerSourceVM();
if(opt.equals("1.1")) {
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_1);
} else if(opt.equals("1.2")) {
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_2);
} else if(opt.equals("1.3")) {
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_3);
} else if(opt.equals("1.4")) {
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_4);
} else if(opt.equals("1.5")) {
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_5);
} else if(opt.equals("1.6")) {
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_6);
} else if(opt.equals("1.7")) {
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_7);
} else {
log.warn("Unknown source VM " + opt + " ignored.");
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_5);
}
} else {
// Default to 1.5
settings.put(CompilerOptions.OPTION_Source,
CompilerOptions.VERSION_1_5);
} // Target JVM
if(ctxt.getOptions().getCompilerTargetVM() != null) {
String opt = ctxt.getOptions().getCompilerTargetVM();
if(opt.equals("1.1")) {
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_1);
} else if(opt.equals("1.2")) {
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_2);
} else if(opt.equals("1.3")) {
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_3);
} else if(opt.equals("1.4")) {
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_4);
} else if(opt.equals("1.5")) {
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_5);
settings.put(CompilerOptions.OPTION_Compliance,
CompilerOptions.VERSION_1_5);
} else if(opt.equals("1.6")) {
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_6);
settings.put(CompilerOptions.OPTION_Compliance,
CompilerOptions.VERSION_1_6);
} else if(opt.equals("1.7")) {
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_7);
settings.put(CompilerOptions.OPTION_Compliance,
CompilerOptions.VERSION_1_7);
} else {
log.warn("Unknown target VM " + opt + " ignored.");
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_5);
}
} else {
// Default to 1.5
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_5);
settings.put(CompilerOptions.OPTION_Compliance,
CompilerOptions.VERSION_1_5);
} final IProblemFactory problemFactory =
new DefaultProblemFactory(Locale.getDefault()); final ICompilerRequestor requestor = new ICompilerRequestor() {
public void acceptResult(CompilationResult result) {
try {
if (result.hasProblems()) {
IProblem[] problems = result.getProblems();
for (int i = 0; i < problems.length; i++) {
IProblem problem = problems[i];
if (problem.isError()) {
String name =
new String(problems[i].getOriginatingFileName());
try {
problemList.add(ErrorDispatcher.createJavacError
(name, pageNodes, new StringBuffer(problem.getMessage()),
problem.getSourceLineNumber(), ctxt));
} catch (JasperException e) {
log.error("Error visiting node", e);
}
}
}
}
if (problemList.isEmpty()) {
ClassFile[] classFiles = result.getClassFiles();
for (int i = 0; i < classFiles.length; i++) {
ClassFile classFile = classFiles[i];
char[][] compoundName =
classFile.getCompoundName();
String className = "";
String sep = "";
for (int j = 0;
j < compoundName.length; j++) {
className += sep;
className += new String(compoundName[j]);
sep = ".";
}
byte[] bytes = classFile.getBytes();
String outFile = outputDir + "/" +
className.replace('.', '/') + ".class";
FileOutputStream fout =
new FileOutputStream(outFile);
BufferedOutputStream bos =
new BufferedOutputStream(fout);
bos.write(bytes);
bos.close();
}
}
} catch (IOException exc) {
log.error("Compilation error", exc);
}
}
}; ICompilationUnit[] compilationUnits =
new ICompilationUnit[classNames.length];
for (int i = 0; i < compilationUnits.length; i++) {
String className = classNames[i];
compilationUnits[i] = new CompilationUnit(fileNames[i], className);
}
Compiler compiler = new Compiler(env,
policy,
settings,
requestor,
problemFactory,
true);
compiler.compile(compilationUnits); if (!ctxt.keepGenerated()) {
File javaFile = new File(ctxt.getServletJavaFileName());
javaFile.delete();
} if (!problemList.isEmpty()) {
JavacErrorDetail[] jeds =
(JavacErrorDetail[]) problemList.toArray(new JavacErrorDetail[0]);
errDispatcher.javacError(jeds);
} if( log.isDebugEnabled() ) {
long t2=System.currentTimeMillis();
log.debug("Compiled " + ctxt.getServletJavaFileName() + " "
+ (t2-t1) + "ms");
} if (ctxt.isPrototypeMode()) {
return;
} // JSR45 Support
if (! options.isSmapSuppressed()) {
SmapUtil.installSmap(smap);
} } }

TomcatAdapter

  

  从427可以知道,Tomcat使用了org.eclipse.jdt.internal.compiler.Compiler#compile(ICompilationUnit[])

  当然,在这之前使用了很多代码来进行配置。

  第一篇文章就到这里。

欢迎您移步我们的交流群,无聊的时候大家一起打发时间:

或者通过QQ与我联系:

(最后编辑时间2014-01-18 13:59:01)

(ecj)Eclipse的Java编译器分析之一——ecj介绍的更多相关文章

  1. eclipse 项目资源与 java 编译器级别不致总是;说明资源路径位置类型Java编译器级别不匹配t

    问题:Description Resource Path Location Type Java compiler level does not match t 今天在自己项目中整合HBase API的 ...

  2. Java 性能分析工具 , 第 3 部分: Java Mission Control

    引言 本文为 Java 性能分析工具系列文章第三篇,这里将介绍如何使用 Java 任务控制器 Java Mission Control 深入分析 Java 应用程序的性能,为程序开发人员在使用 Jav ...

  3. Java 性能分析工具 , 第 2 部分:Java 内置监控工具

    引言 本文为 Java 性能分析工具系列文章第二篇,第一篇:操作系统工具.在本文中将介绍如何使用 Java 内置监控工具更加深入的了解 Java 应用程序和 JVM 本身.在 JDK 中有许多内置的工 ...

  4. windows 下用eclipse搭建java、python开发环境

    本人只针对小白!本文只针对小白!本文只针对小白! 最近闲来无事,加上之前虽没有做过eclipse上java.python的开发工作,但一直想尝试一下.于是边查找资料边试验,花了一天时间在自己的机器上用 ...

  5. Java编译器如何生成重载和覆盖方法代码

    下面是一个很简单的例子,关于Java中的多态:方法重载和方法覆盖: 多态指的是方法在不同的时刻表现出不同的形式:在编译期间,这被叫做方法重载:方法重载允许相关的方法被同一个方法名字调用,这有时候被叫做 ...

  6. JavaWeb学习----JSP简介及入门(含Eclipse for Java EE及Tomcat的配置)

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  7. java代码分析及分析工具

    一个项目从搭建开始,开发的初期往往思路比较清晰,代码也比较清晰.随着时间的推移,业务越来越复杂.代码也就面临着耦合,冗余,甚至杂乱,到最后谁都不敢碰. 作为一个互联网电子商务网站的业务支撑系统,业务复 ...

  8. [置顶] JDK工具(一)–Java编译器javac

    1.概述    javac.exe: Java编译器,将Java源代码转换成字节码. 2.用法    javac <选项> <源文件> (使用过程中发现,javac <源 ...

  9. Java编译器、JVM、解释器

    Java虚拟机(JVM)是可运行Java代码的假想计算机.只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的任何Java代码能够在该系统上运行.本文首先简要介绍从Java文件的编译 ...

随机推荐

  1. CustomJsonDateDeserializer @JsonDeserialize(using = CustomJsonDateDeserializer.class) Jackson 反序列化Date时遇到的问题 java中json日期属性反序列化

    public class CustomJsonDateDeserializer extends JsonDeserializer<Date> { @Override public Date ...

  2. 微信小程序无法获取UnionId的情况及处理

    问题背景:做了微信小程序,一切都还正常,但是最后体验版放出去时,却发现很多用户无法绑定用户,后台返回:参数非法.经过多方排查,发现是微信拿到的code请求返回的数据里没有UnionId,也就是接口返回 ...

  3. 为什么用svg放弃了iconfont?

    svg替代iconfont的好处(无论是基于Vue.Jquery),都推荐svg http://www.woshipm.com/pd/463866.html svg图标库,svg图标在线制作 http ...

  4. 微软BI 之SSIS 系列 - 平面文件格式的区别(Delimited,Fixed width,Ragged Right, Fixed width ...)

    开篇介绍 SSIS 中处理文件,一般在描述输出平面文件格式的时候通常会出现以下几种选项: Delimited - 默认输出列使用逗号分隔,也可以选择其它的诸如 | ,或者 Tab 等. Fixed W ...

  5. expdp ORA-39070:Unable to open the log file

    Oracle中,当执行expdp或impdp的时候,有时候会出现错误: [oracle@bi-dw ~]$ expdp dp_user/dp_password@dw directory=expdp_d ...

  6. aaronyang的百度地图API之LBS云与.NET开发 Javascript API 2.0【把数据存到LBS云2/2】

    中国的IT 需要无私分享和贡献的人,一起努力 本篇博客来自地址:http://www.cnblogs.com/AaronYang/p/3672898.html,请支持原创,未经允许不许转载 1.新建一 ...

  7. Cortex-A15架构解析:它为什么这么强(转)

    今年的新手机趋势无异是全面向四核靠拢,不过同样是四核,在实际的性能上其实是千差万别.例如针对入门级主流市场的四核手机普遍采用的都是Cortex-A7以及 Cortex-A9 级别的CPU内核,这类内核 ...

  8. post请求数据量过大,提交失败

    HttpRuntimeSection.MaxRequestLength 属性,请求的最大大小(以千字节为单位). 默认大小为 4096 KB (4 MB) <system.web> < ...

  9. java框架篇---hibernate之缓存机制

    一.why(为什么要用Hibernate缓存?) Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数 ...

  10. 前台报错:Uncaught TypeError: Cannot read property '0' of null

    错误现象: var div1=mycss[0].style.backgroundColor;  //这一行提示360和chrome提示:Uncaught TypeError: Cannot read  ...