1 /* 2 * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.javac.api; 27 28 import java.io.InputStream; 29 import java.io.OutputStream; 30 import java.io.OutputStreamWriter; 31 import java.io.PrintWriter; 32 import java.io.Writer; 33 import java.nio.charset.Charset; 34 import java.util.Collections; 35 import java.util.EnumSet; 36 import java.util.Locale; 37 import java.util.Objects; 38 import java.util.Set; 39 40 import javax.lang.model.SourceVersion; 41 import javax.tools.*; 42 43 import com.sun.source.util.JavacTask; 44 import com.sun.tools.javac.file.JavacFileManager; 45 import com.sun.tools.javac.main.Arguments; 46 import com.sun.tools.javac.main.Option; 47 import com.sun.tools.javac.file.BaseFileManager; 48 import com.sun.tools.javac.file.CacheFSInfo; 49 import com.sun.tools.javac.jvm.Target; 50 import com.sun.tools.javac.util.ClientCodeException; 51 import com.sun.tools.javac.util.Context; 52 import com.sun.tools.javac.util.DefinedBy; 53 import com.sun.tools.javac.util.DefinedBy.Api; 54 import com.sun.tools.javac.util.List; 55 import com.sun.tools.javac.util.Log; 56 import com.sun.tools.javac.util.PropagatedException; 57 58 /** 59 * TODO: describe com.sun.tools.javac.api.Tool 60 * 61 * <p><b>This is NOT part of any supported API. 62 * If you write code that depends on this, you do so at your own 63 * risk. This code and its internal interfaces are subject to change 64 * or deletion without notice.</b></p> 65 * 66 * @author Peter von der Ah\u00e9 67 */ 68 public final class JavacTool implements JavaCompiler { 69 /** 70 * Constructor used by service provider mechanism. The recommended way to 71 * obtain an instance of this class is by using {@link #create} or the 72 * service provider mechanism. 73 * @see javax.tools.JavaCompiler 74 * @see javax.tools.ToolProvider 75 * @see #create 76 */ 77 @Deprecated 78 public JavacTool() {} 79 80 // @Override // can't add @Override until bootstrap JDK provides Tool.name() 81 @DefinedBy(Api.COMPILER) 82 public String name() { 83 return "javac"; 84 } 85 86 /** 87 * Static factory method for creating new instances of this tool. 88 * @return new instance of this tool 89 */ 90 public static JavacTool create() { 91 return new JavacTool(); 92 } 93 94 @Override @DefinedBy(Api.COMPILER) 95 public JavacFileManager getStandardFileManager( 96 DiagnosticListener<? super JavaFileObject> diagnosticListener, 97 Locale locale, 98 Charset charset) { 99 Context context = new Context(); 100 context.put(Locale.class, locale); 101 if (diagnosticListener != null) 102 context.put(DiagnosticListener.class, diagnosticListener); 103 PrintWriter pw = (charset == null) 104 ? new PrintWriter(System.err, true) 105 : new PrintWriter(new OutputStreamWriter(System.err, charset), true); 106 context.put(Log.errKey, pw); 107 CacheFSInfo.preRegister(context); 108 return new JavacFileManager(context, true, charset); 109 } 110 111 @Override @DefinedBy(Api.COMPILER) 112 public JavacTask getTask(Writer out, 113 JavaFileManager fileManager, 114 DiagnosticListener<? super JavaFileObject> diagnosticListener, 115 Iterable<String> options, 116 Iterable<String> classes, 117 Iterable<? extends JavaFileObject> compilationUnits) { 118 Context context = new Context(); 119 return getTask(out, fileManager, diagnosticListener, 120 options, classes, compilationUnits, 121 context); 122 } 123 124 /* Internal version of getTask, allowing context to be provided. */ 125 public JavacTask getTask(Writer out, 126 JavaFileManager fileManager, 127 DiagnosticListener<? super JavaFileObject> diagnosticListener, 128 Iterable<String> options, 129 Iterable<String> classes, 130 Iterable<? extends JavaFileObject> compilationUnits, 131 Context context) 132 { 133 try { 134 ClientCodeWrapper ccw = ClientCodeWrapper.instance(context); 135 136 if (options != null) { 137 for (String option : options) 138 Objects.requireNonNull(option); 139 } 140 141 if (classes != null) { 142 for (String cls : classes) { 143 int sep = cls.indexOf('/'); // implicit null check 144 if (sep > 0) { 145 String mod = cls.substring(0, sep); 146 if (!SourceVersion.isName(mod)) 147 throw new IllegalArgumentException("Not a valid module name: " + mod); 148 cls = cls.substring(sep + 1); 149 } 150 if (!SourceVersion.isName(cls)) 151 throw new IllegalArgumentException("Not a valid class name: " + cls); 152 } 153 } 154 155 if (compilationUnits != null) { 156 compilationUnits = ccw.wrapJavaFileObjects(compilationUnits); // implicit null check 157 for (JavaFileObject cu : compilationUnits) { 158 if (cu.getKind() != JavaFileObject.Kind.SOURCE) { 159 String kindMsg = "Compilation unit is not of SOURCE kind: " 160 + "\"" + cu.getName() + "\""; 161 throw new IllegalArgumentException(kindMsg); 162 } 163 } 164 } 165 166 if (diagnosticListener != null) 167 context.put(DiagnosticListener.class, ccw.wrap(diagnosticListener)); 168 169 if (out == null) 170 context.put(Log.errKey, new PrintWriter(System.err, true)); 171 else 172 context.put(Log.errKey, new PrintWriter(out, true)); 173 174 if (fileManager == null) { 175 fileManager = getStandardFileManager(diagnosticListener, null, null); 176 if (fileManager instanceof BaseFileManager) { 177 ((BaseFileManager) fileManager).autoClose = true; 178 } 179 } 180 fileManager = ccw.wrap(fileManager); 181 182 context.put(JavaFileManager.class, fileManager); 183 184 Arguments args = Arguments.instance(context); 185 args.init("javac", options, classes, compilationUnits); 186 187 // init multi-release jar handling 188 if (fileManager.isSupportedOption(Option.MULTIRELEASE.primaryName) == 1) { 189 Target target = Target.instance(context); 190 List<String> list = List.of(target.multiReleaseValue()); 191 fileManager.handleOption(Option.MULTIRELEASE.primaryName, list.iterator()); 192 } 193 194 return new JavacTaskImpl(context); 195 } catch (PropagatedException ex) { 196 throw ex.getCause(); 197 } catch (ClientCodeException ex) { 198 throw new RuntimeException(ex.getCause()); 199 } 200 } 201 202 @Override @DefinedBy(Api.COMPILER) 203 public int run(InputStream in, OutputStream out, OutputStream err, String... arguments) { 204 if (err == null) 205 err = System.err; 206 for (String argument : arguments) 207 Objects.requireNonNull(argument); 208 return com.sun.tools.javac.Main.compile(arguments, new PrintWriter(err, true)); 209 } 210 211 @Override @DefinedBy(Api.COMPILER) 212 public Set<SourceVersion> getSourceVersions() { 213 return Collections.unmodifiableSet(EnumSet.range(SourceVersion.RELEASE_3, 214 SourceVersion.latest())); 215 } 216 217 @Override @DefinedBy(Api.COMPILER) 218 public int isSupportedOption(String option) { 219 Set<Option> recognizedOptions = Option.getJavacToolOptions(); 220 for (Option o : recognizedOptions) { 221 if (o.matches(option)) { 222 return o.hasArg() ? 1 : 0; 223 } 224 } 225 return -1; 226 } 227 228 }