All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jaxx.compiler.binding.JavaParserUtil Maven / Gradle / Ivy

There is a newer version: 3.0-alpha-6
Show newest version
/*
 * #%L
 * JAXX :: Compiler
 * %%
 * Copyright (C) 2008 - 2014 Code Lutin, Tony Chemit
 * %%
 * 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 jaxx.compiler.binding;

import jaxx.compiler.java.parser.JavaParserTreeConstants;
import jaxx.compiler.java.parser.SimpleNode;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

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 Log log = LogFactory.getLog(JavaParserUtil.class); private static final Comparator STRING_LENGTH_COMPARATOR = new Comparator() { @Override public int compare(String o1, String o2) { return o1.length() - o2.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.indexOf(".") == -1) { // 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.indexOf("(") == -1) { // 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; } Collections.sort(result, 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.indexOf("(") > -1) { // 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.get(lastExpressionNode); if (simpleNodeList == null) { simpleNodeList = new ArrayList(); casts.put(lastExpressionNode, simpleNodeList); } simpleNodeList.add(node); } if (node.getId() == JavaParserTreeConstants.JJTPRIMARYEXPRESSION) { if (store.get(node) == null) { store.put(node, 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); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy