I am trying to find a way to parse java code source in netbeans using the Tree API, I learned through this guide how I can access high level language elements (classes,methods,fields ..).
what I'm looking for is a way to parse if else statements (for a start) since I'm trying to apply replace type code with state strategy refactoring afterwards. it is very important for me to get the if condition. Any help would be deeply appreciated.
After diving into the Compiler Tree API doc I found how to access low level code the condition of a selected if statement in my case, here is a code snippet
#Override
public Void visitIf(IfTree node, Void p) {
try {
JTextComponent editor = EditorRegistry.lastFocusedComponent();
if (editor.getDocument() == info.getDocument()) {
InputOutput io = IOProvider.getDefault().getIO("Analysis of " + info.getFileObject().getName(),
true);
ExpressionTree exTree = node.getCondition();
if (exTree.getKind() == Tree.Kind.PARENTHESIZED) {
ParenthesizedTree parTree = (ParenthesizedTree) exTree;
BinaryTree conditionTree = (BinaryTree) parTree.getExpression();
ExpressionTree identTree = conditionTree.getLeftOperand();
if (identTree.getKind() == Tree.Kind.IDENTIFIER) {
Name name = ((IdentifierTree) identTree).getName();
io.getOut().println("Hurray, this is the name of the identifier in the left operand: " + name.toString());
}
io.getOut().close();
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
return null;
}
Thankfully the code naming is intuitive otherwise the documentation doesn't help much. debugging using println is very useful to know what kind of tree to deal with next.
Related
Giving an example, lets say we have a code like the one below:
String phone = currentCustomer.getMainAddress().getContactInformation().getLandline()
As we know there is no elvis operator in Java and catching NPE like this:
String phone = null;
try {
phone = currentCustomer.getMainAddress().getContactInformation().getLandline()
} catch (NullPointerException npe) {}
Is not something anyone would advise. Using Java 8 Optional is one solution but the code is far from clear to read -> something along these lines:
String phone = Optional.ofNullable(currentCustomer).flatMap(Customer::getMainAddress)
.flatMap(Address::getContactInformation)
.map(ContactInfo::getLandline)
.orElse(null);
So, is there any other robust solution that does not sacrifice readability?
Edit: There were some good ideas already below, but let's assume the model is either auto generated (not convenient to alter each time) or inside a third party jar that would need to be rebuild from source to be modified.
The "heart" of the problem
This pattern currentCustomer.getMainAddress().getContactInformation().getLandline() is called TrainWreck and should be avoided. Had you done that - not only you'd have better encapsulation and less coupled code, as a "side-effect" you wouldn't have to deal with this problem you're currently facing.
How to do it?
Simple, the class of currentCustomer should expose a new method: getPhoneNumber() this way the user can call: currentCustomer.getPhoneNumber() without worrying about the implementation details (which are exposed by the train-wreck).
Does it completely solve my problem?
No. But now you can use Java 8 optional to tweak the last step. Unlike the example in the question, Optionals are used to return from a method when the returned value might be null, lets see how it can be implemented (inside class Customer):
Optional<String> getPhoneNumber() {
Optional<String> phone = Optional.empty();
try {
phone = Optional.of(mainAddress.getContactInformation().getLandline());
} catch (NullPointerException npe) {
// you might want to do something here:
// print to log, report error metric etc
}
return phone;
}
Per Nick's comment below, ideally, the method getLandline() would return an Optional<String>, this way we can skip the bad practice of swallowing up exceptions (and also raising them when we can avoid it), this would also make our code cleaner as well as more concise:
Optional<String> getPhoneNumber() {
Optional<String> phone = mainAddress.getContactInformation().getLandline();
return phone;
}
String s = null;
System.out.println(s == null);
or
String s = null;
if(s == null)System.out.println("Bad Input, please try again");
If your question was with the object being null, you should have made that clear in your question...
PhoneObject po = null;
if(po==null) System.out.println("This object is null");
If your problem is with checking whether all the parts of the line are null, then you should have also made that clear...
if(phone == null) return -1;
Customer c = phone.currentCustomer();
if(c == null)return -1;
MainAddress ma = c.getMainAddress();
if(ma == null) return -1;
ContactInfo ci = ma.getContactInformation();
if(ci == null)return -1;
LandLine ll = ci.getLandline();
if(ll == null)return -1;
else return ll.toNumber()//or whatever method
Honestly, code that's well written shouldn't have this many opportunities to return null.
In our uni project we were asked to build a project in which we should also provide an info class in which we should insert all the info like total number of lines of code, number of methods (in the whole project).
We were asked to provide the complete number of methods, to compute with Reflection & RTTI, and obviously with no use of external libraries.
How shall I do?
Simplest approach you can use is,
Create a class to store the info you need ( number of methods,lines or whatever) - use setters/getters.
Use a static block in all your application classes, to calculate the methods, lines etc for each class & update it to info class.
I hope at a given instant it can give you the info about the loaded number of methods/code.
As #Jägermeister rightly said, the aim of this project is to try-out things yourself. So I gave some insights - which you can follow & try out yourself.
Eventually I came to a solution, thank you all.
Here's the code:
private int getNumMethods() {
java.io.File src = new java.io.File("src/APManager2016");
int result = 0;
if (src.isDirectory()) {
String[] list = src.list((java.io.File dir, String name) -> name.toLowerCase().endsWith(".java"));
try {
for (String x : list) {
Class<?> c = Class.forName("APManager2016." + x.replace(".java", ""));
result += c.getDeclaredMethods().length;
}
} catch (ClassNotFoundException ex) {
System.err.println(ex.getMessage());
result = 0;
}
}
if (result == 0)
{
result = 111;
}
return result;
}
I have two questions about Java Convention. I try to make use od Robert C. Martin's "Clean Code".
Following case:
public void startProgressIfAllowed() {
try {
tryStartProgressIfAllowed();
} catch (Exception exception) {
// log error
}
}
private void tryStartProgressIfAllowed() {
if (isStartProgressAllowed()) {
stopProgressOnCurrentlyStartedTask();
startProgressOnThisTask();
}
}
private boolean isStartProgressAllowed() {
// Calls JOptionPane.showConfirmDialog with JOptionPane.YES_NO_OPTION.
// Created dialog contains checkbox indicating that saving currently started task is required.
// returns boolean depending on JOptionPane.YES_NO_OPTION clicked button
}
private void stopProgressOnCurrentlyStartedTask() {
// Saves currently started task depending on checkbox selecion property and stops currently started.
// What is the correct way to get checkbox selecion property?
}
Proposed solution:
public void tryStartProgressIfAllowed() {
if (tryToStopProgressOnStartedTaskIfNecessary()) {
startProgressOnThisTask();
}
}
private boolean tryToStopProgressOnStartedTaskIfNecessary() {
// Calls JOptionPane.showConfirmDialog with JOptionPane.YES_NO_OPTION.
// Created dialog contains checkbox indicating that saving currently started task is required.
// Depending on checkbox selecion property saves task.
// returns boolean depending on JOptionPane.YES_NO_OPTION clicked button
}
But this approach doesn't meet the "Command Query Separation" principle, because tryToStopProgressOnStartedTaskIfNecessary(...) method performs some logic and returns success/failure value.
I think this approach also doesn't meet the "One level of abstraction per function" principle, because I suppose "check" and "save" operations are on different levels of abstraction.
Is the method name correct to avoid disinformation? Maybe better name would be tryToStopProgressAndSaveStartedTaskIfNecessary(...)?
Is there any better solution for above problem?
What about the following:
public void tryStartProgressOnThisTaskIfAllowed() {
tryStopTaskInProgressIfAllowed()
if (!isTaskInProgress()) {
tryStartProgressOnThisTask();
}
}
private void tryStopTaskInProgressIfAllowed() {
if (!isTaskInProgress()) {
return;
}
TaskInProgressResult result = whatToDoWithTaskInProgress();
if (result == Result.KEEP) {
return;
} else if (result == Result.DROP)
tryDropTaskInProgress();
} else if (result == Result.SAVE) {
trySaveTaskInProgress();
}
}
About your points:
You now have two separate methods for C and Q
I think the two things whatToDoWithTaskInProgress and tryDropTaskInProgress are the same level of abstraction. If you'd inline the code of one or the other you were absolutely right of course.
I changed some of the method names according to my taste :) The only thing I still don't like is the part "OnThisTask" because this task is somewhat meaningless. Maybe it's only because the rest of the code is unknown maybe OnNextTask or OnNewTask are better.
The problem we were having is that we were thinking in UI terms YES/NO + checkbox value. But it is much better to think in business terms here. I identified three different outcomes that are of interest: KEEP, SAVE, DROP How the answer is obtained should not matter to the calling method.
This seems something to ask on CodeReview, see the drop down at the top left of the page.
An example of how such stateliness is realized in Java SE: the regex Matcher class.
String s = ...
Pattern pattern = Pattern.compile("...");
Matcher m = pattern.matcher(s);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, ... m.group(1) ...);
}
m.appendTail(sb);
with m.matches() and m.lookingAt as alternative circuits too.
In short state is held in a processing class on the actual data (String here).
This is related to this other question:
Last evaluated expression in Javascript
But I wanted to provide more details about what I wanted to do and show how I finally solved the problem as some users requested in the comments.
I have snippets of Javascript that are written by users of my app. This snippets need to go to a kind of template like this:
var foo1 = function(data, options) {
<snippet of code written by user>
}
var foo2 = function(data, options) {
<snippet of code written by user>
}
...
Expressions can be very different, from simple things like this:
data.price * data.qty
To more complex tings like this:
if (data.isExternal) {
data.email;
} else {
data.userId;
}
The value returned by the function should be always the last evaluated expression.
Before we had something like this:
var foo1 = function(data, options) {
return eval(<snippet of code written by user>);
}
But due to optimizations and changes we are making, we cannot keep using eval, but we need to return the last evaluated expression.
Just adding a 'return' keyword won't work because expressions can have several statements. So I need to make those functions return the last evaluated expressions.
Restrictions and clarification:
I cannot force users to add the 'return' keyword to all the scripts they have because there are many scripts written already and it is not very intuitive for simple expressions like 'a * b'.
I'm using Java and Rhino to run Javascripts on server side.
As people pointed out in Last evaluated expression in Javascript, getting the last evaluated expression is not possible in standard Javascript.
What I finally ended up doing, as suggested by FelixKling, was to manipulate the AST of the script written by the user. This way I store the user written script and the modified version, which is the one I finally run.
For manipulating the AST I used Rhino and basically modify all EXPR_RESULT nodes to store the result in a variable that I finally return at the end of the script. Here is the code to do that:
public class ScriptsManipulationService {
private static final Logger logger = LoggerFactory.getLogger(ScriptsManipulationService.class);
public String returnLastExpressionEvaluated(String script) {
Parser jsParser = new Parser();
try {
AstRoot ast = jsParser.parse(script, "script", 1);
ast.getType();
ast.visitAll(new NodeVisitor() {
#Override
public boolean visit(AstNode node) {
if (node.getType() == Token.EXPR_RESULT) {
ExpressionStatement exprNode = (ExpressionStatement) node;
Assignment assignmentNode = createAssignmentNode("_returnValue", exprNode.getExpression());
assignmentNode.setParent(exprNode);
exprNode.setExpression(assignmentNode);
}
return true;
}
});
StringBuilder result = new StringBuilder();
result.append("var _returnValue;\n");
result.append(ast.toSource());
result.append("return _returnValue;\n");
return result.toString();
} catch (Exception e) {
logger.debug(LogUtils.format("Error parsing script"), e);
return script;
}
}
private Assignment createAssignmentNode(String varName, AstNode rightNode) {
Assignment assignmentNode = new Assignment();
assignmentNode.setType(Token.ASSIGN);
Name leftNode = new Name();
leftNode.setType(Token.NAME);
leftNode.setIdentifier(varName);
leftNode.setParent(assignmentNode);
assignmentNode.setLeft(leftNode);
rightNode.setParent(assignmentNode);
assignmentNode.setRight(rightNode);
return assignmentNode;
}
}
This way, if you pass the following script:
data.price * data.qty;
You will get back:
var _returnValue;
_returnValue = data.price * data.qty;
return _returnValue;
Or if you pass:
var _returnValue;
if (data.isExternal) {
_returnValue = data.email;
} else {
_returnValue = data.userId;
}
return _returnValue;
Please keep in mind that I haven't done an exhaustive testing and will be polishing it over time, but this should show the general idea.
I have a set of sentences. For each of them I want to obtain a "generalized" typed dependencies graph in which every word is replaced by the corresponding POS tag (except verbs and some keywords like LOCATION and TARGET).
For example, from the sentence
take a left turn till you come to a LOCATION
I want to obtain
amod(take,JJ)dobj(take,NN)mark(come,IN)nsubj(come,PP)prep_to(come,LOCATION)
What is the simpler way to do this?
Ok. I solved this problem with a bit of tree manipulation.
public static void exploreTree(Tree t) {
List<Tree> child = t.getChildrenAsList();
Tree terminal;
for (Tree c : child) {
if (c.isPreTerminal()) {
terminal = c.getChild(0);
String t_value = terminal.value();
String c_value = c.value();
if (!c_value.startsWith("VB")) {
if (!t_value.equals("LOCATION") && !t_value.equals("TARGET")) {
terminal.setValue(c.value());
}
}
// test[1].setValue(test[0].value());
} else
exploreTree(c);
}
}
It change internal data of Stanford Parser tree according my request. Maybe is not the most elegant and robust solution but works.