Java tutorial
/** * jetbrick-template * http://subchen.github.io/jetbrick-template/ * * Copyright 2010-2014 Guoqiang Chen. All rights reserved. * Email: subchen@gmail.com * * Licensed 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 jetbrick.template.compiler; import java.io.*; import java.net.URL; import java.util.*; import jetbrick.template.utils.*; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.internal.compiler.*; import org.eclipse.jdt.internal.compiler.Compiler; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.env.*; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @since 1.2.3 * @author Guoqiang Chen */ public class JdtCompiler extends JavaCompiler { final Logger log = LoggerFactory.getLogger(JdtCompiler.class); @Override protected void generateJavaClass(JavaSource source) throws IOException { INameEnvironment env = new NameEnvironment(source); IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.proceedWithAllProblems(); CompilerOptions options = getCompilerOptions(); CompilerRequestor requestor = new CompilerRequestor(); IProblemFactory problemFactory = new DefaultProblemFactory(Locale.getDefault()); Compiler compiler = new Compiler(env, policy, options, requestor, problemFactory); compiler.compile(new ICompilationUnit[] { new CompilationUnit(source) }); if (requestor.hasErrors()) { String sourceCode = source.getSourceCode(); String[] sourceCodeLines = sourceCode.split("(\r\n|\r|\n)", -1); StringBuilder sb = new StringBuilder(); sb.append("Compilation failed."); sb.append('\n'); for (IProblem p : requestor.getErrors()) { sb.append(p.getMessage()).append('\n'); int start = p.getSourceStart(); int column = start; // default for (int i = start; i >= 0; i--) { char c = sourceCode.charAt(i); if (c == '\n' || c == '\r') { column = start - i; break; } } sb.append(StringUtils.getPrettyError(sourceCodeLines, p.getSourceLineNumber(), column, p.getSourceStart(), p.getSourceEnd(), 3)); } sb.append(requestor.getErrors().length); sb.append(" error(s)\n"); throw new CompileErrorException(sb.toString()); } requestor.save(source.getOutputdir()); } private CompilerOptions getCompilerOptions() { Map<String, String> settings = new HashMap<String, String>(); settings.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.GENERATE); settings.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.GENERATE); settings.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.IGNORE); settings.put(CompilerOptions.OPTION_Encoding, JavaSource.JAVA_FILE_ENCODING); settings.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE); settings.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_6); settings.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6); settings.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_6); CompilerOptions options = new CompilerOptions(settings); options.parseLiteralExpressionsAsConstants = true; return options; } static class CompilationUnit implements ICompilationUnit { final JavaSource source; public CompilationUnit(JavaSource source) { this.source = source; } @Override public char[] getFileName() { return source.getJavaFile().getAbsolutePath().toCharArray(); } @Override public char[] getContents() { return source.getSourceCode().toCharArray(); } @Override public char[] getMainTypeName() { String qualifiedClassName = source.getQualifiedClassName(); int dot = qualifiedClassName.lastIndexOf('.'); if (dot > 0) { return qualifiedClassName.substring(dot + 1).toCharArray(); } return qualifiedClassName.toCharArray(); } @Override public char[][] getPackageName() { StringTokenizer tokenizer = new StringTokenizer(source.getQualifiedClassName(), "."); char[][] result = new char[tokenizer.countTokens() - 1][]; for (int i = 0; i < result.length; i++) { String tok = tokenizer.nextToken(); result[i] = tok.toCharArray(); } return result; } @Override public boolean ignoreOptionalProblems() { return false; } } static class NameEnvironment implements INameEnvironment { static final Logger log = LoggerFactory.getLogger(NameEnvironment.class); final Map<String, Boolean> cache = new HashMap<String, Boolean>(); final ClassLoader classLoader; final JavaSource source; public NameEnvironment(JavaSource source) { this.source = source; this.classLoader = ClassLoaderUtils.getContextClassLoader(); } @Override public NameEnvironmentAnswer findType(char[][] compoundTypeName) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < compoundTypeName.length; i++) { if (i > 0) { sb.append('.'); } sb.append(compoundTypeName[i]); } return findType(sb.toString()); } @Override public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < packageName.length; i++) { sb.append(packageName[i]).append('.'); } sb.append(typeName); return findType(sb.toString()); } private NameEnvironmentAnswer findType(String className) { if (className.equals(source.getQualifiedClassName())) { return new NameEnvironmentAnswer(new CompilationUnit(source), null); } InputStream is = null; try { String resourceName = className.replace('.', '/') + ".class"; is = classLoader.getResourceAsStream(resourceName); if (is != null) { byte[] bytes = IoUtils.toByteArray(is); char[] fileName = resourceName.toCharArray(); ClassFileReader classFileReader = new ClassFileReader(bytes, fileName, true); return new NameEnvironmentAnswer(classFileReader, null); } } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException e) { log.error("Compilation error", e); } finally { IoUtils.closeQuietly(is); } return null; } @Override public boolean isPackage(char[][] parentPackageName, char[] packageName) { StringBuilder sb = new StringBuilder(); if (parentPackageName != null) { for (char[] p : parentPackageName) { sb.append(p).append('.'); } } sb.append(packageName); String name = sb.toString(); Boolean found = cache.get(name); if (found != null) { return found.booleanValue(); } boolean isPackage = !isJavaClass(name); cache.put(name, isPackage); return isPackage; } private boolean isJavaClass(String name) { if (name.equals(source.getQualifiedClassName())) { return true; } String resourceName = name.replace('.', '/') + ".class"; URL url = classLoader.getResource(resourceName); return url != null; } @Override public void cleanup() { } } static class CompilerRequestor implements ICompilerRequestor { static final Logger log = LoggerFactory.getLogger(CompilerRequestor.class); ClassFile[] classFiles; IProblem[] errors; @Override public void acceptResult(CompilationResult result) { if (result.hasErrors()) { errors = result.getErrors(); } else { classFiles = result.getClassFiles(); } } public boolean hasErrors() { return errors != null; } public IProblem[] getErrors() { return errors; } public ClassFile[] getClassFiles() { return classFiles; } public void save(File outputdir) throws IOException { if (classFiles == null) return; for (ClassFile classFile : classFiles) { String fileName = new String(classFile.fileName()) + ".class"; File javaClassFile = new File(outputdir, fileName); FileOutputStream fout = new FileOutputStream(javaClassFile); try { BufferedOutputStream bos = new BufferedOutputStream(fout); bos.write(classFile.getBytes()); bos.close(); } finally { IoUtils.closeQuietly(fout); } } } } }