Java8, how discover the class and method name in visitMethodInvocation? - java

With Java7 and Java8, I would like to generate a warning if some methods was called.
The warning will be print if a specific jar is present when then user compile.
I write an Annotation Processor and catch the visitMethodInvocation(). Now, I want extract the class and method names will be invoked.
Is it possible to do that ?
Or how to approach this?

You can do something like:
package mystuff;
import com.sun.source.tree.*;
import com.sun.source.util.*;
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.element.*;
import javax.tools.*;
#SupportedAnnotationTypes("*")
public class Proc extends AbstractProcessor{
#Override
public boolean process(Set<?extends TypeElement>annotations,RoundEnvironment roundEnvironment){
final Trees trees=Trees.instance(processingEnv);
for(Element element:roundEnvironment.getRootElements()){
TreePath path=trees.getPath(element);
final CompilationUnitTree compilationUnit=path.getCompilationUnit();
compilationUnit.accept(new TreeScanner<Object,Object>(){
#Override
public Object visitMethodInvocation(MethodInvocationTree tree,Object data){
tree.getMethodSelect().accept(new SimpleTreeVisitor<Object,Object>(){
#Override
public Object visitMemberSelect(MemberSelectTree tree,Object data){
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,String.format("class: %1$s\nmethod: %2$s",tree.getExpression(),tree.getIdentifier()));
return null;
}
},null);
return null;
}
},null);
}
return true;
}
}
I used that processor to process the below class
package stuff;
import java.util.*;
#MyAnnotation
class MyProgram{
public void run(){
System.out.println("Hello World!");
}
}
and achieved this result:
class: System.out
method: println
I am pretty sure that the method name generated is what you are looking for. I am pretty sure that the "class" is not exactly what you are looking for, but is a pretty good start.
In my example you probably wanted it to print "java.io.PrintStream" for the class. To get that you could use processingEnv.getElementUtils().getTypeElement("java.lang.System") to get a TypeElement representing the system class. Then you can use processingEnv.getElementUtils().getAllMembers() to get every single member of the system class. Iterate through that to find out. Use the asType method to get its type.
The preceding paragraph was a gross simplification. The processor did not know a priori that out is a static member of a class that is part of the implicitly imported java.lang package. So your code will have to try and fail to find the following classes System and java.util.System (because it is in the imports), System.out, java.util.System.out, and java.lang.System.out.
I only dealt with MemberSelect. You will have to deal with other possibilities including MethodInvocation. For example new Object().toString().hashCode() should be class=Object, method=hashCode.

As an alternative to the great answer from #emory, you can consider using the pluggable type-checking annotation processing provided by the Checker Framework. The advantage is it can help you to easily determinate the type of the method invoker. Here is an example processor based on the checker framework (add checker.jar to the classpath when compile).
#SupportedAnnotationTypes("*")
#SupportedSourceVersion(SourceVersion.RELEASE_8)
public class MyTypeProcessor extends AbstractTypeProcessor {
class MyTreePathScanner extends TreePathScanner<Void, Void> {
private final Trees trees;
private final TreePath root;
public MyTreePathScanner(TreePath root) {
this.trees = Trees.instance(processingEnv);
this.root = root;
}
#Override
public Void visitMemberSelect(MemberSelectTree node, Void aVoid) {
ExpressionTree expression = node.getExpression();
TreePath expr = TreePath.getPath(root, expression);
TypeMirror type = trees.getTypeMirror(expr);
Element typeElement = processingEnv.getTypeUtils().asElement(type);
Optional<? extends Element> invoker = typeElement.getEnclosedElements().stream().filter(
e -> e.getSimpleName().equals(node.getIdentifier())).findFirst();
if (invoker.isPresent() && invoker.get().getKind() == ElementKind.METHOD) {
System.out.println("Type: " + typeElement + ", method: " + invoker.get());
}
return super.visitMemberSelect(node, aVoid);
}
}
#Override
public void typeProcess(TypeElement typeElement, TreePath root) {
new MyTreePathScanner(root).scan(root, null);
}
}
Which is processing the following input source.
public class Test {
public void foo() {
}
public static void main(String[] args) {
System.out.println("Hello world!");
Test t = new Test();
t.foo();
}
}
Here is the output:
Type: java.io.PrintStream, method: println()
Type: Test, method: foo()

Related

Which pattern or method to use when calling a regex check method in multiple if statements?

I created a factory pattern in my class.
In this class I injected classes which implements Command interface based on incoming String parameter.
Factory class
#Component
#RequiredArgsConstructor
public class CommandFactory {
private final ACommand aCommand;
private final BCommand bCommand;
private final CCommand cCommand;
private final DCommand dCommand;
private final ECommand eCommand;
private final FCommand fCommand;
public Command createCommand(String content) {
if (aCommand.isMatching(content)) {
return aCommand;
} else if (bCommand.isMatching(content)) {
return bCommand;
} else if (cCommand.isMatching(content)) {
return cCommand;
} else if (dCommand.isMatching(content)) {
return dCommand;
} else if (eCommand.isMatching(content)) {
return eCommand;
} else if (fCommand.isMatching(content)) {
return fCommand;
} else {
return null;
}
}
In isMatching() method there are different regex'es and I try to figure out how this incoming String should be processed.
I am looking for a cleaner way to get rid of these sequential if statements. Because whenever I create a new class into this factory I add another if statement.
Maybe Stream can help?
Stream<Command> stream = Stream.of(aCommand, bCommand, cCommand ...);
return stream.filter(x -> x.isMatching(content)).findFirst().orElse(null);
Now every time you add a new class, you just add a new object to the first line.
If you want to get rid of the sequential if statements you can use streams (like user Sweeper suggested) or loops and I would also suggest to return and optional which makes null handling clearer for the client.
Here are two suggested options to get rid of if else repetitions one with loops another with streams:
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class CommandPatternExample {
private List<Command> candidates = Arrays.asList(new ACommand(), new BCommand(), new CCommand());
public Optional<Command> createCommand(String content) {
for(Command command : candidates) {
if(command.isMatching(content)) {
return Optional.of(command);
}
}
return Optional.empty();
}
public Optional<Command> createCommandStream(String content) {
return candidates.stream().filter(c -> c.isMatching(content)).findFirst();
}
}
interface Command<T> {
void execute(T obj);
boolean isMatching(String s);
}
class ACommand implements Command<String> {
#Override
public void execute(String obj) {
}
#Override
public boolean isMatching(String s) {
return "A".equals(s);
}
}
class BCommand implements Command<String> {
#Override
public void execute(String obj) {
}
#Override
public boolean isMatching(String s) {
return "B".equals(s);
}
}
class CCommand implements Command<String> {
#Override
public void execute(String obj) {
}
#Override
public boolean isMatching(String s) {
return "C".equals(s);
}
}
Map might be a good idea. Meaning if you place your command instances into a map as values where your key would be something that you could match against incoming String. Then instead of sequential search with Efficiency O(n) you can get much better performance O(1). This is a short answer.
Besides that There is an open source java library MgntUtils (wriiten by me) that contains some utility called "Self-instantiating factories" Basically it manages and the Factory for you. All you will need to do is to create a class that implements a certain interface and the utility will add it for you into a map based factory. It might be useful to you. Here is the link to an article that explains about the utilities in the library as well as where to get the library (Github and Maven central). In the article look for the paragraph "Lifecycle management (Self-instantiating factories)". Also library comes with a detailed written javadoc and code example for that feature.

Sonarqube Custom Rule- String Literal should not be duplicated, ignored in context of logger

Trying to extend the below linked Sonarqube rule to ignore the occurrence of a string literal in a logger method.
I am having issues trying to extract method names for methods (which in the context of the Base Visitor Tree may not be scoped as methods from my analysis. But have had some luck looking at methodInvocation type to extract a few method names).
So my question is does any one have a definition list of the Base Visitor Tree elements and how it would see different statements?
e.g. weeLogger.Log(exception, "exception occurred");
or
e.g. logger(exception1, "exception occured);
And as well has anyone done anything similar and share how they extracted out method names from the Base Visitor Tree class for analysis with Sonarqube?
https://github.com/SonarSource/sonar-java/blob/master/java-checks/src/main/java/org/sonar/java/checks/StringLiteralDuplicatedCheck.java
get method name
public class SomeClass extends IssuableSubscriptionVisitor {
#Override
public List<Tree.Kind> nodesToVisit() {
return ImmutableList.of(Tree.Kind.METHOD);
}
#Override
public void visitNode(Tree tree) {
MethodTree methodTree = (MethodTree) tree;
IdentifierTree methodName = methodTree.simpleName();
// getName from methodName.
}
**get invocation method name**
public class SomeClass extends IssuableSubscriptionVisitor {
public static IdentifierTree methodName(MethodInvocationTree mit) {
IdentifierTree id;
if (mit.methodSelect().is(Tree.Kind.IDENTIFIER)) {
id = (IdentifierTree) mit.methodSelect();
} else {
id = ((MemberSelectExpressionTree) mit.methodSelect()).identifier();
}
return id;
}
#Override
public void visitMethodInvocation(MethodInvocationTree tree) {
IdentifierTree id;
if (tree.methodSelect().is(Tree.Kind.IDENTIFIER)){
id = (IdentifierTree) tree.methodSelect();
} else {
id = ((MemberSelectExpressionTree) tree.methodSelect()).identifier();
}
if(id.name().matches("(.*)[lL]og(.*)")){
//Do nothing -> Ignores method with the "log" in them for scanning
}else {
scan(tree.methodSelect());
scan(tree.typeArguments());
scan(tree.arguments());
}
}

How can I add Levels to my game with less duplication of code?

I am designing a game with multiple levels. I have a setup class that sets up the board based on the argument it receives, which indicates which level it should set up. Here is the class:
public class BoardState {
public BoardState(InitialState state) {
switch (state) {
case EMPTY:
setupEmptyState();
break;
case INTEGRATIONTEST:
setupIntegrationTestState();
break;
case LEVEL_1:
setupLevelOne();
break;
case LEVEL_2:
setupLevelTwo();
break;
default:
throw new Error("Invalid level selection");
}
}
private void setupEmptyState() { }
private void setupIntegrationTestState() { }
private void setupLevelOne() { }
private void setupLevelTwo() { }
}
This works fine, but every time I add a new level I have to add code in three places: The InitialState enum which defines the list of accepted states, the switch statement in the constructor, and the body of the class, where I have to add a method to set up the level in question.
One nice thing that I want to keep is the fact that my GUI automatically populates with a new button for each level I add based on the enum defining the list of levels.
How can I refactor this code so that there is less overhead associated with adding a new level?
Often when you need to reduce code duplication, an interface arise. This time (based on your comment in OP) it seems you need to add different objects to the board depending on which level you are:
import java.util.List;
public interface LevelSettings {
List<GameObject> startingObjects();
}
Now, BoardState looks like that (no more setupX() methods)
import java.util.List;
public class BoardState {
private final List<GameObject> gameObjects;
public BoardState(LevelSettings settings) {
this.gameObjects = settings.startingObjects();
}
}
Since you also specified it is nice for you to have an enum to dynamically creates buttons on the GUI, one can combine the best of both world (interface and enum) by implementing the interface in an enum...
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public enum InitialState implements LevelSettings {
EMPTY {
#Override
public List<GameObject> startingObjects() {
return Collections.emptyList();
}
},
INTEGRATIONTEST {
#Override
public List<GameObject> startingObjects() {
GameObject g1 = new GameObject("dummy 1");
GameObject g2 = new GameObject("dummy 2");
return Arrays.asList(g1, g2);
}
},
LEVEL_1 {
#Override
public List<GameObject> startingObjects() {
//read a config file to get the starting objects informations
//or also hardcoded (not preferred)
}
},
LEVEL_2 {
#Override
public List<GameObject> startingObjects() {
//read a config file to get the starting objects
//or also hardcoded (not preferred)
}
};
}
And that's it basically. If you need to add LEVEL_3 do it in InitialState and everything will follow.
Going one step further
From here it goes beyond what you requested, feel free to ignore this part if you are not convinced.
As a good practice I would store these configurations only in config files to reduce even more the code duplication and gain in flexibility:
import java.util.List;
public enum InitialState implements LevelSettings {
EMPTY {
#Override
public List<GameObject> startingObjects() {
return readFromFile("empty.level");
}
},
INTEGRATIONTEST {
#Override
public List<GameObject> startingObjects() {
return readFromFile("integration_test.level");
}
},
LEVEL_1 {
#Override
public List<GameObject> startingObjects() {
return readFromFile("1.level");
}
},
LEVEL_2 {
#Override
public List<GameObject> startingObjects() {
return readFromFile("2.level");
}
};
private static List<GameObject> readFromFile(String filename) {
//Open file
//Serialize its content in GameObjects
//return them as a list
}
}
So that when you decide to add a new level you actually only need to know the filename in which the level's configuration is stored.
Going another step further
What you will see there is really tricky and I don't advice you to use it in production code (but it reduces code duplication) !
import java.util.List;
public enum InitialState implements LevelSettings {
EMPTY, INTEGRATIONTEST, LEVEL_1, LEVEL_2;
#Override
public List<GameObject> startingObjects() {
return readFromFile(this.name() + ".level");
}
private static List<GameObject> readFromFile(String filename) {
//Open file
//Serialize its content in GameObjects
//return them as a list
}
}
Here we rely on enum names themselves to find the corresponding correct file. This code works because it is based on the convention that the files are named accordingly to the enum names with the ".level" extension. When you need to add a new level, just add it to the enum and that's it...
You could use inheritance, polymorphism is the keyword here.
Set up your InitialState class as abstract base class (or interface if you have no common fields) and define a method public abstract void setup();.
abstract class InitialState {
public abstract void setup();
}
Then, for each of your original switch cases, derive a class from your base class, for example LevelOne, and implement its specific by overriding setup().
class LevelOne extends InitialState {
#Override
public void setup() {
// The code from "setupLevelOne()" goes here
}
}
Your BoardState class reduces to this:
public class BoardState {
public BoardState(InitialState state) {
// At runtime, the right method of the actual
// state type will be called dynamically
state.setup();
}
}
However, if you need to set interal state of your BoardState class, consider defining the setup method as public abstract void setup(BoardState boardState), so you can access its getter and setter methods.
This appraoch could also foster reuse of code, as you could add several abstract layers for different types of levels.
well you can refactor all of the work into a one method.
say it takes an int as the ID of the level, while it loads a JSON file containing structured information of each level, and creates the given level.
for example :
"levels" : [
"level" : {
"id" : "001",
"size" : "200",
"difficulty" : "2"
},
"level" : {
"id" : "002",
"size" : "300",
"difficulty" : "3"
}
]
then, in your code:
public void setupLevel(int id) throws levelNotFoundException{
//somehow like this
Document doc = parse("levels.json");
for(element elm: doc.get("levels")){
if(Integer.parseInt(elm.get("id")).equals(id)){
//setup your level
}
}
}
and then somewhere you call your method:
int levelId = getNextLevel();
try{
setupLevel(levelId);
} catch (LevelNotFoundException e){e.printStackTrace();}
or you can use XML, or simply hard code it, and store all levels in an array

How to iterate over a custom type and find specific one?

I have an ArrayList of class Olive:
ArrayList<Olive> olives = new ArrayList<Olive>();
olives.add(new Kalamata());
olives.add(new Ligurian());
olives.add(new Kalamata());
olives.add(new Ligurian());
Inside the kalamata and ligurian classes, I have set their names:
this.name = "Ligurian";
this.name = "Kalamata";
How can I iterate over the Olive type arrayList? I want to find where the name variable = "Ligurian" and then return Ligurian.getOrigin()
Use the streams API:
Olive olive = olives.stream()
.filter(o -> o.name.equals("Ligurian"))
.findAny().get();
String origin = olive.getOrigin();
If you're using Java 7 you can use a loop, which is a shame for you but also ok:
Olive found;
for(Olive olive : olives) {
if(olive.name.equals("Ligurian")) {
found = olive;
break;
}
}
String origin = found.getOrigin();
In Java, iterate over a custom Type and pick out one.
for (Olive olive : olives) {
if (olive instanceof Ligurian) {
String origin = olive.getOrigin();
}
}
Consider having this class to manage your olives (or anything else):
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TypedList<T> {
Map<Class<? extends T>,List<T>> mlt;
public TypedList() {
mlt = new HashMap<>();
}
private <U extends T> void add(Class<U> t,U o) {
List<U> lu = (List<U>)mlt.get(t);
if (lu == null) {
lu = new ArrayList<>();
mlt.put(t, (List<T>)lu);
}
lu.add(o);
}
public void add(T o) {
add((Class<T>)o.getClass(),o);
}
public <U extends T> List<U> get(Class<U> t) {
return (List<U>)mlt.get(t);
}
public <U extends T> List<? extends U> getIncludingDescendands(Class<U> t) {
List<U> nl = new ArrayList<>();
// Inefficient Unions
mlt.entrySet().stream().filter((e)->t.isAssignableFrom(e.getKey())).forEach((e)->{nl.addAll((List<U>)e.getValue());});
return nl;
}
}
Then your main code could look like something like this:
public class Main {
public static void main(String[] args) {
TypedList<Olive> olives = new TypedList<>();
olives.add(new Kalamata());
olives.add(new Ligurian());
olives.add(new Kalamata());
olives.add(new Ligurian());
olives.add(new BigKalamata());
System.out.println("Number of Ligurian: "+olives.get(Ligurian.class).size());
System.out.println("Number of Kalamata: "+olives.get(Kalamata.class).size());
System.out.println("Number of BigKalamata: "+olives.get(BigKalamata.class).size());
System.out.println("Number of Kalamata and Subspecies: "+olives.getIncludingDescendands(Kalamata.class).size());
// get first Ligurian:
Ligurian ligurian = olives.get(Ligurian.class).get(0); // Carefull for NPE
}
}
Consider also following
public interface Olive {}
public class Ligurian implements Olive {}
public class Kalamata implements Olive {}
public class BigKalamata extends Kalamata {}
Note that as an additional feature, this would work even without a getName being exposed. Rather than using getName it uses the class of the added object to subcategorize or partition. Use of the actual class name, like when using olives.get(Ligurian.class), gives as additional benefits that typo's would be caught during compilation time, and the returned object is strongly typed.
Always better to organize your data while you are accumulating it, if the overhead is negligible for doing so. This will make later processing much more efficient (if you code it right). Foresight in how you are going to use it later on helps.
One additional thought might be needed, is what to be done in case of multiple ClassLoader's. I am not sure. Might need to store internally using class name instead.

Avoiding many levels of loop nesting

I have a object graph which goes like this:
root
: childs (array)
: childs (array)
I am building a JSON response out of this so I need to loop through each collection creating code like this:
// code for root
// loop through direct root childs
for (Child child : childs) {
// Loop through the childs of the object in current context.
for (AnotherChild anotherChild : moreChilds) {
}
}
How do you avoid such code? It will be an arrow in the end. I could have created own methods for each level of for loop, but is that a good approach? Are there other approaches which is better?
If we are talking about this specific problem (building a JSON response) you use some kind of serializer like jackson or write a custom one. There is a relevant question on this topic https://stackoverflow.com/questions/338586/a-better-java-json-library
On the other hand for some other uses you can use a more functional approach like Guava or Lambdaj.
But when it comes done to big O complexity these are not much of a help there, so you may wanna try different approach if possible then.
That's a recursive structure, then you should use recursion to handle nesting. A depth first visit should do.
edit to interface JSON you would really follow the advice by #Mite Mitreski, for a recursive visit pseudocode sample:
void visit(Child tree) {
json_write_class(tree);
for (Attribute a : tree.attributes) {
json_write_attr(a);
if (tree.children != null) {
json_push_indent();
for (Child child : tree.children) {
visit(child);
}
json_pop_indent();
}
}
If you need more control, you could write kind of 'semantic actions' on nodes of that tree to establish the attributes, and implement the visitor pattern to output the data (more verbose than the first alternative).
Frequently helps to use the analogy of grammars and syntax trees, these are the most obvious sample we (as programmers) are used to.
I think you have a nasty design issue there, as the class that is doing all those loops knows a hell lot of the other classes (and thus breaking the Law of Demeter).
An approach I try to use (that I've learn from some very experienced developers) is to wrap collections (or arrays) in their own classes; and then create methods that iterate over the array/collection performing one operation. In this case, it could be calling another method in another class that wraps a collection.
In this way, each class has very little knowledge of what the other classes do (or the internals of the child objects).
Edit
Here's an example. Imagine that you have an account in a website similar to amazon. In that account, you have associated a few credit cards.
So, instead of having
class Account {
List<CreditCard> creditCards;
public CreditCard getPrimaryCard() {
//complex code to find the primary credit card
}
//lots of other code related to the account and credit cards
}
you can do
class Account {
CreditCards creditCards;
public CreditCard getPrimaryCard() {
creditCards.getPrimaryCard()
}
//lots of other code related to the account
}
class CreditCards {
List<CreditCard> creditCards;
public CreditCard getPrimaryCard() {
//complex code to find the primary credit card
}
public void addCard(CreditCard creditCard) {
//complex logic to validate that the card is not duplicated.
}
//lots of other code related to credit cards
}
In this way, Account doesn't need to know about how the creditCards are stored in memory (should it be a list? or a set? or get it from a remote webservice?)
Please bear in mind that this is a trivial example.
You could provide interface which all interested class should implement. That interface should provide method to converting a current object to JSON. See example:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class JsonProgram {
public static void main(String[] args) {
Root root = new Root(Arrays.asList(new Child(Arrays.asList(
new AnotherChild(1), new AnotherChild(2)))));
System.out.println(root.toJSON());
}
}
interface JsonState {
String toJSON();
}
class Root implements JsonState {
private List<Child> childs = new ArrayList<Child>();
public Root(List<Child> childs) {
this.childs = childs;
}
#Override
public String toJSON() {
StringBuilder builder = new StringBuilder();
builder.append("{").append("\"childs\"").append(":[");
int index = 0;
for (Child child : childs) {
builder.append(child.toJSON());
if (index < childs.size() - 1) {
builder.append(",");
}
index++;
}
builder.append("]\"}");
return builder.toString();
}
}
class Child implements JsonState {
private List<AnotherChild> anotherChilds = new ArrayList<AnotherChild>();
public Child(List<AnotherChild> anotherChilds) {
this.anotherChilds = anotherChilds;
}
#Override
public String toJSON() {
StringBuilder builder = new StringBuilder();
builder.append("{").append("\"anotherChilds\"").append(":[");
int index = 0;
for (AnotherChild child : anotherChilds) {
builder.append(child.toJSON());
if (index < anotherChilds.size() - 1) {
builder.append(",");
}
index++;
}
builder.append("]}");
return builder.toString();
}
}
class AnotherChild implements JsonState {
private int value;
public AnotherChild(int value) {
this.value = value;
}
#Override
public String toJSON() {
StringBuilder builder = new StringBuilder();
builder.append("{").append("\"value\"").append(":\"").append(value)
.append("\"}");
return builder.toString();
}
}
Output:
{
"childs":[
{
"anotherChilds":[
{
"value":"1"
},
{
"value":"2"
}
]
}
]
}
But it is not a good solution. Instead of implementing Your own solution You should use some library which can do it for You. I recommend to You google-gson. For me is the best.
EDIT - GSON EXAMPLE
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class JsonProgram {
public static void main(String[] args) {
Root root = new Root(Arrays.asList(new Child(Arrays.asList(
new AnotherChild(1), new AnotherChild(2)))));
Gson gson = new GsonBuilder().serializeNulls().create();
System.out.println(gson.toJson(root));
}
}
class Root {
private List<Child> childs = new ArrayList<Child>();
public Root(List<Child> childs) {
this.childs = childs;
}
#Override
public String toString() {
return Arrays.toString(childs.toArray());
}
}
class Child {
private List<AnotherChild> anotherChilds = new ArrayList<AnotherChild>();
public Child(List<AnotherChild> anotherChilds) {
this.anotherChilds = anotherChilds;
}
#Override
public String toString() {
return Arrays.toString(anotherChilds.toArray());
}
}
class AnotherChild {
private int value;
public AnotherChild(int value) {
this.value = value;
}
#Override
public String toString() {
return Integer.toString(value);
}
}
Above example create same output. For me this is a more elegant solution.

Categories