permanent storage of parameter names in bytecode using javac -parameters <Classname> - java

What I'm doing
I'm using reflection in my code to decouple all my classes and To do so I need to be able to dynamically create instances of objects. I've done this by text matching parameter names to input data. To do a text match however, I need access to the formal parameter names rather than the synthetic arg0, arg1 ... that I know gets created if IsNamePresent returns false.
What I've done
I researched how to get the formal names (google searching things like: "when I compile my java classes with the parameter option enabled, does that make reflection work forever? or only one time when the classes are run?" to no useful results). I've also tried searches similar to that here and seen info related to javac with one of the questions being "Drawbacks of javac -parameters flag" as an example. While these addressed parts of my question they really didn't answer the meat of what I need. I've found that in java 8 you can just do "javac -parameters " and you will be fine. Note that I had to use the directory of the jdk as the starting point (my command line input looks exactly like this):
C:\Program Files\Java\jdk-10.0.1\bin>javac -parameters C:\Users\abbotts1\IdeaProjects\project\src\Sales_Rep_Data\*.java
and so far that works without any errors and my project has bytecode compiled files in it now so I know its doing something. Just what exactly (or if its as a result of the above) is a mystery to me because there is no timestamp or anything I can find for these files that points to which command I tried that made it (I've been trying these commands for a while).
Detailed description of question scope
My question is this: is this command line input the only way to get formal parameters. If it is then, am I doing it right (correct input syntax)? If I'm doing it right then how can I make it so that when I debug my code and run param.getName() it actually returns the formal name? So far I've ran the above command on the command line and tried to debug in my java code this line:
Boolean check = param.isNamePresent();
where param is just the parameter coming from a for-each loop that uses the constructor of the class I am getting through reflection. Point is, every-time I run it this Boolean returns false in the debugger and the names are synthetic (arg0, arg1 ect). I want it to return true (and actually use the formal names) so I can debug the rest of my code.
If this isn't the only way to achieve the stated goal of getting formal parameter names then where can I find a better way? I've seen some framework stuff and heard of Eclipse being used to do this, however I don't want to get too deep into new software just to accomplish one thing AND I am working so I don't have administrator privileges (which is why I needed to specify the jdk in cmd directly rather than just set the PATH variables the usual way). This would make it a hassle to have to download something like Eclipse.
Update
I've researched into using annotations to get the parameter names since I have no good idea why the compiled class won't actually store the parameter names. This strategy was suggested in an initial answer (since deleted) and I took it upon myself to go learn some basic annotations. They have worked to a point but right now I'm getting a wrong arguments error where I shouldn't. I've checked the debugger and the number of arguments passed in are the same number needed so it must be a type error with the wrapping/unwrapping according to the javadoc for the newInstance(Object[]) method). I want to be able to initialize null parameters and I think thats the source of my problem (i. e. null type errors or something but not shown as NPE). Other potential sources include the fact that I'm passing in an Object[] and typing it stricter in the class (i.e. newInstance(Object[] array) is creating an instance of a class that has String parameters and other various sub classes of Object including array lists) Since asking about that error here would constitute an XY problem I won't ask but just describe it for clarification on the original question. My original question still stands even as this workaround is being worked on because I'd still love to know why compiling this class with the -parameters flag didn't store the parameter names. I'm 99% sure the class path is correct since I copy pasted it from the directory. This sounds silly but do I have to actually run the class using the below line?
C:\Program Files\Java\jdk-10.0.1\bin>java C:\Users\abbotts1\IdeaProjects\project\src\Sales_Rep_Data\Data_Parser.java
I was under the impression that compiling it with the parameters flag was all you needed and then the formal parameter names would be available.

Related

Step Into isAssignableFrom() method in Eclipse

I'm currently debugging some code that looks like this:
if (!clazz.isAssignableFrom(TypeName.class)){
return
}
Using the standard Eclipse debugging tools, I can inspect both classes and see that their names are both
com.packagename.package1.TypeName
I'd like to step into the isAssignableFrom() method that is being used to fail this evaluation when it seems like it should be passing to narrow down what the issue is. I've followed the answers from this question however, when attempting to "Step Into" isAssignableFrom(), Eclipse skips the line and goes right to the return statement, providing me no information about why two of the exact same type somehow aren't assignable from or to one another.
How can I step into this method to see which comparison is failing in an effort to fix the obvious issue with my TypeName class?
You cannot. It's a native method. There is no Java implementation to step into; it's baked into the JVM.
Likely the classes are loaded from different classloaders.
You could check with cls.getClassLoader().hashCode()

Is it possible to compare two .java files methods and fields in all cases?

I am currently taking a project management class and the professor gave this assignment to compare two .java files methods and fields in all cases programmatically. I don't think it's actually possible to do but maybe I am wrong!
The assignment spec is as following (its extremely ambiguous I know)
In this assignment, you are required to write a comparison tool for two
versions of a Java source file.
Your program takes as input two .java files representing those two versions
and reports the following atomic changes:
1. AM: Add a new method
2. DM: Delete a method
3. CM: Change the body of a method (note: you need to handle the case where a method is
relocated within the body of its class)
4. AF: Add a field
5. DF: Delete a field
6. CFI: Change the definition of an instance field initializer (including (i) adding an initialization to a
field, (ii) deleting an initialization of a field, (iii) making changes to the initialized value of a field,
and (iv) making changes to a field modifier, e.g., private to public)
So that's what I am working with and my approach was to use reflection as it allows you to do everything but detect differences in the method body.
I had considered the idea that you could create a parser but that seemed ridiculous, especially for a 3 credit undergrad class in project management. Tools like BeyondCompare don't list what methods or fields changed, just lines that are different so don't meet the requirements.
I turned in this assignment and pretty much the entire class failed it with the reason as "our code would not work for java files with external dependencies that are not given or with java files in different projects" - which is completely correct but also I'm thinking, impossible to do.
I am trying to nail down a concrete answer as to why this is not actually possible to do or learn something new about why this is possible so any insight would be great.
What you got wrong here is that you have started to examine the .class files (using reflection). Some of the information listed above is not even available at that stage (generics, in-lined functions). What you need to do is parsing the .java files as text. That is the only way to actually solve the problem. A very high-level solution could be writing a program that:
reads the files
constructs a specific object for each .java file containing all the informations that needs to be compared (name of the functions, name of the instance variables, etc)
compares the constructed objects (example: addedFunctions = functionsFromA.removeAll(functionsFromB)) to provide the requested results
Note: if this is an assignment, you should not be using solutions provided by anybody else, you need to do it on your own. Likely you will not get a single point if you use a library written by somebody else.

What happen if I manually changed the bytecode before running it?

I am little bit curious about that what happen if I manually changed something into bytecode before execution. For instance, let suppose assigning int type variable into byte type variable without casting or remove semicolon from somewhere in program or anything that leads to compile time error. As I know all compile time errors are checked by compiler before making .class file. So what happen when I changed byte code after successfully compile a program then changed bytecode manually ? Is there any mechanism to handle this ? or if not then how program behaves after execution ?
EDIT :-
As Hot Licks, Darksonn and manouti already gave correct satisfy answers.Now I just conclude for those readers who all seeking answer for this type question :-
Every Java virtual machine has a class-file verifier, which ensures that loaded class files have a proper internal structure. If the class-file verifier discovers a problem with a class file, it throws an exception. Because a class file is just a sequence of binary data, a virtual machine can't know whether a particular class file was generated by a well-meaning Java compiler or by shady crackers bent on compromising the integrity of the virtual machine. As a consequence, all JVM implementations have a class-file verifier that can be invoked on untrusted classes, to make sure the classes are safe to use.
Refer this for more details.
You certainly can use a hex editor (eg, the free "HDD Hex Editor Neo") or some other tool to modify the bytes of a Java .class file. But obviously, you must do so in a way that maintains the file's "integrity" (tables all in correct format, etc). Furthermore (and much trickier), any modification you make must pass muster by the JVM's "verifier", which essentially rechecks everything that javac verified while compiling the program.
The verification process occurs during class loading and is quite complex. Basically, a data flow analysis is done on each procedure to assure that only the correct data types can "reach" a point where the data type is assumed. Eg, you can't change a load operation to load a reference to a HashMap onto the "stack" when the eventual user of the loaded reference will be assuming it's a String. (But enumerating all the checks the verifier does would be a major task in itself. I can't remember half of them, even though I wrote the verifier for the IBM iSeries JVM.)
(If you're asking if one can "jailbreak" a Java .class file to introduce code that does unauthorized things, the answer is no.)
You will most likely get a java.lang.VerifyError:
Thrown when the "verifier" detects that a class file, though well formed, contains some sort of internal inconsistency or security problem.
You can certainly do this, and there are even tools to make it easier, like http://set.ee/jbe/. The Java runtime will run your modified bytecode just as it would run the bytecode emitted by the compiler. What you're describing is a Java-specific case of a binary patch.
The semicolon example wouldn't be an issue, since semicolons are only for the convenience of the compiler and don't appear in the bytecode.
Either the bytecode executes normally and performs the instructions given or the jvm rejects them.
I played around with programming directly in java bytecode some time ago using jasmin, and I noticed some things.
If the bytecode you edited it into makes sense, it will of coursse run as expected. However there are some bytecode patterns that are rejected with a VerifyError.
For the specific examble of out of bounds access, you can compile code with out of bounds just fine. They will get you an ArrayIndexOutOfBoundsException at runtime.
int[] arr = new int[20];
for (int i = 0; i < 100; i++) {
arr[i] = i;
}
However you can construct bytecode that is more fundamentally flawed than that. To give an example I'll explain some things first.
The java bytecode works with a stack, and instructions works with the top elements on the stack.
The stack naturally have different sizes at different places in the program but sometimes you might use a goto in the bytecode to cause the stack to look different depending on how you reached there.
The stack might contain object, int then you store the object in an object array and the int in an int array. Then you go on and from somewhere else in that bytecode you use a goto, but now your stack contains int, object which would result in an int being passed to an object array and vice versa.
This is just one example of things that could happen which makes your bytecode fundamentally flawed. The JVM detects these kinds of flaws when the class is loaded at runtime, and then emits a VerifyError if something dosen't work.

What's the point of String[] args in Java?

Whenever you declare the main method in a class, you always have to do a String array called "args". What's the point? Unless I live under a rock, command line agruments in Java are barely used anymore. And when I try and run this...
//this program won't compile
public class SomeClass {
public static void main(){
System.out.println("This text will never be displayed :(");
}
}
The output shows this in red text:
Error: Main method not found in class SomeClass, please define the main method as:
public static void main(String[] args)
I, the newbie Java programmer, would greatly appreciate it if anyone told my why it's required to enter that parameter into a main method.
Because that is the signature of the main method that is called when you execute a Java class. There needs to be some convention which method will be executed. By convention it is the
public static void main(String[] args) method
And yes, you do live under the rock, there are plenty of situations when command line arguments are used. Why would they not be used?
You could ask: why require it? Why not just pick any other main method? The answer is that it would be adding complexity with 0 benefit. As is now, main function looks distinctive. If you look at it, you know it is the one that will get called. If any main would be called, you would have to always ask yourself: is the main I am looking at the one to be invoked, or is there another main in this class which takes precedence?
Short answer: because that's the way Java is.
Command-line arguments are used all the time, but you don't always see them due to launcher scripts, or because the program's running on a server, etc.
That said, a lot of time the command line arguments are of the -D variety, slurped up by the JVM before reaching main. But it depends on what you're doing.
A Java application can accept any number of arguments from the command line. This allows the user to specify configuration information when the application is launched. (From Command-Line Arguments) and as everyone else said here, it is the way it is!
For gods sake,Please Don't say if I don't need this ,no-one else need this! :)
Because
Command-line arguments are still used, even by many UI programs (did you know that Microsoft Outlook supports some very handy command-line arguments?)*; and:
That's Just How Java Works (TM). Among other things, it reduces the complexity of both the code (by disallowing multiple forms and possible accidental shadowing) and run-time (by not needing to find out "which main" to call). Allowing a secondary form without "args" just adds too little.
Happy coding...
*Yes, Outlook is not Java. However, if Outlook has command-line arguments, well, they must still be worth something -- it was a hyperbole ;-)
Almost every UI program that deals opening reading files will allow specifying which file to open via command-line arguments (Gimp, Notepad, Firefox, to name a few others). Among other things, this is to allow integration with "double clicking to open" on items in Windows Explorer and similar.
I actually have no idea why it's required, other than to say that it is a syntactical convention. In the same way that a function is (defined function-name()) in Lisp/Scheme, or there are do..end blocks in Ruby, the syntax of a Java Main function is with String[] args.
As for not using command line arguments, it's entirely dependent on the program. Entirely. I write programs in java all the time that take command line arguments; it's just a question of what you're trying to accomplish.
One case I can think of is, when you want to have a command line driven interface for your software along with the GUI. An example is the Android tools, all of them have console driven interfaces.
Command-line argument support is largely standard among programming languages. Even in this age of GUIs, there are all sorts of hidden ways to run a program with command line arguments. I know Windows has shortcut configurations for advanced users where you can run a program with a given set of command line arguments, for example.
Java also enforces types, and by extension function signatures (look it up on Google if you don't know what those are). The main function is expected to take an array of Strings - if the main function you define doesn't match that argument signature (1 argument, array of Strings), then it causes an incompatibility.
Java supports function overloading (you can define the same function name several times with different arguments). To find which function to invoke, Java takes the input argument types and looks for an applicable defined function that takes the matching arguments.
When the program runs, Java specifically looks for a function named main with 1 argument (String []). Your program doesn't define a main function with that argument specification, so this lookup fails with an error message.

Finding out which methods were changed by a checkin?

Here's the deal - I want a way to figure out specifically which methods were touched or changed within the last milestone/iteration so that the methods' Javadoc is checked for correct content, especially for the public API methods.
Any ideas on how to do this, perhaps with an SVN hook?
there is no single command to achieve this, but you can combine some svn commands to achive something similar:
svn diff last tag with your trunk:HEAD revision with --summarize option
svn annotate each file you revceived by step 1 and parse the output to find the changed codelines (their rev is greater than tag-rev.)
mark associated functions or output them into a report file(just remember the last function signature if you parse the file line by line)
the class/methodname is trivial to get for usual java classes, however, if you use innerclasses, it will be more difficult, but then : do they have or need javadoc comments?
An idea, at least: svn diff has the ability to pass arguments to the diff command. One such option is -p, also known as --show-c-function. This would probably figure in a solution of this problem for C code. So, the question becomes: is there a diff implementation that knows enough of the Java syntax to support a similar option? I've Googled, but not found anything yet.

Categories