From 951e517caf3c95676e341c3c453d7148db8c16e3 Mon Sep 17 00:00:00 2001 From: Koen De Groote Date: Thu, 11 May 2017 12:07:10 +0200 Subject: [PATCH] Replaced Tail Recursion while while/true loops. (#1019) --- .../config/AbstractNamingConvention.java | 59 +++--- src/main/java/io/ebean/util/StringHelper.java | 193 +++++++++--------- .../server/deploy/BeanDescriptor.java | 58 +++--- .../server/deploy/DeployUpdateParser.java | 62 +++--- .../server/deploy/DetermineAggPath.java | 22 +- .../server/deploy/parse/DeployInherit.java | 18 +- .../server/query/SqlTreeBuilder.java | 39 ++-- .../server/type/TypeReflectHelper.java | 11 +- 8 files changed, 250 insertions(+), 212 deletions(-) diff --git a/src/main/java/io/ebean/config/AbstractNamingConvention.java b/src/main/java/io/ebean/config/AbstractNamingConvention.java index e97d7a5db..6c2ca3f46 100644 --- a/src/main/java/io/ebean/config/AbstractNamingConvention.java +++ b/src/main/java/io/ebean/config/AbstractNamingConvention.java @@ -185,30 +185,33 @@ public abstract class AbstractNamingConvention implements NamingConvention { */ @Override public TableName getTableName(Class beanClass) { + while (true) { - TableName tableName = getTableNameFromAnnotation(beanClass); - if (tableName == null) { - Class supCls = beanClass.getSuperclass(); - if (hasInheritance(supCls)) { - // get the table as per inherited class in case there - // is not a table annotation in the inheritance hierarchy - return getTableName(supCls); + TableName tableName = getTableNameFromAnnotation(beanClass); + if (tableName == null) { + Class supCls = beanClass.getSuperclass(); + if (hasInheritance(supCls)) { + // get the table as per inherited class in case there + // is not a table annotation in the inheritance hierarchy + beanClass = supCls; + continue; + } + + tableName = getTableNameByConvention(beanClass); } - tableName = getTableNameByConvention(beanClass); + // Use naming convention for catalog or schema, + // if not set in the annotation. + String catalog = tableName.getCatalog(); + if (isEmpty(catalog)) { + catalog = getCatalog(); + } + String schema = tableName.getSchema(); + if (isEmpty(schema)) { + schema = getSchema(); + } + return new TableName(catalog, schema, tableName.getName()); } - - // Use naming convention for catalog or schema, - // if not set in the annotation. - String catalog = tableName.getCatalog(); - if (isEmpty(catalog)) { - catalog = getCatalog(); - } - String schema = tableName.getSchema(); - if (isEmpty(schema)) { - schema = getSchema(); - } - return new TableName(catalog, schema, tableName.getName()); } /** @@ -271,14 +274,16 @@ public abstract class AbstractNamingConvention implements NamingConvention { * Search recursively for an @Table in the class hierarchy. */ protected Table findTableAnnotation(Class cls) { - if (cls.equals(Object.class)) { - return null; + while (true) { + if (cls.equals(Object.class)) { + return null; + } + Table table = cls.getAnnotation(Table.class); + if (table != null) { + return table; + } + cls = cls.getSuperclass(); } - Table table = cls.getAnnotation(Table.class); - if (table != null) { - return table; - } - return findTableAnnotation(cls.getSuperclass()); } /** diff --git a/src/main/java/io/ebean/util/StringHelper.java b/src/main/java/io/ebean/util/StringHelper.java index a4b482e08..639aad8c6 100644 --- a/src/main/java/io/ebean/util/StringHelper.java +++ b/src/main/java/io/ebean/util/StringHelper.java @@ -48,42 +48,44 @@ public class StringHelper { */ private static HashMap parseNameQuotedValue(HashMap map, String tag, int pos) throws RuntimeException { + while (true) { - int equalsPos = tag.indexOf('=', pos); - if (equalsPos > -1) { - // check for begin quote... - char firstQuote = tag.charAt(equalsPos + 1); - if (firstQuote != SINGLE_QUOTE && firstQuote != DOUBLE_QUOTE) { - throw new RuntimeException("missing begin quote at " + (equalsPos) + "[" - + tag.charAt(equalsPos + 1) + "] in [" + tag + "]"); + int equalsPos = tag.indexOf('=', pos); + if (equalsPos > -1) { + // check for begin quote... + char firstQuote = tag.charAt(equalsPos + 1); + if (firstQuote != SINGLE_QUOTE && firstQuote != DOUBLE_QUOTE) { + throw new RuntimeException("missing begin quote at " + (equalsPos) + "[" + + tag.charAt(equalsPos + 1) + "] in [" + tag + "]"); + } + + // check for end quote... + int endQuotePos = tag.indexOf(firstQuote, equalsPos + 2); + if (endQuotePos == -1) { + throw new RuntimeException("missing end quote [" + firstQuote + "] after " + pos + " in [" + tag + "]"); + } + + // we have a valid name and value... + // dp("pos="+pos+" equalsPos="+equalsPos+" + // endQuotePos="+endQuotePos); + String name = tag.substring(pos, equalsPos); + // dp("name="+name+"; value="+value+";"); + + // trim off any whitespace from the front of name... + name = trimFront(name, " "); + if ((name.indexOf(SINGLE_QUOTE) > -1) || (name.indexOf(DOUBLE_QUOTE) > -1)) { + throw new RuntimeException("attribute name contains a quote [" + name + "]"); + } + + String value = tag.substring(equalsPos + 2, endQuotePos); + map.put(name, value); + + pos = endQuotePos + 1; + + } else { + // no more equals... stop parsing... + return map; } - - // check for end quote... - int endQuotePos = tag.indexOf(firstQuote, equalsPos + 2); - if (endQuotePos == -1) { - throw new RuntimeException("missing end quote [" + firstQuote + "] after " + pos + " in [" + tag + "]"); - } - - // we have a valid name and value... - // dp("pos="+pos+" equalsPos="+equalsPos+" - // endQuotePos="+endQuotePos); - String name = tag.substring(pos, equalsPos); - // dp("name="+name+"; value="+value+";"); - - // trim off any whitespace from the front of name... - name = trimFront(name, " "); - if ((name.indexOf(SINGLE_QUOTE) > -1) || (name.indexOf(DOUBLE_QUOTE) > -1)) { - throw new RuntimeException("attribute name contains a quote [" + name + "]"); - } - - String value = tag.substring(equalsPos + 2, endQuotePos); - map.put(name, value); - - return parseNameQuotedValue(map, tag, endQuotePos + 1); - - } else { - // no more equals... stop parsing... - return map; } } @@ -96,14 +98,15 @@ public class StringHelper { } private static int countOccurances(String content, String occurs, int pos, int countSoFar) { - int equalsPos = content.indexOf(occurs, pos); - if (equalsPos > -1) { - countSoFar += 1; - pos = equalsPos + occurs.length(); - // dp("countSoFar="+countSoFar+" pos="+pos); - return countOccurances(content, occurs, pos, countSoFar); - } else { - return countSoFar; + while (true) { + int equalsPos = content.indexOf(occurs, pos); + if (equalsPos > -1) { + countSoFar += 1; + pos = equalsPos + occurs.length(); + // dp("countSoFar="+countSoFar+" pos="+pos); + } else { + return countSoFar; + } } } @@ -135,14 +138,16 @@ public class StringHelper { * @param trim the string to trim off the front */ public static String trimFront(String source, String trim) { - if (source == null) { - return null; - } - if (source.indexOf(trim) == 0) { - // dp("trim ..."); - return trimFront(source.substring(trim.length()), trim); - } else { - return source; + while (true) { + if (source == null) { + return null; + } + if (source.indexOf(trim) == 0) { + // dp("trim ..."); + source = source.substring(trim.length()); + } else { + return source; + } } } @@ -158,55 +163,57 @@ public class StringHelper { */ private static HashMap getKeyValue(HashMap map, int pos, String allNameValuePairs, String listDelimiter, String nameValueSeparator) { + while (true) { - if (pos >= allNameValuePairs.length()) { - // dp("end as "+pos+" >= "+allNameValuePairs.length() ); - return map; - } - - int equalsPos = allNameValuePairs.indexOf(nameValueSeparator, pos); - int delimPos = allNameValuePairs.indexOf(listDelimiter, pos); - - if (delimPos == -1) { - delimPos = allNameValuePairs.length(); - } - if (equalsPos == -1) { - // dp("no more equals..."); - return map; - } - if (delimPos == (equalsPos + 1)) { - // dp("Ignoring as nothing between delim and equals... - // delim:"+delimPos+" eq:"+equalsPos); - return getKeyValue(map, delimPos + 1, allNameValuePairs, listDelimiter, - nameValueSeparator); - } - if (equalsPos > delimPos) { - // there is a key without a value? - String key = allNameValuePairs.substring(pos, delimPos); - key = key.trim(); - if (!key.isEmpty()) { - map.put(key, null); + if (pos >= allNameValuePairs.length()) { + // dp("end as "+pos+" >= "+allNameValuePairs.length() ); + return map; } - return getKeyValue(map, delimPos + 1, allNameValuePairs, listDelimiter, - nameValueSeparator); - } - String key = allNameValuePairs.substring(pos, equalsPos); + int equalsPos = allNameValuePairs.indexOf(nameValueSeparator, pos); + int delimPos = allNameValuePairs.indexOf(listDelimiter, pos); - if (delimPos > -1) { - String value = allNameValuePairs.substring(equalsPos + 1, delimPos); - // dp("cont "+key+","+value+" pos:"+pos+" - // len:"+allNameValuePairs.length()); - key = key.trim(); + if (delimPos == -1) { + delimPos = allNameValuePairs.length(); + } + if (equalsPos == -1) { + // dp("no more equals..."); + return map; + } + if (delimPos == (equalsPos + 1)) { + // dp("Ignoring as nothing between delim and equals... + // delim:"+delimPos+" eq:"+equalsPos); + pos = delimPos + 1; + continue; + } + if (equalsPos > delimPos) { + // there is a key without a value? + String key = allNameValuePairs.substring(pos, delimPos); + key = key.trim(); + if (!key.isEmpty()) { + map.put(key, null); + } + pos = delimPos + 1; + continue; - map.put(key, value); - pos = delimPos + 1; + } + String key = allNameValuePairs.substring(pos, equalsPos); - // recurse the rest of the values... - return getKeyValue(map, pos, allNameValuePairs, listDelimiter, nameValueSeparator); - } else { - // dp("ERROR: delimPos < 0 ???"); - return map; + if (delimPos > -1) { + String value = allNameValuePairs.substring(equalsPos + 1, delimPos); + // dp("cont "+key+","+value+" pos:"+pos+" + // len:"+allNameValuePairs.length()); + key = key.trim(); + + map.put(key, value); + pos = delimPos + 1; + + // recurse the rest of the values... + + } else { + // dp("ERROR: delimPos < 0 ???"); + return map; + } } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index b4541b07e..a9af1cdbf 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -1726,15 +1726,19 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { * account inheritance. */ public BeanProperty getBeanPropertyFromPath(String path) { + BeanDescriptor other = this; + while (true) { - String[] split = SplitName.splitBegin(path); - if (split[1] == null) { - return _findBeanProperty(split[0]); + String[] split = SplitName.splitBegin(path); + if (split[1] == null) { + return other._findBeanProperty(split[0]); + } + BeanPropertyAssoc assocProp = (BeanPropertyAssoc) other._findBeanProperty(split[0]); + BeanDescriptor targetDesc = assocProp.getTargetDescriptor(); + + path = split[1]; + other = targetDesc; } - BeanPropertyAssoc assocProp = (BeanPropertyAssoc) _findBeanProperty(split[0]); - BeanDescriptor targetDesc = assocProp.getTargetDescriptor(); - - return targetDesc.getBeanPropertyFromPath(split[1]); } @Override @@ -1746,18 +1750,22 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { * Return the BeanDescriptor for a given path of Associated One or Many beans. */ public BeanDescriptor getBeanDescriptor(String path) { - if (path == null) { - return this; - } - String[] splitBegin = SplitName.splitBegin(path); + BeanDescriptor result = this; + while (true) { + if (path == null) { + return result; + } + String[] splitBegin = SplitName.splitBegin(path); - BeanProperty beanProperty = findBeanProperty(splitBegin[0]); - if (beanProperty instanceof BeanPropertyAssoc) { - BeanPropertyAssoc assocProp = (BeanPropertyAssoc) beanProperty; - return assocProp.getTargetDescriptor().getBeanDescriptor(splitBegin[1]); + BeanProperty beanProperty = result.findBeanProperty(splitBegin[0]); + if (beanProperty instanceof BeanPropertyAssoc) { + BeanPropertyAssoc assocProp = (BeanPropertyAssoc) beanProperty; + path = splitBegin[1]; + result = assocProp.getTargetDescriptor(); - } else { - throw new PersistenceException("Invalid path " + path + " from " + getFullName()); + } else { + throw new PersistenceException("Invalid path " + path + " from " + result.getFullName()); + } } } @@ -1777,13 +1785,17 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { *

*/ public BeanPropertyAssocOne getUnidirectional() { - if (unidirectional != null) { - return unidirectional; + BeanDescriptor other = this; + while (true) { + if (other.unidirectional != null) { + return other.unidirectional; + } + if (other.inheritInfo != null && !other.inheritInfo.isRoot()) { + other = other.inheritInfo.getParent().desc(); + continue; + } + return null; } - if (inheritInfo != null && !inheritInfo.isRoot()) { - return inheritInfo.getParent().desc().getUnidirectional(); - } - return null; } /** diff --git a/src/main/java/io/ebeaninternal/server/deploy/DeployUpdateParser.java b/src/main/java/io/ebeaninternal/server/deploy/DeployUpdateParser.java index 73e66d699..3aa8ce83d 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DeployUpdateParser.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DeployUpdateParser.java @@ -36,41 +36,43 @@ public final class DeployUpdateParser extends DeployParser { } private String convertSubword(int start, String currentWord, StringBuilder localBuffer) { + while (true) { - int dotPos = currentWord.indexOf('.', start); - if (start == 0 && dotPos == -1) { - return currentWord; - } - if (start == 0) { - localBuffer = new StringBuilder(); - } - if (dotPos == -1) { - // no match... - localBuffer.append(currentWord.substring(start)); - return localBuffer.toString(); - } + int dotPos = currentWord.indexOf('.', start); + if (start == 0 && dotPos == -1) { + return currentWord; + } + if (start == 0) { + localBuffer = new StringBuilder(); + } + if (dotPos == -1) { + // no match... + localBuffer.append(currentWord.substring(start)); + return localBuffer.toString(); + } - // append up to the dot - localBuffer.append(currentWord.substring(start, dotPos + 1)); + // append up to the dot + localBuffer.append(currentWord.substring(start, dotPos + 1)); - if (dotPos == currentWord.length() - 1) { - // ends with a "." ??? - return localBuffer.toString(); - } + if (dotPos == currentWord.length() - 1) { + // ends with a "." ??? + return localBuffer.toString(); + } - // get the remainder after the dot - start = dotPos + 1; - String remainder = currentWord.substring(start, currentWord.length()); + // get the remainder after the dot + start = dotPos + 1; + String remainder = currentWord.substring(start, currentWord.length()); - //String dbWord = deployMap.get(remainder.toLowerCase()); - String dbWord = getDeployWord(remainder); - if (dbWord != null) { - // we have found a match for the remainder - localBuffer.append(dbWord); - return localBuffer.toString(); - } else { - // - return convertSubword(start, currentWord, localBuffer); + //String dbWord = deployMap.get(remainder.toLowerCase()); + String dbWord = getDeployWord(remainder); + if (dbWord != null) { + // we have found a match for the remainder + localBuffer.append(dbWord); + return localBuffer.toString(); + } else { + // + + } } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/DetermineAggPath.java b/src/main/java/io/ebeaninternal/server/deploy/DetermineAggPath.java index b57d9973b..83608456b 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DetermineAggPath.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DetermineAggPath.java @@ -79,18 +79,22 @@ class DetermineAggPath { } String getManyPath(int pos, DeployBeanDescriptor desc) { + while (true) { - String path = paths[pos]; - DeployBeanProperty details = desc.getBeanProperty(path); - if (details instanceof DeployBeanPropertyAssocMany) { - return path(pos); + String path = paths[pos]; + DeployBeanProperty details = desc.getBeanProperty(path); + if (details instanceof DeployBeanPropertyAssocMany) { + return path(pos); - } else if (details instanceof DeployBeanPropertyAssocOne) { - DeployBeanPropertyAssocOne one = (DeployBeanPropertyAssocOne) details; - DeployBeanDescriptor targetDesc = one.getTargetDeploy(); - return getManyPath(pos + 1, targetDesc); + } else if (details instanceof DeployBeanPropertyAssocOne) { + DeployBeanPropertyAssocOne one = (DeployBeanPropertyAssocOne) details; + DeployBeanDescriptor targetDesc = one.getTargetDeploy(); + desc = targetDesc; + pos = pos + 1; + continue; + } + throw new IllegalArgumentException("Can not find path to many in aggregation formula [" + aggregation + "]"); } - throw new IllegalArgumentException("Can not find path to many in aggregation formula [" + aggregation + "]"); } } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java index a89bed0d4..a4a4f5539 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java @@ -146,15 +146,17 @@ public class DeployInherit { } private boolean isInheritanceClass(Class cls) { - if (cls.equals(Object.class)) { - return false; + while (true) { + if (cls.equals(Object.class)) { + return false; + } + Annotation a = AnnotationBase.findAnnotation(cls, Inheritance.class); + if (a != null) { + return true; + } + // search up the inheritance heirarchy + cls = cls.getSuperclass(); } - Annotation a = AnnotationBase.findAnnotation(cls, Inheritance.class); - if (a != null) { - return true; - } - // search up the inheritance heirarchy - return isInheritanceClass(cls.getSuperclass()); } } diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java index 648cfb296..46a2b924f 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java @@ -674,28 +674,31 @@ public final class SqlTreeBuilder { */ private SqlTreeNodeExtraJoin findExtraJoinRoot(String includeProp, SqlTreeNodeExtraJoin childJoin) { + while (true) { - int dotPos = includeProp.lastIndexOf('.'); - if (dotPos == -1) { - // no parent possible(parent is root) - return childJoin; - - } else { - // look in register ... - String parentPropertyName = includeProp.substring(0, dotPos); - if (selectIncludes.contains(parentPropertyName)) { - // parent already handled by select + int dotPos = includeProp.lastIndexOf('.'); + if (dotPos == -1) { + // no parent possible(parent is root) return childJoin; - } - SqlTreeNodeExtraJoin parentJoin = joinRegister.get(parentPropertyName); - if (parentJoin == null) { - // we need to create this the parent implicitly... - parentJoin = createJoinLeaf(parentPropertyName); - } + } else { + // look in register ... + String parentPropertyName = includeProp.substring(0, dotPos); + if (selectIncludes.contains(parentPropertyName)) { + // parent already handled by select + return childJoin; + } - parentJoin.addChild(childJoin); - return findExtraJoinRoot(parentPropertyName, parentJoin); + SqlTreeNodeExtraJoin parentJoin = joinRegister.get(parentPropertyName); + if (parentJoin == null) { + // we need to create this the parent implicitly... + parentJoin = createJoinLeaf(parentPropertyName); + } + + parentJoin.addChild(childJoin); + childJoin = parentJoin; + includeProp = parentPropertyName; + } } } diff --git a/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java b/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java index 232608502..95cc0529f 100644 --- a/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java +++ b/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java @@ -17,11 +17,14 @@ public class TypeReflectHelper { public static Class getClass(Type type) { - if (type instanceof ParameterizedType) { - return getClass(((ParameterizedType) type).getRawType()); - } + while (true) { + if (type instanceof ParameterizedType) { + type = ((ParameterizedType) type).getRawType(); + continue; + } - return (Class) type; + return (Class) type; + } } private static Type[] getParamType(Class cls, Class matchRawType) {