/*
* Copyright ( c ) 2009 , 2014 , Oracle and / or its affiliates . All rights reserved .
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER .
*
* This code is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 only , as
* published by the Free Software Foundation . Oracle designates this
* particular file as subject to the " Classpath " exception as provided
* by Oracle in the LICENSE file that accompanied this code .
*
* This code is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* version 2 for more details ( a copy is included in the LICENSE file that
* accompanied this code ) .
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* Please contact Oracle , 500 Oracle Parkway , Redwood Shores , CA 94065 USA
* or visit www . oracle . com if you need additional information or have any
* questions .
*/
package genstubs;
import java.io.*;
import java.util.*;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.util.JavacTask;
import com.sun.tools.javac.api.JavacTool;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCImport;
import com.sun.tools.javac.tree.JCTree.JCLiteral;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.Pretty;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeScanner;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;
import javax.tools.JavaFileManager;
/**
* Generate stub source files by removing implementation details from input files .
*
* This is a special purpose stub generator , specific to the needs of generating
* stub files for JDK 7 API that are needed to compile langtools files that depend
* on that API . The stub generator works by removing as much of the API source code
* as possible without affecting the public signature , in order to reduce the
* transitive closure of the API being referenced . The resulting stubs can be
* put on the langtools sourcepath with - implicit : none to compile the langtools
* files that depend on the JDK 7 API .
*
* Usage :
* genstubs - s < outdir > - sourcepath < path > < classnames >
*
* The specified class names are looked up on the sourcepath , and corresponding
* stubs are written to the source output directory .
*
* Classes are parsed into javac ASTs , then processed with a javac TreeTranslator
* to remove implementation details , and written out in the source output directory .
* Documentation comments and annotations are removed . Method bodies are removed
* and methods are marked native . Private and package - private field definitions
* have their initializers replace with 0 , 0 . 0 , false , null as appropriate .
*/
public class GenStubs {
static class Fault extends Exception {
private static final long serialVersionUID = 0 ;
Fault(String message) {
super (message);
}
Fault(String message, Throwable cause) {
super (message);
initCause(cause);
}
}
public static void main(String[] args) {
boolean ok = new GenStubs().run(args);
if (!ok)
System.exit(1 );
}
public boolean run(String... args) {
File outdir = null ;
String sourcepath = null ;
List<String> classes = new ArrayList<String>();
for (ListIterator<String> iter = Arrays.asList(args).listIterator(); iter.hasNext(); ) {
String arg = iter.next();
if (arg.equals("-s" ) && iter.hasNext())
outdir = new File(iter.next());
else if (arg.equals("-sourcepath" ) && iter.hasNext())
sourcepath = iter.next();
else if (arg.startsWith("-" ))
throw new IllegalArgumentException(arg);
else {
classes.add(arg);
while (iter.hasNext())
classes.add(iter.next());
}
}
return run(sourcepath, outdir, classes);
}
public boolean run(String sourcepath, File outdir, List<String> classes) {
//System.err.println("run: sourcepath:" + sourcepath + " outdir:" + outdir + " classes:" + classes);
if (sourcepath == null )
throw new IllegalArgumentException("sourcepath not set" );
if (outdir == null )
throw new IllegalArgumentException("source output dir not set" );
JavacTool tool = JavacTool.create();
StandardJavaFileManager fm = tool.getStandardFileManager(null , null , null );
try {
fm.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(outdir));
fm.setLocation(StandardLocation.SOURCE_PATH, splitPath(sourcepath));
List<JavaFileObject> files = new ArrayList<JavaFileObject>();
for (String c: classes) {
JavaFileObject fo = fm.getJavaFileForInput(
StandardLocation.SOURCE_PATH, c, JavaFileObject.Kind.SOURCE);
if (fo == null )
error("class not found: " + c);
else
files.add(fo);
}
JavacTask t = tool.getTask(null , fm, null , null , null , files);
Iterable<? extends CompilationUnitTree> trees = t.parse();
for (CompilationUnitTree tree: trees) {
makeStub(fm, tree);
}
} catch (IOException e) {
error("IO error " + e, e);
}
return (errors == 0 );
}
void makeStub(StandardJavaFileManager fm, CompilationUnitTree tree) throws IOException {
CompilationUnitTree tree2 = new StubMaker().translate(tree);
CompilationUnitTree tree3 = new ImportCleaner(fm).removeRedundantImports(tree2);
String className = fm.inferBinaryName(StandardLocation.SOURCE_PATH, tree.getSourceFile());
JavaFileObject fo = fm.getJavaFileForOutput(StandardLocation.SOURCE_OUTPUT,
className, JavaFileObject.Kind.SOURCE, null );
// System.err.println("Writing " + className + " to " + fo.getName());
Writer out = fo.openWriter();
try {
new Pretty(out, true ).printExpr((JCTree) tree3);
} finally {
out.close();
}
}
List<File> splitPath(String path) {
List<File> list = new ArrayList<File>();
for (String p: path.split(File.pathSeparator)) {
if (p.length() > 0 )
list.add(new File(p));
}
return list;
}
void error(String message) {
System.err.println(message);
errors++;
}
void error(String message, Throwable cause) {
error(message);
}
int errors;
class StubMaker extends TreeTranslator {
CompilationUnitTree translate(CompilationUnitTree tree) {
return super .translate((JCCompilationUnit) tree);
}
/**
* compilation units : remove javadoc comments
* - - required , in order to remove @ deprecated tags , since we
* ( separately ) remove all annotations , including @ Deprecated
*/
public void visitTopLevel(JCCompilationUnit tree) {
super .visitTopLevel(tree);
tree.docComments = null ;
}
/**
* methods : remove method bodies , make methods native
*/
@Override
public void visitClassDef(JCClassDecl tree) {
long prevClassMods = currClassMods;
currClassMods = tree.mods.flags;
try {
super .visitClassDef(tree);
} finally {
currClassMods = prevClassMods;
}
}
private long currClassMods = 0 ;
/**
* methods : remove method bodies , make methods native
*/
@Override
public void visitMethodDef(JCMethodDecl tree) {
tree.mods = translate(tree.mods);
tree.restype = translate(tree.restype);
tree.typarams = translateTypeParams(tree.typarams);
tree.params = translateVarDefs(tree.params);
tree.thrown = translate(tree.thrown);
if (tree.body != null ) {
if ((currClassMods & Flags.INTERFACE ) != 0 ) {
tree.mods.flags &= ~(Flags.DEFAULT | Flags.STATIC );
} else {
tree.mods.flags |= Flags.NATIVE ;
}
tree.body = null ;
}
result = tree;
}
/**
* modifiers : remove annotations
*/
@Override
public void visitModifiers(JCModifiers tree) {
tree.annotations = com.sun.tools.javac.util.List.nil();
result = tree;
}
/**
* field definitions : replace initializers with 0 , 0 . 0 , false etc
* when possible - - i . e . leave public , protected initializers alone
*/
@Override
public void visitVarDef(JCVariableDecl tree) {
tree.mods = translate(tree.mods);
tree.vartype = translate(tree.vartype);
if (tree.init != null ) {
if ((tree.mods.flags & (Flags.PUBLIC | Flags.PROTECTED )) != 0 )
tree.init = translate(tree.init);
else {
String t = tree.vartype.toString();
if (t.equals("boolean" ))
tree.init = new JCLiteral(TypeTag.BOOLEAN , 0 ) { };
else if (t.equals("byte" ))
tree.init = new JCLiteral(TypeTag.BYTE , 0 ) { };
else if (t.equals("char" ))
tree.init = new JCLiteral(TypeTag.CHAR , 0 ) { };
else if (t.equals("double" ))
tree.init = new JCLiteral(TypeTag.DOUBLE , 0 .d) { };
else if (t.equals("float" ))
tree.init = new JCLiteral(TypeTag.FLOAT , 0 .f) { };
else if (t.equals("int" ))
tree.init = new JCLiteral(TypeTag.INT , 0 ) { };
else if (t.equals("long" ))
tree.init = new JCLiteral(TypeTag.LONG , 0 ) { };
else if (t.equals("short" ))
tree.init = new JCLiteral(TypeTag.SHORT , 0 ) { };
else
tree.init = new JCLiteral(TypeTag.BOT, null ) { };
}
}
result = tree;
}
}
class ImportCleaner extends TreeScanner {
private Set<Name> names = new HashSet<Name>();
private TreeMaker m;
ImportCleaner(JavaFileManager fm) {
// ImportCleaner itself doesn't require a filemanager, but instantiating
// a TreeMaker does, indirectly (via ClassReader, sigh)
Context c = new Context();
c.put(JavaFileManager.class , fm);
m = TreeMaker.instance(c);
}
CompilationUnitTree removeRedundantImports(CompilationUnitTree t) {
JCCompilationUnit tree = (JCCompilationUnit) t;
tree.accept(this );
ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
for (JCTree def: tree.defs) {
if (def.getTag() == JCTree.Tag.IMPORT ) {
JCImport imp = (JCImport) def;
if (imp.qualid.getTag() == JCTree.Tag.SELECT) {
JCFieldAccess qualid = (JCFieldAccess) imp.qualid;
if (!qualid.name.toString().equals("*" )
&& !names.contains(qualid.name)) {
continue ;
}
}
}
defs.add(def);
}
tree.defs = tree.defs.intersect(defs.toList());
return tree;
}
@Override
public void visitImport(JCImport tree) { } // ignore names found in imports
@Override
public void visitIdent(JCIdent tree) {
names.add(tree.name);
}
@Override
public void visitSelect(JCFieldAccess tree) {
super .visitSelect(tree);
names.add(tree.name);
}
}
}
Messung V0.5 in Prozent C=96 H=99 G=97
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland