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

ro.isdc.wro.extensions.script.RhinoUtils Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
/*
 * Copyright (C) 2011. All rights reserved.
 */
package ro.isdc.wro.extensions.script;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.mozilla.javascript.EcmaError;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.RhinoException;
import org.mozilla.javascript.ScriptableObject;



/**
 * Direct conversion between native Rhino objects and JSON.
 * 

* This class can be used directly in Rhino. *

* This class was inspired from {@link http * ://mongodb-rhino.googlecode.com/svn/trunk/modules/com.mongodb.rhino/src/com/mongodb/rhino/JSON.java} * * @author Alex Objelean * @since 1.3.6 */ public class RhinoUtils { /** * Creates a more detailed message based on {@link RhinoException} thrown by rhino execution. The message will contain * a detailed description of the problem by inspecting the JSON value provided by exception. * * @param e {@link RhinoException} thrown by rhino execution. * @return detailed string message. */ public static String createExceptionMessage(final RhinoException e) { String message = "Could not execute the script because: "; if (e instanceof JavaScriptException) { message += toJson(((JavaScriptException) e).getValue()); } else if (e instanceof EcmaError) { final EcmaError ecmaError = (EcmaError)e; message += String.format("Error message: %s at line: %s. \nSource: %s", ecmaError.getErrorMessage(), ecmaError.lineNumber(), ecmaError.lineSource()); } else { message += e.getMessage(); } return message; } /** * Recursively convert from native Rhino to JSON. *

* Recognizes JavaScript objects, arrays and primitives. *

* Special support for JavaScript dates: converts to {"$date": timestamp} in JSON. *

* Special support for MongoDB ObjectId: converts to {"$oid": "objectid"} in JSON. *

* Also recognizes JVM types: java.util.Map, java.util.Collection, java.util.Date. * * @param object * A Rhino native object * @return The JSON string * @see RhinoUtils#convertSpecial(Object) */ public static String toJson(final Object object) { return toJson(object, false); } /** * Recursively convert from native Rhino to JSON. *

* Recognizes JavaScript objects, arrays and primitives. *

* Special support for JavaScript dates: converts to {"$date": timestamp} in JSON. *

* Special support for MongoDB ObjectId: converts to {"$oid": "objectid"} in JSON. *

* Also recognizes JVM types: java.util.Map, java.util.Collection, java.util.Date. * * @param object * A Rhino native object * @param indent * Whether to indent the JSON for human readability * @return The JSON string */ public static String toJson(final Object object, final boolean indent) { final StringBuilder s = new StringBuilder(); encode(s, object, indent, indent ? 0 : -1); return s.toString(); } private static void encode(final StringBuilder s, final Object object, final boolean indent, final int depth) { if (indent) indent(s, depth); if (object == null) { s.append("null"); } else if (object instanceof Number) { s.append(object); } else if (object instanceof Boolean) { s.append(object); } else if (object instanceof Date) { final HashMap map = new HashMap(); map.put("$date", ((Date) object).getTime()); encode(s, map, depth); } else if (object instanceof Collection) { encode(s, (Collection) object, depth); } else if (object instanceof Map) { encode(s, (Map) object, depth); // } else if (object instanceof NativeArray) { // final NativeArray nativeArray = (NativeArray) object; // encode(s, nativeArray, depth); } else if (object instanceof ScriptableObject) { final ScriptableObject scriptable = (ScriptableObject) object; if (scriptable.getClassName().equals("Date")) { // (The NativeDate class is private in Rhino, but we can access // it like a regular object.) final Object time = ScriptableObject.callMethod(scriptable, "getTime", null); if (time instanceof Number) { encode(s, new Date(((Number) time).longValue()), false, depth); return; } } encode(s, scriptable, depth); } else { s.append('\"'); s.append(escape(object.toString())); s.append('\"'); } } private static void encode(final StringBuilder s, final Collection collection, final int depth) { s.append('['); final Iterator i = collection.iterator(); if (i.hasNext()) { if (depth > -1) s.append('\n'); while (true) { final Object value = i.next(); encode(s, value, true, depth > -1 ? depth + 1 : -1); if (i.hasNext()) { s.append(','); if (depth > -1) s.append('\n'); } else break; } if (depth > -1) s.append('\n'); } if (depth > -1) indent(s, depth); s.append(']'); } private static void encode(final StringBuilder s, final Map map, final int depth) { s.append('{'); final Iterator i = map.entrySet().iterator(); if (i.hasNext()) { if (depth > -1) s.append('\n'); while (true) { final Map.Entry entry = (Map.Entry) i.next(); final String key = entry.getKey().toString(); final Object value = entry.getValue(); if (depth > -1) indent(s, depth + 1); s.append('\"'); s.append(escape(key)); s.append("\":"); if (depth > -1) s.append(' '); encode(s, value, false, depth > -1 ? depth + 1 : -1); if (i.hasNext()) { s.append(','); if (depth > -1) s.append('\n'); } else break; } if (depth > -1) s.append('\n'); } if (depth > -1) indent(s, depth); s.append('}'); } private static void encode(final StringBuilder s, final NativeArray array, final int depth) { s.append('['); final long length = array.getLength(); if (length > 0) { if (depth > -1) s.append('\n'); for (int i = 0; i < length; i++) { final Object value = ScriptableObject.getProperty(array, i); encode(s, value, true, depth > -1 ? depth + 1 : -1); if (i < length - 1) { s.append(','); if (depth > -1) s.append('\n'); } } if (depth > -1) s.append('\n'); } if (depth > -1) indent(s, depth); s.append(']'); } private static void encode(final StringBuilder s, final ScriptableObject object, final int depth) { s.append('{'); final Object[] ids = object.getAllIds(); if (ids.length > 0) { if (depth > -1) s.append('\n'); final int length = ids.length; for (int i = 0; i < length; i++) { final String key = ids[i].toString(); final Object value = ScriptableObject.getProperty(object, key); if (depth > -1) indent(s, depth + 1); s.append('\"'); s.append(escape(key)); s.append("\":"); if (depth > -1) s.append(' '); encode(s, value, false, depth > -1 ? depth + 1 : -1); if (i < length - 1) { s.append(','); if (depth > -1) s.append('\n'); } } if (depth > -1) s.append('\n'); } if (depth > -1) indent(s, depth); s.append('}'); } private static void indent(final StringBuilder s, final int depth) { for (int i = depth - 1; i >= 0; i--) s.append(" "); } private static Pattern[] ESCAPE_PATTERNS = new Pattern[] { Pattern.compile("\\\\"), Pattern.compile("\\n"), Pattern.compile("\\r"), Pattern.compile("\\t"), Pattern.compile("\\f"), Pattern.compile("\\\"") }; private static String[] ESCAPE_REPLACEMENTS = new String[] { Matcher.quoteReplacement("\\\\"), Matcher.quoteReplacement("\\n"), Matcher.quoteReplacement("\\r"), Matcher.quoteReplacement("\\t"), Matcher.quoteReplacement("\\f"), Matcher.quoteReplacement("\\\"") }; private static String escape(String string) { for (int i = 0, length = ESCAPE_PATTERNS.length; i < length; i++) string = ESCAPE_PATTERNS[i].matcher(string).replaceAll(ESCAPE_REPLACEMENTS[i]); return string; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy