Github user aledsage commented on a diff in the pull request: https://github.com/apache/brooklyn-server/pull/982#discussion_r214611925 --- Diff: utils/common/src/main/java/org/apache/brooklyn/util/text/StringEscapes.java --- @@ -315,12 +320,121 @@ else if (c=='\"') { throw new IllegalArgumentException("String '"+s+"' is not a valid Java string (unterminated string)"); } + /** @deprecated since 1.0.0, use {@link #unwrapJsonishListStringIfPossible(String)} (old semantics) + * or {@link #unwrapJsonishListStringIfPossible(String)} (improved) */ + public static List<String> unwrapJsonishListIfPossible(String input) { + return unwrapJsonishListStringIfPossible(input); + } + + /** converts a comma separated list in a single string to a list of json primitives or maps, + * falling back to returning the input. + * <p> + * specifically: + * <li> 1) if of form <code>[ X ]</code> (in brackets after trim), parse as YAML; + * if parse succeeds return the result, or if parse fails, return {@link Maybe#absent()}. + * <ll> 2) if not of form <code>[ X ]</code>, wrap in brackets and parse as YAML, + * and if that succeeds and is a list, return the result. + * <li> 3) otherwise, expect comma-separated tokens which after trimming are of the form "A" or B, + * where "A" is a valid Java string or C is any string not starting with ' + * and not containing " or ,. return the list of those tokens, where A and B + * are their string value, and C as a primitive if it is a number or boolean or null, + * or else a string, including the empty string if empty. + * <li> 4) if such tokens are not found, return {@link Maybe#absent()}. + * <p> + * @see #unwrapOptionallyQuotedJavaStringList(String) + **/ + public static Maybe<List<Object>> tryUnwrapJsonishList(String input) { + if (input==null) return Maybe.absent("null input cannot unwrap to a list"); + String inputT = input.trim(); + + String inputYaml = null; + if (!inputT.startsWith("[") && !inputT.endsWith("]")) { + inputYaml = "[" + inputT + "]"; + } + if (inputT.startsWith("[") && inputT.endsWith("]")) { + inputYaml = inputT; + } + if (inputYaml!=null) { + try { + Object r = Iterables.getOnlyElement( Yamls.parseAll(inputYaml) ); + if (r instanceof List) { + @SuppressWarnings("unchecked") + List<Object> result = (List<Object>)r; + return Maybe.of(result); + } + } catch (Exception e) {} + if (inputT.startsWith("[")) { + // if supplied as yaml, don't allow failures + return Maybe.absent("Supplied format looked like YAML but could not parse as YAML"); + } + } + + List<Object> result = MutableList.of(); + + // double quote: ^ \s* " ([not quote or backslash] or [backslash any-char])* " \s* (, or $) + Pattern dq = Pattern.compile("^\\s*(\"([^\"\\\\]|[\\\\.])*\")\\s*(,|$)"); + // could also support this, but we need new unescape routines +// // single quote: ^ \s* ' ([not quote or backslash] or [backslash any-char])* ' \s* (, or $) +// Pattern sq = Pattern.compile("^\\s*'([^\'\\\\]|[\\\\.])'*\\s*(,|$)"); + // no quote: ^ \s* (empty, or [not ' or " or space] ([not , or "]* [not , or " or space])?) \s* (, or $) + Pattern nq = Pattern.compile("^\\s*(|[^,\"\\s]([^,\"]*[^,\"\\s])?)\\s*(,|$)"); + + int removedChars = 0; + while (true) { + Object ri; + Matcher m = dq.matcher(input); + if (m.find()) { + try { + ri = unwrapJavaString(m.group(1)); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + return Maybe.absent("Could not match valid quote pattern" + + (removedChars>0 ? " at position "+removedChars : "") + + ": "+ Exceptions.collapseText(e)); + } + } else { + m = nq.matcher(input); + if (m.find()) { + String w = m.group(1); + + ri = w; + if (w.matches("[0-9]*.[0-9]+")) { --- End diff -- Should this not be an escaped decimal place rather than any char (`.`)? Are you meaning to deal with `e` as well? Is `.4` a valid double in yaml (rather than having to write `0.4`)?
---