OSDir


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GitHub] brooklyn-server pull request #982: Improve coercions esp with generics


Github user aledsage commented on a diff in the pull request:

    https://github.com/apache/brooklyn-server/pull/982#discussion_r214642777
  
    --- 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 --
    
    It was a bit tricky to actually get into this code block! Sensible-looking things are pretty much always covered by the `Yamls.parseAll`. An example failing test is:
    
    ```
    Assert.assertEquals(JavaStringEscapes.tryUnwrapJsonishList("[1, 123").get(),
            MutableList.of("[1", 123));
    ```
    This gives `Double.valueOf(123)`  as the second value in the list.


---