You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cz...@apache.org on 2016/12/20 16:36:42 UTC

svn commit: r1775317 - in /felix/trunk/configurator/src: main/java/org/apache/felix/configurator/impl/json/JSMin.java main/java/org/apache/felix/configurator/impl/json/JSONUtil.java test/java/org/apache/felix/configurator/impl/json/JSMinTest.java

Author: cziegeler
Date: Tue Dec 20 16:36:41 2016
New Revision: 1775317

URL: http://svn.apache.org/viewvc?rev=1775317&view=rev
Log:
Add JSMin for handling comments in json

Added:
    felix/trunk/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSMin.java   (with props)
    felix/trunk/configurator/src/test/java/org/apache/felix/configurator/impl/json/JSMinTest.java   (with props)
Modified:
    felix/trunk/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSONUtil.java

Added: felix/trunk/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSMin.java
URL: http://svn.apache.org/viewvc/felix/trunk/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSMin.java?rev=1775317&view=auto
==============================================================================
--- felix/trunk/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSMin.java (added)
+++ felix/trunk/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSMin.java Tue Dec 20 16:36:41 2016
@@ -0,0 +1,290 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * <p>
+ * Copyright (c) 2006 John Reilly (www.inconspicuous.org) This work is a
+ * translation from C to Java of jsmin.c published by Douglas Crockford.
+ * Permission is hereby granted to use the Java version under the same
+ * conditions as the jsmin.c on which it is based.
+ * <p>
+ * http://www.crockford.com/javascript/jsmin.html
+ */
+package org.apache.felix.configurator.impl.json;
+
+import java.io.IOException;
+import java.io.PushbackReader;
+import java.io.Reader;
+import java.io.Writer;
+
+public class JSMin {
+
+    private static final int EOF = -1;
+
+    private final PushbackReader in;
+
+    private final Writer out;
+
+    private int theA;
+
+    private int theB;
+
+    private int theLookahead = EOF;
+
+    private int theX = EOF;
+
+    private int theY = EOF;
+
+    public JSMin(final Reader in, final Writer out) {
+        this.in = new PushbackReader(in);
+        this.out = out;
+    }
+
+    /**
+     * isAlphanum -- return true if the character is a letter, digit, underscore,
+     * dollar sign, or non-ASCII character.
+     */
+    private boolean isAlphanum(final int c) {
+        return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')
+            || (c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' || c > 126);
+    }
+
+    /**
+     * get -- return the next character from stdin. Watch out for lookahead. If
+     * the character is a control character, translate it to a space or
+     * linefeed.
+     */
+    private int get() throws IOException {
+        int c = theLookahead;
+        theLookahead = EOF;
+        if ( c == EOF ) {
+            c = in.read();
+        }
+
+        if (c >= ' ' || c == '\n' || c == EOF) {
+            return c;
+        }
+
+        if (c == '\r') {
+            return '\n';
+        }
+
+        return ' ';
+    }
+
+    /**
+     * peek -- get the next character without getting it.
+     */
+    private int peek() throws IOException {
+        theLookahead = get();
+        return theLookahead;
+    }
+
+    /**
+     * next -- get the next character, excluding comments. peek() is used to see
+     * if a '/' is followed by a '/' or '*'.
+     */
+    private int next() throws IOException {
+        int c = get();
+        if (c == '/') {
+            switch (peek()) {
+            case '/':
+                for (;;) {
+                    c = get();
+                    if (c <= '\n') {
+                        break;
+                    }
+                }
+                break;
+            case '*':
+                get();
+                while (c != ' ') {
+                    switch (get()) {
+                    case '*':
+                        if (peek() == '/') {
+                            get();
+                            c = ' ';
+                        }
+                        break;
+                    case EOF:
+                        throw new IOException("Unterminated comment.");
+                    }
+                }
+                break;
+            }
+
+        }
+        theY = theX;
+        theX = c;
+        return c;
+    }
+
+    /**
+     * action -- do something! What you do is determined by the argument:
+     * <ul>
+     *   <li>1 Output A. Copy B to A. Get the next B.</li>
+     *   <li>2 Copy B to A. Get the next B. (Delete A).</li>
+     *   <li>3 Get the next B. (Delete B).</li>
+     * </ul>
+     * action treats a string as a single character. Wow!<br/>
+     * action recognizes a regular expression if it is preceded by ( or , or =.
+     */
+    void action(final int d) throws IOException {
+        switch (d) {
+        case 1:
+            out.write(theA);
+            if ((theY == '\n' || theY == ' ') &&
+                (theA == '+' || theA == '-' || theA == '*' || theA == '/') &&
+                (theB == '+' || theB == '-' || theB == '*' || theB == '/')) {
+                out.write(theY);
+            }
+        case 2:
+            theA = theB;
+
+            if (theA == '\'' || theA == '"' || theA == '`') {
+                for (;;) {
+                    out.write(theA);
+                    theA = get();
+                    if (theA == theB) {
+                        break;
+                    }
+                    if (theA == '\\') {
+                        out.write(theA);
+                        theA = get();
+                    }
+                    if ( theA == EOF) {
+                        throw new IOException("Unterminated string literal.");
+                    }
+                }
+            }
+
+        case 3:
+            theB = next();
+            if (theB == '/'
+                    && (theA == '(' || theA == ',' || theA == '=' || theA == ':'
+                    || theA == '[' || theA == '!' || theA == '&' || theA == '|'
+                    || theA == '?' || theA == '+' || theA == '-' || theA == '~'
+                    || theA == '*' || theA == '/' || theA == '{' || theA == '\n')) {
+                out.write(theA);
+                if (theA == '/' || theA == '*') {
+                    out.write(' ');
+                }
+                out.write(theB);
+                for (;;) {
+                    theA = get();
+                    if (theA == '[') {
+                        for (;;) {
+                            out.write(theA);
+                            theA = get();
+                            if (theA == ']') {
+                                break;
+                            }
+                            if (theA == '\\') {
+                                out.write(theA);
+                                theA = get();
+                            }
+                            if (theA == EOF) {
+                                throw new IOException("Unterminated set in Regular Expression literal.");
+                            }
+                        }
+                    } else if (theA == '/') {
+                        switch (peek()) {
+                        case '/':
+                        case '*':
+                            throw new IOException("Unterminated set in Regular Expression literal.");
+                        }
+                        break;
+                    } else if (theA == '\\') {
+                        out.write(theA);
+                        theA = get();
+                    } else if (theA == EOF) {
+                        throw new IOException("Unterminated Regular Expression literal.");
+                    }
+                    out.write(theA);
+                }
+                theB = next();
+            }
+        }
+    }
+
+    /**
+     * jsmin -- Copy the input to the output, deleting the characters which are
+     * insignificant to JavaScript. Comments will be removed. Tabs will be
+     * replaced with spaces. Carriage returns will be replaced with linefeeds.
+     * Most spaces and linefeeds will be removed.
+     */
+    public void jsmin() throws IOException {
+        if (peek() == 0xEF) {
+            get();
+            get();
+            get();
+        }
+        theA = '\n';
+        action(3);
+        while (theA != EOF) {
+            switch (theA) {
+            case ' ':
+                action(isAlphanum(theB) ? 1: 2);
+                break;
+            case '\n':
+                switch (theB) {
+                case '{':
+                case '[':
+                case '(':
+                case '+':
+                case '-':
+                case '!':
+                case '~':
+                    action(1);
+                    break;
+                case ' ':
+                    action(3);
+                    break;
+                default:
+                    action(isAlphanum(theB) ? 1: 2);
+                }
+                break;
+            default:
+                switch (theB) {
+                case ' ':
+                    action(isAlphanum(theB) ? 1: 3);
+                    break;
+                case '\n':
+                    switch (theA) {
+                    case '}':
+                    case ']':
+                    case ')':
+                    case '+':
+                    case '-':
+                    case '"':
+                    case '\'':
+                    case '`':
+                        action(1);
+                        break;
+                    default:
+                        action(isAlphanum(theB) ? 1: 3);
+                    }
+                    break;
+                default:
+                    action(1);
+                    break;
+                }
+            }
+        }
+        out.flush();
+    }
+}
\ No newline at end of file

Propchange: felix/trunk/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSMin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSMin.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Modified: felix/trunk/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSONUtil.java
URL: http://svn.apache.org/viewvc/felix/trunk/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSONUtil.java?rev=1775317&r1=1775316&r2=1775317&view=diff
==============================================================================
--- felix/trunk/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSONUtil.java (original)
+++ felix/trunk/configurator/src/main/java/org/apache/felix/configurator/impl/json/JSONUtil.java Tue Dec 20 16:36:41 2016
@@ -19,7 +19,10 @@
 package org.apache.felix.configurator.impl.json;
 
 import java.io.IOException;
+import java.io.Reader;
 import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -235,7 +238,17 @@ public class JSONUtil {
      * @param contents The contents
      * @return The parsed JSON object or {@code null} on failure,
      */
-    public static JsonObject parseJSON(final String name, final String contents) {
+    public static JsonObject parseJSON(final String name, String contents) {
+        // minify JSON first (remove comments)
+        try (final Reader in = new StringReader(contents);
+             final Writer out = new StringWriter()) {
+            final JSMin min = new JSMin(in, out);
+            min.jsmin();
+            contents = out.toString();
+        } catch ( final IOException ioe) {
+            SystemLogger.error("Invalid JSON from " + name);
+            return null;
+        }
         try (final JsonReader reader = Json.createReader(new StringReader(contents)) ) {
             final JsonStructure obj = reader.read();
             if ( obj != null && obj.getValueType() == ValueType.OBJECT ) {

Added: felix/trunk/configurator/src/test/java/org/apache/felix/configurator/impl/json/JSMinTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/configurator/src/test/java/org/apache/felix/configurator/impl/json/JSMinTest.java?rev=1775317&view=auto
==============================================================================
--- felix/trunk/configurator/src/test/java/org/apache/felix/configurator/impl/json/JSMinTest.java (added)
+++ felix/trunk/configurator/src/test/java/org/apache/felix/configurator/impl/json/JSMinTest.java Tue Dec 20 16:36:41 2016
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.configurator.impl.json;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import org.junit.Test;
+
+public class JSMinTest {
+
+    @Test public void simpleTest() throws IOException {
+        final String input = "// Some comment\n" +
+                             "{\n"
+                             + "  \"a\" : 1,\n"
+                             + "  // another comment\n"
+                             + "  /** And more\n"
+                             + "   * comments\n"
+                             + "   */\n"
+                             + "  \"b\" : 2\n"
+                             + "}\n";
+        final StringWriter w = new StringWriter();
+        final JSMin min = new JSMin(new StringReader(input), w);
+        min.jsmin();
+        assertEquals("\n{\"a\":1,\"b\":2}", w.toString());
+    }
+}

Propchange: felix/trunk/configurator/src/test/java/org/apache/felix/configurator/impl/json/JSMinTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/configurator/src/test/java/org/apache/felix/configurator/impl/json/JSMinTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url