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

com.hfg.javascript.JsArray Maven / Gradle / Ivy

There is a newer version: 20240423
Show newest version
package com.hfg.javascript;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.hfg.util.StringUtil;
import com.hfg.xml.XMLException;

//------------------------------------------------------------------------------
/**
 A Javascript array container useful for creating JSON.
 
JSON RFC: http://www.ietf.org/rfc/rfc4627.txt
@author J. Alex Taylor, hairyfatguy.com */ //------------------------------------------------------------------------------ // com.hfg Library // // This library 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 2.1 of the License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com // [email protected] //------------------------------------------------------------------------------ public class JsArray extends ArrayList implements JsCollection { private static final Pattern UNQUOTED_VALUE_PATTERN = Pattern.compile("(.+?)\\s*[,}\\]]"); //-------------------------------------------------------------------------- public JsArray() { super(); } //-------------------------------------------------------------------------- public JsArray(int inInitialCapacity) { super(inInitialCapacity); } //-------------------------------------------------------------------------- public JsArray(Collection inCollection) { super(inCollection); } //-------------------------------------------------------------------------- public JsArray(Object[] inArray) { this(); if (inArray != null) { for (Object obj : inArray) { add(obj); } } } //-------------------------------------------------------------------------- public JsArray(int[] inArray) { this(); if (inArray != null) { for (Object obj : inArray) { add(obj); } } } //-------------------------------------------------------------------------- public JsArray(long[] inArray) { this(); if (inArray != null) { for (Object obj : inArray) { add(obj); } } } //-------------------------------------------------------------------------- public JsArray(float[] inArray) { this(); if (inArray != null) { for (Object obj : inArray) { add(obj); } } } //-------------------------------------------------------------------------- public JsArray(double[] inArray) { this(); if (inArray != null) { for (Object obj : inArray) { add(obj); } } } //-------------------------------------------------------------------------- public JsArray(CharSequence inJSONString) { if (StringUtil.isSet(inJSONString)) { parse(inJSONString); } } //########################################################################### // PUBLIC METHODS //########################################################################### //-------------------------------------------------------------------------- @Override public String toString() { return toJSON(); } //-------------------------------------------------------------------------- public String toJSON() { ByteArrayOutputStream outStream; try { outStream = new ByteArrayOutputStream(2048); toJSON(outStream); outStream.close(); } catch (Exception e) { throw new XMLException(e); } return outStream.toString(); } //--------------------------------------------------------------------------- public void toJSON(OutputStream inStream) { // JSON should be encoded with UTF-8. PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(inStream, StandardCharsets.UTF_8)), true); toJSON(writer); writer.flush(); } //-------------------------------------------------------------------------- public void toJSON(Writer inWriter) { try { inWriter.write("[ "); int i = 0; for (Object value : this) { if (i > 0) { inWriter.write(", "); } inWriter.write(composeValueJSON(value)); i++; } inWriter.write(" ]"); } catch (IOException e) { throw new RuntimeException(e); } } //-------------------------------------------------------------------------- public String toJavascript() { ByteArrayOutputStream outStream; try { outStream = new ByteArrayOutputStream(2048); toJavascript(outStream); outStream.close(); } catch (Exception e) { throw new XMLException(e); } return outStream.toString(); } //--------------------------------------------------------------------------- public void toJavascript(OutputStream inStream) { PrintWriter writer = new PrintWriter(inStream); toJavascript(writer); writer.flush(); } //-------------------------------------------------------------------------- public void toJavascript(Writer inWriter) { try { inWriter.write("[ "); int i = 0; for (Object value : this) { if (i > 0) { inWriter.write(", "); } inWriter.write(composeValueJavascript(value)); i++; } inWriter.write(" ]"); } catch (IOException e) { throw new RuntimeException(e); } } //-------------------------------------------------------------------------- public String getString(int inIndex) { Object value = get(inIndex); return (value != null ? value.toString() : null); } //########################################################################### // PRIVATE METHODS //########################################################################### //-------------------------------------------------------------------------- private String composeValueJSON(Object inValue) { String value = "null"; if (inValue != null) { if (inValue instanceof Number || inValue instanceof Boolean) { value = inValue.toString(); } else if (inValue instanceof JsArray) { value = ((JsArray) inValue).toJSON(); } else if (inValue instanceof JsObjMap) { value = ((JsObjMap) inValue).toJSON(); } else { value = "\"" + JSONUtil.escapeString(inValue.toString()) + "\""; } } return value; } //-------------------------------------------------------------------------- private String composeValueJavascript(Object inValue) { String value = "null"; if (inValue != null) { if (inValue instanceof Number || inValue instanceof Boolean) { value = inValue.toString(); } else if (inValue instanceof JsArray) { value = ((JsArray) inValue).toJavascript(); } else if (inValue instanceof JsObjMap) { value = ((JsObjMap) inValue).toJavascript(); } else { value = "\"" + JSONUtil.escapeString(inValue.toString()) + "\""; } } return value; } //-------------------------------------------------------------------------- private void parse(CharSequence inString) { String str = inString.toString().trim(); if (str.charAt(0) != '[' || str.charAt(str.length() - 1) != ']') { throw new RuntimeException("JSON array string must be enclosed with []!"); } int index = 1; while (index < str.length() - 1) { char theChar = str.charAt(index); if (Character.isWhitespace(theChar) || theChar == ',') { index++; } else if (theChar == '[') // Array within the array { // Find the ending bracket int depth = 1; char quote = ' '; boolean inEscape = false; boolean inValue = false; int end = index + 1; while (end < str.length() -1 && (depth != 1 || inValue || str.charAt(end) != ']')) { char theEndChar = str.charAt(end); if (theEndChar == '\\' && inValue) { inEscape = ! inEscape; } else { if (theEndChar == '\'' && (str.charAt(end - 1) != '\\' || !inEscape)) { if (!inValue) { inValue = true; quote = '\''; } else if (quote == '\'') { inValue = false; } } else if (theEndChar == '"' && (str.charAt(end - 1) != '\\' || !inEscape)) { if (!inValue) { inValue = true; quote = '"'; } else if (quote == '"') { inValue = false; } } else if (!inValue && theEndChar == '[') { depth++; } else if (!inValue && theEndChar == ']') { depth--; } if (inEscape) { inEscape = false; } } end++; } JsArray value = new JsArray(str.substring(index, end + 1)); add(value); index = end + 1; } else if (theChar == '{') // Map within the array { // Find the ending brace int depth = 1; char quote = ' '; boolean inValue = false; int escapeIdx = -10; int end = index + 1; while (end < str.length() -1 && (depth != 1 || inValue || str.charAt(end) != '}')) { char theEndChar = str.charAt(end); if (theEndChar == '\\' && inValue && escapeIdx < end - 1) { escapeIdx = end; } if (theEndChar == '\'' && (str.charAt(end -1) != '\\' || escapeIdx < end - 1)) { if (! inValue) { inValue = true; quote = '\''; } else if (quote == '\'') { inValue = false; } } else if (theEndChar == '"' && (str.charAt(end -1) != '\\' || escapeIdx < end - 1)) { if (! inValue) { inValue = true; quote = '"'; } else if (quote == '"') { inValue = false; } } else if (! inValue && theEndChar == '{') { depth++; } else if (! inValue && theEndChar == '}') { depth--; } end++; } // JsObjMap value = new JsObjMap(StringUtil.replaceAll(str.substring(index, end + 1), "\\", "\\\\")); JsObjMap value = new JsObjMap(str.substring(index, end + 1)); add(value); index = end + 1; } else { if (theChar == '"') { boolean inEscape = false; int valueStartIndex = index; StringBuilder valueBuffer = new StringBuilder(); // Continue until we find the next unescaped quote. while ((index++) < str.length() - 1 && ((theChar = str.charAt(index)) != '"') || inEscape) { if (theChar == '\\') { inEscape = ! inEscape; } else if (inEscape) { inEscape = false; } if (! inEscape) { valueBuffer.append(theChar); } } if (index == str.length() - 1) { throw new RuntimeException("Problem parsing value @ position " + valueStartIndex + " in JSON string!"); } index++; // consume the trailing quote add(JSONUtil.unescapeString(valueBuffer.toString())); } else { Matcher m = UNQUOTED_VALUE_PATTERN.matcher(str); if (m.find(index)) { String stringValue = JSONUtil.unescapeString(m.group(1)); index = m.end() - 1; add(JSONUtil.convertStringValueToObject(stringValue)); } } } } } }