from command-line i can get a alias list of the function renaming from compiler.jar
Help says:
java -jar compiler.jar --help
[...]
--create_name_map_files : If true, variable renaming and
property renaming map files will be
produced as {binary name}_vars_map.out
and {binary name}_props_map.out. Note
that this flag cannot be used in
conjunction with either variableMapOut
putFile or property_map_output_file
--create_source_map VAL : If specified, a source map file
mapping the generated source files
back to the original source file will
be output to the specified path. The
%outname% placeholder will expand to
the name of the output file that the
source map corresponds to.
[...]
so, how can i get "create_name_map_files" from inline java? i took a look into the AbstractCommandLineRunner.java but all classes/methods which relate to this command line option are private and not reachable from my code..
My Code:
CompilerOptions opt = new CompilerOptions();
// decide mode
compilationLevel.ADVANCED_OPTIMIZATIONS.setOptionsForCompilationLevel(opt);
opt.prettyPrint = false;
Compiler.setLoggingLevel(Level.OFF);
Compiler compressor = new Compiler();
compressor.disableThreads();
List<SourceFile> inputs = ...;
List<SourceFile> externs = ...;
compressor.compile(externs, inputs, opt);
you can just use the option : variable_map_output_file filename , similarly for props.
Note that: The flags variable_map_output_file and create_name_map_files cannot both be used simultaniously.
From CommandLineRunner.java, I would say
opt.setCreateNameMapFiles(true)
The "compile" function returns a Result object that contains the variable (variableMap) and property (propertyMap) renaming maps. These properties contain VariableMap objects that can be serialized:
Result result = compiler.compiler(...);
result.variableMap.save(varmapPath);
result.propertyMap.save(propmapPath);
Related
I tried the commmand line option:
-D sys.fullName=CustomName
but to no effect (empty full name).
The help mentions that only variables defined on the "General Settings->Compiler Variables" step can be overridden like this.
Does that mean I have to create an additional 'intermediate' compiler variable and place it in the Full Name field with ${compiler:intermediate_full_name_variable}?
(v8.0.11)
I tried the approach with the intermediate compiler variable, but now I have the problem that the localization does not work:
-D intermediate_full_name_variable=Custom Name ${i18n:msgkey}
Results in "Welcome to Custom Name messages not found Setup Assistant". I double checked that the language files and keys exist.
Does that mean I have to create an additional 'intermediate' compiler variable and
place it in the Full Name field with ${compiler:intermediate_full_name_variable}?
That is correct.
now I have the problem that the localization does not work:
You could set the "Full name" field to ${i18:myFullName} and define a message key "myFullName" that includes a compiler variable, like
myFullName=${compiler:productName} Setup Assistant
You can then pass -D productName=Custom name on the command line.
I am trying to remotely invoke an MBean via a commandline. Right now, I am able to list attributes and operations. For example, I can list all the attributes and operations for HotspotDiagnostic using this command:
java -jar cmdline-jmxclient-0.10.3.jar admin:P#sSw0rd 10.11.12.13:1111 com.sun.management:type=HotSpotDiagnostic
Which gives me this list of Attributes and Operations
Attributes:
DiagnosticOptions: DiagnosticOptions (type=[Ljavax.management.openmbean.CompositeData;)
ObjectName: ObjectName (type=javax.management.ObjectName)
Operations:
dumpHeap: dumpHeap
Parameters 2, return type=void
name=p0 type=java.lang.String p0
name=p1 type=boolean p1
getVMOption: getVMOption
Parameters 1, return type=javax.management.openmbean.CompositeData
name=p0 type=java.lang.String p0
setVMOption: setVMOption
Parameters 2, return type=void
name=p0 type=java.lang.String p0
name=p1 type=java.lang.String p1
But now lets say I want to invoke the dumpHeap operation which takes two parameters p0 and p1 of type string and boolean, respectively. How would I pass those arguments in?
I've tried these:
java -jar cmdline-jmxclient-0.10.3.jar admin:P#sSw0rd10.11.12.13:1111 com.sun.management:type=HotSpotDiagnostic dumpHeap p0=aaa p1=true
java -jar cmdline-jmxclient-0.10.3.jar admin:P#sSw0rd10.11.12.13:1111 com.sun.management:type=HotSpotDiagnostic dumpHeap aaa true
But I'm not sure what the syntax is, or even what I'm supposed to pass for the string parameter. This isn't for anything specific btw. Merely want to learn and understand more about how to leverage these operations from the command line. Any docs and assistance much appreciated.
EDIT: I'm naive. Oracle docs indicate the string param is an output file per this link. But still uncertain about how to pass the parameters into my command.
According to the cmdline-jmxclient documentation:
http://crawler.archive.org/cmdline-jmxclient/ you have to use comma-delimited parameters to pass to your operation.
So in your case if would be:
java -jar cmdline-jmxclient-0.10.3.jar admin:P#sSw0rd10.11.12.13:1111 com.sun.management:type=HotSpotDiagnostic dumpHeap test,true
Take note that there is an present bug in the cmdline jar file that doesn't take into account Java primitives(int, booelean, byte, etc.) and will throw a ClassNotFoundException because it can't find by the primitive name.
If you find yourself coming across this issue you can either apply the patch to the jar code that is documented here: https://webarchive.jira.com/browse/HER-1630. Or simply change the type field in the jmx endpoint code from it's primitive type to it's Wrapper object type (int -> Integer)
I am trying bcel to modify a method by inserting invoke before specific instructions.
It seems that my instrumentation would result in a different stackmap table, which can not be auto-generated by the bcel package itself.
So, my instrumented class file contains the old stackmap table, which would cause error with jvm.
I haved tried with removeCodeAttributes, the method of MethodGen, that can remove all the code attributes. It can work in simple cases, a wrapped function, for example. And it can not work in my case now.
public class Insert{
public static void main(String[] args) throws ClassFormatException, IOException{
Insert isrt = new Insert();
String className = "StringBuilder.class";
JavaClass jclzz = new ClassParser(className).parse();
ClassGen cgen = new ClassGen(jclzz);
ConstantPoolGen cpgen = cgen.getConstantPool();
MethodGen mgen = new MethodGen(jclzz.getMethods()[1], className, cpgen);
InstructionFactory ifac = new InstructionFactory(cgen);
InstructionList ilist = mgen.getInstructionList();
for (InstructionHandle ihandle : ilist.getInstructionHandles()){
System.out.println(ihandle.toString());
}
InstructionFinder f = new InstructionFinder(ilist);
InstructionHandle[] insert_pos = (InstructionHandle[])(f.search("invokevirtual").next());
Instruction inserted_inst = ifac.createInvoke("java.lang.System", "currentTimeMillis", Type.LONG, Type.NO_ARGS, Constants.INVOKESTATIC);
System.out.println(inserted_inst.toString());
ilist.insert(insert_pos[0], inserted_inst);
mgen.setMaxStack();
mgen.setMaxLocals();
mgen.removeCodeAttributes();
cgen.replaceMethod(jclzz.getMethods()[1], mgen.getMethod());
ilist.dispose();
//output the file
FileOutputStream fos = new FileOutputStream(className);
cgen.getJavaClass().dump(fos);
fos.close();
}
}
Removing a StackMapTable is not a proper solution for fixing a wrong StackMapTable. The important cite is:
4.7.4. The StackMapTable Attribute
In a class file whose version number is 50.0 or above, if a method's Code attribute does not have a StackMapTable attribute, it has an implicit stack map attribute (§4.10.1). This implicit stack map attribute is equivalent to a StackMapTable attribute with number_of_entries equal to zero.
Since a StackMapTable must have explicit entries for every branch target, such an implicit StackMapTable will work with branch-free methods only. But in these cases, the method usually doesn’t have an explicit StackMapTable anyway, so you wouldn’t have that problem then (unless the method had branches which your instrumentation removed).
Another conclusion is that you can get away with removing the StackMapTable, if you patch the class file version number to a value below 50. Of course, this is only a solution if you don’t need any class file feature introduced in version 50 or newer…
There was a grace period in which JVMs supported a fall-back mode for class files with broken StackMapTables just for scenarios like yours, where the tool support is not up-to-date. (See -XX:+FailoverToOldVerifier or -XX:-UseSplitVerifier) But the grace period is over now and that support has been declined, i.e. Java 8 JVMs do not support the fall-back mode anymore.
If you want to keep up with the Java development and instrument newer class files which might use features of these new versions you have only two choices:
Calculate the correct StackMapTable manually
Use a tool which supports calculating the correct StackMapTable attributes, e.g. ASM, (see java-bytecode-asm) does support it
I switched an existing code base to Java 7 and I keep getting this warning:
warning: File for type '[Insert class here]' created in the last round
will not be subject to annotation processing.
A quick search reveals that no one has hit this warning.
It's not documented in the javac compiler source either:
From OpenJDK\langtools\src\share\classes\com\sun\tools\javac\processing\JavacFiler.java
private JavaFileObject createSourceOrClassFile(boolean isSourceFile, String name) throws IOException {
checkNameAndExistence(name, isSourceFile);
Location loc = (isSourceFile ? SOURCE_OUTPUT : CLASS_OUTPUT);
JavaFileObject.Kind kind = (isSourceFile ?
JavaFileObject.Kind.SOURCE :
JavaFileObject.Kind.CLASS);
JavaFileObject fileObject =
fileManager.getJavaFileForOutput(loc, name, kind, null);
checkFileReopening(fileObject, true);
if (lastRound) // <-------------------------------TRIGGERS WARNING
log.warning("proc.file.create.last.round", name);
if (isSourceFile)
aggregateGeneratedSourceNames.add(name);
else
aggregateGeneratedClassNames.add(name);
openTypeNames.add(name);
return new FilerOutputJavaFileObject(name, fileObject);
}
What does this mean and what steps can I take to clear this warning?
Thanks.
The warning
warning: File for type '[Insert class here]' created in the last round
will not be subject to annotation processing
means that your were running an annotation processor creating a new class or source file using a javax.annotation.processing.Filer implementation (provided through the javax.annotation.processing.ProcessingEnvironment) although the processing tool already decided its "in the last round".
This may be problem (and thus the warning) because the generated file itself may contain annotations being ignored by the annotation processor (because it is not going to do a further round).
The above ought to answer the first part of your question
What does this mean and what steps can I take to clear this warning?
(you figured this out already by yourself, didn't you :-))
What possible steps to take? Check your annotation processors:
1) Do you really have to use filer.createClassFile / filer.createSourceFile on the very last round of the annotaion processor? Usually one uses the filer object inside of a code block like
for (TypeElement annotation : annotations) {
...
}
(in method process). This ensures that the annotation processor will not be in its last round (the last round always being the one having an empty set of annotations).
2) If you really can't avoid writing your generated files in the last round and these files are source files, trick the annotation processor and use the method "createResource" of the filer object (take "SOURCE_OUTPUT" as location).
In OpenJDK test case this warning produced because processor uses "processingOver()" to write new file exactly at last round.
public boolean process(Set<? extends TypeElement> elems, RoundEnvironment renv) {
if (renv.processingOver()) { // Write only at last round
Filer filer = processingEnv.getFiler();
Messager messager = processingEnv.getMessager();
try {
JavaFileObject fo = filer.createSourceFile("Gen");
Writer out = fo.openWriter();
out.write("class Gen { }");
out.close();
messager.printMessage(Diagnostic.Kind.NOTE, "File 'Gen' created");
} catch (IOException e) {
messager.printMessage(Diagnostic.Kind.ERROR, e.toString());
}
}
return false;
}
I modified original example code a bit. Added diagnostic note "File 'Gen' created", replaced "*" mask with "org.junit.runner.RunWith" and set return value to "true". Produced compiler log was:
Round 1:
input files: {ProcFileCreateLastRound}
annotations: [org.junit.runner.RunWith]
last round: false
Processor AnnoProc matches [org.junit.runner.RunWith] and returns true.
Round 2:
input files: {}
annotations: []
last round: true
Note: File 'Gen' created
Compilation completed successfully with 1 warning
0 errors
1 warning
Warning: File for type 'Gen' created in the last round will not be subject to annotation processing.
If we remove my custom note from log, it's hard to tell that file 'Gen' was actually created on 'Round 2' - last round. So, basic advice applies: if in doubt - add more logs.
Where is also a little bit of useful info on this page:
http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/javac.html
Read section about "ANNOTATION PROCESSING" and try to get more info with compiler options:
-XprintProcessorInfo
Print information about which annotations a processor is asked to process.
-XprintRounds Print information about initial and subsequent annotation processing rounds.
I poked around the java 7 compiler options and I found this:
-implicit:{class,none}
Controls the generation of class files for implicitly loaded source files. To automatically generate class files, use -implicit:class. To suppress class file generation, use -implicit:none. If this option is not specified, the default is to automatically generate class files. In this case, the compiler will issue a warning if any such class files are generated when also doing annotation processing. The warning will not be issued if this option is set explicitly. See Searching For Types.
Source
Can you try and implicitly declare the class file.
I am getting expected ClassVerifyErrors when attempting to load a class i have generated using ASM. On further inspection i can see that the jvm is correct and that the method is talking about has an invalid MAX_STACK value. THe strange thing is am using the auto calculate the stack and max local options so this should not be a problem...
The method with the invalid option is very simple and yet the result is bad bytecode.
I have written a class with the intended method and compared my asm generated class against what javac produces and the byte codes matchup with the only error being the max stack is 0 which is wrong while javac sets a value of 2.
Id like to avoid having to calculate tha max stack/locals myself.
Max stack and variable calculation can produce the wrong results if bytecode is not valid. You can verify that by running generated code trough the CheckClassAdapter.
For example,
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
// generate code into cw instance...
PrintWriter pw = new PrintWriter(System.out);
CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), true, pw);