自己编写的一个Json工具类,实现了反射将整个Object转换为Json对象的功能,支持Hibernate的延迟加载对象[修订081217]
最后更新:09-02-08
bug fix:支持了Hibernate one-to-many映射到List的处理
由于Json自己的String转换有问题,无法正确的转换中文为uxxxx的字符,因此改用DWR包内的JavascriptUtil处理String类型。可以直接引用,还可以拆离出来,因为仅是一个转换工具类,跟DWR的没有依赖关系。这样就可以采用ISO-8859-1编码来传递所有UNICODE了。
代码:
- package com.aherp.framework.util;
- import org.json.JSONString;
- public class JSONStringObject implements JSONString {
- private String jsonString = null;
- public JSONStringObject(String jsonString){
- this.jsonString = jsonString;
- }
- @Override
- public String toString() {
- return jsonString;
- }
- public String toJSONString() {
- return jsonString;
- }
- }
- package com.aherp.framework.util;
- import java.lang.reflect.Array;
- import java.lang.reflect.Method;
- import java.util.Calendar;
- import java.util.Date;
- import java.util.Map;
- import java.util.Map.Entry;
- import org.json.JSONArray;
- import org.json.JSONException;
- import org.json.JSONObject;
- import org.json.JSONString;
- /**
- * JSON工具类,反射的方式转换整个对象
- * @author Jim Wu
- *
- */
- public class JSONUtil {
- private static JSONUtil instance = null;
- public JSONUtil(){}
- /**
- * 代理类是否输出的检查,返回true则允许继续转换
- * @param bean
- * @return 是否允许继续转换
- */
- protected boolean canProxyOutput(Object bean) {
- return true;
- }
- /**
- * 代理类时做的检查.返回应该检查的对象.
- * @param bean
- * @return 实际获取的对象
- */
- protected Object proxyConvert(Object bean){
- return bean;
- }
- static public String toJSONString(Object obj) throws JSONException{
- return toJSONString(obj, false);
- }
- static public String toJSONString(Object obj, boolean useClassConvert) throws JSONException{
- if(instance == null)
- instance = new JSONUtil();
- return instance.getJSONObject(obj, useClassConvert).toString();
- }
- @SuppressWarnings("unchecked")
- private String getJSONArray(Object arrayObj, boolean useClassConvert) throws JSONException{
- if(arrayObj == null)
- return "null";
- arrayObj = proxyConvert(arrayObj);
- JSONArray jSONArray = new JSONArray();
- if(arrayObj instanceof Iterable){
- for(Object rowObj: ((Iterable)arrayObj)){
- if(canProxyOutput(rowObj)){
- if(rowObj == null)
- jSONArray.put(new JSONStringObject(null));
- else if(rowObj.getClass().isArray() || rowObj instanceof Iterable)
- jSONArray.put(getJSONArray(rowObj, useClassConvert));
- else
- jSONArray.put(getJSONObject(rowObj, useClassConvert));
- }
- }
- }
- if(arrayObj.getClass().isArray()){
- int arrayLength = Array.getLength(arrayObj);
- for(int i = 0; i < arrayLength; i ++){
- Object rowObj = Array.get(arrayObj, i);
- if(canProxyOutput(rowObj)){
- if(rowObj == null)
- jSONArray.put(new JSONStringObject(null));
- else if(rowObj.getClass().isArray() || rowObj instanceof Iterable)
- jSONArray.put(getJSONArray(rowObj, useClassConvert));
- else
- jSONArray.put(getJSONObject(rowObj, useClassConvert));
- }
- }
- }
- return jSONArray.toString();
- }
- @SuppressWarnings("unchecked")
- JSONStringObject getJSONObject(Object value, boolean useClassConvert) throws JSONException{
- //处理原始类型
- if (value == null) {
- return new JSONStringObject("null");
- }
- value = proxyConvert(value);
- if (value instanceof JSONString) {
- Object o;
- try {
- o = ((JSONString)value).toJSONString();
- } catch (Exception e) {
- throw new JSONException(e);
- }
- throw new JSONException("Bad value from toJSONString: " + o);
- }
- if (value instanceof Number) {
- return new JSONStringObject(JSONObject.numberToString((Number) value));
- }
- if (value instanceof Boolean || value instanceof JSONObject ||
- value instanceof JSONArray) {
- return new JSONStringObject(value.toString());
- }
- if (value instanceof String)
- return new JSONStringObject('"' + JavascriptUtil.escapeJavaScript(value.toString()) + '"');
- if (value instanceof Map) {
- JSONObject jSONObject = new JSONObject();
- for(Object rowObj: ((Map)value).entrySet()){
- Entry entry = (Entry)rowObj;
- Object valueObj = entry.getValue();
- if(canProxyOutput(valueObj))
- jSONObject.put(entry.getKey().toString(), getJSONObject(valueObj, useClassConvert));
- }
- return new JSONStringObject(jSONObject.toString());
- }
- if(value instanceof Date){
- Calendar calendar = Calendar.getInstance();
- calendar.setTime(calendar.getTime());
- StringBuilder sb = new StringBuilder("new Date(");
- sb.append(calendar.get(Calendar.YEAR));
- sb.append(",");
- sb.append(calendar.get(Calendar.MONTH));
- sb.append(",");
- sb.append(calendar.get(Calendar.DAY_OF_MONTH));
- sb.append(",");
- sb.append(calendar.get(Calendar.HOUR_OF_DAY));
- sb.append(",");
- sb.append(calendar.get(Calendar.MINUTE));
- sb.append(",");
- sb.append(calendar.get(Calendar.SECOND));
- sb.append(")");
- return new JSONStringObject(sb.toString());
- }
- //class
- if(value instanceof Class)
- return new JSONStringObject(JavascriptUtil.escapeJavaScript(((Class)value).getSimpleName()));
- //数组
- if (value instanceof Iterable || value.getClass().isArray()) {
- return new JSONStringObject(getJSONArray(proxyConvert(value), useClassConvert));
- }
- return reflectObject(value, useClassConvert);
- }
- @SuppressWarnings("unchecked")
- private JSONStringObject reflectObject(Object bean, boolean useClassConvert){
- JSONObject jSONObject = new JSONObject();
- Class klass = bean.getClass();
- for (Method method: klass.getMethods()) {
- try {
- String name = method.getName();
- String key = "";
- if (name.startsWith("get")) {
- key = name.substring(3);
- } else if (name.startsWith("is")) {
- key = name.substring(2);
- }
- if (key.length() > 0 &
- Character.isUpperCase(key.charAt(0)) &
- method.getParameterTypes().length == 0) {
- if (key.length() == 1) {
- key = key.toLowerCase();
- } else if (!Character.isUpperCase(key.charAt(1))) {
- key = key.substring(0, 1).toLowerCase() +
- key.substring(1);
- }
- Object elementObj = method.invoke(bean);
- if(!useClassConvert && elementObj instanceof Class)
- continue;
- if(canProxyOutput(elementObj))
- jSONObject.put(key, getJSONObject(elementObj, useClassConvert));
- }
- } catch (Exception e) {
- /* forget about it */
- }
- }
- return new JSONStringObject(jSONObject.toString());
- }
- }
调用测试程序
import java.util.HashMap;
import java.util.List;
public class AObj ... {
private int ii = 7;
private boolean bb = true;
private String ss = "你好";
private List aList = new ArrayList();
public AObj()...{
aList.add("hello");
aList.add(false);
aList.add(new BObj());
aList.add(new HashMap());
}
public boolean isBb() ...{
return bb;
}
public void setBb(boolean bb) ...{
this.bb = bb;
}
public int getIi() ...{
return ii;
}
public void setIi(int ii) ...{
this.ii = ii;
}
public String getSs() ...{
return ss;
}
public void setSs(String ss) ...{
this.ss = ss;
}
public List getAList() ...{
return aList;
}
public void setAList(List list) ...{
aList = list;
}
}
import java.util.HashMap;
public class BObj ... {
private HashMap innerhm = new HashMap();
public BObj()...{
double dd = 7.4354;
innerhm.put("gigi", "高兴");
innerhm.put("sina", new BigDecimal(dd));
}
public HashMap getInnerhm() ...{
return innerhm;
}
public void setInnerhm(HashMap innerhm) ...{
this.innerhm = innerhm;
}
}
public class CObj extends AObj ... {
private Object[] oarray = new Object[]...{352, false, "kick"};
public Object[] getOarray() ...{
return oarray;
}
public void setOarray(Object[] oarray) ...{
this.oarray = oarray;
}
}
import com.aherp.framework.util.JSONUtil;
public class Test ... {
public static void main(String[] args) throws JSONException ...{
CObj cObj = new CObj();
System.out.println(JSONUtil.toJSONString(cObj));
}
}
输出:
{"AList":["hello",false,{"innerhm":{"gigi":"/u9AD8/u5174","sina":7.4353999999999995651478457148186862468719482421875}},{}],"ii":7,"oarray":[352,false,"kick"],"ss":"/u4F60/u597D","bb":true}
如果需要支持Hibernate,那么必须弄清其机制。Hibernate采用CGLIB对VO对象进行字节码增加,实际机制就是使用一个原类型的proxy子类,其子类实现了HibernateProxy接口。其接口有一个isUninitialized的判断方法,用来判断该代理类是否已经初始化(还记得在事务外使用延迟加载的对象会抛no Session的错误吗,正是由于实际使用的对象已经变成原来类的子类proxy了)。而对于one-to-many映射时,很难判断对象只加载一次,因此为了避免递归调用死循环,忽略了Hibernate的one-to-many集合的递归反射。其原理和many-to-one一样,也是一个子类化的proxy,具有PersistentSet的接口。
因此,支持Hibernate的JSONUtil如下:
- package com.aherp.framework.util;
- import org.hibernate.collection.PersistentSet;
- import org.hibernate.proxy.HibernateProxy;
- import org.hibernate.proxy.LazyInitializer;
- import org.json.JSONException;
- /**
- * 支持Hibernate的JSONUtil.
- * 自动检测是否已经代理加载,如果未加载,则将对象仅加载为OID
- * @author Jim Wu
- *
- */
- public class HiJSONUtil extends JSONUtil {
- private static HiJSONUtil instance = null;
- static public String toJSONString(Object obj) throws JSONException{
- return toJSONString(obj, false);
- }
- static public String toJSONString(Object obj, boolean useClassConvert) throws JSONException{
- if(instance == null)
- instance = new HiJSONUtil();
- return instance.getJSONObject(obj, useClassConvert).toString();
- }
- @Override
- protected Object proxyConvert(Object bean) {
- if(bean instanceof HibernateProxy){
- LazyInitializer lazyInitializer = ((HibernateProxy)bean).getHibernateLazyInitializer();
- if(lazyInitializer.isUninitialized()){
- return lazyInitializer.getIdentifier();
- }else
- return lazyInitializer.getImplementation();
- }
- if(bean instanceof PersistentSet || bean instanceof PersistentList){
- return new String[]{}; //忽略hibernate one-to-many
- }
- return bean;
- }
- @Override
- protected boolean canProxyOutput(Object bean) {
- return !(bean != null && (bean instanceof PersistentSet || bean instanceof PersistentList));
- }
- }
- ;
但是这样还是有个问题,当one-to-one具备双向映射关系时,会陷入调用递归死循环。因此避免这样的情况。
将本人修改过的JavaScriptUtil也附上
- /*
- * Copyright 2005 Joe Walker
- *
- * Licensed 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 com.aherp.framework.util;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.StringReader;
- import java.util.Arrays;
- import java.util.Locale;
- import java.util.SortedSet;
- import java.util.TreeSet;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- /**
- * Various Javascript code utilities.
- * The escape classes were taken from jakarta-commons-lang which in turn borrowed
- * from Turbine and other projects. The list of authors below is almost certainly
- * far too long, but I'm not sure who really wrote these methods.
- * @author Joe Walker [joe at getahead dot ltd dot uk]
- * @author Apache Jakarta Turbine
- * @author GenerationJavaCore library
- * @author Purple Technology
- * @author <a href="mailto:bayard@generationjava.com">Henri Yandell</a>
- * @author <a href="mailto:alex@purpletech.com">Alexander Day Chaffee</a>
- * @author <a href="mailto:cybertiger@cyberiantiger.org">Antony Riley</a>
- * @author Helge Tesgaard
- * @author <a href="sean@boohai.com">Sean Brown</a>
- * @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a>
- * @author Phil Steitz
- * @author Pete Gieser
- */
- @SuppressWarnings("unchecked")
- public class JavascriptUtil
- {
- /**
- * Flag for use in javascript compression: Remove single line comments.
- * For ease of use you may wish to use one of the LEVEL_* compression levels.
- * @noinspection PointlessBitwiseExpression
- */
- public static final int COMPRESS_STRIP_SL_COMMENTS = 1 << 0;
- /**
- * Flag for use in javascript compression: Remove multi line comments.
- * For ease of use you may wish to use one of the LEVEL_* compression levels.
- */
- public static final int COMPRESS_STRIP_ML_COMMENTS = 1 << 1;
- /**
- * Flag for use in javascript compression: Remove whitespace at the start and end of a line.
- * For ease of use you may wish to use one of the LEVEL_* compression levels.
- */
- public static final int COMPRESS_TRIM_LINES = 1 << 2;
- /**
- * Flag for use in javascript compression: Remove blank lines.
- * This option will make the javascript harder to debug because line number references
- * are likely be altered.
- * For ease of use you may wish to use one of the LEVEL_* compression levels.
- */
- public static final int COMPRESS_STRIP_BLANKLINES = 1 << 3;
- /**
- * Flag for use in javascript compression: Shrink variable names.
- * This option is currently un-implemented.
- * For ease of use you may wish to use one of the LEVEL_* compression levels.
- */
- public static final int COMPRESS_SHRINK_VARS = 1 << 4;
- /**
- * Flag for use in javascript compression: Remove all lines endings.
- * Warning: Javascript can add semi-colons in for you. If you make use of this feature
- * then removing newlines may well break.
- * For ease of use you may wish to use one of the LEVEL_* compression levels.
- */
- public static final int COMPRESS_REMOVE_NEWLINES = 1 << 5;
- /**
- * Compression level that leaves the source un-touched.
- */
- public static final int LEVEL_NONE = 0;
- /**
- * Basic compression that leaves the source fully debuggable.
- * This includes removing all comments and extraneous whitespace.
- */
- public static final int LEVEL_DEBUGGABLE = COMPRESS_STRIP_SL_COMMENTS | COMPRESS_STRIP_ML_COMMENTS | COMPRESS_TRIM_LINES;
- /**
- * Normal compression makes all changes that will work for generic javascript.
- * This adds variable name compression and blank line removal in addition to the
- * compressions done by LEVEL_DEBUGGABLE.
- */
- public static final int LEVEL_NORMAL = LEVEL_DEBUGGABLE | COMPRESS_STRIP_BLANKLINES | COMPRESS_SHRINK_VARS;
- /**
- * LEVEL_ULTRA performs additional compression that makes some assumptions about the
- * style of javascript.
- * Specifically it assumes that you are not using javascripts ability to infer where the ;
- * should go.
- */
- public static final int LEVEL_ULTRA = LEVEL_NORMAL | COMPRESS_REMOVE_NEWLINES;
- /**
- * Compress the source code by removing java style comments and removing
- * leading and trailing spaces.
- * @param text The javascript (or java) program to compress
- * @param level The compression level - see LEVEL_* and COMPRESS_* constants.
- * @return The compressed version
- */
- public static String compress(String text, int level)
- {
- String reply = text;
- // First we strip multi line comments. I think this is important:
- if ((level & COMPRESS_STRIP_ML_COMMENTS) != 0)
- {
- reply = stripMultiLineComments(text);
- }
- if ((level & COMPRESS_STRIP_SL_COMMENTS) != 0)
- {
- reply = stripSingleLineComments(reply);
- }
- if ((level & COMPRESS_TRIM_LINES) != 0)
- {
- reply = trimLines(reply);
- }
- if ((level & COMPRESS_STRIP_BLANKLINES) != 0)
- {
- reply = stripBlankLines(reply);
- }
- if ((level & COMPRESS_SHRINK_VARS) != 0)
- {
- reply = shrinkVariableNames(reply);
- }
- if ((level & COMPRESS_REMOVE_NEWLINES) != 0)
- {
- reply = stripNewlines(reply);
- }
- return reply;
- }
- /**
- * Remove any leading or trailing spaces from a line of code.
- * This function could be improved by making it strip unnecessary double
- * spaces, but since we would need to leave double spaces inside strings
- * this is not simple and since the benefit is small, we'll leave it for now
- * @param text The javascript program to strip spaces from.
- * @return The stripped program
- */
- public static String trimLines(String text)
- {
- if (text == null)
- {
- return null;
- }
- try
- {
- StringBuffer output = new StringBuffer();
- // First we strip multi line comments. I think this is important:
- BufferedReader in = new BufferedReader(new StringReader(text));
- while (true)
- {
- String line = in.readLine();
- if (line == null)
- {
- break;
- }
- output.append(line.trim());
- output.append('/n');
- }
- return output.toString();
- }
- catch (IOException ex)
- {
- log.error("IOExecption unexpected.", ex);
- throw new IllegalArgumentException("IOExecption unexpected.");
- }
- }
- /**
- * Remove all the single-line comments from a block of text
- * @param text The text to remove single-line comments from
- * @return The single-line comment free text
- */
- public static String stripSingleLineComments(String text)
- {
- if (text == null)
- {
- return null;
- }
- try
- {
- StringBuffer output = new StringBuffer();
- BufferedReader in = new BufferedReader(new StringReader(text));
- while (true)
- {
- String line = in.readLine();
- if (line == null)
- {
- break;
- }
- // Skip @DWR comments
- if (line.indexOf(COMMENT_RETAIN) == -1)
- {
- int cstart = line.indexOf(COMMENT_SL_START);
- if (cstart >= 0)
- {
- line = line.substring(0, cstart);
- }
- }
- output.append(line);
- output.append('/n');
- }
- return output.toString();
- }
- catch (IOException ex)
- {
- log.error("IOExecption unexpected.", ex);
- throw new IllegalArgumentException("IOExecption unexpected.");
- }
- }
- /**
- * Remove all the multi-line comments from a block of text
- * @param text The text to remove multi-line comments from
- * @return The multi-line comment free text
- */
- public static String stripMultiLineComments(String text)
- {
- if (text == null)
- {
- return null;
- }
- try
- {
- StringBuffer output = new StringBuffer();
- // Comment rules:
- /*/ This is still a comment
- /* /* */ // Comments do not nest
- // /* */ This is in a comment
- /* // */ // The second // is needed to make this a comment.
- // First we strip multi line comments. I think this is important:
- boolean inMultiLine = false;
- BufferedReader in = new BufferedReader(new StringReader(text));
- while (true)
- {
- String line = in.readLine();
- if (line == null)
- {
- break;
- }
- if (!inMultiLine)
- {
- // We are not in a multi-line comment, check for a start
- int cstart = line.indexOf(COMMENT_ML_START);
- if (cstart >= 0)
- {
- // This could be a MLC on one line ...
- int cend = line.indexOf(COMMENT_ML_END, cstart + COMMENT_ML_START.length());
- if (cend >= 0)
- {
- // A comment that starts and ends on one line
- // BUG: you can have more than 1 multi-line comment on a line
- line = line.substring(0, cstart) + SPACE + line.substring(cend + COMMENT_ML_END.length());
- }
- else
- {
- // A real multi-line comment
- inMultiLine = true;
- line = line.substring(0, cstart) + SPACE;
- }
- }
- else
- {
- // We are not in a multi line comment and we havn't
- // started one so we are going to ignore closing
- // comments even if they exist.
- }
- }
- else
- {
- // We are in a multi-line comment, check for the end
- int cend = line.indexOf(COMMENT_ML_END);
- if (cend >= 0)
- {
- // End of comment
- line = line.substring(cend + COMMENT_ML_END.length());
- inMultiLine = false;
- }
- else
- {
- // The comment continues
- line = SPACE;
- }
- }
- output.append(line);
- output.append('/n');
- }
- return output.toString();
- }
- catch (IOException ex)
- {
- log.error("IOExecption unexpected.", ex);
- throw new IllegalArgumentException("IOExecption unexpected.");
- }
- }
- /**
- * Remove all blank lines from a string.
- * A blank line is defined to be a line where the only characters are whitespace.
- * We always ensure that the line contains a newline at the end.
- * @param text The string to strip blank lines from
- * @return The blank line stripped reply
- */
- public static String stripBlankLines(String text)
- {
- if (text == null)
- {
- return null;
- }
- try
- {
- StringBuffer output = new StringBuffer();
- BufferedReader in = new BufferedReader(new StringReader(text));
- boolean doneOneLine = false;
- while (true)
- {
- String line = in.readLine();
- if (line == null)
- {
- break;
- }
- if (line.trim().length() > 0)
- {
- output.append(line);
- output.append('/n');
- doneOneLine = true;
- }
- }
- if (!doneOneLine)
- {
- output.append('/n');
- }
- return output.toString();
- }
- catch (IOException ex)
- {
- log.error("IOExecption unexpected.", ex);
- throw new IllegalArgumentException("IOExecption unexpected.");
- }
- }
- /**
- * Remove all newline characters from a string.
- * @param text The string to strip newline characters from
- * @return The stripped reply
- */
- public static String stripNewlines(String text)
- {
- if (text == null)
- {
- return null;
- }
- try
- {
- StringBuffer output = new StringBuffer();
- BufferedReader in = new BufferedReader(new StringReader(text));
- while (true)
- {
- String line = in.readLine();
- if (line == null)
- {
- break;
- }
- output.append(line);
- output.append(SPACE);
- }
- output.append('/n');
- return output.toString();
- }
- catch (IOException ex)
- {
- log.error("IOExecption unexpected.", ex);
- throw new IllegalArgumentException("IOExecption unexpected.");
- }
- }
- /**
- * Shrink variable names to a minimum.
- * @param text The javascript program to shrink the variable names in.
- * @return The shrunk version of the javascript program.
- */
- public static String shrinkVariableNames(String text)
- {
- if (text == null)
- {
- return null;
- }
- throw new UnsupportedOperationException("Variable name shrinking is not supported");
- }
- /**
- * <p>Escapes the characters in a <code>String</code> using JavaScript String rules.</p>
- * <p>Escapes any values it finds into their JavaScript String form.
- * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
- *
- * <p>So a tab becomes the characters <code>'//'</code> and
- * <code>'t'</code>.</p>
- *
- * <p>The only difference between Java strings and JavaScript strings
- * is that in JavaScript, a single quote must be escaped.</p>
- *
- * <p>Example:
- * <pre>
- * input string: He didn't say, "Stop!"
- * output string: He didn/'t say, /"Stop!/"
- * </pre>
- * </p>
- *
- * @param str String to escape values in, may be null
- * @return String with escaped values, <code>null</code> if null string input
- */
- public static String escapeJavaScript(String str)
- {
- if (str == null)
- {
- return null;
- }
- StringBuffer writer = new StringBuffer(str.length() * 2);
- int sz = str.length();
- for (int i = 0; i < sz; i++)
- {
- char ch = str.charAt(i);
- // handle unicode
- if (ch > 0xfff)
- {
- writer.append("//u");
- writer.append(hex(ch));
- }
- else if (ch > 0xff)
- {
- writer.append("//u0");
- writer.append(hex(ch));
- }
- else if (ch > 0x7f)
- {
- writer.append("//u00");
- writer.append(hex(ch));
- }
- else if (ch < 32)
- {
- switch (ch)
- {
- case '/b':
- writer.append('//');
- writer.append('b');
- break;
- case '/n':
- writer.append('//');
- writer.append('n');
- break;
- case '/t':
- writer.append('//');
- writer.append('t');
- break;
- case '/f':
- writer.append('//');
- writer.append('f');
- break;
- case '/r':
- writer.append('//');
- writer.append('r');
- break;
- default:
- if (ch > 0xf)
- {
- writer.append("//u00");
- writer.append(hex(ch));
- }
- else
- {
- writer.append("//u000");
- writer.append(hex(ch));
- }
- break;
- }
- }
- else
- {
- switch (ch)
- {
- case '/'':
- // If we wanted to escape for Java strings then we would
- // not need this next line.
- writer.append('//');
- writer.append('/'');
- break;
- case '"':
- writer.append('//');
- writer.append('"');
- break;
- case '//':
- writer.append('//');
- writer.append('//');
- break;
- case '<':
- writer.append("//u003c");
- break;
- case '>':
- writer.append("//u003e");
- break;
- default:
- writer.append(ch);
- break;
- }
- }
- }
- return writer.toString();
- }
- /**
- * <p>Returns an upper case hexadecimal <code>String</code> for the given
- * character.</p>
- * @param ch The character to convert.
- * @return An upper case hexadecimal <code>String</code>
- */
- private static String hex(char ch)
- {
- return Integer.toHexString(ch).toUpperCase(Locale.ENGLISH);
- }
- /**
- * <p>Unescapes any JavaScript literals found in the <code>String</code>.</p>
- * <p>For example, it will turn a sequence of <code>'/'</code> and <code>'n'</code>
- * into a newline character, unless the <code>'/'</code> is preceded by another
- * <code>'/'</code>.</p>
- * @param str the <code>String</code> to unescape, may be null
- * @return A new unescaped <code>String</code>, <code>null</code> if null string input
- */
- public static String unescapeJavaScript(String str)
- {
- if (str == null)
- {
- return null;
- }
- StringBuffer writer = new StringBuffer(str.length());
- int sz = str.length();
- StringBuffer unicode = new StringBuffer(4);
- boolean hadSlash = false;
- boolean inUnicode = false;
- for (int i = 0; i < sz; i++)
- {
- char ch = str.charAt(i);
- if (inUnicode)
- {
- // if in unicode, then we're reading unicode
- // values in somehow
- unicode.append(ch);
- if (unicode.length() == 4)
- {
- // unicode now contains the four hex digits
- // which represents our unicode chacater
- try
- {
- int value = Integer.parseInt(unicode.toString(), 16);
- writer.append((char) value);
- unicode.setLength(0);
- inUnicode = false;
- hadSlash = false;
- }
- catch (NumberFormatException nfe)
- {
- throw new IllegalArgumentException("Unable to parse unicode value: " + unicode + " cause: " + nfe);
- }
- }
- continue;
- }
- if (hadSlash)
- {
- // handle an escaped value
- hadSlash = false;
- switch (ch)
- {
- case '//':
- writer.append('//');
- break;
- case '/'':
- writer.append('/'');
- break;
- case '/"':
- writer.append('"');
- break;
- case 'r':
- writer.append('/r');
- break;
- case 'f':
- writer.append('/f');
- break;
- case 't':
- writer.append('/t');
- break;
- case 'n':
- writer.append('/n');
- break;
- case 'b':
- writer.append('/b');
- break;
- case 'u':
- // uh-oh, we're in unicode country....
- inUnicode = true;
- break;
- default:
- writer.append(ch);
- break;
- }
- continue;
- }
- else if (ch == '//')
- {
- hadSlash = true;
- continue;
- }
- writer.append(ch);
- }
- if (hadSlash)
- {
- // then we're in the weird case of a / at the end of the
- // string, let's output it anyway.
- writer.append('//');
- }
- return writer.toString();
- }
- /**
- * Check to see if the given word is reserved or a bad idea in any known
- * version of JavaScript.
- * @param name The word to check
- * @return false if the word is not reserved
- */
- public static boolean isReservedWord(String name)
- {
- return reserved.contains(name);
- }
- /**
- * The array of javascript reserved words
- */
- private static final String[] RESERVED_ARRAY = new String[]
- {
- // Reserved and used at ECMAScript 4
- "as",
- "break",
- "case",
- "catch",
- "class",
- "const",
- "continue",
- "default",
- "delete",
- "do",
- "else",
- "export",
- "extends",
- "false",
- "finally",
- "for",
- "function",
- "if",
- "import",
- "in",
- "instanceof",
- "is",
- "namespace",
- "new",
- "null",
- "package",
- "private",
- "public",
- "return",
- "super",
- "switch",
- "this",
- "throw",
- "true",
- "try",
- "typeof",
- "use",
- "var",
- "void",
- "while",
- "with",
- // Reserved for future use at ECMAScript 4
- "abstract",
- "debugger",
- "enum",
- "goto",
- "implements",
- "interface",
- "native",
- "protected",
- "synchronized",
- "throws",
- "transient",
- "volatile",
- // Reserved in ECMAScript 3, unreserved at 4 best to avoid anyway
- "boolean",
- "byte",
- "char",
- "double",
- "final",
- "float",
- "int",
- "long",
- "short",
- "static",
- // I have seen the folowing list as 'best avoided for function names'
- // but it seems way to all encompassing, so I'm not going to include it
- /*
- "alert", "anchor", "area", "arguments", "array", "assign", "blur",
- "boolean", "button", "callee", "caller", "captureevents", "checkbox",
- "clearinterval", "cleartimeout", "close", "closed", "confirm",
- "constructor", "date", "defaultstatus", "document", "element", "escape",
- "eval", "fileupload", "find", "focus", "form", "frame", "frames",
- "getclass", "hidden", "history", "home", "image", "infinity",
- "innerheight", "isfinite", "innerwidth", "isnan", "java", "javaarray",
- "javaclass", "javaobject", "javapackage", "length", "link", "location",
- "locationbar", "math", "menubar", "mimetype", "moveby", "moveto",
- "name", "nan", "navigate", "navigator", "netscape", "number", "object",
- "onblur", "onerror", "onfocus", "onload", "onunload", "open", "opener",
- "option", "outerheight", "outerwidth", "packages", "pagexoffset",
- "pageyoffset", "parent", "parsefloat", "parseint", "password",
- "personalbar", "plugin", "print", "prompt", "prototype", "radio", "ref",
- "regexp", "releaseevents", "reset", "resizeby", "resizeto",
- "routeevent", "scroll", "scrollbars", "scrollby", "scrollto", "select",
- "self", "setinterval", "settimeout", "status", "statusbar", "stop",
- "string", "submit", "sun", "taint", "text", "textarea", "toolbar",
- "top", "tostring", "unescape", "untaint", "unwatch", "valueof", "watch",
- "window",
- */
- };
- private static SortedSet reserved = new TreeSet();
- /**
- * For easy access ...
- */
- static
- {
- // The Javascript reserved words array so we don't generate illegal javascript
- reserved.addAll(Arrays.asList(RESERVED_ARRAY));
- }
- private static final String SPACE = " ";
- /**
- * How does a multi line comment start?
- */
- private static final String COMMENT_ML_START = "/*";
- /**
- * How does a multi line comment end?
- */
- private static final String COMMENT_ML_END = "*/";
- /**
- * How does a single line comment start?
- */
- private static final String COMMENT_SL_START = "//";
- /**
- * Sometimes we need to retain the comment because it has special meaning
- */
- private static final String COMMENT_RETAIN = "#DWR";
- /**
- * The log stream
- */
- private static final Log log = LogFactory.getLog(JavascriptUtil.class);
- }
需要的JSON类我已经放到共享,你可以从
http://download.csdn.net/source/879579
下载
更多推荐
所有评论(0)