Automatically fix non formatting but simple CheckStyle issues - java

Is there a command line tool that can automatically fix non formatting but still seemingly simple CheckStyle issues in Java source code like:
Avoid inline conditionals
Make "xxx" a static method
I know there are various tools to fix formatting and some IDEs have fairly advanced quick fixers but so far I could not find anything that can recursively run on a source code folder or be integrated in a commit hook.

Sounds like a nice challenge, but I was also unable to find an automatic tool that can do this. As you already described, there are plenty of options to change code formatting. For other small issues, you could perhaps run Checkstyle from the command-line and filter out fixable warnings. A library for parsing and changing Java source code could help to actually make the changes, like for example JavaParser. Perhaps you could write a custom tool in a relatively small amount of time using a Java source code manipulation tool like JavaParser.
(There are other tools like ANTLR that could be used; see for more ideas this question on Stack Overflow: Java: parse java source code, extract methods. Some libraries like Roaster and JavaPoet do not parse the body of methods, which makes them less suitable in this situation.)
As a very simple example, assume we have a small Java class for which Checkstyle generates two messages (with a minimalistic checkstyle-checks.xml Checkstyle configuration file that only checks FinalParameters and FinalLocalVariable):
// Example.java:
package q45326752;
public class Example {
public static void main(String[] arguments) {
System.out.println("Hello Checkstyle...");
int perfectNumber = 1 + 2 + 3;
System.out.println("Perfect number: " + perfectNumber);
}
}
Checkstyle warnings:
java -jar checkstyle-8.0-all.jar -c checkstyle-checks.xml Example.java
[ERROR] Example.java:4:29: Parameter arguments should be final. [FinalParameters]
[ERROR] Example.java:7:13: Variable 'perfectNumber' should be declared final. [FinalLocalVariable]
Using JavaParser, these two warnings could be fixed automatically like this (the code tries to demonstrate the idea; some parts have been ignored for now):
// AutomaticCheckstyleFix.java:
package q45326752;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.*;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.*;
import java.io.File;
import java.io.FileNotFoundException;
public class AutomaticCheckstyleFix {
private MethodDeclaration bestMatchMethod;
private int bestMatchMethodLineNumber;
private Statement statementByLineNumber;
public static void main(final String[] arguments) {
final String filePath = "q45326752\\input\\Example.java";
try {
new AutomaticCheckstyleFix().fixSimpleCheckstyleIssues(new File(filePath));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
private void fixSimpleCheckstyleIssues(File file) throws FileNotFoundException {
CompilationUnit javaClass = JavaParser.parse(file);
System.out.println("Original Java class:\n\n" + javaClass);
System.out.println();
System.out.println();
// Example.java:4:29: Parameter arguments should be final. [FinalParameters]
MethodDeclaration methodIssue1 = getMethodByLineNumber(javaClass, 4);
if (methodIssue1 != null) {
methodIssue1.getParameterByName("arguments")
.ifPresent(parameter -> parameter.setModifier(Modifier.FINAL, true));
}
// Example.java:7:13: Variable 'perfectNumber' should be declared final.
// [FinalLocalVariable]
Statement statementIssue2 = getStatementByLineNumber(javaClass, 7);
if (statementIssue2 instanceof ExpressionStmt) {
Expression expression = ((ExpressionStmt) statementIssue2).getExpression();
if (expression instanceof VariableDeclarationExpr) {
((VariableDeclarationExpr) expression).addModifier(Modifier.FINAL);
}
}
System.out.println("Modified Java class:\n\n" + javaClass);
}
private MethodDeclaration getMethodByLineNumber(CompilationUnit javaClass,
int issueLineNumber) {
bestMatchMethod = null;
javaClass.getTypes().forEach(type -> type.getMembers().stream()
.filter(declaration -> declaration instanceof MethodDeclaration)
.forEach(method -> {
if (method.getTokenRange().isPresent()) {
int methodLineNumber = method.getTokenRange().get()
.getBegin().getRange().begin.line;
if (bestMatchMethod == null
|| (methodLineNumber < issueLineNumber
&& methodLineNumber > bestMatchMethodLineNumber)) {
bestMatchMethod = (MethodDeclaration) method;
bestMatchMethodLineNumber = methodLineNumber;
}
}
})
);
return bestMatchMethod;
}
private Statement getStatementByLineNumber(CompilationUnit javaClass,
int issueLineNumber) {
statementByLineNumber = null;
MethodDeclaration method = getMethodByLineNumber(javaClass, issueLineNumber);
if (method != null) {
method.getBody().ifPresent(blockStmt
-> blockStmt.getStatements().forEach(statement
-> statement.getTokenRange().ifPresent(tokenRange -> {
if (tokenRange.getBegin().getRange().begin.line == issueLineNumber) {
statementByLineNumber = statement;
}
})));
}
return statementByLineNumber;
}
}
Another approach could be to create new Checkstyle plugins based on the ones you are trying to create an automatic fix for. Perhaps you have enough information available to not only give a warning but to also generate a modified version with these issues fixed.
Personally I would hesitate to have issues fixed automatically upon commit. When there are many simple fixes to be made, automation is welcome, but I would like to check these changes before committing them. Running a tool like this and checking the changes could be a very fast way to fix a lot of simple issues.
Some checks that I think could be fixed automatically:
adding static
fixing inline conditionals
FinalParameters and FinalLocalVariable: adding final
ModifierOrder: reordering modifiers (example: final static private)
NeedBraces: adding braces

Related

IllegalState At least one issue expected in Sonar custom plugin

I am very new to Sonar.
I am trying to make my own plugin for sonar. After downloading plugin example, I make it eclipse ready using mvn eclipse:eclipse and import to workspace. It is compiling fine.
But I need to add my own Rule files to it.
For that purpose, I have created 2 files.
MyCustomNLSRuleTest .java
package org.sonar.samples.java.checks;
import org.junit.Test;
import org.sonar.java.checks.verifier.JavaCheckVerifier;
public class MyCustomNLSRuleTest {
#Test
public void check() {
// Verifies that the check will raise the adequate issues with the expected message.
// In the test file, lines which should raise an issue have been commented out
// by using the following syntax: "// Noncompliant {{EXPECTED_MESSAGE}}"
JavaCheckVerifier.verify("src/test/files/MissingCheck.java", new MyCustomSubscriptionRule());
}
}
The actual rule is provided to me in the following java file which looks like below -
MissingCheck.java
public class MissingCheck extends Check
{
private HashMap<Integer, Integer> lineStringMap;
#Override
public void beginTree(DetailAST aRootAST) {
super.beginTree(aRootAST);
lineStringMap = new HashMap<>();
}
#Override
public int[] getDefaultTokens() {
return new int[] { TokenTypes.STRING_LITERAL};
}
#Override
public void visitToken(DetailAST ast) {
DetailAST parent = ast.getParent();
if (parent != null) {
DetailAST grandpa = parent.getParent();
if (isAnnotation(grandpa.getType())) {
return;
}
}
Integer count = lineStringMap.get(ast.getLineNo());
if (count == null) {
count = new Integer(1);
} else {
count++;
}
FileContents contents = getFileContents();
String[] line = contents.getLines();
if (line.length >= ast.getLineNo()) {
String l = line[ast.getLineNo() - 1];
if (!l.contains("$NON-NLS-" + count + "$")) {
log(ast.getLineNo(), "String_Not_Externalized", new Object[] { ast.getText() });
}
}
lineStringMap.put(ast.getLineNo(), count);
}
/**
* Checks if type is an annotation.
* #param type to check
* #return <code>true</code> if type is an annotation.
*/
private boolean isAnnotation(int type) {
return (type >= TokenTypes.ANNOTATION_DEF && type <= TokenTypes.ANNOTATION_ARRAY_INIT);
}
}
But, I am trying to do mvn clean package this project, it gives me error:
Results :
Tests in error:
MyCustomNLSRuleTest.check:13 ยป IllegalState At least one issue expected
Tests run: 8, Failures: 0, Errors: 1, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ---------------------------------------------------------------------
Any idea, how I can add a new rule in the plugin?
Thanks!
Okay, it seems that you are very far from what you are supposed to do when writing custom rules for the java plugin... A few questions first:
Did you actually tried to have a look at the dedicated page from the SonarQube confluence? http://docs.sonarqube.org/display/DEV/Custom+Rules+for+Java
Did you actually look at the following links before trying to write a rule?
The rule already implemented in the example project,
How they are tested,
With which test files,
How they are registered in the custom plugin,
The comments from the unit test you are actually writing.
Now... Let's start by explaining to you what you are currently doing, as apparently it's not clear at all.
You created a test file called MyCustomNLSRuleTest.java, which should theoretically correspond to a rule called MyCustomNLSRule. Note that it's probably not the case, as you are saying that the rule is provided to you in the MissingCheck.java file.
Your unit test uses JavaCheckVerifier to verify that the file provided as argument, "src/test/files/MissingCheck.java", will raise all the expected issues when playing the rule MyCustomSubscriptionRule against it.
At this point, you are not testing at all your MissingCheck, but using it as data for the MyCustomSubscriptionRule rule... And it's probably your main issue.
However, if this is actually really what you are trying to achieve, it means that:
You modified the rule MyCustomSubscriptionRule to have a custom behavior, different from the one from the original example project.
When executing it on the file MissingCheck.java, the check is supposed to raise issue (with the line having issue being commented out with // Noncompliant {{expected message}})
Your custom rule does not work, as it apparently raised no issue at all when playing the test.
Please look at all the links provided above to see how custom rules works, what is available in the java plugin API, and what you can achieve with it.

javac equivalent of "-D"?

Is there a way to give the java compiler some kind of variable that is accessible to the running java code?
In C/C++ I can give the compile -DKEY=VALUE and that would cause the preprocessor to have a #define for KEY equals to VALUE. I can then check this value in compile time to effect what code is being compiled.
I found java's -D, but that puts values give the the java command line in System.getProperty(). I want an argument give in compile time, not invocation time.
javac has the
-Akey[=value]
commandline option to pass information to annotation processors.
With java annotations it is possible to generate additional code on the fly, which can be configured on command line. It allow to produce more source code, configuration files, xml files, ... The main limitation is that you are allowed only to (re)generate new source files, you cannot modify existing ones.
Below is a short tutorial on how to allow from javac command specify parameters which will be visible in Java code. How usefull is that? Ie. you could specify a boolean option which would disable some parts of code, I am preety sure this parts of code could be removed using tools like proguard - or even optimized out by javac. Other uses is to specify new version number. Those use cases are mostly what c++ marcros are used for.
So, you need :
a dummy annotation class which will allow processor to run. It should be specified only once in your application.
a processor class which will run for above dummy annotation, and generate options class. It will also read options from javac command line.
a dummy Main class for testing purposes.
You will have to also compile your processor file before compiling Main class. This of course is done only when processor class is modified. All the three files are at the bottom. Now the compilation looks as follows (I am on windows):
Compile processor:
javac .\com\example\ConfigWritterAnnotationProcessor.java
Then Main.java with additional parameters to processor:
javac -processor com.example.ConfigWritterAnnotationProcessor -AtextToPrint="Hello World!" -AenablePrint=true ./com/example/Main.java
And thats all, now you may run Main.class and it will use Options class generated during compilation with above parameters set. It will look as follows:
package com.example;
public class Options {
public static final String textToPrint = "Hello World!";
public static final boolean enablePrint = true;
}
ProcessorStarterAnnotation.java
package com.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Target({ElementType.TYPE})
public #interface ProcessorStarterAnnotation {
}
Main.java
package com.example;
#ProcessorStarterAnnotation
public class Main {
public static void main(String[] args) {
if ( com.example.Options.enablePrint ) {
System.out.println(com.example.Options.textToPrint);
}
else {
System.out.println("Print disabled");
}
}
}
ConfigWritterAnnotationProcessor.java
package com.example;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Map;
import java.util.Set;
#SupportedAnnotationTypes("com.example.ProcessorStarterAnnotation")
#SupportedSourceVersion(SourceVersion.RELEASE_6)
#SupportedOptions({"textToPrint", "enablePrint"})
public class ConfigWritterAnnotationProcessor extends AbstractProcessor {
private Map<String,String> options;
#Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
options = processingEnv.getOptions();
}
#Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment currentRound) {
if (!currentRound.processingOver()) {
// This for-s are because processor is also run on newly created Options class.
for (TypeElement te : annotations) {
for (Element e : currentRound.getElementsAnnotatedWith(te)) {
try {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Creating com.example.Options");
JavaFileObject javaFile = processingEnv.getFiler().createSourceFile("com.example.Options");
Writer w = javaFile.openWriter();
try {
PrintWriter pw = new PrintWriter(w);
pw.println("package com.example;");
pw.println("public class Options {");
pw.println(" public static final String textToPrint = \"" + options.get("textToPrint") + "\";");
pw.println(" public static final boolean enablePrint = " + options.get("enablePrint") + ";");
pw.println("}");
pw.flush();
} finally {
w.close();
}
} catch (IOException x) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
x.toString());
}
}
}
}
return false;
}
}
There is nothing like this in Java. Compile time constants must be declared in source code, and as far as I know, there is no pre-processor.
BTW, you could use flags given to java command line (-D args) to initialize java constants at runtime, that would mimic what you are looking for.
Ex:
class Foo {
private static final String BAR;
static {
String foobar = System.getProperty("foo.bar");
if(foobar != null && foobar.length()>0) {
BAR = foobar;
} else {
BAR = "somedefaultvalue";
}
}
}
Invoke with java Xxx -Dfoo.bar=foobar
As there is no notion of preprocessing in Java, a solution is to design your own.
One may think of using a standard C preprocessor or a custom-made one and compile the preprocessed output, but this has the disadvantage of duplicating the files, so that the project will become more complex, and the support from the development environment will degrade (like ability to jump to a syntax error).
My suggestion is to use annotations via comments that will guide a custom preprocessor and let it do substitutions before compiling.
For example,
public static void main(String[] args) {
int nDisks = 3;
doTowers(nDisks, 'A', 'B', 'C');
}
would become
public static void main(String[] args) {
int nDisks = /*#NDISKS*/ 3 /**/;
doTowers(nDisks, 'A', 'B', 'C');
}
Then your preprocessor would have a definition file such as
NDISKS 5
turning the code in
public static void main(String[] args) {
int nDisks = /*#NDISKS*/ 5 /**/;
doTowers(nDisks, 'A', 'B', 'C');
}
Similarly, you can emulate conditional code compilation with
doTowers(topN - 1, from, to, inter);
/*!PRINT*/
System.out.println("Disk "
+ topN + " from " + from + " to " + to);
/**/
doTowers(topN - 1, inter, from, to);
which could be turned by the preprocessor (with a definition like PRINT OFF) into
doTowers(topN - 1, from, to, inter);
/*!PRINT
System.out.println("Disk "
+ topN + " from " + from + " to " + to);
*/
doTowers(topN - 1, inter, from, to);
You can use alternative syntaxes, but the main ideas are
that the annotated code remains compilable,
that the preprocessor substitutions are reversible.
It would be against the design of the language to have it that way. What -DKEY=VALUE does is that it actually replaces KEY with VALUE in the source during preprocessor in C/C++.
Java does not have a preprocessor so that's mechanism is not available. If you want something "equivalent" you have to question what you mean by that. By not preprocessing the source it wouldn't be really equivalent.
If you on the other hand would like it to mean to set the value of the symbol KEY to the value VALUE you'd run into the problem that you would need to declare the symbol KEY anyway to determine it's type. In this case it would only be yet another constant/variable with the constraints that implies.
This means that even with such a feature it would not actually alter the generated code and you would hardly be better of than defining the value att launch time. That's why supplying the parameter via java would be the way to go.

How to improve logging mechanism with Java8s lambdas

How is it possible, to improve your logging mechanism, by not having the overhead of string concatenations?
Consider the following example:
import java.util.logging.Level;
import java.util.logging.Logger;
public class LoggerTest {
public static void main(String[] args) {
// get logger
Logger log = Logger.getLogger(LoggerTest.class.getName());
// set log level to INFO (so fine will not be logged)
log.setLevel(Level.INFO);
// this line won't log anything, but will evaluate the getValue method
log.fine("Trace value: " + getValue());
}
// example method to get a value with a lot of string concatenation
private static String getValue() {
String val = "";
for (int i = 0; i < 1000; i++) {
val += "foo";
}
return val;
}
}
The log method log.fine(...) will not log anything, because the log level is set to INFO. The problem is, that the method getValue will be evaluated anyway.
And this is a big performance issue in big applications with a lot of debug statements.
So, how to solve this problem?
Since Java8 it is possible to use the new introduced lambda expressions for this scenario.
Here is a modified example of the logging:
LoggerTest.class
import java.util.logging.Level;
import java.util.logging.Logger;
public class LoggerTest {
public static void main(String[] args) {
// get own lambda logger
LambdaLogger log = new LambdaLogger(LoggerTest.class.getName());
// set log level to INFO (so fine will not be logged)
log.setLevel(Level.INFO);
// this line won't log anything, and will also not evaluate the getValue method!
log.fine(()-> "Trace value: " + getValue()); // changed to lambda expression
}
// example method to get a value with a lot of string concatenation
private static String getValue() {
String val = "";
for (int i = 0; i < 1000; i++) {
val += "foo";
}
return val;
}
}
LambdaLogger.class
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LambdaLogger extends Logger {
public LambdaLogger(String name) {
super(name, null);
}
public void fine(Callable<String> message) {
// log only, if it's loggable
if (isLoggable(Level.FINE)) {
try {
// evaluate here the callable method
super.fine(message.call());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
With this modification you can improve the performance of your applications a lot, if you have many log statements, which are only for debugging purposes.
Of course you can use any Logger you want. This is only an example of the java.util.Logger.
#bobbel has explained how to do it.
I'd like to add that while this represents a performance improvement over your original code, the classic way of dealing with this is still faster:
if (log.isLoggable(Level.FINE)) {
log.fine("Trace value: " + getValue());
}
and only marginally more verbose / wordy.
The reason it is faster is that the lambda version has the additional runtime overheads of creating the callable instance (capture cost), and an extra level of method calls.
And finally, there is the issue of creating the LambdaLogger instances. #bobbel's code shows this being done using a constructor, but in reality java.util.logging.Logger objects need to be created by a factory method to avoid proliferation of objects. That implies a bunch of extra infrastructure (and code changes) to get this to work with a custom subclass of Logger.
Apparently Log4j 2.4 includes support for lambda expressions which are exactly useful for your case (and which other answers have replicated manually):
From https://garygregory.wordpress.com/2015/09/16/a-gentle-introduction-to-the-log4j-api-and-lambda-basics/
// Uses Java 8 lambdas to build arguments on demand
logger.debug("I am logging that {} happened.", () -> compute());
Just create wrapper methods for your current logger as:
public static void info(Logger logger, Supplier<String> message) {
if (logger.isLoggable(Level.INFO))
logger.info(message.get());
}
and use it:
info(log, () -> "x: " + x + ", y: " + y);
Reference: JAVA SE 8 for the Really Impatient eBook, pages 48-49.
use a format String, and an array of Supplier<String>. this way no toString methods are called unless the the log record is actually publishable. this way you dont have to bother with ugly if statements about logging in application code.

How can I get the complete Call Hierarchy of a Java source code?

This is a bit tricky to explain. I have a class A:
public class A {
private Integer a1;
private Integer a2;
// getters and setters.
}
There is a static class B that returns my class A:
public static class B {
public static A getCurrentA() {
return a;
}
}
I need to find all usages of class A returned by B. So let's say class C calls c.setA(B.getCurrentA()) and then further along there's a call to c.getA().getA2();, I'd want to find all of these.
In the real scenario, I have 217 different classes that call B.getCurrentA(). I can't manually follow all the calls in Eclipse and find out which methods are getting called.
Eclipse call hierarchy view only shows me all calls to B.getCurrentA().
How can I achieve this?
EDIT
Chris Hayes understood what I want to do. In order to refactor some really bad legacy code without breaking the whole system, I need to first fine-tune some queries using Hibernate's projections (every mapped entity in the system is eagerly loaded, and many entities are related, so some queries take a LONG time fetching everything). But first I need to find which properties are used so that I don't get a NullPointerException somewhere...
Here's an example of what I'd have to do manually:
Use Eclipse's Search to find all calls to B.getCurrentA();
Open the first method found, let's say it's the one below:
public class CController {
C c = new C();
CFacade facade = new CFacade();
List<C> Cs = new ArrayList<C>();
public void getAllCs() {
c.setA(B.getCurrentA()); // found it!
facade.search(c);
}
}
Open the search method in the CFacade class:
public class CFacade {
CBusinessObject cBo = new CBusinessObject();
public List<C> search(C c) {
// doing stuff...
cBo.verifyA(c);
cBo.search(c); // yes, the system is that complicated
}
}
Open the verifyA method in the CBusinessObject class and identify that field a2 is used:
public class CBusinessObject {
public void verifyA(c) {
if (Integer.valueOf(1).equals(c.getA().getA2())) {
// do stuff
else {
// something else
}
}
}
Repeat steps 2-4 for the next 216 matches... Yay.
Please help.
If you want to make any source code changes/refactoring you will have to manually find all usages and apply your code changes;
Any way, I have two different aproach
Static search
You can simply do Text Search in eclipse to find the occurance of getA2() . It will directly take you to the Caller method (here CBusinessObject.verifyA()) -but it will give you every getA2() occurances, may be from different class
Run time search
Use java instrumentation API to change the byte code at run time on your required method to find invoking class and run as java agent - Enable you to identify the caller with out touching the existing code base and very useful especially when you don't have access to source code.
Here you go how to implement
Step 1- Write Agent main class to initiate instrumentation
public class BasicAgent {
public static void premain(String agentArguments, Instrumentation instrumentation){
System.out.println("Simple Agent");
FindUsageTransformer transformer = new FindUsageTransformer ();
instrumentation.addTransformer(transformer,true);
}
}
Step 2 -Write a ClassFileTransformer implementation and capture the method
public class FindUsageTransformer implements ClassFileTransformer{
Class clazz = null;
public byte[] transform(ClassLoader loader,String className,Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if(className.equals("A")){
doClass(className, classBeingRedefined, classfileBuffer);
}
return classfileBuffer;
}
private byte[] doClass(String name, Class clazz, byte[] b) {
ClassPool pool = ClassPool.getDefault();
CtClass cl = null;
try {
cl = pool.makeClass(new java.io.ByteArrayInputStream(b));
CtMethod method = cl.getDeclaredMethod("getA2");
// here you have lot of options to explore
method.insertBefore("System.out.println(Thread.currentThread().getStackTrace()[0].getClassName()+ Thread.currentThread().getStackTrace()[0].getMethodName());");
b = cl.toBytecode();
} catch (Exception e) {
System.err.println("Could not instrument " + name
+ ", exception : " + e.getMessage());
} finally {
if (cl != null) {
cl.detach();
}
}
return b;
}
Step 3- create jar file for agent classes ( you have to set manifest file with premain class, and add javaassit jar) snippet of build file is given - you can do it by manually as well
<jar destfile="build/jar/BasicAgent.jar" basedir="build/classes">
<manifest>
<attribute name="Manifest-Version" value="1.0"/>
<attribute name="Premain-Class" value="com.sk.agent.basic.BasicAgent"/>
<attribute name="Boot-Class-Path" value="../lib/javassist.jar"/>
</manifest>
</jar>
Step 4- Run your main application with java agent - before that set VM arguments to load agent
-`javaagent:D:\softwares\AgentProject\AgentLib\build\jar\BasicAgent.jar`
Pre requisite : you would need javassist.jar in the class path.
Depending on the IDE you are using this problem is simpler to find.
Eclipse IDE has one of the most potential Call Hierarchy modules existing, you just need to put the mouse in the method declaration that you want to find and execute Ctrl + Alt + H
This will give you the entire hierarchy of which method is using the method you want to analyze.
Also the Call Hierarchy module offers a mode where you can find the methods that your method is calling.
Some extra info: http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.cdt.doc.user%2Freference%2Fcdt_u_call_hierarchy_view.htm
In IntelliJ IDEA, if you want to find usages of c.getA().getA2(); right-click on A.a2 and choose "find usages." Similarly for A.a1 and B.getCurrentA(). Unused fields and methods show up in a different color in IDEA. I've heard that IntelliJ has more refactoring power than Eclipse, but I bet Eclipse does the same thing, just slightly differently.
Also, using grep, find, and sed, you can search for the appropriate methods, just in files that are in the same package as A or that import A, or spell it out by name.
I hope I understood your question correctly. I think you can use grep -Irns function to find the calls. You can grep for getA().getA2(). That will return lines from where functions are called along with line numbers.
Rather than scanning for all references to the method getCurrentA do a scan for all references to the Class A.
This will show you everywhere that class is used within your program and you will probably find it is easier to go through and scan that list by hand and decide if you need to act on each result found than trying to do anything fancy.
The easiest way to find Call Usage is using references in eclipse,but there is a funny way
:
Change method name to B.getCurrentAA()
Build your Project
Your Project compiles with error
Go to Marks Part and see usage Error And Find Usage Of your method
I think IntelliJ can solve your problem. It have an "Analyze dataflow" feature and I think it is doing what you are looking for:
Here is my sample code:
public class Main {
private static A a = new A(); //nevermind the way it is initialized
public static A getA(){
return a;
}
public void method(){
A myA = getA();
Integer a1 = myA.getA1(); //this line is found
Integer a2 = myA.getA2(); //this line is found
}
public void anotherMethod(){
A myA = new A();
Integer a1 = myA.getA1(); //this line is NOT found
Integer a2 = myA.getA2(); //this line is NOT found
}
}
Running the "Analyze dataflow from here" (with cursor on return a; line) give me this:
Sorry to provide you only a solution with IntelliJ (tested with IntelliJ-13 Ultimate Edition)

Code Structure for Parsing Command line Arguments in Java

I have a question regarding structuring of code.
I have let us say three types of packages A,B and C.
Now, classes in package A contains classes which contain the main() function. These classes
need some command line arguments to run.
In package B, there are classes which contains some public variables, which need to be configured, at different times. For example before calling function A, the variable should be set or reset, the output differs according to this variable.
In package C, uses the classes in package B to perform some tasks. They do configure their variables as said before. Not only when the object is created, but also at intermediate stage.
Package A also has classes which in turn use classes from package B and package C. In order to configure the variables in classes of B and C, class in package A containing the main() function, reads command line arguments and passes the correct values to respective class.
Now, given this scenario, I want to use Apache Commons CLI parser.
I am unable to understand how exactly I should write my code to be structured in an elegant way. What is a good design practice for such scenario.
Initially I wrote a class without Apache to parse the command line arguments.
Since I want a suggestion on design issue, I will give an excerpt of code rather than complete code.
public class ProcessArgs
{
private String optionA= "default";
private String optionB= "default";
private String optionC= "default";
public void printHelp ()
{
System.out.println ("FLAG : DESCRIPTION : DEFAULT VALUE");
System.out.println ("-A <Option A> : Enable Option A : " + optionA);
System.out.println ("-B <Option B> : Enable Option B : " + optionB);
System.out.println ("-C <Option C> : Enable Option C : " + optionC);
}
public void printConfig()
{
System.out.println ("Option A " + optionA);
System.out.println ("Option B " + optionB);
System.out.println ("Option C " + optionC);
}
public void parseArgs (String[] args)
{
for (int i=0;i<args.length;i++)
{
if (args[i].equalsIgnoreCase ("-A"))
optionA = args[++i];
else if (args[i].equalsIgnoreCase ("-B"))
optionB = args[++i];
else if (args[i].equalsIgnoreCase ("-C"))
optionC = args[++i];
else
throw new RuntimeException ("Wrong Argument : " + args[i] + " :: -h for Help.");
}
}
}
Points to note -
I already have 50+ command line options and they are all in one place.
Every class uses only a group of command line options.
I tried to write an interface, somehow but I am unsuccessful. I am not sure if this is a good way to do it or not. I need some design guidelines.
Here is the code which I wrote -
public interface ClassOptions
{
Options getClassOptions();
void setClassOptions(Options options);
}
public class Aclass implements ClassOptions
{
private String optionA="defaultA";
private String optionB="defaultB";
public Options getClassOptions()
{
Options options = new Options();
options.addOption("A", true, "Enable Option A");
options.addOption("B", true, "Enable Option B");
return options;
}
public void setClassOptions(Options options, String args[])
{
CommandLineParser parser = new BasicParser();
CommandLine cmd=null;
try
{
cmd = parser.parse( options, args);
} catch (ParseException e)
{
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println("ignored option");
}
if(cmd.hasOption("A"))
optionA = "enabled";
if(cmd.hasOption("B"))
optionB = "enabled";
}
}
I think the problems in such writing of code are -
There are different types of arguments like int, double, string, boolean. How to handle them all.
getClassOption() and setClassOption() both contain the arguments "A", "B" for example. This code is prone to errors made while writing code, which I would like to eliminate.
I think the code is getting repetitive here, which could be encapsulated somehow in another class.
Not all the arguments are required, but can be ignored.
Thank You !
I would recommend to you JCommander.
I think it's a really good Argument Parser for Java.
You define all the Argument stuff within annotations and just call JCommander to parse it.
On top of that it also (based on your annotations) can print out the corresponding help page.
You don't have to take care about anything.
I believe you will love it! :)
Take a look at it: http://jcommander.org/
There are a lot of examples and such!
Good Luck! :)
simple example for command line argument
class CMDLineArgument
{
public static void main(String args[])
{
int length=args.length();
String array[]=new String[length];
for(int i=0;i<length;i++)
{
array[i]=args[i];
}
for(int i=0;i<length;i++)
{
System.out.println(array[i]);
}

Categories

Resources