Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* #%L
* JAXX :: Compiler
* %%
* Copyright (C) 2008 - 2020 Code Lutin, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
package org.nuiton.jaxx.compiler.binding;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.nuiton.jaxx.compiler.java.parser.JavaParserTreeConstants;
import org.nuiton.jaxx.compiler.java.parser.SimpleNode;
import java.beans.Introspector;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Created: 4 déc. 2009
*
* @author Tony Chemit - [email protected]
* @version $Revision$
*
* Mise a jour: $Date$ par :
* $Author$
*/
public class JavaParserUtil {
/**
* Logger
*/
private static final Logger log = LogManager.getLogger(JavaParserUtil.class);
private static final Comparator STRING_LENGTH_COMPARATOR = Comparator.comparingInt(String::length);
/**
* Obtain all expressions of a node and store them in {@code store} with their dependencies expressions.
*
* Also fill the {@code literals} list of literal expressions.
*
* @param node the node to scan
* @param store the store of expressions detected with all the expression which compose the expression (can be empty)
* @param literals the list of literal expressions detected
* @param casts the list of casted expression detected
*/
public static void getExpressions(SimpleNode node, Map> store, List literals, Map> casts) {
if (node.getId() == JavaParserTreeConstants.JJTMETHODDECLARATION ||
node.getId() == JavaParserTreeConstants.JJTFIELDDECLARATION) {
//TODO add all others non intressing type of node to reject directly
return;
}
if (node.getId() == JavaParserTreeConstants.JJTPRIMARYEXPRESSION) {
// get a primary expression, look for his dependencies
scanForExpressions(node, null, store, literals, casts);
return;
}
// recurse of childs of node
for (int i = 0, count = node.jjtGetNumChildren(); i < count; i++) {
getExpressions(node.getChild(i), store, literals, casts);
}
}
/**
* Remove from expressions store, all literal expressions and dependencies on it.
*
* @param store the store of expressions with theirs dependencies
* @param literalExpressions the unvierse of literal expressions
*/
public static void removeLiteralExpressions(Map> store, List literalExpressions) {
for (SimpleNode n : literalExpressions) {
// on supprime toutes les dependences sur les expression literales
// car on en a pas besoin pour decouvrir les expressions qui peuvent etre nulles...
if (log.isDebugEnabled()) {
log.debug("Reject literal expression " + n.getText());
}
for (List dependencies : store.values()) {
dependencies.remove(n);
}
store.remove(n);
}
}
/**
* Remove from expressions sotre, all expressions with dependencies.
*
* @param store the store of expressions with their dependencies
* @param castsExpressions list of cast expression to keep
*/
public static void removeNoneStandaloneExpressions(Map> store, Map> castsExpressions) {
List rejectedExpressions = new ArrayList<>();
for (Map.Entry> e : store.entrySet()) {
List dependencies = e.getValue();
SimpleNode node = e.getKey();
if (castsExpressions.containsKey(node)) {
// the expression is part of a cast, need to keep it
continue;
}
if (!dependencies.isEmpty()) {
// expression with dependencies, don't treate it, but treate all in dependencies :)
rejectedExpressions.add(node);
if (log.isDebugEnabled()) {
log.debug("Reject expression " + node.getText() + " with " + dependencies.size() + " dependencies");
for (SimpleNode n : dependencies) {
log.debug(" " + n.getText());
}
}
}
}
for (SimpleNode node : rejectedExpressions) {
store.remove(node);
}
rejectedExpressions.clear();
}
public static Set getRequired(Set store, Map> casts) {
if (store.isEmpty()) {
return null;
}
Set castCodes = new LinkedHashSet<>();
for (List cast : casts.values()) {
for (SimpleNode node : cast) {
castCodes.add(node);
if (log.isDebugEnabled()) {
log.debug("cast = " + node.getText().trim());
}
}
}
List result = new ArrayList<>();
for (SimpleNode node : store) {
String expression = node.getText().trim();
if (result.contains(expression)) {
// already treated
continue;
}
for (SimpleNode castCode : castCodes) {
String str = castCode.getText().trim();
int index = expression.indexOf(str);
if (index > -1) {
// got a cast, replace the cast expression, by the simple expression
// we have (CAST)XXX --> XXX
if (log.isDebugEnabled()) {
log.debug("got a cast in expresion " + expression + " = " + castCode);
}
String tmp = "";
//FIXME : should check this is a complete cast : could be only a conversion...
if (index > 1) {
tmp = expression.substring(0, index - 1);
}
tmp += ((SimpleNode) castCode.jjtGetChild(1)).getText().trim() + expression.substring(index + str.length() + 1);
if (log.isDebugEnabled()) {
log.debug("REMOVED CAST : " + tmp);
}
expression = tmp;
}
}
if (!expression.contains(".")) {
// not an expression to keep
// a simple field use like 'isEnabled()' or 'field'
// or a not method invocation
if (log.isDebugEnabled()) {
log.debug("Reject simple expression " + expression);
}
continue;
}
if (!expression.contains("(")) {
// expression with no called method, probably is a constant
// should test it, but for the moment just limits bindings to interfield expressions : a.b
// is not possible, use a.getB() instead of
if (log.isDebugEnabled()) {
log.debug("Reject constant or static expression " + expression);
}
continue;
}
if (log.isDebugEnabled()) {
log.debug("Keep expression " + expression);
}
result.add(expression);
}
if (result.isEmpty()) {
return null;
}
result.sort(STRING_LENGTH_COMPARATOR);
if (log.isDebugEnabled()) {
log.debug("======= start with values : " + result);
}
Set objectCodes = new LinkedHashSet<>();
for (String expression : result) {
// test if we have a cast in this expression
Set tmp = new LinkedHashSet<>();
String[] paths = expression.split("\\s*\\.\\s*");
if (paths.length < 2) {
// just a simple expression
// TODO Should never come here...
continue;
}
if (log.isDebugEnabled()) {
log.debug("Expression to treate : " + expression + " :: " + Arrays.toString(paths));
}
StringBuilder buffer = new StringBuilder();
String last = paths[0].trim();
if (last.contains("(")) {
// first path is a method invocation or a cast
// at the moment allow cast only on the first member and do no perform any check
// must check this is a complete method invocation
String args = getMethodInvocationParameters(last);
if (args == null) {
// this path is not a method invocation
// must break
continue;
}
if (!args.isEmpty()) {
// for the moment, we only accept method with no args
// must break
continue;
}
}
buffer.append(last);
tmp.add(buffer.toString());
for (int i = 1, max = paths.length - 1; i < max; i++) {
String s = paths[i].trim();
String args = getMethodInvocationParameters(s);
if (args == null) {
// this path is not a method invocation
// must break
// if previous
break;
}
if (!args.isEmpty()) {
// for the moment, we only accept method with no args
// must break
break;
}
buffer.append(".").append(s);
last = buffer.toString();
tmp.add(last);
}
objectCodes.addAll(tmp);
}
if (log.isDebugEnabled()) {
log.debug("Detected requirements : " + objectCodes);
}
return objectCodes;
}
public static String getMethodInvocationParameters(String code) {
int openIndex = code.indexOf("(");
int closeIndex = code.lastIndexOf(")");
if (openIndex > -1 && closeIndex > -1) {
if (closeIndex == openIndex + 1) {
return "";
}
// missing something
return code.substring(openIndex + 1, closeIndex - 1).trim();
}
return null;
}
public static String getPropertyNameFromMethod(String code) {
int openIndex = code.indexOf("(");
if (openIndex != -1) {
code = code.substring(0, openIndex);
}
int index = 3;
if (code.startsWith("is")) {
index = 2;
}
code = code.substring(index);
code = Introspector.decapitalize(code);
return code;
}
public static void scanForExpressions(SimpleNode node, SimpleNode lastExpressionNode, Map> store, List literals, Map> casts) {
String nodeExpression = node.getText().trim();
if (log.isTraceEnabled()) {
log.trace("node " + node.getId() + " nbChilds : " + node.jjtGetNumChildren() + " : " + nodeExpression);
}
if (node.getId() == JavaParserTreeConstants.JJTLITERAL) {
// expression literal qu'on ne veut pas garder ?
if (log.isDebugEnabled()) {
log.debug("detected literal " + nodeExpression + " for last expression " + lastExpressionNode.getText());
}
literals.add(lastExpressionNode);
return;
}
if (node.getId() == JavaParserTreeConstants.JJTCASTEXPRESSION) {
// expression literal qu'on ne veut pas garder ?
if (log.isDebugEnabled()) {
log.debug("detected cast " + nodeExpression + " for last expression " + lastExpressionNode.getText());
}
List simpleNodeList = casts.computeIfAbsent(lastExpressionNode, k -> new ArrayList<>());
simpleNodeList.add(node);
}
if (node.getId() == JavaParserTreeConstants.JJTPRIMARYEXPRESSION) {
store.computeIfAbsent(node, k -> new ArrayList<>());
if (lastExpressionNode == null) {
// premiere entree dans la methode (detection d'une nouvelle expression)
// rien a faire
} else {
// on vient d'un appel recursif, on ajoute le noeud courant a la liste des expression de l'expression parent
List simpleNodeList = store.get(lastExpressionNode);
if (simpleNodeList == null) {
simpleNodeList = new ArrayList<>();
store.put(node, simpleNodeList);
}
simpleNodeList.add(node);
}
// on change la derniere expression rencontree
lastExpressionNode = node;
}
// on parcours tous les fils du noeud courant
for (int i = 0, count = node.jjtGetNumChildren(); i < count; i++) {
scanForExpressions(node.getChild(i), lastExpressionNode, store, literals, casts);
}
}
}